Compare commits

...

12 Commits

60 changed files with 1082 additions and 207 deletions

View File

@@ -29,6 +29,7 @@ jobs:
# henrygd/beszel-agent:alpine
- image: henrygd/beszel-agent
dockerfile: ./internal/dockerfile_agent_alpine
flavor: latest=false
registry: docker.io
username_secret: DOCKERHUB_USERNAME
password_secret: DOCKERHUB_TOKEN
@@ -55,6 +56,7 @@ jobs:
# henrygd/beszel-agent-nvidia:slim
- image: henrygd/beszel-agent-nvidia
dockerfile: ./internal/dockerfile_agent_nvidia_slim
flavor: latest=false
platforms: linux/amd64,linux/arm64
registry: docker.io
username_secret: DOCKERHUB_USERNAME
@@ -123,6 +125,7 @@ jobs:
# ghcr.io/henrygd/beszel-agent-nvidia:slim
- image: ghcr.io/${{ github.repository }}/beszel-agent-nvidia
dockerfile: ./internal/dockerfile_agent_nvidia_slim
flavor: latest=false
platforms: linux/amd64,linux/arm64
registry: ghcr.io
username: ${{ github.actor }}
@@ -150,6 +153,7 @@ jobs:
# ghcr.io/henrygd/beszel-agent:alpine
- image: ghcr.io/${{ github.repository }}/beszel-agent
dockerfile: ./internal/dockerfile_agent_alpine
flavor: latest=false
registry: ghcr.io
username: ${{ github.actor }}
password_secret: GITHUB_TOKEN
@@ -159,7 +163,7 @@ jobs:
type=semver,pattern={{major}}.{{minor}}-alpine
type=semver,pattern={{major}}-alpine
# henrygd/beszel-agent (keep at bottom so it gets built after :alpine and gets the latest tag)
# henrygd/beszel-agent
- image: henrygd/beszel-agent
dockerfile: ./internal/dockerfile_agent
registry: docker.io
@@ -200,6 +204,8 @@ jobs:
uses: docker/metadata-action@v6
with:
images: ${{ matrix.image }}
# Variant images must not overwrite the standard image's latest tag.
flavor: ${{ matrix.flavor || 'latest=auto' }}
tags: ${{ matrix.tags }}
# https://github.com/docker/login-action

View File

@@ -201,12 +201,9 @@ func mdraidSmartStatus(health mdraidHealth) string {
if health.mismatchCnt > 0 {
return "WARNING"
}
// "check" scans for consistency problems without repairing mismatches.
// With no mismatches, keep it green while reporting progress attributes.
switch syncAction {
case "repair":
return "WARNING"
}
// "check" and "repair" are requested consistency scans, not evidence of
// array failure. With no health issues above, keep scrubbing green while
// reporting the sync action and progress attributes.
switch state {
case "clean", "active", "active-idle", "write-pending", "read-auto", "readonly":
return "PASSED"

View File

@@ -174,8 +174,25 @@ func TestMdraidSmartStatus(t *testing.T) {
if got := mdraidSmartStatus(mdraidHealth{arrayState: "clean", mismatchCnt: 1}); got != "WARNING" {
t.Fatalf("mdraidSmartStatus(clean+mismatch) = %q, want WARNING", got)
}
if got := mdraidSmartStatus(mdraidHealth{arrayState: "clean", syncAction: "repair"}); got != "WARNING" {
t.Fatalf("mdraidSmartStatus(repair) = %q, want WARNING", got)
for _, tc := range []struct {
name string
health mdraidHealth
want string
}{
{"clean", mdraidHealth{arrayState: "clean"}, "PASSED"},
{"active", mdraidHealth{arrayState: "active"}, "PASSED"},
{"mismatch", mdraidHealth{arrayState: "active", mismatchCnt: 1}, "WARNING"},
{"degraded", mdraidHealth{arrayState: "active", degraded: 1}, "FAILED"},
{"faulty member", mdraidHealth{arrayState: "active", faultyDisks: 1}, "FAILED"},
{"inactive", mdraidHealth{arrayState: "inactive"}, "FAILED"},
{"unknown", mdraidHealth{arrayState: "unknown"}, "UNKNOWN"},
} {
t.Run("repair/"+tc.name, func(t *testing.T) {
tc.health.syncAction = "repair"
if got := mdraidSmartStatus(tc.health); got != tc.want {
t.Fatalf("mdraidSmartStatus(%+v) = %q, want %s", tc.health, got, tc.want)
}
})
}
if got := mdraidSmartStatus(mdraidHealth{arrayState: "clean"}); got != "PASSED" {
t.Fatalf("mdraidSmartStatus(clean) = %q, want PASSED", got)

View File

@@ -11,6 +11,7 @@ import (
"strings"
"sync/atomic"
"testing"
"testing/synctest"
beszelTests "github.com/henrygd/beszel/internal/tests"
pbTests "github.com/pocketbase/pocketbase/tests"
@@ -533,6 +534,20 @@ func TestSendTestNotification(t *testing.T) {
for _, url := range []string{localURL, "smtp://user:pass@127.0.0.1/?fromAddress=sender@example.com&toAddresses=recipient@example.com", "mqtt://127.0.0.1/topic"} {
scenarios = append(scenarios, beszelTests.ApiScenario{
BeforeTestFunc: func(tb testing.TB, _ *pbTests.TestApp, e *core.ServeEvent) {
if !strings.HasPrefix(url, "mqtt://") {
return
}
// Keep the real MQTT rejection path, but advance its library's
// fixed timeout using virtual time instead of waiting 10 seconds.
e.Router.BindFunc(func(re *core.RequestEvent) error {
var err error
synctest.Test(tb.(*testing.T), func(t *testing.T) {
err = re.Next()
})
return err
})
},
Name: "readonly cannot send to " + url,
Method: http.MethodPost,
URL: "/api/beszel/test-notification",

View File

@@ -11,6 +11,7 @@ import (
"strings"
"sync/atomic"
"testing"
"testing/synctest"
"github.com/nicholas-fedor/shoutrrr/pkg/types"
"golang.org/x/net/dns/dnsmessage"
@@ -178,39 +179,45 @@ func TestPublicNotificationTCP(t *testing.T) {
} {
t.Run(rawURL, func(t *testing.T) {
t.Parallel()
// MQTT waits for a fixed library timeout even after a dial failure.
// Virtual time preserves the full send/cleanup path without that delay.
t.Run("internal destination", func(t *testing.T) {
err := sendPublicNotification(strings.ReplaceAll(rawURL, "HOST", "127.0.0.1"), "test")
if !errors.Is(err, errInternalDestination) {
t.Fatalf("expected blocked destination, got %v", err)
}
synctest.Test(t, func(t *testing.T) {
err := sendPublicNotification(strings.ReplaceAll(rawURL, "HOST", "127.0.0.1"), "test")
if !errors.Is(err, errInternalDestination) {
t.Fatalf("expected blocked destination, got %v", err)
}
})
})
t.Run("public destination uses injected dialer", func(t *testing.T) {
var calls atomic.Int32
stopped := errors.New("test dial stopped")
service, err := newPublicNotificationService(strings.ReplaceAll(rawURL, "HOST", "8.8.8.8"), types.SenderOptions{
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
calls.Add(1)
if network != "tcp" || !strings.HasPrefix(address, "8.8.8.8:") {
t.Errorf("unexpected dial: %s %s", network, address)
}
if err := checkNotificationAddress(address); err != nil {
t.Error(err)
}
return nil, stopped
},
synctest.Test(t, func(t *testing.T) {
var calls atomic.Int32
stopped := errors.New("test dial stopped")
service, err := newPublicNotificationService(strings.ReplaceAll(rawURL, "HOST", "8.8.8.8"), types.SenderOptions{
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
calls.Add(1)
if network != "tcp" || !strings.HasPrefix(address, "8.8.8.8:") {
t.Errorf("unexpected dial: %s %s", network, address)
}
if err := checkNotificationAddress(address); err != nil {
t.Error(err)
}
return nil, stopped
},
})
if err != nil {
t.Fatal(err)
}
if closer, ok := service.(io.Closer); ok {
defer closer.Close()
}
if err := service.Send("test", &types.Params{}); err == nil {
t.Fatal("expected dial failure")
}
if calls.Load() == 0 {
t.Fatal("custom dialer was not used")
}
})
if err != nil {
t.Fatal(err)
}
if closer, ok := service.(io.Closer); ok {
defer closer.Close()
}
if err := service.Send("test", &types.Params{}); err == nil {
t.Fatal("expected dial failure")
}
if calls.Load() == 0 {
t.Fatal("custom dialer was not used")
}
})
})
}

View File

@@ -12,7 +12,7 @@ RUN apk add --no-cache ca-certificates && update-ca-certificates
# Build
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./internal/cmd/agent
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./internal/cmd/agent
RUN rm -rf /tmp/*

View File

@@ -10,14 +10,14 @@ COPY . ./
# Build
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./internal/cmd/agent
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./internal/cmd/agent
RUN rm -rf /tmp/*
# --------------------------
# Final image: default scratch-based agent
# --------------------------
FROM alpine:3.23
FROM alpine:3.24
COPY --from=builder /agent /agent
# AMD GPU name lookup (used by agent on Linux when /usr/share/libdrm/amdgpu.ids is read)
@@ -28,4 +28,4 @@ RUN apk add --no-cache smartmontools zfs
# Ensure data persistence across container recreations
VOLUME ["/var/lib/beszel-agent"]
ENTRYPOINT ["/agent"]
ENTRYPOINT ["/agent"]

View File

@@ -10,13 +10,13 @@ COPY . ./
# Build
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./internal/cmd/agent
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./internal/cmd/agent
# --------------------------
# Final image
# Note: must cap_add: [CAP_PERFMON] and mount /dev/dri/ as volume
# --------------------------
FROM alpine:3.23
FROM alpine:3.24
COPY --from=builder /agent /agent

View File

@@ -10,7 +10,7 @@ COPY . ./
# Build
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -tags glibc -ldflags "-w -s" -o /agent ./internal/cmd/agent
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -tags glibc -ldflags "-w -s" -o /agent ./internal/cmd/agent
# --------------------------
# Smartmontools builder stage

View File

@@ -17,7 +17,7 @@ RUN set -eux; \
if [ "$TARGETARCH" = "arm" ] && [ -n "$TARGETVARIANT" ]; then \
export GOARM="${TARGETVARIANT#v}"; \
fi; \
CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH \
CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH \
go build -tags glibc -ldflags "-w -s" -o /agent ./internal/cmd/agent
# --------------------------

View File

@@ -17,7 +17,7 @@ RUN update-ca-certificates
# Build
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /beszel ./internal/cmd/hub
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /beszel ./internal/cmd/hub
# ? -------------------------
FROM scratch
@@ -31,4 +31,4 @@ VOLUME ["/beszel_data"]
EXPOSE 8090
ENTRYPOINT [ "/beszel" ]
CMD ["serve", "--http=0.0.0.0:8090"]
CMD ["serve", "--http=0.0.0.0:8090"]

View File

@@ -978,11 +978,18 @@ func TestAgentWebSocketIntegration(t *testing.T) {
}
}
// Verify system status
updatedSystemRecord, err := testApp.FindRecordById("systems", systemRecord.Id)
require.NoError(t, err)
status := updatedSystemRecord.GetString("status")
assert.Equal(t, tc.expectSystemStatus, status, "System status should match expected value")
// A connected WebSocket does not mean the hub has finished verifying
// the agent and updating the system. Wait for the database state rather
// than assuming that work completes within a fixed sleep under load.
var status string
require.EventuallyWithT(t, func(c *assert.CollectT) {
updatedSystemRecord, err := testApp.FindRecordById("systems", systemRecord.Id)
if !assert.NoError(c, err) {
return
}
status = updatedSystemRecord.GetString("status")
assert.Equal(c, tc.expectSystemStatus, status, "System status should match expected value")
}, 5*time.Second, 20*time.Millisecond)
t.Logf("%s - System status: %s, Fingerprint: %s", tc.description, status, finalFingerprint)
})
@@ -1142,42 +1149,43 @@ func TestMultipleSystemsWithSameUniversalToken(t *testing.T) {
// Verify system creation/reuse behavior
if tc.expectConnection {
// Count systems after connection
systemsAfter, err := testApp.FindRecordsByFilter("systems", "users ~ {:userId}", "", -1, 0, map[string]any{"userId": userRecord.Id})
require.NoError(t, err)
systemsAfterCount := len(systemsAfter)
expectedSystemsAfter := systemsBeforeCount
if tc.expectNewSystem {
// Should have created a new system
expectedSystemsAfter++
systemCount++
assert.Equal(t, systemsBeforeCount+1, systemsAfterCount, "Should have created a new system")
assert.Equal(t, systemCount, systemsAfterCount, "Total system count should match expected")
} else {
// Should have reused existing system
assert.Equal(t, systemsBeforeCount, systemsAfterCount, "Should not have created a new system")
assert.Equal(t, systemCount, systemsAfterCount, "Total system count should remain the same")
}
time.Sleep(20 * time.Millisecond)
// WebSocket connection precedes the hub's asynchronous system
// setup. Re-read all database state until setup is complete.
var systemId, status string
require.EventuallyWithT(t, func(c *assert.CollectT) {
systemsAfter, err := testApp.FindRecordsByFilter("systems", "users ~ {:userId}", "", -1, 0, map[string]any{"userId": userRecord.Id})
if !assert.NoError(c, err) {
return
}
assert.Len(c, systemsAfter, expectedSystemsAfter, "System creation/reuse should match expected behavior")
assert.Len(c, systemsAfter, systemCount, "Total system count should match expected")
// Verify that a fingerprint record exists for this fingerprint
fingerprints, err := testApp.FindRecordsByFilter("fingerprints", "token = {:token} && fingerprint = {:fingerprint}", "", -1, 0, map[string]any{
"token": universalToken,
"fingerprint": tc.agentFingerprint,
})
require.NoError(t, err)
require.Len(t, fingerprints, 1, "Should have exactly one fingerprint record for this token+fingerprint combination")
fingerprints, err := testApp.FindRecordsByFilter("fingerprints", "token = {:token} && fingerprint = {:fingerprint}", "", -1, 0, map[string]any{
"token": universalToken,
"fingerprint": tc.agentFingerprint,
})
if !assert.NoError(c, err) || !assert.Len(c, fingerprints, 1, "Should have exactly one fingerprint record for this token+fingerprint combination") {
return
}
fingerprint := fingerprints[0]
assert.Equal(t, universalToken, fingerprint.GetString("token"), "Fingerprint should have the universal token")
assert.Equal(t, tc.agentFingerprint, fingerprint.GetString("fingerprint"), "Fingerprint should match agent's fingerprint")
fingerprint := fingerprints[0]
assert.Equal(c, universalToken, fingerprint.GetString("token"), "Fingerprint should have the universal token")
assert.Equal(c, tc.agentFingerprint, fingerprint.GetString("fingerprint"), "Fingerprint should match agent's fingerprint")
// Verify system status
systemId := fingerprint.GetString("system")
system, err := testApp.FindRecordById("systems", systemId)
require.NoError(t, err)
status := system.GetString("status")
assert.Equal(t, tc.expectSystemStatus, status, "System status should match expected value")
systemId = fingerprint.GetString("system")
system, err := testApp.FindRecordById("systems", systemId)
if !assert.NoError(c, err) {
return
}
status = system.GetString("status")
assert.Equal(c, tc.expectSystemStatus, status, "System status should match expected value")
}, 5*time.Second, 20*time.Millisecond)
t.Logf("%s - System ID: %s, Status: %s, New System: %v", tc.description, systemId, status, tc.expectNewSystem)
}

View File

@@ -0,0 +1,159 @@
//go:build testing
package systems
import (
"context"
"crypto/ed25519"
"crypto/rand"
"net"
"sync/atomic"
"testing"
"time"
"github.com/fxamacker/cbor/v2"
"github.com/henrygd/beszel/internal/common"
"github.com/henrygd/beszel/internal/entities/monitor"
esystem "github.com/henrygd/beszel/internal/entities/system"
"github.com/henrygd/beszel/internal/hub/expirymap"
"github.com/pocketbase/pocketbase/core"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/ssh"
)
func TestSSHNetworkMonitorReconnectSync(t *testing.T) {
sys, app := newTestSystemWithHub(t)
sys.manager.zfsFetchMap = expirymap.New[zfsFetchState](time.Hour)
t.Cleanup(sys.manager.zfsFetchMap.StopCleaner)
sys.ctx = context.Background()
sys.Status = up
_, key, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
signer, err := ssh.NewSignerFromKey(key)
require.NoError(t, err)
config := &ssh.ServerConfig{NoClientAuth: true, ServerVersion: "SSH-2.0-beszel_0.20.0"}
config.AddHostKey(signer)
listener, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err)
t.Cleanup(func() { _ = listener.Close() })
sys.Host, sys.Port, err = net.SplitHostPort(listener.Addr().String())
require.NoError(t, err)
sys.manager.sshConfig = &ssh.ClientConfig{User: "test", HostKeyCallback: ssh.InsecureIgnoreHostKey(), Timeout: time.Second}
t.Cleanup(sys.closeSSHConnection)
requests := make(chan monitor.SyncRequest, 10)
var failSync atomic.Bool
go func() {
for {
conn, err := listener.Accept()
if err != nil {
return
}
go func() {
server, channels, reqs, err := ssh.NewServerConn(conn, config)
if err != nil {
_ = conn.Close()
return
}
defer server.Close()
go ssh.DiscardRequests(reqs)
for channel := range channels {
ch, reqs, err := channel.Accept()
if err != nil {
return
}
go func() {
defer ch.Close()
for req := range reqs {
if req.Type != "shell" {
_ = req.Reply(false, nil)
continue
}
_ = req.Reply(true, nil)
var request common.HubRequest[cbor.RawMessage]
if cbor.NewDecoder(ch).Decode(&request) != nil {
return
}
response := common.AgentResponse{}
switch request.Action {
case common.GetData:
response.SystemData = &esystem.CombinedData{}
case common.SyncNetworkMonitors:
var syncReq monitor.SyncRequest
if cbor.Unmarshal(request.Data, &syncReq) != nil {
return
}
requests <- syncReq
if failSync.Load() {
response.Error = "test sync failure"
} else {
response.Data, _ = cbor.Marshal(monitor.SyncResponse{})
}
}
_ = cbor.NewEncoder(ch).Encode(response)
_, _ = ch.SendRequest("exit-status", false, ssh.Marshal(struct{ Status uint32 }{0}))
return
}
}()
}
}()
}
}()
collection, err := app.FindCachedCollectionByNameOrId("network_monitors")
require.NoError(t, err)
probe := core.NewRecord(collection)
probe.Load(map[string]any{"system": sys.Id, "target": "localhost", "protocol": "tcp", "port": 80, "interval": 60, "enabled": true})
require.NoError(t, app.SaveNoValidate(probe))
fetch := func() {
t.Helper()
_, err := sys.fetchDataFromAgent(common.DataRequestOptions{})
require.NoError(t, err, "monitor sync failure must not fail stats fetching")
}
receive := func() monitor.SyncRequest {
t.Helper()
select {
case req := <-requests:
require.Equal(t, monitor.SyncActionReplace, req.Action)
return req
case <-time.After(time.Second):
t.Fatal("missing full monitor sync")
return monitor.SyncRequest{}
}
}
fetch()
require.Equal(t, probe.Id, receive().Configs[0].ID)
require.False(t, sys.monitorsNeedSync.Load())
fetch()
require.Empty(t, requests, "steady-state fetch must not resync")
// Simulate loss of the agent process/connection and its in-memory monitors.
require.NoError(t, sys.client.Load().Close())
fetch()
require.Equal(t, probe.Id, receive().Configs[0].ID)
require.False(t, sys.monitorsNeedSync.Load())
// Failed replacements are retried on the next successful stats fetch.
require.NoError(t, sys.client.Load().Close())
failSync.Store(true)
fetch()
receive()
require.True(t, sys.monitorsNeedSync.Load())
failSync.Store(false)
fetch()
receive()
require.False(t, sys.monitorsNeedSync.Load())
probe.Set("enabled", false)
require.NoError(t, app.SaveNoValidate(probe))
require.NoError(t, sys.client.Load().Close())
fetch()
require.Empty(t, receive().Configs, "empty replacement must clear stale monitors")
}
func TestPendingNetworkMonitorSyncQueryFailure(t *testing.T) {
sys, app := newTestSystemWithHub(t)
_, err := app.DB().NewQuery("DROP TABLE network_monitors").Execute()
require.NoError(t, err)
sys.monitorsNeedSync.Store(true)
sys.syncPendingNetworkMonitors()
require.True(t, sys.monitorsNeedSync.Load())
}

View File

@@ -6,6 +6,7 @@ import (
"net/http"
"net/http/httptest"
"strings"
"sync/atomic"
"testing"
"time"
@@ -13,6 +14,7 @@ import (
"github.com/fxamacker/cbor/v2"
"github.com/henrygd/beszel/internal/common"
"github.com/henrygd/beszel/internal/entities/monitor"
esystem "github.com/henrygd/beszel/internal/entities/system"
"github.com/henrygd/beszel/internal/hub/ws"
"github.com/lxzan/gws"
"github.com/pocketbase/pocketbase/core"
@@ -22,17 +24,31 @@ import (
type monitorSyncClient struct {
gws.BuiltinEventHandler
requests chan common.HubRequest[monitor.SyncRequest]
failSync atomic.Bool
}
func (c *monitorSyncClient) OnMessage(conn *gws.Conn, message *gws.Message) {
defer message.Close()
var req common.HubRequest[monitor.SyncRequest]
var req common.HubRequest[cbor.RawMessage]
if err := cbor.Unmarshal(message.Bytes(), &req); err != nil {
return
}
c.requests <- req
data, _ := cbor.Marshal(monitor.SyncResponse{})
response, _ := cbor.Marshal(common.AgentResponse{Id: req.Id, Data: data})
resp := common.AgentResponse{Id: req.Id}
if req.Action == common.GetData {
resp.SystemData = &esystem.CombinedData{}
} else {
var data monitor.SyncRequest
if err := cbor.Unmarshal(req.Data, &data); err != nil {
return
}
c.requests <- common.HubRequest[monitor.SyncRequest]{Id: req.Id, Action: req.Action, Data: data}
if c.failSync.Load() {
resp.Error = "test sync failure"
} else {
resp.Data, _ = cbor.Marshal(monitor.SyncResponse{})
}
}
response, _ := cbor.Marshal(resp)
_ = conn.WriteMessage(gws.OpcodeBinary, response)
}
@@ -57,7 +73,7 @@ func TestNetworkMonitorSyncSkipsOlderAgents(t *testing.T) {
}
func TestNetworkMonitorReconnectSync(t *testing.T) {
for _, change := range []string{"delete", "disable"} {
for _, change := range []string{"delete", "disable", "retry"} {
t.Run(change, func(t *testing.T) {
sys, app := newTestSystemWithHub(t)
record, err := app.FindRecordById("systems", sys.Id)
@@ -120,9 +136,33 @@ func TestNetworkMonitorReconnectSync(t *testing.T) {
}
}
client.failSync.Store(change == "retry")
initial := connect()
require.Len(t, initial.Configs, 1)
require.Equal(t, probe.Id, initial.Configs[0].ID)
if change == "retry" {
system, err := sm.GetSystem(sys.Id)
require.NoError(t, err)
require.Eventually(t, system.monitorsNeedSync.Load, time.Second, time.Millisecond)
// A second failed sync must not fail the stats fetch or clear pending state.
_, err = system.fetchDataFromAgent(common.DataRequestOptions{})
require.NoError(t, err)
require.True(t, system.monitorsNeedSync.Load())
require.Len(t, client.requests, 1)
<-client.requests
client.failSync.Store(false)
_, err = system.fetchDataFromAgent(common.DataRequestOptions{})
require.NoError(t, err)
require.False(t, system.monitorsNeedSync.Load())
require.Len(t, client.requests, 1)
retry := <-client.requests
require.Equal(t, monitor.SyncActionReplace, retry.Data.Action)
require.Equal(t, initial.Configs, retry.Data.Configs)
_, err = system.fetchDataFromAgent(common.DataRequestOptions{})
require.NoError(t, err)
require.Empty(t, client.requests, "successful sync must not repeat on every fetch")
return
}
require.NoError(t, sm.RemoveSystem(sys.Id))
if change == "delete" {
require.NoError(t, app.Delete(probe))

View File

@@ -2,6 +2,7 @@ package systems
import (
"context"
"fmt"
"time"
"github.com/henrygd/beszel"
@@ -9,6 +10,27 @@ import (
"github.com/henrygd/beszel/internal/entities/monitor"
)
// syncPendingNetworkMonitors runs on WebSocket connect and after successful stats
// fetches. Failed syncs retry on the next update without taking the system down.
func (sys *System) syncPendingNetworkMonitors() {
if !sys.monitorsNeedSync.Swap(false) {
return
}
if err := sys.syncAllNetworkMonitors(); err != nil {
sys.monitorsNeedSync.Store(true)
sys.manager.hub.Logger().Warn("failed to sync monitors to agent", "system", sys.Id, "err", err)
}
}
func (sys *System) syncAllNetworkMonitors() error {
configs, err := sys.manager.GetMonitorConfigsForSystem(sys.Id)
if err != nil {
return fmt.Errorf("failed to load monitors: %w", err)
}
// An empty set must also replace probes retained across a disconnect.
return sys.SyncNetworkMonitors(configs)
}
// SyncNetworkMonitors sends monitor configurations to the agent.
func (sys *System) SyncNetworkMonitors(configs []monitor.Config) error {
_, err := sys.syncNetworkMonitors(monitor.SyncRequest{Action: monitor.SyncActionReplace, Configs: configs})

View File

@@ -56,6 +56,9 @@ type System struct {
smartInterval time.Duration // Interval for periodic SMART data updates
zfsFetching atomic.Bool // True if ZFS pools are currently being fetched
zfsInterval time.Duration // Interval for periodic ZFS detail data updates
// A fresh connection needs a full monitor configuration sync.
monitorsNeedSync atomic.Bool
// Serialize persistence from scheduled updates and resumes through commit.
recordsMu sync.Mutex
// Protected by recordsMu; realtime reads don't consume probes.
@@ -630,7 +633,10 @@ func (sys *System) request(ctx context.Context, action common.WebSocketAction, r
err := sys.sshTransport.RequestWithRetry(ctx, action, req, dest, 1)
// Keep legacy SSH client/version fields in sync for other code paths.
if sys.sshTransport != nil {
sys.client.Store(sys.sshTransport.GetClient())
client := sys.sshTransport.GetClient()
if previous := sys.client.Swap(client); client != nil && client != previous {
sys.monitorsNeedSync.Store(true)
}
sys.agentVersion = sys.sshTransport.GetAgentVersion()
}
return err
@@ -688,6 +694,7 @@ func (sys *System) fetchDataFromAgent(options common.DataRequestOptions) (*syste
if sys.WsConn != nil && sys.WsConn.IsConnected() {
wsData, err := sys.fetchDataViaWebSocket(options)
if err == nil {
sys.syncPendingNetworkMonitors()
return wsData, nil
}
// close the WebSocket connection if error and try SSH
@@ -698,6 +705,7 @@ func (sys *System) fetchDataFromAgent(options common.DataRequestOptions) (*syste
if err != nil {
return nil, err
}
sys.syncPendingNetworkMonitors()
return sshData, nil
}
@@ -932,6 +940,7 @@ func (s *System) createSSHClient() error {
return err
}
s.agentVersion, _ = extractAgentVersion(string(client.Conn.ServerVersion()))
s.monitorsNeedSync.Store(true)
s.manager.resetFailedSmartFetchState(s.Id)
s.manager.resetFailedZfsFetchState(s.Id)
return nil

View File

@@ -349,23 +349,14 @@ func (sm *SystemManager) AddWebSocketSystem(systemId string, agentVersion semver
system := sm.NewSystem(systemId)
system.WsConn = wsConn
system.agentVersion = agentVersion
system.monitorsNeedSync.Store(true)
if err := sm.AddRecord(systemRecord, system); err != nil {
return err
}
// Sync network monitors to the newly connected agent
go func() {
configs, err := sm.GetMonitorConfigsForSystem(systemId)
if err != nil {
sm.hub.Logger().Warn("failed to load monitors for agent", "system", systemId, "err", err)
return
}
// An empty set must also replace any probes retained across a disconnect.
if err := system.SyncNetworkMonitors(configs); err != nil {
sm.hub.Logger().Warn("failed to sync monitors to agent", "system", systemId, "err", err)
}
}()
go system.syncPendingNetworkMonitors()
return nil
}

View File

@@ -1057,6 +1057,15 @@ func init() {
"required": true,
"system": false,
"type": "number"
},
{
"hidden": false,
"id": "bool2084032502",
"name": "updatable",
"presentable": false,
"required": false,
"system": false,
"type": "bool"
}
],
"indexes": [

View File

@@ -1,27 +0,0 @@
package migrations
import (
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
)
func init() {
m.Register(func(app core.App) error {
c, err := app.FindCollectionByNameOrId("zfs_pools")
if err != nil {
return err
}
c.Fields.Add(&core.TextField{Name: "display_name"})
c.Fields.Add(&core.BoolField{Name: "raw"})
return app.Save(c)
}, func(app core.App) error {
c, err := app.FindCollectionByNameOrId("zfs_pools")
if err != nil {
return err
}
c.Fields.RemoveByName("display_name")
c.Fields.RemoveByName("raw")
return app.Save(c)
})
}

View File

@@ -1,24 +0,0 @@
package migrations
import (
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
)
func init() {
m.Register(func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("containers")
if err != nil {
return err
}
collection.Fields.Add(&core.BoolField{Name: "updatable"})
return app.Save(collection)
}, func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("containers")
if err != nil {
return err
}
collection.Fields.RemoveByName("updatable")
return app.Save(collection)
})
}

View File

@@ -59,7 +59,11 @@ export const containerChartCols: ColumnDef<ContainerRecord>[] = [
const allSystems = $allSystemsById.get()
const systemNameA = allSystems[a.original.system]?.name ?? ""
const systemNameB = allSystems[b.original.system]?.name ?? ""
return systemNameA.localeCompare(systemNameB)
const primary = systemNameA.localeCompare(systemNameB)
if (primary !== 0) {
return primary
}
return a.original.name.localeCompare(b.original.name)
},
header: ({ column }) => <HeaderButton column={column} name={t`System`} Icon={ServerIcon} />,
cell: ({ getValue }) => {

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ar\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:46\n"
"PO-Revision-Date: 2026-09-18 19:22\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"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: bg\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Bulgarian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: cs\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Czech\n"
"Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 3;\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: da\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Danish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: de\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:46\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: German\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: el\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Greek\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: es\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Spanish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: fa\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:46\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: Persian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: fr\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: French\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: he\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Hebrew\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n==2 ? 1 : 2);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: hr\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:46\n"
"PO-Revision-Date: 2026-09-18 19:22\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"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: hu\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Hungarian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: id\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:46\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: Indonesian\n"
"Plural-Forms: nplurals=1; plural=0;\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: it\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Italian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ja\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Japanese\n"
"Plural-Forms: nplurals=1; plural=0;\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ko\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Korean\n"
"Plural-Forms: nplurals=1; plural=0;\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: nl\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Dutch\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: no\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Norwegian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: pl\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\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"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: pt\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\n"
"Last-Translator: \n"
"Language-Team: Portuguese\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ro\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 00:33\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: Romanian\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100>0 && n%100<20)) ? 1 : 2);\n"
@@ -30,6 +30,12 @@ msgstr ""
msgid "{0} of {1} row(s) selected."
msgstr "{0} din {1} rând(uri) selectat(e)."
#. placeholder {0}: selectedSystemIds.size
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "{0} selected"
msgstr ""
#: src/components/routes/system/info-bar.tsx
msgid "{cores, plural, one {# core} other {# cores}}"
msgstr ""
@@ -61,7 +67,7 @@ msgstr "1 oră"
#. 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"
@@ -78,7 +84,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"
@@ -91,7 +97,7 @@ msgstr "30 zile"
#. 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
@@ -121,6 +127,10 @@ msgstr "Stare activă"
#: src/components/add-system.tsx
#: src/components/navbar.tsx
#: src/components/navbar.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/quiet-hours.tsx
msgid "Add {foo}"
@@ -142,7 +152,7 @@ msgstr "Reglaţi lăţimea aspectului principal"
#: src/components/command-palette.tsx
#: src/components/navbar.tsx
msgid "Admin"
msgstr ""
msgstr "Admin"
#: src/components/systemd-table/systemd-table.tsx
msgid "After"
@@ -154,7 +164,7 @@ msgstr "După setarea variabilelor de mediu, reporniţi centrul Beszel pentru ca
#: 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
@@ -188,6 +198,7 @@ msgstr "Toate sistemele"
msgid "Are you sure you want to delete {name}?"
msgstr "Sigur vrei să ștergi {name}?"
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr "Ești sigur?"
@@ -245,6 +256,14 @@ msgstr "Utilizarea medie a {0}"
msgid "Average utilization of GPU engines"
msgstr ""
#: src/components/routes/system/charts/monitors-charts.tsx
msgid "Average, minimum, and maximum response time"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Avg 1h"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/navbar.tsx
msgid "Backups"
@@ -306,6 +325,19 @@ msgstr "Biți (Kbps, Mbps, Gbps)"
msgid "Boot state"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Bulk Add"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Bulk Add {foo}"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Bulk copy"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
@@ -327,6 +359,7 @@ msgstr ""
msgid "Can stop"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/systems-table/systems-table-columns.tsx
@@ -348,7 +381,7 @@ msgstr "Atenție - posibilă pierdere de date"
#: 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."
@@ -396,6 +429,7 @@ msgid "Checksum errors"
msgstr ""
#: src/components/containers-table/containers-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/system/smart-table.tsx
#: src/components/routes/system/storage-pools-table.tsx
#: src/components/routes/system/storage-pools-table.tsx
@@ -403,6 +437,14 @@ msgstr ""
msgid "Clear"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Clear all"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Clear matches"
msgstr ""
#: src/components/containers-table/containers-table.tsx
msgid "Click on a container to view more information."
msgstr ""
@@ -432,6 +474,10 @@ msgstr ""
msgid "Configure how you receive alert notifications."
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Configure response monitoring from this agent."
msgstr ""
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
@@ -457,6 +503,7 @@ msgstr ""
msgid "Containers"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Continue"
@@ -517,6 +564,10 @@ msgstr ""
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Copy to system"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
@@ -530,7 +581,7 @@ msgstr ""
#: 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"
@@ -630,6 +681,7 @@ msgstr ""
msgid "Default time period"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/system/smart-table.tsx
@@ -718,12 +770,14 @@ msgstr "Descarcă"
msgid "Duration"
msgstr "Durată"
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Edit"
msgstr "Editează"
#: src/components/add-system.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/routes/settings/quiet-hours.tsx
msgid "Edit {foo}"
msgstr "Editează {foo}"
@@ -732,7 +786,7 @@ msgstr "Editează {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"
@@ -772,6 +826,11 @@ msgstr ""
msgid "Ephemeral"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/heartbeat.tsx
@@ -844,6 +903,11 @@ msgstr ""
msgid "Failed to authenticate"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
msgid "Failed to delete monitors."
msgstr ""
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/quiet-hours.tsx
@@ -862,6 +926,10 @@ msgstr ""
msgid "Failed to update alert"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
msgid "Failed to update monitors."
msgstr ""
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
#: src/components/systemd-table/systemd-table.tsx
msgid "Failed: {0}"
@@ -872,6 +940,7 @@ msgid "Fans"
msgstr ""
#: src/components/containers-table/containers-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/system/chart-card.tsx
#: src/components/routes/system/smart-table.tsx
@@ -924,7 +993,7 @@ msgstr ""
#: src/components/routes/settings/quiet-hours.tsx
msgid "Global"
msgstr ""
msgstr "Global"
#: src/components/routes/system.tsx
msgid "GPU"
@@ -1011,14 +1080,25 @@ msgctxt "Docker image"
msgid "Image"
msgstr "Imagine"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Docker image"
msgid "Image update available"
msgstr ""
#: src/components/routes/settings/quiet-hours.tsx
msgid "Inactive"
msgstr "Inactiv"
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/heartbeat.tsx
msgid "Interval"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Interval (seconds)"
msgstr ""
#: src/components/login/auth-form.tsx
msgid "Invalid email address."
msgstr ""
@@ -1097,6 +1177,15 @@ msgstr "Jurnale"
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
msgstr ""
#: src/components/routes/system/charts/monitors-charts.tsx
msgctxt "Packet loss"
msgid "Loss"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Loss 1h"
msgstr ""
#: src/components/systemd-table/systemd-table.tsx
msgid "Main PID"
msgstr ""
@@ -1115,6 +1204,10 @@ msgstr ""
msgid "Max 1 min"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Max 1h"
msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/routes/system/info-bar.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -1141,9 +1234,23 @@ msgstr "Memorie Utilizată"
msgid "Memory usage of containers"
msgstr "Utilizarea memoriei de către containere"
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Min 1h"
msgstr ""
#. Device model
#: src/components/routes/system/smart-table.tsx
msgid "Model"
msgstr "Model"
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Monitor"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Monitors created"
msgstr ""
#: src/components/routes/system/storage-pools-table.tsx
@@ -1163,6 +1270,29 @@ msgstr "Nume"
msgid "Net"
msgstr "Rețea"
#: src/components/routes/system.tsx
msgid "Network"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Network Monitor"
msgstr ""
#: src/lib/alerts.ts
msgid "Network Monitor Loss"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/navbar.tsx
#: src/components/navbar.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/monitors.tsx
msgid "Network Monitors"
msgstr ""
#: src/components/routes/system/charts/network-charts.tsx
msgid "Network traffic of containers"
msgstr "Traficul de rețea al containerelor"
@@ -1197,6 +1327,7 @@ msgstr ""
#: src/components/containers-table/containers-table.tsx
#: src/components/containers-table/containers-table.tsx
#: src/components/containers-table/containers-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/system/smart-table.tsx
#: src/components/systemd-table/systemd-table.tsx
@@ -1207,6 +1338,7 @@ msgstr ""
msgid "No S.M.A.R.T. attributes available for this device."
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -1238,6 +1370,11 @@ msgstr ""
msgid "One or more containers are unhealthy"
msgstr ""
#. placeholder {0}: alert.value
#: src/components/active-alerts.tsx
msgid "One or more monitors exceed {0}% loss"
msgstr ""
#: src/lib/alerts.ts
msgid "One or more services are in a failed state"
msgstr ""
@@ -1251,6 +1388,7 @@ msgstr ""
msgid "One-time password"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -1272,6 +1410,11 @@ msgstr "Altele"
msgid "Overwrite existing alerts"
msgstr ""
#: src/components/routes/system/charts/monitors-charts.tsx
msgid "Packet loss (%)"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
@@ -1309,6 +1452,7 @@ msgstr ""
msgid "Past"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Pause"
msgstr "Suspendare"
@@ -1392,8 +1536,9 @@ msgid "Pool Usage"
msgstr ""
#: src/components/add-system.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Port"
msgstr ""
msgstr "Port"
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Container ports"
@@ -1418,6 +1563,11 @@ msgstr ""
msgid "Process started"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Protocol"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Public key"
msgstr ""
@@ -1503,10 +1653,20 @@ msgstr ""
msgid "Resolved"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/system/charts/monitors-charts.tsx
msgid "Response"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
msgid "Response time monitoring from agents."
msgstr ""
#: src/components/systemd-table/systemd-table.tsx
msgid "Restarts"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Resume"
msgstr ""
@@ -1539,6 +1699,7 @@ msgid "S.M.A.R.T. Self-Test"
msgstr ""
#: src/components/add-system.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Save {foo}"
msgstr ""
@@ -1575,6 +1736,11 @@ msgstr "Caută"
msgid "Search for systems or settings..."
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Search systems"
msgstr ""
#: src/components/routes/settings/heartbeat.tsx
msgid "Seconds between pings (default: 60)"
msgstr ""
@@ -1587,6 +1753,27 @@ msgstr ""
msgid "Select {foo}"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Select a system"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Select all"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Select matches"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Select row"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Select systems"
msgstr ""
#: src/components/routes/settings/heartbeat.tsx
msgid "Send a single heartbeat ping to verify your endpoint is working."
msgstr ""
@@ -1692,6 +1879,8 @@ msgstr ""
#: src/components/alerts-history-columns.tsx
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/navbar.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/quiet-hours.tsx
@@ -1716,6 +1905,8 @@ msgid "Systemd Services"
msgstr ""
#: src/components/navbar.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Systems"
msgstr "Sisteme"
@@ -1732,6 +1923,11 @@ msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Target"
msgstr ""
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
msgstr "Sarcini"
@@ -1779,6 +1975,7 @@ msgstr ""
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
@@ -1821,7 +2018,7 @@ msgstr ""
#: 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"
@@ -1839,7 +2036,7 @@ msgstr ""
#. 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"
@@ -1901,6 +2098,10 @@ msgstr ""
msgid "Triggers when memory usage exceeds a threshold"
msgstr ""
#: src/lib/alerts.ts
msgid "Triggers when one hour loss exceeds a threshold"
msgstr ""
#: src/lib/alerts.ts
msgid "Triggers when status switches between up and down"
msgstr ""
@@ -1960,6 +2161,7 @@ msgid "Update"
msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/system/smart-table.tsx
#: src/components/routes/system/storage-pools-table.tsx
#: src/components/systemd-table/systemd-table-columns.tsx

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ru\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:21\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"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: sl\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:22\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"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: sr\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:22\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"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: sv\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: Swedish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: th\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 00:33\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: Thai\n"
"Plural-Forms: nplurals=1; plural=0;\n"
@@ -30,6 +30,12 @@ msgstr ""
msgid "{0} of {1} row(s) selected."
msgstr ""
#. placeholder {0}: selectedSystemIds.size
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "{0} selected"
msgstr ""
#: src/components/routes/system/info-bar.tsx
msgid "{cores, plural, one {# core} other {# cores}}"
msgstr ""
@@ -121,6 +127,10 @@ msgstr ""
#: src/components/add-system.tsx
#: src/components/navbar.tsx
#: src/components/navbar.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/quiet-hours.tsx
msgid "Add {foo}"
@@ -188,6 +198,7 @@ msgstr ""
msgid "Are you sure you want to delete {name}?"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
@@ -245,6 +256,14 @@ msgstr ""
msgid "Average utilization of GPU engines"
msgstr ""
#: src/components/routes/system/charts/monitors-charts.tsx
msgid "Average, minimum, and maximum response time"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Avg 1h"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/navbar.tsx
msgid "Backups"
@@ -306,6 +325,19 @@ msgstr ""
msgid "Boot state"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Bulk Add"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Bulk Add {foo}"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Bulk copy"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
@@ -327,6 +359,7 @@ msgstr ""
msgid "Can stop"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/systems-table/systems-table-columns.tsx
@@ -396,6 +429,7 @@ msgid "Checksum errors"
msgstr ""
#: src/components/containers-table/containers-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/system/smart-table.tsx
#: src/components/routes/system/storage-pools-table.tsx
#: src/components/routes/system/storage-pools-table.tsx
@@ -403,6 +437,14 @@ msgstr ""
msgid "Clear"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Clear all"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Clear matches"
msgstr ""
#: src/components/containers-table/containers-table.tsx
msgid "Click on a container to view more information."
msgstr ""
@@ -432,6 +474,10 @@ msgstr ""
msgid "Configure how you receive alert notifications."
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Configure response monitoring from this agent."
msgstr ""
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
@@ -457,6 +503,7 @@ msgstr ""
msgid "Containers"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Continue"
@@ -517,6 +564,10 @@ msgstr ""
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Copy to system"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
@@ -630,6 +681,7 @@ msgstr ""
msgid "Default time period"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/system/smart-table.tsx
@@ -718,12 +770,14 @@ msgstr ""
msgid "Duration"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Edit"
msgstr ""
#: src/components/add-system.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/routes/settings/quiet-hours.tsx
msgid "Edit {foo}"
msgstr ""
@@ -772,6 +826,11 @@ msgstr ""
msgid "Ephemeral"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/heartbeat.tsx
@@ -844,6 +903,11 @@ msgstr ""
msgid "Failed to authenticate"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
msgid "Failed to delete monitors."
msgstr ""
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/quiet-hours.tsx
@@ -862,6 +926,10 @@ msgstr ""
msgid "Failed to update alert"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
msgid "Failed to update monitors."
msgstr ""
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
#: src/components/systemd-table/systemd-table.tsx
msgid "Failed: {0}"
@@ -872,6 +940,7 @@ msgid "Fans"
msgstr ""
#: src/components/containers-table/containers-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/system/chart-card.tsx
#: src/components/routes/system/smart-table.tsx
@@ -1011,14 +1080,25 @@ msgctxt "Docker image"
msgid "Image"
msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Docker image"
msgid "Image update available"
msgstr ""
#: src/components/routes/settings/quiet-hours.tsx
msgid "Inactive"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/heartbeat.tsx
msgid "Interval"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Interval (seconds)"
msgstr ""
#: src/components/login/auth-form.tsx
msgid "Invalid email address."
msgstr ""
@@ -1097,6 +1177,15 @@ msgstr ""
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
msgstr ""
#: src/components/routes/system/charts/monitors-charts.tsx
msgctxt "Packet loss"
msgid "Loss"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Loss 1h"
msgstr ""
#: src/components/systemd-table/systemd-table.tsx
msgid "Main PID"
msgstr ""
@@ -1115,6 +1204,10 @@ msgstr ""
msgid "Max 1 min"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Max 1h"
msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/routes/system/info-bar.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -1141,11 +1234,25 @@ msgstr ""
msgid "Memory usage of containers"
msgstr "การใช้หน่วยความจำของคอนเทนเนอร์"
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Min 1h"
msgstr ""
#. Device model
#: src/components/routes/system/smart-table.tsx
msgid "Model"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Monitor"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Monitors created"
msgstr ""
#: src/components/routes/system/storage-pools-table.tsx
msgid "Mountpoint"
msgstr ""
@@ -1163,6 +1270,29 @@ msgstr ""
msgid "Net"
msgstr ""
#: src/components/routes/system.tsx
msgid "Network"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Network Monitor"
msgstr ""
#: src/lib/alerts.ts
msgid "Network Monitor Loss"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/navbar.tsx
#: src/components/navbar.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/monitors.tsx
msgid "Network Monitors"
msgstr ""
#: src/components/routes/system/charts/network-charts.tsx
msgid "Network traffic of containers"
msgstr "การรับส่งข้อมูลเครือข่ายของคอนเทนเนอร์"
@@ -1197,6 +1327,7 @@ msgstr ""
#: src/components/containers-table/containers-table.tsx
#: src/components/containers-table/containers-table.tsx
#: src/components/containers-table/containers-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/system/smart-table.tsx
#: src/components/systemd-table/systemd-table.tsx
@@ -1207,6 +1338,7 @@ msgstr ""
msgid "No S.M.A.R.T. attributes available for this device."
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -1238,6 +1370,11 @@ msgstr ""
msgid "One or more containers are unhealthy"
msgstr ""
#. placeholder {0}: alert.value
#: src/components/active-alerts.tsx
msgid "One or more monitors exceed {0}% loss"
msgstr ""
#: src/lib/alerts.ts
msgid "One or more services are in a failed state"
msgstr ""
@@ -1251,6 +1388,7 @@ msgstr ""
msgid "One-time password"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -1272,6 +1410,11 @@ msgstr ""
msgid "Overwrite existing alerts"
msgstr ""
#: src/components/routes/system/charts/monitors-charts.tsx
msgid "Packet loss (%)"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
@@ -1309,6 +1452,7 @@ msgstr ""
msgid "Past"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Pause"
msgstr ""
@@ -1392,6 +1536,7 @@ msgid "Pool Usage"
msgstr ""
#: src/components/add-system.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Port"
msgstr ""
@@ -1418,6 +1563,11 @@ msgstr ""
msgid "Process started"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Protocol"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Public key"
msgstr ""
@@ -1503,10 +1653,20 @@ msgstr ""
msgid "Resolved"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/system/charts/monitors-charts.tsx
msgid "Response"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
msgid "Response time monitoring from agents."
msgstr ""
#: src/components/systemd-table/systemd-table.tsx
msgid "Restarts"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Resume"
msgstr ""
@@ -1539,6 +1699,7 @@ msgid "S.M.A.R.T. Self-Test"
msgstr ""
#: src/components/add-system.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Save {foo}"
msgstr ""
@@ -1575,6 +1736,11 @@ msgstr ""
msgid "Search for systems or settings..."
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Search systems"
msgstr ""
#: src/components/routes/settings/heartbeat.tsx
msgid "Seconds between pings (default: 60)"
msgstr ""
@@ -1587,6 +1753,27 @@ msgstr ""
msgid "Select {foo}"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Select a system"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Select all"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Select matches"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Select row"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Select systems"
msgstr ""
#: src/components/routes/settings/heartbeat.tsx
msgid "Send a single heartbeat ping to verify your endpoint is working."
msgstr ""
@@ -1692,6 +1879,8 @@ msgstr ""
#: src/components/alerts-history-columns.tsx
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/navbar.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/quiet-hours.tsx
@@ -1716,6 +1905,8 @@ msgid "Systemd Services"
msgstr ""
#: src/components/navbar.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Systems"
msgstr ""
@@ -1732,6 +1923,11 @@ msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Target"
msgstr ""
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
msgstr ""
@@ -1779,6 +1975,7 @@ msgstr ""
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
@@ -1901,6 +2098,10 @@ msgstr ""
msgid "Triggers when memory usage exceeds a threshold"
msgstr ""
#: src/lib/alerts.ts
msgid "Triggers when one hour loss exceeds a threshold"
msgstr ""
#: src/lib/alerts.ts
msgid "Triggers when status switches between up and down"
msgstr ""
@@ -1960,6 +2161,7 @@ msgid "Update"
msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/system/smart-table.tsx
#: src/components/routes/system/storage-pools-table.tsx
#: src/components/systemd-table/systemd-table-columns.tsx

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: tr\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: Turkish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ug\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 00:33\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: Uyghur\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -30,6 +30,12 @@ msgstr ""
msgid "{0} of {1} row(s) selected."
msgstr ""
#. placeholder {0}: selectedSystemIds.size
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "{0} selected"
msgstr ""
#: src/components/routes/system/info-bar.tsx
msgid "{cores, plural, one {# core} other {# cores}}"
msgstr ""
@@ -121,6 +127,10 @@ msgstr ""
#: src/components/add-system.tsx
#: src/components/navbar.tsx
#: src/components/navbar.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/quiet-hours.tsx
msgid "Add {foo}"
@@ -188,6 +198,7 @@ msgstr ""
msgid "Are you sure you want to delete {name}?"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
@@ -245,6 +256,14 @@ msgstr ""
msgid "Average utilization of GPU engines"
msgstr ""
#: src/components/routes/system/charts/monitors-charts.tsx
msgid "Average, minimum, and maximum response time"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Avg 1h"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/navbar.tsx
msgid "Backups"
@@ -306,6 +325,19 @@ msgstr ""
msgid "Boot state"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Bulk Add"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Bulk Add {foo}"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Bulk copy"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
@@ -327,6 +359,7 @@ msgstr ""
msgid "Can stop"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/systems-table/systems-table-columns.tsx
@@ -396,6 +429,7 @@ msgid "Checksum errors"
msgstr ""
#: src/components/containers-table/containers-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/system/smart-table.tsx
#: src/components/routes/system/storage-pools-table.tsx
#: src/components/routes/system/storage-pools-table.tsx
@@ -403,6 +437,14 @@ msgstr ""
msgid "Clear"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Clear all"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Clear matches"
msgstr ""
#: src/components/containers-table/containers-table.tsx
msgid "Click on a container to view more information."
msgstr ""
@@ -432,6 +474,10 @@ msgstr ""
msgid "Configure how you receive alert notifications."
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Configure response monitoring from this agent."
msgstr ""
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
msgid "Confirm password"
@@ -457,6 +503,7 @@ msgstr ""
msgid "Containers"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Continue"
@@ -517,6 +564,10 @@ msgstr ""
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Copy to system"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
@@ -630,6 +681,7 @@ msgstr ""
msgid "Default time period"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/system/smart-table.tsx
@@ -718,12 +770,14 @@ msgstr ""
msgid "Duration"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Edit"
msgstr ""
#: src/components/add-system.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/routes/settings/quiet-hours.tsx
msgid "Edit {foo}"
msgstr ""
@@ -772,6 +826,11 @@ msgstr ""
msgid "Ephemeral"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/heartbeat.tsx
@@ -844,6 +903,11 @@ msgstr ""
msgid "Failed to authenticate"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
msgid "Failed to delete monitors."
msgstr ""
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/quiet-hours.tsx
@@ -862,6 +926,10 @@ msgstr ""
msgid "Failed to update alert"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
msgid "Failed to update monitors."
msgstr ""
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
#: src/components/systemd-table/systemd-table.tsx
msgid "Failed: {0}"
@@ -872,6 +940,7 @@ msgid "Fans"
msgstr ""
#: src/components/containers-table/containers-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/system/chart-card.tsx
#: src/components/routes/system/smart-table.tsx
@@ -1011,14 +1080,25 @@ msgctxt "Docker image"
msgid "Image"
msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/containers-table/containers-table-columns.tsx
msgctxt "Docker image"
msgid "Image update available"
msgstr ""
#: src/components/routes/settings/quiet-hours.tsx
msgid "Inactive"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/heartbeat.tsx
msgid "Interval"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Interval (seconds)"
msgstr ""
#: src/components/login/auth-form.tsx
msgid "Invalid email address."
msgstr ""
@@ -1097,6 +1177,15 @@ msgstr ""
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
msgstr ""
#: src/components/routes/system/charts/monitors-charts.tsx
msgctxt "Packet loss"
msgid "Loss"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Loss 1h"
msgstr ""
#: src/components/systemd-table/systemd-table.tsx
msgid "Main PID"
msgstr ""
@@ -1115,6 +1204,10 @@ msgstr ""
msgid "Max 1 min"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Max 1h"
msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/routes/system/info-bar.tsx
#: src/components/systemd-table/systemd-table-columns.tsx
@@ -1141,11 +1234,25 @@ msgstr ""
msgid "Memory usage of containers"
msgstr "كونتېينېرلارنىڭ ئەسلەك ئىشلىتىشى"
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Min 1h"
msgstr ""
#. Device model
#: src/components/routes/system/smart-table.tsx
msgid "Model"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Monitor"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Monitors created"
msgstr ""
#: src/components/routes/system/storage-pools-table.tsx
msgid "Mountpoint"
msgstr ""
@@ -1163,6 +1270,29 @@ msgstr ""
msgid "Net"
msgstr ""
#: src/components/routes/system.tsx
msgid "Network"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Network Monitor"
msgstr ""
#: src/lib/alerts.ts
msgid "Network Monitor Loss"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/navbar.tsx
#: src/components/navbar.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/monitors.tsx
msgid "Network Monitors"
msgstr ""
#: src/components/routes/system/charts/network-charts.tsx
msgid "Network traffic of containers"
msgstr "كونتېينېرلارنىڭ تور ئېقىمى"
@@ -1197,6 +1327,7 @@ msgstr ""
#: src/components/containers-table/containers-table.tsx
#: src/components/containers-table/containers-table.tsx
#: src/components/containers-table/containers-table.tsx
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/system/smart-table.tsx
#: src/components/systemd-table/systemd-table.tsx
@@ -1207,6 +1338,7 @@ msgstr ""
msgid "No S.M.A.R.T. attributes available for this device."
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -1238,6 +1370,11 @@ msgstr ""
msgid "One or more containers are unhealthy"
msgstr ""
#. placeholder {0}: alert.value
#: src/components/active-alerts.tsx
msgid "One or more monitors exceed {0}% loss"
msgstr ""
#: src/lib/alerts.ts
msgid "One or more services are in a failed state"
msgstr ""
@@ -1251,6 +1388,7 @@ msgstr ""
msgid "One-time password"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -1272,6 +1410,11 @@ msgstr ""
msgid "Overwrite existing alerts"
msgstr ""
#: src/components/routes/system/charts/monitors-charts.tsx
msgid "Packet loss (%)"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
@@ -1309,6 +1452,7 @@ msgstr ""
msgid "Past"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Pause"
msgstr ""
@@ -1392,6 +1536,7 @@ msgid "Pool Usage"
msgstr ""
#: src/components/add-system.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Port"
msgstr ""
@@ -1418,6 +1563,11 @@ msgstr ""
msgid "Process started"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Protocol"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Public key"
msgstr ""
@@ -1503,10 +1653,20 @@ msgstr ""
msgid "Resolved"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/system/charts/monitors-charts.tsx
msgid "Response"
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
msgid "Response time monitoring from agents."
msgstr ""
#: src/components/systemd-table/systemd-table.tsx
msgid "Restarts"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Resume"
msgstr ""
@@ -1539,6 +1699,7 @@ msgid "S.M.A.R.T. Self-Test"
msgstr ""
#: src/components/add-system.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Save {foo}"
msgstr ""
@@ -1575,6 +1736,11 @@ msgstr ""
msgid "Search for systems or settings..."
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Search systems"
msgstr ""
#: src/components/routes/settings/heartbeat.tsx
msgid "Seconds between pings (default: 60)"
msgstr ""
@@ -1587,6 +1753,27 @@ msgstr ""
msgid "Select {foo}"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Select a system"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Select all"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Select matches"
msgstr ""
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Select row"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Select systems"
msgstr ""
#: src/components/routes/settings/heartbeat.tsx
msgid "Send a single heartbeat ping to verify your endpoint is working."
msgstr ""
@@ -1692,6 +1879,8 @@ msgstr ""
#: src/components/alerts-history-columns.tsx
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/navbar.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/quiet-hours.tsx
@@ -1716,6 +1905,8 @@ msgid "Systemd Services"
msgstr ""
#: src/components/navbar.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/monitor-dialog.tsx
msgid "Systems"
msgstr ""
@@ -1732,6 +1923,11 @@ msgctxt "Tabs system layout option"
msgid "Tabs"
msgstr ""
#: src/components/network-monitors-table/monitor-dialog.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
msgid "Target"
msgstr ""
#: src/components/systemd-table/systemd-table.tsx
msgid "Tasks"
msgstr ""
@@ -1779,6 +1975,7 @@ msgstr ""
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr ""
#: src/components/network-monitors-table/network-monitors-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
@@ -1901,6 +2098,10 @@ msgstr ""
msgid "Triggers when memory usage exceeds a threshold"
msgstr ""
#: src/lib/alerts.ts
msgid "Triggers when one hour loss exceeds a threshold"
msgstr ""
#: src/lib/alerts.ts
msgid "Triggers when status switches between up and down"
msgstr ""
@@ -1960,6 +2161,7 @@ msgid "Update"
msgstr ""
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/network-monitors-table/network-monitors-columns.tsx
#: src/components/routes/system/smart-table.tsx
#: src/components/routes/system/storage-pools-table.tsx
#: src/components/systemd-table/systemd-table-columns.tsx

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: uk\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19: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"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: uz\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:46\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: Uzbek\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: vi\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-16 10:11\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: Vietnamese\n"
"Plural-Forms: nplurals=1; plural=0;\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: zh\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: Chinese Simplified\n"
"Plural-Forms: nplurals=1; plural=0;\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: zh\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:46\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: Chinese Traditional, Hong Kong\n"
"Plural-Forms: nplurals=1; plural=0;\n"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: zh\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-09-10 01:45\n"
"PO-Revision-Date: 2026-09-18 19:22\n"
"Last-Translator: \n"
"Language-Team: Chinese Traditional\n"
"Plural-Forms: nplurals=1; plural=0;\n"

View File

@@ -1,3 +1,39 @@
## 0.20.0
- Add network monitoring from agents (#2266, #1911)
- Add Docker image update available flag (#2211)
- Add btrfs filesystem reporting as storage pools (#2315)
- Add persistence of view preferences and language to user settings (#1831)
- Add `TRUSTED_PROXY_IPS` allowlist for `TRUSTED_AUTH_HEADER` (#2327)
- Add ZFS utilities to Intel and NVIDIA agent images (#2288, #2311)
- Revert SMART warnings for certain attributes (#2296, #2308, #2347)
- Improve NVMe data units display as human-readable GB/TB (#2303)
- Fix agent disconnects during slow collections by extending WebSocket deadline (#2294)
- Fix missing root CA certificates in base agent image (#2291)
- Fix false RAID health warnings during healthy data scrubbing (#2109)
- Fix ZFS monitoring when /dev/zfs is unavailable (#2325)
- Fix spurious `HUB_URL` warning in SSH-only mode (#2316)
- Fix idle GPU utilization display in systems table (#2312)
- Fix session handling to clear auth store after token expiry (#2310)
- Fix chart history handling when switching to live charts (#2333)
- Update Go dependencies
## 0.19.0
- **Potential breaking change:** Agents now verify HTTPS certificates. If an agent connects to a hub using a self-signed or otherwise untrusted certificate, configure `CA_CERT_FILE` with the appropriate CA certificate or the connection will be rejected.

View File

@@ -2,9 +2,9 @@ apiVersion: v1
description: Installs beszel-agent in kubernetes
home: https://github.com/henrygd/beszel/tree/main/supplemental/helm/beszel-agent
name: beszel-agent
appVersion: "0.19.0"
appVersion: "0.20.0"
# Bump this version when publishing chart changes.
version: 0.1.6
version: 0.1.7
sources:
- https://github.com/henrygd/beszel/tree/main/supplemental/helm/beszel-agent
- https://www.beszel.dev/

View File

@@ -80,7 +80,7 @@ Essential parameters to configure:
| `secret.sshKey` | `ssh-key` | Key name in the secret for the SSH public key |
| `secret.tokenKey` | `token` | Key name in the secret for the authentication token |
| `image.repository` | `henrygd/beszel-agent` | Container image |
| `image.tag` | Chart AppVersion (0.19.0) | Image version |
| `image.tag` | Chart AppVersion (0.20.0) | Image version |
| `hostNetwork` | `false` | Use host network for network monitoring |
| `tolerations` | Allows all taints | Tolerations for running on tainted nodes |
@@ -385,7 +385,7 @@ helm upgrade beszel-agent ./beszel-agent \
# Change image version
helm upgrade beszel-agent ./beszel-agent \
--set image.tag="0.19.0"
--set image.tag="0.20.0"
```
### Restart All Agents
@@ -522,7 +522,7 @@ kubectl get secret beszel-agent -o jsonpath='{.data.ssh-key}' | base64 -d
## Chart Information
- **Chart Version**: 0.1.0
- **App Version**: 0.19.0
- **App Version**: 0.20.0
- **Kubernetes Version**: 1.19+
- **Maintainer**: cloudwithdan (nikoloskid@pm.me)

View File

@@ -2,9 +2,9 @@ apiVersion: v1
description: Installs beszel-hub in kubernetes
home: https://github.com/henrygd/beszel/tree/main/supplemental/helm/beszel-hub
name: beszel-hub
appVersion: "0.19.0"
appVersion: "0.20.0"
# Bump this version when publishing chart changes.
version: 0.1.6
version: 0.1.7
sources:
- https://github.com/henrygd/beszel/tree/main/supplemental/helm/beszel-hub
- https://www.beszel.dev/

View File

@@ -47,7 +47,7 @@ Key configuration options in `values.yaml`:
|-----------|---------|-------------|
| `replicaCount` | `1` | Number of Beszel Hub replicas |
| `image.repository` | `henrygd/beszel` | Container image repository |
| `image.tag` | Chart AppVersion (0.19.0) | Container image tag |
| `image.tag` | Chart AppVersion (0.20.0) | Container image tag |
| `image.pullPolicy` | `IfNotPresent` | Image pull policy |
| `service.port` | `8090` | Service port |
| `persistentVolumeClaim.enabled` | `true` | Enable persistent volume |
@@ -169,7 +169,7 @@ tolerations:
```yaml
replicaCount: 3
image:
tag: "0.19.0"
tag: "0.20.0"
service:
type: LoadBalancer
ingress:
@@ -330,7 +330,7 @@ By default, Beszel Hub uses a PersistentVolumeClaim for data storage. Ensure you
## Chart Information
- **Chart Version**: 0.1.0
- **App Version**: 0.19.0
- **App Version**: 0.20.0
- **Kubernetes Version**: 1.19+
- **Maintainer**: cloudwithdan (nikoloskid@pm.me)