Compare commits

...

647 Commits

Author SHA1 Message Date
hank
74635e5763 New translations en.po (Spanish) 2025-12-14 04:39:12 -05:00
hank
8ce9088d9d New translations en.po (Serbian (Cyrillic)) 2025-12-08 13:22:54 -05:00
hank
b3331c00f8 New translations en.po (Chinese Traditional) 2025-12-08 10:28:57 -05:00
hank
d0559065c1 New translations en.po (Chinese Traditional) 2025-12-08 08:54:57 -05:00
hank
78f6006bdc New translations en.po (Serbian (Cyrillic)) 2025-12-05 15:24:47 -05:00
hank
436b42f4d1 New translations en.po (Swedish) 2025-12-05 15:24:42 -05:00
hank
16f7b30624 New translations en.po (Slovenian) 2025-12-05 15:24:41 -05:00
hank
9249256c9f New translations en.po (Portuguese) 2025-12-05 15:24:40 -05:00
hank
34163b8595 New translations en.po (Norwegian) 2025-12-05 15:24:38 -05:00
hank
a4731f9179 New translations en.po (German) 2025-12-05 15:24:34 -05:00
hank
9c74eccaf0 New translations en.po (Danish) 2025-12-05 15:24:33 -05:00
hank
4768adf440 New translations en.po (Czech) 2025-12-05 15:24:32 -05:00
hank
11ffb422e8 New translations en.po (French) 2025-12-05 15:24:29 -05:00
hank
bab02ad738 New translations en.po (Spanish) 2025-12-05 15:24:28 -05:00
hank
61faee2450 New translations en.po (Serbian (Cyrillic)) 2025-12-04 15:03:35 -05:00
hank
d0be54f47c New translations en.po (Chinese Traditional, Hong Kong) 2025-12-02 18:18:21 -05:00
hank
cc2be97055 New translations en.po (Croatian) 2025-12-02 18:18:20 -05:00
hank
2fc1565b75 New translations en.po (Persian) 2025-12-02 18:18:19 -05:00
hank
f5421eff3c New translations en.po (Indonesian) 2025-12-02 18:18:18 -05:00
hank
fc01ca1cad New translations en.po (Vietnamese) 2025-12-02 18:18:17 -05:00
hank
e2923126d2 New translations en.po (Chinese Simplified) 2025-12-02 18:18:16 -05:00
hank
972ce62ff5 New translations en.po (Ukrainian) 2025-12-02 18:18:15 -05:00
hank
05d9297ca3 New translations en.po (Turkish) 2025-12-02 18:18:14 -05:00
hank
ffc35b3c51 New translations en.po (Swedish) 2025-12-02 18:18:13 -05:00
hank
a547de8bf0 New translations en.po (Slovenian) 2025-12-02 18:18:12 -05:00
hank
d8d1a89256 New translations en.po (Portuguese) 2025-12-02 18:18:11 -05:00
hank
c29ba1c353 New translations en.po (Polish) 2025-12-02 18:18:10 -05:00
hank
474d860929 New translations en.po (Norwegian) 2025-12-02 18:18:09 -05:00
hank
fb57a57e77 New translations en.po (Dutch) 2025-12-02 18:18:08 -05:00
hank
02e5a8e9fc New translations en.po (Korean) 2025-12-02 18:18:07 -05:00
hank
c0f6f64aa7 New translations en.po (Japanese) 2025-12-02 18:18:06 -05:00
hank
3077ed045d New translations en.po (Hungarian) 2025-12-02 18:18:05 -05:00
hank
f7b62a2868 New translations en.po (Hebrew) 2025-12-02 18:18:04 -05:00
hank
5daa0d3576 New translations en.po (German) 2025-12-02 18:18:03 -05:00
hank
a6b9fa2aa9 New translations en.po (Danish) 2025-12-02 18:18:02 -05:00
hank
5195e6d675 New translations en.po (Czech) 2025-12-02 18:18:01 -05:00
hank
93e71dcf30 New translations en.po (Bulgarian) 2025-12-02 18:18:00 -05:00
hank
826227f3af New translations en.po (Arabic) 2025-12-02 18:17:59 -05:00
hank
cfe8645c18 New translations en.po (French) 2025-12-02 18:17:58 -05:00
hank
681184b444 New translations en.po (Romanian) 2025-12-02 18:17:56 -05:00
hank
6d759cbe9f New translations en.po (Spanish) 2025-12-02 18:17:55 -05:00
hank
75480f66fa New translations en.po (Russian) 2025-12-02 18:17:55 -05:00
hank
416c237ef3 New translations en.po (Italian) 2025-12-02 18:17:53 -05:00
hank
ff64ac7a37 New translations en.po (Chinese Traditional) 2025-12-02 18:17:52 -05:00
hank
555f668b54 New translations en.po (Spanish) 2025-12-01 18:32:58 -05:00
hank
0dedc634a7 New translations en.po (Russian) 2025-12-01 18:32:57 -05:00
hank
5500e45951 New translations en.po (Chinese Traditional) 2025-12-01 18:32:56 -05:00
hank
e7574a927f New translations en.po (Chinese Traditional) 2025-11-22 06:14:37 -05:00
hank
83fbaa7a3f New translations en.po (Chinese Traditional) 2025-11-22 00:56:30 -05:00
hank
cf3efa1f9f New translations en.po (Chinese Traditional) 2025-11-21 22:50:27 -05:00
hank
24093e33a9 New translations en.po (Russian) 2025-11-21 18:15:30 -05:00
hank
075fad1da4 New translations en.po (Italian) 2025-11-20 11:58:14 -05:00
hank
a35631415a New translations en.po (Polish) 2025-11-17 11:53:50 -05:00
hank
8e99d67174 New translations en.po (Spanish) 2025-11-15 03:26:28 -05:00
hank
cf37c9a93c New translations en.po (Indonesian) 2025-11-14 17:51:43 -05:00
hank
402d1d9fec New translations en.po (Hebrew) 2025-11-14 17:51:41 -05:00
hank
b4f2afa4b6 New translations en.po (Chinese Traditional, Hong Kong) 2025-11-14 17:51:40 -05:00
hank
beff2eb43f New translations en.po (Persian) 2025-11-14 17:51:39 -05:00
hank
2e0d12a02d New translations en.po (Vietnamese) 2025-11-14 17:51:38 -05:00
hank
bc2fd34ac5 New translations en.po (Chinese Simplified) 2025-11-14 17:51:37 -05:00
hank
333cfae109 New translations en.po (Ukrainian) 2025-11-14 17:51:36 -05:00
hank
8cf8dd492d New translations en.po (Turkish) 2025-11-14 17:51:35 -05:00
hank
9b664b6400 New translations en.po (Swedish) 2025-11-14 17:51:34 -05:00
hank
c30d2fbe39 New translations en.po (Slovenian) 2025-11-14 17:51:33 -05:00
hank
f1a4fae659 New translations en.po (Russian) 2025-11-14 17:51:32 -05:00
hank
32675e403f New translations en.po (Polish) 2025-11-14 17:51:31 -05:00
hank
d92d67eece New translations en.po (Korean) 2025-11-14 17:51:30 -05:00
hank
ed1fc63ce2 New translations en.po (Japanese) 2025-11-14 17:51:29 -05:00
hank
0e2b1675fa New translations en.po (Italian) 2025-11-14 17:51:28 -05:00
hank
ee8f901918 New translations en.po (Danish) 2025-11-14 17:51:27 -05:00
hank
7dc2a86b1e New translations en.po (Czech) 2025-11-14 17:51:26 -05:00
hank
51699ddc12 New translations en.po (Bulgarian) 2025-11-14 17:51:25 -05:00
hank
e0675567b8 New translations en.po (Arabic) 2025-11-14 17:51:24 -05:00
hank
61b3102eda New translations en.po (Spanish) 2025-11-14 17:51:23 -05:00
hank
7cc8f2b933 New translations en.po (Romanian) 2025-11-14 17:51:22 -05:00
hank
d38e3eab9c New translations en.po (Croatian) 2025-11-14 17:51:21 -05:00
hank
4ceb06b0c5 New translations en.po (Chinese Traditional) 2025-11-14 17:51:19 -05:00
hank
b1a468a0ab New translations en.po (Portuguese) 2025-11-14 17:51:18 -05:00
hank
c6755183a8 New translations en.po (Norwegian) 2025-11-14 17:51:17 -05:00
hank
cdc9f11ac0 New translations en.po (Dutch) 2025-11-14 17:51:16 -05:00
hank
6ccaaee57e New translations en.po (Hungarian) 2025-11-14 17:51:15 -05:00
hank
214ee4a75a New translations en.po (German) 2025-11-14 17:51:14 -05:00
hank
a506d3c84a New translations en.po (French) 2025-11-14 17:51:13 -05:00
hank
812e849769 New translations en.po (Spanish) 2025-11-14 12:09:18 -05:00
hank
774eef1f3f New translations en.po (Polish) 2025-11-13 09:52:30 -05:00
hank
fc85c50f2f New translations en.po (Indonesian) 2025-11-12 15:36:57 -05:00
hank
fad22eee61 New translations en.po (Hebrew) 2025-11-12 15:36:56 -05:00
hank
e84dbd639b New translations en.po (Chinese Traditional, Hong Kong) 2025-11-12 15:36:55 -05:00
hank
2dd59b4e11 New translations en.po (Persian) 2025-11-12 15:36:54 -05:00
hank
bb649971dc New translations en.po (Vietnamese) 2025-11-12 15:36:53 -05:00
hank
3f82ee0330 New translations en.po (Chinese Simplified) 2025-11-12 15:36:52 -05:00
hank
a26fde66e6 New translations en.po (Ukrainian) 2025-11-12 15:36:51 -05:00
hank
ed9b576bde New translations en.po (Turkish) 2025-11-12 15:36:49 -05:00
hank
aea463f5da New translations en.po (Swedish) 2025-11-12 15:36:48 -05:00
hank
45e00c70ab New translations en.po (Slovenian) 2025-11-12 15:36:47 -05:00
hank
7fc4655f13 New translations en.po (Russian) 2025-11-12 15:36:46 -05:00
hank
7dcaeaa2b4 New translations en.po (Polish) 2025-11-12 15:36:45 -05:00
hank
d07293bf1a New translations en.po (Korean) 2025-11-12 15:36:44 -05:00
hank
38298bbeab New translations en.po (Japanese) 2025-11-12 15:36:43 -05:00
hank
0124ccfac1 New translations en.po (Italian) 2025-11-12 15:36:42 -05:00
hank
5f62ebcd7b New translations en.po (Danish) 2025-11-12 15:36:41 -05:00
hank
ac354e9d6b New translations en.po (Czech) 2025-11-12 15:36:40 -05:00
hank
5572cad7f6 New translations en.po (Bulgarian) 2025-11-12 15:36:39 -05:00
hank
5fa6a7c4e4 New translations en.po (Arabic) 2025-11-12 15:36:37 -05:00
hank
0f9442eaf8 New translations en.po (Spanish) 2025-11-12 15:36:36 -05:00
hank
6094d8d92d New translations en.po (Romanian) 2025-11-12 15:36:35 -05:00
hank
1469710166 New translations en.po (Croatian) 2025-11-12 15:36:34 -05:00
hank
c1df7edddc New translations en.po (Chinese Traditional) 2025-11-12 15:36:33 -05:00
hank
e70f06285c New translations en.po (Portuguese) 2025-11-12 15:36:32 -05:00
hank
c5efa9b20c New translations en.po (Norwegian) 2025-11-12 15:36:31 -05:00
hank
29a948ece4 New translations en.po (Dutch) 2025-11-12 15:36:30 -05:00
hank
d9b587c67b New translations en.po (Hungarian) 2025-11-12 15:36:28 -05:00
hank
f806ae58b6 New translations en.po (German) 2025-11-12 15:36:27 -05:00
hank
8b5dd8dedd New translations en.po (French) 2025-11-12 15:36:26 -05:00
hank
222e5addef New translations en.po (French) 2025-11-11 14:25:02 -05:00
hank
21e7bae720 New translations en.po (Romanian) 2025-11-10 20:21:58 -05:00
hank
a13d90d794 New translations en.po (Swedish) 2025-11-09 20:57:18 -05:00
hank
6e900d0f26 New translations en.po (Portuguese) 2025-11-08 18:43:12 -05:00
hank
112f1853ee New translations en.po (Swedish) 2025-11-06 10:06:27 -05:00
hank
7aa9e3a6d3 New translations en.po (Spanish) 2025-11-05 13:06:57 -05:00
hank
6e9bc6a53b New translations en.po (French) 2025-11-05 10:16:19 -05:00
hank
12eb884b1e New translations en.po (Indonesian) 2025-11-04 18:47:36 -05:00
hank
270afa1c00 New translations en.po (Hebrew) 2025-11-04 18:47:35 -05:00
hank
35505f2d50 New translations en.po (Chinese Traditional, Hong Kong) 2025-11-04 18:47:34 -05:00
hank
5a28ba3a74 New translations en.po (Persian) 2025-11-04 18:47:33 -05:00
hank
08d9126883 New translations en.po (Vietnamese) 2025-11-04 18:47:32 -05:00
hank
e9829229b6 New translations en.po (Chinese Simplified) 2025-11-04 18:47:31 -05:00
hank
6d7bb7ceee New translations en.po (Ukrainian) 2025-11-04 18:47:30 -05:00
hank
60a8b06b72 New translations en.po (Turkish) 2025-11-04 18:47:29 -05:00
hank
c4a145836b New translations en.po (Swedish) 2025-11-04 18:47:28 -05:00
hank
ea37451c98 New translations en.po (Slovenian) 2025-11-04 18:47:27 -05:00
hank
1faad84cc2 New translations en.po (Russian) 2025-11-04 18:47:26 -05:00
hank
d0b6200c5b New translations en.po (Polish) 2025-11-04 18:47:25 -05:00
hank
fb66760665 New translations en.po (Korean) 2025-11-04 18:47:24 -05:00
hank
480f1596bb New translations en.po (Japanese) 2025-11-04 18:47:23 -05:00
hank
6c11e2954e New translations en.po (Italian) 2025-11-04 18:47:22 -05:00
hank
6a5f6530ef New translations en.po (Danish) 2025-11-04 18:47:21 -05:00
hank
a4ee88bf7f New translations en.po (Czech) 2025-11-04 18:47:20 -05:00
hank
d9f1f06b15 New translations en.po (Bulgarian) 2025-11-04 18:47:19 -05:00
hank
4c00988a37 New translations en.po (Arabic) 2025-11-04 18:47:18 -05:00
hank
193fbe9d31 New translations en.po (Spanish) 2025-11-04 18:47:17 -05:00
hank
ca6b6394ef New translations en.po (Romanian) 2025-11-04 18:47:16 -05:00
hank
1600b94846 New translations en.po (Croatian) 2025-11-04 18:47:15 -05:00
hank
b5aa66224a New translations en.po (Chinese Traditional) 2025-11-04 18:47:15 -05:00
hank
5a14eafae5 New translations en.po (Portuguese) 2025-11-04 18:47:14 -05:00
hank
0b11dcdb1b New translations en.po (Norwegian) 2025-11-04 18:47:13 -05:00
hank
fc1c135e71 New translations en.po (Dutch) 2025-11-04 18:47:12 -05:00
hank
7cb6966335 New translations en.po (Hungarian) 2025-11-04 18:47:11 -05:00
hank
c090cf9e3e New translations en.po (German) 2025-11-04 18:47:10 -05:00
hank
224bce7616 New translations en.po (French) 2025-11-04 18:47:09 -05:00
hank
7fc3afb82b New translations en.po (Spanish) 2025-11-04 17:13:09 -05:00
hank
affdd66065 New translations en.po (Portuguese) 2025-11-04 17:13:06 -05:00
hank
466c5a237b New translations en.po (Portuguese) 2025-11-02 10:12:47 -05:00
hank
827758c97f New translations en.po (Spanish) 2025-11-02 01:32:54 -05:00
hank
fb4a35b054 New translations en.po (Indonesian) 2025-11-01 15:01:34 -04:00
hank
ba561ec34c New translations en.po (Hebrew) 2025-11-01 15:01:33 -04:00
hank
a94f85794c New translations en.po (Chinese Traditional, Hong Kong) 2025-11-01 15:01:32 -04:00
hank
aa408f82c6 New translations en.po (Persian) 2025-11-01 15:01:31 -04:00
hank
e8045a3438 New translations en.po (Vietnamese) 2025-11-01 15:01:30 -04:00
hank
7afd678f54 New translations en.po (Chinese Simplified) 2025-11-01 15:01:28 -04:00
hank
77e2b98470 New translations en.po (Ukrainian) 2025-11-01 15:01:27 -04:00
hank
70e894caf4 New translations en.po (Turkish) 2025-11-01 15:01:26 -04:00
hank
433bd6dde1 New translations en.po (Swedish) 2025-11-01 15:01:25 -04:00
hank
f60ee6a839 New translations en.po (Slovenian) 2025-11-01 15:01:24 -04:00
hank
56e6dbf0a8 New translations en.po (Russian) 2025-11-01 15:01:23 -04:00
hank
7ae179764d New translations en.po (Polish) 2025-11-01 15:01:22 -04:00
hank
e54cac2c7b New translations en.po (Korean) 2025-11-01 15:01:21 -04:00
hank
6bc8878408 New translations en.po (Japanese) 2025-11-01 15:01:20 -04:00
hank
0f6d85f124 New translations en.po (Italian) 2025-11-01 15:01:19 -04:00
hank
b6717c11ae New translations en.po (Danish) 2025-11-01 15:01:18 -04:00
hank
3cff9ccff8 New translations en.po (Czech) 2025-11-01 15:01:17 -04:00
hank
3fb5f065b8 New translations en.po (Bulgarian) 2025-11-01 15:01:16 -04:00
hank
73e397abbf New translations en.po (Arabic) 2025-11-01 15:01:15 -04:00
hank
38f63b02bd New translations en.po (Spanish) 2025-11-01 15:01:14 -04:00
hank
879e84bb34 New translations en.po (Romanian) 2025-11-01 15:01:13 -04:00
hank
79b709d53c New translations en.po (Croatian) 2025-11-01 15:01:12 -04:00
hank
97e188a619 New translations en.po (Chinese Traditional) 2025-11-01 15:01:11 -04:00
hank
9459b59b14 New translations en.po (Portuguese) 2025-11-01 15:01:10 -04:00
hank
c281a0717f New translations en.po (Norwegian) 2025-11-01 15:01:09 -04:00
hank
b274261d3e New translations en.po (Dutch) 2025-11-01 15:01:08 -04:00
hank
63a78f2829 New translations en.po (Hungarian) 2025-11-01 15:01:07 -04:00
hank
31aa6df5b2 New translations en.po (German) 2025-11-01 15:01:06 -04:00
hank
74d8f685bd New translations en.po (French) 2025-11-01 15:01:05 -04:00
hank
43a32ef0ce New translations en.po (Spanish) 2025-11-01 13:41:18 -04:00
hank
4426b53f47 New translations en.po (Chinese Traditional) 2025-11-01 03:52:31 -04:00
hank
6902e90ca7 New translations en.po (Hebrew) 2025-10-30 17:53:10 -04:00
hank
9aeb80ce88 New translations en.po (Chinese Simplified) 2025-10-30 17:53:08 -04:00
hank
60c557055f New translations en.po (Italian) 2025-10-30 17:53:02 -04:00
hank
0a6020b6b8 New translations en.po (Arabic) 2025-10-30 17:52:59 -04:00
hank
7f85b8f2a9 New translations en.po (Spanish) 2025-10-30 17:52:58 -04:00
hank
5ca388d855 New translations en.po (Portuguese) 2025-10-30 17:52:56 -04:00
hank
34d74b3bcd New translations en.po (Hebrew) 2025-10-30 16:47:52 -04:00
hank
86ff86aa99 New translations en.po (Indonesian) 2025-10-29 17:56:50 -04:00
hank
d9a463e465 New translations en.po (Hebrew) 2025-10-29 17:56:49 -04:00
hank
a5d0690a81 New translations en.po (Chinese Traditional, Hong Kong) 2025-10-28 19:00:28 -04:00
hank
eef4092b16 New translations en.po (Persian) 2025-10-28 19:00:27 -04:00
hank
a4e89676df New translations en.po (Vietnamese) 2025-10-28 19:00:26 -04:00
hank
3f083686fe New translations en.po (Chinese Simplified) 2025-10-28 19:00:25 -04:00
hank
cf2ccc1eb4 New translations en.po (Ukrainian) 2025-10-28 19:00:24 -04:00
hank
43c44a085b New translations en.po (Turkish) 2025-10-28 19:00:23 -04:00
hank
e90dfde12e New translations en.po (Swedish) 2025-10-28 19:00:22 -04:00
hank
a1bb77f4f2 New translations en.po (Slovenian) 2025-10-28 19:00:21 -04:00
hank
ef582ec1ef New translations en.po (Russian) 2025-10-28 19:00:20 -04:00
hank
2c30bdb2e4 New translations en.po (Polish) 2025-10-28 19:00:19 -04:00
hank
5bfbc0420a New translations en.po (Korean) 2025-10-28 19:00:18 -04:00
hank
b7a3222d31 New translations en.po (Japanese) 2025-10-28 19:00:17 -04:00
hank
d4955af3ba New translations en.po (Italian) 2025-10-28 19:00:16 -04:00
hank
bde88dda26 New translations en.po (Danish) 2025-10-28 19:00:14 -04:00
hank
3f51bd5ec6 New translations en.po (Czech) 2025-10-28 19:00:13 -04:00
hank
092e8c9948 New translations en.po (Bulgarian) 2025-10-28 19:00:11 -04:00
hank
c35762de98 New translations en.po (Arabic) 2025-10-28 19:00:10 -04:00
hank
7c43e9e27c New translations en.po (Spanish) 2025-10-28 19:00:09 -04:00
hank
ee07a0d181 New translations en.po (Romanian) 2025-10-28 19:00:06 -04:00
hank
3178587f20 New translations en.po (Croatian) 2025-10-28 19:00:05 -04:00
hank
b07a791d6a New translations en.po (Chinese Traditional) 2025-10-28 19:00:03 -04:00
hank
8b6918b4a5 New translations en.po (Portuguese) 2025-10-28 19:00:02 -04:00
hank
c7733146b7 New translations en.po (Norwegian) 2025-10-28 19:00:01 -04:00
hank
8f23bbd436 New translations en.po (Dutch) 2025-10-28 18:59:59 -04:00
hank
7ca3cca15d New translations en.po (Hungarian) 2025-10-28 18:59:58 -04:00
hank
dd553ec7b6 New translations en.po (German) 2025-10-28 18:59:57 -04:00
hank
1a8dd0ab32 New translations en.po (French) 2025-10-28 18:59:56 -04:00
hank
48e0c1efbf New translations en.po (German) 2025-10-27 19:49:39 -04:00
hank
8cdddc9f5e New translations en.po (Spanish) 2025-10-27 14:01:40 -04:00
hank
756c5eab3e New translations en.po (Italian) 2025-10-26 22:07:18 -04:00
hank
cf8102d547 New translations en.po (Danish) 2025-10-26 15:21:12 -04:00
hank
156a54f26c New translations en.po (Polish) 2025-10-26 05:04:19 -04:00
hank
ad1e7772af New translations en.po (Chinese Traditional, Hong Kong) 2025-10-25 19:16:37 -04:00
hank
62edf55a37 New translations en.po (Persian) 2025-10-25 19:16:36 -04:00
hank
223b627619 New translations en.po (Vietnamese) 2025-10-25 19:16:35 -04:00
hank
d3bc1a6764 New translations en.po (Chinese Simplified) 2025-10-25 19:16:34 -04:00
hank
5157144504 New translations en.po (Ukrainian) 2025-10-25 19:16:33 -04:00
hank
cdb396408f New translations en.po (Turkish) 2025-10-25 19:16:32 -04:00
hank
ca7c68140a New translations en.po (Swedish) 2025-10-25 19:16:31 -04:00
hank
5af7afb970 New translations en.po (Slovenian) 2025-10-25 19:16:30 -04:00
hank
fd053fc8e5 New translations en.po (Russian) 2025-10-25 19:16:29 -04:00
hank
f1f01657c0 New translations en.po (Polish) 2025-10-25 19:16:28 -04:00
hank
1c9f03c848 New translations en.po (Korean) 2025-10-25 19:16:27 -04:00
hank
82b5ee0424 New translations en.po (Japanese) 2025-10-25 19:16:26 -04:00
hank
0885bf2ba4 New translations en.po (Italian) 2025-10-25 19:16:25 -04:00
hank
d541b42bef New translations en.po (Danish) 2025-10-25 19:16:24 -04:00
hank
29599cd59c New translations en.po (Czech) 2025-10-25 19:16:23 -04:00
hank
5fff9bd3ac New translations en.po (Bulgarian) 2025-10-25 19:16:22 -04:00
hank
81b6198ee7 New translations en.po (Arabic) 2025-10-25 19:16:21 -04:00
hank
01f58a328e New translations en.po (Spanish) 2025-10-25 19:16:20 -04:00
hank
6ffef3c33b New translations en.po (Romanian) 2025-10-25 19:16:19 -04:00
hank
3d50d0cbba New translations en.po (Croatian) 2025-10-25 19:16:18 -04:00
hank
a8ec54f5a5 New translations en.po (Chinese Traditional) 2025-10-25 19:16:17 -04:00
hank
3c44f51671 New translations en.po (Portuguese) 2025-10-25 19:16:16 -04:00
hank
449642fdd2 New translations en.po (Norwegian) 2025-10-25 19:16:15 -04:00
hank
bb324258d6 New translations en.po (Dutch) 2025-10-25 19:16:14 -04:00
hank
693117724a New translations en.po (Hungarian) 2025-10-25 19:16:13 -04:00
hank
008dd9d184 New translations en.po (German) 2025-10-25 19:16:12 -04:00
hank
f171ec9932 New translations en.po (French) 2025-10-25 19:16:11 -04:00
hank
9e6e1771d1 New translations en.po (Chinese Simplified) 2025-10-25 17:09:25 -04:00
hank
bde6264d11 New translations en.po (Spanish) 2025-10-25 17:09:17 -04:00
hank
ae61acbedd New translations en.po (German) 2025-10-25 17:09:12 -04:00
hank
af392c8084 New translations en.po (French) 2025-10-25 16:53:16 -04:00
hank
ce8d206004 New translations en.po (Danish) 2025-10-25 06:58:38 -04:00
hank
5a15e7c048 New translations en.po (Danish) 2025-10-25 05:58:43 -04:00
hank
3a360f3ede New translations en.po (Spanish) 2025-10-24 13:47:34 -04:00
hank
7cf2493af7 New translations en.po (Spanish) 2025-10-24 12:17:55 -04:00
hank
d71a0083bb New translations en.po (Chinese Simplified) 2025-10-23 15:40:46 -04:00
hank
6f6aeeb315 New translations en.po (Danish) 2025-10-22 19:14:03 -04:00
hank
7845d25c83 New translations en.po (Danish) 2025-10-22 17:51:32 -04:00
hank
3320707567 New translations en.po (Danish) 2025-10-22 14:17:32 -04:00
hank
e0df2a1e60 New translations en.po (Norwegian) 2025-10-22 06:37:12 -04:00
hank
881c0cd137 New translations en.po (German) 2025-10-22 06:37:11 -04:00
hank
5bde9500b6 New translations en.po (French) 2025-10-21 06:28:47 -04:00
hank
b43541ea60 New translations en.po (German) 2025-10-21 04:08:22 -04:00
hank
339e443bca New translations en.po (Chinese Traditional, Hong Kong) 2025-10-20 17:37:43 -04:00
hank
8643fb2fd5 New translations en.po (Persian) 2025-10-20 17:37:42 -04:00
hank
8dcf03fb15 New translations en.po (Vietnamese) 2025-10-20 17:37:41 -04:00
hank
53c3b0c359 New translations en.po (Chinese Simplified) 2025-10-20 17:37:40 -04:00
hank
1701947b26 New translations en.po (Ukrainian) 2025-10-20 17:37:39 -04:00
hank
c8cb041855 New translations en.po (Turkish) 2025-10-20 17:37:38 -04:00
hank
032d06601e New translations en.po (Swedish) 2025-10-20 17:37:37 -04:00
hank
1507825c16 New translations en.po (Slovenian) 2025-10-20 17:37:36 -04:00
hank
073fc308bb New translations en.po (Russian) 2025-10-20 17:37:35 -04:00
hank
9d5aaaf989 New translations en.po (Polish) 2025-10-20 17:37:34 -04:00
hank
0f6063ebe5 New translations en.po (Korean) 2025-10-20 17:37:33 -04:00
hank
742c217b5f New translations en.po (Japanese) 2025-10-20 17:37:32 -04:00
hank
85589e1e07 New translations en.po (Italian) 2025-10-20 17:37:31 -04:00
hank
6ceb58254b New translations en.po (Greek) 2025-10-20 17:37:30 -04:00
hank
10e21993ce New translations en.po (Danish) 2025-10-20 17:37:29 -04:00
hank
ccff653ef1 New translations en.po (Czech) 2025-10-20 17:37:28 -04:00
hank
323705aced New translations en.po (Bulgarian) 2025-10-20 17:37:27 -04:00
hank
774ddaa726 New translations en.po (Arabic) 2025-10-20 17:37:26 -04:00
hank
e75ada4483 New translations en.po (Spanish) 2025-10-20 17:37:24 -04:00
hank
14e8b28b85 New translations en.po (Romanian) 2025-10-20 17:37:24 -04:00
hank
1f7f764fca New translations en.po (Croatian) 2025-10-20 17:37:23 -04:00
hank
2757e51040 New translations en.po (Chinese Traditional) 2025-10-20 17:37:22 -04:00
hank
1233e6bee6 New translations en.po (Portuguese) 2025-10-20 17:37:21 -04:00
hank
e4619b303e New translations en.po (Norwegian) 2025-10-20 17:37:20 -04:00
hank
3abb7a2a29 New translations en.po (Dutch) 2025-10-20 17:37:19 -04:00
hank
045c3cfdf8 New translations en.po (Hungarian) 2025-10-20 17:37:18 -04:00
hank
4b5e1cc5fa New translations en.po (German) 2025-10-20 17:37:17 -04:00
hank
7600a47d08 New translations en.po (French) 2025-10-20 17:37:16 -04:00
hank
47827c09f6 New translations en.po (French) 2025-10-20 12:38:50 -04:00
hank
c8c84ca0ad New translations en.po (French) 2025-10-20 11:14:32 -04:00
hank
309860f9d0 New translations en.po (Chinese Traditional, Hong Kong) 2025-10-18 19:59:24 -04:00
hank
2a76cf4a1f New translations en.po (Persian) 2025-10-18 19:59:23 -04:00
hank
6d6b6891e1 New translations en.po (Vietnamese) 2025-10-18 19:59:22 -04:00
hank
bdd24b95d2 New translations en.po (Chinese Simplified) 2025-10-18 19:59:21 -04:00
hank
9ae2bee9e3 New translations en.po (Ukrainian) 2025-10-18 19:59:20 -04:00
hank
b2396de0d9 New translations en.po (Turkish) 2025-10-18 19:59:19 -04:00
hank
d85e3bc26f New translations en.po (Swedish) 2025-10-18 19:59:18 -04:00
hank
2a3220be5a New translations en.po (Slovenian) 2025-10-18 19:59:17 -04:00
hank
92910faca0 New translations en.po (Russian) 2025-10-18 19:59:16 -04:00
hank
d596474426 New translations en.po (Polish) 2025-10-18 19:59:15 -04:00
hank
db471ea619 New translations en.po (Korean) 2025-10-18 19:59:13 -04:00
hank
f6e30b1c9f New translations en.po (Japanese) 2025-10-18 19:59:13 -04:00
hank
dcc013330e New translations en.po (Italian) 2025-10-18 19:59:12 -04:00
hank
d6feda8a91 New translations en.po (Greek) 2025-10-18 19:59:11 -04:00
hank
310892d401 New translations en.po (Danish) 2025-10-18 19:59:09 -04:00
hank
302e951bb9 New translations en.po (Czech) 2025-10-18 19:59:08 -04:00
hank
6810270f51 New translations en.po (Bulgarian) 2025-10-18 19:59:07 -04:00
hank
1403f75781 New translations en.po (Arabic) 2025-10-18 19:59:06 -04:00
hank
660a7967f8 New translations en.po (Spanish) 2025-10-18 19:59:05 -04:00
hank
5ad420a6bc New translations en.po (Romanian) 2025-10-18 19:59:04 -04:00
hank
7403f67109 New translations en.po (Croatian) 2025-10-18 19:59:03 -04:00
hank
626b865c3b New translations en.po (Chinese Traditional) 2025-10-18 19:59:02 -04:00
hank
ebbddef0d9 New translations en.po (Portuguese) 2025-10-18 19:59:01 -04:00
hank
a528ddfea3 New translations en.po (Norwegian) 2025-10-18 19:59:00 -04:00
hank
9c6a4873b2 New translations en.po (Dutch) 2025-10-18 19:58:59 -04:00
hank
82e976ff0b New translations en.po (Hungarian) 2025-10-18 19:58:58 -04:00
hank
5342f2cbbc New translations en.po (German) 2025-10-18 19:58:57 -04:00
hank
c7838f744f New translations en.po (French) 2025-10-18 19:58:56 -04:00
hank
74e41851cf New translations en.po (Croatian) 2025-10-18 18:52:43 -04:00
hank
f1342a305c New translations en.po (Hungarian) 2025-10-14 19:40:36 -04:00
hank
7f926c687b New translations en.po (Hungarian) 2025-10-14 16:31:25 -04:00
hank
496cc67390 New translations en.po (Hungarian) 2025-10-14 15:16:43 -04:00
hank
e4b300bc71 New translations en.po (Hungarian) 2025-10-14 14:15:05 -04:00
hank
cee20d701a New translations en.po (Norwegian) 2025-10-13 13:31:12 -04:00
hank
0cd5f3696d New translations en.po (Norwegian) 2025-10-13 11:54:15 -04:00
hank
3686df0f9d New translations en.po (Chinese Traditional) 2025-10-11 23:15:08 -04:00
hank
f58f555367 New translations en.po (French) 2025-10-09 18:25:14 -04:00
hank
adfa14ccbe New translations en.po (Portuguese) 2025-10-09 08:03:07 -04:00
hank
26a147e2e5 New translations en.po (Norwegian) 2025-10-06 03:37:07 -04:00
hank
b9a74e1284 New translations en.po (German) 2025-10-05 12:13:24 -04:00
hank
21d2b3ec7b New translations en.po (Romanian) 2025-10-03 14:42:32 -04:00
hank
69d94b0bf9 New translations en.po (Chinese Traditional, Hong Kong) 2025-10-03 14:42:31 -04:00
hank
5e49fca60e New translations en.po (Croatian) 2025-10-03 14:42:30 -04:00
hank
9babff17d1 New translations en.po (Persian) 2025-10-03 14:42:29 -04:00
hank
be86983f00 New translations en.po (Vietnamese) 2025-10-03 14:42:28 -04:00
hank
907bb4dc52 New translations en.po (Chinese Traditional) 2025-10-03 14:42:27 -04:00
hank
9a34a3700d New translations en.po (Chinese Simplified) 2025-10-03 14:42:26 -04:00
hank
fdb468abf4 New translations en.po (Ukrainian) 2025-10-03 14:42:25 -04:00
hank
0de0326778 New translations en.po (Turkish) 2025-10-03 14:42:24 -04:00
hank
30db58b94f New translations en.po (Swedish) 2025-10-03 14:42:23 -04:00
hank
8e40b1013b New translations en.po (Slovenian) 2025-10-03 14:42:22 -04:00
hank
aa96521696 New translations en.po (Russian) 2025-10-03 14:42:21 -04:00
hank
17f40d58ac New translations en.po (Portuguese) 2025-10-03 14:42:20 -04:00
hank
bdcdda4e9c New translations en.po (Polish) 2025-10-03 14:42:18 -04:00
hank
c36d57f962 New translations en.po (Norwegian) 2025-10-03 14:42:17 -04:00
hank
542ac4bfc0 New translations en.po (Dutch) 2025-10-03 14:42:16 -04:00
hank
68a684f3d6 New translations en.po (Korean) 2025-10-03 14:42:15 -04:00
hank
b9bcb372f7 New translations en.po (Japanese) 2025-10-03 14:42:14 -04:00
hank
3d94451124 New translations en.po (Italian) 2025-10-03 14:42:13 -04:00
hank
0af952d66c New translations en.po (Hungarian) 2025-10-03 14:42:12 -04:00
hank
e46bc1ee36 New translations en.po (Greek) 2025-10-03 14:42:11 -04:00
hank
5d297be871 New translations en.po (German) 2025-10-03 14:42:10 -04:00
hank
6c0bc90f96 New translations en.po (Danish) 2025-10-03 14:42:09 -04:00
hank
db0b6f77e3 New translations en.po (Czech) 2025-10-03 14:42:08 -04:00
hank
7f42ab68d2 New translations en.po (Bulgarian) 2025-10-03 14:42:07 -04:00
hank
c4f6e81c56 New translations en.po (Arabic) 2025-10-03 14:42:06 -04:00
hank
3bf595959b New translations en.po (Spanish) 2025-10-03 14:42:05 -04:00
hank
5af1e058b0 New translations en.po (French) 2025-10-03 14:42:03 -04:00
hank
ec62d1597b New translations en.po (Romanian) 2025-10-03 13:07:14 -04:00
hank
fa06a2935b New translations en.po (Russian) 2025-09-28 03:31:06 -04:00
hank
2cdd521a10 New translations en.po (Portuguese) 2025-09-26 15:48:54 -04:00
hank
90ac853e4f New translations en.po (Slovenian) 2025-09-25 13:11:54 -04:00
hank
007fe0c0af New translations en.po (Croatian) 2025-09-24 18:31:13 -04:00
hank
f3afcd351a New translations en.po (Chinese Traditional) 2025-09-24 18:31:12 -04:00
hank
8eb161171e New translations en.po (Chinese Simplified) 2025-09-24 18:31:11 -04:00
hank
413f829107 New translations en.po (Croatian) 2025-09-23 08:43:25 -04:00
hank
7f09474f33 New translations en.po (Korean) 2025-09-22 22:45:02 -04:00
hank
28386c58db New translations en.po (Chinese Traditional, Hong Kong) 2025-09-22 19:10:36 -04:00
hank
e79aae7925 New translations en.po (Croatian) 2025-09-22 19:10:35 -04:00
hank
fabadf998b New translations en.po (Persian) 2025-09-22 19:10:34 -04:00
hank
2f0d158ed8 New translations en.po (Icelandic) 2025-09-22 19:10:33 -04:00
hank
b5f08d4e4c New translations en.po (Vietnamese) 2025-09-22 19:10:32 -04:00
hank
fce10da7f6 New translations en.po (Chinese Traditional) 2025-09-22 19:10:31 -04:00
hank
d59937dba7 New translations en.po (Chinese Simplified) 2025-09-22 19:10:30 -04:00
hank
0eb2bfab12 New translations en.po (Ukrainian) 2025-09-22 19:10:29 -04:00
hank
bb4111671f New translations en.po (Turkish) 2025-09-22 19:10:28 -04:00
hank
5e50d791fd New translations en.po (Swedish) 2025-09-22 19:10:27 -04:00
hank
cfaf0712d6 New translations en.po (Slovenian) 2025-09-22 19:10:26 -04:00
hank
9cb2d694fe New translations en.po (Russian) 2025-09-22 19:10:25 -04:00
hank
9f4c6b30d8 New translations en.po (Portuguese) 2025-09-22 19:10:24 -04:00
hank
b9055a5d22 New translations en.po (Polish) 2025-09-22 19:10:23 -04:00
hank
aa0d1e7f61 New translations en.po (Norwegian) 2025-09-22 19:10:22 -04:00
hank
35a8cb1d36 New translations en.po (Dutch) 2025-09-22 19:10:21 -04:00
hank
92ba8a0ca3 New translations en.po (Korean) 2025-09-22 19:10:20 -04:00
hank
acbc02162f New translations en.po (Japanese) 2025-09-22 19:10:19 -04:00
hank
8da777b6f4 New translations en.po (Italian) 2025-09-22 19:10:18 -04:00
hank
e62ec1d993 New translations en.po (Hungarian) 2025-09-22 19:10:16 -04:00
hank
4fa11b4c79 New translations en.po (Greek) 2025-09-22 19:10:15 -04:00
hank
c9dba873ee New translations en.po (German) 2025-09-22 19:10:14 -04:00
hank
3e2e897f34 New translations en.po (Danish) 2025-09-22 19:10:13 -04:00
hank
9658fba5aa New translations en.po (Czech) 2025-09-22 19:10:12 -04:00
hank
1c00c39eac New translations en.po (Bulgarian) 2025-09-22 19:10:11 -04:00
hank
2d3f186c18 New translations en.po (Arabic) 2025-09-22 19:10:10 -04:00
hank
983a471e6f New translations en.po (Spanish) 2025-09-22 19:10:08 -04:00
hank
7a228f553c New translations en.po (French) 2025-09-22 19:10:08 -04:00
hank
007dfa9519 New translations en.po (Dutch) 2025-09-21 14:30:42 -04:00
hank
f3a74b1f46 New translations en.po (Polish) 2025-09-18 11:36:03 -04:00
hank
4a76b620e7 New translations en.po (Polish) 2025-09-18 08:40:40 -04:00
hank
25210d031d New translations en.po (Chinese Traditional, Hong Kong) 2025-09-17 14:45:45 -04:00
hank
87b55fd4cf New translations en.po (Croatian) 2025-09-17 14:45:44 -04:00
hank
b4430ac76f New translations en.po (Persian) 2025-09-17 14:45:43 -04:00
hank
5f9aa78b72 New translations en.po (Icelandic) 2025-09-17 14:45:42 -04:00
hank
7537f6bd5c New translations en.po (Vietnamese) 2025-09-17 14:45:41 -04:00
hank
83dee5e554 New translations en.po (Chinese Traditional) 2025-09-17 14:45:40 -04:00
hank
036b4495e6 New translations en.po (Chinese Simplified) 2025-09-17 14:45:39 -04:00
hank
31cd36fcc1 New translations en.po (Ukrainian) 2025-09-17 14:45:38 -04:00
hank
0a2aaf3260 New translations en.po (Turkish) 2025-09-17 14:45:36 -04:00
hank
6e2e90120a New translations en.po (Swedish) 2025-09-17 14:45:35 -04:00
hank
23f95d6ebd New translations en.po (Slovenian) 2025-09-17 14:45:35 -04:00
hank
56dc1096d9 New translations en.po (Russian) 2025-09-17 14:45:34 -04:00
hank
9dd203f85a New translations en.po (Portuguese) 2025-09-17 14:45:32 -04:00
hank
adac9cf79d New translations en.po (Polish) 2025-09-17 14:45:31 -04:00
hank
efd2ba04c5 New translations en.po (Norwegian) 2025-09-17 14:45:30 -04:00
hank
a9055e216d New translations en.po (Dutch) 2025-09-17 14:45:29 -04:00
hank
f64130029b New translations en.po (Korean) 2025-09-17 14:45:28 -04:00
hank
6d172bac82 New translations en.po (Japanese) 2025-09-17 14:45:27 -04:00
hank
354cba5690 New translations en.po (Italian) 2025-09-17 14:45:26 -04:00
hank
e65cde9675 New translations en.po (Hungarian) 2025-09-17 14:45:25 -04:00
hank
fbd2fbb6a6 New translations en.po (Greek) 2025-09-17 14:45:24 -04:00
hank
01bf64083a New translations en.po (German) 2025-09-17 14:45:23 -04:00
hank
103856121d New translations en.po (Danish) 2025-09-17 14:45:21 -04:00
hank
8a798c7e3f New translations en.po (Czech) 2025-09-17 14:45:20 -04:00
hank
beeec5c39e New translations en.po (Bulgarian) 2025-09-17 14:45:19 -04:00
hank
6d43045d79 New translations en.po (Arabic) 2025-09-17 14:45:18 -04:00
hank
88ea94f5b0 New translations en.po (Spanish) 2025-09-17 14:45:17 -04:00
hank
3b8d333f8e New translations en.po (French) 2025-09-17 14:45:16 -04:00
hank
3a06982502 New translations en.po (Chinese Simplified) 2025-09-17 01:21:38 -04:00
hank
b820b46042 New translations en.po (Polish) 2025-09-14 04:46:36 -04:00
hank
fab799f177 New translations en.po (Chinese Traditional, Hong Kong) 2025-09-11 12:53:01 -04:00
hank
5eaf9b9157 New translations en.po (Croatian) 2025-09-11 12:53:00 -04:00
hank
1eed3c53c8 New translations en.po (Persian) 2025-09-11 12:52:59 -04:00
hank
90729a7a95 New translations en.po (Icelandic) 2025-09-11 12:52:58 -04:00
hank
d450f6df10 New translations en.po (Vietnamese) 2025-09-11 12:52:57 -04:00
hank
7aa2bcf761 New translations en.po (Chinese Traditional) 2025-09-11 12:52:55 -04:00
hank
a7a86f46c3 New translations en.po (Chinese Simplified) 2025-09-11 12:52:54 -04:00
hank
17e30aff60 New translations en.po (Ukrainian) 2025-09-11 12:52:53 -04:00
hank
66008e47f3 New translations en.po (Turkish) 2025-09-11 12:52:52 -04:00
hank
56788b1e5b New translations en.po (Swedish) 2025-09-11 12:52:51 -04:00
hank
b72371487a New translations en.po (Slovenian) 2025-09-11 12:52:50 -04:00
hank
7656b4189e New translations en.po (Russian) 2025-09-11 12:52:49 -04:00
hank
8e6731c102 New translations en.po (Portuguese) 2025-09-11 12:52:48 -04:00
hank
e86fa40fe4 New translations en.po (Polish) 2025-09-11 12:52:46 -04:00
hank
f0e728a1ed New translations en.po (Norwegian) 2025-09-11 12:52:45 -04:00
hank
bb076eb439 New translations en.po (Dutch) 2025-09-11 12:52:44 -04:00
hank
2f0b16367a New translations en.po (Korean) 2025-09-11 12:52:43 -04:00
hank
aa33124e18 New translations en.po (Japanese) 2025-09-11 12:52:42 -04:00
hank
42f404c80a New translations en.po (Italian) 2025-09-11 12:52:41 -04:00
hank
5056fddd40 New translations en.po (Hungarian) 2025-09-11 12:52:40 -04:00
hank
2296202ea1 New translations en.po (Greek) 2025-09-11 12:52:39 -04:00
hank
c034e9b0fa New translations en.po (German) 2025-09-11 12:52:38 -04:00
hank
2d45119a98 New translations en.po (Danish) 2025-09-11 12:52:36 -04:00
hank
63be4f1ab5 New translations en.po (Czech) 2025-09-11 12:52:35 -04:00
hank
6d2259100e New translations en.po (Bulgarian) 2025-09-11 12:52:34 -04:00
hank
142af6e7b6 New translations en.po (Arabic) 2025-09-11 12:52:33 -04:00
hank
5c1e009188 New translations en.po (Spanish) 2025-09-11 12:52:32 -04:00
hank
27b2cb84d6 New translations en.po (French) 2025-09-11 12:52:31 -04:00
hank
8db87e5497 Update Crowdin configuration file 2025-09-11 12:45:43 -04:00
henrygd
e601a0d564 add TRUSTED_AUTH_HEADER for auth forwarding (#399) 2025-09-10 21:26:59 -04:00
Fankesyooni
07491108cd new zh-CN translations (#1160) 2025-09-10 13:34:17 -04:00
henrygd
42ab17de1f move i18n.yml to project root 2025-09-10 13:30:42 -04:00
henrygd
2d14174f61 update i18n.yml 2025-09-10 13:28:06 -04:00
henrygd
a19ccc9263 comments 2025-09-09 17:13:15 -04:00
henrygd
956880aa59 improve container filtering performance
- also a few instances of autoformat
2025-09-09 16:59:16 -04:00
henrygd
b2b54db409 update makefile with proper site src path 2025-09-09 15:41:15 -04:00
henrygd
32d5188eef path updates after reorganization 2025-09-09 13:53:36 -04:00
henrygd
46dab7f531 fix gitignore after reorganization 2025-09-09 13:51:46 -04:00
henrygd
c898a9ebbc update /src to /internal 2025-09-09 13:35:34 -04:00
henrygd
8a13b05c20 rename /src to /internal (sorry i'll fix the prs) 2025-09-09 13:29:07 -04:00
henrygd
86ea23fe39 refactor install-agent.sh for freebsd
- Updated paths for FreeBSD installation, changing default directories from /opt/beszel-agent to /usr/local/etc/beszel-agent and /usr/local/sbin.
- Introduced conditional path setting based on the operating system.
- Updated cron job creation to use /etc/cron.d
2025-09-08 19:46:39 -04:00
henrygd
a284dd74dd add time format (12h, 24h) settings (#424)
- Some biome formatting :/
- Changed chartTime update to use listenkeys
2025-09-08 17:12:43 -04:00
Alexander Mnich
6a0075291c [FIX] OpenWRT auto update (#1155)
* switch to root crontab for OpenWRT auto update

* fix: OpenWRT auto update restart condition
2025-09-08 16:50:39 -04:00
henrygd
f542bc70a1 add biome and apply selected formatting / fixes 2025-09-08 15:22:04 -04:00
henrygd
270e59d9ea add support for otp and mfa 2025-09-07 20:46:34 -04:00
henrygd
0d97a604f8 rename main.go to beszel.go 2025-09-07 17:34:56 -04:00
henrygd
f6078fc232 fix govulncheck workflow 2025-09-07 16:52:46 -04:00
henrygd
6f5d95031c update project structure
- move agent to /agent
- change /beszel to /src
- update workflows and docker builds
2025-09-07 16:42:15 -04:00
henrygd
4e26defdca update imports for gh package name 2025-09-07 14:48:39 -04:00
Ayman Nedjmeddine
cda8fa7efd Rename Go module to github.com/henrygd/beszel 2025-09-07 14:29:56 -04:00
henrygd
fd050f2a8f revert to previous version behavior of setting hub.appURL (#1148)
- remove fallback that sets appUrl to settings.Meta.AppURL
- prefer using current browser URL in generated config if APP_URL not set
2025-09-07 14:10:47 -04:00
henrygd
e53d41dcec refactor: launch web url for dev server + css update 2025-09-07 14:10:34 -04:00
Sasha Blue
a1eb15dabb Adding openwrt restart procedure after updating the agent automatically (#1151) 2025-09-07 13:25:23 -04:00
henrygd
eb4bdafbea add freebsd support to agent install script / update command (#39) 2025-09-05 19:15:21 -04:00
Alexander Mnich
fea2330534 fix: avoid goreleaser truthy evaluation (#1146)
Goreleaser performs truthy evaluation on templates. As .Env.IS_FORK is a string the env variable containing a non empty-string already evaluated to true.
2025-09-05 17:25:57 -04:00
henrygd
5e37469ea9 0.12.7 release :) 2025-09-05 14:00:24 -04:00
henrygd
e027479bb1 make sure initial user is verfied when supplying user/pass 2025-09-05 14:00:21 -04:00
henrygd
1597e869c1 update translations 2025-09-05 13:53:17 -04:00
henrygd
862399d8ec update language files 2025-09-05 12:36:45 -04:00
henrygd
f6f85f8f9d Add USER_EMAIL and USER_PASSWORD env vars to set the email / pass of initial user (#1137) 2025-09-05 11:42:43 -04:00
Riedel, Max
e22d7ca801 fix: add nextSystemToken to deps of useEffect to generate a new token after system creation (#1142) 2025-09-05 11:00:32 -04:00
henrygd
c382c1d5f6 windows: make LHM opt-in with LHM=true (#1130) 2025-09-05 10:39:18 -04:00
henrygd
f7618ed6b0 update go version for vulcheck action 2025-09-04 19:17:44 -04:00
henrygd
d1295b7c50 alerts tests and small refactoring 2025-09-04 19:13:10 -04:00
henrygd
a162a54a58 bump go version and add keyword 2025-09-04 19:13:10 -04:00
henrygd
794db0ac6a make sure old names are removed in systemsbyname store 2025-09-04 19:13:10 -04:00
henrygd
e9fb9b856f install script: remove newlines from KEY (#1139) 2025-09-04 11:26:53 -04:00
Sven van Ginkel
66bca11d36 [Bug] Update install script to use crontab on Alpine (#1136)
* add cron

* update the install script
2025-09-03 23:10:38 -04:00
henrygd
86e87f0d47 refactor hub dev server
- moved html replacement functionality from vite to go
2025-09-01 22:16:57 -04:00
henrygd
fadfc5d81d refactor(hub): separate development and production server logic 2025-09-01 19:27:11 -04:00
henrygd
fc39ff1e4d add pflag to go deps 2025-09-01 19:24:26 -04:00
henrygd
82ccfc66e0 refactor: shared container charts config hook 2025-09-01 18:41:30 -04:00
henrygd
890bad1c39 refactor: improve runOnce with weakmap cache 2025-09-01 18:34:29 -04:00
henrygd
9c458885f1 refactor (hub): add systemsManager module
- Removed the `updateSystemList` function and replaced it with a more efficient system management approach using `systemsManager`.
- Updated the `App` component to initialize and subscribe to system updates through the new `systemsManager`.
- Refactored the `SystemsTable` and `SystemDetail` components to utilize the new state management for systems, improving performance and maintainability.
- Enhanced the `ActiveAlerts` component to fetch system names directly from the new state structure.
2025-09-01 17:29:33 -04:00
henrygd
d2aed0dc72 refactor: replace useLocalStorage with useBrowserStorage 2025-09-01 17:28:13 -04:00
Augustin ROLET
3dbcb5d7da Minor UI changes (#1110)
* ui: add devices count from #1078

* ux: save sortMode in localStorage from #1024

* fix: reload component when system switch to "up"

* ux: move running systems to desc field
2025-08-31 18:16:25 -04:00
Alexander Mnich
57a1a8b39e [Feature] improved support for mips and mipsle architectures (#1112)
* switch mipsle to softfloat

* feat: add support for mips
2025-08-30 15:50:15 -04:00
Alexander Mnich
ab81c04569 [Fix] fix GitHub workflow errors in forks (#1113)
* feat: do not run winget/homebrew/scoop release in fork

* fix: replaced deprecated goreleaser fields

https://goreleaser.com/deprecations/#archivesbuilds

* fix: push docker images only with access to the registry
2025-08-30 15:49:49 -04:00
henrygd
0c32be3bea 0.12.6 release :) 2025-08-29 17:24:45 -04:00
henrygd
81d43fbf6e refactor: small style improvements 2025-08-29 17:23:47 -04:00
henrygd
96f441de40 Virtualize All Systems table to improve performance with hundreds of systems (#1100)
- Also truncate long system names in tables and alerts sheet. (#1104)
2025-08-29 16:16:45 -04:00
henrygd
0e95caaee9 update command ui component 2025-08-29 15:04:26 -04:00
Sven van Ginkel
7697a12b42 fix alignment for metrics (#1109) 2025-08-29 14:00:17 -04:00
henrygd
94245a9ba4 fix update mirror and make opt-in with --china-mirrors (#1035) 2025-08-29 13:46:24 -04:00
henrygd
b084814aea auth form: fix border style and add theme toggle 2025-08-28 21:17:44 -04:00
Impact
cce74246ee Use older cuda image for increased compatibility (#1103) 2025-08-28 20:49:52 -04:00
henrygd
a3420b8c67 add max 1 min memory 2025-08-28 20:07:22 -04:00
henrygd
e1bb17ee9e update locale files 2025-08-28 18:23:40 -04:00
henrygd
52983f60b7 refactor: add api module and page preloading 2025-08-28 18:23:24 -04:00
henrygd
1f053fd85d update 2025-08-28 17:31:18 -04:00
Sven van Ginkel
a989d121d3 [Feature] Add Status Filtering to Systems Table (#927) 2025-08-28 17:30:44 -04:00
Sven van Ginkel
50d2406423 [Bug] Fix system table in Safari (#1092)
Co-authored-by: henrygd <hank@henrygd.me>
2025-08-28 12:07:27 -04:00
Sven van Ginkel
059d2d0a5b Add missing os.Chmod step to hub update command (#1093) 2025-08-27 13:00:03 -04:00
henrygd
621bef30b5 update changelog 2025-08-26 21:26:18 -04:00
henrygd
5f4d3dc730 0.12.5 release :) 2025-08-26 21:04:46 -04:00
henrygd
8fa9aece63 change long german translation 2025-08-26 20:50:35 -04:00
henrygd
2f1a022e2a refactor: use width for meters instead of scale 2025-08-26 20:49:31 -04:00
henrygd
4815cd29bc ghupdate: rename plugin struct 2025-08-26 18:41:42 -04:00
henrygd
e49bfaf5d7 downgrade gopsutil to fix freebsd bug (#1083) 2025-08-26 18:40:32 -04:00
henrygd
b13915b76f freebsd: fix battery-related bug (#1081) 2025-08-26 18:39:42 -04:00
henrygd
e2a57dc43b update tooltip component for tailwind 4 2025-08-26 16:16:38 -04:00
henrygd
7222224b40 add battery to supported metrics 2025-08-25 23:15:19 -04:00
henrygd
02ff475b84 improve language toggle selected style 2025-08-25 22:14:48 -04:00
henrygd
09cd8d0db9 add check for battery array length (#1076) 2025-08-25 21:34:34 -04:00
henrygd
36f1a0c53b update synctest.run to synctest.test 2025-08-25 21:25:19 -04:00
henrygd
0b0e94e045 remove pocketbase imports from ghupdate 2025-08-25 21:16:43 -04:00
henrygd
20ca6edf81 0.12.4 release :) 2025-08-25 20:23:38 -04:00
henrygd
1990f8c6df use mirror for asset download in update command (#1035) 2025-08-25 20:18:31 -04:00
henrygd
6e9dbf863f remove rhysd/go-github-selfupdate dependency 2025-08-25 20:05:02 -04:00
henrygd
fa921d77f1 update updater (#1009) 2025-08-25 20:04:23 -04:00
Sven van Ginkel
ff854d481d [Chore] Improve auto update mechanism (#1009) 2025-08-25 17:30:42 -04:00
henrygd
4ce491fe48 i18n: add default machine translations for new strings 2025-08-25 17:02:34 -04:00
henrygd
493bae7eb6 i18n: new battery strings 2025-08-25 16:46:15 -04:00
henrygd
ae5532aa36 new translations 2025-08-25 16:37:20 -04:00
NaNomicon
a1eae6413a New Vietnamese translations 2025-08-25 16:36:41 -04:00
henrygd
ee52bf1fbf New Polish translations by dymek37 2025-08-25 16:32:15 -04:00
Alex van Steenhoven
2ff0bd6b44 New Dutch translations 2025-08-25 16:30:57 -04:00
harupong
a385233b7d New Japanese translations 2025-08-25 16:28:02 -04:00
henrygd
f5648a415d New Italian translations by Tommaso Cavazza 2025-08-25 16:27:35 -04:00
Radoslav Mandev
556fb18953 New Bulgarian translations 2025-08-25 16:26:03 -04:00
henrygd
a482f78739 add changelog 2025-08-25 16:21:07 -04:00
henrygd
4a580ce972 tailwind 4 upgrade + update js deps 2025-08-25 16:12:15 -04:00
henrygd
e07558237f remove dropdown from theme mode toggle 2025-08-25 16:09:49 -04:00
henrygd
fb3c70a1bc update battery charge to include all batteries 2025-08-24 22:34:38 -04:00
henrygd
cba4d60895 improve chart legend alignment 2025-08-24 22:34:26 -04:00
henrygd
8b655ef2b9 add battery charge monitoring 2025-08-24 20:45:38 -04:00
henrygd
0188418055 update go deps 2025-08-24 19:57:40 -04:00
henrygd
72334c42d0 refactor: add @/lib/alerts 2025-08-24 19:57:28 -04:00
henrygd
0638ff3c21 refactor: add subscribe / unsubscribe to alertManager 2025-08-24 19:48:21 -04:00
henrygd
b64318d9e8 fix: frontend token generation in insecure contexts 2025-08-24 17:24:34 -04:00
henrygd
0f5b1b5157 refactor: replace status strings with systemstatus enum
- also small style changes after tailwind update
2025-08-23 20:35:18 -04:00
henrygd
3c4ae46f50 remove usememo return in add system dialog
- forgot to remove this before last commit. interferes with token display.
2025-08-22 20:27:12 -04:00
henrygd
c158b1aeeb move alerts ui to sheet component 2025-08-22 19:28:00 -04:00
henrygd
684d92c497 upgrade to tailwind 4 2025-08-22 18:06:19 -04:00
henrygd
bbd9595ec0 upgrade js dependencies (react 19) 2025-08-22 14:39:48 -04:00
henrygd
bbebb3e301 update Link component to support opening links in new tabs with ctrl/cmd key 2025-08-21 19:00:34 -04:00
henrygd
9d25181d1d use anchor tag for system table links 2025-08-21 18:44:38 -04:00
henrygd
7ba1f366ba remove batch api in favor of custom endpoint for alerts management (#1039, #1023) 2025-08-19 20:56:12 -04:00
henrygd
37c6b920f9 refactor: move useStore above possible return nulls 2025-08-19 20:20:47 -04:00
henrygd
49db81dac8 refactor: api router groups and auth handling
- require auth for `/api/beszel/getkey`
- Change `GET /api/beszel/send-test-notification` endpoint to `POST /api/beszel/test-notification`.
- add tests for API endpoints
2025-08-19 20:14:01 -04:00
henrygd
a9e90ec19c update resolveAlertHistoryRecord params to use alert ID directly 2025-08-19 19:56:51 -04:00
henrygd
2ad60507b7 small style updates 2025-08-19 19:48:25 -04:00
henrygd
12059ee3db refactor: js performance improvements 2025-08-06 22:21:48 -04:00
henrygd
de56544ca3 0.12.3 release :) 2025-08-03 22:10:51 -04:00
henrygd
065c7facb6 update language files 2025-08-03 22:10:25 -04:00
NickAss512
630c92c139 New Czech translations 2025-08-03 21:53:51 -04:00
henrygd
e11d452d91 separate agent dockerfiles 2025-08-03 21:14:43 -04:00
dalton-baker
99c7f7bd8a Add GPU-enabled build target in dockerfile_Agent (nvidia-smi support) (#898) 2025-08-03 13:31:26 -04:00
henrygd
8af3a0eb5b refactor: add getMeterState function 2025-08-02 23:44:07 -04:00
henrygd
5f7950b474 tweaks to custom meter percentages 2025-08-02 20:53:49 -04:00
Sven van Ginkel
df9e2dec28 [Feature] Add custom meter percentages (#942) 2025-08-02 17:58:52 -04:00
henrygd
a0f271545a refactoring (no functionality changes) 2025-08-02 17:04:38 -04:00
Bradley Varol
aa2bc9f118 fix systems table names wrapping (#1027) 2025-08-02 12:28:49 -04:00
henrygd
b22ae87022 disable winget auto pr and reactivate docker workflow 2025-08-01 21:15:37 -04:00
henrygd
79e79079bc fix goreleaser winget token field and temp disable docker workflow 2025-08-01 20:43:33 -04:00
henrygd
1811ebdee4 0.12.2 release :) 2025-08-01 20:36:29 -04:00
henrygd
137f3f3e24 update language files 2025-08-01 20:34:38 -04:00
Mikael Richardsson
ed1d1e77c0 Update Swedish translations 2025-08-01 20:29:02 -04:00
henrygd
8c36dd1caa windows: embed LibreHardwareMonitorLib for better sensors detection
- Updated GitHub Actions release workflow to set up .NET and build the LHM executable.
- Modified Makefile to include a conditional build step for the .NET executable on Windows.
2025-08-01 20:04:40 -04:00
hank
57bfe72486 Update readme.md 2025-07-31 19:43:08 -04:00
henrygd
75f66b0246 fix: handle missing docker group in debian postinstall script (#1012)
Check if docker group exists before attempting to add beszel user to it, preventing installation failure when Docker is not installed.
2025-07-30 19:09:10 -04:00
henrygd
ce93d54aa7 fix agent data directory resolution (#991) 2025-07-30 14:34:36 -04:00
henrygd
39dbe0eac5 ensure /etc/machine-id exists for persistent fingerprint in install-agent.sh 2025-07-30 14:25:41 -04:00
henrygd
7282044f80 improve memo deps for default area chart 2025-07-29 20:53:44 -04:00
henrygd
d77c37c0b0 winget upgrade: make sure service is stopped before updating package 2025-07-29 18:37:34 -04:00
Sven van Ginkel
e362cbbca5 Move copy button (#1010)
Thank you!
2025-07-28 19:20:37 -04:00
evrial
118544926b [Fix] OpenWrt agent install script (#1005)
* Update install-agent.sh

* Update install-agent.sh

* Update install-agent.sh
2025-07-28 14:56:31 -04:00
henrygd
d4bb0a0a30 fix: consolidate OpenWRT environment variables into single procd_set_param call 2025-07-27 18:51:26 -04:00
henrygd
fe5e35d1a9 agent install script: improve openwrt compatibility 2025-07-27 18:44:36 -04:00
henrygd
60a6ae2caa add winget token for goreleaser action 2025-07-25 20:13:31 -04:00
henrygd
80338d36aa release 0.12.1 :) 2025-07-25 19:23:53 -04:00
henrygd
f0d2c242e8 update language files 2025-07-25 19:19:49 -04:00
zoixc
559f83d99c Updated Russian translations 2025-07-25 19:14:08 -04:00
Kamil
d3a751ee6c Updated Polish translations 2025-07-25 19:13:18 -04:00
Sven van Ginkel
fb70a166fa Updated Dutch translations 2025-07-25 19:13:18 -04:00
Alberto Rizzi
c12457b707 Updated Italian translations 2025-07-25 19:08:03 -04:00
Lucas Pedro
3e53d73d56 Updated Portuguese translations 2025-07-25 19:03:45 -04:00
Mikki Alexander Mousing Sørensen
80338c5e98 Updated Danish translations 2025-07-25 19:01:34 -04:00
NickAss512
249cd8ad19 Updated Czech translations
Co-authored-by: Gear <88455107+GearCzech@users.noreply.github.com>
2025-07-25 19:01:34 -04:00
henrygd
ccdff46370 add TOKEN_FILE env var 2025-07-25 18:26:31 -04:00
henrygd
91679b5cc0 refactor load average handling (#982)
- Transitioned from individual load average fields (LoadAvg1, LoadAvg5,
LoadAvg15) to a single array (LoadAvg)
- Ensure load is displayed when all zero values.
2025-07-25 18:07:29 -04:00
henrygd
6953edf59e sort token / fingerprint table by system name 2025-07-25 15:53:40 -04:00
henrygd
b91c77ec92 make sure only 200 records are returned for alert history table 2025-07-25 15:43:19 -04:00
henrygd
3ac0b185d1 fix oidc icon display issue (#990) 2025-07-25 13:55:02 -04:00
henrygd
1e675cabb5 refactor agent data directory resolution (#991) 2025-07-25 13:37:23 -04:00
henrygd
5f44965c2c improve table formatting and fix #983
- should fix NaN display bug for dasboard cpu
- standardize decimals for dash meters
2025-07-25 00:29:08 -04:00
henrygd
f080929296 Update goreleaser configuration
- Removed the name field for brew.
- Enabled pull requests for winget.
2025-07-24 22:31:27 -04:00
henrygd
f055658eba update bun.lockb and package-lock.json 2025-07-24 20:03:19 -04:00
henrygd
e430c747fe 0.12.0 release :) 2025-07-24 19:51:51 -04:00
henrygd
ca62b1db36 update translations 2025-07-24 19:47:25 -04:00
henrygd
38569b7057 update install scripts for 0.12.0 release 2025-07-24 18:39:13 -04:00
henrygd
203244090f update alert history icon 2025-07-24 18:11:39 -04:00
henrygd
2bed722045 add windows upgrade scripts 2025-07-24 17:36:17 -04:00
henrygd
13f3a52760 remove beta scripts from copy/paste commands 2025-07-24 17:35:21 -04:00
henrygd
16b9827c70 bump migration name for 0.12.0 release 2025-07-24 17:35:06 -04:00
henrygd
0fc352d7fc update js deps 2025-07-23 19:51:19 -04:00
凉心
8a2bee11d4 Update viewport meta to prevent input zoom on iOS (#858)
- Prevents page zoom when tapping input fields on iPhone
2025-07-23 19:39:39 -04:00
henrygd
485f7d16ff add tests for agent/client.go and hub/ws/ws.go 2025-07-23 15:54:02 -04:00
henrygd
46fdc94cb8 improve bandwidth measurement precision + refactor default area chart 2025-07-23 15:52:02 -04:00
henrygd
261f7fb76c update go dependencies 2025-07-21 20:14:31 -04:00
henrygd
18d9258907 Alert history updates 2025-07-21 20:07:52 -04:00
Sven van Ginkel
9d7fb8ab80 [Feature] Add Alerts History page (#973)
* Add alert history

* refactor

* fix one colunm

* update migration

* add retention
2025-07-20 19:20:51 -04:00
henrygd
3730a78e5a update load avg display and include it in longer records 2025-07-16 21:24:42 -04:00
Sven van Ginkel
7cdd0907e8 [Feature][0.12.0-Beta] Enhance Load Average Display, Charting & Alert Grouping (#960)
* Add 1m load

* update alart dialog

* fix null data

* Remove omit zero

* change table and alert view
2025-07-16 16:03:26 -04:00
henrygd
3586f73f30 check for malformed sensor names on darwin (#796) 2025-07-16 14:56:13 -04:00
henrygd
752ccc6beb hide tokens page for readonly users 2025-07-16 14:41:23 -04:00
henrygd
f577476c81 clear systems from memory on logout (#970) 2025-07-16 14:39:15 -04:00
henrygd
49ae424698 refactor: consolidate fixedFloat funcs + remove trailing zeroes from y axis 2025-07-15 21:46:41 -04:00
henrygd
d4fd19522b fix races when loading user settings 2025-07-15 21:29:51 -04:00
henrygd
5c047e4afd Refactor unit preferences and update chart components
* Refactor user settings to use enum for unit preferences (temperature,
network, disk).
* Update chart components to utilize new unit formatting functions
* Remove deprecated conversion functions and streamline unit handling
across charts.
* Enhance settings page to allow user selection of unit preferences with
updated labels.
2025-07-15 18:57:37 -04:00
278 changed files with 57519 additions and 23807 deletions

48
.dockerignore Normal file
View 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

View File

@@ -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
@@ -73,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] }}
@@ -87,7 +109,7 @@ jobs:
with:
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 }}

View File

@@ -3,7 +3,7 @@ name: Make release and binaries
on:
push:
tags:
- 'v*'
- "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 || secrets.GITHUB_TOKEN }}
WINGET_TOKEN: ${{ secrets.WINGET_TOKEN }}
IS_FORK: ${{ github.repository_owner != 'henrygd' }}

View File

@@ -15,7 +15,7 @@ permissions:
jobs:
vulncheck:
name: Analysis
name: VulnCheck
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
@@ -23,11 +23,11 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.24.x
cached: false
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 -C ./beszel -show verbose ./...
run: govulncheck -show verbose ./...
shell: bash

11
.gitignore vendored
View File

@@ -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

View File

@@ -9,7 +9,7 @@ before:
builds:
- id: beszel
binary: beszel
main: cmd/hub/hub.go
main: internal/cmd/hub/hub.go
env:
- CGO_ENABLED=0
goos:
@@ -22,7 +22,7 @@ builds:
- id: beszel-agent
binary: beszel-agent
main: cmd/agent/agent.go
main: internal/cmd/agent/agent.go
env:
- CGO_ENABLED=0
goos:
@@ -38,12 +38,25 @@ builds:
- 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
@@ -54,7 +67,7 @@ builds:
archives:
- id: beszel-agent
formats: [tar.gz]
builds:
ids:
- beszel-agent
name_template: >-
{{ .Binary }}_
@@ -66,7 +79,7 @@ archives:
- id: beszel
formats: [tar.gz]
builds:
ids:
- beszel
name_template: >-
{{ .Binary }}_
@@ -85,33 +98,33 @@ nfpms:
API access.
maintainer: henrygd <hank@henrygd.me>
section: net
builds:
ids:
- beszel-agent
formats:
- deb
contents:
- src: ../supplemental/debian/beszel-agent.service
- src: ./supplemental/debian/beszel-agent.service
dst: lib/systemd/system/beszel-agent.service
packager: deb
- src: ../supplemental/debian/copyright
- src: ./supplemental/debian/copyright
dst: usr/share/doc/beszel-agent/copyright
packager: deb
- src: ../supplemental/debian/lintian-overrides
- 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
postinstall: ./supplemental/debian/postinstall.sh
preremove: ./supplemental/debian/prerm.sh
postremove: ./supplemental/debian/postrm.sh
deb:
predepends:
- adduser
- debconf
scripts:
templates: ../supplemental/debian/templates
templates: ./supplemental/debian/templates
# Currently broken due to a bug in goreleaser
# https://github.com/goreleaser/goreleaser/issues/5487
#config: ../supplemental/debian/config.sh
#config: ./supplemental/debian/config.sh
scoops:
- ids: [beszel-agent]
@@ -122,6 +135,7 @@ 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:
@@ -155,7 +169,7 @@ brews:
homepage: "https://beszel.dev"
description: "Agent for Beszel, a lightweight server monitoring platform."
license: MIT
skip_upload: auto
skip_upload: '{{ if eq (tolower .Env.IS_FORK) "true" }}true{{ else }}auto{{ end }}'
extra_install: |
(bin/"beszel-agent-launcher").write <<~EOS
#!/bin/bash
@@ -173,7 +187,6 @@ brews:
error_log_path "#{Dir.home}/.cache/beszel/beszel-agent.log"
keep_alive true
restart_delay 5
name beszel-agent
process_type :background
winget:
@@ -188,7 +201,7 @@ winget:
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: auto
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
@@ -203,13 +216,14 @@ winget:
owner: henrygd
name: beszel-winget
branch: henrygd.beszel-agent-{{ .Version }}
pull_request:
enabled: false
draft: false
base:
owner: microsoft
name: winget-pkgs
branch: master
token: "{{ .Env.WINGET_TOKEN }}"
# pull_request:
# enabled: true
# draft: false
# base:
# owner: microsoft
# name: winget-pkgs
# branch: master
release:
draft: true

102
Makefile Normal file
View 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

View File

@@ -1,9 +1,10 @@
// Package agent handles the agent's SSH server and system stats collection.
// 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 (
"beszel"
"beszel/internal/entities/system"
"crypto/sha256"
"encoding/hex"
"log/slog"
@@ -14,6 +15,8 @@ import (
"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"
)
@@ -40,13 +43,13 @@ type Agent struct {
// 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) {
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)
agent.dataDir, err = getDataDir(dataDir...)
if err != nil {
slog.Warn("Data directory not found")
} else {
@@ -113,37 +116,37 @@ 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
data, isCached := a.cache.Get(sessionID)
if isCached {
slog.Debug("Cached data", "session", sessionID)
return data
}
*cachedData = system.CombinedData{
*data = system.CombinedData{
Stats: a.getSystemStats(),
Info: a.systemInfo,
}
slog.Debug("System stats", "data", cachedData)
slog.Debug("System data", "data", data)
if a.dockerManager != nil {
if containerStats, err := a.dockerManager.getDockerStats(); err == nil {
cachedData.Containers = containerStats
slog.Debug("Docker stats", "data", cachedData.Containers)
data.Containers = containerStats
slog.Debug("Containers", "data", data.Containers)
} else {
slog.Debug("Docker stats", "err", err)
slog.Debug("Containers", "err", err)
}
}
cachedData.Stats.ExtraFs = make(map[string]*system.FsStats)
data.Stats.ExtraFs = make(map[string]*system.FsStats)
for name, stats := range a.fsStats {
if !stats.Root && stats.DiskTotal > 0 {
cachedData.Stats.ExtraFs[name] = stats
data.Stats.ExtraFs[name] = stats
}
}
slog.Debug("Extra filesystems", "data", cachedData.Stats.ExtraFs)
slog.Debug("Extra FS", "data", data.Stats.ExtraFs)
a.cache.Set(sessionID, cachedData)
return cachedData
a.cache.Set(sessionID, data)
return data
}
// StartAgent initializes and starts the agent with optional WebSocket connection

View File

@@ -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

View File

@@ -4,17 +4,18 @@
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{

53
agent/battery/battery.go Normal file
View 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
}

View 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
}

View File

@@ -1,8 +1,6 @@
package agent
import (
"beszel"
"beszel/internal/common"
"crypto/tls"
"errors"
"fmt"
@@ -10,10 +8,14 @@ import (
"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"
@@ -53,9 +55,9 @@ func newWebSocketClient(agent *Agent) (client *WebSocketClient, err error) {
return nil, errors.New("invalid hub URL")
}
// get registration token
client.token, _ = GetEnv("TOKEN")
if client.token == "" {
return nil, errors.New("TOKEN environment variable not set")
client.token, err = getToken()
if err != nil {
return nil, err
}
client.agent = agent
@@ -65,6 +67,27 @@ func newWebSocketClient(agent *Agent) (client *WebSocketClient, err error) {
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 {

540
agent/client_test.go Normal file
View 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")
})
}

View File

@@ -1,13 +1,14 @@
package agent
import (
"beszel/internal/agent/health"
"errors"
"log/slog"
"os"
"os/signal"
"syscall"
"time"
"github.com/henrygd/beszel/agent/health"
)
// ConnectionManager manages the connection state and events for the agent.

View File

@@ -9,35 +9,30 @@ import (
)
// getDataDir returns the path to the data directory for the agent and an error
// if the directory is not valid. Pass an empty string to attempt to find the
// optimal data directory.
func getDataDir(dataDir string) (string, error) {
if dataDir == "" {
dataDir, _ = GetEnv("DATA_DIR")
// 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 != "" {
return testDataDirs([]string{dataDir})
dataDirs = append(dataDirs, dataDir)
}
var dirsToTry []string
if runtime.GOOS == "windows" {
dirsToTry = []string{
dataDirs = append(dataDirs,
filepath.Join(os.Getenv("APPDATA"), "beszel-agent"),
filepath.Join(os.Getenv("LOCALAPPDATA"), "beszel-agent"),
}
)
} else {
homeDir, err := os.UserHomeDir()
if err != nil {
return "", err
}
dirsToTry = []string{
"/var/lib/beszel-agent",
filepath.Join(homeDir, ".config", "beszel"),
dataDirs = append(dataDirs, "/var/lib/beszel-agent")
if homeDir, err := os.UserHomeDir(); err == nil {
dataDirs = append(dataDirs, filepath.Join(homeDir, ".config", "beszel"))
}
}
return testDataDirs(dirsToTry)
return testDataDirs(dataDirs)
}
func testDataDirs(paths []string) (string, error) {

View File

@@ -44,15 +44,15 @@ func TestGetDataDir(t *testing.T) {
oldValue := os.Getenv("DATA_DIR")
defer func() {
if oldValue == "" {
os.Unsetenv("DATA_DIR")
os.Unsetenv("BESZEL_AGENT_DATA_DIR")
} else {
os.Setenv("DATA_DIR", oldValue)
os.Setenv("BESZEL_AGENT_DATA_DIR", oldValue)
}
}()
os.Setenv("DATA_DIR", tempDir)
os.Setenv("BESZEL_AGENT_DATA_DIR", tempDir)
result, err := getDataDir("")
result, err := getDataDir()
require.NoError(t, err)
assert.Equal(t, tempDir, result)
})
@@ -79,7 +79,7 @@ func TestGetDataDir(t *testing.T) {
// 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("")
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 {

View File

@@ -1,7 +1,6 @@
package agent
import (
"beszel/internal/entities/system"
"log/slog"
"os"
"path/filepath"
@@ -9,6 +8,8 @@ import (
"strings"
"time"
"github.com/henrygd/beszel/internal/entities/system"
"github.com/shirou/gopsutil/v4/disk"
)

View File

@@ -1,7 +1,6 @@
package agent
import (
"beszel/internal/entities/container"
"bytes"
"context"
"encoding/json"
@@ -15,6 +14,8 @@ import (
"sync"
"time"
"github.com/henrygd/beszel/internal/entities/container"
"github.com/blang/semver"
)

View File

@@ -1,7 +1,6 @@
package agent
import (
"beszel/internal/entities/system"
"bufio"
"bytes"
"encoding/json"
@@ -13,6 +12,8 @@ import (
"sync"
"time"
"github.com/henrygd/beszel/internal/entities/system"
"golang.org/x/exp/slog"
)

View File

@@ -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"
)

View File

@@ -39,7 +39,7 @@ func TestHealth(t *testing.T) {
// 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.Run(func() {
synctest.Test(t, func(t *testing.T) {
// Update the file to set the initial timestamp.
require.NoError(t, Update(), "Update() failed inside synctest")

80
agent/lhm/beszel_lhm.cs Normal file
View 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}");
}
}
}

View 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>

View File

@@ -1,13 +1,16 @@
package agent
import (
"beszel/internal/entities/system"
"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"
@@ -82,10 +85,10 @@ func (a *Agent) updateTemperatures(systemStats *system.Stats) {
// reset high temp
a.systemInfo.DashboardTemp = 0
temps, err := a.getTempsWithPanicRecovery(sensors.TemperaturesWithContext)
temps, err := a.getTempsWithPanicRecovery(getSensorTemps)
if err != nil {
// retry once on panic (gopsutil/issues/1832)
temps, err = a.getTempsWithPanicRecovery(sensors.TemperaturesWithContext)
temps, err = a.getTempsWithPanicRecovery(getSensorTemps)
if err != nil {
slog.Warn("Error updating temperatures", "err", err)
if len(systemStats.Temperatures) > 0 {
@@ -103,6 +106,11 @@ func (a *Agent) updateTemperatures(systemStats *system.Stats) {
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)

9
agent/sensors_default.go Normal file
View File

@@ -0,0 +1,9 @@
//go:build !windows
package agent
import (
"github.com/shirou/gopsutil/v4/sensors"
)
var getSensorTemps = sensors.TemperaturesWithContext

View File

@@ -4,12 +4,13 @@
package agent
import (
"beszel/internal/entities/system"
"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"

286
agent/sensors_windows.go Normal file
View 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
}

View File

@@ -1,9 +1,6 @@
package agent
import (
"beszel"
"beszel/internal/common"
"beszel/internal/entities/system"
"encoding/json"
"errors"
"fmt"
@@ -14,6 +11,10 @@ import (
"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"

View File

@@ -1,8 +1,6 @@
package agent
import (
"beszel/internal/entities/container"
"beszel/internal/entities/system"
"context"
"crypto/ed25519"
"encoding/json"
@@ -15,6 +13,9 @@ import (
"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"
@@ -473,11 +474,11 @@ func TestWriteToSessionEncoding(t *testing.T) {
hubVersion: "0.12.0-beta0",
expectedUsesCbor: false,
},
{
name: "matching beta version should use CBOR",
hubVersion: "0.12.0-beta2",
expectedUsesCbor: true,
},
// {
// name: "matching beta version should use CBOR",
// hubVersion: "0.12.0-beta2",
// expectedUsesCbor: true,
// },
}
for _, tt := range tests {

View File

@@ -1,8 +1,6 @@
package agent
import (
"beszel"
"beszel/internal/entities/system"
"bufio"
"fmt"
"log/slog"
@@ -11,6 +9,10 @@ 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"
@@ -59,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
}
}
@@ -70,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 {
@@ -80,10 +87,10 @@ func (a *Agent) getSystemStats() system.Stats {
// load average
if avgstat, err := load.Avg(); err == nil {
systemStats.LoadAvg1 = twoDecimals(avgstat.Load1)
systemStats.LoadAvg5 = twoDecimals(avgstat.Load5)
systemStats.LoadAvg15 = twoDecimals(avgstat.Load15)
slog.Debug("Load average", "5m", systemStats.LoadAvg5, "15m", systemStats.LoadAvg15)
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)
}
@@ -174,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)
@@ -206,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
}
}
@@ -251,12 +262,17 @@ func (a *Agent) getSystemStats() system.Stats {
// update base system info
a.systemInfo.Cpu = systemStats.Cpu
a.systemInfo.LoadAvg5 = systemStats.LoadAvg5
a.systemInfo.LoadAvg15 = systemStats.LoadAvg15
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

165
agent/update.go Normal file
View 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
View 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")

View File

@@ -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 --host 0.0.0.0; \
else \
cd ./site && npm run dev --host 0.0.0.0; \
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 ./internal/{alerts,hub,records,users} -name "*.go" | entr -r -s "cd ./cmd/hub && go run . serve"; \
else \
cd ./cmd/hub && go run . serve --http 0.0.0.0:8090; \
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

View File

@@ -1,122 +0,0 @@
package main
import (
"beszel"
"beszel/internal/agent"
"beszel/internal/agent/health"
"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":
err := health.Check()
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, err := agent.NewAgent("")
if err != nil {
log.Fatal("Failed to create agent: ", err)
}
if err := agent.Start(serverConfig); err != nil {
log.Fatal("Failed to start server: ", err)
}
}

View File

@@ -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))
}

View File

@@ -1,256 +0,0 @@
//go:build testing
// +build testing
package hub_test
import (
"beszel/internal/tests"
"testing"
"crypto/ed25519"
"encoding/pem"
"os"
"path/filepath"
"strings"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/ssh"
)
func getTestHub(t testing.TB) *tests.TestHub {
hub, _ := tests.NewTestHub(t.TempDir())
return hub
}
func TestMakeLink(t *testing.T) {
hub := getTestHub(t)
tests := []struct {
name string
appURL string
parts []string
expected string
}{
{
name: "no parts, no trailing slash in AppURL",
appURL: "http://localhost:8090",
parts: []string{},
expected: "http://localhost:8090",
},
{
name: "no parts, with trailing slash in AppURL",
appURL: "http://localhost:8090/",
parts: []string{},
expected: "http://localhost:8090", // TrimSuffix should handle the trailing slash
},
{
name: "one part",
appURL: "http://example.com",
parts: []string{"one"},
expected: "http://example.com/one",
},
{
name: "multiple parts",
appURL: "http://example.com",
parts: []string{"alpha", "beta", "gamma"},
expected: "http://example.com/alpha/beta/gamma",
},
{
name: "parts with spaces needing escaping",
appURL: "http://example.com",
parts: []string{"path with spaces", "another part"},
expected: "http://example.com/path%20with%20spaces/another%20part",
},
{
name: "parts with slashes needing escaping",
appURL: "http://example.com",
parts: []string{"a/b", "c"},
expected: "http://example.com/a%2Fb/c", // url.PathEscape escapes '/'
},
{
name: "AppURL with subpath, no trailing slash",
appURL: "http://localhost/sub",
parts: []string{"resource"},
expected: "http://localhost/sub/resource",
},
{
name: "AppURL with subpath, with trailing slash",
appURL: "http://localhost/sub/",
parts: []string{"item"},
expected: "http://localhost/sub/item",
},
{
name: "empty parts in the middle",
appURL: "http://localhost",
parts: []string{"first", "", "third"},
expected: "http://localhost/first/third",
},
{
name: "leading and trailing empty parts",
appURL: "http://localhost",
parts: []string{"", "path", ""},
expected: "http://localhost/path",
},
{
name: "parts with various special characters",
appURL: "https://test.dev/",
parts: []string{"p@th?", "key=value&"},
expected: "https://test.dev/p@th%3F/key=value&",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Store original app URL and restore it after the test
originalAppURL := hub.Settings().Meta.AppURL
hub.Settings().Meta.AppURL = tt.appURL
defer func() { hub.Settings().Meta.AppURL = originalAppURL }()
got := hub.MakeLink(tt.parts...)
assert.Equal(t, tt.expected, got, "MakeLink generated URL does not match expected")
})
}
}
func TestGetSSHKey(t *testing.T) {
hub := getTestHub(t)
// Test Case 1: Key generation (no existing key)
t.Run("KeyGeneration", func(t *testing.T) {
tempDir := t.TempDir()
// Ensure pubKey is initially empty or different to ensure GetSSHKey sets it
hub.SetPubkey("")
signer, err := hub.GetSSHKey(tempDir)
assert.NoError(t, err, "GetSSHKey should not error when generating a new key")
assert.NotNil(t, signer, "GetSSHKey should return a non-nil signer")
// Check if private key file was created
privateKeyPath := filepath.Join(tempDir, "id_ed25519")
info, err := os.Stat(privateKeyPath)
assert.NoError(t, err, "Private key file should be created")
assert.False(t, info.IsDir(), "Private key path should be a file, not a directory")
// Check if h.pubKey was set
assert.NotEmpty(t, hub.GetPubkey(), "h.pubKey should be set after key generation")
assert.True(t, strings.HasPrefix(hub.GetPubkey(), "ssh-ed25519 "), "h.pubKey should start with 'ssh-ed25519 '")
// Verify the generated private key is parsable
keyData, err := os.ReadFile(privateKeyPath)
require.NoError(t, err)
_, err = ssh.ParsePrivateKey(keyData)
assert.NoError(t, err, "Generated private key should be parsable by ssh.ParsePrivateKey")
})
// Test Case 2: Existing key
t.Run("ExistingKey", func(t *testing.T) {
tempDir := t.TempDir()
// Manually create a valid key pair for the test
rawPubKey, rawPrivKey, err := ed25519.GenerateKey(nil)
require.NoError(t, err, "Failed to generate raw ed25519 key pair for pre-existing key test")
// Marshal the private key into OpenSSH PEM format
pemBlock, err := ssh.MarshalPrivateKey(rawPrivKey, "")
require.NoError(t, err, "Failed to marshal private key to PEM block for pre-existing key test")
privateKeyBytes := pem.EncodeToMemory(pemBlock)
require.NotNil(t, privateKeyBytes, "PEM encoded private key bytes should not be nil")
privateKeyPath := filepath.Join(tempDir, "id_ed25519")
err = os.WriteFile(privateKeyPath, privateKeyBytes, 0600)
require.NoError(t, err, "Failed to write pre-existing private key")
// Determine the expected public key string
sshPubKey, err := ssh.NewPublicKey(rawPubKey)
require.NoError(t, err)
expectedPubKeyStr := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(sshPubKey)))
// Reset h.pubKey to ensure it's set by GetSSHKey from the file
hub.SetPubkey("")
signer, err := hub.GetSSHKey(tempDir)
assert.NoError(t, err, "GetSSHKey should not error when reading an existing key")
assert.NotNil(t, signer, "GetSSHKey should return a non-nil signer for an existing key")
// Check if h.pubKey was set correctly to the public key from the file
assert.Equal(t, expectedPubKeyStr, hub.GetPubkey(), "h.pubKey should match the existing public key")
// Verify the signer's public key matches the original public key
signerPubKey := signer.PublicKey()
marshaledSignerPubKey := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(signerPubKey)))
assert.Equal(t, expectedPubKeyStr, marshaledSignerPubKey, "Signer's public key should match the existing public key")
})
// Test Case 3: Error cases
t.Run("ErrorCases", func(t *testing.T) {
tests := []struct {
name string
setupFunc func(dir string) error
errorCheck func(t *testing.T, err error)
}{
{
name: "CorruptedKey",
setupFunc: func(dir string) error {
return os.WriteFile(filepath.Join(dir, "id_ed25519"), []byte("this is not a valid SSH key"), 0600)
},
errorCheck: func(t *testing.T, err error) {
assert.Error(t, err)
assert.Contains(t, err.Error(), "ssh: no key found")
},
},
{
name: "PermissionDenied",
setupFunc: func(dir string) error {
// Create the key file
keyPath := filepath.Join(dir, "id_ed25519")
if err := os.WriteFile(keyPath, []byte("dummy content"), 0600); err != nil {
return err
}
// Make it read-only (can't be opened for writing in case a new key needs to be written)
return os.Chmod(keyPath, 0400)
},
errorCheck: func(t *testing.T, err error) {
// On read-only key, the parser will attempt to parse it and fail with "ssh: no key found"
assert.Error(t, err)
},
},
{
name: "EmptyFile",
setupFunc: func(dir string) error {
// Create an empty file
return os.WriteFile(filepath.Join(dir, "id_ed25519"), []byte{}, 0600)
},
errorCheck: func(t *testing.T, err error) {
assert.Error(t, err)
// The error from attempting to parse an empty file
assert.Contains(t, err.Error(), "ssh: no key found")
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
tempDir := t.TempDir()
// Setup the test case
err := tc.setupFunc(tempDir)
require.NoError(t, err, "Setup failed")
// Reset h.pubKey before each test case
hub.SetPubkey("")
// Attempt to get SSH key
_, err = hub.GetSSHKey(tempDir)
// Verify the error
tc.errorCheck(t, err)
// Check that pubKey was not set in error cases
assert.Empty(t, hub.GetPubkey(), "h.pubKey should not be set if there was an error")
})
}
})
}

View File

@@ -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))
}

View File

@@ -1,29 +0,0 @@
package migrations
import (
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
)
const (
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.

View File

@@ -1,73 +0,0 @@
{
"name": "beszel",
"private": true,
"version": "0.12.0-beta2",
"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.3.2",
"@lingui/macro": "^5.3.2",
"@lingui/react": "^5.3.2",
"@nanostores/react": "^0.7.3",
"@nanostores/router": "^0.11.0",
"@radix-ui/react-alert-dialog": "^1.1.14",
"@radix-ui/react-checkbox": "^1.3.2",
"@radix-ui/react-dialog": "^1.1.14",
"@radix-ui/react-direction": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.15",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-select": "^2.2.5",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slider": "^1.3.5",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.5",
"@radix-ui/react-tabs": "^1.1.12",
"@radix-ui/react-toast": "^1.2.14",
"@radix-ui/react-tooltip": "^1.2.7",
"@tanstack/react-table": "^8.21.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"d3-time": "^3.1.0",
"lucide-react": "^0.452.0",
"nanostores": "^0.11.4",
"pocketbase": "^0.26.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"recharts": "^2.15.3",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
"valibot": "^0.42.1"
},
"devDependencies": {
"@lingui/cli": "^5.3.2",
"@lingui/swc-plugin": "^5.5.2",
"@lingui/vite-plugin": "^5.3.2",
"@types/bun": "^1.2.15",
"@types/react": "^18.3.23",
"@types/react-dom": "^18.3.7",
"@vitejs/plugin-react-swc": "^3.10.1",
"autoprefixer": "^10.4.21",
"postcss": "^8.5.4",
"tailwindcss": "^3.4.17",
"tailwindcss-rtl": "^0.9.0",
"typescript": "^5.8.3",
"vite": "^6.3.5"
},
"overrides": {
"@nanostores/router": {
"nanostores": "^0.11.3"
}
},
"optionalDependencies": {
"@esbuild/linux-arm64": "^0.21.5"
}
}

View File

@@ -1,6 +0,0 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@@ -1,153 +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 { $router, Link } from "../router"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Checkbox } from "../ui/checkbox"
import { SystemAlert, SystemAlertGlobal } from "./alerts-system"
import { getPagePath } from "@nanostores/router"
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 sm:max-h-[95svh] overflow-auto max-w-[37rem]">
{opened && <AlertDialogContent system={system} />}
</DialogContent>
</Dialog>
),
[opened, hasAlert]
)
// return useMemo(
// () => (
// <Sheet>
// <SheetTrigger 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>
// </SheetTrigger>
// <SheetContent className="max-h-full overflow-auto w-[35em] p-4 sm:p-5">
// {opened && <AlertDialogContent system={system} />}
// </SheetContent>
// </Sheet>
// ),
// [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={getPagePath($router, "settings", { name: "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])
}

View File

@@ -1,311 +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 : data.alert.start ?? 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])
}}
step={data.alert.step ?? 1}
min={data.alert.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>
)
}

View File

@@ -1,181 +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,
convertNetworkSpeed,
convertDiskSpeed,
} from "@/lib/utils"
// import Spinner from '../spinner'
import { ChartData } from "@/types"
import { memo, useMemo } from "react"
import { useLingui } from "@lingui/react/macro"
import { useStore } from "@nanostores/react"
import { $userSettings } from "@/lib/stores"
/** [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 userSettings = useStore($userSettings)
const { chartTime } = chartData
const showMax = chartTime !== "1h" && maxToggled
// Determine if this is a network chart or disk chart and adjust unit accordingly
const isNetworkChart = chartName === "bw"
const isDiskChart = chartName === "dio" || chartName.startsWith("efs")
const displayUnit = useMemo(() => {
if (isNetworkChart) {
const { symbol } = convertNetworkSpeed(1, userSettings.networkUnit)
return symbol
} else if (isDiskChart) {
const { symbol } = convertDiskSpeed(1, userSettings.diskUnit)
return symbol
}
return unit
}, [isNetworkChart, isDiskChart, userSettings.networkUnit, userSettings.diskUnit, unit])
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 if (isNetworkChart) {
const { value: convertedValue, symbol } = convertNetworkSpeed(value, userSettings.networkUnit)
val = toFixedWithoutTrailingZeros(convertedValue, 2) + symbol
} else if (isDiskChart) {
const { value: convertedValue, symbol } = convertDiskSpeed(value, userSettings.diskUnit)
val = toFixedWithoutTrailingZeros(convertedValue, 2) + symbol
} else {
val = toFixedWithoutTrailingZeros(value, 2) + displayUnit
}
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)
} else if (isNetworkChart) {
const { display } = convertNetworkSpeed(value, userSettings.networkUnit)
return display
} else if (isDiskChart) {
const { display } = convertDiskSpeed(value, userSettings.diskUnit)
return display
}
return decimalString(value) + displayUnit
}}
// 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>
)
})

View File

@@ -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>
)
}

View File

@@ -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>
)
})

View File

@@ -1,168 +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 improve our translations? Check{" "}
<a href="https://crowdin.com/project/beszel" className="link" target="_blank" rel="noopener noreferrer">
Crowdin
</a>{" "}
for 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 />
<div className="space-y-2">
<div className="mb-4">
<h3 className="mb-1 text-lg font-medium">
<Trans>Unit preferences</Trans>
</h3>
<p className="text-sm text-muted-foreground leading-relaxed">
<Trans>Adjust Display units for metrics.</Trans>
</p>
</div>
<div className="space-y-4">
<div className="space-y-2">
<Label className="block" htmlFor="temperatureUnit">
<Trans>Temperature unit</Trans>
</Label>
<Select name="temperatureUnit" key={userSettings.temperatureUnit} defaultValue={userSettings.temperatureUnit || "celsius"}>
<SelectTrigger id="temperatureUnit">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="celsius">Celsius (°C)</SelectItem>
<SelectItem value="fahrenheit">Fahrenheit (°F)</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label className="block" htmlFor="networkUnit">
<Trans>Network unit</Trans>
</Label>
<Select name="networkUnit" key={userSettings.networkUnit} defaultValue={userSettings.networkUnit || "mbps"}>
<SelectTrigger id="networkUnit">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="mbps">MB/s (Megabytes per second)</SelectItem>
<SelectItem value="bps">bps (Bits per second)</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label className="block" htmlFor="diskUnit">
<Trans>Disk unit</Trans>
</Label>
<Select name="diskUnit" key={userSettings.diskUnit} defaultValue={userSettings.diskUnit || "mbps"}>
<SelectTrigger id="diskUnit">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="mbps">MB/s (Megabytes per second)</SelectItem>
<SelectItem value="bps">bps (Bits per second)</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</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>
)
}

View File

@@ -1,768 +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, $userSettings, pb } from "@/lib/stores"
import { useStore } from "@nanostores/react"
import {
cn,
copyToClipboard,
decimalString,
isReadOnlyUser,
useLocalStorage,
convertTemperature,
convertNetworkSpeed,
} from "@/lib/utils"
import AlertsButton from "../alerts/alert-button"
import { $router, Link, navigate } from "../router"
import { EthernetIcon, GpuIcon, HourglassIcon, 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-8">{decimalString(val, 1)}%</span>
<span className="grow min-w-8 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,
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,
invertSorting: 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,
},
{
accessorFn: (originalRow) => originalRow.info.cpu,
id: "cpu",
name: () => t`CPU`,
cell: CellFormatter,
Icon: CpuIcon,
header: sortableHeader,
},
{
// accessorKey: "info.mp",
accessorFn: (originalRow) => originalRow.info.mp,
id: "memory",
name: () => t`Memory`,
cell: CellFormatter,
Icon: MemoryStickIcon,
header: sortableHeader,
},
{
accessorFn: (originalRow) => originalRow.info.dp,
id: "disk",
name: () => t`Disk`,
cell: CellFormatter,
Icon: HardDriveIcon,
header: sortableHeader,
},
{
accessorFn: (originalRow) => originalRow.info.g,
id: "gpu",
name: () => "GPU",
cell: CellFormatter,
Icon: GpuIcon,
header: sortableHeader,
},
{
accessorFn: (originalRow) => originalRow.info.b || 0,
id: "net",
name: () => t`Net`,
size: 50,
Icon: EthernetIcon,
header: sortableHeader,
cell(info) {
const val = info.getValue() as number
const userSettings = useStore($userSettings)
const { display } = convertNetworkSpeed(val, userSettings.networkUnit)
return <span className="tabular-nums whitespace-nowrap">{display}</span>
},
},
{
accessorFn: (originalRow) => originalRow.info.l5,
id: "l5",
name: () => t({ message: "L5", comment: "Load average 5 minutes" }),
size: 0,
hideSort: true,
Icon: HourglassIcon,
header: sortableHeader,
cell(info) {
const val = info.getValue() as number
if (!val) {
return null
}
return (
<span className={cn("tabular-nums whitespace-nowrap", viewMode === "table" && "ps-1")}>
{decimalString(val)}
</span>
)
},
},
{
accessorFn: (originalRow) => originalRow.info.l15,
id: "l15",
name: () => t({ message: "L15", comment: "Load average 15 minutes" }),
size: 0,
hideSort: true,
Icon: HourglassIcon,
header: sortableHeader,
cell(info) {
const val = info.getValue() as number
if (!val) {
return null
}
return (
<span className={cn("tabular-nums whitespace-nowrap", viewMode === "table" && "ps-1")}>
{decimalString(val)}
</span>
)
},
},
{
accessorFn: (originalRow) => originalRow.info.dt,
id: "temp",
name: () => t({ message: "Temp", comment: "Temperature label in systems table" }),
size: 50,
hideSort: true,
Icon: ThermometerIcon,
header: sortableHeader,
cell(info) {
const val = info.getValue() as number
if (!val) {
return null
}
const userSettings = useStore($userSettings)
const { value, symbol } = convertTemperature(val, userSettings.temperatureUnit)
return (
<span className={cn("tabular-nums whitespace-nowrap", viewMode === "table" && "ps-0.5")}>
{decimalString(value, value >= 100 ? 1 : 2)} {symbol}
</span>
)
},
},
{
accessorFn: (originalRow) => originalRow.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", viewMode === "table" && "ps-0.5")}>
<IndicatorDot
system={system}
className={
(system.status !== "up" && "bg-primary/30") ||
(version === globalThis.BESZEL.HUB_VERSION && "bg-green-500") ||
"bg-yellow-500"
}
/>
<span className="truncate max-w-14">{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 -ms-3">
<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: {
// sortDescFirst: true,
invertSorting: true,
sortUndefined: "last",
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-1" 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" }}
/>
)
}

View File

@@ -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,
}

View File

@@ -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 }

View File

@@ -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>
)
}

View File

@@ -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 }

View File

@@ -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;
}

View File

@@ -1,13 +0,0 @@
export enum Os {
Linux = 0,
Darwin,
Windows,
FreeBSD,
}
export enum ChartType {
Memory,
Disk,
Network,
CPU,
}

View File

@@ -1,51 +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 || ""],
temperatureUnit: "celsius",
networkUnit: "mbps",
diskUnit: "mbps",
})
// 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("")
/** Temperature chart filter */
export const $temperatureFilter = atom("")
/** Fallback copy to clipboard dialog content */
export const $copyContent = atom("")
/** Direction for localization */
export const $direction = atom<"ltr" | "rtl">("ltr")

View File

@@ -1,485 +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, FingerprintRecord, SystemRecord, TemperatureUnit, TemperatureConversion, SpeedUnit, SpeedConversion } 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, HourglassIcon, 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]
}
/** Convert temperature from Celsius to the specified unit */
export function convertTemperature(
celsius: number,
unit: TemperatureUnit = "celsius"
): TemperatureConversion {
switch (unit) {
case "fahrenheit":
return { value: (celsius * 9) / 5 + 32, symbol: "°F" }
default:
return { value: celsius, symbol: "°C" }
}
}
/** Convert network speed from MB/s to the specified unit */
export function convertNetworkSpeed(
mbps: number,
unit: SpeedUnit = "mbps"
): SpeedConversion {
switch (unit) {
case "bps": {
const bps = mbps * 8 * 1_000_000 // Convert MB/s to bits per second
// Format large numbers appropriately
if (bps >= 1_000_000_000) {
return {
value: bps / 1_000_000_000,
symbol: " Gbps",
display: `${decimalString(bps / 1_000_000_000, bps >= 10_000_000_000 ? 0 : 1)} Gbps`,
}
} else if (bps >= 1_000_000) {
return {
value: bps / 1_000_000,
symbol: " Mbps",
display: `${decimalString(bps / 1_000_000, bps >= 10_000_000 ? 0 : 1)} Mbps`,
}
} else if (bps >= 1_000) {
return {
value: bps / 1_000,
symbol: " Kbps",
display: `${decimalString(bps / 1_000, bps >= 10_000 ? 0 : 1)} Kbps`,
}
} else {
return {
value: bps,
symbol: " bps",
display: `${Math.round(bps)} bps`,
}
}
}
default:
return {
value: mbps,
symbol: " MB/s",
display: `${decimalString(mbps, mbps >= 100 ? 1 : 2)} MB/s`,
}
}
}
/** Convert disk speed from MB/s to the specified unit */
export function convertDiskSpeed(
mbps: number,
unit: SpeedUnit = "mbps"
): SpeedConversion {
switch (unit) {
case "bps": {
const bps = mbps * 8 * 1_000_000 // Convert MB/s to bits per second
// Format large numbers appropriately
if (bps >= 1_000_000_000) {
return {
value: bps / 1_000_000_000,
symbol: " Gbps",
display: `${decimalString(bps / 1_000_000_000, bps >= 10_000_000_000 ? 0 : 1)} Gbps`,
}
} else if (bps >= 1_000_000) {
return {
value: bps / 1_000_000,
symbol: " Mbps",
display: `${decimalString(bps / 1_000_000, bps >= 10_000_000 ? 0 : 1)} Mbps`,
}
} else if (bps >= 1_000) {
return {
value: bps / 1_000,
symbol: " Kbps",
display: `${decimalString(bps / 1_000, bps >= 10_000 ? 0 : 1)} Kbps`,
}
} else {
return {
value: bps,
symbol: " bps",
display: `${Math.round(bps)} bps`,
}
}
}
default:
return {
value: mbps,
symbol: " MB/s",
display: `${decimalString(mbps, mbps >= 100 ? 1 : 2)} MB/s`,
}
}
}
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`,
},
LoadAvg5: {
name: () => t`Load Average 5m`,
unit: "",
icon: HourglassIcon,
max: 100,
min: 0.1,
start: 10,
step: 0.1,
desc: () => t`Triggers when 5 minute load average exceeds a threshold`,
},
LoadAvg15: {
name: () => t`Load Average 15m`,
unit: "",
icon: HourglassIcon,
min: 0.1,
max: 100,
start: 10,
step: 0.1,
desc: () => t`Triggers when 15 minute load average 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)
/** Generate a random token for the agent */
export const generateToken = () => crypto?.randomUUID() ?? (performance.now() * Math.random()).toString(16)
/** Get the hub URL from the global BESZEL object */
export const getHubURL = () => BESZEL?.HUB_URL || window.location.origin
/** Map of system IDs to their corresponding tokens (used to avoid fetching in add-system dialog) */
export const tokenMap = new Map<SystemRecord["id"], FingerprintRecord["token"]>()

View File

@@ -1,966 +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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# ден} other {# дни}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# час} other {# часа}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1 час"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 седмица"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12 часа"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 часа"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30 дни"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Действия"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Активни тревоги"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "Добави <0>Система</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "Добави нова система"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "Добави система"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "Добави URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "Настрой опциите за показване на диаграмите."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "Администратор"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "Агент"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "Тревоги"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "Всички системи"
#: src/components/systems-table/systems-table.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "Сигурен ли си, че искаш да изтриеш {name}?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Автоматичното копиране изисква защитен контескт."
#: src/components/routes/system.tsx
msgid "Average"
msgstr "Средно"
#: src/components/routes/system.tsx
msgid "Average CPU utilization of containers"
msgstr "Средно използване на процесора на контейнерите"
#. placeholder {0}: data.alert.unit
#: src/components/alerts/alerts-system.tsx
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Средната стойност надхвърля <0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "Средна консумация на ток от графични карти"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "Средно използване на процесора на цялата система"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "Средно използване на {0}"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "Архиви"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "Bandwidth на мрежата"
#: src/components/login/auth-form.tsx
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
msgstr "Beszel поддържа OpenID Connect и много други OAuth2 доставчици за удостоверяване."
#: src/components/routes/settings/notifications.tsx
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
msgstr "Beszel ползва <0>Shoutrrr</0> за да се интегрира с известни услуги за уведомяване."
#: src/components/add-system.tsx
msgid "Binary"
msgstr "Двоичен код"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Кеш / Буфери"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "Откажи"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "Внимание - възможност за загуба на данни"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Смени общите опции на приложението."
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "Опции на диаграмата"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "Провери {email} за линк за нулиране."
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "Провери log-овете за повече информация."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "Провери услугата си за удостоверяване"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "Настисни за да копираш"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "Инструкции за командната линия"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "Настрой как получаваш нотификации за тревоги."
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "Потвърди парола"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "Продължи"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "Записано в клипборда"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Копирай docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Копирай docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Копирай хоста"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Копирай linux командата"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "Копирай текста"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "Процесор"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Употреба на процесор"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "Създай акаунт"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "Тъмно"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "Табло"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "Времеви диапазон по подразбиране"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "Изтрий"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Диск"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "Диск I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "Използване на диск"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Изполване на диск от {extraFsName}"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Използване на процесор от docker"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Изполване на памет от docker"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Мрежов I/O използван от docker"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "Документация"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr ""
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "Имейл"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "Имейл нотификации"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
msgstr "Въведи имейл адрес за да нулираш паролата"
#: src/components/routes/settings/notifications.tsx
msgid "Enter email address..."
msgstr "Въведи имейл адрес..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Грешка"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "Експортирай конфигурация"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "Експортирай конфигурацията на системите."
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Неуспешно удостоверяване"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "Неуспешно запазване на настройки"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "Неуспешно изпрати тестова нотификация"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "Неуспешно обнови тревога"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "Филтрирай..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "Забравена парола?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "Общо"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "Консумация на ток от графична карта"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "Мрежово"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Команда Homebrew"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "Хост / IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "Невалиден имейл адрес."
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Linux Kernel"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "Език"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "Подреждане"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "Светъл"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Изход"
#: src/components/login/login.tsx
msgid "Login"
msgstr "Вход"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "Неуспешен опит за вход"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "Логове"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "Управление на предпочитанията за показване и уведомяване."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "Максимум 1 минута"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "Памет"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "Употреба на паметта"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Използването на памет от docker контейнерите"
#: src/components/add-system.tsx
msgid "Name"
msgstr "Име"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "Мрежа"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Мрежов трафик на docker контейнери"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "Мрежов трафик на публични интерфейси"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Няма намерени резултати."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "Няма намерени системи."
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "Нотификации"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "Поддръжка на OAuth 2 / OIDC"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Отвори менюто"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "Или продължи с"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "Презапиши съществуващи тревоги"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "Страница"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Страници / Настройки"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "Парола"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "Паролата трябва да е поне 8 символа."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr ""
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "Получено е искането за нулиране на паролата"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "Пауза"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "На пауза"
#: src/components/routes/settings/notifications.tsx
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
msgstr "Моля <0>конфигурурай SMTP сървър</0> за да се подсигуриш, че тревогите са доставени."
#: src/components/alerts/alerts-system.tsx
msgid "Please check logs for more details."
msgstr "Моля провери log-овете за повече информация."
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "Моля провери дадената информация и опитай отново"
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "Моля създай администраторски акаунт"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "Моля активирай изскачащите прозорци за този сайт"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "Моля влез отново"
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "Моля виж <0>документацията</0> за инструкции."
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "Моля влез в акаунта ти"
#: src/components/add-system.tsx
msgid "Port"
msgstr "Порт"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "Точно използване в записаното време"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "Предпочитан език"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "Публичен ключ"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Прочети"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Получени"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "Нулиране на парола"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Възобнови"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Запази адреса с enter или запетая. Остави празно за да изключиш нотификациите чрез имейл."
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "Запази настройките"
#: src/components/add-system.tsx
msgid "Save system"
msgstr ""
#: src/components/navbar.tsx
msgid "Search"
msgstr "Търси"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "Търси за системи или настройки..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "Изпратени"
#: src/components/routes/settings/general.tsx
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Задава диапазона за време за диаграмите, когато се разглежда система."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "Настройки"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "Настройките са запазени"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "Влез"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "Настройки за SMTP"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "Сортиране по"
#: src/lib/utils.ts
msgid "Status"
msgstr "Статус"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "Изполван swap от системата"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "Използване на swap"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Система"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Системи"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "Таблица"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Температура"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Температири на системни сензори"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "Тествай <0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "Тестова нотификация изпратена"
#: src/components/login/forgot-pass-form.tsx
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
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
msgid "Throughput of {extraFsName}"
msgstr "Пропускателна способност на {extraFsName}"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "Пропускателна способност на root файловата система"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "До имейл(ите)"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "Превключване на мрежа"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "Включи тема"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Задейства се, когато някой даден сензор надвиши зададен праг"
#: src/lib/utils.ts
msgid "Triggers when combined up/down exceeds a threshold"
msgstr "Задейства се, когато комбинираното качване/сваляне надвиши зададен праг"
#: src/lib/utils.ts
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "Задейства се, когато употребата на процесора надвиши зададен праг"
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "Задейства се, когато употребата на паметта надвиши зададен праг"
#: src/lib/utils.ts
msgid "Triggers when status switches between up and down"
msgstr "Задейства се, когато статуса превключва между долу и горе"
#: src/lib/utils.ts
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Задейства се, когато употребата на някой диск надивши зададен праг"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Updated in real time. Click on a system to view information."
msgstr "Актуализира се в реално време. Натисни на система за да видиш информация."
#: src/components/routes/system.tsx
msgid "Uptime"
msgstr "Време на работа"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Употреба"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "Употреба на root partition-а"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Използвани"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "Потребители"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Изглед"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Видими полета"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "Изчаква се за достатъчно записи за показване"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
msgstr "Искаш да помогнеш да направиш преводите още по-добри? Провери нашия <0>Crowdin</0> за повече детайли."
#: src/components/routes/settings/notifications.tsx
msgid "Webhook / Push notifications"
msgstr "Webhook / Пуш нотификации"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Команда Windows"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Запиши"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML конфигурация"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML конфигурация"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Настройките за потребителя ти са обновени."

View File

@@ -1,966 +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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# den} few {# dny} other {# dní}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# Hodina} few {# Hodiny} many {# Hodin} other {# Hodin}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1 hodina"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 týden"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12 hodin"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 hodin"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30 dní"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Akce"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktivní výstrahy"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "Přidat <0>Systém</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "Přidat nový systém"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "Přidat systém"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "Přidat URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "Upravit možnosti zobrazení pro grafy."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "Admin"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "Agent"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "Výstrahy"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "Všechny systémy"
#: src/components/systems-table/systems-table.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "Opravdu chcete odstranit {name}?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Automatická kopie vyžaduje zabezpečený kontext."
#: src/components/routes/system.tsx
msgid "Average"
msgstr "Průměr"
#: src/components/routes/system.tsx
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
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Průměr je vyšší než <0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "Průměrná spotřeba energie GPU"
#: src/components/routes/system.tsx
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
msgid "Average utilization of {0}"
msgstr "Průměrné využití {0}"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "Zálohy"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "Přenos"
#: src/components/login/auth-form.tsx
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
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
msgid "Binary"
msgstr "Binary"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / vyrovnávací paměť"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "Zrušit"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "Upozornění - možná ztráta dat"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Změnit obecné nastavení aplikace."
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "Možnosti grafu"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "Zkontrolujte {email} pro odkaz na obnovení."
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "Pro více informací zkontrolujte logy."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "Zkontrolujte službu upozornění"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "Klikněte pro zkopírování"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "Instrukce příkazového řádku"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "Konfigurace způsobu přijímání upozornění."
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "Potvrdit heslo"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "Pokračovat"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "Zkopírováno do schránky"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Kopírovat docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopírovat hostitele"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopírovat příkaz Linux"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "Kopírovat text"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "Procesor"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Využití procesoru"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "Vytvořit účet"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "Tmavý"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "Přehled"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "Výchozí doba"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "Odstranit"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "Disk I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "Využití disku"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Využití disku {extraFsName}"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Využití CPU Dockeru"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Využití paměti Dockeru"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Síťové I/O Dockeru"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "Dokumentace"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Nefunkční"
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr "Upravit"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "Email"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "Emailová upozornění"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
msgstr "Zadejte e-mailovou adresu pro obnovu hesla"
#: src/components/routes/settings/notifications.tsx
msgid "Enter email address..."
msgstr "Zadejte e-mailovou adresu..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Chyba"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "Exportovat konfiguraci"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "Exportovat aktuální konfiguraci systémů."
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Ověření se nezdařilo"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "Nepodařilo se uložit nastavení"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "Nepodařilo se odeslat testovací oznámení"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "Nepodařilo se aktualizovat upozornění"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "Filtr..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "Zapomněli jste heslo?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "Obecné"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "Spotřeba energie GPU"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "Mřížka"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr ""
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "Hostitel / IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "Neplatná e-mailová adresa."
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Kernel"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "Jazyk"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "Rozvržení"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "Světlý"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Odhlásit"
#: src/components/login/login.tsx
msgid "Login"
msgstr "Přihlásit"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "Pokus o přihlášení selhal"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "Logy"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "Správa nastavení zobrazení a oznámení."
#: src/components/add-system.tsx
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
msgid "Max 1 min"
msgstr "Max. 1 min"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "Paměť"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "Využití paměti"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Využití paměti docker kontejnerů"
#: src/components/add-system.tsx
msgid "Name"
msgstr "Název"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "Síť"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Síťový provoz kontejnerů docker"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "Síťový provoz veřejných rozhraní"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Nenalezeny žádné výskyty."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "Nenalezeny žádné systémy."
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "Upozornění"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "Podpora OAuth 2 / OIDC"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Otevřít menu"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "Nebo pokračujte s"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "Přepsat existující upozornění"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "Stránka"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Stránky / Nastavení"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "Heslo"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "Heslo musí obsahovat alespoň 8 znaků."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr "Heslo musí být menší než 72 bytů."
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "Žádost o obnovu hesla byla přijata"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "Pozastavit"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "Pozastaveno"
#: src/components/routes/settings/notifications.tsx
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
msgid "Please check logs for more details."
msgstr "Pro více informací zkontrolujte logy."
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
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
msgid "Please create an admin account"
msgstr "Vytvořte si prosím účet administrátora"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "Prosím povolte vyskakovací okna pro tento web"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "Přihlaste se prosím znovu"
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "Instrukce naleznete v <0>dokumentaci</0>."
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "Přihlaste se prosím k vašemu účtu"
#: src/components/add-system.tsx
msgid "Port"
msgstr "Port"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "Přesné využití v zaznamenaném čase"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "Upřednostňovaný jazyk"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "Veřejný klíč"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Číst"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Přijato"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "Obnovit heslo"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Pokračovat"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/notifications.tsx
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
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "Uložit nastavení"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "Uložit systém"
#: src/components/navbar.tsx
msgid "Search"
msgstr "Hledat"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "Hledat systémy nebo nastavení..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "Odeslat"
#: src/components/routes/settings/general.tsx
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
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "Nastavení"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "Nastavení uloženo"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "Přihlásit se"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "Nastavení SMTP"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "Seřadit podle"
#: src/lib/utils.ts
msgid "Status"
msgstr "Stav"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "Swap prostor využívaný systémem"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "Swap využití"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Systém"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Systémy"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "Tabulka"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "Teplota"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Teplota"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Teploty systémových senzorů"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "Test <0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "Testovací oznámení odesláno"
#: src/components/login/forgot-pass-form.tsx
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
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
msgid "Throughput of {extraFsName}"
msgstr "Propustnost {extraFsName}"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "Propustnost kořenového souborového systému"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "Na email(y)"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "Přepnout mřížku"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "Přepnout motiv"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Spustí se, když některý senzor překročí prahovou hodnotu"
#: src/lib/utils.ts
msgid "Triggers when combined up/down exceeds a threshold"
msgstr "Spustí se, když kombinace up/down překročí prahovou hodnotu"
#: src/lib/utils.ts
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "Spustí se, když využití procesoru překročí prahovou hodnotu"
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "Spustí se, když využití paměti překročí prahovou hodnotu"
#: src/lib/utils.ts
msgid "Triggers when status switches between up and down"
msgstr "Spouští se, když se změní dostupnost"
#: src/lib/utils.ts
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Spustí se, když využití disku překročí prahovou hodnotu"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr "Funkční"
#: src/components/systems-table/systems-table.tsx
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
msgid "Uptime"
msgstr "Doba provozu"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Využití"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "Využití kořenového oddílu"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Využito"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "Uživatelé"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Zobrazení"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Viditelné sloupce"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "Čeká se na dostatek záznamů k zobrazení"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for 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
msgid "Webhook / Push notifications"
msgstr "Webhook / Push oznámení"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr ""
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Psát"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML konfigurace"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML konfigurace"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Vaše uživatelská nastavení byla aktualizována."

View File

@@ -1,966 +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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# day} other {# days}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# hour} other {# hours}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1 time"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 uge"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12 timer"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 timer"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30 dage"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Handlinger"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktive Alarmer"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "Tilføj <0>System</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "Tilføj nyt system"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "Tilføj system"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "Tilføj URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "Juster visningsindstillinger for diagrammer."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "Admin"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "Agent"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "Alarmer"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "Alle systemer"
#: src/components/systems-table/systems-table.tsx
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
msgid "Automatic copy requires a secure context."
msgstr "Automatisk kopiering kræver en sikker kontekst."
#: src/components/routes/system.tsx
msgid "Average"
msgstr "Gennemsnitlig"
#: src/components/routes/system.tsx
msgid "Average CPU utilization of containers"
msgstr "Gennemsnitlig CPU udnyttelse af containere"
#. placeholder {0}: data.alert.unit
#: src/components/alerts/alerts-system.tsx
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Gennemsnit overstiger <0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "Gennemsnitligt strømforbrug for GPU'er"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "Gennemsnitlig systembaseret CPU-udnyttelse"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "Gennemsnitlig udnyttelse af {0}"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "Sikkerhedskopier"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "Båndbredde"
#: src/components/login/auth-form.tsx
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
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
msgid "Binary"
msgstr "Binær"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / Buffere"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "Fortryd"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "Forsigtig - muligt tab af data"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Skift generelle applikationsindstillinger."
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "Diagrammuligheder"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "Tjek {email} for et nulstillingslink."
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "Tjek logfiler for flere detaljer."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "Tjek din notifikationstjeneste"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "Klik for at kopiere"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "Instruktioner for kommandolinje"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "Konfigurer hvordan du modtager advarselsmeddelelser."
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "Bekræft adgangskode"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "Forsæt"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "Kopieret til udklipsholder"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Kopiér docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Kopiér docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopier host"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopier Linux kommando"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "Kopier tekst"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU forbrug"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "Opret konto"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "Mørk"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "Oversigtspanel"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "Standard tidsperiode"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "Slet"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "Disk I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "Diskforbrug"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Diskforbrug af {extraFsName}"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Docker CPU forbrug"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Docker Hukommelsesforbrug"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Docker Netværk I/O"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "Dokumentation"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr ""
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "E-mail"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "Email-notifikationer"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
msgstr "Indtast e-mailadresse for at nulstille adgangskoden"
#: src/components/routes/settings/notifications.tsx
msgid "Enter email address..."
msgstr "Indtast e-mailadresse..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Fejl"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "Eksporter konfiguration"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "Eksporter din nuværende systemkonfiguration."
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Kunne ikke godkende"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "Kunne ikke gemme indstillinger"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "Afsendelse af testnotifikation mislykkedes"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "Kunne ikke opdatere alarm"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "Glemt adgangskode?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "Generelt"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "Gpu Strøm Træk"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "Gitter"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew-kommando"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "Vært / IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "Ugyldig email adresse."
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Kernel"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "Sprog"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "Layout"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "Lys"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Log ud"
#: src/components/login/login.tsx
msgid "Login"
msgstr "Log ind"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "Loginforsøg mislykkedes"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "Logs"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "Administrer display og notifikationsindstillinger."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "Maks. 1 min"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "Hukommelse"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "Hukommelsesforbrug"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Hukommelsesforbrug af dockercontainere"
#: src/components/add-system.tsx
msgid "Name"
msgstr "Navn"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "Net"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Netværkstrafik af dockercontainere"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "Netværkstrafik af offentlige grænseflader"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Ingen resultater fundet."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "Ingen systemer fundet."
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "Notifikationer"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "OAuth 2 / OIDC understøttelse"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Åbn menu"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "Eller fortsæt med"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "Overskriv eksisterende alarmer"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "Side"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Sider / Indstillinger"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "Adgangskode"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "Adgangskoden skal være på mindst 8 tegn."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr ""
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "Anmodning om nulstilling af adgangskode modtaget"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "Pause"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "Sat på pause"
#: src/components/routes/settings/notifications.tsx
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
msgid "Please check logs for more details."
msgstr "Tjek logfiler for flere detaljer."
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "Tjek dine legitimationsoplysninger og prøv igen"
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "Opret venligst en administratorkonto"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "Aktiver pop-ups for dette websted"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "Log venligst ind igen"
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "Se <0>dokumentationen</0> for instruktioner."
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "Log venligst ind på din konto"
#: src/components/add-system.tsx
msgid "Port"
msgstr "Port"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "Præcis udnyttelse på det registrerede tidspunkt"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "Foretrukket sprog"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "Offentlig nøgle"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Læs"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Modtaget"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "Nulstil adgangskode"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Genoptag"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/notifications.tsx
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
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "Gem indstillinger"
#: src/components/add-system.tsx
msgid "Save system"
msgstr ""
#: src/components/navbar.tsx
msgid "Search"
msgstr "Søg"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "Søg efter systemer eller indstillinger..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "Sendt"
#: src/components/routes/settings/general.tsx
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
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "Indstillinger"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "Indstillinger gemt"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "Log ind"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "SMTP-indstillinger"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "Sorter efter"
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "Swap plads brugt af systemet"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "Swap forbrug"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "System"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Systemer"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "Tabel"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Temperatur"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperaturer i systemsensorer"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "Test <0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "Test notifikation sendt"
#: src/components/login/forgot-pass-form.tsx
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
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
msgid "Throughput of {extraFsName}"
msgstr "Gennemløb af {extraFsName}"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "Gennemløb af rodfilsystemet"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "Til email(s)"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "Slå gitter til/fra"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "Skift tema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Udløser når en sensor overstiger en tærskel"
#: src/lib/utils.ts
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
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "Udløser når CPU-forbrug overstiger en tærskel"
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "Udløser når hukommelsesforbruget overstiger en tærskel"
#: src/lib/utils.ts
msgid "Triggers when status switches between up and down"
msgstr "Udløser når status skifter mellem op og ned"
#: src/lib/utils.ts
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Udløser når brugen af en disk overstiger en tærskel"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr ""
#: src/components/systems-table/systems-table.tsx
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
msgid "Uptime"
msgstr "Oppetid"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Forbrug"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "Brug af rodpartition"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Brugt"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "Brugere"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Vis"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Synlige felter"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "Venter på nok posteringer til at vise"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for 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
msgid "Webhook / Push notifications"
msgstr "Webhook / Push notifikationer"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows-kommando"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Skriv"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML Konfiguration"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML Konfiguration"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Dine brugerindstillinger er opdateret."

View File

@@ -1,966 +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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# día} other {# días}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# hora} other {# horas}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1 hora"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 semana"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12 horas"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 horas"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30 días"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Acciones"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Alertas Activas"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "Agregar <0>Sistema</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "Agregar Nuevo Sistema"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "Agregar sistema"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "Agregar URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "Ajustar las opciones de visualización para los gráficos."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "Administrador"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "Agente"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "Alertas"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "Todos los Sistemas"
#: src/components/systems-table/systems-table.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "¿Está seguro de que desea eliminar {name}?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "La copia automática requiere un contexto seguro."
#: src/components/routes/system.tsx
msgid "Average"
msgstr "Promedio"
#: src/components/routes/system.tsx
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
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "El promedio excede <0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "Consumo de energía promedio de GPUs"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "Utilización promedio de CPU del sistema"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "Uso promedio de {0}"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "Copias de Seguridad"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "Ancho de banda"
#: src/components/login/auth-form.tsx
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
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
msgid "Binary"
msgstr "Binario"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Caché / Buffers"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "Cancelar"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "Precaución - posible pérdida de datos"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Cambiar las opciones generales de la aplicación."
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "Opciones de Gráficos"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "Revise {email} para un enlace de restablecimiento."
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "Revise los registros para más detalles."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "Verifique su servicio de notificaciones"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "Haga clic para copiar"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "Instrucciones de línea de comandos"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "Configure cómo recibe las notificaciones de alertas."
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "Confirmar contraseña"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "Continuar"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "Copiado al portapapeles"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Copiar docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Copiar docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "Copiar env"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Copiar host"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Copiar comando de Linux"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "Copiar texto"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "Copia el comando de instalación del agente a continuación, o registra agentes automáticamente con un <0>token universal</0>."
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr "Copia el contenido del<0>docker-compose.yml</0> para el agente a continuación, o registra agentes automáticamente con un <1>token universal</1>."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "Copiar YAML"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Uso de CPU"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "Crear cuenta"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "Oscuro"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "Tablero"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "Período de tiempo predeterminado"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "Eliminar"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "Eliminar huella digital"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disco"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "E/S de Disco"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "Uso de Disco"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Uso de disco de {extraFsName}"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Uso de CPU de Docker"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Uso de Memoria de Docker"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "E/S de Red de Docker"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "Documentación"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Abajo"
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr "Editar"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "Correo electrónico"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "Notificaciones por correo"
#: src/components/login/login.tsx
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
msgid "Enter email address..."
msgstr "Ingrese dirección de correo..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Error"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "Exportar configuración"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "Exporte la configuración actual de sus sistemas."
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Error al autenticar"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "Error al guardar la configuración"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "Error al enviar la notificación de prueba"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "Error al actualizar la alerta"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "Filtrar..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "¿Olvidó su contraseña?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "General"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "Consumo de energía de la GPU"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "Cuadrícula"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Comando Homebrew"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "Host / IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "Dirección de correo electrónico no válida."
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Kernel"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "Idioma"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "Diseño"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "Claro"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Cerrar Sesión"
#: src/components/login/login.tsx
msgid "Login"
msgstr "Iniciar sesión"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "Intento de inicio de sesión fallido"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "Registros"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "Administrar preferencias de visualización y notificaciones."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "Instrucciones manuales de configuración"
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "Máx 1 min"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "Memoria"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "Uso de Memoria"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Uso de memoria de los contenedores de Docker"
#: src/components/add-system.tsx
msgid "Name"
msgstr "Nombre"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "Red"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Tráfico de red de los contenedores de Docker"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "Tráfico de red de interfaces públicas"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "No se encontraron resultados."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "No se encontraron sistemas."
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "Notificaciones"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "Soporte para OAuth 2 / OIDC"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Abrir menú"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "O continuar con"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "Sobrescribir alertas existentes"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "Página"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Páginas / Configuraciones"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "Contraseña"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "La contraseña debe tener al menos 8 caracteres."
#: src/components/login/auth-form.tsx
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
msgid "Password reset request received"
msgstr "Solicitud de restablecimiento de contraseña recibida"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "Pausar"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "Pausado"
#: src/components/routes/settings/notifications.tsx
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
msgid "Please check logs for more details."
msgstr "Por favor, revise los registros para más detalles."
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "Por favor, verifique sus credenciales e intente de nuevo"
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "Por favor, cree una cuenta de administrador"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "Por favor, habilite las ventanas emergentes para este sitio"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "Por favor, inicie sesión de nuevo"
#: src/components/login/auth-form.tsx
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
msgid "Please sign in to your account"
msgstr "Por favor, inicie sesión en su cuenta"
#: src/components/add-system.tsx
msgid "Port"
msgstr "Puerto"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "Utilización precisa en el momento registrado"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "Idioma Preferido"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "Clave Pública"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Lectura"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Recibido"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "Restablecer Contraseña"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Reanudar"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "Rotar token"
#: src/components/routes/settings/notifications.tsx
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
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "Guardar Configuración"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "Guardar Sistema"
#: src/components/navbar.tsx
msgid "Search"
msgstr "Buscar"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "Buscar sistemas o configuraciones..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "Enviado"
#: src/components/routes/settings/general.tsx
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
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "Configuración"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "Configuración guardada"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "Iniciar sesión"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "Configuración SMTP"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "Ordenar por"
#: src/lib/utils.ts
msgid "Status"
msgstr "Estado"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "Espacio de swap utilizado por el sistema"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "Uso de Swap"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Sistema"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Sistemas"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "Tabla"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "Temperatura"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Temperatura"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperaturas de los sensores del sistema"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "Probar <0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "Notificación de prueba enviada"
#: src/components/login/forgot-pass-form.tsx
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
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
msgid "Throughput of {extraFsName}"
msgstr "Rendimiento de {extraFsName}"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "Rendimiento del sistema de archivos raíz"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "A correo(s)"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "Alternar cuadrícula"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "Alternar tema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "Token"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "Tokens y Huellas Digitales"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr "Los tokens permiten que los agentes se conecten y registren. Las huellas digitales son identificadores estables únicos para cada sistema, establecidos en la primera conexión."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "Los tokens y las huellas digitales se utilizan para autenticar las conexiones WebSocket al hub."
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Se activa cuando cualquier sensor supera un umbral"
#: src/lib/utils.ts
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
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "Se activa cuando el uso de CPU supera un umbral"
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "Se activa cuando el uso de memoria supera un umbral"
#: src/lib/utils.ts
msgid "Triggers when status switches between up and down"
msgstr "Se activa cuando el estado cambia entre activo e inactivo"
#: src/lib/utils.ts
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Se activa cuando el uso de cualquier disco supera un umbral"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "Token universal"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr "Activo"
#: src/components/systems-table/systems-table.tsx
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
msgid "Uptime"
msgstr "Tiempo de actividad"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Uso"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "Uso de la partición raíz"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Usado"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "Usuarios"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Vista"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Columnas visibles"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "Esperando suficientes registros para mostrar"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
msgstr "¿Quieres ayudarnos a mejorar nuestras traducciones? Consulta <0>Crowdin</0> para más detalles."
#: src/components/routes/settings/notifications.tsx
msgid "Webhook / Push notifications"
msgstr "Notificaciones Webhook / Push"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "Cuando está habilitado, este token permite que los agentes se auto-registren sin crear previamente el sistema. Expira después de una hora o al reiniciar el hub."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Comando Windows"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Escritura"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "Configuración YAML"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "Configuración YAML"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Su configuración de usuario ha sido actualizada."

View File

@@ -1,966 +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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dan} other {# dani}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# sat} other {# sati}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1 sat"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 tjedan"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12 sati"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 sati"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30 dana"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Akcije"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktivna upozorenja"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "Dodaj <0>Sistem</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "Dodaj Novi Sistem"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "Dodaj sistem"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "Dodaj URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "Podesite opcije prikaza za grafikone."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "Admin"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "Agent"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "Upozorenja"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "Svi Sistemi"
#: src/components/systems-table/systems-table.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "Jeste li sigurni da želite izbrisati {name}?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Automatsko kopiranje zahtijeva siguran kontekst."
#: src/components/routes/system.tsx
msgid "Average"
msgstr "Prosjek"
#: src/components/routes/system.tsx
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
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Prosjek premašuje <0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr ""
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "Prosječna iskorištenost procesora na cijelom sustavu"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr ""
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "Sigurnosne kopije"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "Propusnost"
#: src/components/login/auth-form.tsx
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
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
msgid "Binary"
msgstr "Binarni"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Predmemorija / Međuspremnici"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "Otkaži"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "Oprez - mogući gubitak podataka"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Promijenite opće opcije aplikacije."
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "Opcije grafikona"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "Provjerite {email} za vezu za resetiranje."
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "Provjerite logove za više detalja."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "Provjerite Vaš servis notifikacija"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "Pritisnite za kopiranje"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "Upute za naredbeni redak"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "Konfigurirajte način primanja obavijesti upozorenja."
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "Potvrdite lozinku"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "Nastavite"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "Kopirano u međuspremnik"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Kopiraj docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Kopiraj docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopiraj hosta"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopiraj Linux komandu"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "Kopiraj tekst"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "Procesor"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Iskorištenost procesora"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "Napravite račun"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "Tamno"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "Nadzorna ploča"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "Zadano vremensko razdoblje"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "Izbriši"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "Disk I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "Iskorištenost Diska"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Iskorištenost diska od {extraFsName}"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Iskorištenost Docker Procesora"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Iskorištenost Docker Memorije"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Docker Mrežni I/O"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "Dokumentacija"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr ""
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "Email"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "Email notifikacije"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
msgstr "Unesite email adresu za resetiranje lozinke"
#: src/components/routes/settings/notifications.tsx
msgid "Enter email address..."
msgstr "Unesite email adresu..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Greška"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "Izvoz konfiguracije"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "Izvoz trenutne sistemske konfiguracije."
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Provjera autentičnosti nije uspjela"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "Neuspješno snimanje postavki"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "Neuspješno slanje testne notifikacije"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "Ažuriranje upozorenja nije uspjelo"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "Zaboravljena lozinka?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "Općenito"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "Mreža"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew naredba"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "Host / IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "Nevažeća adresa e-pošte."
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Kernel"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "Jezik"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "Izgled"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "Svijetlo"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Odjava"
#: src/components/login/login.tsx
msgid "Login"
msgstr "Prijava"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "Pokušaj prijave nije uspio"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "Logovi"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "Upravljajte postavkama prikaza i obavijesti."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "Maksimalno 1 minuta"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "Memorija"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "Upotreba memorije"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Upotreba memorije Docker spremnika"
#: src/components/add-system.tsx
msgid "Name"
msgstr "Ime"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "Mreža"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Mrežni promet Docker spremnika"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "Mrežni promet javnih sučelja"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Nema rezultata."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "Nije pronađen nijedan sustav."
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "Obavijesti"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "Podrška za OAuth 2 / OIDC"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Otvori menu"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "Ili nastavi sa"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "Prebrišite postojeća upozorenja"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "Stranica"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Stranice / Postavke"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "Lozinka"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "Lozinka mora imati najmanje 8 znakova."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr ""
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "Zahtjev za ponovno postavljanje lozinke primljen"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "Pauza"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "Pauzirano"
#: src/components/routes/settings/notifications.tsx
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
msgid "Please check logs for more details."
msgstr "Za više detalja provjerite logove."
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "Provjerite svoje podatke i pokušajte ponovno"
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "Molimo kreirajte administratorski račun"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "Omogućite skočne prozore za ovu stranicu"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "Molimo prijavite se ponovno"
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "Molimo pogledajte <0>dokumentaciju</0> za instrukcije."
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "Molimo prijavite se u svoj račun"
#: src/components/add-system.tsx
msgid "Port"
msgstr "Port"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "Precizno iskorištenje u zabilježenom vremenu"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "Preferirani jezik"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "Javni Ključ"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Pročitaj"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Primljeno"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "Resetiraj Lozinku"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Nastavi"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/notifications.tsx
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
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "Spremi Postavke"
#: src/components/add-system.tsx
msgid "Save system"
msgstr ""
#: src/components/navbar.tsx
msgid "Search"
msgstr "Pretraži"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "Pretraži za sisteme ili postavke..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "Poslano"
#: src/components/routes/settings/general.tsx
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
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "Postavke"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "Postavke spremljene"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "Prijava"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "SMTP postavke"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "Sortiraj po"
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "Swap prostor uzet od strane sistema"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "Swap Iskorištenost"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Sistem"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Sistemi"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "Tablica"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Temperatura"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperature sistemskih senzora"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "Testni <0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "Testna obavijest poslana"
#: src/components/login/forgot-pass-form.tsx
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
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
msgid "Throughput of {extraFsName}"
msgstr "Protok {extraFsName}"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "Protok root datotečnog sustava"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "Primaoci e-pošte"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "Uključi/isključi rešetku"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "Uključi/isključi temu"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Pokreće se kada bilo koji senzor prijeđe prag"
#: src/lib/utils.ts
msgid "Triggers when combined up/down exceeds a threshold"
msgstr "Pokreće se kada kombinacija gore/dolje premaši prag"
#: src/lib/utils.ts
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "Pokreće se kada iskorištenost procesora premaši prag"
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "Pokreće se kada iskorištenost memorije premaši prag"
#: src/lib/utils.ts
msgid "Triggers when status switches between up and down"
msgstr "Pokreće se kada se status sistema promijeni"
#: src/lib/utils.ts
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Pokreće se kada iskorištenost bilo kojeg diska premaši prag"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr ""
#: src/components/systems-table/systems-table.tsx
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
msgid "Uptime"
msgstr "Vrijeme rada"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Iskorištenost"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "Iskorištenost root datotečnog sustava"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Iskorišteno"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "Korisnici"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Prikaz"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Vidljiva polja"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "Čeka se na više podataka prije prikaza"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for 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
msgid "Webhook / Push notifications"
msgstr "Webhook / Push obavijest"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows naredba"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Piši"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML Config"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML Konfiguracija"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Vaše korisničke postavke su ažurirane."

View File

@@ -1,966 +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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# nap} other {# nap}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# óra} other {# óra}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1 óra"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 hét"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12 óra"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 óra"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30 nap"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Műveletek"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktív riasztások"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "Hozzáadás <0>System</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "Új rendszer hozzáadása"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "Rendszer hozzáadása"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "URL hozzáadása"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "Állítsa be a diagram megjelenítését."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "Admin"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "Ügynök"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "Riasztások"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "Minden rendszer"
#: src/components/systems-table/systems-table.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "Biztosan törölni szeretnéd {name}-t?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Az automatikus másolás biztonságos környezetet igényel."
#: src/components/routes/system.tsx
msgid "Average"
msgstr "Átlag"
#: src/components/routes/system.tsx
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
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Az átlag meghaladja a <0>{value}{0}</0> értéket"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "GPU-k átlagos energiafogyasztása"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "Rendszerszintű CPU átlagos kihasználtság"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "{0} átlagos kihasználtsága"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "Biztonsági mentések"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "Sávszélesség"
#: src/components/login/auth-form.tsx
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
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
msgid "Binary"
msgstr "Bináris"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Gyorsítótár / Pufferelések"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "Mégsem"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "Figyelem - potenciális adatvesztés"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Általános alkalmazásbeállítások módosítása."
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "Diagram beállítások"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Check logs for more details."
msgstr "Ellenőrizd a naplót a további részletekért."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "Ellenőrizd az értesítési szolgáltatásodat"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "Kattints a másoláshoz"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "Parancssori utasítások"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "Konfiguráld, hogyan kapod az értesítéseket."
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "Jelszó megerősítése"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "Tovább"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "Vágólapra másolva"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Docker compose másolása"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Docker run másolása"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Hoszt másolása"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Linux parancs másolása"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "Szöveg másolása"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU használat"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "Fiók létrehozása"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "Sötét"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "Áttekintés"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "Alapértelmezett időszak"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "Törlés"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Lemez"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "Lemez I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "Lemezhasználat"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Lemezhasználat a {extraFsName}"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Docker CPU használat"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Docker memória használat"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Docker hálózat I/O"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "Dokumentáció"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr ""
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "Email"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "E-mail értesítések"
#: src/components/login/login.tsx
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
msgid "Enter email address..."
msgstr "Adja meg az e-mail címet..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Hiba"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "Konfiguráció exportálása"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "Exportálja a jelenlegi rendszerkonfigurációt."
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Hitelesítés sikertelen"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "Nem sikerült menteni a beállításokat"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "Teszt értesítés elküldése sikertelen"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "Nem sikerült frissíteni a riasztást"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "Szűrő..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "Elfelejtette a jelszavát?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "Általános"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "GPU áramfelvétele"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "Rács"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew parancs"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "Állomás / IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "Érvénytelen e-mail cím."
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Kernel"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "Nyelv"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "Elrendezés"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "Világos"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Kijelentkezés"
#: src/components/login/login.tsx
msgid "Login"
msgstr "Bejelentkezés"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "Bejelentkezés sikertelen"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "Naplók"
#: src/components/routes/settings/notifications.tsx
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
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
msgid "Manual setup instructions"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "Maximum 1 perc"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "RAM"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "Memóriahasználat"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Docker konténerek memória használata"
#: src/components/add-system.tsx
msgid "Name"
msgstr "Név"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "Hálózat"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Docker konténerek hálózati forgalma"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "Nyilvános interfészek hálózati forgalma"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Nincs találat."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "Nem található rendszer."
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "Értesítések"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "OAuth 2 / OIDC támogatás"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Menü megnyitása"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "Vagy folytasd ezzel"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "Felülírja a meglévő riasztásokat"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "Oldal"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Oldalak / Beállítások"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "Jelszó"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "A jelszónak legalább 8 karakternek kell lennie."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr ""
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "Jelszó-visszaállítási kérelmet kaptunk"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "Szüneteltetés"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "Szüneteltetve"
#: src/components/routes/settings/notifications.tsx
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
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
#: src/components/login/auth-form.tsx
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
msgid "Please create an admin account"
msgstr "Kérjük, hozzon létre egy admin fiókot"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "Kérjük, engedélyezze a felugró ablakokat ezen az oldalon"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "Kérjük jelentkezz be újra"
#: src/components/login/auth-form.tsx
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
msgid "Please sign in to your account"
msgstr "Kérjük, jelentkezzen be a fiókjába"
#: src/components/add-system.tsx
msgid "Port"
msgstr "Port"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "Pontos kihasználás a rögzített időpontban"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "Preferált nyelv"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "Nyilvános kulcs"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Olvasás"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Fogadott"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "Jelszó visszaállítása"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Folytatás"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/notifications.tsx
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
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "Beállítások mentése"
#: src/components/add-system.tsx
msgid "Save system"
msgstr ""
#: src/components/navbar.tsx
msgid "Search"
msgstr "Keresés"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "Keresés rendszerek vagy beállítások után..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "Elküldve"
#: src/components/routes/settings/general.tsx
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
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "Beállítások"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "Beállítások elmentve"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "Bejelentkezés"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "SMTP beállítások"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "Rendezés"
#: src/lib/utils.ts
msgid "Status"
msgstr "Állapot"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "Rendszer által használt swap terület"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "Swap használat"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Rendszer"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Rendszer"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "Tábla"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Hőmérséklet"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "A rendszer érzékelőinek hőmérséklete"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "Teszt <0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "Teszt értesítés elküldve"
#: src/components/login/forgot-pass-form.tsx
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
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
msgid "Throughput of {extraFsName}"
msgstr "A {extraFsName} átviteli teljesítménye"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "A gyökér fájlrendszer átviteli teljesítménye"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "E-mailben"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "Rács ki- és bekapcsolása"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "Téma váltása"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
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
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
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
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
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
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"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr ""
#: src/components/systems-table/systems-table.tsx
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
msgid "Uptime"
msgstr "Üzemidő"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Használat"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "Root partíció kihasználtsága"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Felhasznált"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "Felhasználók"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Nézet"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Látható mezők"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "Elegendő rekordra várva a megjelenítéshez"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for 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
msgid "Webhook / Push notifications"
msgstr "Webhook / Push értesítések"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows parancs"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Írás"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML konfiguráció"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML konfiguráció"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "A felhasználói beállítások frissítésre kerültek."

View File

@@ -1,966 +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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# 일} other {# 일}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# 시간} other {# 시간}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1시간"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1주"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12시간"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24시간"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30일"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "작업"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "활성화된 알림들"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "<0>시스템</0> 추가"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "새 시스템 추가"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "시스템 추가"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "URL 추가"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "차트 표시 옵션 변경."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "관리자"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "에이전트"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "알림"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "모든 시스템"
#: src/components/systems-table/systems-table.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "{name}을(를) 삭제하시겠습니까?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "자동 복사는 안전한 컨텍스트가 필요합니다."
#: src/components/routes/system.tsx
msgid "Average"
msgstr "평균"
#: src/components/routes/system.tsx
msgid "Average CPU utilization of containers"
msgstr "컨테이너의 평균 CPU 사용량"
#. placeholder {0}: data.alert.unit
#: src/components/alerts/alerts-system.tsx
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "평균이 <0>{value}{0}</0>을(를) 초과합니다"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "GPU들의 평균 전원 사용량"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "시스템 전체의 평균 CPU 사용량"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "평균 {0} 사용량"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "백업"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "대역폭"
#: src/components/login/auth-form.tsx
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
msgstr "Beszel은 OpenID Connect 및 많은 OAuth2 인증 제공자를 지원합니다."
#: src/components/routes/settings/notifications.tsx
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
msgstr "Beszel은 여러 인기 있는 알림 서비스와 연동하기 위해 <0>Shoutrrr</0>을 이용합니다."
#: src/components/add-system.tsx
msgid "Binary"
msgstr "실행 파일"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "캐시 / 버퍼"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "취소"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "주의 - 데이터 손실 가능성"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "일반 애플리케이션 옵션 변경."
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "차트 옵션"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "{email}에서 재설정 링크를 확인하세요."
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "자세한 내용은 로그를 확인하세요."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "알림 서비스를 확인하세요."
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "클릭하여 복사"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "명령어 사용 지침"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "알림을 수신할 방법을 설정하세요."
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "비밀번호 확인"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "계속"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "클립보드에 복사됨"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "docker compose 복사"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "docker run 복사"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "호스트 복사"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "리눅스 명령어 복사"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "텍스트 복사"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU 사용량"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "계정 생성"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "어둡게"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "대시보드"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "기본 기간"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "삭제"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "디스크"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "디스크 I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "디스크 사용량"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "{extraFsName}의 디스크 사용량"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Docker CPU 사용량"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Docker 메모리 사용량"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Docker 네트워크 I/O"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "문서"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "오프라인"
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr "수정"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "이메일"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "이메일 알림"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
msgstr "비밀번호를 재설정하려면 이메일 주소를 입력하세요"
#: src/components/routes/settings/notifications.tsx
msgid "Enter email address..."
msgstr "이메일 주소 입력..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "오류"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "구성 내보내기"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "현재 시스템 구성 내보내기"
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "인증 실패"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "설정 저장 실패"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "테스트 알림 전송 실패"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "알림 수정 실패"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "필터..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "비밀번호를 잊으셨나요?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "일반"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "GPU 전원 사용량"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "그리드"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew 명령어"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "호스트 / IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "잘못된 이메일 주소입니다."
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "커널"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "언어"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "레이아웃"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "밝게"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "로그아웃"
#: src/components/login/login.tsx
msgid "Login"
msgstr "로그인"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "로그인 실패"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "로그"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "디스플레이 및 알림 설정"
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "수동 설정 방법"
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "1분간 최댓값"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "메모리"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "메모리 사용량"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Docker 컨테이너의 메모리 사용량"
#: src/components/add-system.tsx
msgid "Name"
msgstr "이름"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "네트워크"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Docker 컨테이너의 네트워크 트래픽"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "공용 인터페이스의 네트워크 트래픽"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "결과가 없습니다."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "시스템을 찾을 수 없습니다."
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "알림"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "OAuth 2 / OIDC 지원"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "메뉴 열기"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "또는 아래 항목으로 진행하기"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "기존 알림 덮어쓰기"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "페이지"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "페이지 / 설정"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "비밀번호"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "비밀번호는 최소 8자 이상이어야 합니다."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr "비밀번호는 72 바이트 이하여야 합니다."
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "비밀번호 재설정 요청이 접수되었습니다"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "일시 중지"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "일시정지됨"
#: src/components/routes/settings/notifications.tsx
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
msgstr "알림이 전달되도록 <0>SMTP 서버를 구성</0>하세요."
#: src/components/alerts/alerts-system.tsx
msgid "Please check logs for more details."
msgstr "자세한 내용은 로그를 확인하세요."
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "자격 증명을 확인하고 다시 시도하세요."
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "관리자 계정을 생성하세요."
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "이 사이트에 대해 팝업을 활성화하세요."
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "다시 로그인하세요."
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "사용법은 <0>문서</0>를 참조하세요."
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "계정에 로그인하세요."
#: src/components/add-system.tsx
msgid "Port"
msgstr "포트"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "기록된 시간의 정확한 사용량"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "선호 언어"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "공개 키"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "읽기"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "수신됨"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "비밀번호 재설정"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "재개"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Enter 키 또는 쉼표를 사용하여 주소를 저장하세요. 이메일 알림을 비활성화하려면 비워 두세요."
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "설정 저장"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "시스템 저장"
#: src/components/navbar.tsx
msgid "Search"
msgstr "검색"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "시스템 또는 설정 검색..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "보냄"
#: src/components/routes/settings/general.tsx
msgid "Sets the default time range for charts when a system is viewed."
msgstr "시스템을 볼 때 차트의 기본 시간 범위를 설정합니다."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "설정"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "설정이 저장되었습니다."
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "로그인"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "SMTP 설정"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "정렬 기준"
#: src/lib/utils.ts
msgid "Status"
msgstr "상태"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "시스템에서 사용된 스왑 공간"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "스왑 사용량"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "시스템"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "시스템"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "표"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "온도"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "온도"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "시스템 센서의 온도"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "테스트 <0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "테스트 알림이 전송되었습니다."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "그런 다음 백엔드에 로그인하여 사용자 테이블에서 사용자 계정 비밀번호를 재설정하세요."
#: src/components/systems-table/systems-table.tsx
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
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName}의 처리량"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "루트 파일 시스템의 처리량"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "받는사람(들)"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "그리드 전환"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "테마 전환"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "센서가 임계값을 초과할 때 트리거됩니다."
#: src/lib/utils.ts
msgid "Triggers when combined up/down exceeds a threshold"
msgstr "업로드와 다운로드 대역폭의 합이 임계값을 초과할 때 트리거됩니다."
#: src/lib/utils.ts
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "CPU 사용량이 임계값을 초과할 때 트리거됩니다."
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "메모리 사용량이 임계값을 초과할 때 트리거됩니다."
#: src/lib/utils.ts
msgid "Triggers when status switches between up and down"
msgstr "시스템의 전원이 켜지거나 꺼질때 트리거됩니다."
#: src/lib/utils.ts
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "디스크 사용량이 임계값을 초과할 때 트리거됩니다."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr "온라인"
#: src/components/systems-table/systems-table.tsx
msgid "Updated in real time. Click on a system to view information."
msgstr "실시간으로 업데이트됩니다. 시스템을 클릭하여 정보를 확인하세요."
#: src/components/routes/system.tsx
msgid "Uptime"
msgstr "가동 시간"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "사용량"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "루트 파티션의 사용량"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "사용됨"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "사용자"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "보기"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "표시할 열"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "표시할 충분한 기록을 기다리는 중"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
msgstr "번역을 더 좋게 만드는 데 도움을 주시겠습니까? 자세한 내용은 <0>Crowdin</0>을 확인하세요."
#: src/components/routes/settings/notifications.tsx
msgid "Webhook / Push notifications"
msgstr "Webhook / 푸시 알림"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows 명령어"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "쓰기"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML 구성"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML 구성"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "사용자 설정이 업데이트되었습니다."

View File

@@ -1,966 +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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dag} other {# dagen}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# uur} other {# uren}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1 uur"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 week"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12 uren"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 uren"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30 dagen"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Acties"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Actieve waarschuwingen"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "Voeg <0>Systeem</0> toe"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "Nieuw systeem toevoegen"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "Voeg systeem toe"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "Voeg URL toe"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "Weergaveopties voor grafieken aanpassen."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "Admin"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "Agent"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "Waarschuwingen"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "Alle systemen"
#: src/components/systems-table/systems-table.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "Weet je zeker dat je {name} wilt verwijderen?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Automatisch kopiëren vereist een veilige context."
#: src/components/routes/system.tsx
msgid "Average"
msgstr "Gemiddelde"
#: src/components/routes/system.tsx
msgid "Average CPU utilization of containers"
msgstr "Gemiddeld CPU-gebruik van containers"
#. placeholder {0}: data.alert.unit
#: src/components/alerts/alerts-system.tsx
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Gemiddelde overschrijdt <0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "Gemiddeld stroomverbruik van GPU's"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "Gemiddeld systeembrede CPU-gebruik"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "Gemiddeld gebruik van {0}"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "Back-ups"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "Bandbreedte"
#: src/components/login/auth-form.tsx
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
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
msgid "Binary"
msgstr "Binair"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / Buffers"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "Annuleren"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "Opgelet - potentieel gegevensverlies"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Wijzig algemene applicatie opties."
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "Grafiekopties"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "Controleer {email} op een reset link."
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "Controleer de logs voor meer details."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "Controleer je meldingsservice"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "Klik om te kopiëren"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "Instructies voor de opdrachtregel"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "Configureer hoe je waarschuwingsmeldingen ontvangt."
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "Bevestig wachtwoord"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "Volgende"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "Gekopieerd naar het klembord"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Docker compose kopiëren"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Docker run kopiëren"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopieer host"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopieer Linux-opdracht"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "Kopieer tekst"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Processorgebruik"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "Account aanmaken"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "Donker"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "Dashboard"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "Standaard tijdsduur"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "Verwijderen"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Schijf"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "Schijf I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "Schijfgebruik"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Schijfgebruik van {extraFsName}"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Docker CPU-gebruik"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Docker geheugengebruik"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Docker netwerk I/O"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "Documentatie"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Offline"
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr "Bewerken"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "E-mail"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "E-mailnotificaties"
#: src/components/login/login.tsx
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
msgid "Enter email address..."
msgstr "Voer een e-mailadres in..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Fout"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "Configuratie exporteren"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "Exporteer je huidige systeemconfiguratie."
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Authenticatie mislukt"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "Instellingen opslaan mislukt"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "Versturen test notificatie mislukt"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "Bijwerken waarschuwing mislukt"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "Wachtwoord vergeten?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "Algemeen"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "GPU stroomverbruik"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "Raster"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew-commando"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "Host / IP-adres"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "Ongeldig e-mailadres."
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Kernel"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "Taal"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "Indeling"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "Licht"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Afmelden"
#: src/components/login/login.tsx
msgid "Login"
msgstr "Aanmelden"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "Aanmelding mislukt"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "Logs"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "Weergave- en notificatievoorkeuren beheren."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "Handmatige installatie-instructies"
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "Max 1 min"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "Geheugen"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "Geheugengebruik"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Geheugengebruik van docker containers"
#: src/components/add-system.tsx
msgid "Name"
msgstr "Naam"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "Net"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Netwerkverkeer van docker containers"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "Netwerkverkeer van publieke interfaces"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Geen resultaten gevonden."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "Geen systemen gevonden."
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "Meldingen"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "OAuth 2 / OIDC ondersteuning"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Open menu"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "Of ga verder met"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "Overschrijf bestaande waarschuwingen"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "Pagina"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Pagina's / Instellingen"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "Wachtwoord"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "Het wachtwoord moet minimaal 8 tekens bevatten."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr "Het wachtwoord moet minder zijn dat 72 bytes."
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "Wachtwoord reset aanvraag ontvangen"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "Pauze"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "Gepauzeerd"
#: src/components/routes/settings/notifications.tsx
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
msgid "Please check logs for more details."
msgstr "Controleer de logs voor meer details."
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "Controleer je aanmeldgegevens en probeer het opnieuw"
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "Maak een beheerdersaccount aan"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "Activeer pop-ups voor deze website"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "Meld je opnieuw aan"
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "Bekijk <0>de documentatie</0> voor instructies."
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "Meld je aan bij je account"
#: src/components/add-system.tsx
msgid "Port"
msgstr "Poort"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "Nauwkeurig gebruik op de opgenomen tijd"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "Voorkeurstaal"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "Publieke sleutel"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Lezen"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Ontvangen"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "Wachtwoord resetten"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Hervatten"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/notifications.tsx
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
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "Instellingen opslaan"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "Systeem bewaren"
#: src/components/navbar.tsx
msgid "Search"
msgstr "Zoeken"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "Zoek naar systemen of instellingen..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "Verzonden"
#: src/components/routes/settings/general.tsx
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
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "Instellingen"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "Instellingen opgeslagen"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "Aanmelden"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "SMTP-instellingen"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "Sorteren op"
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "Swap ruimte gebruikt door het systeem"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "Swap gebruik"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Systeem"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Systemen"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "Tabel"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "Temperatuur"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Temperatuur"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperatuur van systeem sensoren"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "Test <0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "Testmelding verzonden"
#: src/components/login/forgot-pass-form.tsx
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
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
msgid "Throughput of {extraFsName}"
msgstr "Doorvoer van {extraFsName}"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "Doorvoer van het root bestandssysteem"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "Naar e-mail(s)"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "Schakel raster"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "Schakel thema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Triggert wanneer een sensor een drempelwaarde overschrijdt"
#: src/lib/utils.ts
msgid "Triggers when combined up/down exceeds a threshold"
msgstr "Triggert wanneer de gecombineerde up/down een drempelwaarde overschrijdt"
#: src/lib/utils.ts
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "Triggert wanneer het CPU-gebruik een drempelwaarde overschrijdt"
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "Triggert wanneer het geheugengebruik een drempelwaarde overschrijdt"
#: src/lib/utils.ts
msgid "Triggers when status switches between up and down"
msgstr "Triggert wanneer de status schakelt tussen up en down"
#: src/lib/utils.ts
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Triggert wanneer het gebruik van een schijf een drempelwaarde overschrijdt"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr "Online"
#: src/components/systems-table/systems-table.tsx
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
msgid "Uptime"
msgstr "Actief"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Gebruik"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "Gebruik van root-partitie"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Gebruikt"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "Gebruikers"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Weergave"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Zichtbare kolommen"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "Wachtend op genoeg records om weer te geven"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for 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
msgid "Webhook / Push notifications"
msgstr "Webhook / Pushmeldingen"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows-commando"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Schrijven"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML Configuratie"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML Configuratie"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Je gebruikersinstellingen zijn bijgewerkt."

View File

@@ -1,966 +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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dag} other {# dager}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# time} other {# timer}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1 time"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 uke"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12 timer"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 timer"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30 dager"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Handlinger"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktive Alarmer"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "Legg til <0>System</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "Legg Til Nytt System"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "Legg til system"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "Legg Til URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "Juster visningsalternativer for diagrammer."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "Admin"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "Agent"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "Alarmer"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "Alle Systemer"
#: src/components/systems-table/systems-table.tsx
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
msgid "Automatic copy requires a secure context."
msgstr "Automatisk kopiering krever en sikker kontekst."
#: src/components/routes/system.tsx
msgid "Average"
msgstr "Gjennomsnitt"
#: src/components/routes/system.tsx
msgid "Average CPU utilization of containers"
msgstr "Gjennomsnittlig CPU-utnyttelse av konteinere"
#. placeholder {0}: data.alert.unit
#: src/components/alerts/alerts-system.tsx
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Gjennomsnittet overstiger <0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "Gjennomsnittlig strømforbruk for GPU-er"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "Gjennomsnittlig CPU-utnyttelse for hele systemet"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "Gjennomsnittlig utnyttelse av {0}"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "Sikkerhetskopier"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "Båndbredde"
#: src/components/login/auth-form.tsx
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
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
msgid "Binary"
msgstr "Binær"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / Buffere"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "Avbryt"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "Advarsel - potensielt tap av data"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Endre generelle program-innstillinger."
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "Diagraminnstillinger"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "Sjekk {email} for en nullstillings-link."
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "Sjekk loggene for flere detaljer."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "Sjekk din meldingstjeneste"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "Klikk for å kopiere"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "Kommandolinje-instrukser"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "Konfigurer hvordan du vil motta alarmvarsler."
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "Bekreft passord"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "Fortsett"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "Kopiert til utklippstavlen"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Kopier docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Kopier docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopier vert"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopier Linux-kommando"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "Kopier tekst"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU-bruk"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "Opprett konto"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "Mørkt"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "Dashbord"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "Standard tidsperiode"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "Slett"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "Disk I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "Diskbruk"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Diskbruk av {extraFsName}"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Docker CPU-bruk"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Docker Minnebruk"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Docker Nettverks-I/O"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "Dokumentasjon"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Nede"
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr "Rediger"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "E-post"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "E-postvarslinger"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
msgstr "Skriv inn e-postadresse for å nullstille passordet"
#: src/components/routes/settings/notifications.tsx
msgid "Enter email address..."
msgstr "Skriv inn e-postadresse..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Feil"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "Eksporter konfigurasjon"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "Eksporter din nåværende systemkonfigurasjon"
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Autentisering mislyktes"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "Kunne ikke lagre innstillingene"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "Kunne ikke sende test-varsling"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "Kunne ikke oppdatere alarm"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "Glemt passord?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "Generelt"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "GPU Effektforbruk"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "Rutenett"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew-kommando"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "Vert / IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "Ugyldig e-postadresse."
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Kjerne"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "Språk"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "Layout"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "Lyst"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Logg Ut"
#: src/components/login/login.tsx
msgid "Login"
msgstr "Logg Inn"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "Innlogging mislyktes"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "Logger"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "Endre visnings- og varslingsinnstillinger."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "Instruks for Manuell Installasjon"
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "Maks 1 min"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "Minne"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "Minnebruk"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Minnebruk av docker-konteinere"
#: src/components/add-system.tsx
msgid "Name"
msgstr "Navn"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "Nett"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Nettverkstrafikk av docker-konteinere"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "Nettverkstrafikk av eksterne nettverksgrensesnitt"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Ingen resultater funnet."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "Ingen systemer funnet."
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "Varslinger"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "OAuth 2 / OIDC-støtte"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Åpne meny"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "Eller fortsett med"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "Overskriv eksisterende alarmer"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "Side"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Sider / Innstillinger"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "Passord"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "Passord må bestå av minst 8 tegn."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr "Passord må være mindre enn 72 byte."
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "Mottatt forespørsel om å nullstille passord"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "Pause"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "Pauset"
#: src/components/routes/settings/notifications.tsx
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
msgid "Please check logs for more details."
msgstr "Vennligst sjekk loggene for mer informasjon."
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "Vennligst kontroller dine innloggingsopplysninger og prøv igjen"
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "Vennligst opprett en admin-konto"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "Vennligst aktiver pop-ups for nettsiden"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "Vennligst logg inn på nytt"
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "Vennligst se <0>dokumentasjonen</0> for instrukser."
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "Vennligst logg inn på kontoen din"
#: src/components/add-system.tsx
msgid "Port"
msgstr "Port"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "Nøyaktig utnyttelse på registrert tidspunkt"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "Foretrukket Språk"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "Offentlig Nøkkel"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Lesing"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Mottatt"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "Nullstill Passord"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Gjenoppta"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/notifications.tsx
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
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "Lagre Innstillinger"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "Lagre system"
#: src/components/navbar.tsx
msgid "Search"
msgstr "Søk"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "Søk etter systemer eller innstillinger..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "Sendt"
#: src/components/routes/settings/general.tsx
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
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "Innstillinger"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "Innstillinger lagret"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "Logg inn"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "SMTP-innstillinger"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "Sorter Etter"
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "Swap-plass i bruk av systemet"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "Swap-bruk"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "System"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Systemer"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "Tabell"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "Temp"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Temperatur"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperaturer på system-sensorer"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "Test <0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "Test-varsling sendt"
#: src/components/login/forgot-pass-form.tsx
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
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
msgid "Throughput of {extraFsName}"
msgstr "Gjennomstrømning av {extraFsName}"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "Gjennomstrømning av rot-filsystemet"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "Til e-postadresse(r)"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "Rutenett av/på"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "Tema av/på"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Slår inn når enhver sensor overstiger en grenseverdi"
#: src/lib/utils.ts
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
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "Slår inn når CPU-bruken overstiger en grenseverdi"
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "Slår inn når minnebruken overstiger en grenseverdi"
#: src/lib/utils.ts
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
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"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr "Oppe"
#: src/components/systems-table/systems-table.tsx
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
msgid "Uptime"
msgstr "Oppetid"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Forbruk"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "Forbruk av rot-partisjon"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Brukt"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "Brukere"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Visning"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Synlige Felter"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "Venter på nok registreringer til å vise"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for 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
msgid "Webhook / Push notifications"
msgstr "Webhook / Push-varslinger"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows-kommando"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Skriving"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML Oppsett"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML Konfigurasjon"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Dine brukerinnstillinger har blitt oppdatert."

View File

@@ -1,966 +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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dzień} few {# dni} many {# dni} other {# dni}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {godzinę} few {# godziny} many {# godzin} other {# godziny}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1 godzina"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 tydzień"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12 godzin"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 godziny"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30 dni"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Akcje"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktywne alerty"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "Dodaj <0>system</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "Dodaj nowy system"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "Dodaj system"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "Dodaj URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "Dostosuj opcje wyświetlania wykresów."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "Admin"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "Agent"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "Alerty"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "Wszystkie systemy"
#: src/components/systems-table/systems-table.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "Czy na pewno chcesz usunąć {name}?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Automatyczne kopiowanie wymaga bezpiecznego kontekstu."
#: src/components/routes/system.tsx
msgid "Average"
msgstr "Średnia"
#: src/components/routes/system.tsx
msgid "Average CPU utilization of containers"
msgstr "Średnie wykorzystanie procesora przez kontenery"
#. placeholder {0}: data.alert.unit
#: src/components/alerts/alerts-system.tsx
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Średnia przekracza <0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "Średnie zużycie energii przez GPU"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "Średnie wykorzystanie procesora w całym systemie"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "Średnie użycie {0}"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "Kopie"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "Przepustowość"
#: src/components/login/auth-form.tsx
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
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
msgid "Binary"
msgstr "Plik binarny"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Pamięć podręczna / Bufory"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "Anuluj"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "Uwaga- potencjalna utrata danych."
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Zmiana ogólnych ustawień aplikacji."
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "Opcje wykresu"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "Sprawdź {email}, aby uzyskać link do resetowania."
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "Sprawdź logi, aby uzyskać więcej informacji."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "Sprawdź swój serwis powiadomień"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "Kliknij, aby skopiować"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "Instrukcje wiersza poleceń"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "Skonfiguruj sposób otrzymywania powiadomień."
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "Potwierdź hasło"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "Kontynuuj"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "Skopiowano do schowka"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Skopiuj docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Skopiuj docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopiuj host"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopiuj polecenie Linux"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "Kopiuj tekst"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "Procesor"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Użycie procesora"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "Utwórz konto"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "Ciemny"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "Panel kontrolny"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "Domyślny przedział czasu"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "Usuń"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Dysk"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "Dysk I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "Użycie dysku"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Wykorzystanie dysku {extraFsName}"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Wykorzystanie procesora przez Docker"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Wykorzystanie pamięci przez Docker"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Sieć Docker I/O"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "Dokumentacja"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr ""
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "E-mail"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "Powiadomienia e-mail"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
msgstr "Wprowadź adres e-mail, aby zresetować hasło"
#: src/components/routes/settings/notifications.tsx
msgid "Enter email address..."
msgstr "Wprowadź adres e-mail..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Błąd"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "Eksportuj konfigurację"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "Eksportuj aktualną konfigurację systemów."
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Błąd autoryzacji"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "Nie udało się zapisać ustawień"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "Nie udało się wysłać testowego powiadomienia"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "Nie udało się zaktualizować powiadomienia"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "Filtruj..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "Zapomniałeś hasła?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "Ogólne"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "Moc GPU"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "Siatka"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Polecenie Homebrew"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "Host / adres IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "Nieprawidłowy adres e-mail."
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Jądro"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "Język"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "Układ"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "Jasny"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Wyloguj"
#: src/components/login/login.tsx
msgid "Login"
msgstr "Logowanie"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "Próba logowania nie powiodła się"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "Logi"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "Zarządzaj preferencjami wyświetlania i powiadomień."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "Maks. 1 min"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "Pamięć"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "Wykorzystanie pamięci"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Użycie pamięci przez kontenery Docker."
#: src/components/add-system.tsx
msgid "Name"
msgstr "Nazwa"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "Sieć"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Ruch sieciowy kontenerów Docker."
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "Ruch sieciowy interfejsów publicznych"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Brak wyników."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "Nie znaleziono systemów."
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "Powiadomienia"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "Wsparcie OAuth 2 / OIDC"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Otwórz menu"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "Lub kontynuuj z"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "Nadpisz istniejące alerty"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "Strona"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Strony / Ustawienia"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "Hasło"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "Hasło musi mieć co najmniej 8 znaków."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr ""
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "Otrzymane żądanie resetowania hasła"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "Pauza"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "Wstrzymane"
#: src/components/routes/settings/notifications.tsx
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
msgid "Please check logs for more details."
msgstr "Sprawdź logi, aby uzyskać więcej informacji."
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "Sprawdź swoje poświadczenia i spróbuj ponownie"
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "Utwórz konto administratora"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "Włącz wyskakujące okna dla tej strony"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "Zaloguj się ponownie"
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "Proszę zapoznać się z <0>dokumentacją</0>."
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "Zaloguj się na swoje konto"
#: src/components/add-system.tsx
msgid "Port"
msgstr "Port"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "Dokładne wykorzystanie w zarejestrowanym czasie"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "Preferowany język"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "Klucz publiczny"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Czytaj"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Otrzymane"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "Resetuj hasło"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Wznów"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/notifications.tsx
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
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "Zapisz ustawienia"
#: src/components/add-system.tsx
msgid "Save system"
msgstr ""
#: src/components/navbar.tsx
msgid "Search"
msgstr "Szukaj"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "Szukaj systemów lub ustawień..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "Wysłane"
#: src/components/routes/settings/general.tsx
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
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "Ustawienia"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "Ustawienia zapisane"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "Zaloguj się"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "Ustawienia SMTP"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "Sortuj według"
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "Pamięć wymiany używana przez system"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "Użycie pamięci wymiany"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "System"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Systemy"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "Tabela"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Temperatura"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperatury czujników systemowych."
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "Test <0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "Testowe powiadomienie wysłane."
#: src/components/login/forgot-pass-form.tsx
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
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
msgid "Throughput of {extraFsName}"
msgstr "Przepustowość {extraFsName}"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "Przepustowość głównego systemu plików"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "Do e-mail(ów)"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "Przełącz siatkę"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "Zmień motyw"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Wyzwalane, gdy jakikolwiek czujnik przekroczy ustalony próg."
#: src/lib/utils.ts
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
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "Wyzwalane, gdy użycie procesora przekracza próg"
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "Wyzwalane, wykorzystanie pamięci przekroczy ustalony próg."
#: src/lib/utils.ts
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
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Wyzwalane, gdy wykorzystanie któregokolwiek dysku przekroczy ustalony próg"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr ""
#: src/components/systems-table/systems-table.tsx
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
msgid "Uptime"
msgstr "Czas pracy"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Wykorzystanie"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "Użycie partycji głównej"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Używane"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "Użytkownicy"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Widok"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Widoczne kolumny"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "Oczekiwanie na wystarczającą liczbę rekordów do wyświetlenia"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for 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
msgid "Webhook / Push notifications"
msgstr "Webhook / Powiadomienia push"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Polecenie Windows"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Napisz"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "Konf. YAML"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "Konfiguracja YAML"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Twoje ustawienia użytkownika zostały zaktualizowane."

View File

@@ -1,966 +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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dan} two {# dneva} few {# dni} other {# dni}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# ura} two {# uri} few {# ur} other {# ur}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1 ura"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 teden"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12 ur"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 ur"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30 dni"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Dejanja"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktivna opozorila"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "Dodaj <0>sistem</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "Dodaj nov sistem"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "Dodaj sistem"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "Dodaj URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "Prilagodi možnosti prikaza za grafikone."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "Administrator"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "Agent"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "Opozorila"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "Vsi sistemi"
#: src/components/systems-table/systems-table.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "Ali ste prepričani, da želite izbrisati {name}?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Za samodejno kopiranje je potreben varen kontekst."
#: src/components/routes/system.tsx
msgid "Average"
msgstr "Povprečno"
#: src/components/routes/system.tsx
msgid "Average CPU utilization of containers"
msgstr "Povprečna izkoriščenost procesorja kontejnerjev"
#. placeholder {0}: data.alert.unit
#: src/components/alerts/alerts-system.tsx
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Povprečje presega <0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "Povprečna poraba energije GPU"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "Povprečna CPU izkoriščenost v celotnem sistemu"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "Povprečna poraba {0}"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "Varnostne kopije"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "Pasovna širina"
#: src/components/login/auth-form.tsx
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
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
msgid "Binary"
msgstr "Binarno"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Predpomnilnik / medpomnilniki"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "Prekliči"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "Pozor - možna izguba podatkov"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Spremeni splošne možnosti aplikacije."
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "Možnosti grafikona"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "Preverite {email} za povezavo za ponastavitev."
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "Za več podrobnosti preverite dnevnike."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "Preverite storitev obveščanja"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "Klikni za kopiranje"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "Navodila za ukazno vrstico"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "Nastavi način prejemanja opozorilnih obvestil."
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "Potrdite geslo"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "Nadaljuj"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "Kopirano v odložišče"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Kopiraj docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Kopiraj docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopiraj gostitelja"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopiraj Linux ukaz"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "Kopiraj besedilo"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU poraba"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "Ustvari račun"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "Temno"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "Nadzorna plošča"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "Privzeto časovno obdobje"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "Izbriši"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "Disk I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "Poraba diska"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Poraba diska za {extraFsName}"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Docker CPU poraba"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Docker poraba spomina"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Docker I/O mreže"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "Dokumentacija"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr ""
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "E-pošta"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "E-poštna obvestila"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
msgstr "Vnesite e-poštni naslov za ponastavitev gesla"
#: src/components/routes/settings/notifications.tsx
msgid "Enter email address..."
msgstr "Vnesite e-poštni naslov..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Napaka"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "Izvozi nastavitve"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "Izvozi trenutne nastavitve sistema."
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Preverjanje pristnosti ni uspelo"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "Shranjevanje nastavitev ni uspelo"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "Pošiljanje testnega obvestila ni uspelo"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "Opozorila ni bilo mogoče posodobiti"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "Pozabljeno geslo?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "Splošno"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "GPU poraba moči"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "Mreža"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Ukaz Homebrew"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "Gostitelj / IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "Napačen e-poštni naslov."
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Jedro"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "Jezik"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "Postavitev"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "Svetlo"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Odjava"
#: src/components/login/login.tsx
msgid "Login"
msgstr "Prijava"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "Poskus prijave ni uspel"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "Dnevniki"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "Upravljajte nastavitve prikaza in obvestil."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "Največ 1 min"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "Pomnilnik"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "Poraba pomnilnika"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Poraba pomnilnika docker kontejnerjev"
#: src/components/add-system.tsx
msgid "Name"
msgstr "Naziv"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "Mreža"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Omrežni promet docker kontejnerjev"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "Omrežni promet javnih vmesnikov"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Ni rezultatov."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "Ne najdem sistema."
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "Obvestila"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "Podpora za OAuth 2 / OIDC"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Odpri menu"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "Ali nadaljuj z"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "Prepiši obstoječe alarme"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "Stran"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Strani / Nastavitve"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "Geslo"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "Geslo mora imeti vsaj 8 znakov."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr ""
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "Prejeta zahteva za ponastavitev gesla"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "Premor"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "Zaustavljeno"
#: src/components/routes/settings/notifications.tsx
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
msgid "Please check logs for more details."
msgstr "Za več podrobnosti preverite dnevnike."
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "Preverite svoje poverilnice in poskusite znova"
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "Ustvarite skrbniški račun"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "Omogočite pojavna okna za to spletno mesto"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "Prosimo, prijavite se znova"
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "Za navodila glejte <0>dokumentacijo</0>."
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "Prijavite se v svoj račun"
#: src/components/add-system.tsx
msgid "Port"
msgstr "Vrata"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "Natančna poraba v zabeleženem času"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "Prednostni jezik"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "Javni ključ"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Preberano"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Prejeto"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "Ponastavi geslo"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Nadaljuj"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/notifications.tsx
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
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "Shrani nastavitve"
#: src/components/add-system.tsx
msgid "Save system"
msgstr ""
#: src/components/navbar.tsx
msgid "Search"
msgstr "Iskanje"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "Iskanje sistemov ali nastavitev..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "Poslano"
#: src/components/routes/settings/general.tsx
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
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "Nastavitve"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "Nastavitve so shranjene"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "Prijavite se"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "SMTP nastavitve"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "Razvrsti po"
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "Swap prostor, ki ga uporablja sistem"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "Swap uporaba"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Sistemsko"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Sistemi"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "Tabela"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Temperatura"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperature sistemskih senzorjev"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "Preveri <0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "Testno obvestilo je poslano"
#: src/components/login/forgot-pass-form.tsx
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
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
msgid "Throughput of {extraFsName}"
msgstr "Prepustnost {extraFsName}"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "Prepustnost korenskega datotečnega sistema"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "E-pošta za"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "Preklopi način mreže"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "Obrni temo"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Sproži se, ko kateri koli senzor preseže prag"
#: src/lib/utils.ts
msgid "Triggers when combined up/down exceeds a threshold"
msgstr "Sproži, ko kombinacija gor/dol preseže prag"
#: src/lib/utils.ts
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "Sproži se, ko poraba procesorja preseže prag"
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "Sproži se, ko uporaba pomnilnika preseže prag"
#: src/lib/utils.ts
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
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Sproži se, ko uporaba katerega koli diska preseže prag"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr ""
#: src/components/systems-table/systems-table.tsx
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
msgid "Uptime"
msgstr "Čas delovanja"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Uporaba"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "Uporaba korenske particije"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Uporabljeno"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "Uporabniki"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Pogled"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Vidna polja"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "Čakam na dovolj zapisov za prikaz"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for 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
msgid "Webhook / Push notifications"
msgstr "Webhook / potisna obvestila"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Ukaz Windows"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Pisanje"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML nastaviitev"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML nastavitev"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Vaše uporabniške nastavitve so posodobljene."

View File

@@ -1,966 +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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dag} other {# dagar}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# timme} other {# timmar}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1 timme"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 vecka"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12 timmar"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 timmar"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30 dagar"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Åtgärder"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktiva larm"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "Lägg till <0>System</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "Lägg till nytt system"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "Lägg till system"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "Lägg till URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "Justera visningsalternativ för diagram."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "Admin"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "Agent"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "Larm"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "Alla system"
#: src/components/systems-table/systems-table.tsx
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
msgid "Automatic copy requires a secure context."
msgstr "Automatisk kopiering kräver en säker kontext."
#: src/components/routes/system.tsx
msgid "Average"
msgstr "Genomsnitt"
#: src/components/routes/system.tsx
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
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Genomsnittet överskrider <0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "Genomsnittlig strömförbrukning för GPU:er"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "Genomsnittlig systemomfattande CPU-användning"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "Genomsnittlig användning av {0}"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "Säkerhetskopior"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "Bandbredd"
#: src/components/login/auth-form.tsx
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
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
msgid "Binary"
msgstr "Binär"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / Buffertar"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "Avbryt"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "Varning - potentiell dataförlust"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Ändra allmänna programalternativ."
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "Diagramalternativ"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "Kontrollera {email} för en återställningslänk."
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "Kontrollera loggarna för mer information."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "Kontrollera din aviseringstjänst"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "Klicka för att kopiera"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "Instruktioner för kommandoraden"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "Konfigurera hur du tar emot larmaviseringar."
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "Bekräfta lösenord"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "Fortsätt"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "Kopierat till urklipp"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Kopiera docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Kopiera docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopiera värd"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopiera Linux-kommando"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "Kopiera text"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU-användning"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "Skapa konto"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "Mörkt"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "Dashboard"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "Standardtidsperiod"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "Ta bort"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "Disk I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "Diskanvändning"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Diskanvändning av {extraFsName}"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Docker CPU-användning"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Docker Minnesanvändning"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Docker Nätverks-I/O"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "Dokumentation"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr ""
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "E-post"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "E-postaviseringar"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
msgstr "Ange e-postadress för att återställa lösenord"
#: src/components/routes/settings/notifications.tsx
msgid "Enter email address..."
msgstr "Ange e-postadress..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Fel"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "Exportera konfiguration"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "Exportera din nuvarande systemkonfiguration."
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Autentisering misslyckades"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "Kunde inte spara inställningar"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "Kunde inte skicka testavisering"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "Kunde inte uppdatera larm"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "Filtrera..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "Glömt lösenordet?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "Allmänt"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "GPU-strömförbrukning"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "Rutnät"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew-kommando"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "Värd / IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "Ogiltig e-postadress."
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Kärna"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "Språk"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "Layout"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "Ljust"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Logga ut"
#: src/components/login/login.tsx
msgid "Login"
msgstr "Logga in"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "Inloggningsförsök misslyckades"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "Loggar"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "Hantera visnings- och aviseringsinställningar."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "Max 1 min"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "Minne"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "Minnesanvändning"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Minnesanvändning för dockercontainrar"
#: src/components/add-system.tsx
msgid "Name"
msgstr "Namn"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "Nät"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Nätverkstrafik för dockercontainrar"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "Nätverkstrafik för publika gränssnitt"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Inga resultat hittades."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "Inga system hittades."
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "Aviseringar"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "Stöd för OAuth 2 / OIDC"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Öppna menyn"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "Eller fortsätt med"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "Skriv över befintliga larm"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "Sida"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Sidor / Inställningar"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "Lösenord"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "Lösenordet måste vara minst 8 tecken."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr ""
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "Begäran om återställning av lösenord mottagen"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "Paus"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "Pausad"
#: src/components/routes/settings/notifications.tsx
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
msgid "Please check logs for more details."
msgstr "Vänligen kontrollera loggarna för mer information."
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "Vänligen kontrollera dina inloggningsuppgifter och försök igen"
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "Vänligen skapa ett administratörskonto"
#: src/components/login/auth-form.tsx
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
msgid "Please log in again"
msgstr "Vänligen logga in igen"
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "Vänligen se <0>dokumentationen</0> för instruktioner."
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "Vänligen logga in på ditt konto"
#: src/components/add-system.tsx
msgid "Port"
msgstr "Port"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "Exakt användning vid den registrerade tidpunkten"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "Föredraget språk"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "Offentlig nyckel"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Läs"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Mottaget"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "Återställ lösenord"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Återuppta"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/notifications.tsx
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
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "Spara inställningar"
#: src/components/add-system.tsx
msgid "Save system"
msgstr ""
#: src/components/navbar.tsx
msgid "Search"
msgstr "Sök"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "Sök efter system eller inställningar..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "Skickat"
#: src/components/routes/settings/general.tsx
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
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "Inställningar"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "Inställningar sparade"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "Logga in"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "SMTP-inställningar"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "Sortera efter"
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "Swap-utrymme som används av systemet"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "Swap-användning"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "System"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "System"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "Tabell"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Temperatur"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperaturer för systemsensorer"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "Testa <0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "Testavisering skickad"
#: src/components/login/forgot-pass-form.tsx
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
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
msgid "Throughput of {extraFsName}"
msgstr "Genomströmning av {extraFsName}"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "Genomströmning av rotfilsystemet"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "Till e-postadress(er)"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "Växla rutnät"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "Växla tema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
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
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
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
msgid "Triggers when memory usage exceeds a threshold"
msgstr "Utlöses när minnesanvändningen överskrider ett tröskelvärde"
#: src/lib/utils.ts
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
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"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr ""
#: src/components/systems-table/systems-table.tsx
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
msgid "Uptime"
msgstr "Drifttid"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Användning"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "Användning av rotpartitionen"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Använt"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "Användare"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Visa"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Synliga fält"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "Väntar på tillräckligt med poster att visa"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for 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
msgid "Webhook / Push notifications"
msgstr "Webhook / Push-aviseringar"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows-kommando"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Skriv"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML-konfiguration"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML-konfiguration"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Dina användarinställningar har uppdaterats."

View File

@@ -1,966 +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: zh\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: Chinese Simplified\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: beszel\n"
"X-Crowdin-Project-ID: 733311\n"
"X-Crowdin-Language: zh-CN\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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# 天} other {# 天}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# 小时} other {# 小时}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1小时"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1周"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12小时"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24小时"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30天"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "操作"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "启用的警报"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "添加<0>客户端</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "添加新客户端"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "添加客户端"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "添加URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "调整图表的显示选项。"
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "管理员"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "客户端"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "警报"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "所有客户端"
#: src/components/systems-table/systems-table.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "您确定要删除{name}吗?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "自动复制所需的安全上下文。"
#: src/components/routes/system.tsx
msgid "Average"
msgstr "平均"
#: src/components/routes/system.tsx
msgid "Average CPU utilization of containers"
msgstr "容器的平均 CPU 使用率"
#. placeholder {0}: data.alert.unit
#: src/components/alerts/alerts-system.tsx
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "平均值超过<0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "GPU 平均能耗"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "系统范围内的平均 CPU 使用率"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "{0} 平均利用率"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "备份"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "带宽"
#: src/components/login/auth-form.tsx
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
msgstr "Beszel支持OpenID Connect和其他OAuth2认证方式。"
#: src/components/routes/settings/notifications.tsx
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
msgstr "Beszel使用<0>Shoutrrr</0>以实现与常见的通知服务集成。"
#: src/components/add-system.tsx
msgid "Binary"
msgstr "二进制"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "缓存/缓冲区"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "取消"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "注意 - 数据可能已经丢失"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "更改常规应用程序选项。"
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "图表选项"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "检查 {email} 以获取重置链接。"
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "检查日志以获取更多详细信息。"
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "检查您的通知服务"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "点击复制"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "命令行说明"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "配置您接收警报通知的方式。"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "确认密码"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "继续"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "已复制到剪贴板"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "复制 docker compose 文件"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "复制 docker run 命令"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "复制环境变量"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "复制主机名"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "复制 Linux 安装命令"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "复制文本"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "复制下面的客户端安装命令,或使用<0>通用令牌</0>自动注册客户端。"
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr "复制下面的客户端<0>docker-compose.yml</0>内容,或使用<1>通用令牌</1>自动注册客户端。"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "复制YAML"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU使用率"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "创建账户"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "深色模式"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "仪表板"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "默认时间段"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "删除"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "删除指纹"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "磁盘"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "磁盘I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "磁盘使用"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "{extraFsName}的磁盘使用"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Docker CPU使用"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Docker内存使用"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Docker网络I/O"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "文档"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "停止"
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr "编辑"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "电子邮件"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "电子邮件通知"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
msgstr "输入电子邮件地址以重置密码"
#: src/components/routes/settings/notifications.tsx
msgid "Enter email address..."
msgstr "输入电子邮件地址..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "错误"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "导出配置"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "导出您当前的系统配置。"
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "认证失败"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "保存设置失败"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "发送测试通知失败"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "更新警报失败"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "过滤..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "忘记密码?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "常规"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "GPU 功耗"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "网格"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew 安装命令"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "主机/IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "无效的电子邮件地址。"
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "内核"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "语言"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "布局"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "浅色模式"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "登出"
#: src/components/login/login.tsx
msgid "Login"
msgstr "登录"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "登录尝试失败"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "日志"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "管理显示和通知偏好。"
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "手动设置说明"
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "1分钟内最大值"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "内存"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "内存使用"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Docker 容器的内存使用"
#: src/components/add-system.tsx
msgid "Name"
msgstr "名称"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "网络"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Docker 容器的网络流量"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "公共接口的网络流量"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "未找到结果。"
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "未找到系统。"
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "通知"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "支持 OAuth 2 / OIDC"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "打开菜单"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "或使用以下方式登录"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "覆盖现有警报"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "页面"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "页面/设置"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "密码"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "密码必须至少包含 8 个字符。"
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr "密码必须小于 72 字节。"
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "已收到密码重置请求"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "暂停"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "已暂停"
#: src/components/routes/settings/notifications.tsx
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
msgstr "请<0>配置SMTP服务器</0>以确保警报被传递。"
#: src/components/alerts/alerts-system.tsx
msgid "Please check logs for more details."
msgstr "请检查日志以获取更多详细信息。"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "请检查您的凭据并重试"
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "请创建一个管理员账户"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "请为此网站启用弹出窗口"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "请重新登录"
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "请参阅<0>文档</0>以获取说明。"
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "请登录您的账户"
#: src/components/add-system.tsx
msgid "Port"
msgstr "端口"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "采集时间下的精确内存使用率"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "首选语言"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "公钥"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "读取"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "接收"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "重置密码"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "恢复"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "轮换令牌"
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "使用回车键或逗号保存地址。留空以禁用电子邮件通知。"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "保存设置"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "保存系统"
#: src/components/navbar.tsx
msgid "Search"
msgstr "搜索"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "搜索系统或设置..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "发送"
#: src/components/routes/settings/general.tsx
msgid "Sets the default time range for charts when a system is viewed."
msgstr "设置查看系统时图表的默认时间范围。"
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "设置"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "设置已保存"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "登录"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "SMTP设置"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "排序依据"
#: src/lib/utils.ts
msgid "Status"
msgstr "状态"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "系统使用的 SWAP 空间"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "SWAP 使用"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "系统"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "系统"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "表格"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "温度"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "温度"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "系统传感器的温度"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "测试<0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "测试通知已发送"
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "然后登录到后台并在用户表中重置您的用户账户密码。"
#: src/components/systems-table/systems-table.tsx
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
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName}的吞吐量"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "根文件系统的吞吐量"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "发送到电子邮件"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "切换网格"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "切换主题"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "令牌"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "令牌和指纹"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr "令牌允许客户端连接和注册。指纹是每个系统唯一的稳定标识符,在首次连接时设置。"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "令牌和指纹用于验证到中心的WebSocket连接。"
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "当任何传感器超过阈值时触发"
#: src/lib/utils.ts
msgid "Triggers when combined up/down exceeds a threshold"
msgstr "当网络的上/下行速度超过阈值时触发"
#: src/lib/utils.ts
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "当CPU使用率超过阈值时触发"
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "当内存使用率超过阈值时触发"
#: src/lib/utils.ts
msgid "Triggers when status switches between up and down"
msgstr "当状态在上线与掉线之间切换时触发"
#: src/lib/utils.ts
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "当任何磁盘的使用率超过阈值时触发"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "通用令牌"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr "启动"
#: src/components/systems-table/systems-table.tsx
msgid "Updated in real time. Click on a system to view information."
msgstr "实时更新。点击系统查看信息。"
#: src/components/routes/system.tsx
msgid "Uptime"
msgstr "正常运行时间"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "使用"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "根分区的使用"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "已用"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "用户"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "视图"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "可见列"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "正在收集足够的数据来显示"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
msgstr "想帮助我们改进翻译吗?查看<0>Crowdin</0>以获取更多详细信息。"
#: src/components/routes/settings/notifications.tsx
msgid "Webhook / Push notifications"
msgstr "Webhook / 推送通知"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "启用时,此令牌允许客户端在无需预先创建系统的情况下自动注册。在一小时后或中心重启时过期。"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows 安装命令"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "写入"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML配置"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML配置"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "您的用户设置已更新。"

View File

@@ -1,966 +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: zh\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: Chinese Traditional, Hong Kong\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: beszel\n"
"X-Crowdin-Project-ID: 733311\n"
"X-Crowdin-Language: zh-HK\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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# 天} other {# 天}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# 小時} other {# 小時}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1小時"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1週"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12小時"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24小時"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30天"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "操作"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "活動警報"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "新增<0>系統</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "新增新系統"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "新增系統"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "添加 URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "調整圖表的顯示選項。"
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "管理員"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "客户端"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "警報"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "所有系統"
#: src/components/systems-table/systems-table.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "您確定要刪除 {name} 嗎?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "自動複製需要安全的上下文。"
#: src/components/routes/system.tsx
msgid "Average"
msgstr "平均"
#: src/components/routes/system.tsx
msgid "Average CPU utilization of containers"
msgstr "容器的平均 CPU 使用率"
#. placeholder {0}: data.alert.unit
#: src/components/alerts/alerts-system.tsx
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "平均值超過 <0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "GPU 的平均功耗"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "系統的平均 CPU 使用率"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "{0} 的平均使用率"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "備份"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "帶寬"
#: src/components/login/auth-form.tsx
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
msgstr "Beszel支持OpenID Connect和許多OAuth2認證提供者。"
#: src/components/routes/settings/notifications.tsx
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
msgstr "Beszel 使用 <0>Shoutrrr</0> 與流行的通知服務集成。"
#: src/components/add-system.tsx
msgid "Binary"
msgstr "執行檔"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "快取 / 緩衝區"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "取消"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "注意 - 可能遺失資料"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "更改一般應用選項。"
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "圖表選項"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "檢查 {email} 以獲取重置鏈接。"
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "檢查日誌以取得更多資訊。"
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "檢查您的通知服務"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "點擊以複製"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "命令行指令"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "配置您接收警報通知的方式。"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "確認密碼"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "繼續"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "已複製到剪貼板"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "複製 docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "複製 docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "複製環境變數"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "複製主機"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "複製 Linux 指令"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "複製文本"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "複製下面的代理程式安裝指令,或使用<0>通用令牌</0>自動註冊代理程式。"
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr "複製下面的代理程式<0>docker-compose.yml</0>內容,或使用<1>通用令牌</1>自動註冊代理程式。"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "複製YAML"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU 使用率"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "創建帳戶"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "深色"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "控制面板"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "預設時間段"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "刪除"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "刪除指紋"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "磁碟"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "磁碟 I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "磁碟使用"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "{extraFsName} 的磁碟使用量"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Docker CPU 使用率"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Docker 記憶體使用率"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Docker 網絡 I/O"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "文件"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr "編輯"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "電子郵件"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "電子郵件通知"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
msgstr "輸入電子郵件地址以重置密碼"
#: src/components/routes/settings/notifications.tsx
msgid "Enter email address..."
msgstr "輸入電子郵件地址..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "錯誤"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "匯出設定"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "匯出您現在的系統設定。"
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "認證失敗"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "儲存設定失敗"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "發送測試通知失敗"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "更新警報失敗"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "篩選..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "忘記密碼?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "一般"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "GPU 功耗"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "網格"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew 指令"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "主機 / IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "無效的電子郵件地址。"
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Kernel"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "語言"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "版面配置"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "淺色"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "登出"
#: src/components/login/login.tsx
msgid "Login"
msgstr "登入"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "登入嘗試失敗"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "日誌"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "管理顯示和通知偏好。"
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "手動設定說明"
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "一分鐘內最大值"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "記憶體"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "記憶體使用"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Docker 容器的記憶體使用量"
#: src/components/add-system.tsx
msgid "Name"
msgstr "名稱"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "網絡"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Docker 容器的網絡流量"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "公共接口的網絡流量"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "未找到結果。"
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "未找到系統。"
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "通知"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "支援 OAuth 2 / OIDC"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "開啟選單"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "或繼續使用"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "覆蓋現有警報"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "頁面"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "頁面 / 設定"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "密碼"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "密碼必須至少包含 8 個字符。"
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr "密碼必須少於 72 個字節。"
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "已收到密碼重設請求"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "暫停"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "已暫停"
#: src/components/routes/settings/notifications.tsx
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
msgstr "請<0>配置SMTP伺服器</0>以確保警報被傳送。"
#: src/components/alerts/alerts-system.tsx
msgid "Please check logs for more details."
msgstr "請檢查日誌以獲取更多資訊。"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "請檢查您的憑證並重試"
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "請建立一個管理員帳號"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "請為此網站啟用彈出窗口"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "請重新登入"
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "請參閱<0>文件</0>以取得說明。"
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "請登入您的帳號"
#: src/components/add-system.tsx
msgid "Port"
msgstr "端口"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "記錄時間的精確使用率"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "首選語言"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "公鑰"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "讀取"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "接收"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "重設密碼"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "恢復"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "輪換令牌"
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "使用回車鍵或逗號保存地址。留空以禁用電子郵件通知。"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "儲存設定"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "儲存系統"
#: src/components/navbar.tsx
msgid "Search"
msgstr "搜索"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "搜索系統或設置..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "發送"
#: src/components/routes/settings/general.tsx
msgid "Sets the default time range for charts when a system is viewed."
msgstr "設置查看系統時圖表的默認時間範圍。"
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "設置"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "設置已保存"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "登錄"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "SMTP設置"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "排序依據"
#: src/lib/utils.ts
msgid "Status"
msgstr "狀態"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "系統使用的交換空間"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "交換使用"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "系統"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "系統"
#: src/components/routes/settings/config-yaml.tsx
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
msgid "Table"
msgstr "表格"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "溫度"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "溫度"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "系統傳感器的溫度"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "測試<0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "測試通知已發送"
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "然後登錄到後端並在用戶表中重置您的用戶帳戶密碼。"
#: src/components/systems-table/systems-table.tsx
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
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName}的吞吐量"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "根文件系統的吞吐量"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "發送到電子郵件"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "切換網格"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "切換主題"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "令牌"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "令牌和指紋"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr "令牌允許代理程式連接和註冊。指紋是每個系統唯一的穩定識別符,在首次連接時設置。"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "令牌和指紋用於驗證到中心的WebSocket連接。"
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "當任何傳感器超過閾值時觸發"
#: src/lib/utils.ts
msgid "Triggers when combined up/down exceeds a threshold"
msgstr "當組合的上/下超過閾值時觸發"
#: src/lib/utils.ts
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "當CPU使用率超過閾值時觸發"
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "當記憶體使用率超過閾值時觸發"
#: src/lib/utils.ts
msgid "Triggers when status switches between up and down"
msgstr "當狀態在上和下之間切換時觸發"
#: src/lib/utils.ts
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "當任何磁碟的使用超過閾值時觸發"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "通用令牌"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Updated in real time. Click on a system to view information."
msgstr "實時更新。點擊系統查看信息。"
#: src/components/routes/system.tsx
msgid "Uptime"
msgstr "正常運行時間"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "使用"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "根分區的使用"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "已用"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "用戶"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "檢視"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "可見欄位"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "等待足夠的記錄以顯示"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
msgstr "想幫助我們改進翻譯嗎?查看<0>Crowdin</0>以獲取更多詳細信息。"
#: src/components/routes/settings/notifications.tsx
msgid "Webhook / Push notifications"
msgstr "Webhook / 推送通知"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "啟用時,此令牌允許代理程式在無需預先創建系統的情況下自動註冊。在一小時後或中心重啟時過期。"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows 指令"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "寫入"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML配置"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML配置"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "您的用戶設置已更新。"

View File

@@ -1,966 +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: zh\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: Chinese Traditional\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: beszel\n"
"X-Crowdin-Project-ID: 733311\n"
"X-Crowdin-Language: zh-TW\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
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# 天} other {# 天}}"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# 小時} other {# 小時}}"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1小時"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1週"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12小時"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24小時"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30天"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "操作"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "活動警報"
#: src/components/add-system.tsx
msgid "Add <0>System</0>"
msgstr "新增<0>系統</0>"
#: src/components/add-system.tsx
msgid "Add New System"
msgstr "新增新系統"
#: src/components/add-system.tsx
msgid "Add system"
msgstr "新增系統"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "新增 URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "調整圖表的顯示選項。"
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
msgstr "管理員"
#: src/components/systems-table/systems-table.tsx
msgid "Agent"
msgstr "代理"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
msgstr "警報"
#: src/components/systems-table/systems-table.tsx
#: src/components/alerts/alert-button.tsx
msgid "All Systems"
msgstr "所有系統"
#: src/components/systems-table/systems-table.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "您確定要刪除 {name} 嗎?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "只有在受保護的環境才能自動複製。"
#: src/components/routes/system.tsx
msgid "Average"
msgstr "平均"
#: src/components/routes/system.tsx
msgid "Average CPU utilization of containers"
msgstr "容器的平均 CPU 使用率"
#. placeholder {0}: data.alert.unit
#: src/components/alerts/alerts-system.tsx
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "平均值超過<0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "GPU 的平均功耗"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
msgstr "系統的平均 CPU 使用率"
#. placeholder {0}: gpu.n
#: src/components/routes/system.tsx
msgid "Average utilization of {0}"
msgstr "{0} 的平均使用率"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Backups"
msgstr "備份"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Bandwidth"
msgstr "網路流量"
#: src/components/login/auth-form.tsx
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
msgstr "Beszel支援OpenID Connect和許多OAuth2認證提供者。"
#: src/components/routes/settings/notifications.tsx
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
msgstr "Beszel 以 <0>Shoutrrr</0> 整合常用的通知服務。"
#: src/components/add-system.tsx
msgid "Binary"
msgstr "執行檔"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "快取/緩衝"
#: src/components/systems-table/systems-table.tsx
msgid "Cancel"
msgstr "取消"
#: src/components/routes/settings/config-yaml.tsx
msgid "Caution - potential data loss"
msgstr "注意 - 可能遺失資料"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "修改一般應用程式選項。"
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "圖表選項"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "檢查{email}以取得重設連結。"
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "檢查系統記錄以取得更多資訊。"
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "檢查您的通知服務"
#: src/components/ui/input-copy.tsx
msgid "Click to copy"
msgstr "點擊複製"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/forgot-pass-form.tsx
msgid "Command line instructions"
msgstr "命令列指令"
#: src/components/routes/settings/notifications.tsx
msgid "Configure how you receive alert notifications."
msgstr "設定您要如何接收警報通知"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
msgstr "確認密碼"
#: src/components/systems-table/systems-table.tsx
msgid "Continue"
msgstr "繼續"
#: src/lib/utils.ts
msgid "Copied to clipboard"
msgstr "已複製到剪貼簿"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "复制 docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "复制 docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "複製環境變數"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "複製主機"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "複製 Linux 指令"
#: src/components/copy-to-clipboard.tsx
msgid "Copy text"
msgstr "複製文字"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "複製下面的代理程式安裝指令,或使用<0>通用令牌</0>自動註冊代理程式。"
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr "複製下面的代理程式<0>docker-compose.yml</0>內容,或使用<1>通用令牌</1>自動註冊代理程式。"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "複製YAML"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU 使用率"
#: src/components/login/auth-form.tsx
msgid "Create account"
msgstr "建立帳號"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
msgstr "深色"
#: src/components/command-palette.tsx
#: src/components/routes/home.tsx
msgid "Dashboard"
msgstr "控制面板"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "預設時間段"
#: src/components/systems-table/systems-table.tsx
msgid "Delete"
msgstr "刪除"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "刪除指紋"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "磁碟"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "磁碟 I/O"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
msgid "Disk Usage"
msgstr "磁碟使用量"
#: src/components/routes/system.tsx
msgid "Disk usage of {extraFsName}"
msgstr "{extraFsName}的磁碟使用量"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Docker CPU 使用率"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Docker 記憶體使用率"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Docker 網路 I/O"
#: src/components/command-palette.tsx
msgid "Documentation"
msgstr "文件"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr "編輯"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Email"
msgstr "電子郵件"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
msgstr "電子郵件通知"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
msgstr "輸入電子郵件地址以重設密碼"
#: src/components/routes/settings/notifications.tsx
msgid "Enter email address..."
msgstr "輸入電子郵件地址..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "錯誤"
#. placeholder {0}: alert.value
#. placeholder {1}: info.unit
#. placeholder {2}: alert.min
#: src/components/routes/home.tsx
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
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
msgid "Export configuration"
msgstr "匯出設定"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "匯出您現在的系統設定。"
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "認證失敗"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Failed to save settings"
msgstr "儲存設定失敗"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "發送測試通知失敗"
#: src/components/alerts/alerts-system.tsx
msgid "Failed to update alert"
msgstr "更新警報失敗"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Filter..."
msgstr "篩選..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
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
msgid "Forgot password?"
msgstr "忘記密碼?"
#. Context: General settings
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/general.tsx
msgid "General"
msgstr "一般"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "GPU 功耗"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "網格"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew 命令"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr "Host / IP"
#: src/components/login/forgot-pass-form.tsx
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
msgid "Invalid email address."
msgstr "無效的電子郵件地址。"
#. Linux kernel
#: src/components/routes/system.tsx
msgid "Kernel"
msgstr "Kernel"
#. Load average 15 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L15"
msgstr ""
#. Load average 5 minutes
#: src/components/systems-table/systems-table.tsx
msgid "L5"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Language"
msgstr "語言"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "版面配置"
#. Light theme
#: src/components/mode-toggle.tsx
msgid "Light"
msgstr "淺色"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "登出"
#: src/components/login/login.tsx
msgid "Login"
msgstr "登入"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Login attempt failed"
msgstr "登入失敗"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Logs"
msgstr "系統記錄"
#: src/components/routes/settings/notifications.tsx
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
msgid "Manage display and notification preferences."
msgstr "管理顯示和通知偏好。"
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "手動設定說明"
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "最多1分鐘"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
msgstr "記憶體"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Memory Usage"
msgstr "記憶體使用量"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Docker 容器的記憶體使用量"
#: src/components/add-system.tsx
msgid "Name"
msgstr "名稱"
#: src/components/systems-table/systems-table.tsx
msgid "Net"
msgstr "網路"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "Docker 容器的網路流量"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "公開介面的網路流量"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "找不到結果。"
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "找不到任何系統。"
#: src/components/command-palette.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/layout.tsx
msgid "Notifications"
msgstr "通知"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "支援 OAuth 2 / OIDC"
#: src/components/routes/settings/config-yaml.tsx
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
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "開啟選單"
#: src/components/login/auth-form.tsx
msgid "Or continue with"
msgstr "或繼續使用"
#: src/components/alerts/alert-button.tsx
msgid "Overwrite existing alerts"
msgstr "覆蓋現有警報"
#: src/components/command-palette.tsx
msgid "Page"
msgstr "頁面"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "頁面 / 設定"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr "密碼"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
msgstr "密碼需要至少8個字元"
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr "密碼必須少於 72 個位元組。"
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
msgstr "已收到密碼重設請求"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "暫停"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "已暂停"
#: src/components/routes/settings/notifications.tsx
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
msgstr "請<0>設定一個SMTP 伺服器</0>以確保能傳送警報。"
#: src/components/alerts/alerts-system.tsx
msgid "Please check logs for more details."
msgstr "請檢查系統記錄以取得更多資訊。"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
msgid "Please check your credentials and try again"
msgstr "請檢查您的憑證後重試"
#: src/components/login/login.tsx
msgid "Please create an admin account"
msgstr "請建立一個管理員帳號"
#: src/components/login/auth-form.tsx
msgid "Please enable pop-ups for this site"
msgstr "請為此網站啟用彈出視窗"
#: src/lib/utils.ts
msgid "Please log in again"
msgstr "請重新登入"
#: src/components/login/auth-form.tsx
msgid "Please see <0>the documentation</0> for instructions."
msgstr "請參閱<0>文件</0>以取得說明。"
#: src/components/login/login.tsx
msgid "Please sign in to your account"
msgstr "請登入您的帳號"
#: src/components/add-system.tsx
msgid "Port"
msgstr "Port"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Precise utilization at the recorded time"
msgstr "紀錄時間內的精確使用量"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "首選語言"
#. Use 'Key' if your language requires many more characters
#: src/components/add-system.tsx
msgid "Public Key"
msgstr "公鑰"
#. Disk read
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "讀取"
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "接收"
#: src/components/login/forgot-pass-form.tsx
msgid "Reset Password"
msgstr "重設密碼"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "繼續"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "輪換令牌"
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "使用 Enter 鍵或逗號儲存地址。留空以停用電子郵件通知。"
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/general.tsx
msgid "Save Settings"
msgstr "儲存設定"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "儲存系統"
#: src/components/navbar.tsx
msgid "Search"
msgstr "搜尋"
#: src/components/command-palette.tsx
msgid "Search for systems or settings..."
msgstr "在設定或系統中搜尋..."
#: src/components/alerts/alert-button.tsx
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
msgid "Sent"
msgstr "傳送"
#: src/components/routes/settings/general.tsx
msgid "Sets the default time range for charts when a system is viewed."
msgstr "設定顯示系統圖表的預設時間範圍。"
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/layout.tsx
msgid "Settings"
msgstr "設定"
#: src/components/routes/settings/layout.tsx
msgid "Settings saved"
msgstr "已儲存設定"
#: src/components/login/auth-form.tsx
msgid "Sign in"
msgstr "登入"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "SMTP 設定"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
msgstr "排序"
#: src/lib/utils.ts
msgid "Status"
msgstr "狀態"
#: src/components/routes/system.tsx
msgid "Swap space used by the system"
msgstr "系統的虛擬記憶體使用量"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "虛擬記憶體使用量"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "系統"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "系統"
#: src/components/routes/settings/config-yaml.tsx
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
msgstr "可以用您Data資料夾中的<0>config.yml</0>來管理系統。"
#: src/components/systems-table/systems-table.tsx
msgid "Table"
msgstr "列表"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "溫度"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "溫度"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "系統感應器的溫度"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr "測試<0>URL</0>"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
msgstr "已發送測試通知"
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "然後登入後台並在使用者列表中重設您的帳號密碼。"
#: src/components/systems-table/systems-table.tsx
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
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName}的傳輸速率"
#: src/components/routes/system.tsx
msgid "Throughput of root filesystem"
msgstr "Root文件系統的傳輸速率"
#: src/components/routes/settings/notifications.tsx
msgid "To email(s)"
msgstr "發送到電子郵件"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
msgid "Toggle grid"
msgstr "切換網格"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "切換主題"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "令牌"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "令牌和指紋"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr "令牌允許代理程式連接和註冊。指紋是每個系統唯一的穩定識別符,在首次連接時設置。"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "令牌和指紋用於驗證到中心的WebSocket連接。"
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "當任何感應器超過閾值時觸發"
#: src/lib/utils.ts
msgid "Triggers when combined up/down exceeds a threshold"
msgstr "當總流量超過閾值時觸發"
#: src/lib/utils.ts
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "當CPU使用率超過閾值時觸發"
#: src/lib/utils.ts
msgid "Triggers when memory usage exceeds a threshold"
msgstr "當記憶體使用率超過閾值時觸發"
#: src/lib/utils.ts
msgid "Triggers when status switches between up and down"
msgstr "當連線和離線時觸發"
#: src/lib/utils.ts
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "當任何磁碟使用率超過閾值時觸發"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "通用令牌"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Updated in real time. Click on a system to view information."
msgstr "實時更新。點擊系統顯示資訊。"
#: src/components/routes/system.tsx
msgid "Uptime"
msgstr "運行時間"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "使用量"
#: src/components/routes/system.tsx
msgid "Usage of root partition"
msgstr "Root 分區的使用量"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "已使用"
#: src/components/navbar.tsx
#: src/components/command-palette.tsx
msgid "Users"
msgstr "使用者"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "檢視"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "顯示欄位"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
msgstr "等待足夠的記錄以顯示"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
msgstr "想幫助我們改善翻譯嗎?查看<0>Crowdin</0>以取得更多詳細信息。"
#: src/components/routes/settings/notifications.tsx
msgid "Webhook / Push notifications"
msgstr "Webhook / 推送通知"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "啟用時,此令牌允許代理程式在無需預先創建系統的情況下自動註冊。在一小時後或中心重啟時過期。"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows 命令"
#. Disk write
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "寫入"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML 設定檔"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML 設定檔"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "已更新您的使用者設定"

View File

@@ -1,100 +0,0 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ["class"],
content: ["./pages/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}", "./app/**/*.{ts,tsx}", "./src/**/*.{ts,tsx}"],
prefix: "",
theme: {
container: {
center: true,
padding: "1rem",
screens: {
"2xl": "1440px",
},
},
extend: {
fontFamily: {
sans: "Inter, sans-serif",
// body: ['Inter', 'sans-serif'],
// display: ['Inter', 'sans-serif'],
},
screens: {
xs: "425px",
450: "450px",
},
colors: {
green: {
50: "#EBF9F0",
100: "#D8F3E1",
200: "#ADE6C0",
300: "#85DBA2",
400: "#5ACE81",
500: "#38BB63",
600: "#2D954F",
700: "#22723D",
800: "#164B28",
900: "#0C2715",
950: "#06140A",
},
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
plugins: [
require("tailwindcss-animate"),
require("tailwindcss-rtl"),
function ({ addVariant }) {
addVariant("light", ".light &")
},
],
}

View File

@@ -1,10 +0,0 @@
package beszel
import "github.com/blang/semver"
const (
Version = "0.12.0-beta2"
AppName = "beszel"
)
var MinVersionCbor = semver.MustParse("0.12.0-beta2")

View File

@@ -1,26 +1,27 @@
module beszel
module github.com/henrygd/beszel
go 1.24.4
go 1.25.1
// lock shoutrrr to specific version to allow review before updating
replace github.com/nicholas-fedor/shoutrrr => github.com/nicholas-fedor/shoutrrr v0.8.8
require (
github.com/blang/semver v3.5.1+incompatible
github.com/fxamacker/cbor/v2 v2.8.0
github.com/distatus/battery v0.11.0
github.com/fxamacker/cbor/v2 v2.9.0
github.com/gliderlabs/ssh v0.3.8
github.com/google/uuid v1.6.0
github.com/lxzan/gws v1.8.9
github.com/nicholas-fedor/shoutrrr v0.8.15
github.com/nicholas-fedor/shoutrrr v0.8.17
github.com/pocketbase/dbx v1.11.0
github.com/pocketbase/pocketbase v0.28.4
github.com/rhysd/go-github-selfupdate v1.2.3
github.com/pocketbase/pocketbase v0.29.3
github.com/shirou/gopsutil/v4 v4.25.6
github.com/spf13/cast v1.9.2
github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.39.0
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
github.com/spf13/pflag v1.0.7
github.com/stretchr/testify v1.11.0
golang.org/x/crypto v0.41.0
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b
gopkg.in/yaml.v3 v3.0.1
)
@@ -39,34 +40,30 @@ require (
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
github.com/go-sql-driver/mysql v1.9.1 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/google/go-github/v30 v30.1.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
github.com/lufia/plan9stats v0.0.0-20250821153705-5981dea3221d // 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.15 // indirect
github.com/tklauser/numcpus v0.10.0 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/image v0.28.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/image v0.30.0 // indirect
golang.org/x/net v0.43.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.26.0 // indirect
modernc.org/libc v1.65.10 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.28.0 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
howett.net/plist v1.0.1 // indirect
modernc.org/libc v1.66.3 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.38.0 // indirect
modernc.org/sqlite v1.38.2 // indirect
)

View File

@@ -13,6 +13,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
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/distatus/battery v0.11.0 h1:KJk89gz90Iq/wJtbjjM9yUzBXV+ASV/EG2WOOL7N8lc=
github.com/distatus/battery v0.11.0/go.mod h1:KmVkE8A8hpIX4T78QRdMktYpEp35QfOL8A8dwZBxq2k=
github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ=
github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4=
github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8=
@@ -25,9 +27,8 @@ 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/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/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
github.com/ganigeorgiev/fexpr v0.5.0 h1:XA9JxtTE/Xm+g/JFI6RfZEHSiQlk+1glLvRK1Lpv/Tk=
@@ -46,41 +47,28 @@ github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtS
github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
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/google/go-cmp v0.5.2/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-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
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/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.4.0 h1:BvhqnH0JAYbNudL2GMJKgOHe2CtKlzJ/5rWKyp+hc2k=
github.com/jarcoal/httpmock v1.4.0/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
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-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/lufia/plan9stats v0.0.0-20250821153705-5981dea3221d h1:vFzYZc8yji+9DmNRhpEbs8VBK4CgV/DPfGzeVJSSp/8=
github.com/lufia/plan9stats v0.0.0-20250821153705-5981dea3221d/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/lxzan/gws v1.8.9 h1:VU3SGUeWlQrEwfUSfokcZep8mdg/BrUF+y73YYshdBM=
github.com/lxzan/gws v1.8.9/go.mod h1:d9yHaR1eDTBHagQC6KY7ycUOaz5KWeqQtP3xu7aMK8Y=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
@@ -91,11 +79,8 @@ github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdh
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/nicholas-fedor/shoutrrr v0.8.8 h1:F/oyoatWK5cbHPPgkjRZrA0262TP7KWuUQz9KskRtR8=
github.com/nicholas-fedor/shoutrrr v0.8.8/go.mod h1:T30Y+eoZFEjDk4HtOItcHQioZSOe3Z6a6aNfSz6jc5c=
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.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -103,14 +88,12 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
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.28.4 h1:RmhWXDcfKrFM9/W0G0Zrlv4eKBM8/s/v4SQKytjgD20=
github.com/pocketbase/pocketbase v0.28.4/go.mod h1:jSuN93vE/oeJVOz2D2ZxcYyr2bYNmDOMCUkM+JhyJQ0=
github.com/pocketbase/pocketbase v0.29.3 h1:Mj8o5awsbVJIdIoTuQNhfC2oL/c4aImQ3RyfFZlzFVg=
github.com/pocketbase/pocketbase v0.29.3/go.mod h1:oGpT67LObxCFK4V2fSL7J9YnPbBnnshOpJ5v3zcneww=
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/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=
@@ -120,21 +103,17 @@ github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE=
github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
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/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
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/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8=
github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
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/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
@@ -142,75 +121,62 @@ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.28.0 h1:gdem5JW1OLS4FbkWgLO+7ZeFzYtL3xClb97GaUzYMFE=
golang.org/x/image v0.28.0/go.mod h1:GUJYXtnGKEUgggyzh+Vxt+AviiCcyiwpsl8iQ8MvwGY=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/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-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/image v0.30.0 h1:jD5RhkmVAnjqaCUXfbGBrn3lpxbknfN9w2UhHHU+5B4=
golang.org/x/image v0.30.0/go.mod h1:SAEUTxCCMWSrJcCy/4HwavEsfZZJlYxeHLc6tTiAe/c=
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
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/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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-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.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
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.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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=
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
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.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s=
modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM=
modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
modernc.org/fileutil v1.3.3 h1:3qaU+7f7xxTUmvU1pJTZiDLAIoJVdUSSauJNHg9yXoA=
modernc.org/fileutil v1.3.3/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/fileutil v1.3.8 h1:qtzNm7ED75pd1C7WgAGcK4edm4fvhtBsEiI/0NQ54YM=
modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/libc v1.65.10 h1:ZwEk8+jhW7qBjHIT+wd0d9VjitRyQef9BnzlzGwMODc=
modernc.org/libc v1.65.10/go.mod h1:StFvYpx7i/mXtBAfVOjaU0PWZOvIRoZSgXhrwXzr8Po=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ=
modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8=
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.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
@@ -219,8 +185,8 @@ 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.38.0 h1:+4OrfPQ8pxHKuWG4md1JpR/EYAh3Md7TdejuuzE7EUI=
modernc.org/sqlite v1.38.0/go.mod h1:1Bj+yES4SVvBZ4cBOpVZ6QgesMCKpJZDq0nxYzOpmNE=
modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek=
modernc.org/sqlite v1.38.2/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E=
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=

View File

@@ -1,3 +1,3 @@
files:
- source: /beszel/site/src/locales/en/en.po
translation: /beszel/site/src/locales/%two_letters_code%/%two_letters_code%.po
- source: /internal/site/src/locales/en/
translation: /internal/site/src/locales/%two_letters_code%/%two_letters_code%.po

View File

@@ -10,7 +10,6 @@ import (
"github.com/nicholas-fedor/shoutrrr"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/mailer"
)
@@ -47,8 +46,7 @@ type SystemAlertStats struct {
NetSent float64 `json:"ns"`
NetRecv float64 `json:"nr"`
Temperatures map[string]float32 `json:"t"`
LoadAvg5 float64 `json:"l5"`
LoadAvg15 float64 `json:"l15"`
LoadAvg [3]float64 `json:"la"`
}
type SystemAlertData struct {
@@ -89,13 +87,21 @@ var supportsTitle = map[string]struct{}{
func NewAlertManager(app hubLike) *AlertManager {
am := &AlertManager{
hub: app,
alertQueue: make(chan alertTask),
alertQueue: make(chan alertTask, 5),
stopChan: make(chan struct{}),
}
am.bindEvents()
go am.startWorker()
return am
}
// Bind events to the alerts collection lifecycle
func (am *AlertManager) bindEvents() {
am.hub.OnRecordAfterUpdateSuccess("alerts").BindFunc(updateHistoryOnAlertUpdate)
am.hub.OnRecordAfterDeleteSuccess("alerts").BindFunc(resolveHistoryOnAlertDelete)
}
// SendAlert sends an alert to the user
func (am *AlertManager) SendAlert(data AlertMessageData) error {
// get user settings
record, err := am.hub.FindFirstRecordByFilter(
@@ -199,16 +205,14 @@ func (am *AlertManager) SendShoutrrrAlert(notificationUrl, title, message, link,
}
func (am *AlertManager) SendTestNotification(e *core.RequestEvent) error {
info, _ := e.RequestInfo()
if info.Auth == nil {
return apis.NewForbiddenError("Forbidden", nil)
var data struct {
URL string `json:"url"`
}
url := e.Request.URL.Query().Get("url")
// log.Println("url", url)
if url == "" {
return e.JSON(200, map[string]string{"err": "URL is required"})
err := e.BindBody(&data)
if err != nil || data.URL == "" {
return e.BadRequestError("URL is required", err)
}
err := am.SendShoutrrrAlert(url, "Test Alert", "This is a notification from Beszel.", am.hub.Settings().Meta.AppURL, "View Beszel")
err = am.SendShoutrrrAlert(data.URL, "Test Alert", "This is a notification from Beszel.", am.hub.Settings().Meta.AppURL, "View Beszel")
if err != nil {
return e.JSON(200, map[string]string{"err": err.Error()})
}

View File

@@ -0,0 +1,119 @@
package alerts
import (
"database/sql"
"errors"
"net/http"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
)
// UpsertUserAlerts handles API request to create or update alerts for a user
// across multiple systems (POST /api/beszel/user-alerts)
func UpsertUserAlerts(e *core.RequestEvent) error {
userID := e.Auth.Id
reqData := struct {
Min uint8 `json:"min"`
Value float64 `json:"value"`
Name string `json:"name"`
Systems []string `json:"systems"`
Overwrite bool `json:"overwrite"`
}{}
err := e.BindBody(&reqData)
if err != nil || userID == "" || reqData.Name == "" || len(reqData.Systems) == 0 {
return e.BadRequestError("Bad data", err)
}
alertsCollection, err := e.App.FindCachedCollectionByNameOrId("alerts")
if err != nil {
return err
}
err = e.App.RunInTransaction(func(txApp core.App) error {
for _, systemId := range reqData.Systems {
// find existing matching alert
alertRecord, err := txApp.FindFirstRecordByFilter(alertsCollection,
"system={:system} && name={:name} && user={:user}",
dbx.Params{"system": systemId, "name": reqData.Name, "user": userID})
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
// skip if alert already exists and overwrite is not set
if !reqData.Overwrite && alertRecord != nil {
continue
}
// create new alert if it doesn't exist
if alertRecord == nil {
alertRecord = core.NewRecord(alertsCollection)
alertRecord.Set("user", userID)
alertRecord.Set("system", systemId)
alertRecord.Set("name", reqData.Name)
}
alertRecord.Set("value", reqData.Value)
alertRecord.Set("min", reqData.Min)
if err := txApp.SaveNoValidate(alertRecord); err != nil {
return err
}
}
return nil
})
if err != nil {
return err
}
return e.JSON(http.StatusOK, map[string]any{"success": true})
}
// DeleteUserAlerts handles API request to delete alerts for a user across multiple systems
// (DELETE /api/beszel/user-alerts)
func DeleteUserAlerts(e *core.RequestEvent) error {
userID := e.Auth.Id
reqData := struct {
AlertName string `json:"name"`
Systems []string `json:"systems"`
}{}
err := e.BindBody(&reqData)
if err != nil || userID == "" || reqData.AlertName == "" || len(reqData.Systems) == 0 {
return e.BadRequestError("Bad data", err)
}
var numDeleted uint16
err = e.App.RunInTransaction(func(txApp core.App) error {
for _, systemId := range reqData.Systems {
// Find existing alert to delete
alertRecord, err := txApp.FindFirstRecordByFilter("alerts",
"system={:system} && name={:name} && user={:user}",
dbx.Params{"system": systemId, "name": reqData.AlertName, "user": userID})
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
// alert doesn't exist, continue to next system
continue
}
return err
}
if err := txApp.Delete(alertRecord); err != nil {
return err
}
numDeleted++
}
return nil
})
if err != nil {
return err
}
return e.JSON(http.StatusOK, map[string]any{"success": true, "count": numDeleted})
}

View File

@@ -0,0 +1,74 @@
package alerts
import (
"time"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
)
// On triggered alert record delete, set matching alert history record to resolved
func resolveHistoryOnAlertDelete(e *core.RecordEvent) error {
if !e.Record.GetBool("triggered") {
return e.Next()
}
_ = resolveAlertHistoryRecord(e.App, e.Record.Id)
return e.Next()
}
// On alert record update, update alert history record
func updateHistoryOnAlertUpdate(e *core.RecordEvent) error {
original := e.Record.Original()
new := e.Record
originalTriggered := original.GetBool("triggered")
newTriggered := new.GetBool("triggered")
// no need to update alert history if triggered state has not changed
if originalTriggered == newTriggered {
return e.Next()
}
// if new state is triggered, create new alert history record
if newTriggered {
_, _ = createAlertHistoryRecord(e.App, new)
return e.Next()
}
// if new state is not triggered, check for matching alert history record and set it to resolved
_ = resolveAlertHistoryRecord(e.App, new.Id)
return e.Next()
}
// resolveAlertHistoryRecord sets the resolved field to the current time
func resolveAlertHistoryRecord(app core.App, alertRecordID string) error {
alertHistoryRecord, err := app.FindFirstRecordByFilter("alerts_history", "alert_id={:alert_id} && resolved=null", dbx.Params{"alert_id": alertRecordID})
if err != nil || alertHistoryRecord == nil {
return err
}
alertHistoryRecord.Set("resolved", time.Now().UTC())
err = app.Save(alertHistoryRecord)
if err != nil {
app.Logger().Error("Failed to resolve alert history", "err", err)
}
return err
}
// createAlertHistoryRecord creates a new alert history record
func createAlertHistoryRecord(app core.App, alertRecord *core.Record) (alertHistoryRecord *core.Record, err error) {
alertHistoryCollection, err := app.FindCachedCollectionByNameOrId("alerts_history")
if err != nil {
return nil, err
}
alertHistoryRecord = core.NewRecord(alertHistoryCollection)
alertHistoryRecord.Set("alert_id", alertRecord.Id)
alertHistoryRecord.Set("user", alertRecord.GetString("user"))
alertHistoryRecord.Set("system", alertRecord.GetString("system"))
alertHistoryRecord.Set("name", alertRecord.GetString("name"))
alertHistoryRecord.Set("value", alertRecord.GetFloat("value"))
err = app.Save(alertHistoryRecord)
if err != nil {
app.Logger().Error("Failed to save alert history", "err", err)
}
return alertHistoryRecord, err
}

View File

@@ -136,6 +136,14 @@ func (am *AlertManager) handleSystemUp(systemName string, alertRecords []*core.R
// sendStatusAlert sends a status alert ("up" or "down") to the users associated with the alert records.
func (am *AlertManager) sendStatusAlert(alertStatus string, systemName string, alertRecord *core.Record) error {
switch alertStatus {
case "up":
alertRecord.Set("triggered", false)
case "down":
alertRecord.Set("triggered", true)
}
am.hub.Save(alertRecord)
var emoji string
if alertStatus == "up" {
emoji = "\u2705" // Green checkmark emoji
@@ -146,16 +154,16 @@ func (am *AlertManager) sendStatusAlert(alertStatus string, systemName string, a
title := fmt.Sprintf("Connection to %s is %s %v", systemName, alertStatus, emoji)
message := strings.TrimSuffix(title, emoji)
if errs := am.hub.ExpandRecord(alertRecord, []string{"user"}, nil); len(errs) > 0 {
return errs["user"]
}
user := alertRecord.ExpandedOne("user")
if user == nil {
return nil
}
// if errs := am.hub.ExpandRecord(alertRecord, []string{"user"}, nil); len(errs) > 0 {
// return errs["user"]
// }
// user := alertRecord.ExpandedOne("user")
// if user == nil {
// return nil
// }
return am.SendAlert(AlertMessageData{
UserID: user.Id,
UserID: alertRecord.GetString("user"),
Title: title,
Message: message,
Link: am.hub.MakeLink("system", systemName),

View File

@@ -1,12 +1,13 @@
package alerts
import (
"beszel/internal/entities/system"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/henrygd/beszel/internal/entities/system"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/types"
@@ -15,7 +16,7 @@ import (
func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *system.CombinedData) error {
alertRecords, err := am.hub.FindAllRecords("alerts",
dbx.NewExp("system={:system}", dbx.Params{"system": systemRecord.Id}),
dbx.NewExp("system={:system} AND name!='Status'", dbx.Params{"system": systemRecord.Id}),
)
if err != nil || len(alertRecords) == 0 {
// log.Println("no alerts found for system")
@@ -54,11 +55,14 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *syst
}
val = data.Info.DashboardTemp
unit = "°C"
case "LoadAvg1":
val = data.Info.LoadAvg[0]
unit = ""
case "LoadAvg5":
val = data.Info.LoadAvg5
val = data.Info.LoadAvg[1]
unit = ""
case "LoadAvg15":
val = data.Info.LoadAvg15
val = data.Info.LoadAvg[2]
unit = ""
}
@@ -196,10 +200,12 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *syst
}
alert.mapSums[key] += temp
}
case "LoadAvg1":
alert.val += stats.LoadAvg[0]
case "LoadAvg5":
alert.val += stats.LoadAvg5
alert.val += stats.LoadAvg[1]
case "LoadAvg15":
alert.val += stats.LoadAvg15
alert.val += stats.LoadAvg[2]
default:
continue
}
@@ -288,18 +294,11 @@ func (am *AlertManager) sendSystemAlert(alert SystemAlertData) {
// app.Logger().Error("failed to save alert record", "err", err)
return
}
// expand the user relation and send the alert
if errs := am.hub.ExpandRecord(alert.alertRecord, []string{"user"}, nil); len(errs) > 0 {
// app.Logger().Error("failed to expand user relation", "errs", errs)
return
}
if user := alert.alertRecord.ExpandedOne("user"); user != nil {
am.SendAlert(AlertMessageData{
UserID: user.Id,
Title: subject,
Message: body,
Link: am.hub.MakeLink("system", systemName),
LinkText: "View " + systemName,
})
}
am.SendAlert(AlertMessageData{
UserID: alert.alertRecord.GetString("user"),
Title: subject,
Message: body,
Link: am.hub.MakeLink("system", systemName),
LinkText: "View " + systemName,
})
}

View File

@@ -0,0 +1,604 @@
//go:build testing
// +build testing
package alerts_test
import (
"bytes"
"encoding/json"
"io"
"net/http"
"strings"
"testing"
"testing/synctest"
"time"
beszelTests "github.com/henrygd/beszel/internal/tests"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
pbTests "github.com/pocketbase/pocketbase/tests"
"github.com/stretchr/testify/assert"
)
// marshal to json and return an io.Reader (for use in ApiScenario.Body)
func jsonReader(v any) io.Reader {
data, err := json.Marshal(v)
if err != nil {
panic(err)
}
return bytes.NewReader(data)
}
func TestUserAlertsApi(t *testing.T) {
hub, _ := beszelTests.NewTestHub(t.TempDir())
defer hub.Cleanup()
hub.StartHub()
user1, _ := beszelTests.CreateUser(hub, "alertstest@example.com", "password")
user1Token, _ := user1.NewAuthToken()
user2, _ := beszelTests.CreateUser(hub, "alertstest2@example.com", "password")
user2Token, _ := user2.NewAuthToken()
system1, _ := beszelTests.CreateRecord(hub, "systems", map[string]any{
"name": "system1",
"users": []string{user1.Id},
"host": "127.0.0.1",
})
system2, _ := beszelTests.CreateRecord(hub, "systems", map[string]any{
"name": "system2",
"users": []string{user1.Id, user2.Id},
"host": "127.0.0.2",
})
userRecords, _ := hub.CountRecords("users")
assert.EqualValues(t, 2, userRecords, "all users should be created")
systemRecords, _ := hub.CountRecords("systems")
assert.EqualValues(t, 2, systemRecords, "all systems should be created")
testAppFactory := func(t testing.TB) *pbTests.TestApp {
return hub.TestApp
}
scenarios := []beszelTests.ApiScenario{
// {
// Name: "GET not implemented - returns index",
// Method: http.MethodGet,
// URL: "/api/beszel/user-alerts",
// ExpectedStatus: 200,
// ExpectedContent: []string{"<html ", "globalThis.BESZEL"},
// TestAppFactory: testAppFactory,
// },
{
Name: "POST no auth",
Method: http.MethodPost,
URL: "/api/beszel/user-alerts",
ExpectedStatus: 401,
ExpectedContent: []string{"requires valid"},
TestAppFactory: testAppFactory,
},
{
Name: "POST no body",
Method: http.MethodPost,
URL: "/api/beszel/user-alerts",
Headers: map[string]string{
"Authorization": user1Token,
},
ExpectedStatus: 400,
ExpectedContent: []string{"Bad data"},
TestAppFactory: testAppFactory,
},
{
Name: "POST bad data",
Method: http.MethodPost,
URL: "/api/beszel/user-alerts",
Headers: map[string]string{
"Authorization": user1Token,
},
ExpectedStatus: 400,
ExpectedContent: []string{"Bad data"},
TestAppFactory: testAppFactory,
Body: jsonReader(map[string]any{
"invalidField": "this should cause validation error",
"threshold": "not a number",
}),
},
{
Name: "POST malformed JSON",
Method: http.MethodPost,
URL: "/api/beszel/user-alerts",
Headers: map[string]string{
"Authorization": user1Token,
},
ExpectedStatus: 400,
ExpectedContent: []string{"Bad data"},
TestAppFactory: testAppFactory,
Body: strings.NewReader(`{"alertType": "cpu", "threshold": 80, "enabled": true,}`),
},
{
Name: "POST valid alert data multiple systems",
Method: http.MethodPost,
URL: "/api/beszel/user-alerts",
Headers: map[string]string{
"Authorization": user1Token,
},
ExpectedStatus: 200,
ExpectedContent: []string{"\"success\":true"},
TestAppFactory: testAppFactory,
Body: jsonReader(map[string]any{
"name": "CPU",
"value": 69,
"min": 9,
"systems": []string{system1.Id, system2.Id},
"overwrite": false,
}),
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
// check total alerts
alerts, _ := app.CountRecords("alerts")
assert.EqualValues(t, 2, alerts, "should have 2 alerts")
// check alert has correct values
matchingAlerts, _ := app.CountRecords("alerts", dbx.HashExp{"name": "CPU", "user": user1.Id, "system": system1.Id, "value": 69, "min": 9})
assert.EqualValues(t, 1, matchingAlerts, "should have 1 alert")
},
},
{
Name: "POST valid alert data single system",
Method: http.MethodPost,
URL: "/api/beszel/user-alerts",
Headers: map[string]string{
"Authorization": user1Token,
},
ExpectedStatus: 200,
ExpectedContent: []string{"\"success\":true"},
TestAppFactory: testAppFactory,
Body: jsonReader(map[string]any{
"name": "Memory",
"systems": []string{system1.Id},
"value": 90,
"min": 10,
}),
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
user1Alerts, _ := app.CountRecords("alerts", dbx.HashExp{"user": user1.Id})
assert.EqualValues(t, 3, user1Alerts, "should have 3 alerts")
},
},
{
Name: "Overwrite: false, should not overwrite existing alert",
Method: http.MethodPost,
URL: "/api/beszel/user-alerts",
Headers: map[string]string{
"Authorization": user1Token,
},
ExpectedStatus: 200,
ExpectedContent: []string{"\"success\":true"},
TestAppFactory: testAppFactory,
Body: jsonReader(map[string]any{
"name": "CPU",
"value": 45,
"min": 5,
"systems": []string{system1.Id},
"overwrite": false,
}),
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
beszelTests.ClearCollection(t, app, "alerts")
beszelTests.CreateRecord(app, "alerts", map[string]any{
"name": "CPU",
"system": system1.Id,
"user": user1.Id,
"value": 80,
"min": 10,
})
},
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
alerts, _ := app.CountRecords("alerts")
assert.EqualValues(t, 1, alerts, "should have 1 alert")
alert, _ := app.FindFirstRecordByFilter("alerts", "name = 'CPU' && user = {:user}", dbx.Params{"user": user1.Id})
assert.EqualValues(t, 80, alert.Get("value"), "should have 80 as value")
},
},
{
Name: "Overwrite: true, should overwrite existing alert",
Method: http.MethodPost,
URL: "/api/beszel/user-alerts",
Headers: map[string]string{
"Authorization": user2Token,
},
ExpectedStatus: 200,
ExpectedContent: []string{"\"success\":true"},
TestAppFactory: testAppFactory,
Body: jsonReader(map[string]any{
"name": "CPU",
"value": 45,
"min": 5,
"systems": []string{system2.Id},
"overwrite": true,
}),
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
beszelTests.ClearCollection(t, app, "alerts")
beszelTests.CreateRecord(app, "alerts", map[string]any{
"name": "CPU",
"system": system2.Id,
"user": user2.Id,
"value": 80,
"min": 10,
})
},
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
alerts, _ := app.CountRecords("alerts")
assert.EqualValues(t, 1, alerts, "should have 1 alert")
alert, _ := app.FindFirstRecordByFilter("alerts", "name = 'CPU' && user = {:user}", dbx.Params{"user": user2.Id})
assert.EqualValues(t, 45, alert.Get("value"), "should have 45 as value")
},
},
{
Name: "DELETE no auth",
Method: http.MethodDelete,
URL: "/api/beszel/user-alerts",
ExpectedStatus: 401,
ExpectedContent: []string{"requires valid"},
TestAppFactory: testAppFactory,
Body: jsonReader(map[string]any{
"name": "CPU",
"systems": []string{system1.Id},
}),
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
beszelTests.ClearCollection(t, app, "alerts")
beszelTests.CreateRecord(app, "alerts", map[string]any{
"name": "CPU",
"system": system1.Id,
"user": user1.Id,
"value": 80,
"min": 10,
})
},
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
alerts, _ := app.CountRecords("alerts")
assert.EqualValues(t, 1, alerts, "should have 1 alert")
},
},
{
Name: "DELETE alert",
Method: http.MethodDelete,
URL: "/api/beszel/user-alerts",
Headers: map[string]string{
"Authorization": user1Token,
},
ExpectedStatus: 200,
ExpectedContent: []string{"\"count\":1", "\"success\":true"},
TestAppFactory: testAppFactory,
Body: jsonReader(map[string]any{
"name": "CPU",
"systems": []string{system1.Id},
}),
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
beszelTests.ClearCollection(t, app, "alerts")
beszelTests.CreateRecord(app, "alerts", map[string]any{
"name": "CPU",
"system": system1.Id,
"user": user1.Id,
"value": 80,
"min": 10,
})
},
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
alerts, _ := app.CountRecords("alerts")
assert.Zero(t, alerts, "should have 0 alerts")
},
},
{
Name: "DELETE alert multiple systems",
Method: http.MethodDelete,
URL: "/api/beszel/user-alerts",
Headers: map[string]string{
"Authorization": user1Token,
},
ExpectedStatus: 200,
ExpectedContent: []string{"\"count\":2", "\"success\":true"},
TestAppFactory: testAppFactory,
Body: jsonReader(map[string]any{
"name": "Memory",
"systems": []string{system1.Id, system2.Id},
}),
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
beszelTests.ClearCollection(t, app, "alerts")
for _, systemId := range []string{system1.Id, system2.Id} {
_, err := beszelTests.CreateRecord(app, "alerts", map[string]any{
"name": "Memory",
"system": systemId,
"user": user1.Id,
"value": 90,
"min": 10,
})
assert.NoError(t, err, "should create alert")
}
alerts, _ := app.CountRecords("alerts")
assert.EqualValues(t, 2, alerts, "should have 2 alerts")
},
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
alerts, _ := app.CountRecords("alerts")
assert.Zero(t, alerts, "should have 0 alerts")
},
},
{
Name: "User 2 should not be able to delete alert of user 1",
Method: http.MethodDelete,
URL: "/api/beszel/user-alerts",
Headers: map[string]string{
"Authorization": user2Token,
},
ExpectedStatus: 200,
ExpectedContent: []string{"\"count\":1", "\"success\":true"},
TestAppFactory: testAppFactory,
Body: jsonReader(map[string]any{
"name": "CPU",
"systems": []string{system2.Id},
}),
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
beszelTests.ClearCollection(t, app, "alerts")
for _, user := range []string{user1.Id, user2.Id} {
beszelTests.CreateRecord(app, "alerts", map[string]any{
"name": "CPU",
"system": system2.Id,
"user": user,
"value": 80,
"min": 10,
})
}
alerts, _ := app.CountRecords("alerts")
assert.EqualValues(t, 2, alerts, "should have 2 alerts")
user1AlertCount, _ := app.CountRecords("alerts", dbx.HashExp{"user": user1.Id})
assert.EqualValues(t, 1, user1AlertCount, "should have 1 alert")
user2AlertCount, _ := app.CountRecords("alerts", dbx.HashExp{"user": user2.Id})
assert.EqualValues(t, 1, user2AlertCount, "should have 1 alert")
},
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
user1AlertCount, _ := app.CountRecords("alerts", dbx.HashExp{"user": user1.Id})
assert.EqualValues(t, 1, user1AlertCount, "should have 1 alert")
user2AlertCount, _ := app.CountRecords("alerts", dbx.HashExp{"user": user2.Id})
assert.Zero(t, user2AlertCount, "should have 0 alerts")
},
},
}
for _, scenario := range scenarios {
scenario.Test(t)
}
}
func getHubWithUser(t *testing.T) (*beszelTests.TestHub, *core.Record) {
hub, err := beszelTests.NewTestHub(t.TempDir())
assert.NoError(t, err)
hub.StartHub()
// Manually initialize the system manager to bind event hooks
err = hub.GetSystemManager().Initialize()
assert.NoError(t, err)
// Create a test user
user, err := beszelTests.CreateUser(hub, "test@example.com", "password")
assert.NoError(t, err)
// Create user settings for the test user (required for alert notifications)
userSettingsData := map[string]any{
"user": user.Id,
"settings": `{"emails":[test@example.com],"webhooks":[]}`,
}
_, err = beszelTests.CreateRecord(hub, "user_settings", userSettingsData)
assert.NoError(t, err)
return hub, user
}
func TestStatusAlerts(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
hub, user := getHubWithUser(t)
defer hub.Cleanup()
systems, err := beszelTests.CreateSystems(hub, 4, user.Id, "paused")
assert.NoError(t, err)
var alerts []*core.Record
for i, system := range systems {
alert, err := beszelTests.CreateRecord(hub, "alerts", map[string]any{
"name": "Status",
"system": system.Id,
"user": user.Id,
"min": i + 1,
})
assert.NoError(t, err)
alerts = append(alerts, alert)
}
time.Sleep(10 * time.Millisecond)
for _, alert := range alerts {
assert.False(t, alert.GetBool("triggered"), "Alert should not be triggered immediately")
}
if hub.TestMailer.TotalSend() != 0 {
assert.Zero(t, hub.TestMailer.TotalSend(), "Expected 0 messages, got %d", hub.TestMailer.TotalSend())
}
for _, system := range systems {
assert.EqualValues(t, "paused", system.GetString("status"), "System should be paused")
}
for _, system := range systems {
system.Set("status", "up")
err = hub.SaveNoValidate(system)
assert.NoError(t, err)
}
time.Sleep(time.Second)
assert.EqualValues(t, 0, hub.GetPendingAlertsCount(), "should have 0 alerts in the pendingAlerts map")
for _, system := range systems {
system.Set("status", "down")
err = hub.SaveNoValidate(system)
assert.NoError(t, err)
}
// after 30 seconds, should have 4 alerts in the pendingAlerts map, no triggered alerts
time.Sleep(time.Second * 30)
assert.EqualValues(t, 4, hub.GetPendingAlertsCount(), "should have 4 alerts in the pendingAlerts map")
triggeredCount, err := hub.CountRecords("alerts", dbx.HashExp{"triggered": true})
assert.NoError(t, err)
assert.EqualValues(t, 0, triggeredCount, "should have 0 alert triggered")
assert.EqualValues(t, 0, hub.TestMailer.TotalSend(), "should have 0 messages sent")
// after 1:30 seconds, should have 1 triggered alert and 3 pending alerts
time.Sleep(time.Second * 60)
assert.EqualValues(t, 3, hub.GetPendingAlertsCount(), "should have 3 alerts in the pendingAlerts map")
triggeredCount, err = hub.CountRecords("alerts", dbx.HashExp{"triggered": true})
assert.NoError(t, err)
assert.EqualValues(t, 1, triggeredCount, "should have 1 alert triggered")
assert.EqualValues(t, 1, hub.TestMailer.TotalSend(), "should have 1 messages sent")
// after 2:30 seconds, should have 2 triggered alerts and 2 pending alerts
time.Sleep(time.Second * 60)
assert.EqualValues(t, 2, hub.GetPendingAlertsCount(), "should have 2 alerts in the pendingAlerts map")
triggeredCount, err = hub.CountRecords("alerts", dbx.HashExp{"triggered": true})
assert.NoError(t, err)
assert.EqualValues(t, 2, triggeredCount, "should have 2 alert triggered")
assert.EqualValues(t, 2, hub.TestMailer.TotalSend(), "should have 2 messages sent")
// now we will bring the remaning systems back up
for _, system := range systems {
system.Set("status", "up")
err = hub.SaveNoValidate(system)
assert.NoError(t, err)
}
time.Sleep(time.Second)
// should have 0 alerts in the pendingAlerts map and 0 alerts triggered
assert.EqualValues(t, 0, hub.GetPendingAlertsCount(), "should have 0 alerts in the pendingAlerts map")
triggeredCount, err = hub.CountRecords("alerts", dbx.HashExp{"triggered": true})
assert.NoError(t, err)
assert.Zero(t, triggeredCount, "should have 0 alert triggered")
// 4 messages sent, 2 down alerts and 2 up alerts for first 2 systems
assert.EqualValues(t, 4, hub.TestMailer.TotalSend(), "should have 4 messages sent")
})
}
func TestAlertsHistory(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
hub, user := getHubWithUser(t)
defer hub.Cleanup()
// Create systems and alerts
systems, err := beszelTests.CreateSystems(hub, 1, user.Id, "up")
assert.NoError(t, err)
system := systems[0]
alert, err := beszelTests.CreateRecord(hub, "alerts", map[string]any{
"name": "Status",
"system": system.Id,
"user": user.Id,
"min": 1,
})
assert.NoError(t, err)
// Initially, no alert history records should exist
initialHistoryCount, err := hub.CountRecords("alerts_history", nil)
assert.NoError(t, err)
assert.Zero(t, initialHistoryCount, "Should have 0 alert history records initially")
// Set system to up initially
system.Set("status", "up")
err = hub.SaveNoValidate(system)
assert.NoError(t, err)
time.Sleep(10 * time.Millisecond)
// Set system to down to trigger alert
system.Set("status", "down")
err = hub.SaveNoValidate(system)
assert.NoError(t, err)
// Wait for alert to trigger (after the downtime delay)
// With 1 minute delay, we need to wait at least 1 minute + some buffer
time.Sleep(time.Second * 75)
// Check that alert is triggered
triggeredCount, err := hub.CountRecords("alerts", dbx.HashExp{"triggered": true, "id": alert.Id})
assert.NoError(t, err)
assert.EqualValues(t, 1, triggeredCount, "Alert should be triggered")
// Check that alert history record was created
historyCount, err := hub.CountRecords("alerts_history", dbx.HashExp{"alert_id": alert.Id})
assert.NoError(t, err)
assert.EqualValues(t, 1, historyCount, "Should have 1 alert history record for triggered alert")
// Get the alert history record and verify it's not resolved immediately
historyRecord, err := hub.FindFirstRecordByFilter("alerts_history", "alert_id={:alert_id}", dbx.Params{"alert_id": alert.Id})
assert.NoError(t, err)
assert.NotNil(t, historyRecord, "Alert history record should exist")
assert.Equal(t, alert.Id, historyRecord.GetString("alert_id"), "Alert history should reference correct alert")
assert.Equal(t, system.Id, historyRecord.GetString("system"), "Alert history should reference correct system")
assert.Equal(t, "Status", historyRecord.GetString("name"), "Alert history should have correct name")
// The alert history might be resolved immediately in some cases, so let's check the alert's triggered status
alertRecord, err := hub.FindFirstRecordByFilter("alerts", "id={:id}", dbx.Params{"id": alert.Id})
assert.NoError(t, err)
assert.True(t, alertRecord.GetBool("triggered"), "Alert should still be triggered when checking history")
// Now resolve the alert by setting system back to up
system.Set("status", "up")
err = hub.SaveNoValidate(system)
assert.NoError(t, err)
time.Sleep(200 * time.Millisecond)
// Check that alert is no longer triggered
triggeredCount, err = hub.CountRecords("alerts", dbx.HashExp{"triggered": true, "id": alert.Id})
assert.NoError(t, err)
assert.Zero(t, triggeredCount, "Alert should not be triggered after system is back up")
// Check that alert history record is now resolved
historyRecord, err = hub.FindFirstRecordByFilter("alerts_history", "alert_id={:alert_id}", dbx.Params{"alert_id": alert.Id})
assert.NoError(t, err)
assert.NotNil(t, historyRecord, "Alert history record should still exist")
assert.NotNil(t, historyRecord.Get("resolved"), "Alert history should be resolved")
// Test deleting a triggered alert resolves its history
// Create another system and alert
systems2, err := beszelTests.CreateSystems(hub, 1, user.Id, "up")
assert.NoError(t, err)
system2 := systems2[0]
system2.Set("name", "test-system-2") // Rename for clarity
err = hub.SaveNoValidate(system2)
assert.NoError(t, err)
alert2, err := beszelTests.CreateRecord(hub, "alerts", map[string]any{
"name": "Status",
"system": system2.Id,
"user": user.Id,
"min": 1,
})
assert.NoError(t, err)
// Set system2 to down to trigger alert
system2.Set("status", "down")
err = hub.SaveNoValidate(system2)
assert.NoError(t, err)
// Wait for alert to trigger
time.Sleep(time.Second * 75)
// Verify alert is triggered and history record exists
triggeredCount, err = hub.CountRecords("alerts", dbx.HashExp{"triggered": true, "id": alert2.Id})
assert.NoError(t, err)
assert.EqualValues(t, 1, triggeredCount, "Second alert should be triggered")
historyCount, err = hub.CountRecords("alerts_history", dbx.HashExp{"alert_id": alert2.Id})
assert.NoError(t, err)
assert.EqualValues(t, 1, historyCount, "Should have 1 alert history record for second alert")
// Delete the triggered alert
err = hub.Delete(alert2)
assert.NoError(t, err)
// Check that alert history record is resolved after deletion
historyRecord2, err := hub.FindFirstRecordByFilter("alerts_history", "alert_id={:alert_id}", dbx.Params{"alert_id": alert2.Id})
assert.NoError(t, err)
assert.NotNil(t, historyRecord2, "Alert history record should still exist after alert deletion")
assert.NotNil(t, historyRecord2.Get("resolved"), "Alert history should be resolved after alert deletion")
// Verify total history count is correct (2 records total)
totalHistoryCount, err := hub.CountRecords("alerts_history", nil)
assert.NoError(t, err)
assert.EqualValues(t, 2, totalHistoryCount, "Should have 2 total alert history records")
})
}

View File

@@ -0,0 +1,55 @@
package alerts
import (
"sync"
"time"
"github.com/pocketbase/pocketbase/core"
)
func (am *AlertManager) GetAlertManager() *AlertManager {
return am
}
func (am *AlertManager) GetPendingAlerts() *sync.Map {
return &am.pendingAlerts
}
func (am *AlertManager) GetPendingAlertsCount() int {
count := 0
am.pendingAlerts.Range(func(key, value any) bool {
count++
return true
})
return count
}
// ProcessPendingAlerts manually processes all expired alerts (for testing)
func (am *AlertManager) ProcessPendingAlerts() ([]*core.Record, error) {
now := time.Now()
var lastErr error
var processedAlerts []*core.Record
am.pendingAlerts.Range(func(key, value any) bool {
info := value.(*alertInfo)
if now.After(info.expireTime) {
// Downtime delay has passed, process alert
if err := am.sendStatusAlert("down", info.systemName, info.alertRecord); err != nil {
lastErr = err
}
processedAlerts = append(processedAlerts, info.alertRecord)
am.pendingAlerts.Delete(key)
}
return true
})
return processedAlerts, lastErr
}
// ForceExpirePendingAlerts sets all pending alerts to expire immediately (for testing)
func (am *AlertManager) ForceExpirePendingAlerts() {
now := time.Now()
am.pendingAlerts.Range(func(key, value any) bool {
info := value.(*alertInfo)
info.expireTime = now.Add(-time.Second) // Set to 1 second ago
return true
})
}

157
internal/cmd/agent/agent.go Normal file
View File

@@ -0,0 +1,157 @@
package main
import (
"fmt"
"log"
"os"
"strings"
"github.com/henrygd/beszel"
"github.com/henrygd/beszel/agent"
"github.com/henrygd/beszel/agent/health"
"github.com/spf13/pflag"
"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.
// TODO: add hubURL and token
// hubURL string // hubURL is the URL of the hub to use.
// token string // token is the token to use for authentication.
}
// 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 {
subcommand := ""
if len(os.Args) > 1 {
subcommand = os.Args[1]
}
// Subcommands that don't require any pflag parsing
switch subcommand {
case "-v", "version":
fmt.Println(beszel.AppName+"-agent", beszel.Version)
return true
case "health":
err := health.Check()
if err != nil {
log.Fatal(err)
}
fmt.Print("ok")
return true
}
// pflag.CommandLine.ParseErrorsWhitelist.UnknownFlags = true
pflag.StringVarP(&opts.key, "key", "k", "", "Public key(s) for SSH authentication")
pflag.StringVarP(&opts.listen, "listen", "l", "", "Address or port to listen on")
// pflag.StringVarP(&opts.hubURL, "hub-url", "u", "", "URL of the hub to use")
// pflag.StringVarP(&opts.token, "token", "t", "", "Token to use for authentication")
chinaMirrors := pflag.BoolP("china-mirrors", "c", false, "Use mirror for update (gh.beszel.dev) instead of GitHub")
help := pflag.BoolP("help", "h", false, "Show this help message")
// Convert old single-dash long flags to double-dash for backward compatibility
flagsToConvert := []string{"key", "listen"}
for i, arg := range os.Args {
for _, flag := range flagsToConvert {
singleDash := "-" + flag
doubleDash := "--" + flag
if arg == singleDash {
os.Args[i] = doubleDash
break
} else if strings.HasPrefix(arg, singleDash+"=") {
os.Args[i] = doubleDash + arg[len(singleDash):]
break
}
}
}
pflag.Usage = func() {
builder := strings.Builder{}
builder.WriteString("Usage: ")
builder.WriteString(os.Args[0])
builder.WriteString(" [command] [flags]\n")
builder.WriteString("\nCommands:\n")
builder.WriteString(" health Check if the agent is running\n")
// builder.WriteString(" help Display this help message\n")
builder.WriteString(" update Update to the latest version\n")
builder.WriteString("\nFlags:\n")
fmt.Print(builder.String())
pflag.PrintDefaults()
}
// Parse all arguments with pflag
pflag.Parse()
// Must run after pflag.Parse()
switch {
case *help || subcommand == "help":
pflag.Usage()
return true
case subcommand == "update":
agent.Update(*chinaMirrors)
return true
}
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)
a, err := agent.NewAgent()
if err != nil {
log.Fatal("Failed to create agent: ", err)
}
if err := a.Start(serverConfig); err != nil {
log.Fatal("Failed to start server: ", err)
}
}

View File

@@ -1,13 +1,14 @@
package main
import (
"beszel/internal/agent"
"crypto/ed25519"
"flag"
"os"
"path/filepath"
"testing"
"github.com/henrygd/beszel/agent"
"github.com/spf13/pflag"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/ssh"
@@ -245,7 +246,7 @@ func TestParseFlags(t *testing.T) {
oldArgs := os.Args
defer func() {
os.Args = oldArgs
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
}()
tests := []struct {
@@ -269,6 +270,22 @@ func TestParseFlags(t *testing.T) {
listen: "",
},
},
{
name: "key flag double dash",
args: []string{"cmd", "--key", "testkey"},
expected: cmdOptions{
key: "testkey",
listen: "",
},
},
{
name: "key flag short",
args: []string{"cmd", "-k", "testkey"},
expected: cmdOptions{
key: "testkey",
listen: "",
},
},
{
name: "addr flag only",
args: []string{"cmd", "-listen", ":8080"},
@@ -277,6 +294,22 @@ func TestParseFlags(t *testing.T) {
listen: ":8080",
},
},
{
name: "addr flag double dash",
args: []string{"cmd", "--listen", ":8080"},
expected: cmdOptions{
key: "",
listen: ":8080",
},
},
{
name: "addr flag short",
args: []string{"cmd", "-l", ":8080"},
expected: cmdOptions{
key: "",
listen: ":8080",
},
},
{
name: "both flags",
args: []string{"cmd", "-key", "testkey", "-listen", ":8080"},
@@ -290,12 +323,12 @@ func TestParseFlags(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Reset flags for each test
flag.CommandLine = flag.NewFlagSet(tt.args[0], flag.ExitOnError)
pflag.CommandLine = pflag.NewFlagSet(tt.args[0], pflag.ExitOnError)
os.Args = tt.args
var opts cmdOptions
opts.parse()
flag.Parse()
pflag.Parse()
assert.Equal(t, tt.expected, opts)
})

View File

@@ -1,15 +1,16 @@
package main
import (
"beszel"
"beszel/internal/hub"
_ "beszel/migrations"
"fmt"
"log"
"net/http"
"os"
"time"
"github.com/henrygd/beszel"
"github.com/henrygd/beszel/internal/hub"
_ "github.com/henrygd/beszel/internal/migrations"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/plugins/migratecmd"
"github.com/spf13/cobra"
@@ -45,11 +46,13 @@ func getBaseApp() *pocketbase.PocketBase {
baseApp.RootCmd.Use = beszel.AppName
baseApp.RootCmd.Short = ""
// add update command
baseApp.RootCmd.AddCommand(&cobra.Command{
updateCmd := &cobra.Command{
Use: "update",
Short: "Update " + beszel.AppName + " to the latest version",
Run: hub.Update,
})
}
updateCmd.Flags().Bool("china-mirrors", false, "Use mirror (gh.beszel.dev) instead of GitHub")
baseApp.RootCmd.AddCommand(updateCmd)
// add health command
baseApp.RootCmd.AddCommand(newHealthCmd())

26
internal/dockerfile_agent Normal file
View File

@@ -0,0 +1,26 @@
FROM --platform=$BUILDPLATFORM golang:alpine AS builder
WORKDIR /app
COPY ../go.mod ../go.sum ./
RUN go mod download
# Copy source files
COPY . ./
# Build
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./internal/cmd/agent
RUN rm -rf /tmp/*
# --------------------------
# Final image: default scratch-based agent
# --------------------------
FROM scratch
COPY --from=builder /agent /agent
# this is so we don't need to create the /tmp directory in the scratch container
COPY --from=builder /tmp /tmp
ENTRYPOINT ["/agent"]

View File

@@ -12,15 +12,10 @@ COPY internal ./internal
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./cmd/agent
RUN rm -rf /tmp/*
# ? -------------------------
FROM scratch
# --------------------------
# Final image: GPU-enabled agent with nvidia-smi
# --------------------------
FROM nvidia/cuda:12.2.2-base-ubuntu22.04
COPY --from=builder /agent /agent
# this is so we don't need to create the
# /tmp directory in the scratch container
COPY --from=builder /tmp /tmp
ENTRYPOINT ["/agent"]

View File

@@ -3,16 +3,11 @@ FROM --platform=$BUILDPLATFORM golang:alpine AS builder
WORKDIR /app
# Download Go modules
COPY go.mod go.sum ./
COPY ../go.mod ../go.sum ./
RUN go mod download
# Copy source files
COPY *.go ./
COPY cmd ./cmd
COPY internal ./internal
COPY migrations ./migrations
COPY site/dist ./site/dist
COPY site/*.go ./site
COPY . ./
RUN apk add --no-cache \
unzip \
@@ -22,7 +17,7 @@ RUN update-ca-certificates
# Build
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /beszel ./cmd/hub
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /beszel ./internal/cmd/hub
# ? -------------------------
FROM scratch

View File

@@ -3,8 +3,9 @@ package system
// TODO: this is confusing, make common package with common/types common/helpers etc
import (
"beszel/internal/entities/container"
"time"
"github.com/henrygd/beszel/internal/entities/container"
)
type Stats struct {
@@ -31,9 +32,15 @@ type Stats struct {
Temperatures map[string]float64 `json:"t,omitempty" cbor:"20,keyasint,omitempty"`
ExtraFs map[string]*FsStats `json:"efs,omitempty" cbor:"21,keyasint,omitempty"`
GPUData map[string]GPUData `json:"g,omitempty" cbor:"22,keyasint,omitempty"`
LoadAvg1 float64 `json:"l1,omitempty" cbor:"23,keyasint,omitempty,omitzero"`
LoadAvg5 float64 `json:"l5,omitempty" cbor:"24,keyasint,omitempty,omitzero"`
LoadAvg15 float64 `json:"l15,omitempty" cbor:"25,keyasint,omitempty,omitzero"`
LoadAvg1 float64 `json:"l1,omitempty" cbor:"23,keyasint,omitempty"`
LoadAvg5 float64 `json:"l5,omitempty" cbor:"24,keyasint,omitempty"`
LoadAvg15 float64 `json:"l15,omitempty" cbor:"25,keyasint,omitempty"`
Bandwidth [2]uint64 `json:"b,omitzero" cbor:"26,keyasint,omitzero"` // [sent bytes, recv bytes]
MaxBandwidth [2]uint64 `json:"bm,omitzero" cbor:"27,keyasint,omitzero"` // [sent bytes, recv bytes]
// TODO: remove other load fields in future release in favor of load avg array
LoadAvg [3]float64 `json:"la,omitempty" cbor:"28,keyasint"`
Battery [2]uint8 `json:"bat,omitzero" cbor:"29,keyasint,omitzero"` // [percent, charge state, current]
MaxMem float64 `json:"mm,omitempty" cbor:"30,keyasint,omitempty"`
}
type GPUData struct {
@@ -77,23 +84,27 @@ const (
)
type Info struct {
Hostname string `json:"h" cbor:"0,keyasint"`
KernelVersion string `json:"k,omitempty" cbor:"1,keyasint,omitempty"`
Cores int `json:"c" cbor:"2,keyasint"`
Threads int `json:"t,omitempty" cbor:"3,keyasint,omitempty"`
CpuModel string `json:"m" cbor:"4,keyasint"`
Uptime uint64 `json:"u" cbor:"5,keyasint"`
Cpu float64 `json:"cpu" cbor:"6,keyasint"`
MemPct float64 `json:"mp" cbor:"7,keyasint"`
DiskPct float64 `json:"dp" cbor:"8,keyasint"`
Bandwidth float64 `json:"b" cbor:"9,keyasint"`
AgentVersion string `json:"v" cbor:"10,keyasint"`
Podman bool `json:"p,omitempty" cbor:"11,keyasint,omitempty"`
GpuPct float64 `json:"g,omitempty" cbor:"12,keyasint,omitempty"`
DashboardTemp float64 `json:"dt,omitempty" cbor:"13,keyasint,omitempty"`
Os Os `json:"os" cbor:"14,keyasint"`
LoadAvg5 float64 `json:"l5,omitempty" cbor:"15,keyasint,omitempty,omitzero"`
LoadAvg15 float64 `json:"l15,omitempty" cbor:"16,keyasint,omitempty,omitzero"`
Hostname string `json:"h" cbor:"0,keyasint"`
KernelVersion string `json:"k,omitempty" cbor:"1,keyasint,omitempty"`
Cores int `json:"c" cbor:"2,keyasint"`
Threads int `json:"t,omitempty" cbor:"3,keyasint,omitempty"`
CpuModel string `json:"m" cbor:"4,keyasint"`
Uptime uint64 `json:"u" cbor:"5,keyasint"`
Cpu float64 `json:"cpu" cbor:"6,keyasint"`
MemPct float64 `json:"mp" cbor:"7,keyasint"`
DiskPct float64 `json:"dp" cbor:"8,keyasint"`
Bandwidth float64 `json:"b" cbor:"9,keyasint"`
AgentVersion string `json:"v" cbor:"10,keyasint"`
Podman bool `json:"p,omitempty" cbor:"11,keyasint,omitempty"`
GpuPct float64 `json:"g,omitempty" cbor:"12,keyasint,omitempty"`
DashboardTemp float64 `json:"dt,omitempty" cbor:"13,keyasint,omitempty"`
Os Os `json:"os" cbor:"14,keyasint"`
LoadAvg1 float64 `json:"l1,omitempty" cbor:"15,keyasint,omitempty"`
LoadAvg5 float64 `json:"l5,omitempty" cbor:"16,keyasint,omitempty"`
LoadAvg15 float64 `json:"l15,omitempty" cbor:"17,keyasint,omitempty"`
BandwidthBytes uint64 `json:"bb" cbor:"18,keyasint"`
// TODO: remove load fields in future release in favor of load avg array
LoadAvg [3]float64 `json:"la,omitempty" cbor:"19,keyasint"`
}
// Final data structure to return to the hub

View File

@@ -0,0 +1,140 @@
package ghupdate
import (
"archive/tar"
"archive/zip"
"compress/gzip"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
// extract extracts an archive file to the destination directory.
// Supports .zip and .tar.gz files based on the file extension.
func extract(srcPath, destDir string) error {
if strings.HasSuffix(srcPath, ".tar.gz") {
return extractTarGz(srcPath, destDir)
}
// Default to zip extraction
return extractZip(srcPath, destDir)
}
// extractTarGz extracts a tar.gz archive to the destination directory.
func extractTarGz(srcPath, destDir string) error {
src, err := os.Open(srcPath)
if err != nil {
return err
}
defer src.Close()
gz, err := gzip.NewReader(src)
if err != nil {
return err
}
defer gz.Close()
tr := tar.NewReader(gz)
for {
header, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
if header.Typeflag == tar.TypeDir {
if err := os.MkdirAll(filepath.Join(destDir, header.Name), 0755); err != nil {
return err
}
continue
}
if err := os.MkdirAll(filepath.Dir(filepath.Join(destDir, header.Name)), 0755); err != nil {
return err
}
outFile, err := os.Create(filepath.Join(destDir, header.Name))
if err != nil {
return err
}
if _, err := io.Copy(outFile, tr); err != nil {
outFile.Close()
return err
}
outFile.Close()
}
return nil
}
// extractZip extracts the zip archive at "src" to "dest".
//
// Note that only dirs and regular files will be extracted.
// Symbolic links, named pipes, sockets, or any other irregular files
// are skipped because they come with too many edge cases and ambiguities.
func extractZip(src, dest string) error {
zr, err := zip.OpenReader(src)
if err != nil {
return err
}
defer zr.Close()
// normalize dest path to check later for Zip Slip
dest = filepath.Clean(dest) + string(os.PathSeparator)
for _, f := range zr.File {
err := extractFile(f, dest)
if err != nil {
return err
}
}
return nil
}
// extractFile extracts the provided zipFile into "basePath/zipFileName" path,
// creating all the necessary path directories.
func extractFile(zipFile *zip.File, basePath string) error {
path := filepath.Join(basePath, zipFile.Name)
// check for Zip Slip
if !strings.HasPrefix(path, basePath) {
return fmt.Errorf("invalid file path: %s", path)
}
r, err := zipFile.Open()
if err != nil {
return err
}
defer r.Close()
// allow only dirs or regular files
if zipFile.FileInfo().IsDir() {
if err := os.MkdirAll(path, os.ModePerm); err != nil {
return err
}
} else if zipFile.FileInfo().Mode().IsRegular() {
// ensure that the file path directories are created
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
return err
}
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, zipFile.Mode())
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, r)
if err != nil {
return err
}
}
return nil
}

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