Compare commits

..

37 Commits

Author SHA1 Message Date
hank
451f474016 New translations en.po (Portuguese)
[ci skip]
2026-08-04 14:12:45 -04:00
hank
eb329fa2c1 New translations en.po (Romanian)
[ci skip]
2026-07-19 09:06:15 -04:00
hank
dd6e3ffa7b New translations en.po (Chinese Traditional)
[ci skip]
2026-06-29 00:59:54 -04:00
hank
a5abd977b5 New translations en.po (French)
[ci skip]
2026-06-08 11:20:03 -04:00
hank
bcd9fdd2c7 New translations en.po (Arabic)
[ci skip]
2026-06-02 20:49:19 -04:00
hank
06f8249204 New translations en.po (Arabic)
[ci skip]
2026-06-02 19:51:24 -04:00
hank
123d3270d8 New translations en.po (Turkish)
[ci skip]
2026-05-30 18:33:23 -04:00
hank
1073039a97 New translations en.po (French)
[ci skip]
2026-05-14 08:15:21 -04:00
hank
8599e9de94 New translations en.po (Ukrainian)
[ci skip]
2026-05-08 07:22:59 -04:00
hank
b8b3c8eb4e New translations en.po (Ukrainian)
[ci skip]
2026-05-08 05:27:09 -04:00
hank
362306006a New translations en.po (Chinese Simplified)
[ci skip]
2026-05-06 22:00:52 -04:00
hank
8c1df7cdec New translations en.po (Chinese Simplified)
[ci skip]
2026-05-05 04:16:42 -04:00
hank
0d6d493fcd New translations en.po (French)
[ci skip]
2026-04-29 03:17:40 -04:00
hank
b7ffbb1234 New translations en.po (Russian) 2026-04-28 01:14:47 -04:00
hank
c28d016472 New translations en.po (Norwegian) 2026-04-26 19:25:57 -04:00
hank
772c053804 New translations en.po (Norwegian) 2026-04-26 17:32:39 -04:00
hank
6648f6bfe9 New translations en.po (Serbian (Cyrillic)) 2026-04-22 10:14:43 -04:00
hank
88b2da9fd4 New translations en.po (Italian) 2026-04-17 05:26:04 -04:00
henrygd
e5507fa106 refactor(agent): clean up records package and add tests 2026-04-15 16:24:40 -04:00
Lars Lehtonen
a024c3cfd0 fix(cron): log unhandled records cleanup errors (#1909) 2026-04-15 15:33:55 -04:00
henrygd
07466804e7 ui: allow filtering systems by host and agent version (#163) 2026-04-14 16:27:38 -04:00
henrygd
981c788d6f agent: make sure prefixed ALL_PROXY env var works (#1919) 2026-04-14 14:46:43 -04:00
Rafael Marmelo
f5576759de agent: Allow agent to connect to hub via SOCKS5 proxy 2026-04-14 14:46:43 -04:00
Sven van Ginkel
be0b708064 feat(hub): add OAUTH_DISABLE_POPUP env var (#1900)
Co-authored-by: henrygd <hank@henrygd.me>
2026-04-13 20:00:05 -04:00
amarildo
ab3a3de46c deps: update shoutrrr to 0.14.3, fixing some matrix issues (#1906) 2026-04-10 18:35:20 -04:00
Lars Lehtonen
1556e53926 fix(agent): dropped linux battery error (#1908) 2026-04-10 18:33:42 -04:00
henrygd
e3ade3aeb8 hub: optimize System.HasUser check 2026-04-10 18:32:37 -04:00
henrygd
b013f06956 rm deprecated tsconfig baseUrl property 2026-04-10 18:29:20 -04:00
FlintyLemming
3793b27958 fix(agent): use nvme_total_capacity fallback for NVMe disk size (#1899)
Some enterprise NVMe drives (e.g. Dell Ent NVMe CM7 U.2) report capacity
via nvme_total_capacity instead of user_capacity.bytes in smartctl output.
The NVMe SMART parser now falls back to nvme_total_capacity when
user_capacity.bytes is zero.
2026-04-09 15:50:59 -04:00
y0tka
5b02158228 feat(ui): add theme state that follows system/browser theme (#1903) 2026-04-09 15:48:44 -04:00
henrygd
0ae8c42ae0 fix(hub): System.HasUser - return true if SHARE_ALL_SYSTEMS=true (#1891)
- move hub's GetEnv function to new utils package to more easily share
across different hub packages
- change System.HasUser to take core.Record instead of user ID string
- add tests
2026-04-08 20:13:39 -04:00
henrygd
ea80f3c5a2 fix(agent): add safety check for read returning negative bytes (#1799) 2026-04-07 18:41:22 -04:00
henrygd
c3dffff5e4 hub: prevent non-admin users from sending test alerts to internal hosts 2026-04-07 16:08:28 -04:00
henrygd
06fdd0e7a8 refactor(hub,alerts): move api functions/tests to alerts_api.go 2026-04-07 14:47:08 -04:00
henrygd
6e3fd90834 0.18.7 release 2026-04-05 16:14:39 -04:00
henrygd
5ab82183fa comment out unneeded test that returns different status in dev / prod (add todo) 2026-04-05 16:14:28 -04:00
henrygd
a68e02ca84 update translations 2026-04-05 15:22:26 -04:00
75 changed files with 8427 additions and 1800 deletions

View File

@@ -82,6 +82,9 @@ func GetBatteryStats() (batteryPercent uint8, batteryState uint8, err error) {
return batteryPercent, batteryState, errors.ErrUnsupported
}
paths, err := getBatteryPaths()
if err != nil {
return batteryPercent, batteryState, err
}
if len(paths) == 0 {
return batteryPercent, batteryState, errors.New("no batteries")
}

View File

@@ -20,6 +20,7 @@ import (
"github.com/fxamacker/cbor/v2"
"github.com/lxzan/gws"
"golang.org/x/crypto/ssh"
"golang.org/x/net/proxy"
)
const (
@@ -104,6 +105,11 @@ func (client *WebSocketClient) getOptions() *gws.ClientOption {
}
client.hubURL.Path = path.Join(client.hubURL.Path, "api/beszel/agent-connect")
// make sure BESZEL_AGENT_ALL_PROXY works (GWS only checks ALL_PROXY)
if val := os.Getenv("BESZEL_AGENT_ALL_PROXY"); val != "" {
os.Setenv("ALL_PROXY", val)
}
client.options = &gws.ClientOption{
Addr: client.hubURL.String(),
TlsConfig: &tls.Config{InsecureSkipVerify: true},
@@ -112,6 +118,9 @@ func (client *WebSocketClient) getOptions() *gws.ClientOption {
"X-Token": []string{client.token},
"X-Beszel": []string{beszel.Version},
},
NewDialer: func() (gws.Dialer, error) {
return proxy.FromEnvironment(), nil
},
}
return client.options
}

View File

@@ -156,6 +156,7 @@ func (gm *GPUManager) updateAmdGpuData(cardPath string) bool {
func readSysfsFloat(path string) (float64, error) {
val, err := utils.ReadStringFileLimited(path, 64)
if err != nil {
slog.Debug("Failed to read sysfs value", "path", path, "error", err)
return 0, err
}
return strconv.ParseFloat(val, 64)

View File

@@ -1118,6 +1118,9 @@ func (sm *SmartManager) parseSmartForNvme(output []byte) (bool, int) {
smartData.SerialNumber = data.SerialNumber
smartData.FirmwareVersion = data.FirmwareVersion
smartData.Capacity = data.UserCapacity.Bytes
if smartData.Capacity == 0 {
smartData.Capacity = data.NVMeTotalCapacity
}
if smartData.Capacity == 0 && (runtime.GOOS == "darwin" || sm.darwinNvmeProvider != nil) {
smartData.Capacity = sm.lookupDarwinNvmeCapacity(data.SerialNumber)
}

View File

@@ -1,6 +1,8 @@
// Package utils provides utility functions for the agent.
package utils
import (
"fmt"
"io"
"math"
"os"
@@ -68,6 +70,9 @@ func ReadStringFileLimited(path string, maxSize int) (string, error) {
if err != nil && err != io.EOF {
return "", err
}
if n < 0 {
return "", fmt.Errorf("%s returned negative bytes: %d", path, n)
}
return strings.TrimSpace(string(buf[:n])), nil
}

View File

@@ -6,7 +6,7 @@ import "github.com/blang/semver"
const (
// Version is the current version of the application.
Version = "0.18.6"
Version = "0.18.7"
// AppName is the name of the application.
AppName = "beszel"
)

2
go.mod
View File

@@ -10,7 +10,7 @@ require (
github.com/gliderlabs/ssh v0.3.8
github.com/google/uuid v1.6.0
github.com/lxzan/gws v1.9.1
github.com/nicholas-fedor/shoutrrr v0.14.1
github.com/nicholas-fedor/shoutrrr v0.14.3
github.com/pocketbase/dbx v1.12.0
github.com/pocketbase/pocketbase v0.36.8
github.com/shirou/gopsutil/v4 v4.26.3

4
go.sum
View File

@@ -85,8 +85,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/nicholas-fedor/shoutrrr v0.14.1 h1:6sx4cJNfNuUtD6ygGlB0dqcCQ+abfsUh+b+6jgujf6A=
github.com/nicholas-fedor/shoutrrr v0.14.1/go.mod h1:U7IywBkLpBV7rgn8iLbQ9/LklJG1gm24bFv5cXXsDKs=
github.com/nicholas-fedor/shoutrrr v0.14.3 h1:aBX2iw9a7jl5wfHd3bi9LnS5ucoYIy6KcLH9XVF+gig=
github.com/nicholas-fedor/shoutrrr v0.14.3/go.mod h1:U7IywBkLpBV7rgn8iLbQ9/LklJG1gm24bFv5cXXsDKs=
github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=
github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=

View File

@@ -302,21 +302,6 @@ func (am *AlertManager) SendShoutrrrAlert(notificationUrl, title, message, link,
return nil
}
func (am *AlertManager) SendTestNotification(e *core.RequestEvent) error {
var data struct {
URL string `json:"url"`
}
err := e.BindBody(&data)
if err != nil || data.URL == "" {
return e.BadRequestError("URL is required", err)
}
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()})
}
return e.JSON(200, map[string]bool{"err": false})
}
// setAlertTriggered updates the "triggered" status of an alert record in the database
func (am *AlertManager) setAlertTriggered(alert CachedAlertData, triggered bool) error {
alertRecord, err := am.hub.FindRecordById("alerts", alert.Id)

View File

@@ -3,7 +3,11 @@ package alerts
import (
"database/sql"
"errors"
"net"
"net/http"
"net/url"
"slices"
"strings"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
@@ -117,3 +121,72 @@ func DeleteUserAlerts(e *core.RequestEvent) error {
return e.JSON(http.StatusOK, map[string]any{"success": true, "count": numDeleted})
}
// SendTestNotification handles API request to send a test notification to a specified Shoutrrr URL
func (am *AlertManager) SendTestNotification(e *core.RequestEvent) error {
var data struct {
URL string `json:"url"`
}
err := e.BindBody(&data)
if err != nil || data.URL == "" {
return e.BadRequestError("URL is required", err)
}
// Only allow admins to send test notifications to internal URLs
if !e.Auth.IsSuperuser() && e.Auth.GetString("role") != "admin" {
internalURL, err := isInternalURL(data.URL)
if err != nil {
return e.BadRequestError(err.Error(), nil)
}
if internalURL {
return e.ForbiddenError("Only admins can send to internal destinations", nil)
}
}
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()})
}
return e.JSON(200, map[string]bool{"err": false})
}
// isInternalURL checks if the given shoutrrr URL points to an internal destination (localhost or private IP)
func isInternalURL(rawURL string) (bool, error) {
parsedURL, err := url.Parse(rawURL)
if err != nil {
return false, err
}
host := parsedURL.Hostname()
if host == "" {
return false, nil
}
if strings.EqualFold(host, "localhost") {
return true, nil
}
if ip := net.ParseIP(host); ip != nil {
return isInternalIP(ip), nil
}
// Some Shoutrrr URLs use the host position for service identifiers rather than a
// network hostname (for example, discord://token@webhookid). Restrict DNS lookups
// to names that look like actual hostnames so valid service URLs keep working.
if !strings.Contains(host, ".") {
return false, nil
}
ips, err := net.LookupIP(host)
if err != nil {
return false, nil
}
if slices.ContainsFunc(ips, isInternalIP) {
return true, nil
}
return false, nil
}
func isInternalIP(ip net.IP) bool {
return ip.IsPrivate() || ip.IsLoopback() || ip.IsUnspecified()
}

View File

@@ -0,0 +1,501 @@
//go:build testing
package alerts_test
import (
"bytes"
"encoding/json"
"io"
"net/http"
"strings"
"testing"
"github.com/henrygd/beszel/internal/alerts"
beszelTests "github.com/henrygd/beszel/internal/tests"
pbTests "github.com/pocketbase/pocketbase/tests"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
"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 TestIsInternalURL(t *testing.T) {
testCases := []struct {
name string
url string
internal bool
}{
{name: "loopback ipv4", url: "generic://127.0.0.1", internal: true},
{name: "localhost hostname", url: "generic://localhost", internal: true},
{name: "localhost hostname", url: "generic+http://localhost/api/v1/postStuff", internal: true},
{name: "localhost hostname", url: "generic+http://127.0.0.1:8080/api/v1/postStuff", internal: true},
{name: "localhost hostname", url: "generic+https://beszel.dev/api/v1/postStuff", internal: false},
{name: "public ipv4", url: "generic://8.8.8.8", internal: false},
{name: "token style service url", url: "discord://abc123@123456789", internal: false},
{name: "single label service url", url: "slack://token@team/channel", internal: false},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
internal, err := alerts.IsInternalURL(testCase.url)
assert.NoError(t, err)
assert.Equal(t, testCase.internal, internal)
})
}
}
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 TestSendTestNotification(t *testing.T) {
hub, user := beszelTests.GetHubWithUser(t)
defer hub.Cleanup()
userToken, err := user.NewAuthToken()
adminUser, err := beszelTests.CreateUserWithRole(hub, "admin@example.com", "password123", "admin")
assert.NoError(t, err, "Failed to create admin user")
adminUserToken, err := adminUser.NewAuthToken()
superuser, err := beszelTests.CreateSuperuser(hub, "superuser@example.com", "password123")
assert.NoError(t, err, "Failed to create superuser")
superuserToken, err := superuser.NewAuthToken()
assert.NoError(t, err, "Failed to create superuser auth token")
testAppFactory := func(t testing.TB) *pbTests.TestApp {
return hub.TestApp
}
scenarios := []beszelTests.ApiScenario{
{
Name: "POST /test-notification - no auth should fail",
Method: http.MethodPost,
URL: "/api/beszel/test-notification",
ExpectedStatus: 401,
ExpectedContent: []string{"requires valid"},
TestAppFactory: testAppFactory,
Body: jsonReader(map[string]any{
"url": "generic://127.0.0.1",
}),
},
{
Name: "POST /test-notification - with external auth should succeed",
Method: http.MethodPost,
URL: "/api/beszel/test-notification",
TestAppFactory: testAppFactory,
Headers: map[string]string{
"Authorization": userToken,
},
Body: jsonReader(map[string]any{
"url": "generic://8.8.8.8",
}),
ExpectedStatus: 200,
ExpectedContent: []string{"\"err\":"},
},
{
Name: "POST /test-notification - local url with user auth should fail",
Method: http.MethodPost,
URL: "/api/beszel/test-notification",
TestAppFactory: testAppFactory,
Headers: map[string]string{
"Authorization": userToken,
},
Body: jsonReader(map[string]any{
"url": "generic://localhost:8010",
}),
ExpectedStatus: 403,
ExpectedContent: []string{"Only admins"},
},
{
Name: "POST /test-notification - internal url with user auth should fail",
Method: http.MethodPost,
URL: "/api/beszel/test-notification",
TestAppFactory: testAppFactory,
Headers: map[string]string{
"Authorization": userToken,
},
Body: jsonReader(map[string]any{
"url": "generic+http://192.168.0.5",
}),
ExpectedStatus: 403,
ExpectedContent: []string{"Only admins"},
},
{
Name: "POST /test-notification - internal url with admin auth should succeed",
Method: http.MethodPost,
URL: "/api/beszel/test-notification",
TestAppFactory: testAppFactory,
Headers: map[string]string{
"Authorization": adminUserToken,
},
Body: jsonReader(map[string]any{
"url": "generic://127.0.0.1",
}),
ExpectedStatus: 200,
ExpectedContent: []string{"\"err\":"},
},
{
Name: "POST /test-notification - internal url with superuser auth should succeed",
Method: http.MethodPost,
URL: "/api/beszel/test-notification",
TestAppFactory: testAppFactory,
Headers: map[string]string{
"Authorization": superuserToken,
},
Body: jsonReader(map[string]any{
"url": "generic://127.0.0.1",
}),
ExpectedStatus: 200,
ExpectedContent: []string{"\"err\":"},
},
}
for _, scenario := range scenarios {
scenario.Test(t)
}
}

View File

@@ -3,11 +3,6 @@
package alerts_test
import (
"bytes"
"encoding/json"
"io"
"net/http"
"strings"
"testing"
"testing/synctest"
"time"
@@ -16,359 +11,9 @@ import (
"github.com/henrygd/beszel/internal/alerts"
"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 TestAlertsHistory(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
hub, user := beszelTests.GetHubWithUser(t)

View File

@@ -95,3 +95,7 @@ func (am *AlertManager) RestorePendingStatusAlerts() error {
func (am *AlertManager) SetAlertTriggered(alert CachedAlertData, triggered bool) error {
return am.setAlertTriggered(alert, triggered)
}
func IsInternalURL(rawURL string) (bool, error) {
return isInternalURL(rawURL)
}

View File

@@ -494,7 +494,7 @@ type SmartInfoForNvme struct {
FirmwareVersion string `json:"firmware_version"`
// NVMePCIVendor NVMePCIVendor `json:"nvme_pci_vendor"`
// NVMeIEEEOUIIdentifier uint32 `json:"nvme_ieee_oui_identifier"`
// NVMeTotalCapacity uint64 `json:"nvme_total_capacity"`
NVMeTotalCapacity uint64 `json:"nvme_total_capacity"`
// NVMeUnallocatedCapacity uint64 `json:"nvme_unallocated_capacity"`
// NVMeControllerID uint16 `json:"nvme_controller_id"`
// NVMeVersion VersionStringInfo `json:"nvme_version"`

View File

@@ -14,6 +14,7 @@ import (
"github.com/henrygd/beszel/internal/ghupdate"
"github.com/henrygd/beszel/internal/hub/config"
"github.com/henrygd/beszel/internal/hub/systems"
"github.com/henrygd/beszel/internal/hub/utils"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
@@ -70,13 +71,13 @@ func (h *Hub) registerMiddlewares(se *core.ServeEvent) {
return e.Next()
}
// authenticate with trusted header
if autoLogin, _ := GetEnv("AUTO_LOGIN"); autoLogin != "" {
if autoLogin, _ := utils.GetEnv("AUTO_LOGIN"); autoLogin != "" {
se.Router.BindFunc(func(e *core.RequestEvent) error {
return authorizeRequestWithEmail(e, autoLogin)
})
}
// authenticate with trusted header
if trustedHeader, _ := GetEnv("TRUSTED_AUTH_HEADER"); trustedHeader != "" {
if trustedHeader, _ := utils.GetEnv("TRUSTED_AUTH_HEADER"); trustedHeader != "" {
se.Router.BindFunc(func(e *core.RequestEvent) error {
return authorizeRequestWithEmail(e, e.Request.Header.Get(trustedHeader))
})
@@ -104,7 +105,7 @@ func (h *Hub) registerApiRoutes(se *core.ServeEvent) error {
apiAuth.GET("/info", h.getInfo)
apiAuth.GET("/getkey", h.getInfo) // deprecated - keep for compatibility w/ integrations
// check for updates
if optIn, _ := GetEnv("CHECK_UPDATES"); optIn == "true" {
if optIn, _ := utils.GetEnv("CHECK_UPDATES"); optIn == "true" {
var updateInfo UpdateInfo
apiAuth.GET("/update", updateInfo.getUpdate)
}
@@ -127,7 +128,7 @@ func (h *Hub) registerApiRoutes(se *core.ServeEvent) error {
// get systemd service details
apiAuth.GET("/systemd/info", h.getSystemdInfo)
// /containers routes
if enabled, _ := GetEnv("CONTAINER_DETAILS"); enabled != "false" {
if enabled, _ := utils.GetEnv("CONTAINER_DETAILS"); enabled != "false" {
// get container logs
apiAuth.GET("/containers/logs", h.getContainerLogs)
// get container info
@@ -147,7 +148,7 @@ func (h *Hub) getInfo(e *core.RequestEvent) error {
Key: h.pubKey,
Version: beszel.Version,
}
if optIn, _ := GetEnv("CHECK_UPDATES"); optIn == "true" {
if optIn, _ := utils.GetEnv("CHECK_UPDATES"); optIn == "true" {
info.CheckUpdate = true
}
return e.JSON(http.StatusOK, info)
@@ -315,7 +316,7 @@ func (h *Hub) containerRequestHandler(e *core.RequestEvent, fetchFunc func(*syst
}
system, err := h.sm.GetSystem(systemID)
if err != nil || !system.HasUser(e.App, e.Auth.Id) {
if err != nil || !system.HasUser(e.App, e.Auth) {
return e.NotFoundError("", nil)
}
@@ -350,7 +351,7 @@ func (h *Hub) getSystemdInfo(e *core.RequestEvent) error {
return e.BadRequestError("Invalid system or service parameter", nil)
}
system, err := h.sm.GetSystem(systemID)
if err != nil || !system.HasUser(e.App, e.Auth.Id) {
if err != nil || !system.HasUser(e.App, e.Auth) {
return e.NotFoundError("", nil)
}
// verify service exists before fetching details
@@ -378,7 +379,7 @@ func (h *Hub) refreshSmartData(e *core.RequestEvent) error {
}
system, err := h.sm.GetSystem(systemID)
if err != nil || !system.HasUser(e.App, e.Auth.Id) {
if err != nil || !system.HasUser(e.App, e.Auth) {
return e.NotFoundError("", nil)
}

View File

@@ -66,31 +66,6 @@ func TestApiRoutesAuthentication(t *testing.T) {
scenarios := []beszelTests.ApiScenario{
// Auth Protected Routes - Should require authentication
{
Name: "POST /test-notification - no auth should fail",
Method: http.MethodPost,
URL: "/api/beszel/test-notification",
ExpectedStatus: 401,
ExpectedContent: []string{"requires valid"},
TestAppFactory: testAppFactory,
Body: jsonReader(map[string]any{
"url": "generic://127.0.0.1",
}),
},
{
Name: "POST /test-notification - with auth should succeed",
Method: http.MethodPost,
URL: "/api/beszel/test-notification",
TestAppFactory: testAppFactory,
Headers: map[string]string{
"Authorization": userToken,
},
Body: jsonReader(map[string]any{
"url": "generic://127.0.0.1",
}),
ExpectedStatus: 200,
ExpectedContent: []string{"sending message"},
},
{
Name: "GET /config-yaml - no auth should fail",
Method: http.MethodGet,
@@ -369,6 +344,23 @@ func TestApiRoutesAuthentication(t *testing.T) {
"Authorization": user2Token,
},
},
{
Name: "GET /containers/info - SHARE_ALL_SYSTEMS allows non-member user",
Method: http.MethodGet,
URL: fmt.Sprintf("/api/beszel/containers/info?system=%s&container=abababababab", system.Id),
ExpectedStatus: 500,
ExpectedContent: []string{"Something went wrong while processing your request."},
TestAppFactory: testAppFactory,
Headers: map[string]string{
"Authorization": user2Token,
},
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
t.Setenv("SHARE_ALL_SYSTEMS", "true")
},
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
t.Setenv("SHARE_ALL_SYSTEMS", "")
},
},
{
Name: "GET /containers/logs - with auth but missing system param should fail",
Method: http.MethodGet,
@@ -630,13 +622,17 @@ func TestApiRoutesAuthentication(t *testing.T) {
"systems": []string{system.Id},
}),
},
{
Name: "GET /update - shouldn't exist without CHECK_UPDATES env var",
Method: http.MethodGet,
URL: "/api/beszel/update",
ExpectedStatus: 502,
TestAppFactory: testAppFactory,
},
// this works but diff behavior on prod vs dev.
// dev returns 502; prod returns 200 with static html page 404
// TODO: align dev and prod behavior and re-enable this test
// {
// Name: "GET /update - shouldn't exist without CHECK_UPDATES env var",
// Method: http.MethodGet,
// URL: "/api/beszel/update",
// NotExpectedContent: []string{"v:", "\"v\":"},
// ExpectedStatus: 502,
// TestAppFactory: testAppFactory,
// },
}
for _, scenario := range scenarios {

View File

@@ -1,6 +1,9 @@
package hub
import "github.com/pocketbase/pocketbase/core"
import (
"github.com/henrygd/beszel/internal/hub/utils"
"github.com/pocketbase/pocketbase/core"
)
type collectionRules struct {
list *string
@@ -22,11 +25,11 @@ func setCollectionAuthSettings(app core.App) error {
}
// disable email auth if DISABLE_PASSWORD_AUTH env var is set
disablePasswordAuth, _ := GetEnv("DISABLE_PASSWORD_AUTH")
disablePasswordAuth, _ := utils.GetEnv("DISABLE_PASSWORD_AUTH")
usersCollection.PasswordAuth.Enabled = disablePasswordAuth != "true"
usersCollection.PasswordAuth.IdentityFields = []string{"email"}
// allow oauth user creation if USER_CREATION is set
if userCreation, _ := GetEnv("USER_CREATION"); userCreation == "true" {
if userCreation, _ := utils.GetEnv("USER_CREATION"); userCreation == "true" {
cr := "@request.context = 'oauth2'"
usersCollection.CreateRule = &cr
} else {
@@ -34,7 +37,7 @@ func setCollectionAuthSettings(app core.App) error {
}
// enable mfaOtp mfa if MFA_OTP env var is set
mfaOtp, _ := GetEnv("MFA_OTP")
mfaOtp, _ := utils.GetEnv("MFA_OTP")
usersCollection.OTP.Length = 6
superusersCollection.OTP.Length = 6
usersCollection.OTP.Enabled = mfaOtp == "true"
@@ -50,7 +53,7 @@ func setCollectionAuthSettings(app core.App) error {
// When SHARE_ALL_SYSTEMS is enabled, any authenticated user can read
// system-scoped data. Write rules continue to block readonly users.
shareAllSystems, _ := GetEnv("SHARE_ALL_SYSTEMS")
shareAllSystems, _ := utils.GetEnv("SHARE_ALL_SYSTEMS")
authenticatedRule := "@request.auth.id != \"\""
systemsMemberRule := authenticatedRule + " && users.id ?= @request.auth.id"

View File

@@ -15,6 +15,7 @@ import (
"github.com/henrygd/beszel/internal/hub/config"
"github.com/henrygd/beszel/internal/hub/heartbeat"
"github.com/henrygd/beszel/internal/hub/systems"
"github.com/henrygd/beszel/internal/hub/utils"
"github.com/henrygd/beszel/internal/records"
"github.com/henrygd/beszel/internal/users"
@@ -44,7 +45,7 @@ func NewHub(app core.App) *Hub {
hub.um = users.NewUserManager(hub)
hub.rm = records.NewRecordManager(hub)
hub.sm = systems.NewSystemManager(hub)
hub.hb = heartbeat.New(app, GetEnv)
hub.hb = heartbeat.New(app, utils.GetEnv)
if hub.hb != nil {
hub.hbStop = make(chan struct{})
}
@@ -52,15 +53,6 @@ func NewHub(app core.App) *Hub {
return hub
}
// GetEnv retrieves an environment variable with a "BESZEL_HUB_" prefix, or falls back to the unprefixed key.
func GetEnv(key string) (value string, exists bool) {
if value, exists = os.LookupEnv("BESZEL_HUB_" + key); exists {
return value, exists
}
// Fallback to the old unprefixed key
return os.LookupEnv(key)
}
// onAfterBootstrapAndMigrations ensures the provided function runs after the database is set up and migrations are applied.
// This is a workaround for behavior in PocketBase where onBootstrap runs before migrations, forcing use of onServe for this purpose.
// However, PB's tests.TestApp is already bootstrapped, generally doesn't serve, but does handle migrations.
@@ -131,7 +123,7 @@ func (h *Hub) initialize(app core.App) error {
// batch requests (for alerts)
settings.Batch.Enabled = true
// set URL if APP_URL env is set
if appURL, isSet := GetEnv("APP_URL"); isSet {
if appURL, isSet := utils.GetEnv("APP_URL"); isSet {
h.appURL = appURL
settings.Meta.AppURL = appURL
}

42
internal/hub/server.go Normal file
View File

@@ -0,0 +1,42 @@
package hub
import (
"encoding/json"
"net/url"
"strings"
"github.com/henrygd/beszel"
"github.com/henrygd/beszel/internal/hub/utils"
)
// PublicAppInfo defines the structure of the public app information that will be injected into the HTML
type PublicAppInfo struct {
BASE_PATH string
HUB_VERSION string
HUB_URL string
OAUTH_DISABLE_POPUP bool `json:"OAUTH_DISABLE_POPUP,omitempty"`
}
// modifyIndexHTML injects the public app information into the index.html content
func modifyIndexHTML(hub *Hub, html []byte) string {
info := getPublicAppInfo(hub)
content, err := json.Marshal(info)
if err != nil {
return string(html)
}
htmlContent := strings.ReplaceAll(string(html), "./", info.BASE_PATH)
return strings.Replace(htmlContent, "\"{info}\"", string(content), 1)
}
func getPublicAppInfo(hub *Hub) PublicAppInfo {
parsedURL, _ := url.Parse(hub.appURL)
info := PublicAppInfo{
BASE_PATH: strings.TrimSuffix(parsedURL.Path, "/") + "/",
HUB_VERSION: beszel.Version,
HUB_URL: hub.appURL,
}
if val, _ := utils.GetEnv("OAUTH_DISABLE_POPUP"); val == "true" {
info.OAUTH_DISABLE_POPUP = true
}
return info
}

View File

@@ -10,8 +10,6 @@ import (
"net/url"
"strings"
"github.com/henrygd/beszel"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/osutils"
)
@@ -38,7 +36,7 @@ func (rm *responseModifier) RoundTrip(req *http.Request) (*http.Response, error)
}
resp.Body.Close()
// Create a new response with the modified body
modifiedBody := rm.modifyHTML(string(body))
modifiedBody := modifyIndexHTML(rm.hub, body)
resp.Body = io.NopCloser(strings.NewReader(modifiedBody))
resp.ContentLength = int64(len(modifiedBody))
resp.Header.Set("Content-Length", fmt.Sprintf("%d", len(modifiedBody)))
@@ -46,19 +44,6 @@ func (rm *responseModifier) RoundTrip(req *http.Request) (*http.Response, error)
return resp, nil
}
func (rm *responseModifier) modifyHTML(html string) string {
parsedURL, err := url.Parse(rm.hub.appURL)
if err != nil {
return html
}
// fix base paths in html if using subpath
basePath := strings.TrimSuffix(parsedURL.Path, "/") + "/"
html = strings.ReplaceAll(html, "./", basePath)
html = strings.Replace(html, "{{V}}", beszel.Version, 1)
html = strings.Replace(html, "{{HUB_URL}}", rm.hub.appURL, 1)
return html
}
// startServer sets up the development server for Beszel
func (h *Hub) startServer(se *core.ServeEvent) error {
proxy := httputil.NewSingleHostReverseProxy(&url.URL{

View File

@@ -5,10 +5,9 @@ package hub
import (
"io/fs"
"net/http"
"net/url"
"strings"
"github.com/henrygd/beszel"
"github.com/henrygd/beszel/internal/hub/utils"
"github.com/henrygd/beszel/internal/site"
"github.com/pocketbase/pocketbase/apis"
@@ -17,22 +16,13 @@ import (
// startServer sets up the production server for Beszel
func (h *Hub) startServer(se *core.ServeEvent) error {
// parse app url
parsedURL, err := url.Parse(h.appURL)
if err != nil {
return err
}
// fix base paths in html if using subpath
basePath := strings.TrimSuffix(parsedURL.Path, "/") + "/"
indexFile, _ := fs.ReadFile(site.DistDirFS, "index.html")
html := strings.ReplaceAll(string(indexFile), "./", basePath)
html = strings.Replace(html, "{{V}}", beszel.Version, 1)
html = strings.Replace(html, "{{HUB_URL}}", h.appURL, 1)
html := modifyIndexHTML(h, indexFile)
// set up static asset serving
staticPaths := [2]string{"/static/", "/assets/"}
serveStatic := apis.Static(site.DistDirFS, false)
// get CSP configuration
csp, cspExists := GetEnv("CSP")
csp, cspExists := utils.GetEnv("CSP")
// add route
se.Router.GET("/{path...}", func(e *core.RequestEvent) error {
// serve static assets if path is in staticPaths

View File

@@ -8,13 +8,13 @@ import (
"hash/fnv"
"math/rand"
"net"
"slices"
"strings"
"sync/atomic"
"time"
"github.com/henrygd/beszel/internal/common"
"github.com/henrygd/beszel/internal/hub/transport"
"github.com/henrygd/beszel/internal/hub/utils"
"github.com/henrygd/beszel/internal/hub/ws"
"github.com/henrygd/beszel/internal/entities/container"
@@ -353,14 +353,25 @@ func (sys *System) getRecord(app core.App) (*core.Record, error) {
return record, nil
}
// HasUser checks if the given user ID is in the system's users list.
func (sys *System) HasUser(app core.App, userID string) bool {
record, err := sys.getRecord(app)
if err != nil {
// HasUser checks if the given user is in the system's users list.
// Returns true if SHARE_ALL_SYSTEMS is enabled (any authenticated user can access any system).
func (sys *System) HasUser(app core.App, user *core.Record) bool {
if user == nil {
return false
}
users := record.GetStringSlice("users")
return slices.Contains(users, userID)
if v, _ := utils.GetEnv("SHARE_ALL_SYSTEMS"); v == "true" {
return true
}
var recordData = struct {
Users string
}{}
err := app.DB().NewQuery("SELECT users FROM systems WHERE id={:id}").
Bind(dbx.Params{"id": sys.Id}).
One(&recordData)
if err != nil || recordData.Users == "" {
return false
}
return strings.Contains(recordData.Users, user.Id)
}
// setDown marks a system as down in the database.

View File

@@ -421,3 +421,60 @@ func testOld(t *testing.T, hub *tests.TestHub) {
assert.NoError(t, err)
})
}
func TestHasUser(t *testing.T) {
hub, err := tests.NewTestHub(t.TempDir())
require.NoError(t, err)
defer hub.Cleanup()
sm := hub.GetSystemManager()
err = sm.Initialize()
require.NoError(t, err)
user1, err := tests.CreateUser(hub, "user1@test.com", "password123")
require.NoError(t, err)
user2, err := tests.CreateUser(hub, "user2@test.com", "password123")
require.NoError(t, err)
systemRecord, err := tests.CreateRecord(hub, "systems", map[string]any{
"name": "has-user-test",
"host": "127.0.0.1",
"port": "33914",
"users": []string{user1.Id},
})
require.NoError(t, err)
sys, err := sm.GetSystemFromStore(systemRecord.Id)
require.NoError(t, err)
t.Run("user in list returns true", func(t *testing.T) {
assert.True(t, sys.HasUser(hub, user1))
})
t.Run("user not in list returns false", func(t *testing.T) {
assert.False(t, sys.HasUser(hub, user2))
})
t.Run("unknown user ID returns false", func(t *testing.T) {
assert.False(t, sys.HasUser(hub, nil))
})
t.Run("SHARE_ALL_SYSTEMS=true grants access to non-member", func(t *testing.T) {
t.Setenv("SHARE_ALL_SYSTEMS", "true")
assert.True(t, sys.HasUser(hub, user2))
})
t.Run("BESZEL_HUB_SHARE_ALL_SYSTEMS=true grants access to non-member", func(t *testing.T) {
t.Setenv("BESZEL_HUB_SHARE_ALL_SYSTEMS", "true")
assert.True(t, sys.HasUser(hub, user2))
})
t.Run("additional user works", func(t *testing.T) {
assert.False(t, sys.HasUser(hub, user2))
systemRecord.Set("users", []string{user1.Id, user2.Id})
err = hub.Save(systemRecord)
require.NoError(t, err)
assert.True(t, sys.HasUser(hub, user1))
assert.True(t, sys.HasUser(hub, user2))
})
}

View File

@@ -0,0 +1,12 @@
// Package utils provides utility functions for the hub.
package utils
import "os"
// GetEnv retrieves an environment variable with a "BESZEL_HUB_" prefix, or falls back to the unprefixed key.
func GetEnv(key string) (value string, exists bool) {
if value, exists = os.LookupEnv("BESZEL_HUB_" + key); exists {
return value, exists
}
return os.LookupEnv(key)
}

View File

@@ -3,10 +3,8 @@ package records
import (
"encoding/json"
"fmt"
"log"
"math"
"strings"
"time"
"github.com/henrygd/beszel/internal/entities/container"
@@ -39,16 +37,6 @@ type StatsRecord struct {
Stats []byte `db:"stats"`
}
// global variables for reusing allocations
var (
statsRecord StatsRecord
containerStats []container.Stats
sumStats system.Stats
tempStats system.Stats
queryParams = make(dbx.Params, 1)
containerSums = make(map[string]*container.Stats)
)
// Create longer records by averaging shorter records
func (rm *RecordManager) CreateLongerRecords() {
// start := time.Now()
@@ -163,41 +151,47 @@ func (rm *RecordManager) CreateLongerRecords() {
return nil
})
statsRecord.Stats = statsRecord.Stats[:0]
// log.Println("finished creating longer records", "time (ms)", time.Since(start).Milliseconds())
}
// Calculate the average stats of a list of system_stats records without reflect
func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *system.Stats {
// Clear/reset global structs for reuse
sumStats = system.Stats{}
tempStats = system.Stats{}
sum := &sumStats
stats := &tempStats
stats := make([]system.Stats, 0, len(records))
var row StatsRecord
params := make(dbx.Params, 1)
for _, rec := range records {
row.Stats = row.Stats[:0]
params["id"] = rec.Id
db.NewQuery("SELECT stats FROM system_stats WHERE id = {:id}").Bind(params).One(&row)
var s system.Stats
if err := json.Unmarshal(row.Stats, &s); err != nil {
continue
}
stats = append(stats, s)
}
result := AverageSystemStatsSlice(stats)
return &result
}
// AverageSystemStatsSlice computes the average of a slice of system stats.
func AverageSystemStatsSlice(records []system.Stats) system.Stats {
var sum system.Stats
count := float64(len(records))
if count == 0 {
return sum
}
// necessary because uint8 is not big enough for the sum
batterySum := 0
// accumulate per-core usage across records
var cpuCoresSums []uint64
// accumulate cpu breakdown [user, system, iowait, steal, idle]
var cpuBreakdownSums []float64
count := float64(len(records))
tempCount := float64(0)
// Accumulate totals
for _, record := range records {
id := record.Id
// clear global statsRecord for reuse
statsRecord.Stats = statsRecord.Stats[:0]
// reset tempStats each iteration to avoid omitzero fields retaining stale values
*stats = system.Stats{}
queryParams["id"] = id
db.NewQuery("SELECT stats FROM system_stats WHERE id = {:id}").Bind(queryParams).One(&statsRecord)
if err := json.Unmarshal(statsRecord.Stats, stats); err != nil {
continue
}
for i := range records {
stats := &records[i]
sum.Cpu += stats.Cpu
// accumulate cpu time breakdowns if present
@@ -205,8 +199,8 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *
if len(cpuBreakdownSums) < len(stats.CpuBreakdown) {
cpuBreakdownSums = append(cpuBreakdownSums, make([]float64, len(stats.CpuBreakdown)-len(cpuBreakdownSums))...)
}
for i, v := range stats.CpuBreakdown {
cpuBreakdownSums[i] += v
for j, v := range stats.CpuBreakdown {
cpuBreakdownSums[j] += v
}
}
sum.Mem += stats.Mem
@@ -242,8 +236,8 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *
// extend slices to accommodate core count
cpuCoresSums = append(cpuCoresSums, make([]uint64, len(stats.CpuCoresUsage)-len(cpuCoresSums))...)
}
for i, v := range stats.CpuCoresUsage {
cpuCoresSums[i] += uint64(v)
for j, v := range stats.CpuCoresUsage {
cpuCoresSums[j] += uint64(v)
}
}
// Set peak values
@@ -343,109 +337,107 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *
}
}
// Compute averages in place
if count > 0 {
sum.Cpu = twoDecimals(sum.Cpu / count)
sum.Mem = twoDecimals(sum.Mem / count)
sum.MemUsed = twoDecimals(sum.MemUsed / count)
sum.MemPct = twoDecimals(sum.MemPct / count)
sum.MemBuffCache = twoDecimals(sum.MemBuffCache / count)
sum.MemZfsArc = twoDecimals(sum.MemZfsArc / count)
sum.Swap = twoDecimals(sum.Swap / count)
sum.SwapUsed = twoDecimals(sum.SwapUsed / count)
sum.DiskTotal = twoDecimals(sum.DiskTotal / count)
sum.DiskUsed = twoDecimals(sum.DiskUsed / count)
sum.DiskPct = twoDecimals(sum.DiskPct / count)
sum.DiskReadPs = twoDecimals(sum.DiskReadPs / count)
sum.DiskWritePs = twoDecimals(sum.DiskWritePs / count)
sum.DiskIO[0] = sum.DiskIO[0] / uint64(count)
sum.DiskIO[1] = sum.DiskIO[1] / uint64(count)
for i := range sum.DiskIoStats {
sum.DiskIoStats[i] = twoDecimals(sum.DiskIoStats[i] / count)
}
sum.NetworkSent = twoDecimals(sum.NetworkSent / count)
sum.NetworkRecv = twoDecimals(sum.NetworkRecv / count)
sum.LoadAvg[0] = twoDecimals(sum.LoadAvg[0] / count)
sum.LoadAvg[1] = twoDecimals(sum.LoadAvg[1] / count)
sum.LoadAvg[2] = twoDecimals(sum.LoadAvg[2] / count)
sum.Bandwidth[0] = sum.Bandwidth[0] / uint64(count)
sum.Bandwidth[1] = sum.Bandwidth[1] / uint64(count)
sum.Battery[0] = uint8(batterySum / int(count))
// Compute averages
sum.Cpu = twoDecimals(sum.Cpu / count)
sum.Mem = twoDecimals(sum.Mem / count)
sum.MemUsed = twoDecimals(sum.MemUsed / count)
sum.MemPct = twoDecimals(sum.MemPct / count)
sum.MemBuffCache = twoDecimals(sum.MemBuffCache / count)
sum.MemZfsArc = twoDecimals(sum.MemZfsArc / count)
sum.Swap = twoDecimals(sum.Swap / count)
sum.SwapUsed = twoDecimals(sum.SwapUsed / count)
sum.DiskTotal = twoDecimals(sum.DiskTotal / count)
sum.DiskUsed = twoDecimals(sum.DiskUsed / count)
sum.DiskPct = twoDecimals(sum.DiskPct / count)
sum.DiskReadPs = twoDecimals(sum.DiskReadPs / count)
sum.DiskWritePs = twoDecimals(sum.DiskWritePs / count)
sum.DiskIO[0] = sum.DiskIO[0] / uint64(count)
sum.DiskIO[1] = sum.DiskIO[1] / uint64(count)
for i := range sum.DiskIoStats {
sum.DiskIoStats[i] = twoDecimals(sum.DiskIoStats[i] / count)
}
sum.NetworkSent = twoDecimals(sum.NetworkSent / count)
sum.NetworkRecv = twoDecimals(sum.NetworkRecv / count)
sum.LoadAvg[0] = twoDecimals(sum.LoadAvg[0] / count)
sum.LoadAvg[1] = twoDecimals(sum.LoadAvg[1] / count)
sum.LoadAvg[2] = twoDecimals(sum.LoadAvg[2] / count)
sum.Bandwidth[0] = sum.Bandwidth[0] / uint64(count)
sum.Bandwidth[1] = sum.Bandwidth[1] / uint64(count)
sum.Battery[0] = uint8(batterySum / int(count))
// Average network interfaces
if sum.NetworkInterfaces != nil {
for key := range sum.NetworkInterfaces {
sum.NetworkInterfaces[key] = [4]uint64{
sum.NetworkInterfaces[key][0] / uint64(count),
sum.NetworkInterfaces[key][1] / uint64(count),
sum.NetworkInterfaces[key][2],
sum.NetworkInterfaces[key][3],
// Average network interfaces
if sum.NetworkInterfaces != nil {
for key := range sum.NetworkInterfaces {
sum.NetworkInterfaces[key] = [4]uint64{
sum.NetworkInterfaces[key][0] / uint64(count),
sum.NetworkInterfaces[key][1] / uint64(count),
sum.NetworkInterfaces[key][2],
sum.NetworkInterfaces[key][3],
}
}
}
// Average temperatures
if sum.Temperatures != nil && tempCount > 0 {
for key := range sum.Temperatures {
sum.Temperatures[key] = twoDecimals(sum.Temperatures[key] / tempCount)
}
}
// Average extra filesystem stats
if sum.ExtraFs != nil {
for key := range sum.ExtraFs {
fs := sum.ExtraFs[key]
fs.DiskTotal = twoDecimals(fs.DiskTotal / count)
fs.DiskUsed = twoDecimals(fs.DiskUsed / count)
fs.DiskWritePs = twoDecimals(fs.DiskWritePs / count)
fs.DiskReadPs = twoDecimals(fs.DiskReadPs / count)
fs.DiskReadBytes = fs.DiskReadBytes / uint64(count)
fs.DiskWriteBytes = fs.DiskWriteBytes / uint64(count)
for i := range fs.DiskIoStats {
fs.DiskIoStats[i] = twoDecimals(fs.DiskIoStats[i] / count)
}
}
}
// Average GPU data
if sum.GPUData != nil {
for id := range sum.GPUData {
gpu := sum.GPUData[id]
gpu.Temperature = twoDecimals(gpu.Temperature / count)
gpu.MemoryUsed = twoDecimals(gpu.MemoryUsed / count)
gpu.MemoryTotal = twoDecimals(gpu.MemoryTotal / count)
gpu.Usage = twoDecimals(gpu.Usage / count)
gpu.Power = twoDecimals(gpu.Power / count)
gpu.Count = twoDecimals(gpu.Count / count)
if gpu.Engines != nil {
for engineKey := range gpu.Engines {
gpu.Engines[engineKey] = twoDecimals(gpu.Engines[engineKey] / count)
}
}
sum.GPUData[id] = gpu
}
}
// Average temperatures
if sum.Temperatures != nil && tempCount > 0 {
for key := range sum.Temperatures {
sum.Temperatures[key] = twoDecimals(sum.Temperatures[key] / tempCount)
}
// Average per-core usage
if len(cpuCoresSums) > 0 {
avg := make(system.Uint8Slice, len(cpuCoresSums))
for i := range cpuCoresSums {
v := math.Round(float64(cpuCoresSums[i]) / count)
avg[i] = uint8(v)
}
sum.CpuCoresUsage = avg
}
// Average extra filesystem stats
if sum.ExtraFs != nil {
for key := range sum.ExtraFs {
fs := sum.ExtraFs[key]
fs.DiskTotal = twoDecimals(fs.DiskTotal / count)
fs.DiskUsed = twoDecimals(fs.DiskUsed / count)
fs.DiskWritePs = twoDecimals(fs.DiskWritePs / count)
fs.DiskReadPs = twoDecimals(fs.DiskReadPs / count)
fs.DiskReadBytes = fs.DiskReadBytes / uint64(count)
fs.DiskWriteBytes = fs.DiskWriteBytes / uint64(count)
for i := range fs.DiskIoStats {
fs.DiskIoStats[i] = twoDecimals(fs.DiskIoStats[i] / count)
}
}
}
// Average GPU data
if sum.GPUData != nil {
for id := range sum.GPUData {
gpu := sum.GPUData[id]
gpu.Temperature = twoDecimals(gpu.Temperature / count)
gpu.MemoryUsed = twoDecimals(gpu.MemoryUsed / count)
gpu.MemoryTotal = twoDecimals(gpu.MemoryTotal / count)
gpu.Usage = twoDecimals(gpu.Usage / count)
gpu.Power = twoDecimals(gpu.Power / count)
gpu.Count = twoDecimals(gpu.Count / count)
if gpu.Engines != nil {
for engineKey := range gpu.Engines {
gpu.Engines[engineKey] = twoDecimals(gpu.Engines[engineKey] / count)
}
}
sum.GPUData[id] = gpu
}
}
// Average per-core usage
if len(cpuCoresSums) > 0 {
avg := make(system.Uint8Slice, len(cpuCoresSums))
for i := range cpuCoresSums {
v := math.Round(float64(cpuCoresSums[i]) / count)
avg[i] = uint8(v)
}
sum.CpuCoresUsage = avg
}
// Average CPU breakdown
if len(cpuBreakdownSums) > 0 {
avg := make([]float64, len(cpuBreakdownSums))
for i := range cpuBreakdownSums {
avg[i] = twoDecimals(cpuBreakdownSums[i] / count)
}
sum.CpuBreakdown = avg
// Average CPU breakdown
if len(cpuBreakdownSums) > 0 {
avg := make([]float64, len(cpuBreakdownSums))
for i := range cpuBreakdownSums {
avg[i] = twoDecimals(cpuBreakdownSums[i] / count)
}
sum.CpuBreakdown = avg
}
return sum
@@ -453,29 +445,33 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *
// Calculate the average stats of a list of container_stats records
func (rm *RecordManager) AverageContainerStats(db dbx.Builder, records RecordIds) []container.Stats {
// Clear global map for reuse
for k := range containerSums {
delete(containerSums, k)
}
sums := containerSums
count := float64(len(records))
for i := range records {
id := records[i].Id
// clear global statsRecord for reuse
statsRecord.Stats = statsRecord.Stats[:0]
// must set to nil (not [:0]) to avoid json.Unmarshal reusing backing array
// which causes omitzero fields to inherit stale values from previous iterations
containerStats = nil
queryParams["id"] = id
db.NewQuery("SELECT stats FROM container_stats WHERE id = {:id}").Bind(queryParams).One(&statsRecord)
if err := json.Unmarshal(statsRecord.Stats, &containerStats); err != nil {
allStats := make([][]container.Stats, 0, len(records))
var row StatsRecord
params := make(dbx.Params, 1)
for _, rec := range records {
row.Stats = row.Stats[:0]
params["id"] = rec.Id
db.NewQuery("SELECT stats FROM container_stats WHERE id = {:id}").Bind(params).One(&row)
var cs []container.Stats
if err := json.Unmarshal(row.Stats, &cs); err != nil {
return []container.Stats{}
}
allStats = append(allStats, cs)
}
return AverageContainerStatsSlice(allStats)
}
// AverageContainerStatsSlice computes the average of container stats across multiple time periods.
func AverageContainerStatsSlice(records [][]container.Stats) []container.Stats {
if len(records) == 0 {
return []container.Stats{}
}
sums := make(map[string]*container.Stats)
count := float64(len(records))
for _, containerStats := range records {
for i := range containerStats {
stat := containerStats[i]
stat := &containerStats[i]
if _, ok := sums[stat.Name]; !ok {
sums[stat.Name] = &container.Stats{Name: stat.Name}
}
@@ -504,133 +500,6 @@ func (rm *RecordManager) AverageContainerStats(db dbx.Builder, records RecordIds
return result
}
// Delete old records
func (rm *RecordManager) DeleteOldRecords() {
rm.app.RunInTransaction(func(txApp core.App) error {
err := deleteOldSystemStats(txApp)
if err != nil {
return err
}
err = deleteOldContainerRecords(txApp)
if err != nil {
return err
}
err = deleteOldSystemdServiceRecords(txApp)
if err != nil {
return err
}
err = deleteOldAlertsHistory(txApp, 200, 250)
if err != nil {
return err
}
err = deleteOldQuietHours(txApp)
if err != nil {
return err
}
return nil
})
}
// Delete old alerts history records
func deleteOldAlertsHistory(app core.App, countToKeep, countBeforeDeletion int) error {
db := app.DB()
var users []struct {
Id string `db:"user"`
}
err := db.NewQuery("SELECT user, COUNT(*) as count FROM alerts_history GROUP BY user HAVING count > {:countBeforeDeletion}").Bind(dbx.Params{"countBeforeDeletion": countBeforeDeletion}).All(&users)
if err != nil {
return err
}
for _, user := range users {
_, err = db.NewQuery("DELETE FROM alerts_history WHERE user = {:user} AND id NOT IN (SELECT id FROM alerts_history WHERE user = {:user} ORDER BY created DESC LIMIT {:countToKeep})").Bind(dbx.Params{"user": user.Id, "countToKeep": countToKeep}).Execute()
if err != nil {
return err
}
}
return nil
}
// Deletes system_stats records older than what is displayed in the UI
func deleteOldSystemStats(app core.App) error {
// Collections to process
collections := [2]string{"system_stats", "container_stats"}
// Record types and their retention periods
type RecordDeletionData struct {
recordType string
retention time.Duration
}
recordData := []RecordDeletionData{
{recordType: "1m", retention: time.Hour}, // 1 hour
{recordType: "10m", retention: 12 * time.Hour}, // 12 hours
{recordType: "20m", retention: 24 * time.Hour}, // 1 day
{recordType: "120m", retention: 7 * 24 * time.Hour}, // 7 days
{recordType: "480m", retention: 30 * 24 * time.Hour}, // 30 days
}
now := time.Now().UTC()
for _, collection := range collections {
// Build the WHERE clause
var conditionParts []string
var params dbx.Params = make(map[string]any)
for i := range recordData {
rd := recordData[i]
// Create parameterized condition for this record type
dateParam := fmt.Sprintf("date%d", i)
conditionParts = append(conditionParts, fmt.Sprintf("(type = '%s' AND created < {:%s})", rd.recordType, dateParam))
params[dateParam] = now.Add(-rd.retention)
}
// Combine conditions with OR
conditionStr := strings.Join(conditionParts, " OR ")
// Construct and execute the full raw query
rawQuery := fmt.Sprintf("DELETE FROM %s WHERE %s", collection, conditionStr)
if _, err := app.DB().NewQuery(rawQuery).Bind(params).Execute(); err != nil {
return fmt.Errorf("failed to delete from %s: %v", collection, err)
}
}
return nil
}
// Deletes systemd service records that haven't been updated in the last 20 minutes
func deleteOldSystemdServiceRecords(app core.App) error {
now := time.Now().UTC()
twentyMinutesAgo := now.Add(-20 * time.Minute)
// Delete systemd service records where updated < twentyMinutesAgo
_, err := app.DB().NewQuery("DELETE FROM systemd_services WHERE updated < {:updated}").Bind(dbx.Params{"updated": twentyMinutesAgo.UnixMilli()}).Execute()
if err != nil {
return fmt.Errorf("failed to delete old systemd service records: %v", err)
}
return nil
}
// Deletes container records that haven't been updated in the last 10 minutes
func deleteOldContainerRecords(app core.App) error {
now := time.Now().UTC()
tenMinutesAgo := now.Add(-10 * time.Minute)
// Delete container records where updated < tenMinutesAgo
_, err := app.DB().NewQuery("DELETE FROM containers WHERE updated < {:updated}").Bind(dbx.Params{"updated": tenMinutesAgo.UnixMilli()}).Execute()
if err != nil {
return fmt.Errorf("failed to delete old container records: %v", err)
}
return nil
}
// Deletes old quiet hours records where end date has passed
func deleteOldQuietHours(app core.App) error {
now := time.Now().UTC()
_, err := app.DB().NewQuery("DELETE FROM quiet_hours WHERE type = 'one-time' AND end < {:now}").Bind(dbx.Params{"now": now}).Execute()
if err != nil {
return err
}
return nil
}
/* Round float to two decimals */
func twoDecimals(value float64) float64 {
return math.Round(value*100) / 100

View File

@@ -0,0 +1,820 @@
//go:build testing
package records_test
import (
"sort"
"testing"
"github.com/henrygd/beszel/internal/entities/container"
"github.com/henrygd/beszel/internal/entities/system"
"github.com/henrygd/beszel/internal/records"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAverageSystemStatsSlice_Empty(t *testing.T) {
result := records.AverageSystemStatsSlice(nil)
assert.Equal(t, system.Stats{}, result)
result = records.AverageSystemStatsSlice([]system.Stats{})
assert.Equal(t, system.Stats{}, result)
}
func TestAverageSystemStatsSlice_SingleRecord(t *testing.T) {
input := []system.Stats{
{
Cpu: 45.67,
Mem: 16.0,
MemUsed: 8.5,
MemPct: 53.12,
MemBuffCache: 2.0,
Swap: 4.0,
SwapUsed: 1.0,
DiskTotal: 500.0,
DiskUsed: 250.0,
DiskPct: 50.0,
DiskReadPs: 100.5,
DiskWritePs: 200.75,
NetworkSent: 10.5,
NetworkRecv: 20.25,
LoadAvg: [3]float64{1.5, 2.0, 3.5},
Bandwidth: [2]uint64{1000, 2000},
DiskIO: [2]uint64{500, 600},
Battery: [2]uint8{80, 1},
},
}
result := records.AverageSystemStatsSlice(input)
assert.Equal(t, 45.67, result.Cpu)
assert.Equal(t, 16.0, result.Mem)
assert.Equal(t, 8.5, result.MemUsed)
assert.Equal(t, 53.12, result.MemPct)
assert.Equal(t, 2.0, result.MemBuffCache)
assert.Equal(t, 4.0, result.Swap)
assert.Equal(t, 1.0, result.SwapUsed)
assert.Equal(t, 500.0, result.DiskTotal)
assert.Equal(t, 250.0, result.DiskUsed)
assert.Equal(t, 50.0, result.DiskPct)
assert.Equal(t, 100.5, result.DiskReadPs)
assert.Equal(t, 200.75, result.DiskWritePs)
assert.Equal(t, 10.5, result.NetworkSent)
assert.Equal(t, 20.25, result.NetworkRecv)
assert.Equal(t, [3]float64{1.5, 2.0, 3.5}, result.LoadAvg)
assert.Equal(t, [2]uint64{1000, 2000}, result.Bandwidth)
assert.Equal(t, [2]uint64{500, 600}, result.DiskIO)
assert.Equal(t, uint8(80), result.Battery[0])
assert.Equal(t, uint8(1), result.Battery[1])
}
func TestAverageSystemStatsSlice_BasicAveraging(t *testing.T) {
input := []system.Stats{
{
Cpu: 20.0,
Mem: 16.0,
MemUsed: 6.0,
MemPct: 37.5,
MemBuffCache: 1.0,
MemZfsArc: 0.5,
Swap: 4.0,
SwapUsed: 1.0,
DiskTotal: 500.0,
DiskUsed: 200.0,
DiskPct: 40.0,
DiskReadPs: 100.0,
DiskWritePs: 200.0,
NetworkSent: 10.0,
NetworkRecv: 20.0,
LoadAvg: [3]float64{1.0, 2.0, 3.0},
Bandwidth: [2]uint64{1000, 2000},
DiskIO: [2]uint64{400, 600},
Battery: [2]uint8{80, 1},
},
{
Cpu: 40.0,
Mem: 16.0,
MemUsed: 10.0,
MemPct: 62.5,
MemBuffCache: 3.0,
MemZfsArc: 1.5,
Swap: 4.0,
SwapUsed: 3.0,
DiskTotal: 500.0,
DiskUsed: 300.0,
DiskPct: 60.0,
DiskReadPs: 200.0,
DiskWritePs: 400.0,
NetworkSent: 30.0,
NetworkRecv: 40.0,
LoadAvg: [3]float64{3.0, 4.0, 5.0},
Bandwidth: [2]uint64{3000, 4000},
DiskIO: [2]uint64{600, 800},
Battery: [2]uint8{60, 1},
},
}
result := records.AverageSystemStatsSlice(input)
assert.Equal(t, 30.0, result.Cpu)
assert.Equal(t, 16.0, result.Mem)
assert.Equal(t, 8.0, result.MemUsed)
assert.Equal(t, 50.0, result.MemPct)
assert.Equal(t, 2.0, result.MemBuffCache)
assert.Equal(t, 1.0, result.MemZfsArc)
assert.Equal(t, 4.0, result.Swap)
assert.Equal(t, 2.0, result.SwapUsed)
assert.Equal(t, 500.0, result.DiskTotal)
assert.Equal(t, 250.0, result.DiskUsed)
assert.Equal(t, 50.0, result.DiskPct)
assert.Equal(t, 150.0, result.DiskReadPs)
assert.Equal(t, 300.0, result.DiskWritePs)
assert.Equal(t, 20.0, result.NetworkSent)
assert.Equal(t, 30.0, result.NetworkRecv)
assert.Equal(t, [3]float64{2.0, 3.0, 4.0}, result.LoadAvg)
assert.Equal(t, [2]uint64{2000, 3000}, result.Bandwidth)
assert.Equal(t, [2]uint64{500, 700}, result.DiskIO)
assert.Equal(t, uint8(70), result.Battery[0])
assert.Equal(t, uint8(1), result.Battery[1])
}
func TestAverageSystemStatsSlice_PeakValues(t *testing.T) {
input := []system.Stats{
{
Cpu: 20.0,
MaxCpu: 25.0,
MemUsed: 6.0,
MaxMem: 7.0,
NetworkSent: 10.0,
MaxNetworkSent: 15.0,
NetworkRecv: 20.0,
MaxNetworkRecv: 25.0,
DiskReadPs: 100.0,
MaxDiskReadPs: 120.0,
DiskWritePs: 200.0,
MaxDiskWritePs: 220.0,
Bandwidth: [2]uint64{1000, 2000},
MaxBandwidth: [2]uint64{1500, 2500},
DiskIO: [2]uint64{400, 600},
MaxDiskIO: [2]uint64{500, 700},
DiskIoStats: [6]float64{10.0, 20.0, 30.0, 5.0, 8.0, 12.0},
MaxDiskIoStats: [6]float64{15.0, 25.0, 35.0, 6.0, 9.0, 14.0},
},
{
Cpu: 40.0,
MaxCpu: 50.0,
MemUsed: 10.0,
MaxMem: 12.0,
NetworkSent: 30.0,
MaxNetworkSent: 35.0,
NetworkRecv: 40.0,
MaxNetworkRecv: 45.0,
DiskReadPs: 200.0,
MaxDiskReadPs: 210.0,
DiskWritePs: 400.0,
MaxDiskWritePs: 410.0,
Bandwidth: [2]uint64{3000, 4000},
MaxBandwidth: [2]uint64{3500, 4500},
DiskIO: [2]uint64{600, 800},
MaxDiskIO: [2]uint64{650, 850},
DiskIoStats: [6]float64{50.0, 60.0, 70.0, 15.0, 18.0, 22.0},
MaxDiskIoStats: [6]float64{55.0, 65.0, 75.0, 16.0, 19.0, 23.0},
},
}
result := records.AverageSystemStatsSlice(input)
assert.Equal(t, 50.0, result.MaxCpu)
assert.Equal(t, 12.0, result.MaxMem)
assert.Equal(t, 35.0, result.MaxNetworkSent)
assert.Equal(t, 45.0, result.MaxNetworkRecv)
assert.Equal(t, 210.0, result.MaxDiskReadPs)
assert.Equal(t, 410.0, result.MaxDiskWritePs)
assert.Equal(t, [2]uint64{3500, 4500}, result.MaxBandwidth)
assert.Equal(t, [2]uint64{650, 850}, result.MaxDiskIO)
assert.Equal(t, [6]float64{30.0, 40.0, 50.0, 10.0, 13.0, 17.0}, result.DiskIoStats)
assert.Equal(t, [6]float64{55.0, 65.0, 75.0, 16.0, 19.0, 23.0}, result.MaxDiskIoStats)
}
func TestAverageSystemStatsSlice_DiskIoStats(t *testing.T) {
input := []system.Stats{
{
Cpu: 10.0,
DiskIoStats: [6]float64{10.0, 20.0, 30.0, 5.0, 8.0, 12.0},
MaxDiskIoStats: [6]float64{12.0, 22.0, 32.0, 6.0, 9.0, 13.0},
},
{
Cpu: 20.0,
DiskIoStats: [6]float64{30.0, 40.0, 50.0, 15.0, 18.0, 22.0},
MaxDiskIoStats: [6]float64{28.0, 38.0, 48.0, 14.0, 17.0, 21.0},
},
{
Cpu: 30.0,
DiskIoStats: [6]float64{20.0, 30.0, 40.0, 10.0, 12.0, 16.0},
MaxDiskIoStats: [6]float64{25.0, 35.0, 45.0, 11.0, 13.0, 17.0},
},
}
result := records.AverageSystemStatsSlice(input)
// Average: (10+30+20)/3=20, (20+40+30)/3=30, (30+50+40)/3=40, (5+15+10)/3=10, (8+18+12)/3≈12.67, (12+22+16)/3≈16.67
assert.Equal(t, 20.0, result.DiskIoStats[0])
assert.Equal(t, 30.0, result.DiskIoStats[1])
assert.Equal(t, 40.0, result.DiskIoStats[2])
assert.Equal(t, 10.0, result.DiskIoStats[3])
assert.Equal(t, 12.67, result.DiskIoStats[4])
assert.Equal(t, 16.67, result.DiskIoStats[5])
// Max: current DiskIoStats[0] wins for record 2 (30 > MaxDiskIoStats 28)
assert.Equal(t, 30.0, result.MaxDiskIoStats[0])
assert.Equal(t, 40.0, result.MaxDiskIoStats[1])
assert.Equal(t, 50.0, result.MaxDiskIoStats[2])
assert.Equal(t, 15.0, result.MaxDiskIoStats[3])
assert.Equal(t, 18.0, result.MaxDiskIoStats[4])
assert.Equal(t, 22.0, result.MaxDiskIoStats[5])
}
// Tests that current DiskIoStats values are considered when computing MaxDiskIoStats.
func TestAverageSystemStatsSlice_DiskIoStatsPeakFromCurrentValues(t *testing.T) {
input := []system.Stats{
{Cpu: 10.0, DiskIoStats: [6]float64{95.0, 90.0, 85.0, 50.0, 60.0, 80.0}, MaxDiskIoStats: [6]float64{80.0, 80.0, 80.0, 40.0, 50.0, 70.0}},
{Cpu: 20.0, DiskIoStats: [6]float64{10.0, 10.0, 10.0, 5.0, 6.0, 8.0}, MaxDiskIoStats: [6]float64{20.0, 20.0, 20.0, 10.0, 12.0, 16.0}},
}
result := records.AverageSystemStatsSlice(input)
// Current value from first record (95, 90, 85, 50, 60, 80) beats MaxDiskIoStats in both records
assert.Equal(t, 95.0, result.MaxDiskIoStats[0])
assert.Equal(t, 90.0, result.MaxDiskIoStats[1])
assert.Equal(t, 85.0, result.MaxDiskIoStats[2])
assert.Equal(t, 50.0, result.MaxDiskIoStats[3])
assert.Equal(t, 60.0, result.MaxDiskIoStats[4])
assert.Equal(t, 80.0, result.MaxDiskIoStats[5])
}
// Tests that current values are considered when computing peaks
// (i.e., current cpu > MaxCpu should still win).
func TestAverageSystemStatsSlice_PeakFromCurrentValues(t *testing.T) {
input := []system.Stats{
{Cpu: 95.0, MaxCpu: 80.0, MemUsed: 15.0, MaxMem: 10.0},
{Cpu: 10.0, MaxCpu: 20.0, MemUsed: 5.0, MaxMem: 8.0},
}
result := records.AverageSystemStatsSlice(input)
assert.Equal(t, 95.0, result.MaxCpu)
assert.Equal(t, 15.0, result.MaxMem)
}
// Tests that records without temperature data are excluded from the temperature average.
func TestAverageSystemStatsSlice_Temperatures(t *testing.T) {
input := []system.Stats{
{
Cpu: 10.0,
Temperatures: map[string]float64{"cpu": 60.0, "gpu": 70.0},
},
{
Cpu: 20.0,
Temperatures: map[string]float64{"cpu": 80.0, "gpu": 90.0},
},
{
// No temperatures - should not affect temp averaging
Cpu: 30.0,
},
}
result := records.AverageSystemStatsSlice(input)
require.NotNil(t, result.Temperatures)
// Average over 2 records that had temps, not 3
assert.Equal(t, 70.0, result.Temperatures["cpu"])
assert.Equal(t, 80.0, result.Temperatures["gpu"])
}
func TestAverageSystemStatsSlice_NetworkInterfaces(t *testing.T) {
input := []system.Stats{
{
Cpu: 10.0,
NetworkInterfaces: map[string][4]uint64{
"eth0": {100, 200, 150, 250},
"eth1": {50, 60, 70, 80},
},
},
{
Cpu: 20.0,
NetworkInterfaces: map[string][4]uint64{
"eth0": {200, 400, 300, 500},
"eth1": {150, 160, 170, 180},
},
},
}
result := records.AverageSystemStatsSlice(input)
require.NotNil(t, result.NetworkInterfaces)
// [0] and [1] are averaged, [2] and [3] are max
assert.Equal(t, [4]uint64{150, 300, 300, 500}, result.NetworkInterfaces["eth0"])
assert.Equal(t, [4]uint64{100, 110, 170, 180}, result.NetworkInterfaces["eth1"])
}
func TestAverageSystemStatsSlice_ExtraFs(t *testing.T) {
input := []system.Stats{
{
Cpu: 10.0,
ExtraFs: map[string]*system.FsStats{
"/data": {
DiskTotal: 1000.0,
DiskUsed: 400.0,
DiskReadPs: 50.0,
DiskWritePs: 100.0,
MaxDiskReadPS: 60.0,
MaxDiskWritePS: 110.0,
DiskReadBytes: 5000,
DiskWriteBytes: 10000,
MaxDiskReadBytes: 6000,
MaxDiskWriteBytes: 11000,
DiskIoStats: [6]float64{10.0, 20.0, 30.0, 5.0, 8.0, 12.0},
MaxDiskIoStats: [6]float64{12.0, 22.0, 32.0, 6.0, 9.0, 13.0},
},
},
},
{
Cpu: 20.0,
ExtraFs: map[string]*system.FsStats{
"/data": {
DiskTotal: 1000.0,
DiskUsed: 600.0,
DiskReadPs: 150.0,
DiskWritePs: 200.0,
MaxDiskReadPS: 160.0,
MaxDiskWritePS: 210.0,
DiskReadBytes: 15000,
DiskWriteBytes: 20000,
MaxDiskReadBytes: 16000,
MaxDiskWriteBytes: 21000,
DiskIoStats: [6]float64{50.0, 60.0, 70.0, 15.0, 18.0, 22.0},
MaxDiskIoStats: [6]float64{55.0, 65.0, 75.0, 16.0, 19.0, 23.0},
},
},
},
}
result := records.AverageSystemStatsSlice(input)
require.NotNil(t, result.ExtraFs)
require.NotNil(t, result.ExtraFs["/data"])
fs := result.ExtraFs["/data"]
assert.Equal(t, 1000.0, fs.DiskTotal)
assert.Equal(t, 500.0, fs.DiskUsed)
assert.Equal(t, 100.0, fs.DiskReadPs)
assert.Equal(t, 150.0, fs.DiskWritePs)
assert.Equal(t, 160.0, fs.MaxDiskReadPS)
assert.Equal(t, 210.0, fs.MaxDiskWritePS)
assert.Equal(t, uint64(10000), fs.DiskReadBytes)
assert.Equal(t, uint64(15000), fs.DiskWriteBytes)
assert.Equal(t, uint64(16000), fs.MaxDiskReadBytes)
assert.Equal(t, uint64(21000), fs.MaxDiskWriteBytes)
assert.Equal(t, [6]float64{30.0, 40.0, 50.0, 10.0, 13.0, 17.0}, fs.DiskIoStats)
assert.Equal(t, [6]float64{55.0, 65.0, 75.0, 16.0, 19.0, 23.0}, fs.MaxDiskIoStats)
}
// Tests that ExtraFs DiskIoStats peak considers current values, not just previous peaks.
func TestAverageSystemStatsSlice_ExtraFsDiskIoStatsPeakFromCurrentValues(t *testing.T) {
input := []system.Stats{
{
Cpu: 10.0,
ExtraFs: map[string]*system.FsStats{
"/data": {
DiskIoStats: [6]float64{95.0, 90.0, 85.0, 50.0, 60.0, 80.0}, // exceeds MaxDiskIoStats
MaxDiskIoStats: [6]float64{80.0, 80.0, 80.0, 40.0, 50.0, 70.0},
},
},
},
{
Cpu: 20.0,
ExtraFs: map[string]*system.FsStats{
"/data": {
DiskIoStats: [6]float64{10.0, 10.0, 10.0, 5.0, 6.0, 8.0},
MaxDiskIoStats: [6]float64{20.0, 20.0, 20.0, 10.0, 12.0, 16.0},
},
},
},
}
result := records.AverageSystemStatsSlice(input)
fs := result.ExtraFs["/data"]
assert.Equal(t, 95.0, fs.MaxDiskIoStats[0])
assert.Equal(t, 90.0, fs.MaxDiskIoStats[1])
assert.Equal(t, 85.0, fs.MaxDiskIoStats[2])
assert.Equal(t, 50.0, fs.MaxDiskIoStats[3])
assert.Equal(t, 60.0, fs.MaxDiskIoStats[4])
assert.Equal(t, 80.0, fs.MaxDiskIoStats[5])
}
// Tests that extra FS peak values consider current values, not just previous peaks.
func TestAverageSystemStatsSlice_ExtraFsPeaksFromCurrentValues(t *testing.T) {
input := []system.Stats{
{
Cpu: 10.0,
ExtraFs: map[string]*system.FsStats{
"/data": {
DiskReadPs: 500.0, // exceeds MaxDiskReadPS
MaxDiskReadPS: 100.0,
DiskReadBytes: 50000,
MaxDiskReadBytes: 10000,
},
},
},
{
Cpu: 20.0,
ExtraFs: map[string]*system.FsStats{
"/data": {
DiskReadPs: 50.0,
MaxDiskReadPS: 200.0,
DiskReadBytes: 5000,
MaxDiskReadBytes: 20000,
},
},
},
}
result := records.AverageSystemStatsSlice(input)
fs := result.ExtraFs["/data"]
assert.Equal(t, 500.0, fs.MaxDiskReadPS)
assert.Equal(t, uint64(50000), fs.MaxDiskReadBytes)
}
func TestAverageSystemStatsSlice_GPUData(t *testing.T) {
input := []system.Stats{
{
Cpu: 10.0,
GPUData: map[string]system.GPUData{
"gpu0": {
Name: "RTX 4090",
Temperature: 60.0,
MemoryUsed: 4.0,
MemoryTotal: 24.0,
Usage: 30.0,
Power: 200.0,
Count: 1.0,
Engines: map[string]float64{
"3D": 50.0,
"Video": 10.0,
},
},
},
},
{
Cpu: 20.0,
GPUData: map[string]system.GPUData{
"gpu0": {
Name: "RTX 4090",
Temperature: 80.0,
MemoryUsed: 8.0,
MemoryTotal: 24.0,
Usage: 70.0,
Power: 300.0,
Count: 1.0,
Engines: map[string]float64{
"3D": 90.0,
"Video": 30.0,
},
},
},
},
}
result := records.AverageSystemStatsSlice(input)
require.NotNil(t, result.GPUData)
gpu := result.GPUData["gpu0"]
assert.Equal(t, "RTX 4090", gpu.Name)
assert.Equal(t, 70.0, gpu.Temperature)
assert.Equal(t, 6.0, gpu.MemoryUsed)
assert.Equal(t, 24.0, gpu.MemoryTotal)
assert.Equal(t, 50.0, gpu.Usage)
assert.Equal(t, 250.0, gpu.Power)
assert.Equal(t, 1.0, gpu.Count)
require.NotNil(t, gpu.Engines)
assert.Equal(t, 70.0, gpu.Engines["3D"])
assert.Equal(t, 20.0, gpu.Engines["Video"])
}
func TestAverageSystemStatsSlice_MultipleGPUs(t *testing.T) {
input := []system.Stats{
{
Cpu: 10.0,
GPUData: map[string]system.GPUData{
"gpu0": {Name: "GPU A", Usage: 20.0, Temperature: 50.0},
"gpu1": {Name: "GPU B", Usage: 60.0, Temperature: 70.0},
},
},
{
Cpu: 20.0,
GPUData: map[string]system.GPUData{
"gpu0": {Name: "GPU A", Usage: 40.0, Temperature: 60.0},
"gpu1": {Name: "GPU B", Usage: 80.0, Temperature: 80.0},
},
},
}
result := records.AverageSystemStatsSlice(input)
require.NotNil(t, result.GPUData)
assert.Equal(t, 30.0, result.GPUData["gpu0"].Usage)
assert.Equal(t, 55.0, result.GPUData["gpu0"].Temperature)
assert.Equal(t, 70.0, result.GPUData["gpu1"].Usage)
assert.Equal(t, 75.0, result.GPUData["gpu1"].Temperature)
}
func TestAverageSystemStatsSlice_CpuCoresUsage(t *testing.T) {
input := []system.Stats{
{Cpu: 10.0, CpuCoresUsage: system.Uint8Slice{10, 20, 30, 40}},
{Cpu: 20.0, CpuCoresUsage: system.Uint8Slice{30, 40, 50, 60}},
}
result := records.AverageSystemStatsSlice(input)
require.NotNil(t, result.CpuCoresUsage)
assert.Equal(t, system.Uint8Slice{20, 30, 40, 50}, result.CpuCoresUsage)
}
// Tests that per-core usage rounds correctly (e.g., 15.5 -> 16 via math.Round).
func TestAverageSystemStatsSlice_CpuCoresUsageRounding(t *testing.T) {
input := []system.Stats{
{Cpu: 10.0, CpuCoresUsage: system.Uint8Slice{11}},
{Cpu: 20.0, CpuCoresUsage: system.Uint8Slice{20}},
}
result := records.AverageSystemStatsSlice(input)
require.NotNil(t, result.CpuCoresUsage)
// (11+20)/2 = 15.5, rounds to 16
assert.Equal(t, uint8(16), result.CpuCoresUsage[0])
}
func TestAverageSystemStatsSlice_CpuBreakdown(t *testing.T) {
input := []system.Stats{
{Cpu: 10.0, CpuBreakdown: []float64{5.0, 3.0, 1.0, 0.5, 90.5}},
{Cpu: 20.0, CpuBreakdown: []float64{15.0, 7.0, 3.0, 1.5, 73.5}},
}
result := records.AverageSystemStatsSlice(input)
require.NotNil(t, result.CpuBreakdown)
assert.Equal(t, []float64{10.0, 5.0, 2.0, 1.0, 82.0}, result.CpuBreakdown)
}
// Tests that Battery[1] (charge state) uses the last record's value.
func TestAverageSystemStatsSlice_BatteryLastChargeState(t *testing.T) {
input := []system.Stats{
{Cpu: 10.0, Battery: [2]uint8{100, 1}}, // charging
{Cpu: 20.0, Battery: [2]uint8{90, 0}}, // not charging
}
result := records.AverageSystemStatsSlice(input)
assert.Equal(t, uint8(95), result.Battery[0])
assert.Equal(t, uint8(0), result.Battery[1]) // last record's charge state
}
func TestAverageSystemStatsSlice_ThreeRecordsRounding(t *testing.T) {
input := []system.Stats{
{Cpu: 10.0, Mem: 8.0},
{Cpu: 20.0, Mem: 8.0},
{Cpu: 30.0, Mem: 8.0},
}
result := records.AverageSystemStatsSlice(input)
assert.Equal(t, 20.0, result.Cpu)
assert.Equal(t, 8.0, result.Mem)
}
// Tests records where some have optional fields and others don't.
func TestAverageSystemStatsSlice_MixedOptionalFields(t *testing.T) {
input := []system.Stats{
{
Cpu: 10.0,
CpuCoresUsage: system.Uint8Slice{50, 60},
CpuBreakdown: []float64{5.0, 3.0, 1.0, 0.5, 90.5},
GPUData: map[string]system.GPUData{
"gpu0": {Name: "GPU", Usage: 40.0},
},
},
{
Cpu: 20.0,
// No CpuCoresUsage, CpuBreakdown, or GPUData
},
}
result := records.AverageSystemStatsSlice(input)
assert.Equal(t, 15.0, result.Cpu)
// CpuCoresUsage: only 1 record had it, so sum/2
require.NotNil(t, result.CpuCoresUsage)
assert.Equal(t, uint8(25), result.CpuCoresUsage[0])
assert.Equal(t, uint8(30), result.CpuCoresUsage[1])
// CpuBreakdown: only 1 record had it, so sum/2
require.NotNil(t, result.CpuBreakdown)
assert.Equal(t, 2.5, result.CpuBreakdown[0])
// GPUData: only 1 record had it, so sum/2
require.NotNil(t, result.GPUData)
assert.Equal(t, 20.0, result.GPUData["gpu0"].Usage)
}
// Tests with 10 records matching the common real-world case (10 x 1m -> 1 x 10m).
func TestAverageSystemStatsSlice_TenRecords(t *testing.T) {
input := make([]system.Stats, 10)
for i := range input {
input[i] = system.Stats{
Cpu: float64(i * 10), // 0, 10, 20, ..., 90
Mem: 16.0,
MemUsed: float64(4 + i), // 4, 5, 6, ..., 13
MemPct: float64(25 + i), // 25, 26, ..., 34
DiskTotal: 500.0,
DiskUsed: 250.0,
DiskPct: 50.0,
NetworkSent: float64(i),
NetworkRecv: float64(i * 2),
Bandwidth: [2]uint64{uint64(i * 1000), uint64(i * 2000)},
LoadAvg: [3]float64{float64(i), float64(i) * 0.5, float64(i) * 0.25},
}
}
result := records.AverageSystemStatsSlice(input)
assert.Equal(t, 45.0, result.Cpu) // avg of 0..90
assert.Equal(t, 16.0, result.Mem) // constant
assert.Equal(t, 8.5, result.MemUsed) // avg of 4..13
assert.Equal(t, 29.5, result.MemPct) // avg of 25..34
assert.Equal(t, 500.0, result.DiskTotal)
assert.Equal(t, 250.0, result.DiskUsed)
assert.Equal(t, 50.0, result.DiskPct)
assert.Equal(t, 4.5, result.NetworkSent)
assert.Equal(t, 9.0, result.NetworkRecv)
assert.Equal(t, [2]uint64{4500, 9000}, result.Bandwidth)
}
// --- Container Stats Tests ---
func TestAverageContainerStatsSlice_Empty(t *testing.T) {
result := records.AverageContainerStatsSlice(nil)
assert.Equal(t, []container.Stats{}, result)
result = records.AverageContainerStatsSlice([][]container.Stats{})
assert.Equal(t, []container.Stats{}, result)
}
func TestAverageContainerStatsSlice_SingleRecord(t *testing.T) {
input := [][]container.Stats{
{
{Name: "nginx", Cpu: 5.0, Mem: 128.0, Bandwidth: [2]uint64{1000, 2000}},
},
}
result := records.AverageContainerStatsSlice(input)
require.Len(t, result, 1)
assert.Equal(t, "nginx", result[0].Name)
assert.Equal(t, 5.0, result[0].Cpu)
assert.Equal(t, 128.0, result[0].Mem)
assert.Equal(t, [2]uint64{1000, 2000}, result[0].Bandwidth)
}
func TestAverageContainerStatsSlice_BasicAveraging(t *testing.T) {
input := [][]container.Stats{
{
{Name: "nginx", Cpu: 10.0, Mem: 100.0, Bandwidth: [2]uint64{1000, 2000}},
{Name: "redis", Cpu: 5.0, Mem: 64.0, Bandwidth: [2]uint64{500, 1000}},
},
{
{Name: "nginx", Cpu: 20.0, Mem: 200.0, Bandwidth: [2]uint64{3000, 4000}},
{Name: "redis", Cpu: 15.0, Mem: 128.0, Bandwidth: [2]uint64{1500, 2000}},
},
}
result := records.AverageContainerStatsSlice(input)
sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name })
require.Len(t, result, 2)
assert.Equal(t, "nginx", result[0].Name)
assert.Equal(t, 15.0, result[0].Cpu)
assert.Equal(t, 150.0, result[0].Mem)
assert.Equal(t, [2]uint64{2000, 3000}, result[0].Bandwidth)
assert.Equal(t, "redis", result[1].Name)
assert.Equal(t, 10.0, result[1].Cpu)
assert.Equal(t, 96.0, result[1].Mem)
assert.Equal(t, [2]uint64{1000, 1500}, result[1].Bandwidth)
}
// Tests containers that appear in some records but not all.
func TestAverageContainerStatsSlice_ContainerAppearsInSomeRecords(t *testing.T) {
input := [][]container.Stats{
{
{Name: "nginx", Cpu: 10.0, Mem: 100.0},
{Name: "redis", Cpu: 5.0, Mem: 64.0},
},
{
{Name: "nginx", Cpu: 20.0, Mem: 200.0},
// redis not present
},
}
result := records.AverageContainerStatsSlice(input)
sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name })
require.Len(t, result, 2)
assert.Equal(t, "nginx", result[0].Name)
assert.Equal(t, 15.0, result[0].Cpu)
assert.Equal(t, 150.0, result[0].Mem)
// redis: sum / count where count = total records (2), not records containing redis
assert.Equal(t, "redis", result[1].Name)
assert.Equal(t, 2.5, result[1].Cpu)
assert.Equal(t, 32.0, result[1].Mem)
}
// Tests backward compatibility with deprecated NetworkSent/NetworkRecv (MB) when Bandwidth is zero.
func TestAverageContainerStatsSlice_DeprecatedNetworkFields(t *testing.T) {
input := [][]container.Stats{
{
{Name: "nginx", Cpu: 10.0, Mem: 100.0, NetworkSent: 1.0, NetworkRecv: 2.0}, // 1 MB, 2 MB
},
{
{Name: "nginx", Cpu: 20.0, Mem: 200.0, NetworkSent: 3.0, NetworkRecv: 4.0}, // 3 MB, 4 MB
},
}
result := records.AverageContainerStatsSlice(input)
require.Len(t, result, 1)
assert.Equal(t, "nginx", result[0].Name)
// avg sent = (1*1048576 + 3*1048576) / 2 = 2*1048576
assert.Equal(t, uint64(2*1048576), result[0].Bandwidth[0])
// avg recv = (2*1048576 + 4*1048576) / 2 = 3*1048576
assert.Equal(t, uint64(3*1048576), result[0].Bandwidth[1])
}
// Tests that when Bandwidth is set, deprecated NetworkSent/NetworkRecv are ignored.
func TestAverageContainerStatsSlice_MixedBandwidthAndDeprecated(t *testing.T) {
input := [][]container.Stats{
{
{Name: "nginx", Cpu: 10.0, Mem: 100.0, Bandwidth: [2]uint64{5000, 6000}, NetworkSent: 99.0, NetworkRecv: 99.0},
},
{
{Name: "nginx", Cpu: 20.0, Mem: 200.0, Bandwidth: [2]uint64{7000, 8000}},
},
}
result := records.AverageContainerStatsSlice(input)
require.Len(t, result, 1)
assert.Equal(t, uint64(6000), result[0].Bandwidth[0])
assert.Equal(t, uint64(7000), result[0].Bandwidth[1])
}
func TestAverageContainerStatsSlice_ThreeRecords(t *testing.T) {
input := [][]container.Stats{
{{Name: "app", Cpu: 1.0, Mem: 100.0}},
{{Name: "app", Cpu: 2.0, Mem: 200.0}},
{{Name: "app", Cpu: 3.0, Mem: 300.0}},
}
result := records.AverageContainerStatsSlice(input)
require.Len(t, result, 1)
assert.Equal(t, 2.0, result[0].Cpu)
assert.Equal(t, 200.0, result[0].Mem)
}
func TestAverageContainerStatsSlice_ManyContainers(t *testing.T) {
input := [][]container.Stats{
{
{Name: "a", Cpu: 10.0, Mem: 100.0},
{Name: "b", Cpu: 20.0, Mem: 200.0},
{Name: "c", Cpu: 30.0, Mem: 300.0},
{Name: "d", Cpu: 40.0, Mem: 400.0},
},
{
{Name: "a", Cpu: 20.0, Mem: 200.0},
{Name: "b", Cpu: 30.0, Mem: 300.0},
{Name: "c", Cpu: 40.0, Mem: 400.0},
{Name: "d", Cpu: 50.0, Mem: 500.0},
},
}
result := records.AverageContainerStatsSlice(input)
sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name })
require.Len(t, result, 4)
assert.Equal(t, 15.0, result[0].Cpu)
assert.Equal(t, 25.0, result[1].Cpu)
assert.Equal(t, 35.0, result[2].Cpu)
assert.Equal(t, 45.0, result[3].Cpu)
}

View File

@@ -0,0 +1,138 @@
package records
import (
"fmt"
"log/slog"
"strings"
"time"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
)
// Delete old records
func (rm *RecordManager) DeleteOldRecords() {
rm.app.RunInTransaction(func(txApp core.App) error {
err := deleteOldSystemStats(txApp)
if err != nil {
slog.Error("Error deleting old system stats", "err", err)
}
err = deleteOldContainerRecords(txApp)
if err != nil {
slog.Error("Error deleting old container records", "err", err)
}
err = deleteOldSystemdServiceRecords(txApp)
if err != nil {
slog.Error("Error deleting old systemd service records", "err", err)
}
err = deleteOldAlertsHistory(txApp, 200, 250)
if err != nil {
slog.Error("Error deleting old alerts history", "err", err)
}
err = deleteOldQuietHours(txApp)
if err != nil {
slog.Error("Error deleting old quiet hours", "err", err)
}
return nil
})
}
// Delete old alerts history records
func deleteOldAlertsHistory(app core.App, countToKeep, countBeforeDeletion int) error {
db := app.DB()
var users []struct {
Id string `db:"user"`
}
err := db.NewQuery("SELECT user, COUNT(*) as count FROM alerts_history GROUP BY user HAVING count > {:countBeforeDeletion}").Bind(dbx.Params{"countBeforeDeletion": countBeforeDeletion}).All(&users)
if err != nil {
return err
}
for _, user := range users {
_, err = db.NewQuery("DELETE FROM alerts_history WHERE user = {:user} AND id NOT IN (SELECT id FROM alerts_history WHERE user = {:user} ORDER BY created DESC LIMIT {:countToKeep})").Bind(dbx.Params{"user": user.Id, "countToKeep": countToKeep}).Execute()
if err != nil {
return err
}
}
return nil
}
// Deletes system_stats records older than what is displayed in the UI
func deleteOldSystemStats(app core.App) error {
// Collections to process
collections := [2]string{"system_stats", "container_stats"}
// Record types and their retention periods
type RecordDeletionData struct {
recordType string
retention time.Duration
}
recordData := []RecordDeletionData{
{recordType: "1m", retention: time.Hour}, // 1 hour
{recordType: "10m", retention: 12 * time.Hour}, // 12 hours
{recordType: "20m", retention: 24 * time.Hour}, // 1 day
{recordType: "120m", retention: 7 * 24 * time.Hour}, // 7 days
{recordType: "480m", retention: 30 * 24 * time.Hour}, // 30 days
}
now := time.Now().UTC()
for _, collection := range collections {
// Build the WHERE clause
var conditionParts []string
var params dbx.Params = make(map[string]any)
for i := range recordData {
rd := recordData[i]
// Create parameterized condition for this record type
dateParam := fmt.Sprintf("date%d", i)
conditionParts = append(conditionParts, fmt.Sprintf("(type = '%s' AND created < {:%s})", rd.recordType, dateParam))
params[dateParam] = now.Add(-rd.retention)
}
// Combine conditions with OR
conditionStr := strings.Join(conditionParts, " OR ")
// Construct and execute the full raw query
rawQuery := fmt.Sprintf("DELETE FROM %s WHERE %s", collection, conditionStr)
if _, err := app.DB().NewQuery(rawQuery).Bind(params).Execute(); err != nil {
return fmt.Errorf("failed to delete from %s: %v", collection, err)
}
}
return nil
}
// Deletes systemd service records that haven't been updated in the last 20 minutes
func deleteOldSystemdServiceRecords(app core.App) error {
now := time.Now().UTC()
twentyMinutesAgo := now.Add(-20 * time.Minute)
// Delete systemd service records where updated < twentyMinutesAgo
_, err := app.DB().NewQuery("DELETE FROM systemd_services WHERE updated < {:updated}").Bind(dbx.Params{"updated": twentyMinutesAgo.UnixMilli()}).Execute()
if err != nil {
return fmt.Errorf("failed to delete old systemd service records: %v", err)
}
return nil
}
// Deletes container records that haven't been updated in the last 10 minutes
func deleteOldContainerRecords(app core.App) error {
now := time.Now().UTC()
tenMinutesAgo := now.Add(-10 * time.Minute)
// Delete container records where updated < tenMinutesAgo
_, err := app.DB().NewQuery("DELETE FROM containers WHERE updated < {:updated}").Bind(dbx.Params{"updated": tenMinutesAgo.UnixMilli()}).Execute()
if err != nil {
return fmt.Errorf("failed to delete old container records: %v", err)
}
return nil
}
// Deletes old quiet hours records where end date has passed
func deleteOldQuietHours(app core.App) error {
now := time.Now().UTC()
_, err := app.DB().NewQuery("DELETE FROM quiet_hours WHERE type = 'one-time' AND end < {:now}").Bind(dbx.Params{"now": now}).Execute()
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,428 @@
//go:build testing
package records_test
import (
"fmt"
"testing"
"time"
"github.com/henrygd/beszel/internal/records"
"github.com/henrygd/beszel/internal/tests"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestDeleteOldRecords tests the main DeleteOldRecords function
func TestDeleteOldRecords(t *testing.T) {
hub, err := tests.NewTestHub(t.TempDir())
require.NoError(t, err)
defer hub.Cleanup()
rm := records.NewRecordManager(hub)
// Create test user for alerts history
user, err := tests.CreateUser(hub, "test@example.com", "testtesttest")
require.NoError(t, err)
// Create test system
system, err := tests.CreateRecord(hub, "systems", map[string]any{
"name": "test-system",
"host": "localhost",
"port": "45876",
"status": "up",
"users": []string{user.Id},
})
require.NoError(t, err)
now := time.Now()
// Create old system_stats records that should be deleted
var record *core.Record
record, err = tests.CreateRecord(hub, "system_stats", map[string]any{
"system": system.Id,
"type": "1m",
"stats": `{"cpu": 50.0, "mem": 1024}`,
})
require.NoError(t, err)
// created is autodate field, so we need to set it manually
record.SetRaw("created", now.UTC().Add(-2*time.Hour).Format(types.DefaultDateLayout))
err = hub.SaveNoValidate(record)
require.NoError(t, err)
require.NotNil(t, record)
require.InDelta(t, record.GetDateTime("created").Time().UTC().Unix(), now.UTC().Add(-2*time.Hour).Unix(), 1)
require.Equal(t, record.Get("system"), system.Id)
require.Equal(t, record.Get("type"), "1m")
// Create recent system_stats record that should be kept
_, err = tests.CreateRecord(hub, "system_stats", map[string]any{
"system": system.Id,
"type": "1m",
"stats": `{"cpu": 30.0, "mem": 512}`,
"created": now.Add(-30 * time.Minute), // 30 minutes old, should be kept
})
require.NoError(t, err)
// Create many alerts history records to trigger deletion
for i := range 260 { // More than countBeforeDeletion (250)
_, err = tests.CreateRecord(hub, "alerts_history", map[string]any{
"user": user.Id,
"name": "CPU",
"value": i + 1,
"system": system.Id,
"created": now.Add(-time.Duration(i) * time.Minute),
})
require.NoError(t, err)
}
// Count records before deletion
systemStatsCountBefore, err := hub.CountRecords("system_stats")
require.NoError(t, err)
alertsCountBefore, err := hub.CountRecords("alerts_history")
require.NoError(t, err)
// Run deletion
rm.DeleteOldRecords()
// Count records after deletion
systemStatsCountAfter, err := hub.CountRecords("system_stats")
require.NoError(t, err)
alertsCountAfter, err := hub.CountRecords("alerts_history")
require.NoError(t, err)
// Verify old system stats were deleted
assert.Less(t, systemStatsCountAfter, systemStatsCountBefore, "Old system stats should be deleted")
// Verify alerts history was trimmed
assert.Less(t, alertsCountAfter, alertsCountBefore, "Excessive alerts history should be deleted")
assert.Equal(t, alertsCountAfter, int64(200), "Alerts count should be equal to countToKeep (200)")
}
// TestDeleteOldSystemStats tests the deleteOldSystemStats function
func TestDeleteOldSystemStats(t *testing.T) {
hub, err := tests.NewTestHub(t.TempDir())
require.NoError(t, err)
defer hub.Cleanup()
// Create test system
user, err := tests.CreateUser(hub, "test@example.com", "testtesttest")
require.NoError(t, err)
system, err := tests.CreateRecord(hub, "systems", map[string]any{
"name": "test-system",
"host": "localhost",
"port": "45876",
"status": "up",
"users": []string{user.Id},
})
require.NoError(t, err)
now := time.Now().UTC()
// Test data for different record types and their retention periods
testCases := []struct {
recordType string
retention time.Duration
shouldBeKept bool
ageFromNow time.Duration
description string
}{
{"1m", time.Hour, true, 30 * time.Minute, "1m record within 1 hour should be kept"},
{"1m", time.Hour, false, 2 * time.Hour, "1m record older than 1 hour should be deleted"},
{"10m", 12 * time.Hour, true, 6 * time.Hour, "10m record within 12 hours should be kept"},
{"10m", 12 * time.Hour, false, 24 * time.Hour, "10m record older than 12 hours should be deleted"},
{"20m", 24 * time.Hour, true, 12 * time.Hour, "20m record within 24 hours should be kept"},
{"20m", 24 * time.Hour, false, 48 * time.Hour, "20m record older than 24 hours should be deleted"},
{"120m", 7 * 24 * time.Hour, true, 3 * 24 * time.Hour, "120m record within 7 days should be kept"},
{"120m", 7 * 24 * time.Hour, false, 10 * 24 * time.Hour, "120m record older than 7 days should be deleted"},
{"480m", 30 * 24 * time.Hour, true, 15 * 24 * time.Hour, "480m record within 30 days should be kept"},
{"480m", 30 * 24 * time.Hour, false, 45 * 24 * time.Hour, "480m record older than 30 days should be deleted"},
}
// Create test records for both system_stats and container_stats
collections := []string{"system_stats", "container_stats"}
recordIds := make(map[string][]string)
for _, collection := range collections {
recordIds[collection] = make([]string, 0)
for i, tc := range testCases {
recordTime := now.Add(-tc.ageFromNow)
var stats string
if collection == "system_stats" {
stats = fmt.Sprintf(`{"cpu": %d.0, "mem": %d}`, i*10, i*100)
} else {
stats = fmt.Sprintf(`[{"name": "container%d", "cpu": %d.0, "mem": %d}]`, i, i*5, i*50)
}
record, err := tests.CreateRecord(hub, collection, map[string]any{
"system": system.Id,
"type": tc.recordType,
"stats": stats,
})
require.NoError(t, err)
record.SetRaw("created", recordTime.Format(types.DefaultDateLayout))
err = hub.SaveNoValidate(record)
require.NoError(t, err)
recordIds[collection] = append(recordIds[collection], record.Id)
}
}
// Run deletion
err = records.DeleteOldSystemStats(hub)
require.NoError(t, err)
// Verify results
for _, collection := range collections {
for i, tc := range testCases {
recordId := recordIds[collection][i]
// Try to find the record
_, err := hub.FindRecordById(collection, recordId)
if tc.shouldBeKept {
assert.NoError(t, err, "Record should exist: %s", tc.description)
} else {
assert.Error(t, err, "Record should be deleted: %s", tc.description)
}
}
}
}
// TestDeleteOldAlertsHistory tests the deleteOldAlertsHistory function
func TestDeleteOldAlertsHistory(t *testing.T) {
hub, err := tests.NewTestHub(t.TempDir())
require.NoError(t, err)
defer hub.Cleanup()
// Create test users
user1, err := tests.CreateUser(hub, "user1@example.com", "testtesttest")
require.NoError(t, err)
user2, err := tests.CreateUser(hub, "user2@example.com", "testtesttest")
require.NoError(t, err)
system, err := tests.CreateRecord(hub, "systems", map[string]any{
"name": "test-system",
"host": "localhost",
"port": "45876",
"status": "up",
"users": []string{user1.Id, user2.Id},
})
require.NoError(t, err)
now := time.Now().UTC()
testCases := []struct {
name string
user *core.Record
alertCount int
countToKeep int
countBeforeDeletion int
expectedAfterDeletion int
description string
}{
{
name: "User with few alerts (below threshold)",
user: user1,
alertCount: 100,
countToKeep: 50,
countBeforeDeletion: 150,
expectedAfterDeletion: 100, // No deletion because below threshold
description: "User with alerts below countBeforeDeletion should not have any deleted",
},
{
name: "User with many alerts (above threshold)",
user: user2,
alertCount: 300,
countToKeep: 100,
countBeforeDeletion: 200,
expectedAfterDeletion: 100, // Should be trimmed to countToKeep
description: "User with alerts above countBeforeDeletion should be trimmed to countToKeep",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Create alerts for this user
for i := 0; i < tc.alertCount; i++ {
_, err := tests.CreateRecord(hub, "alerts_history", map[string]any{
"user": tc.user.Id,
"name": "CPU",
"value": i + 1,
"system": system.Id,
"created": now.Add(-time.Duration(i) * time.Minute),
})
require.NoError(t, err)
}
// Count before deletion
countBefore, err := hub.CountRecords("alerts_history",
dbx.NewExp("user = {:user}", dbx.Params{"user": tc.user.Id}))
require.NoError(t, err)
assert.Equal(t, int64(tc.alertCount), countBefore, "Initial count should match")
// Run deletion
err = records.DeleteOldAlertsHistory(hub, tc.countToKeep, tc.countBeforeDeletion)
require.NoError(t, err)
// Count after deletion
countAfter, err := hub.CountRecords("alerts_history",
dbx.NewExp("user = {:user}", dbx.Params{"user": tc.user.Id}))
require.NoError(t, err)
assert.Equal(t, int64(tc.expectedAfterDeletion), countAfter, tc.description)
// If deletion occurred, verify the most recent records were kept
if tc.expectedAfterDeletion < tc.alertCount {
records, err := hub.FindRecordsByFilter("alerts_history",
"user = {:user}",
"-created", // Order by created DESC
tc.countToKeep,
0,
map[string]any{"user": tc.user.Id})
require.NoError(t, err)
assert.Len(t, records, tc.expectedAfterDeletion, "Should have exactly countToKeep records")
// Verify records are in descending order by created time
for i := 1; i < len(records); i++ {
prev := records[i-1].GetDateTime("created").Time()
curr := records[i].GetDateTime("created").Time()
assert.True(t, prev.After(curr) || prev.Equal(curr),
"Records should be ordered by created time (newest first)")
}
}
})
}
}
// TestDeleteOldAlertsHistoryEdgeCases tests edge cases for alerts history deletion
func TestDeleteOldAlertsHistoryEdgeCases(t *testing.T) {
hub, err := tests.NewTestHub(t.TempDir())
require.NoError(t, err)
defer hub.Cleanup()
t.Run("No users with excessive alerts", func(t *testing.T) {
// Create user with few alerts
user, err := tests.CreateUser(hub, "few@example.com", "testtesttest")
require.NoError(t, err)
system, err := tests.CreateRecord(hub, "systems", map[string]any{
"name": "test-system",
"host": "localhost",
"port": "45876",
"status": "up",
"users": []string{user.Id},
})
// Create only 5 alerts (well below threshold)
for i := range 5 {
_, err := tests.CreateRecord(hub, "alerts_history", map[string]any{
"user": user.Id,
"name": "CPU",
"value": i + 1,
"system": system.Id,
})
require.NoError(t, err)
}
// Should not error and should not delete anything
err = records.DeleteOldAlertsHistory(hub, 10, 20)
require.NoError(t, err)
count, err := hub.CountRecords("alerts_history")
require.NoError(t, err)
assert.Equal(t, int64(5), count, "All alerts should remain")
})
t.Run("Empty alerts_history table", func(t *testing.T) {
// Clear any existing alerts
_, err := hub.DB().NewQuery("DELETE FROM alerts_history").Execute()
require.NoError(t, err)
// Should not error with empty table
err = records.DeleteOldAlertsHistory(hub, 10, 20)
require.NoError(t, err)
})
}
// TestDeleteOldSystemdServiceRecords tests systemd service cleanup via DeleteOldRecords
func TestDeleteOldSystemdServiceRecords(t *testing.T) {
hub, err := tests.NewTestHub(t.TempDir())
require.NoError(t, err)
defer hub.Cleanup()
rm := records.NewRecordManager(hub)
// Create test user and system
user, err := tests.CreateUser(hub, "test@example.com", "testtesttest")
require.NoError(t, err)
system, err := tests.CreateRecord(hub, "systems", map[string]any{
"name": "test-system",
"host": "localhost",
"port": "45876",
"status": "up",
"users": []string{user.Id},
})
require.NoError(t, err)
now := time.Now().UTC()
// Create old systemd service records that should be deleted (older than 20 minutes)
oldRecord, err := tests.CreateRecord(hub, "systemd_services", map[string]any{
"system": system.Id,
"name": "nginx.service",
"state": 0, // Active
"sub": 1, // Running
"cpu": 5.0,
"cpuPeak": 10.0,
"memory": 1024000,
"memPeak": 2048000,
})
require.NoError(t, err)
// Set updated time to 25 minutes ago (should be deleted)
oldRecord.SetRaw("updated", now.Add(-25*time.Minute).UnixMilli())
err = hub.SaveNoValidate(oldRecord)
require.NoError(t, err)
// Create recent systemd service record that should be kept (within 20 minutes)
recentRecord, err := tests.CreateRecord(hub, "systemd_services", map[string]any{
"system": system.Id,
"name": "apache.service",
"state": 1, // Inactive
"sub": 0, // Dead
"cpu": 2.0,
"cpuPeak": 3.0,
"memory": 512000,
"memPeak": 1024000,
})
require.NoError(t, err)
// Set updated time to 10 minutes ago (should be kept)
recentRecord.SetRaw("updated", now.Add(-10*time.Minute).UnixMilli())
err = hub.SaveNoValidate(recentRecord)
require.NoError(t, err)
// Count records before deletion
countBefore, err := hub.CountRecords("systemd_services")
require.NoError(t, err)
assert.Equal(t, int64(2), countBefore, "Should have 2 systemd service records initially")
// Run deletion via RecordManager
rm.DeleteOldRecords()
// Count records after deletion
countAfter, err := hub.CountRecords("systemd_services")
require.NoError(t, err)
assert.Equal(t, int64(1), countAfter, "Should have 1 systemd service record after deletion")
// Verify the correct record was kept
remainingRecords, err := hub.FindRecordsByFilter("systemd_services", "", "", 10, 0, nil)
require.NoError(t, err)
assert.Len(t, remainingRecords, 1, "Should have exactly 1 record remaining")
assert.Equal(t, "apache.service", remainingRecords[0].Get("name"), "The recent record should be kept")
}

View File

@@ -3,430 +3,15 @@
package records_test
import (
"fmt"
"testing"
"time"
"github.com/henrygd/beszel/internal/records"
"github.com/henrygd/beszel/internal/tests"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestDeleteOldRecords tests the main DeleteOldRecords function
func TestDeleteOldRecords(t *testing.T) {
hub, err := tests.NewTestHub(t.TempDir())
require.NoError(t, err)
defer hub.Cleanup()
rm := records.NewRecordManager(hub)
// Create test user for alerts history
user, err := tests.CreateUser(hub, "test@example.com", "testtesttest")
require.NoError(t, err)
// Create test system
system, err := tests.CreateRecord(hub, "systems", map[string]any{
"name": "test-system",
"host": "localhost",
"port": "45876",
"status": "up",
"users": []string{user.Id},
})
require.NoError(t, err)
now := time.Now()
// Create old system_stats records that should be deleted
var record *core.Record
record, err = tests.CreateRecord(hub, "system_stats", map[string]any{
"system": system.Id,
"type": "1m",
"stats": `{"cpu": 50.0, "mem": 1024}`,
})
require.NoError(t, err)
// created is autodate field, so we need to set it manually
record.SetRaw("created", now.UTC().Add(-2*time.Hour).Format(types.DefaultDateLayout))
err = hub.SaveNoValidate(record)
require.NoError(t, err)
require.NotNil(t, record)
require.InDelta(t, record.GetDateTime("created").Time().UTC().Unix(), now.UTC().Add(-2*time.Hour).Unix(), 1)
require.Equal(t, record.Get("system"), system.Id)
require.Equal(t, record.Get("type"), "1m")
// Create recent system_stats record that should be kept
_, err = tests.CreateRecord(hub, "system_stats", map[string]any{
"system": system.Id,
"type": "1m",
"stats": `{"cpu": 30.0, "mem": 512}`,
"created": now.Add(-30 * time.Minute), // 30 minutes old, should be kept
})
require.NoError(t, err)
// Create many alerts history records to trigger deletion
for i := range 260 { // More than countBeforeDeletion (250)
_, err = tests.CreateRecord(hub, "alerts_history", map[string]any{
"user": user.Id,
"name": "CPU",
"value": i + 1,
"system": system.Id,
"created": now.Add(-time.Duration(i) * time.Minute),
})
require.NoError(t, err)
}
// Count records before deletion
systemStatsCountBefore, err := hub.CountRecords("system_stats")
require.NoError(t, err)
alertsCountBefore, err := hub.CountRecords("alerts_history")
require.NoError(t, err)
// Run deletion
rm.DeleteOldRecords()
// Count records after deletion
systemStatsCountAfter, err := hub.CountRecords("system_stats")
require.NoError(t, err)
alertsCountAfter, err := hub.CountRecords("alerts_history")
require.NoError(t, err)
// Verify old system stats were deleted
assert.Less(t, systemStatsCountAfter, systemStatsCountBefore, "Old system stats should be deleted")
// Verify alerts history was trimmed
assert.Less(t, alertsCountAfter, alertsCountBefore, "Excessive alerts history should be deleted")
assert.Equal(t, alertsCountAfter, int64(200), "Alerts count should be equal to countToKeep (200)")
}
// TestDeleteOldSystemStats tests the deleteOldSystemStats function
func TestDeleteOldSystemStats(t *testing.T) {
hub, err := tests.NewTestHub(t.TempDir())
require.NoError(t, err)
defer hub.Cleanup()
// Create test system
user, err := tests.CreateUser(hub, "test@example.com", "testtesttest")
require.NoError(t, err)
system, err := tests.CreateRecord(hub, "systems", map[string]any{
"name": "test-system",
"host": "localhost",
"port": "45876",
"status": "up",
"users": []string{user.Id},
})
require.NoError(t, err)
now := time.Now().UTC()
// Test data for different record types and their retention periods
testCases := []struct {
recordType string
retention time.Duration
shouldBeKept bool
ageFromNow time.Duration
description string
}{
{"1m", time.Hour, true, 30 * time.Minute, "1m record within 1 hour should be kept"},
{"1m", time.Hour, false, 2 * time.Hour, "1m record older than 1 hour should be deleted"},
{"10m", 12 * time.Hour, true, 6 * time.Hour, "10m record within 12 hours should be kept"},
{"10m", 12 * time.Hour, false, 24 * time.Hour, "10m record older than 12 hours should be deleted"},
{"20m", 24 * time.Hour, true, 12 * time.Hour, "20m record within 24 hours should be kept"},
{"20m", 24 * time.Hour, false, 48 * time.Hour, "20m record older than 24 hours should be deleted"},
{"120m", 7 * 24 * time.Hour, true, 3 * 24 * time.Hour, "120m record within 7 days should be kept"},
{"120m", 7 * 24 * time.Hour, false, 10 * 24 * time.Hour, "120m record older than 7 days should be deleted"},
{"480m", 30 * 24 * time.Hour, true, 15 * 24 * time.Hour, "480m record within 30 days should be kept"},
{"480m", 30 * 24 * time.Hour, false, 45 * 24 * time.Hour, "480m record older than 30 days should be deleted"},
}
// Create test records for both system_stats and container_stats
collections := []string{"system_stats", "container_stats"}
recordIds := make(map[string][]string)
for _, collection := range collections {
recordIds[collection] = make([]string, 0)
for i, tc := range testCases {
recordTime := now.Add(-tc.ageFromNow)
var stats string
if collection == "system_stats" {
stats = fmt.Sprintf(`{"cpu": %d.0, "mem": %d}`, i*10, i*100)
} else {
stats = fmt.Sprintf(`[{"name": "container%d", "cpu": %d.0, "mem": %d}]`, i, i*5, i*50)
}
record, err := tests.CreateRecord(hub, collection, map[string]any{
"system": system.Id,
"type": tc.recordType,
"stats": stats,
})
require.NoError(t, err)
record.SetRaw("created", recordTime.Format(types.DefaultDateLayout))
err = hub.SaveNoValidate(record)
require.NoError(t, err)
recordIds[collection] = append(recordIds[collection], record.Id)
}
}
// Run deletion
err = records.DeleteOldSystemStats(hub)
require.NoError(t, err)
// Verify results
for _, collection := range collections {
for i, tc := range testCases {
recordId := recordIds[collection][i]
// Try to find the record
_, err := hub.FindRecordById(collection, recordId)
if tc.shouldBeKept {
assert.NoError(t, err, "Record should exist: %s", tc.description)
} else {
assert.Error(t, err, "Record should be deleted: %s", tc.description)
}
}
}
}
// TestDeleteOldAlertsHistory tests the deleteOldAlertsHistory function
func TestDeleteOldAlertsHistory(t *testing.T) {
hub, err := tests.NewTestHub(t.TempDir())
require.NoError(t, err)
defer hub.Cleanup()
// Create test users
user1, err := tests.CreateUser(hub, "user1@example.com", "testtesttest")
require.NoError(t, err)
user2, err := tests.CreateUser(hub, "user2@example.com", "testtesttest")
require.NoError(t, err)
system, err := tests.CreateRecord(hub, "systems", map[string]any{
"name": "test-system",
"host": "localhost",
"port": "45876",
"status": "up",
"users": []string{user1.Id, user2.Id},
})
require.NoError(t, err)
now := time.Now().UTC()
testCases := []struct {
name string
user *core.Record
alertCount int
countToKeep int
countBeforeDeletion int
expectedAfterDeletion int
description string
}{
{
name: "User with few alerts (below threshold)",
user: user1,
alertCount: 100,
countToKeep: 50,
countBeforeDeletion: 150,
expectedAfterDeletion: 100, // No deletion because below threshold
description: "User with alerts below countBeforeDeletion should not have any deleted",
},
{
name: "User with many alerts (above threshold)",
user: user2,
alertCount: 300,
countToKeep: 100,
countBeforeDeletion: 200,
expectedAfterDeletion: 100, // Should be trimmed to countToKeep
description: "User with alerts above countBeforeDeletion should be trimmed to countToKeep",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Create alerts for this user
for i := 0; i < tc.alertCount; i++ {
_, err := tests.CreateRecord(hub, "alerts_history", map[string]any{
"user": tc.user.Id,
"name": "CPU",
"value": i + 1,
"system": system.Id,
"created": now.Add(-time.Duration(i) * time.Minute),
})
require.NoError(t, err)
}
// Count before deletion
countBefore, err := hub.CountRecords("alerts_history",
dbx.NewExp("user = {:user}", dbx.Params{"user": tc.user.Id}))
require.NoError(t, err)
assert.Equal(t, int64(tc.alertCount), countBefore, "Initial count should match")
// Run deletion
err = records.DeleteOldAlertsHistory(hub, tc.countToKeep, tc.countBeforeDeletion)
require.NoError(t, err)
// Count after deletion
countAfter, err := hub.CountRecords("alerts_history",
dbx.NewExp("user = {:user}", dbx.Params{"user": tc.user.Id}))
require.NoError(t, err)
assert.Equal(t, int64(tc.expectedAfterDeletion), countAfter, tc.description)
// If deletion occurred, verify the most recent records were kept
if tc.expectedAfterDeletion < tc.alertCount {
records, err := hub.FindRecordsByFilter("alerts_history",
"user = {:user}",
"-created", // Order by created DESC
tc.countToKeep,
0,
map[string]any{"user": tc.user.Id})
require.NoError(t, err)
assert.Len(t, records, tc.expectedAfterDeletion, "Should have exactly countToKeep records")
// Verify records are in descending order by created time
for i := 1; i < len(records); i++ {
prev := records[i-1].GetDateTime("created").Time()
curr := records[i].GetDateTime("created").Time()
assert.True(t, prev.After(curr) || prev.Equal(curr),
"Records should be ordered by created time (newest first)")
}
}
})
}
}
// TestDeleteOldAlertsHistoryEdgeCases tests edge cases for alerts history deletion
func TestDeleteOldAlertsHistoryEdgeCases(t *testing.T) {
hub, err := tests.NewTestHub(t.TempDir())
require.NoError(t, err)
defer hub.Cleanup()
t.Run("No users with excessive alerts", func(t *testing.T) {
// Create user with few alerts
user, err := tests.CreateUser(hub, "few@example.com", "testtesttest")
require.NoError(t, err)
system, err := tests.CreateRecord(hub, "systems", map[string]any{
"name": "test-system",
"host": "localhost",
"port": "45876",
"status": "up",
"users": []string{user.Id},
})
// Create only 5 alerts (well below threshold)
for i := range 5 {
_, err := tests.CreateRecord(hub, "alerts_history", map[string]any{
"user": user.Id,
"name": "CPU",
"value": i + 1,
"system": system.Id,
})
require.NoError(t, err)
}
// Should not error and should not delete anything
err = records.DeleteOldAlertsHistory(hub, 10, 20)
require.NoError(t, err)
count, err := hub.CountRecords("alerts_history")
require.NoError(t, err)
assert.Equal(t, int64(5), count, "All alerts should remain")
})
t.Run("Empty alerts_history table", func(t *testing.T) {
// Clear any existing alerts
_, err := hub.DB().NewQuery("DELETE FROM alerts_history").Execute()
require.NoError(t, err)
// Should not error with empty table
err = records.DeleteOldAlertsHistory(hub, 10, 20)
require.NoError(t, err)
})
}
// TestDeleteOldSystemdServiceRecords tests systemd service cleanup via DeleteOldRecords
func TestDeleteOldSystemdServiceRecords(t *testing.T) {
hub, err := tests.NewTestHub(t.TempDir())
require.NoError(t, err)
defer hub.Cleanup()
rm := records.NewRecordManager(hub)
// Create test user and system
user, err := tests.CreateUser(hub, "test@example.com", "testtesttest")
require.NoError(t, err)
system, err := tests.CreateRecord(hub, "systems", map[string]any{
"name": "test-system",
"host": "localhost",
"port": "45876",
"status": "up",
"users": []string{user.Id},
})
require.NoError(t, err)
now := time.Now().UTC()
// Create old systemd service records that should be deleted (older than 20 minutes)
oldRecord, err := tests.CreateRecord(hub, "systemd_services", map[string]any{
"system": system.Id,
"name": "nginx.service",
"state": 0, // Active
"sub": 1, // Running
"cpu": 5.0,
"cpuPeak": 10.0,
"memory": 1024000,
"memPeak": 2048000,
})
require.NoError(t, err)
// Set updated time to 25 minutes ago (should be deleted)
oldRecord.SetRaw("updated", now.Add(-25*time.Minute).UnixMilli())
err = hub.SaveNoValidate(oldRecord)
require.NoError(t, err)
// Create recent systemd service record that should be kept (within 20 minutes)
recentRecord, err := tests.CreateRecord(hub, "systemd_services", map[string]any{
"system": system.Id,
"name": "apache.service",
"state": 1, // Inactive
"sub": 0, // Dead
"cpu": 2.0,
"cpuPeak": 3.0,
"memory": 512000,
"memPeak": 1024000,
})
require.NoError(t, err)
// Set updated time to 10 minutes ago (should be kept)
recentRecord.SetRaw("updated", now.Add(-10*time.Minute).UnixMilli())
err = hub.SaveNoValidate(recentRecord)
require.NoError(t, err)
// Count records before deletion
countBefore, err := hub.CountRecords("systemd_services")
require.NoError(t, err)
assert.Equal(t, int64(2), countBefore, "Should have 2 systemd service records initially")
// Run deletion via RecordManager
rm.DeleteOldRecords()
// Count records after deletion
countAfter, err := hub.CountRecords("systemd_services")
require.NoError(t, err)
assert.Equal(t, int64(1), countAfter, "Should have 1 systemd service record after deletion")
// Verify the correct record was kept
remainingRecords, err := hub.FindRecordsByFilter("systemd_services", "", "", 10, 0, nil)
require.NoError(t, err)
assert.Len(t, remainingRecords, 1, "Should have exactly 1 record remaining")
assert.Equal(t, "apache.service", remainingRecords[0].Get("name"), "The recent record should be kept")
}
// TestRecordManagerCreation tests RecordManager creation
func TestRecordManagerCreation(t *testing.T) {
hub, err := tests.NewTestHub(t.TempDir())

View File

@@ -22,11 +22,7 @@
})();
</script>
<script>
globalThis.BESZEL = {
BASE_PATH: "%BASE_URL%",
HUB_VERSION: "{{V}}",
HUB_URL: "{{HUB_URL}}"
}
globalThis.BESZEL = "{info}"
</script>
</head>
<body>

View File

@@ -1,12 +1,12 @@
{
"name": "beszel",
"version": "0.18.6",
"version": "0.18.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "beszel",
"version": "0.18.6",
"version": "0.18.7",
"dependencies": {
"@henrygd/queue": "^1.0.7",
"@henrygd/semaphore": "^0.0.2",

View File

@@ -1,7 +1,7 @@
{
"name": "beszel",
"private": true,
"version": "0.18.6",
"version": "0.18.7",
"type": "module",
"scripts": {
"dev": "vite --host",

View File

@@ -12,7 +12,7 @@ import { Label } from "@/components/ui/label"
import { pb } from "@/lib/api"
import { $authenticated } from "@/lib/stores"
import { cn } from "@/lib/utils"
import { $router, Link, prependBasePath } from "../router"
import { $router, Link, basePath, prependBasePath } from "../router"
import { toast } from "../ui/use-toast"
import { OtpInputForm } from "./otp-forms"
@@ -37,8 +37,7 @@ const RegisterSchema = v.looseObject({
passwordConfirm: passwordSchema,
})
export const showLoginFaliedToast = (description?: string) => {
description ||= t`Please check your credentials and try again`
export const showLoginFaliedToast = (description = t`Please check your credentials and try again`) => {
toast({
title: t`Login attempt failed`,
description,
@@ -130,10 +129,6 @@ export function UserAuthForm({
[isFirstRun]
)
if (!authMethods) {
return null
}
const authProviders = authMethods.oauth2.providers ?? []
const oauthEnabled = authMethods.oauth2.enabled && authProviders.length > 0
const passwordEnabled = authMethods.password.enabled
@@ -142,6 +137,12 @@ export function UserAuthForm({
function loginWithOauth(provider: AuthProviderInfo, forcePopup = false) {
setIsOauthLoading(true)
if (globalThis.BESZEL.OAUTH_DISABLE_POPUP) {
redirectToOauthProvider(provider)
return
}
const oAuthOpts: OAuth2AuthConfig = {
provider: provider.name,
}
@@ -150,10 +151,7 @@ export function UserAuthForm({
const authWindow = window.open()
if (!authWindow) {
setIsOauthLoading(false)
toast({
title: t`Error`,
description: t`Please enable pop-ups for this site`,
})
showLoginFaliedToast(t`Please enable pop-ups for this site`)
return
}
oAuthOpts.urlCallback = (url) => {
@@ -171,16 +169,57 @@ export function UserAuthForm({
})
}
/**
* Redirects the user to the OAuth provider's authentication page in the same window.
* Requires the app's base URL to be registered as a redirect URI with the OAuth provider.
*/
function redirectToOauthProvider(provider: AuthProviderInfo) {
const url = new URL(provider.authURL)
// url.searchParams.set("redirect_uri", `${window.location.origin}${basePath}`)
sessionStorage.setItem("provider", JSON.stringify(provider))
window.location.href = url.toString()
}
useEffect(() => {
// auto login if password disabled and only one auth provider
if (!passwordEnabled && authProviders.length === 1 && !sessionStorage.getItem("lo")) {
// Add a small timeout to ensure browser is ready to handle popups
setTimeout(() => {
loginWithOauth(authProviders[0], true)
}, 300)
// handle redirect-based OAuth callback if we have a code
const params = new URLSearchParams(window.location.search)
const code = params.get("code")
if (code) {
const state = params.get("state")
const provider: AuthProviderInfo = JSON.parse(sessionStorage.getItem("provider") ?? "{}")
if (!state || provider.state !== state) {
showLoginFaliedToast()
} else {
setIsOauthLoading(true)
window.history.replaceState({}, "", window.location.pathname)
pb.collection("users")
.authWithOAuth2Code(provider.name, code, provider.codeVerifier, `${window.location.origin}${basePath}`)
.then(() => $authenticated.set(pb.authStore.isValid))
.catch((e: unknown) => showLoginFaliedToast((e as Error).message))
.finally(() => setIsOauthLoading(false))
}
}
// auto login if password disabled and only one auth provider
if (!code && !passwordEnabled && authProviders.length === 1 && !sessionStorage.getItem("lo")) {
// Add a small timeout to ensure browser is ready to handle popups
setTimeout(() => loginWithOauth(authProviders[0], false), 300)
return
}
// refresh auth if not in above states (required for trusted auth header)
pb.collection("users")
.authRefresh()
.then((res) => {
pb.authStore.save(res.token, res.record)
$authenticated.set(!!pb.authStore.isValid)
})
}, [])
if (!authMethods) {
return null
}
if (otpId && mfaId) {
return <OtpInputForm otpId={otpId} mfaId={mfaId} />
}
@@ -248,7 +287,7 @@ export function UserAuthForm({
)}
<div className="sr-only">
{/* honeypot */}
<label htmlFor="website"></label>
<label htmlFor="website">Website</label>
<input
id="website"
type="text"

View File

@@ -1,28 +1,39 @@
import { t } from "@lingui/core/macro"
import { MoonStarIcon, SunIcon } from "lucide-react"
import { MoonStarIcon, SunIcon, SunMoonIcon } from "lucide-react"
import { useTheme } from "@/components/theme-provider"
import { Button } from "@/components/ui/button"
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"
import { Trans } from "@lingui/react/macro"
import { cn } from "@/lib/utils"
const themes = ["light", "dark", "system"] as const
const icons = [SunIcon, MoonStarIcon, SunMoonIcon] as const
export function ModeToggle() {
const { theme, setTheme } = useTheme()
const currentIndex = themes.indexOf(theme)
const Icon = icons[currentIndex]
return (
<Tooltip>
<TooltipTrigger asChild>
<Button
variant={"ghost"}
size="icon"
aria-label={t`Toggle theme`}
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
aria-label={t`Switch theme`}
onClick={() => setTheme(themes[(currentIndex + 1) % themes.length])}
>
<SunIcon className="h-[1.2rem] w-[1.2rem] transition-all -rotate-90 dark:opacity-0 dark:rotate-0" />
<MoonStarIcon className="absolute h-[1.2rem] w-[1.2rem] transition-all opacity-0 -rotate-90 dark:opacity-100 dark:rotate-0" />
<Icon
className={cn(
"animate-in fade-in spin-in-[-30deg] duration-200",
currentIndex === 2 ? "size-[1.35rem]" : "size-[1.2rem]"
)}
/>
</Button>
</TooltipTrigger>
<TooltipContent>
<Trans>Toggle theme</Trans>
<Trans>Switch theme</Trans>
</TooltipContent>
</Tooltip>
)

View File

@@ -15,6 +15,7 @@ import { isAdmin, pb } from "@/lib/api"
import type { UserSettings } from "@/types"
import { saveSettings } from "./layout"
import { QuietHours } from "./quiet-hours"
import type { ClientResponseError } from "pocketbase"
interface ShoutrrrUrlCardProps {
url: string
@@ -59,10 +60,10 @@ const SettingsNotificationsPage = ({ userSettings }: { userSettings: UserSetting
try {
const parsedData = v.parse(NotificationSchema, { emails, webhooks })
await saveSettings(parsedData)
} catch (e: any) {
} catch (e: unknown) {
toast({
title: t`Failed to save settings`,
description: e.message,
description: (e as Error).message,
variant: "destructive",
})
}
@@ -136,12 +137,7 @@ const SettingsNotificationsPage = ({ userSettings }: { userSettings: UserSetting
</Trans>
</p>
</div>
<Button
type="button"
variant="outline"
className="h-10 shrink-0"
onClick={addWebhook}
>
<Button type="button" variant="outline" className="h-10 shrink-0" onClick={addWebhook}>
<PlusIcon className="size-4" />
<span className="ms-1">
<Trans>Add URL</Trans>
@@ -180,25 +176,34 @@ const SettingsNotificationsPage = ({ userSettings }: { userSettings: UserSetting
)
}
function showTestNotificationError(msg: string) {
toast({
title: t`Error`,
description: msg ?? t`Failed to send test notification`,
variant: "destructive",
})
}
const ShoutrrrUrlCard = ({ url, onUrlChange, onRemove }: ShoutrrrUrlCardProps) => {
const [isLoading, setIsLoading] = useState(false)
const sendTestNotification = async () => {
setIsLoading(true)
const res = await pb.send("/api/beszel/test-notification", { method: "POST", body: { url } })
if ("err" in res && !res.err) {
toast({
title: t`Test notification sent`,
description: t`Check your notification service`,
})
} else {
toast({
title: t`Error`,
description: res.err ?? t`Failed to send test notification`,
variant: "destructive",
})
try {
const res = await pb.send("/api/beszel/test-notification", { method: "POST", body: { url } })
if ("err" in res && !res.err) {
toast({
title: t`Test notification sent`,
description: t`Check your notification service`,
})
} else {
showTestNotificationError(res.err)
}
} catch (e: unknown) {
showTestNotificationError((e as ClientResponseError).data?.message)
} finally {
setIsLoading(false)
}
setIsLoading(false)
}
return (

View File

@@ -152,7 +152,7 @@ export function DiskIOChart({ systemData, extraFsName }: { systemData: SystemDat
return null
}
const title = extraFsName ? t`${extraFsName} I/O` : t`Disk I/O`
const title = extraFsName ? `${extraFsName} I/O` : t`Disk I/O`
const description = extraFsName ? t`Throughput of ${extraFsName}` : t`Throughput of root filesystem`
const hasMoreIOMetrics = chartData.systemStats?.some((record) => record.stats?.dios?.at(0))
@@ -225,7 +225,10 @@ export function DiskUtilizationChart({ systemData, extraFsName }: { systemData:
cornerEl={maxValSelect}
empty={dataEmpty}
grid={grid}
title={t`I/O Utilization`}
title={t({
message: `I/O Utilization`,
context: "Percent of time the disk is busy with I/O",
})}
description={t`Percent of time the disk is busy with I/O`}
// legend={true}
className="min-h-auto"
@@ -239,7 +242,7 @@ export function DiskUtilizationChart({ systemData, extraFsName }: { systemData:
chartProps={{ syncId: "io" }}
dataPoints={[
{
label: t`Utilization`,
label: t({ message: "Utilization", context: "Disk I/O utilization" }),
dataKey: utilFn,
color: 1,
opacity: 0.4,

View File

@@ -84,6 +84,8 @@ export default memo(function DiskIOSheet({
const chartProps = { syncId: "io" }
const queueDepthTranslation = t({ message: "Queue Depth", context: "Disk I/O average queue depth" })
return (
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
<DialogTitle className="sr-only">{title}</DialogTitle>
@@ -120,7 +122,7 @@ export default memo(function DiskIOSheet({
reverseStackOrder={true}
dataPoints={[
{
label: t({ message: "Write", comment: "Disk write" }),
label: t`Write`,
dataKey: writeFn,
color: 3,
opacity: 0.4,
@@ -128,7 +130,7 @@ export default memo(function DiskIOSheet({
order: 0,
},
{
label: t({ message: "Read", comment: "Disk read" }),
label: t`Read`,
dataKey: readFn,
color: 1,
opacity: 0.4,
@@ -152,8 +154,11 @@ export default memo(function DiskIOSheet({
<ChartCard
empty={dataEmpty}
grid={grid}
title={t`I/O Time`}
description={t`Total time spent on read/write (can exceed 100%)`}
title={t({ message: "I/O Time", context: "Disk I/O total time spent on read/write" })}
description={t({
message: "Total time spent on read/write (can exceed 100%)",
context: "Disk I/O",
})}
className="min-h-auto"
cornerEl={maxValSelect}
>
@@ -192,7 +197,7 @@ export default memo(function DiskIOSheet({
<ChartCard
empty={dataEmpty}
grid={grid}
title={t`Average Queue Depth`}
title={queueDepthTranslation}
description={t`Average number of I/O operations waiting to be serviced`}
className="min-h-auto"
cornerEl={maxValSelect}
@@ -206,7 +211,7 @@ export default memo(function DiskIOSheet({
chartProps={chartProps}
dataPoints={[
{
label: t`Queue Depth`,
label: queueDepthTranslation,
dataKey: weightedIOFn,
color: 1,
opacity: 0.4,
@@ -220,8 +225,11 @@ export default memo(function DiskIOSheet({
<ChartCard
empty={dataEmpty}
grid={grid}
title={t`I/O Await`}
description={t`Average service time per operation`}
title={t({ message: "I/O Await", context: "Disk I/O average operation time (iostat await)" })}
description={t({
message: "Average queue to completion time per operation",
context: "Disk I/O average operation time (iostat await)",
})}
className="min-h-auto"
cornerEl={maxValSelect}
// legend={true}

View File

@@ -192,7 +192,7 @@ export function useSystemData(id: string) {
// Skip the fetch if the latest cached point is recent enough that no new point is expected yet
const lastCreated = cachedSystemStats.at(-1)?.created as number | undefined
if (lastCreated && Date.now() - lastCreated < expectedInterval) {
if (lastCreated && Date.now() - lastCreated < expectedInterval * 0.9) {
return
}
} else {

View File

@@ -110,20 +110,23 @@ export function SystemsTableColumns(viewMode: "table" | "grid"): ColumnDef<Syste
// match filter value against name or translated status
return (row, _, newFilterInput) => {
const { name, status } = row.original
const sys = row.original
if (sys.host.includes(newFilterInput) || sys.info.v?.includes(newFilterInput)) {
return true
}
if (newFilterInput !== filterInput) {
filterInput = newFilterInput
filterInputLower = newFilterInput.toLowerCase()
}
let nameLower = nameCache.get(name)
let nameLower = nameCache.get(sys.name)
if (nameLower === undefined) {
nameLower = name.toLowerCase()
nameCache.set(name, nameLower)
nameLower = sys.name.toLowerCase()
nameCache.set(sys.name, nameLower)
}
if (nameLower.includes(filterInputLower)) {
return true
}
const statusLower = statusTranslations[status as keyof typeof statusTranslations]
const statusLower = statusTranslations[sys.status as keyof typeof statusTranslations]
return statusLower?.includes(filterInputLower) || false
}
})(),

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ar\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-06-03 00:49\n"
"Last-Translator: \n"
"Language-Team: Arabic\n"
"Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} متاح"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "المتوسط ينخفض أقل من <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "المتوسط يتجاوز <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "متوسط عدد عمليات الإدخال والإخراج التي تنتظر خدمتها"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "متوسط ​​استهلاك طاقة وحدة معالجة الرسوميات"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "متوسط الوقت من الانتظار في الدور حتى الإتمام لكل عملية"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "متوسط استخدام وحدة المعالجة المركزية على مستوى النظام"
@@ -416,7 +425,7 @@ msgstr "الاتصال مقطوع"
#: src/components/routes/system.tsx
msgid "Containers"
msgstr "الحاويات"
msgstr "حاويات"
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/systems-table/systems-table-columns.tsx
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "نسخ متغيرات البيئة"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "نسخ من"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "نسخ المضيف"
@@ -476,7 +490,7 @@ msgstr "نسخ YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "النواة"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "يوميًا"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "افتراضي"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "وحدة القرص"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "استخدام القرص"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "استخدام القرص لـ {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "عرض"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -686,7 +699,7 @@ msgstr "عنوان URL للنقطة النهائية"
#: src/components/routes/settings/heartbeat.tsx
msgid "Endpoint URL to ping (required)"
msgstr "عنوان URL للنقطة النهائية لل ping (مطلوب)"
msgstr "رابط نقطة النهاية إلى ping (مطلوب)"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
@@ -898,6 +911,21 @@ msgstr "طريقة HTTP"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "طريقة HTTP: POST، GET، أو HEAD (الافتراضي: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "انتظار الإدخال والإخراج"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "وقت الإدخال والإخراج"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "استخدام الإدخال والإخراج"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "تنسيق الحمولة"
msgid "Per-core average utilization"
msgstr "متوسط الاستخدام لكل نواة"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "النسبة المئوية للوقت الذي يكون فيه القرص مشغولاً بالإدخال والإخراج"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "النسبة المئوية للوقت المقضي في كل حالة"
@@ -1259,7 +1291,7 @@ msgstr "المنفذ"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "المنافذ"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "تم بدء العملية"
msgid "Public Key"
msgstr "المفتاح العام"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "عمق الدور"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "ساعات الهدوء"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "قراءة"
@@ -1549,7 +1588,7 @@ msgstr "جدول"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "تبويبات"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "لا يمكن التراجع عن هذا الإجراء. سيؤدي ذل
msgid "This will permanently delete all selected records from the database."
msgstr "سيؤدي هذا إلى حذف جميع السجلات المحددة من قاعدة البيانات بشكل دائم."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "معدل نقل {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "إجمالي البيانات المستلمة لكل واجهة"
msgid "Total data sent for each interface"
msgstr "إجمالي البيانات المرسلة لكل واجهة"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr "إجمالي الوقت المستغرق في القراءة/الكتابة (يمكن أن يتجاوز 100٪)"
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "رفع"
msgid "Uptime"
msgstr "مدة التشغيل"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "مستخدم"
msgid "Users"
msgstr "المستخدمون"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "الاستخدام"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "القيمة"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "عرض"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "عرض المزيد"
@@ -1858,7 +1908,9 @@ msgstr "أمر ويندوز"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "كتابة"
@@ -1879,3 +1931,4 @@ msgstr "نعم"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "تم تحديث إعدادات المستخدم الخاصة بك."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: bg\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-03-28 09:32\n"
"Last-Translator: \n"
"Language-Team: Bulgarian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "Версия {0} е налична"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Средната стойност пада под <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Средната стойност надхвърля <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Среден брой I/O операции, чакащи обслужване"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Средна консумация на ток от графични карти"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Средно време в опашката до приключване на операция"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Средно използване на процесора на цялата система"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Копирай еnv"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Копиране от"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Копирай хоста"
@@ -476,7 +490,7 @@ msgstr "Копирай YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Основни"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Дневно"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Подредба"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Единица за диск"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Използване на диск"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Изполване на диск от {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Показване"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "HTTP метод"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP метод: POST, GET или HEAD (по подразбиране: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O изчакване"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O време"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O натоварване"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Формат на полезния товар"
msgid "Per-core average utilization"
msgstr "Средно използване на ядро"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Процент от времето, в което дискът е зает с I/O операции"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Процент време, прекарано във всяко състояние"
@@ -1259,7 +1291,7 @@ msgstr "Порт"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Портове"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Процесът стартира"
msgid "Public Key"
msgstr "Публичен ключ"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Дълбочина на опашката"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Тихи часове"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Прочети"
@@ -1549,7 +1588,7 @@ msgstr "Таблица"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Табове"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Това действие не може да бъде отменено.
msgid "This will permanently delete all selected records from the database."
msgstr "Това ще доведе до трайно изтриване на всички избрани записи от базата данни."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Пропускателна способност на {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Общо получени данни за всеки интерфейс"
msgid "Total data sent for each interface"
msgstr "Общо изпратени данни за всеки интерфейс"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Качване"
msgid "Uptime"
msgstr "Време на работа"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Използвани"
msgid "Users"
msgstr "Потребители"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Натоварване"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Стойност"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Изглед"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Виж повече"
@@ -1858,7 +1908,9 @@ msgstr "Команда Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Запиши"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: cs\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:27\n"
"Last-Translator: \n"
"Language-Team: Czech\n"
"Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 3;\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} k dispozici"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Průměr klesne pod <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Průměr je vyšší než <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Průměrný počet I/O operací čekajících na vyřízení"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Průměrná spotřeba energie GPU"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Průměrná doba od zařazení do fronty po dokončení operace"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Průměrné využití CPU v celém systému"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Kopírovat env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Kopírovat z"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Kopírovat hostitele"
@@ -476,7 +490,7 @@ msgstr "Kopírovat YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Jádro"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Denně"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Výchozí"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Disková jednotka"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Využití disku"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Využití disku {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Zobrazení"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "HTTP metoda"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP metoda: POST, GET nebo HEAD (výchozí: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O Čekání"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O Čas"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O Využití"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Formát payloadu"
msgid "Per-core average utilization"
msgstr "Průměrné využití na jádro"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Procento času, po který je disk zaneprázdněn I/O operacemi"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Procento času strávěného v každém stavu"
@@ -1259,7 +1291,7 @@ msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Porty"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Proces spuštěn"
msgid "Public Key"
msgstr "Veřejný klíč"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Hloubka fronty"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Tiché hodiny"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Číst"
@@ -1549,7 +1588,7 @@ msgstr "Tabulka"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Karty"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Tuto akci nelze vzít zpět. Tím se z databáze trvale odstraní všech
msgid "This will permanently delete all selected records from the database."
msgstr "Tímto trvale odstraníte všechny vybrané záznamy z databáze."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Propustnost {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Celkový přijatý objem dat pro každé rozhraní"
msgid "Total data sent for each interface"
msgstr "Celkový odeslaný objem dat pro každé rozhraní"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Odeslání"
msgid "Uptime"
msgstr "Doba provozu"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Využito"
msgid "Users"
msgstr "Uživatelé"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Využití"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Hodnota"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Zobrazení"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Zobrazit více"
@@ -1858,7 +1908,9 @@ msgstr "Windows příkaz"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Psát"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: da\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:27\n"
"Last-Translator: \n"
"Language-Team: Danish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} tilgængelig"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Gennemsnit falder under <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Gennemsnittet overstiger <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Gennemsnitligt antal I/O-operationer, der venter på at blive betjent"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Gennemsnitligt strømforbrug for GPU'er"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Gennemsnitlig tid fra kø til færdiggørelse pr. operation"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Gennemsnitlig systembaseret CPU-udnyttelse"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Kopier miljø"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Kopier fra"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Kopier vært"
@@ -476,7 +490,7 @@ msgstr "Kopier YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Kerne"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Dagligt"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Standard"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Diskenhed"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Diskforbrug"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Diskforbrug af {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Visning"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -870,7 +883,7 @@ msgstr "Sundhed"
#: src/components/routes/settings/layout.tsx
msgid "Heartbeat"
msgstr ""
msgstr "Hjerteslag"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat Monitoring"
@@ -898,6 +911,21 @@ msgstr "HTTP-metode"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP-metode: POST, GET eller HEAD (standard: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O Vent"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O Tid"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O Udnyttelse"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Payload-format"
msgid "Per-core average utilization"
msgstr "Gennemsnitlig udnyttelse pr. kerne"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Procentdel af tiden disk-en er optaget af I/O"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Procentdel af tid brugt i hver tilstand"
@@ -1259,7 +1291,7 @@ msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Porte"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Proces startet"
msgid "Public Key"
msgstr "Offentlig nøgle"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Kødybde"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Stille timer"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Læs"
@@ -1549,7 +1588,7 @@ msgstr "Tabel"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Faner"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Denne handling kan ikke fortrydes. Dette vil permanent slette alle aktue
msgid "This will permanently delete all selected records from the database."
msgstr "Dette vil permanent slette alle poster fra databasen."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Gennemløb af {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Samlet modtaget data for hver interface"
msgid "Total data sent for each interface"
msgstr "Samlet sendt data for hver interface"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Overfør"
msgid "Uptime"
msgstr "Oppetid"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Brugt"
msgid "Users"
msgstr "Brugere"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Udnyttelse"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Værdi"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Vis"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Se mere"
@@ -1858,7 +1908,9 @@ msgstr "Windows-kommando"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Skriv"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: de\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-14 20:37\n"
"PO-Revision-Date: 2026-04-05 18:27\n"
"Last-Translator: \n"
"Language-Team: German\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} verfügbar"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Durchschnitt unterschreitet <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Durchschnitt überschreitet <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Durchschnittliche Anzahl der auf Bearbeitung wartenden I/O-Operationen"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Durchschnittlicher Stromverbrauch der GPUs"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Durchschnittliche Warteschlangen- bis Abschlusszeit pro Operation"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Durchschnittliche systemweite CPU-Auslastung"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Umgebungsvariablen kopieren"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Kopieren von"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Host kopieren"
@@ -476,7 +490,7 @@ msgstr "YAML kopieren"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Kern"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Täglich"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Standard"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Festplatteneinheit"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Festplattennutzung"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Festplattennutzung von {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Anzeige"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "HTTP-Methode"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP-Methode: POST, GET oder HEAD (Standard: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O-Wartezeit"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O-Zeit"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O-Auslastung"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Payload-Format"
msgid "Per-core average utilization"
msgstr "Durchschnittliche Auslastung pro Kern"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Prozentsatz der Zeit, in der die Festplatte mit I/O beschäftigt ist"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Prozentsatz der Zeit in jedem Zustand"
@@ -1284,13 +1316,20 @@ msgstr "Prozess gestartet"
msgid "Public Key"
msgstr "Öffentlicher Schlüssel"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Warteschlangentiefe"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Ruhezeiten"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Lesen"
@@ -1602,7 +1641,7 @@ msgstr "Diese Aktion kann nicht rückgängig gemacht werden. Dadurch werden alle
msgid "This will permanently delete all selected records from the database."
msgstr "Dadurch werden alle ausgewählten Datensätze dauerhaft aus der Datenbank gelöscht."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Durchsatz von {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Empfangene Gesamtdatenmenge je Schnittstelle "
msgid "Total data sent for each interface"
msgstr "Gesendete Gesamtdatenmenge je Schnittstelle"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr "Gesamtzeit für Lese-/Schreibvorgänge (kann 100% überschreiten)"
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Hochladen"
msgid "Uptime"
msgstr "Betriebszeit"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Verwendet"
msgid "Users"
msgstr "Benutzer"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Auslastung"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Wert"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Ansicht"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Mehr anzeigen"
@@ -1858,7 +1908,9 @@ msgstr "Windows-Befehl"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Schreiben"

View File

@@ -204,10 +204,19 @@ msgstr "Average drops below <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Average exceeds <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Average number of I/O operations waiting to be serviced"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Average power consumption of GPUs"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Average queue to completion time per operation"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Average system-wide CPU utilization"
@@ -439,6 +448,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Copy env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Copy from"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Copy host"
@@ -594,12 +608,11 @@ msgstr "Disk unit"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Disk Usage"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Disk usage of {extraFsName}"
@@ -893,6 +906,21 @@ msgstr "HTTP Method"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP method: POST, GET, or HEAD (default: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O Await"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O Time"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O Utilization"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1202,6 +1230,10 @@ msgstr "Payload format"
msgid "Per-core average utilization"
msgstr "Per-core average utilization"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Percent of time the disk is busy with I/O"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Percentage of time spent in each state"
@@ -1279,13 +1311,20 @@ msgstr "Process started"
msgid "Public Key"
msgstr "Public Key"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Queue Depth"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Quiet Hours"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Read"
@@ -1597,7 +1636,7 @@ msgstr "This action cannot be undone. This will permanently delete all current r
msgid "This will permanently delete all selected records from the database."
msgstr "This will permanently delete all selected records from the database."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Throughput of {extraFsName}"
@@ -1650,6 +1689,11 @@ msgstr "Total data received for each interface"
msgid "Total data sent for each interface"
msgstr "Total data sent for each interface"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr "Total time spent on read/write (can exceed 100%)"
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1770,7 +1814,7 @@ msgstr "Upload"
msgid "Uptime"
msgstr "Uptime"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1792,6 +1836,11 @@ msgstr "Used"
msgid "Users"
msgstr "Users"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Utilization"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Value"
@@ -1801,6 +1850,7 @@ msgid "View"
msgstr "View"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "View more"
@@ -1853,7 +1903,9 @@ msgstr "Windows command"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Write"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: es\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:27\n"
"Last-Translator: \n"
"Language-Team: Spanish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} disponible"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "El promedio cae por debajo de <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "El promedio excede <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Número medio de operaciones de E/S en espera de ser atendidas"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Consumo de energía promedio de GPUs"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Tiempo medio de cola hasta la finalización por operación"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Utilización promedio de CPU del sistema"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Copiar env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Copiar de"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Copiar host"
@@ -476,7 +490,7 @@ msgstr "Copiar YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Núcleo"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Diariamente"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Predeterminado"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Unidad de disco"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Uso de disco"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Uso de disco de {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Pantalla"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -870,7 +883,7 @@ msgstr "Estado"
#: src/components/routes/settings/layout.tsx
msgid "Heartbeat"
msgstr ""
msgstr "Latido"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat Monitoring"
@@ -898,6 +911,21 @@ msgstr "Método HTTP"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "Método HTTP: POST, GET o HEAD (predeterminado: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "Espera de E/S"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "Tiempo de E/S"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "Utilización de E/S"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Formato de carga útil (payload)"
msgid "Per-core average utilization"
msgstr "Uso promedio por núcleo"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Porcentaje de tiempo que el disco está ocupado con E/S"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Porcentaje de tiempo dedicado a cada estado"
@@ -1259,7 +1291,7 @@ msgstr "Puerto"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Puertos"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Proceso iniciado"
msgid "Public Key"
msgstr "Clave pública"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Profundidad de cola"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Horas de silencio"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Lectura"
@@ -1549,7 +1588,7 @@ msgstr "Tabla"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Pestañas"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Esta acción no se puede deshacer. Esto eliminará permanentemente todos
msgid "This will permanently delete all selected records from the database."
msgstr "Esto eliminará permanentemente todos los registros seleccionados de la base de datos."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Rendimiento de {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Datos totales recibidos por cada interfaz"
msgid "Total data sent for each interface"
msgstr "Datos totales enviados por cada interfaz"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Cargar"
msgid "Uptime"
msgstr "Tiempo de actividad"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Usado"
msgid "Users"
msgstr "Usuarios"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Utilización"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Valor"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Vista"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Ver más"
@@ -1858,7 +1908,9 @@ msgstr "Comando Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Escritura"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: fa\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:28\n"
"Last-Translator: \n"
"Language-Team: Persian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} در دسترس است"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "میانگین به زیر <0>{value}{0}</0> می‌افتد"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "میانگین از <0>{value}{0}</0> فراتر رفته است"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "میانگین تعداد عملیات ورودی/خروجی در انتظار سرویس"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "میانگین مصرف برق پردازنده‌های گرافیکی"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "میانگین زمان صف تا تکمیل به ازای هر عملیات"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "میانگین استفاده از CPU در کل سیستم"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "کپی متغیرهای محیط"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "کپی از"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "کپی میزبان"
@@ -476,7 +490,7 @@ msgstr "کپی YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "هسته"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "روزانه"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "پیش‌فرض"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "واحد دیسک"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "میزان استفاده از دیسک"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "میزان استفاده از دیسک {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "نمایش"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "متد HTTP"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "متد HTTP: POST، GET، یا HEAD (پیش‌فرض: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "انتظار ورودی/خروجی"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "زمان ورودی/خروجی"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "استفاده از ورودی/خروجی"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "فرمت پی‌لود"
msgid "Per-core average utilization"
msgstr "میانگین استفاده در هر هسته"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "درصد زمانی که دیسک مشغول عملیات ورودی/خروجی است"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "درصد زمان صرف شده در هر حالت"
@@ -1259,7 +1291,7 @@ msgstr "پورت"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "پورت‌ها"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "فرآیند شروع شد"
msgid "Public Key"
msgstr "کلید عمومی"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "عمق صف"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "ساعات آرام"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "خواندن"
@@ -1549,7 +1588,7 @@ msgstr "جدول"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "تب‌ها"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "این عمل قابل برگشت نیست. این کار تمام رک
msgid "This will permanently delete all selected records from the database."
msgstr "این کار تمام رکوردهای انتخاب شده را برای همیشه از پایگاه داده حذف خواهد کرد."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "توان عملیاتی {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "داده‌های کل دریافت شده برای هر رابط"
msgid "Total data sent for each interface"
msgstr "داده‌های کل ارسال شده برای هر رابط"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "آپلود"
msgid "Uptime"
msgstr "آپتایم"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "استفاده شده"
msgid "Users"
msgstr "کاربران"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "بهره‌وری"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "مقدار"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "مشاهده"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "مشاهده بیشتر"
@@ -1858,7 +1908,9 @@ msgstr "دستور Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "نوشتن"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: fr\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-06-08 15:20\n"
"Last-Translator: \n"
"Language-Team: French\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} disponible"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -48,7 +48,7 @@ msgstr "{count, plural, one {{countString} minute} other {{countString} minutes}
#: src/components/routes/system/info-bar.tsx
msgid "{threads, plural, one {# thread} other {# threads}}"
msgstr "{threads, plural, one {# fil} other {# fils}}"
msgstr "{threads, plural, one {# thread} other {# threads}}"
#: src/lib/utils.ts
msgid "1 hour"
@@ -57,11 +57,11 @@ msgstr "1 heure"
#. Load average
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
msgstr "1 min"
#: src/lib/utils.ts
msgid "1 minute"
msgstr ""
msgstr "1 minute"
#: src/lib/utils.ts
msgid "1 week"
@@ -74,7 +74,7 @@ msgstr "12 heures"
#. Load average
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
msgstr "15 min"
#: src/lib/utils.ts
msgid "24 hours"
@@ -87,7 +87,7 @@ msgstr "30 jours"
#. Load average
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
msgstr "5 min"
#. Table column
#: src/components/routes/settings/quiet-hours.tsx
@@ -95,14 +95,14 @@ msgstr ""
#: src/components/routes/system/smart-table.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Actions"
msgstr ""
msgstr "Actions"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/settings/heartbeat.tsx
#: src/components/routes/settings/quiet-hours.tsx
msgid "Active"
msgstr ""
msgstr "Active"
#: src/components/active-alerts.tsx
msgid "Active Alerts"
@@ -137,7 +137,7 @@ msgstr "Ajuster la largeur de la mise en page principale"
#: src/components/command-palette.tsx
#: src/components/navbar.tsx
msgid "Admin"
msgstr ""
msgstr "Admin"
#: src/components/systemd-table/systemd-table.tsx
msgid "After"
@@ -149,7 +149,7 @@ msgstr "Après avoir défini les variables d'environnement, redémarrez votre hu
#: src/components/systems-table/systems-table-columns.tsx
msgid "Agent"
msgstr ""
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
@@ -209,10 +209,19 @@ msgstr "La moyenne descend en dessous de <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "La moyenne dépasse <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Nombre moyen d'opérations d'E/S en attente d'être traitées"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Consommation d'énergie moyenne des GPUs"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Temps moyen de file d'attente jusqu'à l'achèvement par opération"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Utilisation moyenne du CPU à l'échelle du système"
@@ -239,7 +248,7 @@ msgstr "Bande passante"
#. Battery label in systems table header
#: src/components/systems-table/systems-table-columns.tsx
msgid "Bat"
msgstr ""
msgstr "Bat"
#: src/components/routes/system/charts/sensor-charts.tsx
#: src/lib/alerts.ts
@@ -280,7 +289,7 @@ msgstr "Binaire"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
msgstr "Bits (Kbps, Mbps, Gbps)"
#: src/components/systemd-table/systemd-table.tsx
msgid "Boot state"
@@ -289,7 +298,7 @@ msgstr "État de démarrage"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
msgstr "Bytes (KB/s, MB/s, GB/s)"
#: src/components/routes/system/charts/memory-charts.tsx
msgid "Cache / Buffers"
@@ -327,7 +336,7 @@ msgstr "Attention - perte de données potentielle"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
msgstr "Celsius (°C)"
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
@@ -339,7 +348,7 @@ msgstr "Modifier les options générales de l'application."
#: src/components/routes/system/charts/sensor-charts.tsx
msgid "Charge"
msgstr ""
msgstr "Charge"
#. Context: Battery state
#: src/lib/i18n.ts
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Copier env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Copier depuis"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Copier l'hôte"
@@ -476,13 +490,13 @@ msgstr "Copier YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Cœur"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "CPU"
msgstr ""
msgstr "CPU"
#: src/components/routes/system/cpu-sheet.tsx
msgid "CPU Cores"
@@ -540,7 +554,7 @@ msgstr "État actuel"
#. Power Cycles
#: src/components/routes/system/smart-table.tsx
msgid "Cycles"
msgstr ""
msgstr "Cycles"
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/quiet-hours.tsx
@@ -550,7 +564,7 @@ msgstr "Quotidien"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Par défaut"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -569,7 +583,7 @@ msgstr "Supprimer l'empreinte"
#: src/components/systemd-table/systemd-table.tsx
msgid "Description"
msgstr ""
msgstr "Description"
#: src/components/containers-table/containers-table.tsx
msgid "Detail"
@@ -599,19 +613,18 @@ msgstr "Unité disque"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Utilisation du disque"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Utilisation du disque de {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Affichage"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -628,7 +641,7 @@ msgstr "Entrée/Sortie réseau Docker"
#: src/components/command-palette.tsx
#: src/components/systemd-table/systemd-table.tsx
msgid "Documentation"
msgstr ""
msgstr "Documentation"
#. Context: System is down
#: src/components/alerts-history-columns.tsx
@@ -664,7 +677,7 @@ msgstr "Modifier {foo}"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/otp-forms.tsx
msgid "Email"
msgstr ""
msgstr "Email"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
@@ -759,7 +772,7 @@ msgstr "Exportez la configuration actuelle de vos systèmes."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
msgstr "Fahrenheit (°F)"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Failed"
@@ -841,11 +854,11 @@ msgstr "Général"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Global"
msgstr ""
msgstr "Global"
#: src/components/routes/system.tsx
msgid "GPU"
msgstr ""
msgstr "GPU"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "GPU Engines"
@@ -870,7 +883,7 @@ msgstr "Santé"
#: src/components/routes/settings/layout.tsx
msgid "Heartbeat"
msgstr ""
msgstr "Pulsation"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat Monitoring"
@@ -898,6 +911,21 @@ msgstr "Méthode HTTP"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "Méthode HTTP : POST, GET ou HEAD (par défaut : POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "Attente E/S"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "Temps E/S"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "Utilisation E/S"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -910,7 +938,7 @@ msgstr "Si vous avez perdu le mot de passe de votre compte administrateur, vous
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Docker image"
msgid "Image"
msgstr ""
msgstr "Image"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Inactive"
@@ -1015,7 +1043,7 @@ msgstr "Guide pour une installation manuelle"
#. Chart select field. Please try to keep this short.
#: src/components/routes/system/chart-card.tsx
msgid "Max 1 min"
msgstr ""
msgstr "Max 1 min"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/routes/system/info-bar.tsx
@@ -1110,7 +1138,7 @@ msgstr "Aucun système trouvé."
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/notifications.tsx
msgid "Notifications"
msgstr ""
msgstr "Notifications"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
@@ -1153,7 +1181,7 @@ msgstr "Écraser les alertes existantes"
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Page"
msgstr ""
msgstr "Page"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
@@ -1188,7 +1216,7 @@ msgstr "Passé"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Pause"
msgstr ""
msgstr "Pause"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Paused"
@@ -1207,13 +1235,17 @@ msgstr "Format de la charge utile"
msgid "Per-core average utilization"
msgstr "Utilisation moyenne par cœur"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Pourcentage de temps pendant lequel le disque est occupé par des E/S"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Pourcentage de temps passé dans chaque état"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Permanent"
msgstr ""
msgstr "Permanent"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Persistence"
@@ -1254,12 +1286,12 @@ msgstr "Veuillez vous connecter à votre compte"
#: src/components/add-system.tsx
msgid "Port"
msgstr ""
msgstr "Port"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Ports"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Processus démarré"
msgid "Public Key"
msgstr "Clé publique"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Profondeur de file d'attente"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Heures calmes"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Lecture"
@@ -1443,7 +1482,7 @@ msgstr "Détails du service"
#: src/components/routes/system.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Services"
msgstr ""
msgstr "Services"
#: src/components/routes/settings/general.tsx
msgid "Set percentage thresholds for meter colors."
@@ -1549,7 +1588,7 @@ msgstr "Tableau"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Onglets"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Cette action ne peut pas être annulée. Cela supprimera définitivement
msgid "This will permanently delete all selected records from the database."
msgstr "Ceci supprimera définitivement tous les enregistrements sélectionnés de la base de données."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Débit de {extraFsName}"
@@ -1626,7 +1665,7 @@ msgstr "Changer le thème"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
msgstr "Token"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -1645,7 +1684,7 @@ msgstr "Les tokens et les empreintes sont utilisés pour authentifier les connex
#: src/components/ui/chart.tsx
#: src/components/ui/chart.tsx
msgid "Total"
msgstr ""
msgstr "Total"
#: src/components/routes/system/network-sheet.tsx
msgid "Total data received for each interface"
@@ -1655,6 +1694,11 @@ msgstr "Données totales reçues pour chaque interface"
msgid "Total data sent for each interface"
msgstr "Données totales envoyées pour chaque interface"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr "Temps total passé en lecture/écriture (peut dépasser 100%)"
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1716,7 +1760,7 @@ msgstr "Déclenchement lorsque l'utilisation de tout disque dépasse un seuil"
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/system/smart-table.tsx
msgid "Type"
msgstr ""
msgstr "Type"
#: src/components/systemd-table/systemd-table.tsx
msgid "Unit file"
@@ -1775,7 +1819,7 @@ msgstr "Téléverser"
msgid "Uptime"
msgstr "Temps de fonctionnement"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Utilisé"
msgid "Users"
msgstr "Utilisateurs"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Utilisation"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Valeur"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Vue"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Voir plus"
@@ -1848,7 +1898,7 @@ msgstr "Lorsqu'il est activé, ce jeton permet aux agents de s'enregistrer autom
#: src/components/routes/settings/heartbeat.tsx
msgid "When using POST, each heartbeat includes a JSON payload with system status summary, list of down systems, and triggered alerts."
msgstr "En utilisant POST, chaque heartbeat inclut une charge utile JSON avec un résumé de l'état du sistema, la liste des systèmes en panne et les alertes déclenchées."
msgstr "En utilisant POST, chaque heartbeat inclut une charge utile JSON avec un résumé de l'état du système, la liste des systèmes en panne et les alertes déclenchées."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -1858,7 +1908,9 @@ msgstr "Commande Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Écriture"
@@ -1879,3 +1931,4 @@ msgstr "Oui"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Vos paramètres utilisateur ont été mis à jour."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: he\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:27\n"
"Last-Translator: \n"
"Language-Team: Hebrew\n"
"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} זמין"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "הממוצע יורד מתחת ל-<0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "הממוצע עולה על <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "מספר ממוצע של פעולות קלט/פלט הממתינות לטיפול"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "צריכת חשמל ממוצעת של GPUs"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "זמן ממוצע מהתור ועד להשלמה לכל פעולה"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "ניצול ממוצע כלל-מערכתי של CPU"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "העתק env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "העתק מ-"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "העתק מארח"
@@ -476,13 +490,13 @@ msgstr "העתק YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "ליבה"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "CPU"
msgstr "CPU"
msgstr ""
#: src/components/routes/system/cpu-sheet.tsx
msgid "CPU Cores"
@@ -550,7 +564,7 @@ msgstr "יומי"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "ברירת מחדל"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "יחידת דיסק"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "שימוש בדיסק"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "שימוש בדיסק של {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "תצוגה"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "שיטת HTTP"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "שיטת HTTP: POST, GET, או HEAD (ברירת מחדל: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "המתנת קלט/פלט"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "זמן קלט/פלט"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "ניצול קלט/פלט"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "פורמט מטען (Payload)"
msgid "Per-core average utilization"
msgstr "ניצול ממוצע לליבה"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "אחוז הזמן שבו הדיסק עסוק בפעולות קלט/פלט"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "אחוז הזמן המוקדש לכל מצב"
@@ -1259,7 +1291,7 @@ msgstr "פורט"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "פורטים"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "תהליך התחיל"
msgid "Public Key"
msgstr "מפתח ציבורי"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "עומק תור"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "שעות שקט"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "קריאה"
@@ -1549,7 +1588,7 @@ msgstr "טבלה"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "לשוניות"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "פעולה זו לא ניתנת לביטול. פעולה זו תמחק
msgid "This will permanently delete all selected records from the database."
msgstr "פעולה זו תמחק לצמיתות את כל הרשומות שנבחרו ממסד הנתונים."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "תפוקה של {extraFsName}"
@@ -1626,7 +1665,7 @@ msgstr "החלף ערכת נושא"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -1655,6 +1694,11 @@ msgstr "סך נתונים שהתקבלו עבור כל ממשק"
msgid "Total data sent for each interface"
msgstr "סך נתונים שנשלחו עבור כל ממשק"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "העלאה"
msgid "Uptime"
msgstr "זמן פעילות"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "בשימוש"
msgid "Users"
msgstr "משתמשים"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "ניצולת"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "ערך"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "צפה"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "צפה בעוד"
@@ -1858,7 +1908,9 @@ msgstr "פקודת Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "כתיבה"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: hr\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:28\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"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} dostupno"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Prosjek pada ispod <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Prosjek premašuje <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Prosječan broj I/O operacija koje čekaju na obradu"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Prosječna potrošnja energije grafičkog procesora"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Prosječno vrijeme od čekanja do završetka po operaciji"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Prosječna iskorištenost procesora u cijelom sustavu"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Kopiraj env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Kopiraj iz"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Kopiraj hosta"
@@ -476,7 +490,7 @@ msgstr "Kopiraj YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Jezgra"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Dnevno"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Zadano"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Mjerna jedinica za disk"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Iskorištenost Diska"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Iskorištenost diska od {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Prikaz"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "HTTP metoda"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP metoda: POST, GET ili HEAD (zadano: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O čekanje"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O vrijeme"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O iskorištenost"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Format korisnog tereta (Payload)"
msgid "Per-core average utilization"
msgstr "Prosječna iskorištenost po jezgri"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Postotak vremena u kojem je disk zauzet I/O operacijama"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Postotak vremena provedenog u svakom stanju"
@@ -1259,7 +1291,7 @@ msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Portovi"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Proces pokrenut"
msgid "Public Key"
msgstr "Javni Ključ"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Dubina reda"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Tihi sati"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Pročitaj"
@@ -1549,7 +1588,7 @@ msgstr "Tablica"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Kartice"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Ova radnja ne može se poništiti. Svi trenutni zapisi za {name} bit će
msgid "This will permanently delete all selected records from the database."
msgstr "Ovom radnjom će se trajno izbrisati svi odabrani zapisi iz baze podataka."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Protok {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Ukupni podaci primljeni za svako sučelje"
msgid "Total data sent for each interface"
msgstr "Ukupni podaci poslani za svako sučelje"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Otpremi"
msgid "Uptime"
msgstr "Vrijeme rada"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Iskorišteno"
msgid "Users"
msgstr "Korisnici"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Iskorištenost"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Vrijednost"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Prikaz"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Prikaži više"
@@ -1858,7 +1908,9 @@ msgstr "Windows naredba"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Piši"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: hu\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:27\n"
"Last-Translator: \n"
"Language-Team: Hungarian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} elérhető"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Az átlag esik <0>{value}{0}</0> alá"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Az átlag meghaladja a <0>{value}{0}</0> értéket"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Kiszolgálásra váró I/O műveletek átlagos száma"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "GPU-k átlagos energiafogyasztása"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Műveletenkénti átlagos várakozási és befejezési idő"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Rendszerszintű CPU átlagos kihasználtság"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Környezet másolása"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Másolás innen:"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Hoszt másolása"
@@ -476,7 +490,7 @@ msgstr "YAML másolása"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Mag"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Napi"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Alapértelmezett"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Lemez mértékegysége"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Lemezhasználat"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Lemezhasználat a {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Megjelenítés"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "HTTP metódus"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP metódus: POST, GET vagy HEAD (alapértelmezett: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O várakozás"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O idő"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O kihasználtság"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Payload formátum"
msgid "Per-core average utilization"
msgstr "Átlagos kihasználtság magonként"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Az az időtartam százalékban, amíg a lemez I/O műveletekkel van elfoglalva"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Az idő százalékos aránya minden állapotban"
@@ -1259,7 +1291,7 @@ msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Portok"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Folyamat elindítva"
msgid "Public Key"
msgstr "Nyilvános kulcs"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Várakozási sor mélysége"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Csendes órák"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Olvasás"
@@ -1549,7 +1588,7 @@ msgstr "Tábla"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Lapok"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Ezt a műveletet nem lehet visszavonni! Véglegesen törli a {name} öss
msgid "This will permanently delete all selected records from the database."
msgstr "Ez véglegesen törli az összes kijelölt bejegyzést az adatbázisból."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "A {extraFsName} átviteli teljesítménye"
@@ -1655,6 +1694,11 @@ msgstr "Összes fogadott adat minden interfészenként"
msgid "Total data sent for each interface"
msgstr "Összes elküldött adat minden interfészenként"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Feltöltés"
msgid "Uptime"
msgstr "Üzemidő"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Felhasznált"
msgid "Users"
msgstr "Felhasználók"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Kihasználtság"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Érték"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Nézet"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Továbbiak megjelenítése"
@@ -1858,7 +1908,9 @@ msgstr "Windows parancs"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Írás"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: id\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:28\n"
"Last-Translator: \n"
"Language-Team: Indonesian\n"
"Plural-Forms: nplurals=1; plural=0;\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} tersedia"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Rata-rata turun di bawah <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Rata-rata melebihi <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Jumlah rata-rata operasi I/O yang menunggu untuk dilayani"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Rata-rata konsumsi daya GPU"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Waktu rata-rata antrian hingga selesai per operasi"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Rata-rata utilisasi CPU seluruh sistem"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Salin env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Salin dari"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Salin host"
@@ -476,7 +490,7 @@ msgstr "Salin YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Inti"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -599,19 +613,18 @@ msgstr "Unit disk"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Penggunaan Disk"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Penggunaan disk dari {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Tampilan"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "Metode HTTP"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "Metode HTTP: POST, GET, atau HEAD (default: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr ""
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "Waktu I/O"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "Utilisasi I/O"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -910,7 +938,7 @@ msgstr "Jika anda kehilangan kata sandi untuk akun admin anda, anda dapat merese
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Docker image"
msgid "Image"
msgstr ""
msgstr "Gambar"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Inactive"
@@ -1207,6 +1235,10 @@ msgstr "Format payload"
msgid "Per-core average utilization"
msgstr "Rata-rata utilisasi per-inti"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Persentase waktu disk sibuk dengan I/O"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Persentase waktu yang dihabiskan di setiap status"
@@ -1259,7 +1291,7 @@ msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Port"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Proses dimulai"
msgid "Public Key"
msgstr "Kunci Publik"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Kedalaman Antrian"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Jam Tenang"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Baca"
@@ -1549,7 +1588,7 @@ msgstr "Tabel"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Tab"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Aksi ini tidak dapat di kembalikan. ini akan menghapus permanen semua re
msgid "This will permanently delete all selected records from the database."
msgstr "Ini akan menghapus secara permanen semua record yang dipilih dari database."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Throughput dari {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Total data yang diterima untuk setiap antarmuka"
msgid "Total data sent for each interface"
msgstr "Total data yang dikirim untuk setiap antarmuka"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Unggah"
msgid "Uptime"
msgstr "Waktu aktif"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Digunakan"
msgid "Users"
msgstr "Pengguna"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Utilisasi"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Nilai"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Lihat"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Lihat lebih banyak"
@@ -1858,7 +1908,9 @@ msgstr "Perintah Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Tulis"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: it\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-17 09:26\n"
"Last-Translator: \n"
"Language-Team: Italian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} disponibile"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -57,7 +57,7 @@ msgstr "1 ora"
#. Load average
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
msgstr "1 min"
#: src/lib/utils.ts
msgid "1 minute"
@@ -74,7 +74,7 @@ msgstr "12 ore"
#. Load average
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
msgstr "15 min"
#: src/lib/utils.ts
msgid "24 hours"
@@ -87,7 +87,7 @@ msgstr "30 giorni"
#. Load average
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
msgstr "5 min"
#. Table column
#: src/components/routes/settings/quiet-hours.tsx
@@ -209,10 +209,19 @@ msgstr "La media scende sotto <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "La media supera <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Numero medio di operazioni di I/O in attesa di essere servite"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Consumo energetico medio delle GPU"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Tempo medio dalla coda al completamento per operazione"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Utilizzo medio della CPU a livello di sistema"
@@ -239,7 +248,7 @@ msgstr "Larghezza di banda"
#. Battery label in systems table header
#: src/components/systems-table/systems-table-columns.tsx
msgid "Bat"
msgstr ""
msgstr "Batt"
#: src/components/routes/system/charts/sensor-charts.tsx
#: src/lib/alerts.ts
@@ -327,7 +336,7 @@ msgstr "Attenzione - possibile perdita di dati"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
msgstr "Celsius (°C)"
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Copia env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Copia da"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Copia host"
@@ -476,13 +490,13 @@ msgstr "Copia YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Interne"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "CPU"
msgstr ""
msgstr "CPU"
#: src/components/routes/system/cpu-sheet.tsx
msgid "CPU Cores"
@@ -550,7 +564,7 @@ msgstr "Giornaliero"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Predefinito"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Unità disco"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Utilizzo Disco"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Utilizzo del disco di {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Display"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -664,7 +677,7 @@ msgstr "Modifica {foo}"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/otp-forms.tsx
msgid "Email"
msgstr ""
msgstr "Email"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
@@ -759,7 +772,7 @@ msgstr "Esporta la configurazione attuale dei tuoi sistemi."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
msgstr "Fahrenheit (°F)"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Failed"
@@ -811,7 +824,7 @@ msgstr "Impronta digitale"
#: src/components/routes/system/smart-table.tsx
msgid "Firmware"
msgstr ""
msgstr "Firmware"
#: src/components/alerts/alerts-sheet.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
@@ -845,7 +858,7 @@ msgstr "Globale"
#: src/components/routes/system.tsx
msgid "GPU"
msgstr ""
msgstr "GPU"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "GPU Engines"
@@ -870,7 +883,7 @@ msgstr "Stato"
#: src/components/routes/settings/layout.tsx
msgid "Heartbeat"
msgstr ""
msgstr "Hearthbeat"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat Monitoring"
@@ -888,7 +901,7 @@ msgstr "Comando Homebrew"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr ""
msgstr "Host / IP"
#: src/components/routes/settings/heartbeat.tsx
msgid "HTTP Method"
@@ -898,6 +911,21 @@ msgstr "Metodo HTTP"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "Metodo HTTP: POST, GET o HEAD (predefinito: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "Attesa I/O"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "Tempo I/O"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "Utilizzo I/O"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1015,7 +1043,7 @@ msgstr "Istruzioni di configurazione manuale"
#. Chart select field. Please try to keep this short.
#: src/components/routes/system/chart-card.tsx
msgid "Max 1 min"
msgstr ""
msgstr "Max 1 min"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/routes/system/info-bar.tsx
@@ -1081,7 +1109,7 @@ msgstr "Unità rete"
#: src/components/systemd-table/systemd-table.tsx
#: src/components/systemd-table/systemd-table.tsx
msgid "No"
msgstr ""
msgstr "No"
#: src/components/command-palette.tsx
#: src/components/systemd-table/systemd-table.tsx
@@ -1168,7 +1196,7 @@ msgstr "Pagine / Impostazioni"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Password"
msgstr ""
msgstr "Password"
#: src/components/login/auth-form.tsx
msgid "Password must be at least 8 characters."
@@ -1207,6 +1235,10 @@ msgstr "Formato del payload"
msgid "Per-core average utilization"
msgstr "Utilizzo medio per core"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Percentuale di tempo in cui il disco è occupato con l'I/O"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Percentuale di tempo trascorso in ogni stato"
@@ -1259,7 +1291,7 @@ msgstr "Porta"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Porte"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Processo avviato"
msgid "Public Key"
msgstr "Chiave Pub"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Profondità coda"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Ore silenziose"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Lettura"
@@ -1345,7 +1384,7 @@ msgstr "Riprendi"
#: src/components/systems-table/systems-table-columns.tsx
msgctxt "Root disk label"
msgid "Root"
msgstr ""
msgstr "Root"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
@@ -1549,7 +1588,7 @@ msgstr "Tabella"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Schede"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1576,11 +1615,11 @@ msgstr "Temperature dei sensori di sistema"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr ""
msgstr "Test <0>URL</0>"
#: src/components/routes/settings/heartbeat.tsx
msgid "Test heartbeat"
msgstr ""
msgstr "Test Heartbeat"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
@@ -1602,7 +1641,7 @@ msgstr "Questa azione non può essere annullata. Questo eliminerà permanentemen
msgid "This will permanently delete all selected records from the database."
msgstr "Questo eliminerà permanentemente tutti i record selezionati dal database."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Throughput di {extraFsName}"
@@ -1626,7 +1665,7 @@ msgstr "Attiva/disattiva tema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
msgstr "Token"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -1655,6 +1694,11 @@ msgstr "Dati totali ricevuti per ogni interfaccia"
msgid "Total data sent for each interface"
msgstr "Dati totali inviati per ogni interfaccia"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Carica"
msgid "Uptime"
msgstr "Tempo di attività"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Utilizzato"
msgid "Users"
msgstr "Utenti"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Utilizzo"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Valore"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Vista"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Visualizza altro"
@@ -1858,7 +1908,9 @@ msgstr "Comando Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Scrittura"
@@ -1879,3 +1931,4 @@ msgstr "Sì"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Le impostazioni utente sono state aggiornate."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ja\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:27\n"
"Last-Translator: \n"
"Language-Team: Japanese\n"
"Plural-Forms: nplurals=1; plural=0;\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} が利用可能"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "平均が<0>{value}{0}</0>を下回っています"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "平均が<0>{value}{0}</0>を超えています"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "サービスを待機している I/O 操作の平均数"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "GPUの平均消費電力"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "操作ごとの平均キューから完了までの時間"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "システム全体の平均CPU使用率"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "環境変数をコピー"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "コピー元"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "ホストをコピー"
@@ -476,7 +490,7 @@ msgstr "YAMLをコピー"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "コア"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "毎日"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "デフォルト"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "ディスク単位"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "ディスク使用率"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "{extraFsName}のディスク使用率"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "表示"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "HTTP メソッド"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP メソッド: POST、GET、または HEAD (デフォルト: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O 待機"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O 時間"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O 利用率"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "ペイロード形式"
msgid "Per-core average utilization"
msgstr "コアごとの平均使用率"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "ディスクが I/O でビジー状態である時間の割合"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "各状態で費やした時間の割合"
@@ -1259,7 +1291,7 @@ msgstr "ポート"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "ポート"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "プロセス開始"
msgid "Public Key"
msgstr "公開鍵"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "キューの深さ"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "サイレント時間"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "読み取り"
@@ -1549,7 +1588,7 @@ msgstr "テーブル"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "タブ"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "この操作は元に戻せません。これにより、データベー
msgid "This will permanently delete all selected records from the database."
msgstr "これにより、選択したすべてのレコードがデータベースから完全に削除されます。"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName}のスループット"
@@ -1655,6 +1694,11 @@ msgstr "各インターフェースの総受信データ量"
msgid "Total data sent for each interface"
msgstr "各インターフェースの総送信データ量"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "アップロード"
msgid "Uptime"
msgstr "稼働時間"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "使用中"
msgid "Users"
msgstr "ユーザー"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "利用率"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "値"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "表示"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "もっと見る"
@@ -1858,7 +1908,9 @@ msgstr "Windows コマンド"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "書き込み"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ko\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:27\n"
"Last-Translator: \n"
"Language-Team: Korean\n"
"Plural-Forms: nplurals=1; plural=0;\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} 사용 가능"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "평균이 <0>{value}{0}</0> 아래로 떨어집니다"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "평균이 <0>{value}{0}</0>을(를) 초과합니다"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "서비스를 기다리는 평균 I/O 작업 수"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "GPU들의 평균 전원 사용량"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "작업당 평균 대기 후 완료 시간"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "시스템 전체의 평균 CPU 사용량"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "환경 복사"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "다음에서 복사"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "호스트 복사"
@@ -476,7 +490,7 @@ msgstr "YAML 복사"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "코어"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "매일"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "기본값"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "디스크 단위"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "디스크 사용량"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "{extraFsName}의 디스크 사용량"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "표시"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "HTTP 메서드"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP 메서드: POST, GET 또는 HEAD (기본값: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O 대기"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O 시간"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O 사용률"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "페이로드 형식"
msgid "Per-core average utilization"
msgstr "코어별 평균 사용률"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "디스크가 I/O로 바쁜 시간의 비율"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "각 상태에서 보낸 시간의 백분율"
@@ -1259,7 +1291,7 @@ msgstr "포트"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "포트"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "프로세스 시작됨"
msgid "Public Key"
msgstr "공개 키"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "대기열 깊이"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "조용한 시간"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "읽기"
@@ -1549,7 +1588,7 @@ msgstr "표"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr ""
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "이 작업은 되돌릴 수 없습니다. 데이터베이스에서 {name
msgid "This will permanently delete all selected records from the database."
msgstr "선택한 모든 레코드를 데이터베이스에서 영구적으로 삭제합니다."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName}의 처리량"
@@ -1655,6 +1694,11 @@ msgstr "각 인터페이스별 총합 다운로드 데이터량"
msgid "Total data sent for each interface"
msgstr "각 인터페이스별 총합 업로드 데이터량"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "업로드"
msgid "Uptime"
msgstr "가동 시간"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "사용됨"
msgid "Users"
msgstr "사용자"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "사용률"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "값"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "보기"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "더 보기"
@@ -1858,7 +1908,9 @@ msgstr "Windows 명령어"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "쓰기"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: nl\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:27\n"
"Last-Translator: \n"
"Language-Team: Dutch\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} beschikbaar"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Gemiddelde daalt onder <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Gemiddelde overschrijdt <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Gemiddeld aantal I/O-bewerkingen dat wacht op afhandeling"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Gemiddeld stroomverbruik van GPU's"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Gemiddelde tijd van wachtrij tot voltooiing per bewerking"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Gemiddeld systeembrede CPU-gebruik"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Env kopiëren"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Kopiëren van"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Kopieer host"
@@ -476,7 +490,7 @@ msgstr "YAML kopiëren"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Kern"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Dagelijks"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Standaard"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Schijf eenheid"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Schijfgebruik"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Schijfgebruik van {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Weergave"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "HTTP-methode"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP-methode: POST, GET of HEAD (standaard: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O Wachten"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O Tijd"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O Gebruik"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Payload-indeling"
msgid "Per-core average utilization"
msgstr "Gemiddeld gebruik per kern"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Percentage van de tijd dat de schijf bezig is met I/O"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Percentage tijd besteed in elke status"
@@ -1259,7 +1291,7 @@ msgstr "Poort"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Poorten"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Proces gestart"
msgid "Public Key"
msgstr "Publieke sleutel"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Wachtrijdiepte"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Stille uren"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Lezen"
@@ -1549,7 +1588,7 @@ msgstr "Tabel"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Tabbladen"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Deze actie kan niet ongedaan worden gemaakt. Dit zal alle huidige record
msgid "This will permanently delete all selected records from the database."
msgstr "Dit zal alle geselecteerde records verwijderen uit de database."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Doorvoer van {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Totaal ontvangen gegevens per interface"
msgid "Total data sent for each interface"
msgstr "Totaal verzonden gegevens per interface"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Uploaden"
msgid "Uptime"
msgstr "Actief"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Gebruikt"
msgid "Users"
msgstr "Gebruikers"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Gebruik"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Waarde"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Weergave"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Meer weergeven"
@@ -1858,7 +1908,9 @@ msgstr "Windows-commando"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Schrijven"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: no\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-26 23:25\n"
"Last-Translator: \n"
"Language-Team: Norwegian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} tilgjengelig"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -57,7 +57,7 @@ msgstr "1 time"
#. Load average
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
msgstr "1 min"
#: src/lib/utils.ts
msgid "1 minute"
@@ -74,7 +74,7 @@ msgstr "12 timer"
#. Load average
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
msgstr "15 min"
#: src/lib/utils.ts
msgid "24 hours"
@@ -87,7 +87,7 @@ msgstr "30 dager"
#. Load average
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
msgstr "5 min"
#. Table column
#: src/components/routes/settings/quiet-hours.tsx
@@ -137,7 +137,7 @@ msgstr "Juster bredden på hovedlayouten"
#: src/components/command-palette.tsx
#: src/components/navbar.tsx
msgid "Admin"
msgstr ""
msgstr "Admin"
#: src/components/systemd-table/systemd-table.tsx
msgid "After"
@@ -149,7 +149,7 @@ msgstr "Etter å ha angitt miljøvariablene, start Beszel-huben på nytt for at
#: src/components/systems-table/systems-table-columns.tsx
msgid "Agent"
msgstr ""
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
@@ -209,10 +209,19 @@ msgstr "Gjennomsnittet faller under <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Gjennomsnittet overstiger <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Gjennomsnittlig antall I/O-operasjoner som venter på behandling"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Gjennomsnittlig strømforbruk for GPU-er"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Gjennomsnittlig tid fra kø til ferdigstillelse per operasjon"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Gjennomsnittlig CPU-utnyttelse for hele systemet"
@@ -280,7 +289,7 @@ msgstr "Binær"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
msgstr "Bits (Kbps, Mbps, Gbps)"
#: src/components/systemd-table/systemd-table.tsx
msgid "Boot state"
@@ -289,7 +298,7 @@ msgstr "Oppstartstilstand"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
msgstr "Bytes (KB/s, MB/s, GB/s)"
#: src/components/routes/system/charts/memory-charts.tsx
msgid "Cache / Buffers"
@@ -327,7 +336,7 @@ msgstr "Advarsel - potensielt tap av data"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
msgstr "Celsius (°C)"
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
@@ -352,7 +361,7 @@ msgstr "Diagraminnstillinger"
#: src/components/routes/system/info-bar.tsx
msgid "Chart width"
msgstr "Grafbredde"
msgstr "Diagrambredde"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Kopier env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Kopier fra"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Kopier vert"
@@ -476,13 +490,13 @@ msgstr "Kopier YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Kjerne"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "CPU"
msgstr ""
msgstr "CPU"
#: src/components/routes/system/cpu-sheet.tsx
msgid "CPU Cores"
@@ -550,7 +564,7 @@ msgstr "Daglig"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Standard"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -587,11 +601,11 @@ msgstr "Lader ut"
#: src/components/routes/system.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Disk"
msgstr ""
msgstr "Disk"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk I/O"
msgstr ""
msgstr "Disk I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
@@ -599,19 +613,18 @@ msgstr "Diskenhet"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Diskbruk"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Diskbruk av {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Vis"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -702,7 +715,7 @@ msgstr "Skriv inn ditt engangspassord."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Ephemeral"
msgstr "Flyktig"
msgstr "Midlertidig"
#: src/components/login/auth-form.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
@@ -759,7 +772,7 @@ msgstr "Eksporter din nåværende systemkonfigurasjon"
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
msgstr "Fahrenheit (°F)"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Failed"
@@ -781,7 +794,7 @@ msgstr "Kunne ikke lagre innstillingene"
#: src/components/routes/settings/heartbeat.tsx
msgid "Failed to send heartbeat"
msgstr "Kunne ikke sende heartbeat"
msgstr "Kunne ikke sende hjerteslag"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
@@ -803,7 +816,7 @@ msgstr "Mislyktes: {0}"
#: src/components/systemd-table/systemd-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Filter..."
msgstr ""
msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
@@ -841,11 +854,11 @@ msgstr "Generelt"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Global"
msgstr ""
msgstr "Global"
#: src/components/routes/system.tsx
msgid "GPU"
msgstr ""
msgstr "GPU"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "GPU Engines"
@@ -870,15 +883,15 @@ msgstr "Helse"
#: src/components/routes/settings/layout.tsx
msgid "Heartbeat"
msgstr ""
msgstr "Hjerteslag"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat Monitoring"
msgstr "Heartbeat-overvåking"
msgstr "Hjerteslagsovervåking"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat sent successfully"
msgstr "Heartbeat sendt"
msgstr "Hjerteslag sendt vellykket"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -898,6 +911,21 @@ msgstr "HTTP-metode"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP-metode: POST, GET eller HEAD (standard: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O-ventetid"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O-tid"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O-utnyttelse"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -910,7 +938,7 @@ msgstr "Dersom du har mistet passordet til admin-kontoen kan du nullstille det m
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Docker image"
msgid "Image"
msgstr ""
msgstr "Image"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Inactive"
@@ -1188,7 +1216,7 @@ msgstr "Fortid"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Pause"
msgstr ""
msgstr "Pause"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Paused"
@@ -1200,20 +1228,24 @@ msgstr "Pauset ({pausedSystemsLength})"
#: src/components/routes/settings/heartbeat.tsx
msgid "Payload format"
msgstr "Nyttelastformat"
msgstr "Lastformat"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/cpu-sheet.tsx
msgid "Per-core average utilization"
msgstr "Gjennomsnittlig utnyttelse per kjerne"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Prosentandel av tiden disken er opptatt med I/O"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Prosentandel av tid brukt i hver tilstand"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Permanent"
msgstr ""
msgstr "Permanent"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Persistence"
@@ -1254,12 +1286,12 @@ msgstr "Vennligst logg inn på kontoen din"
#: src/components/add-system.tsx
msgid "Port"
msgstr ""
msgstr "Port"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Porter"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Prosess startet"
msgid "Public Key"
msgstr "Offentlig Nøkkel"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Kødybde"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Stille timer"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Lesing"
@@ -1418,7 +1457,7 @@ msgstr "Velg {foo}"
#: src/components/routes/settings/heartbeat.tsx
msgid "Send a single heartbeat ping to verify your endpoint is working."
msgstr "Send en enkelt heartbeat-ping for å bekrefte at endepunktet fungerer."
msgstr "Send en enkelt hjerteslag-ping for å verifisere at endepunktet ditt fungerer."
#: src/components/routes/settings/heartbeat.tsx
msgid "Send periodic outbound pings to an external monitoring service so you can monitor Beszel without exposing it to the internet."
@@ -1426,7 +1465,7 @@ msgstr "Send periodiske utgående pinger til en ekstern overvåkingstjeneste sli
#: src/components/routes/settings/heartbeat.tsx
msgid "Send test heartbeat"
msgstr "Send test-heartbeat"
msgstr "Send test-hjerteslag"
#: src/components/routes/system/charts/network-charts.tsx
msgid "Sent"
@@ -1451,7 +1490,7 @@ msgstr "Angi prosentvise terskler for målerfarger."
#: src/components/routes/settings/heartbeat.tsx
msgid "Set the following environment variables on your Beszel hub to enable heartbeat monitoring:"
msgstr "Angi følgende miljøvariabler på Beszel-huben din for å aktivere heartbeat-overvåking:"
msgstr "Sett følgende miljøvariabler på Beszel-huben din for å aktivere hjerteslagsovervåking:"
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
@@ -1497,7 +1536,7 @@ msgstr "Tilstand"
#: src/components/systems-table/systems-table.tsx
#: src/lib/alerts.ts
msgid "Status"
msgstr ""
msgstr "Status"
#: src/components/systemd-table/systemd-table-columns.tsx
msgid "Sub State"
@@ -1524,7 +1563,7 @@ msgstr "Swap-bruk"
#: src/components/systems-table/systems-table-columns.tsx
#: src/lib/alerts.ts
msgid "System"
msgstr ""
msgstr "System"
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "System load averages over time"
@@ -1549,7 +1588,7 @@ msgstr "Tabell"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Faner"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1559,7 +1598,7 @@ msgstr "Oppgaver"
#: src/components/routes/system/smart-table.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Temp"
msgstr ""
msgstr "Temp"
#: src/components/routes/system/charts/sensor-charts.tsx
#: src/lib/alerts.ts
@@ -1576,11 +1615,11 @@ msgstr "Temperaturer på system-sensorer"
#: src/components/routes/settings/notifications.tsx
msgid "Test <0>URL</0>"
msgstr ""
msgstr "Test <0>URL</0>"
#: src/components/routes/settings/heartbeat.tsx
msgid "Test heartbeat"
msgstr "Test-heartbeat"
msgstr "Test-hjerteslag"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
@@ -1602,7 +1641,7 @@ msgstr "Denne handlingen kan ikke omgjøres. Dette vil slette alle poster for {n
msgid "This will permanently delete all selected records from the database."
msgstr "Dette vil permanent slette alle valgte oppføringer fra databasen."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Gjennomstrømning av {extraFsName}"
@@ -1626,7 +1665,7 @@ msgstr "Tema av/på"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
msgstr "Token"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -1655,6 +1694,11 @@ msgstr "Totalt mottatt data for hvert grensesnitt"
msgid "Total data sent for each interface"
msgstr "Totalt sendt data for hvert grensesnitt"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr "Total tid brukt på lesing/skriving (kan overstige 100 %)"
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1716,7 +1760,7 @@ msgstr "Slår inn når forbruk av hvilken som helst disk overstiger en grensever
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/system/smart-table.tsx
msgid "Type"
msgstr ""
msgstr "Type"
#: src/components/systemd-table/systemd-table.tsx
msgid "Unit file"
@@ -1730,7 +1774,7 @@ msgstr "Enhetspreferanser"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
msgstr "Universal token"
#. Context: Battery state
#: src/lib/i18n.ts
@@ -1775,7 +1819,7 @@ msgstr "Last opp"
msgid "Uptime"
msgstr "Oppetid"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Brukt"
msgid "Users"
msgstr "Brukere"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Utnyttelse"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Verdi"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Visning"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Se mer"
@@ -1848,7 +1898,7 @@ msgstr "Når aktivert, tillater denne tokenen agenter å registrere seg selv ute
#: src/components/routes/settings/heartbeat.tsx
msgid "When using POST, each heartbeat includes a JSON payload with system status summary, list of down systems, and triggered alerts."
msgstr "Ved bruk av POST inkluderer hver heartbeat en JSON-nyttelast med systemstatussammendrag, liste over nede systemer og utløste varsler."
msgstr "Ved bruk av POST inkluderer hver hjerteslag en JSON-nyttelast med systemstatussammendrag, liste over nede systemer og utløste varsler."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -1858,7 +1908,9 @@ msgstr "Windows-kommando"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Skriving"
@@ -1879,3 +1931,4 @@ msgstr "Ja"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Dine brukerinnstillinger har blitt oppdatert."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: pl\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18: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"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} jest dostępna"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -40,7 +40,7 @@ msgstr "{count, plural, one {{countString} dzień} few {{countString} dni} many
#: src/lib/utils.ts
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
msgstr "{count, plural, one {godzinę} few {{countString} godziny} many {{countString} godzin} other {{countString} godziny}}"
msgstr "{count, plural, one {godzina} few {{countString} godziny} many {{countString} godzin} other {{countString} godziny}}"
#: src/lib/utils.ts
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
@@ -110,7 +110,7 @@ msgstr "Aktywne alerty"
#: src/components/systemd-table/systemd-table.tsx
msgid "Active state"
msgstr "Stan aktywny"
msgstr "Status aktywny"
#: src/components/add-system.tsx
#: src/components/add-system.tsx
@@ -145,7 +145,7 @@ msgstr "Po"
#: src/components/routes/settings/heartbeat.tsx
msgid "After setting the environment variables, restart your Beszel hub for changes to take effect."
msgstr "Po ustawieniu zmiennych środowiskowych zrestartuj hub Beszel, aby zmiany weszły w życie."
msgstr "Po ustawieniu zmiennych środowiskowych zrestartuj Beszel hub, aby zmiany zostały zaaplikowane."
#: src/components/systems-table/systems-table-columns.tsx
msgid "Agent"
@@ -209,10 +209,19 @@ msgstr "Średnia spada poniżej <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Średnia przekracza <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Średnia liczba operacji I/O oczekujących na obsłużenie"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Średnie zużycie energii przez GPU"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Średni czas od kolejki do zakończenia operacji"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Średnie wykorzystanie CPU w całym systemie"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Kopiuj env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Kopiuj z"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Kopiuj host"
@@ -476,7 +490,7 @@ msgstr "Kopiuj YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Główne"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Codziennie"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Domyślne"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Jednostka dysku"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Użycie dysku"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Wykorzystanie dysku {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Widok"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "Metoda HTTP"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "Metoda HTTP: POST, GET lub HEAD (domyślnie: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "Oczekiwanie I/O"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "Czas I/O"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "Użycie I/O"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1200,13 +1228,17 @@ msgstr "Wstrzymane ({pausedSystemsLength})"
#: src/components/routes/settings/heartbeat.tsx
msgid "Payload format"
msgstr "Format ładunku"
msgstr "Format payload'u"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/cpu-sheet.tsx
msgid "Per-core average utilization"
msgstr "Średnie wykorzystanie na rdzeń"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Procent czasu, w którym dysk jest zajęty operacjami I/O"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Procent czasu spędzonego w każdym stanie"
@@ -1259,7 +1291,7 @@ msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Porty"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Proces uruchomiony"
msgid "Public Key"
msgstr "Klucz publiczny"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Głębokość kolejki"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Godziny ciszy"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Odczyt"
@@ -1422,7 +1461,7 @@ msgstr "Wyślij pojedynczy ping heartbeat, aby sprawdzić, czy punkt końcowy dz
#: src/components/routes/settings/heartbeat.tsx
msgid "Send periodic outbound pings to an external monitoring service so you can monitor Beszel without exposing it to the internet."
msgstr "Wysyłaj okresowe pingi wychodzące do zewnętrznej usługi monitorowania, dzięki czemu możesz monitorować Beszel bez wystawiania go na działanie Internetu."
msgstr "Wysyłaj cyklicznie pingi wychodzące do zewnętrznej usługi monitorowania, co pozwala monitorować Beszel bez potrzeby udostępniania go publicznie w sieci."
#: src/components/routes/settings/heartbeat.tsx
msgid "Send test heartbeat"
@@ -1549,7 +1588,7 @@ msgstr "Tabela"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Karty"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1588,7 +1627,7 @@ msgstr "Testowe powiadomienie wysłane."
#: src/components/routes/settings/heartbeat.tsx
msgid "The overall status is <0>ok</0> when all systems are up, <1>warn</1> when alerts are triggered, and <2>error</2> when any system is down."
msgstr "Ogólny status to <0>ok</0>, gdy wszystkie systemy działają, <1>ostrzeżenie</1>, gdy wyzwalane są alerty, oraz <2>błąd</2>, gdy którykolwiek system nie działa."
msgstr "Ogólny status to <0>ok</0>, gdy wszystkie systemy działają, <1>ostrzeżenie</1>, gdy wyzwalane są alerty, oraz <2>błąd</2>, gdy którykolwiek z systemów nie działa."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
@@ -1602,7 +1641,7 @@ msgstr "Tej akcji nie można cofnąć. Spowoduje to trwałe usunięcie wszystkic
msgid "This will permanently delete all selected records from the database."
msgstr "Spowoduje to trwałe usunięcie wszystkich zaznaczonych rekordów z bazy danych."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Przepustowość {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Całkowita ilość danych odebranych dla każdego interfejsu"
msgid "Total data sent for each interface"
msgstr "Całkowita ilość danych wysłanych dla każdego interfejsu"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Wysyłanie"
msgid "Uptime"
msgstr "Czas pracy"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Używane"
msgid "Users"
msgstr "Użytkownicy"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Użycie"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Wartość"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Widok"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Zobacz więcej"
@@ -1848,7 +1898,7 @@ msgstr "Gdy jest włączony, ten token pozwala agentom na samodzielną rejestrac
#: src/components/routes/settings/heartbeat.tsx
msgid "When using POST, each heartbeat includes a JSON payload with system status summary, list of down systems, and triggered alerts."
msgstr "W przypadku korzystania z POST każdy heartbeat zawiera ładunek JSON z podsumowaniem statusu systemu, listą wyłączonych systemów i wyzwolonymi alertami."
msgstr "Przy użyciu metody POST każdy heartbeat zawiera payload JSON z podsumowaniem statusu systemu, listą niedostępnych systemów i wywołanymi alertami."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -1858,7 +1908,9 @@ msgstr "Polecenie Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Zapis"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: pt\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-08-04 18:12\n"
"Last-Translator: \n"
"Language-Team: Portuguese\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} disponível"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -48,7 +48,7 @@ msgstr "{count, plural, one {{countString} minuto} other {{countString} minutos}
#: src/components/routes/system/info-bar.tsx
msgid "{threads, plural, one {# thread} other {# threads}}"
msgstr ""
msgstr "{threads, plural, one {# thread} other {# threads}}"
#: src/lib/utils.ts
msgid "1 hour"
@@ -57,7 +57,7 @@ msgstr "1 hora"
#. Load average
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
msgstr "1 min"
#: src/lib/utils.ts
msgid "1 minute"
@@ -74,7 +74,7 @@ msgstr "12 horas"
#. Load average
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
msgstr "15 min"
#: src/lib/utils.ts
msgid "24 hours"
@@ -87,7 +87,7 @@ msgstr "30 dias"
#. Load average
#: src/components/routes/system/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
msgstr "5 min"
#. Table column
#: src/components/routes/settings/quiet-hours.tsx
@@ -137,7 +137,7 @@ msgstr "Ajustar a largura do layout principal"
#: src/components/command-palette.tsx
#: src/components/navbar.tsx
msgid "Admin"
msgstr ""
msgstr "Admin"
#: src/components/systemd-table/systemd-table.tsx
msgid "After"
@@ -209,10 +209,19 @@ msgstr "A média cai abaixo de <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "A média excede <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Número médio de operações de E/S à espera de serem atendidas"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Consumo médio de energia pelas GPU's"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Tempo médio de fila até à conclusão por operação"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Utilização média de CPU em todo o sistema"
@@ -239,7 +248,7 @@ msgstr "Largura de Banda"
#. Battery label in systems table header
#: src/components/systems-table/systems-table-columns.tsx
msgid "Bat"
msgstr ""
msgstr "Bat"
#: src/components/routes/system/charts/sensor-charts.tsx
#: src/lib/alerts.ts
@@ -280,7 +289,7 @@ msgstr "Binário"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
msgstr "Bits (Kbps, Mbps, Gbps)"
#: src/components/systemd-table/systemd-table.tsx
msgid "Boot state"
@@ -289,11 +298,11 @@ msgstr "Estado de inicialização"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
msgstr "Bytes (KB/s, MB/s, GB/s)"
#: src/components/routes/system/charts/memory-charts.tsx
msgid "Cache / Buffers"
msgstr ""
msgstr "Cache / Buffers"
#: src/components/systemd-table/systemd-table.tsx
msgid "Can reload"
@@ -327,7 +336,7 @@ msgstr "Cuidado - possível perda de dados"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
msgstr "Celsius (°C)"
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Copiar variáveis de ambiente"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Copiar de"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Copiar host"
@@ -476,13 +490,13 @@ msgstr "Copiar YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Núcleos"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "CPU"
msgstr ""
msgstr "CPU"
#: src/components/routes/system/cpu-sheet.tsx
msgid "CPU Cores"
@@ -550,7 +564,7 @@ msgstr "Diariamente"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Predefinido"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Unidade de disco"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Uso de Disco"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Uso de disco de {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Ecrã"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -664,7 +677,7 @@ msgstr "Editar {foo}"
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/otp-forms.tsx
msgid "Email"
msgstr ""
msgstr "Email"
#: src/components/routes/settings/notifications.tsx
msgid "Email notifications"
@@ -759,7 +772,7 @@ msgstr "Exporte a configuração atual dos seus sistemas."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
msgstr "Fahrenheit (°F)"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Failed"
@@ -811,7 +824,7 @@ msgstr "Impressão digital"
#: src/components/routes/system/smart-table.tsx
msgid "Firmware"
msgstr ""
msgstr "Firmware"
#: src/components/alerts/alerts-sheet.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
@@ -841,11 +854,11 @@ msgstr "Geral"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Global"
msgstr ""
msgstr "Global"
#: src/components/routes/system.tsx
msgid "GPU"
msgstr ""
msgstr "GPU"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "GPU Engines"
@@ -870,7 +883,7 @@ msgstr "Saúde"
#: src/components/routes/settings/layout.tsx
msgid "Heartbeat"
msgstr ""
msgstr "Pulso"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat Monitoring"
@@ -888,7 +901,7 @@ msgstr "Comando Homebrew"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr ""
msgstr "Host / IP"
#: src/components/routes/settings/heartbeat.tsx
msgid "HTTP Method"
@@ -898,6 +911,21 @@ msgstr "Método HTTP"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "Método HTTP: POST, GET ou HEAD (predefinido: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "Espera de E/S"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "Tempo de E/S"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "Utilização de E/S"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -993,7 +1021,7 @@ msgstr "Tentativa de login falhou"
#: src/components/containers-table/containers-table.tsx
#: src/components/navbar.tsx
msgid "Logs"
msgstr ""
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."
@@ -1207,6 +1235,10 @@ msgstr "Formato do payload"
msgid "Per-core average utilization"
msgstr "Utilização média por núcleo"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Percentagem de tempo em que o disco está ocupado com E/S"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Percentagem de tempo gasto em cada estado"
@@ -1259,7 +1291,7 @@ msgstr "Porta"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Portas"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Processo iniciado"
msgid "Public Key"
msgstr "Chave Pública"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Profundidade da fila"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Horas Silenciosas"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Ler"
@@ -1345,7 +1384,7 @@ msgstr "Retomar"
#: src/components/systems-table/systems-table-columns.tsx
msgctxt "Root disk label"
msgid "Root"
msgstr ""
msgstr "Raiz"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
@@ -1549,7 +1588,7 @@ msgstr "Tabela"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Separadores"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1559,7 +1598,7 @@ msgstr "Tarefas"
#: src/components/routes/system/smart-table.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Temp"
msgstr ""
msgstr "Temp"
#: src/components/routes/system/charts/sensor-charts.tsx
#: src/lib/alerts.ts
@@ -1602,7 +1641,7 @@ msgstr "Esta ação não pode ser desfeita. Isso excluirá permanentemente todos
msgid "This will permanently delete all selected records from the database."
msgstr "Isso excluirá permanentemente todos os registros selecionados do banco de dados."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Taxa de transferência de {extraFsName}"
@@ -1626,7 +1665,7 @@ msgstr "Alternar tema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
msgstr "Token"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -1645,7 +1684,7 @@ msgstr "Tokens e impressões digitais são usados para autenticar conexões WebS
#: src/components/ui/chart.tsx
#: src/components/ui/chart.tsx
msgid "Total"
msgstr ""
msgstr "Total"
#: src/components/routes/system/network-sheet.tsx
msgid "Total data received for each interface"
@@ -1655,10 +1694,15 @@ msgstr "Dados totais recebidos para cada interface"
msgid "Total data sent for each interface"
msgstr "Dados totais enviados para cada interface"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr "Tempo total gasto em leitura/escrita (pode exceder 100%)"
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
msgstr ""
msgstr "Total: {0}"
#: src/components/systemd-table/systemd-table.tsx
msgid "Triggered by"
@@ -1775,7 +1819,7 @@ msgstr "Carregar"
msgid "Uptime"
msgstr "Tempo de Atividade"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Usado"
msgid "Users"
msgstr "Usuários"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Utilização"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Valor"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Visual"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Ver mais"
@@ -1858,7 +1908,9 @@ msgstr "Comando Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Escrever"
@@ -1879,3 +1931,4 @@ msgstr "Sim"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "As configurações do seu usuário foram atualizadas."

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ru\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-02-21 09:46\n"
"PO-Revision-Date: 2026-04-28 05:14\n"
"Last-Translator: \n"
"Language-Team: Russian\n"
"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} доступно"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Среднее опускается ниже <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Среднее превышает <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Среднее количество операций ввода/вывода, ожидающих обслуживания"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Среднее потребление мощности всеми GPU"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Среднее время от очереди до завершения на одну операцию"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Среднее использование CPU по всей системе"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Скопировать env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Копировать из"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Копировать хост"
@@ -476,7 +490,7 @@ msgstr "Скопировать YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Процессор"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Ежедневно"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "По умолчанию"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Единицы измерения дисковой активности"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Использование диска"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Использование диска {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Отображение"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -845,7 +858,7 @@ msgstr "Глобально"
#: src/components/routes/system.tsx
msgid "GPU"
msgstr ""
msgstr "GPU"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "GPU Engines"
@@ -870,7 +883,7 @@ msgstr "Здоровье"
#: src/components/routes/settings/layout.tsx
msgid "Heartbeat"
msgstr ""
msgstr "Heartbeat"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat Monitoring"
@@ -898,6 +911,21 @@ msgstr "HTTP-метод"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP-метод: POST, GET или HEAD (по умолчанию: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "Ожидание ввода/вывода"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "Время ввода/вывода"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "Использование ввода/вывода"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Формат полезной нагрузки"
msgid "Per-core average utilization"
msgstr "Среднее использование на ядро"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Процент времени, в течение которого диск занят вводом/выводом"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Процент времени, проведенного в каждом состоянии"
@@ -1259,7 +1291,7 @@ msgstr "Порт"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Порты"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Процесс запущен"
msgid "Public Key"
msgstr "Ключ"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Глубина очереди"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Тихие часы"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Чтение"
@@ -1549,7 +1588,7 @@ msgstr "Таблица"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Вкладки"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Это действие не может быть отменено. Эт
msgid "This will permanently delete all selected records from the database."
msgstr "Это навсегда удалит все выбранные записи из базы данных."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Пропускная способность {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Общий объем полученных данных для кажд
msgid "Total data sent for each interface"
msgstr "Общий объем отправленных данных для каждого интерфейса"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr "Общее время, потраченное на чтение/запись (может превышать 100%)"
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Отдача"
msgid "Uptime"
msgstr "Время работы"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Использовано"
msgid "Users"
msgstr "Пользователи"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Использование"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Значение"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Вид"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Показать больше"
@@ -1858,7 +1908,9 @@ msgstr "Команда Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Запись"
@@ -1879,3 +1931,4 @@ msgstr "Да"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Ваши настройки пользователя были обновлены."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: sl\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18: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"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} na voljo"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Povprečje pade pod <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Povprečje presega <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Povprečno število I/O operacij, ki čakajo na obdelavo"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Povprečna poraba energije GPU"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Povprečni čas od čakalne vrste do zaključka na operacijo"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Povprečna CPU izkoriščenost v celotnem sistemu"
@@ -239,7 +248,7 @@ msgstr "Pasovna širina"
#. Battery label in systems table header
#: src/components/systems-table/systems-table-columns.tsx
msgid "Bat"
msgstr ""
msgstr "Baterija"
#: src/components/routes/system/charts/sensor-charts.tsx
#: src/lib/alerts.ts
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Kopiraj okoljske spremenljivke"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Kopiraj iz"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Kopiraj gostitelja"
@@ -476,7 +490,7 @@ msgstr "Kopiraj YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Jedro"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Dnevno"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Privzeto"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Enota diska"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Poraba diska"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Poraba diska za {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Zaslon"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "Metoda HTTP"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "Metoda HTTP: POST, GET ali HEAD (privzeto: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O čakanje"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O čas"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O izkoriščenost"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Oblika tovora (payload)"
msgid "Per-core average utilization"
msgstr "Povprečna izkoriščenost na jedro"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Odstotek časa, ko je disk zaposlen z I/O operacijami"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Odstotek časa, preživetega v vsakem stanju"
@@ -1259,7 +1291,7 @@ msgstr "Vrata"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Vrata"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Proces začet"
msgid "Public Key"
msgstr "Javni ključ"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Globina čakalne vrste"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Tihi čas"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Preberano"
@@ -1549,7 +1588,7 @@ msgstr "Tabela"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Zavihki"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Tega dejanja ni mogoče razveljaviti. To bo trajno izbrisalo vse trenutn
msgid "This will permanently delete all selected records from the database."
msgstr "To bo trajno izbrisalo vse izbrane zapise iz zbirke podatkov."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Prepustnost {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Skupni prejeti podatki za vsak vmesnik"
msgid "Total data sent for each interface"
msgstr "Skupni poslani podatki za vsak vmesnik"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Naloži"
msgid "Uptime"
msgstr "Čas delovanja"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Uporabljeno"
msgid "Users"
msgstr "Uporabniki"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Izkoriščenost"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Vrednost"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Pogled"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Prikaži več"
@@ -1858,7 +1908,9 @@ msgstr "Ukaz Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Pisanje"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: sr\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-02-23 15:11\n"
"PO-Revision-Date: 2026-04-22 14:14\n"
"Last-Translator: \n"
"Language-Team: Serbian (Cyrillic)\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"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} доступно"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Prosek pada ispod <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Просек премашује <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Просечан број I/O операција које чекају на обраду"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Просечна потрошња енергије графичких картица"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Просечно време од чекања до завршетка по операцији"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Просечна системска искоришћеност процесор"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Копирај env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Копирај из"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Копирај хоста"
@@ -476,7 +490,7 @@ msgstr "Копирај YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Језгро"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Дневно"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Подразумевано"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Диск јединица"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Употреба диска"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Употреба диска {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Приказ"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -845,7 +858,7 @@ msgstr "Глобално"
#: src/components/routes/system.tsx
msgid "GPU"
msgstr ""
msgstr "ГПЈ"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "GPU Engines"
@@ -898,6 +911,21 @@ msgstr "HTTP metod"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP metod: POST, GET ili HEAD (podrazumevano: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O чекање"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O време"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O искоришћеност"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Format korisnog opterećenja (payload)"
msgid "Per-core average utilization"
msgstr "Просечна употреба по језгру"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Проценат времена у којем је диск заузет I/O операцијама"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Проценат времена проведеног у сваком стању"
@@ -1259,7 +1291,7 @@ msgstr "Порт"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Портови"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Процес покренут"
msgid "Public Key"
msgstr "Јавни кључ"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Дубина реда"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Тихи сати"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Читање"
@@ -1345,7 +1384,7 @@ msgstr "Настави"
#: src/components/systems-table/systems-table-columns.tsx
msgctxt "Root disk label"
msgid "Root"
msgstr ""
msgstr "Root"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
@@ -1549,7 +1588,7 @@ msgstr "Табела"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Картице"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Ова акција се не може опозвати. Ово ће т
msgid "This will permanently delete all selected records from the database."
msgstr "Ово ће трајно избрисати све изабране записе из базе података."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Проток {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Укупни подаци примљени за сваки интерф
msgid "Total data sent for each interface"
msgstr "Укупни подаци poslati за сваки интерфејс"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr "Укупно време проведено на читању/писању (може бити веће од 100%)"
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Отпреми"
msgid "Uptime"
msgstr "Време рада"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Коришћено"
msgid "Users"
msgstr "Корисници"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Искоришћеност"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Вредност"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Погледај"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Погледај више"
@@ -1858,7 +1908,9 @@ msgstr "Windows команда"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Писање"
@@ -1879,3 +1931,4 @@ msgstr "Да"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Ваша корисничка подешавања су ажурирана."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: sv\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:27\n"
"Last-Translator: \n"
"Language-Team: Swedish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} tillgänglig"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Genomsnittet sjunker under <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Genomsnittet överskrider <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Genomsnittligt antal I/O-operationer som väntar på att betjänas"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Genomsnittlig strömförbrukning för GPU:er"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Genomsnittlig tid i kö till färdigställande per operation"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Genomsnittlig systemomfattande CPU-användning"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Kopiera env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Kopiera från"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Kopiera värd"
@@ -476,7 +490,7 @@ msgstr "Kopiera YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Kärna"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Dagligen"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Standard"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Diskenhet"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Diskanvändning"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Diskanvändning av {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Visa"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -870,7 +883,7 @@ msgstr "Hälsa"
#: src/components/routes/settings/layout.tsx
msgid "Heartbeat"
msgstr ""
msgstr "Hjärtslag"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat Monitoring"
@@ -898,6 +911,21 @@ msgstr "HTTP-metod"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP-metod: POST, GET eller HEAD (standard: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O Väntan"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O Tid"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O Användning"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Nyttolastformat"
msgid "Per-core average utilization"
msgstr "Genomsnittlig användning per kärna"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Procent av tiden disken är upptagen med I/O"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Procentandel av tid spenderad i varje tillstånd"
@@ -1259,7 +1291,7 @@ msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Portar"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Process startad"
msgid "Public Key"
msgstr "Offentlig nyckel"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Kö-djup"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Tysta timmar"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Läs"
@@ -1549,7 +1588,7 @@ msgstr "Tabell"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Flikar"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Den här åtgärden kan inte ångras. Detta kommer permanent att ta bort
msgid "This will permanently delete all selected records from the database."
msgstr "Detta kommer permanent att ta bort alla valda poster från databasen."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Genomströmning av {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Totalt mottagen data för varje gränssnitt"
msgid "Total data sent for each interface"
msgstr "Totalt skickad data för varje gränssnitt"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Ladda upp"
msgid "Uptime"
msgstr "Drifttid"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Använt"
msgid "Users"
msgstr "Användare"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Användning"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Värde"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Visa"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Visa mer"
@@ -1858,7 +1908,9 @@ msgstr "Windows-kommando"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Skriv"

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: tr\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-02 13:16\n"
"PO-Revision-Date: 2026-05-30 22:33\n"
"Last-Translator: \n"
"Language-Team: Turkish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} mevcut"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Ortalama <0>{value}{0}</0> altına düşüyor"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Ortalama <0>{value}{0}</0> aşıyor"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Servis edilmeyi bekleyen ortalama G/Ç (I/O) işlemi sayısı"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "GPU ların ortalama güç tüketimi"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "İşlem başına ortalama kuyruktan tamamlanmaya kadar geçen süre"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Sistem genelinde ortalama CPU kullanımı"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Ortam değişkenlerini kopyala"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Şuradan kopyala"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Ana bilgisayarı kopyala"
@@ -476,7 +490,7 @@ msgstr "YAML'ı kopyala"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Çekirdek"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Günlük"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Varsayılan"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Disk birimi"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Disk Kullanımı"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "{extraFsName} disk kullanımı"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Görünüm"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -845,7 +858,7 @@ msgstr "Genel"
#: src/components/routes/system.tsx
msgid "GPU"
msgstr ""
msgstr "Ekran Kartı"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "GPU Engines"
@@ -870,7 +883,7 @@ msgstr "Sağlık"
#: src/components/routes/settings/layout.tsx
msgid "Heartbeat"
msgstr ""
msgstr "Sağlık Sinyali"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat Monitoring"
@@ -898,6 +911,21 @@ msgstr "HTTP Yöntemi"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP yöntemi: POST, GET veya HEAD (varsayılan: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "G/Ç Bekleme"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "G/Ç Süresi"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "G/Ç Kullanımı"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1046,7 +1074,7 @@ msgstr "Docker konteynerlerinin bellek kullanımı"
#. Device model
#: src/components/routes/system/smart-table.tsx
msgid "Model"
msgstr ""
msgstr "Model"
#: src/components/add-system.tsx
#: src/components/alerts-history-columns.tsx
@@ -1207,6 +1235,10 @@ msgstr "Yük (Payload) formatı"
msgid "Per-core average utilization"
msgstr "Çekirdek başına ortalama kullanım"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Diskin G/Ç işlemleriyle meşgul olduğu sürenin yüzdesi"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Her durumda harcanan zamanın yüzdesi"
@@ -1254,12 +1286,12 @@ msgstr "Lütfen hesabınıza giriş yapın"
#: src/components/add-system.tsx
msgid "Port"
msgstr ""
msgstr "Port"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Portlar"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Süreç başlatıldı"
msgid "Public Key"
msgstr "Genel Anahtar"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Kuyruk Derinliği"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Sessiz Saatler"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Oku"
@@ -1549,7 +1588,7 @@ msgstr "Tablo"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Sekmeler"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Bu işlem geri alınamaz. Bu, veritabanından {name} için tüm mevcut k
msgid "This will permanently delete all selected records from the database."
msgstr "Bu, seçilen tüm kayıtları veritabanından kalıcı olarak silecektir."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName} verimliliği"
@@ -1655,6 +1694,11 @@ msgstr "Her arayüz için alınan toplam veri"
msgid "Total data sent for each interface"
msgstr "Her arayüz için gönderilen toplam veri"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr "Okuma/yazma işlemlerinde harcanan toplam süre (100%’ü aşabilir)"
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Yükle"
msgid "Uptime"
msgstr "Çalışma Süresi"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Kullanıldı"
msgid "Users"
msgstr "Kullanıcılar"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Kullanım"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Değer"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Görüntüle"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Daha fazla göster"
@@ -1858,7 +1908,9 @@ msgstr "Windows komutu"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Yaz"
@@ -1879,3 +1931,4 @@ msgstr "Evet"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Kullanıcı ayarlarınız güncellendi."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: uk\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-05-08 11:22\n"
"Last-Translator: \n"
"Language-Team: Ukrainian\n"
"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} Доступно"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Середнє опускається нижче <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Середнє перевищує <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Середня кількість операцій вводу-виводу, що очікують на обслуговування"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Середнє енергоспоживання GPUs"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Середній час від черги до завершення на одну операцію"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Середнє використання CPU по всій системі"
@@ -239,7 +248,7 @@ msgstr "Пропускна здатність"
#. Battery label in systems table header
#: src/components/systems-table/systems-table-columns.tsx
msgid "Bat"
msgstr ""
msgstr "Батарея"
#: src/components/routes/system/charts/sensor-charts.tsx
#: src/lib/alerts.ts
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Копіювати env"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Копіювати з"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Копіювати хост"
@@ -476,7 +490,7 @@ msgstr "Копіювати YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Ядро"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Щодня"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "За замовчуванням"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Одиниця виміру диска"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Використання диска"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Використання диска {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Відображення"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -845,7 +858,7 @@ msgstr "Глобально"
#: src/components/routes/system.tsx
msgid "GPU"
msgstr ""
msgstr "Графічний процесор"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "GPU Engines"
@@ -870,7 +883,7 @@ msgstr "Здоров'я"
#: src/components/routes/settings/layout.tsx
msgid "Heartbeat"
msgstr ""
msgstr "Heartbeat"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat Monitoring"
@@ -898,6 +911,21 @@ msgstr "HTTP-метод"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP-метод: POST, GET або HEAD (за замовчуванням: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "Очікування вводу-виводу"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "Час вводу-виводу"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "Використання вводу-виводу"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Формат корисного навантаження"
msgid "Per-core average utilization"
msgstr "Середнє використання на ядро"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Відсоток часу, протягом якого диск зайнятий вводом-виводом"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Відсоток часу, проведеного в кожному стані"
@@ -1259,7 +1291,7 @@ msgstr "Порт"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Порти"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Процес запущено"
msgid "Public Key"
msgstr "Ключ"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Глибина черги"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Тихі години"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Читання"
@@ -1549,7 +1588,7 @@ msgstr "Таблиця"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Вкладки"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Цю дію не можна скасувати. Це назавжди в
msgid "This will permanently delete all selected records from the database."
msgstr "Це назавжди видалить усі вибрані записи з бази даних."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Пропускна здатність {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Загальний обсяг отриманих даних для ко
msgid "Total data sent for each interface"
msgstr "Загальний обсяг відправлених даних для кожного інтерфейсу"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr "Загальний час, витрачений на читання/запис (може перевищувати 100%)"
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Відвантажити"
msgid "Uptime"
msgstr "Час роботи"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Використано"
msgid "Users"
msgstr "Користувачі"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Використання"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Значення"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Вигляд"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Переглянути більше"
@@ -1858,7 +1908,9 @@ msgstr "Команда Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Запис"
@@ -1879,3 +1931,4 @@ msgstr "Так"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Ваші налаштування користувача були оновлені."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: vi\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:28\n"
"Last-Translator: \n"
"Language-Team: Vietnamese\n"
"Plural-Forms: nplurals=1; plural=0;\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} có sẵn"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "Trung bình giảm xuống dưới <0>{value}{0}</0>"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "Trung bình vượt quá <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "Số lượng trung bình các hoạt động I/O đang chờ được xử lý"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "Tiêu thụ điện năng trung bình của GPU"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "Thời gian trung bình từ khi xếp hàng đến khi hoàn thành mỗi hoạt động"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "Sử dụng CPU trung bình toàn hệ thống"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "Sao chép môi trường"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "Sao chép từ"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "Sao chép máy chủ"
@@ -476,7 +490,7 @@ msgstr "Sao chép YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "Lõi"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "Hàng ngày"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "Mặc định"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "Đơn vị đĩa"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "Sử dụng Đĩa"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "Sử dụng đĩa của {extraFsName}"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "Hiển thị"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "Phương thức HTTP"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "Phương thức HTTP: POST, GET hoặc HEAD (mặc định: POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O Chờ"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "Thời gian I/O"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "Sử dụng I/O"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "Định dạng tải trọng (payload)"
msgid "Per-core average utilization"
msgstr "Tỷ lệ sử dụng trung bình mỗi nhân"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "Phần trăm thời gian đĩa bận rộn với các hoạt động I/O"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "Phần trăm thời gian dành cho mỗi trạng thái"
@@ -1259,7 +1291,7 @@ msgstr "Cổng"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Cổng"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "Tiến trình đã khởi động"
msgid "Public Key"
msgstr "Khóa"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "Độ sâu hàng đợi"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "Giờ yên tĩnh"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "Đọc"
@@ -1549,7 +1588,7 @@ msgstr "Bảng"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "Tab"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "Hành động này không thể hoàn tác. Điều này sẽ xóa vĩnh
msgid "This will permanently delete all selected records from the database."
msgstr "Thao tác này sẽ xóa vĩnh viễn tất cả các bản ghi đã chọn khỏi cơ sở dữ liệu."
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "Thông lượng của {extraFsName}"
@@ -1655,6 +1694,11 @@ msgstr "Tổng dữ liệu nhận được cho mỗi giao diện"
msgid "Total data sent for each interface"
msgstr "Tổng dữ liệu gửi đi cho mỗi giao diện"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "Tải lên"
msgid "Uptime"
msgstr "Thời gian hoạt động"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "Đã sử dụng"
msgid "Users"
msgstr "Người dùng"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "Sử dụng"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Giá trị"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "Xem"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "Xem thêm"
@@ -1858,7 +1908,9 @@ msgstr "Lệnh Windows"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "Ghi"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: zh\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-01 17:14\n"
"PO-Revision-Date: 2026-05-07 01:51\n"
"Last-Translator: \n"
"Language-Team: Chinese Simplified\n"
"Plural-Forms: nplurals=1; plural=0;\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} 可用"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "平均值降至<0>{value}{0}</0>以下"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "平均值超过<0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "等待处理的 I/O 操作平均数量"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "GPU 平均能耗"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "每次操作的平均队列到完成时间"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "系统范围内的平均 CPU 使用率"
@@ -263,7 +272,7 @@ msgstr "之前"
#. placeholder {2}: alert.min
#: src/components/active-alerts.tsx
msgid "Below {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
msgstr "在过去{2, plural, one {# 分钟} other {# 分钟}}中低于{0}{1}"
msgstr "在过去{2, plural, one {# 分钟} other {# 分钟}}中低于{0}{1}"
#: src/components/login/auth-form.tsx
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "复制环境变量"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "复制自"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "复制主机名"
@@ -476,13 +490,13 @@ msgstr "复制 YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "核心"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "CPU"
msgstr ""
msgstr "CPU"
#: src/components/routes/system/cpu-sheet.tsx
msgid "CPU Cores"
@@ -550,7 +564,7 @@ msgstr "每日"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "默认"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "磁盘单位"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "磁盘使用"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "{extraFsName}的磁盘使用"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "显示"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -702,7 +715,7 @@ msgstr "输入您的一次性密码。"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Ephemeral"
msgstr "时"
msgstr "时"
#: src/components/login/auth-form.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
@@ -743,7 +756,7 @@ msgstr "退出活动状态"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Expires after one hour or on hub restart."
msgstr "一小时后或重新启动集线器时过期。"
msgstr "将在一小时后或Hub重启时失效。"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
@@ -781,7 +794,7 @@ msgstr "保存设置失败"
#: src/components/routes/settings/heartbeat.tsx
msgid "Failed to send heartbeat"
msgstr "发送 heartbeat 失败"
msgstr "心跳发送失败"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
@@ -845,7 +858,7 @@ msgstr "全局"
#: src/components/routes/system.tsx
msgid "GPU"
msgstr ""
msgstr "显卡"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "GPU Engines"
@@ -874,11 +887,11 @@ msgstr "心跳"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat Monitoring"
msgstr "Heartbeat 监控"
msgstr "心跳监控"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat sent successfully"
msgstr "Heartbeat 发送成功"
msgstr "心跳发送成功"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -898,6 +911,21 @@ msgstr "HTTP 方法"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP 方法POST、GET 或 HEAD (默认POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O 等待"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O 时间"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O 利用率"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "有效载荷 (Payload) 格式"
msgid "Per-core average utilization"
msgstr "每个核心的平均利用率"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "磁盘用于 I/O 操作的繁忙时间百分比"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "在每个状态下花费的时间百分比"
@@ -1259,7 +1291,7 @@ msgstr "端口"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "端口"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "进程启动"
msgid "Public Key"
msgstr "公钥"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "队列深度"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "静默时间"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "读取"
@@ -1382,7 +1421,7 @@ msgstr "保存设置"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Saved in the database and does not expire until you disable it."
msgstr "保存在数据库中,在您禁用之前不会过期。"
msgstr "保存在数据库中的数据,在您禁用之前不会过期。"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Schedule"
@@ -1418,15 +1457,15 @@ msgstr "选择 {foo}"
#: src/components/routes/settings/heartbeat.tsx
msgid "Send a single heartbeat ping to verify your endpoint is working."
msgstr "发送单个 heartbeat ping 以验证您的端点是否正常工作。"
msgstr "发送单个 心跳ping 以验证您的端点是否正常工作。"
#: src/components/routes/settings/heartbeat.tsx
msgid "Send periodic outbound pings to an external monitoring service so you can monitor Beszel without exposing it to the internet."
msgstr "定期向外部监控服务发送出站 ping以便您在不将 Beszel 暴露于互联网的情况下进行监控。"
msgstr "定期向外部监控服务发送外发探测请求,这样您便可以在不将其暴露于互联网的情况下对 Beszel 进行监控。"
#: src/components/routes/settings/heartbeat.tsx
msgid "Send test heartbeat"
msgstr "发送测试 heartbeat"
msgstr "发送测试 心跳"
#: src/components/routes/system/charts/network-charts.tsx
msgid "Sent"
@@ -1549,7 +1588,7 @@ msgstr "表格"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "标签页"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "此操作无法撤销。这将永久删除数据库中{name}的所有当
msgid "This will permanently delete all selected records from the database."
msgstr "这将永久删除数据库中所有选定的记录。"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName}的吞吐量"
@@ -1655,6 +1694,11 @@ msgstr "每个接口的总接收数据量"
msgid "Total data sent for each interface"
msgstr "每个接口的总发送数据量"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr "读写操作总耗时(可超过 100%"
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "上传"
msgid "Uptime"
msgstr "正常运行时间"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "已用"
msgid "Users"
msgstr "用户"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "利用率"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "值"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "视图"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "查看更多"
@@ -1858,7 +1908,9 @@ msgstr "Windows 安装命令"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "写入"
@@ -1879,3 +1931,4 @@ msgstr "是"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "您的用户设置已更新。"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: zh\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-04-05 18:28\n"
"Last-Translator: \n"
"Language-Team: Chinese Traditional, Hong Kong\n"
"Plural-Forms: nplurals=1; plural=0;\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} 可用"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -209,10 +209,19 @@ msgstr "平均值降至<0>{value}{0}</0>以下"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "平均值超過 <0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "等待服務的平均 I/O 操作數"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "GPU 的平均功耗"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "每次操作的平均隊列到完成時間"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "系統的平均 CPU 使用率"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "複製環境變數"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "複製自"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "複製主機"
@@ -476,7 +490,7 @@ msgstr "複製YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "核心"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -550,7 +564,7 @@ msgstr "每日"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "預設"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "磁碟單位"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "磁碟使用"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "{extraFsName} 的磁碟使用量"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "顯示"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -898,6 +911,21 @@ msgstr "HTTP 方法"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP 方法POST、GET 或 HEAD (預設POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O 等待"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O 時間"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O 利用率"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1207,6 +1235,10 @@ msgstr "負載 (Payload) 格式"
msgid "Per-core average utilization"
msgstr "每個核心的平均使用率"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "磁碟忙於 I/O 操作的時間百分比"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "在每個狀態下花費的時間百分比"
@@ -1259,7 +1291,7 @@ msgstr "端口"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "連接埠"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "進程啟動"
msgid "Public Key"
msgstr "公鑰"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "隊列深度"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "靜音時段"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "讀取"
@@ -1549,7 +1588,7 @@ msgstr "表格"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "分頁"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1602,7 +1641,7 @@ msgstr "此操作無法撤銷。這將永久刪除數據庫中{name}的所有當
msgid "This will permanently delete all selected records from the database."
msgstr "這將從資料庫中永久刪除所有選定的記錄。"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName}的吞吐量"
@@ -1655,6 +1694,11 @@ msgstr "每個介面的總接收資料量"
msgid "Total data sent for each interface"
msgstr "每個介面的總傳送資料量"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "上傳"
msgid "Uptime"
msgstr "正常運行時間"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "已用"
msgid "Users"
msgstr "用戶"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "利用率"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "值"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "檢視"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "查看更多"
@@ -1858,7 +1908,9 @@ msgstr "Windows 指令"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "寫入"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: zh\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-03-27 19:17\n"
"PO-Revision-Date: 2026-06-29 04:59\n"
"Last-Translator: \n"
"Language-Team: Chinese Traditional\n"
"Plural-Forms: nplurals=1; plural=0;\n"
@@ -22,7 +22,7 @@ msgstr ""
#: src/components/footer-repo-link.tsx
msgctxt "New version available"
msgid "{0} available"
msgstr ""
msgstr "{0} 現已推出"
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
#. placeholder {1}: table.getFilteredRowModel().rows.length
@@ -145,11 +145,11 @@ msgstr "之後"
#: src/components/routes/settings/heartbeat.tsx
msgid "After setting the environment variables, restart your Beszel hub for changes to take effect."
msgstr "設環境變數後,重新啟動您的 Beszel hub 以使更生效。"
msgstr "設環境變數後,重新啟動 Beszel Hub 以使更生效。"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Agent"
msgstr ""
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
@@ -209,10 +209,19 @@ msgstr "平均值降至<0>{value}{0}</0>以下"
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "平均值超過<0>{value}{0}</0>"
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Average number of I/O operations waiting to be serviced"
msgstr "等待服務的平均 I/O 操作數"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "Average power consumption of GPUs"
msgstr "GPU 的平均功耗"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "Average queue to completion time per operation"
msgstr "每次操作的平均隊列到完成時間"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Average system-wide CPU utilization"
msgstr "系統的平均 CPU 使用率"
@@ -444,6 +453,11 @@ msgctxt "Environment variables"
msgid "Copy env"
msgstr "複製環境變數"
#: src/components/alerts/alerts-sheet.tsx
msgctxt "Copy alerts from another system"
msgid "Copy from"
msgstr "複製自"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Copy host"
msgstr "複製主機"
@@ -476,13 +490,13 @@ msgstr "複製 YAML"
#: src/components/routes/system.tsx
msgctxt "Core system metrics"
msgid "Core"
msgstr ""
msgstr "核心指標"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "CPU"
msgstr ""
msgstr "CPU"
#: src/components/routes/system/cpu-sheet.tsx
msgid "CPU Cores"
@@ -550,7 +564,7 @@ msgstr "每日"
#: src/components/routes/system/info-bar.tsx
msgctxt "Default system layout option"
msgid "Default"
msgstr ""
msgstr "預設"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
@@ -599,19 +613,18 @@ msgstr "磁碟單位"
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/lib/alerts.ts
msgid "Disk Usage"
msgstr "磁碟使用量"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Disk usage of {extraFsName}"
msgstr "{extraFsName}的磁碟使用量"
#: src/components/routes/system/info-bar.tsx
msgctxt "Layout display options"
msgid "Display"
msgstr ""
msgstr "顯示"
#: src/components/routes/system/charts/cpu-charts.tsx
msgid "Docker CPU Usage"
@@ -682,11 +695,11 @@ msgstr "結束時間"
#: src/components/routes/settings/heartbeat.tsx
msgid "Endpoint URL"
msgstr "端點 URL"
msgstr "Endpoint URL"
#: src/components/routes/settings/heartbeat.tsx
msgid "Endpoint URL to ping (required)"
msgstr "要 ping 的端點 URL (必填)"
msgstr "要 Ping 的 Endpoint URL (必填)"
#: src/components/login/login.tsx
msgid "Enter email address to reset password"
@@ -781,7 +794,7 @@ msgstr "儲存設定失敗"
#: src/components/routes/settings/heartbeat.tsx
msgid "Failed to send heartbeat"
msgstr "發送 heartbeat 失敗"
msgstr "Heartbeat 發送失敗"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
@@ -807,7 +820,7 @@ msgstr "篩選..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
msgstr "Fingerprint"
#: src/components/routes/system/smart-table.tsx
msgid "Firmware"
@@ -845,7 +858,7 @@ msgstr "全域"
#: src/components/routes/system.tsx
msgid "GPU"
msgstr ""
msgstr "GPU"
#: src/components/routes/system/charts/gpu-charts.tsx
msgid "GPU Engines"
@@ -870,7 +883,7 @@ msgstr "健康狀態"
#: src/components/routes/settings/layout.tsx
msgid "Heartbeat"
msgstr "心跳 (Heartbeat)"
msgstr "Heartbeat"
#: src/components/routes/settings/heartbeat.tsx
msgid "Heartbeat Monitoring"
@@ -888,7 +901,7 @@ msgstr "Homebrew 指令"
#: src/components/add-system.tsx
msgid "Host / IP"
msgstr ""
msgstr "Host / IP"
#: src/components/routes/settings/heartbeat.tsx
msgid "HTTP Method"
@@ -898,6 +911,21 @@ msgstr "HTTP 方法"
msgid "HTTP method: POST, GET, or HEAD (default: POST)"
msgstr "HTTP 方法POST、GET 或 HEAD (預設POST)"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average operation time (iostat await)"
msgid "I/O Await"
msgstr "I/O 等待"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O total time spent on read/write"
msgid "I/O Time"
msgstr "I/O 時間"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Percent of time the disk is busy with I/O"
msgid "I/O Utilization"
msgstr "I/O 利用率"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Idle"
@@ -1200,13 +1228,17 @@ msgstr "已暫停 ({pausedSystemsLength})"
#: src/components/routes/settings/heartbeat.tsx
msgid "Payload format"
msgstr "有效載荷 (Payload) 格式"
msgstr "Payload 格式"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/cpu-sheet.tsx
msgid "Per-core average utilization"
msgstr "核心平均使用率"
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Percent of time the disk is busy with I/O"
msgstr "磁碟忙於 I/O 操作的時間百分比"
#: src/components/routes/system/cpu-sheet.tsx
msgid "Percentage of time spent in each state"
msgstr "狀態時間佔比"
@@ -1254,12 +1286,12 @@ msgstr "請登入您的帳號"
#: src/components/add-system.tsx
msgid "Port"
msgstr ""
msgstr "Port"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
msgid "Ports"
msgstr ""
msgstr "Port 映射"
#. Power On Time
#: src/components/routes/system/smart-table.tsx
@@ -1284,13 +1316,20 @@ msgstr "進程啟動"
msgid "Public Key"
msgstr "公鑰"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O average queue depth"
msgid "Queue Depth"
msgstr "隊列深度"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Quiet Hours"
msgstr "靜音時段"
#. Disk read
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Read"
msgstr "讀取"
@@ -1345,7 +1384,7 @@ msgstr "繼續"
#: src/components/systems-table/systems-table-columns.tsx
msgctxt "Root disk label"
msgid "Root"
msgstr ""
msgstr "Root"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
@@ -1418,15 +1457,15 @@ msgstr "選取{foo}"
#: src/components/routes/settings/heartbeat.tsx
msgid "Send a single heartbeat ping to verify your endpoint is working."
msgstr "發送單個 heartbeat ping 以驗證您的端點是否正常工作。"
msgstr "發送單次 Heartbeat Ping 以驗證您的 Endpoint 是否運作正常。"
#: src/components/routes/settings/heartbeat.tsx
msgid "Send periodic outbound pings to an external monitoring service so you can monitor Beszel without exposing it to the internet."
msgstr "定期向外部監控服務發送出站 ping以便您在不將 Beszel 暴露於網際網路的情況下進行監控。"
msgstr "定期發送 Outbound Ping 至外部監控服務,讓您無需將 Beszel 暴露於網際網路即可進行監控。"
#: src/components/routes/settings/heartbeat.tsx
msgid "Send test heartbeat"
msgstr "發送測試 heartbeat"
msgstr "發送測試 Heartbeat"
#: src/components/routes/system/charts/network-charts.tsx
msgid "Sent"
@@ -1451,7 +1490,7 @@ msgstr "設定儀表顏色的百分比閾值。"
#: src/components/routes/settings/heartbeat.tsx
msgid "Set the following environment variables on your Beszel hub to enable heartbeat monitoring:"
msgstr "在您的 Beszel hub 上設置以下環境變數以啟用 heartbeat 監控:"
msgstr "設定以下環境變數至 Beszel Hub 以啟用 Heartbeat 監控:"
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
@@ -1549,7 +1588,7 @@ msgstr "列表"
#: src/components/routes/system/info-bar.tsx
msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
msgstr "分頁"
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
@@ -1580,7 +1619,7 @@ msgstr "測試<0>URL</0>"
#: src/components/routes/settings/heartbeat.tsx
msgid "Test heartbeat"
msgstr "測試 heartbeat"
msgstr "測試 Heartbeat"
#: src/components/routes/settings/notifications.tsx
msgid "Test notification sent"
@@ -1588,7 +1627,7 @@ msgstr "已發送測試通知"
#: src/components/routes/settings/heartbeat.tsx
msgid "The overall status is <0>ok</0> when all systems are up, <1>warn</1> when alerts are triggered, and <2>error</2> when any system is down."
msgstr "當所有系統都正常運行時,整體狀態為 <0>ok</0>;當觸發警報時為 <1>警告</1>;當任何系統故障時為 <2>錯誤</2>。"
msgstr "當所有系統都正常運行時,整體狀態為 <0>正常</0>;當觸發警報時為 <1>警告</1>;當任何系統故障時為 <2>錯誤</2>。"
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
@@ -1602,7 +1641,7 @@ msgstr "此操作無法復原。這將永久刪除資料庫中{name}的所有當
msgid "This will permanently delete all selected records from the database."
msgstr "這將從資料庫中永久刪除所有選定的記錄。"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName}的傳輸速率"
@@ -1626,7 +1665,7 @@ msgstr "切換主題"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
msgstr "Token"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -1655,6 +1694,11 @@ msgstr "每個介面的總接收資料量"
msgid "Total data sent for each interface"
msgstr "每個介面的總傳送資料量"
#: src/components/routes/system/disk-io-sheet.tsx
msgctxt "Disk I/O"
msgid "Total time spent on read/write (can exceed 100%)"
msgstr ""
#. placeholder {0}: data.length
#: src/components/systemd-table/systemd-table.tsx
msgid "Total: {0}"
@@ -1775,7 +1819,7 @@ msgstr "上傳"
msgid "Uptime"
msgstr "運行時間"
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
#: src/components/routes/system/charts/gpu-charts.tsx
@@ -1797,6 +1841,11 @@ msgstr "已使用"
msgid "Users"
msgstr "使用者"
#: src/components/routes/system/charts/disk-charts.tsx
msgctxt "Disk I/O utilization"
msgid "Utilization"
msgstr "利用率"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "值"
@@ -1806,6 +1855,7 @@ msgid "View"
msgstr "檢視"
#: src/components/routes/system/cpu-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/network-sheet.tsx
msgid "View more"
msgstr "查看更多"
@@ -1848,7 +1898,7 @@ msgstr "啟用後,此 Token 可讓 Agent 自行註冊,無需預先在系統
#: src/components/routes/settings/heartbeat.tsx
msgid "When using POST, each heartbeat includes a JSON payload with system status summary, list of down systems, and triggered alerts."
msgstr "使用 POST 時,每個 heartbeat 都包含一個 JSON 有效載荷,其中包含系統狀態摘要、故障系統列表和觸發的警報。"
msgstr "使用 POST 時,每個 Heartbeat 都包含一個 JSON Payload內容涵蓋系統狀態概況、離線系統清單以及已觸發的警報。"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -1858,7 +1908,9 @@ msgstr "Windows 指令"
#. Disk write
#: src/components/routes/system/charts/disk-charts.tsx
#: src/components/routes/system/charts/extra-fs-charts.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
#: src/components/routes/system/disk-io-sheet.tsx
msgid "Write"
msgstr "寫入"
@@ -1879,3 +1931,4 @@ msgstr "是"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "已更新您的使用者設定"

View File

@@ -94,18 +94,6 @@ const Layout = () => {
document.documentElement.dir = direction
}, [direction])
useEffect(() => {
// refresh auth if not authenticated (required for trusted auth header)
if (!authenticated) {
pb.collection("users")
.authRefresh()
.then((res) => {
pb.authStore.save(res.token, res.record)
$authenticated.set(!!pb.authStore.isValid)
})
}
}, [])
return (
<DirectionProvider dir={direction}>
{!authenticated ? (

View File

@@ -7,6 +7,7 @@ declare global {
BASE_PATH: string
HUB_VERSION: string
HUB_URL: string
OAUTH_DISABLE_POPUP: boolean
}
}

View File

@@ -7,7 +7,7 @@
"module": "ESNext",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"baseUrl": ".",
// "baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},

View File

@@ -1,3 +1,31 @@
## 0.18.7
- Add more disk I/O metrics (utilization, read/write time, await, queue depth) (#1866)
- Add ability to copy alerts between systems (#1853)
- Add `SENSORS_TIMEOUT` environment variable (#1871)
- Replace `distatus/battery` with an internal implementation (#1872)
- Restrict universal token API to non-superuser accounts (#1870)
- Fix macOS ARM64 crashes by upgrading `gopsutil` to v4.26.3 (#1881, #796)
- Fix text size for system names in grid view (#1860)
- Fix NVMe capacity reporting for Apple SSDs (#1873)
- Fix Windows root disk detection when the executable is not on the root disk (#1863)
- Fix nested virtual filesystem inclusion in Docker when mounting host root (#1859)
- Fix OPNsense installation persistence by using the daemon user (#1880)
- Upgrade JS dependencies with dependabot security alerts (#1882)
- Upgrade PocketBase to latest version
## 0.18.6
- Add apple-touch-icon link to index.html (#1850)