mirror of
https://github.com/henrygd/beszel.git
synced 2026-03-28 16:36:16 +01:00
Compare commits
26 Commits
e4e0affbc1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9840b99327 | ||
|
|
f7b5a505e8 | ||
|
|
3cb32ac046 | ||
|
|
e610d9bfc8 | ||
|
|
b53fdbe0ef | ||
|
|
c7261b56f1 | ||
|
|
3f4c3d51b6 | ||
|
|
ad21cab457 | ||
|
|
f04684b30a | ||
|
|
4d4e4fba9b | ||
|
|
62587919f4 | ||
|
|
35528332fd | ||
|
|
e3e453140e | ||
|
|
7a64da9f65 | ||
|
|
8e71c8ad97 | ||
|
|
97f3b8c61f | ||
|
|
0b0b5d16d7 | ||
|
|
b2fd50211e | ||
|
|
c159eaacd1 | ||
|
|
441bdd2ec5 | ||
|
|
ff36138229 | ||
|
|
be70840609 | ||
|
|
565162ef5f | ||
|
|
adbfe7cfb7 | ||
|
|
1ff7762c80 | ||
|
|
0ab8a606e0 |
6
.github/workflows/vulncheck.yml
vendored
6
.github/workflows/vulncheck.yml
vendored
@@ -19,11 +19,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: 1.25.x
|
||||
go-version: 1.26.x
|
||||
# cached: false
|
||||
- name: Get official govulncheck
|
||||
run: go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
|
||||
@@ -70,19 +70,11 @@ func TestNewWebSocketClient(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Set up environment
|
||||
if tc.hubURL != "" {
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", tc.hubURL)
|
||||
} else {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", tc.hubURL)
|
||||
}
|
||||
if tc.token != "" {
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", tc.token)
|
||||
} else {
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", tc.token)
|
||||
}
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
|
||||
client, err := newWebSocketClient(agent)
|
||||
|
||||
@@ -138,12 +130,8 @@ func TestWebSocketClient_GetOptions(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Set up environment
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", tc.inputURL)
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", tc.inputURL)
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
|
||||
client, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
@@ -185,12 +173,8 @@ func TestWebSocketClient_VerifySignature(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up environment
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
|
||||
client, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
@@ -258,12 +242,8 @@ func TestWebSocketClient_HandleHubRequest(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
|
||||
// Set up environment
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
|
||||
client, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
@@ -350,13 +330,8 @@ func TestGetUserAgent(t *testing.T) {
|
||||
func TestWebSocketClient_Close(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
|
||||
// Set up environment
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
|
||||
client, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
@@ -371,13 +346,8 @@ func TestWebSocketClient_Close(t *testing.T) {
|
||||
func TestWebSocketClient_ConnectRateLimit(t *testing.T) {
|
||||
agent := createTestAgent(t)
|
||||
|
||||
// Set up environment
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
|
||||
client, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
@@ -393,20 +363,10 @@ func TestWebSocketClient_ConnectRateLimit(t *testing.T) {
|
||||
|
||||
// TestGetToken tests the getToken function with various scenarios
|
||||
func TestGetToken(t *testing.T) {
|
||||
unsetEnvVars := func() {
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
os.Unsetenv("TOKEN")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN_FILE")
|
||||
os.Unsetenv("TOKEN_FILE")
|
||||
}
|
||||
|
||||
t.Run("token from TOKEN environment variable", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Set TOKEN env var
|
||||
expectedToken := "test-token-from-env"
|
||||
os.Setenv("TOKEN", expectedToken)
|
||||
defer os.Unsetenv("TOKEN")
|
||||
t.Setenv("TOKEN", expectedToken)
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
@@ -414,12 +374,9 @@ func TestGetToken(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("token from BESZEL_AGENT_TOKEN environment variable", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Set BESZEL_AGENT_TOKEN env var (should take precedence)
|
||||
expectedToken := "test-token-from-beszel-env"
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", expectedToken)
|
||||
defer os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", expectedToken)
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
@@ -427,8 +384,6 @@ func TestGetToken(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("token from TOKEN_FILE", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Create a temporary token file
|
||||
expectedToken := "test-token-from-file"
|
||||
tokenFile, err := os.CreateTemp("", "token-test-*.txt")
|
||||
@@ -440,8 +395,7 @@ func TestGetToken(t *testing.T) {
|
||||
tokenFile.Close()
|
||||
|
||||
// Set TOKEN_FILE env var
|
||||
os.Setenv("TOKEN_FILE", tokenFile.Name())
|
||||
defer os.Unsetenv("TOKEN_FILE")
|
||||
t.Setenv("TOKEN_FILE", tokenFile.Name())
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
@@ -449,8 +403,6 @@ func TestGetToken(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("token from BESZEL_AGENT_TOKEN_FILE", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Create a temporary token file
|
||||
expectedToken := "test-token-from-beszel-file"
|
||||
tokenFile, err := os.CreateTemp("", "token-test-*.txt")
|
||||
@@ -462,8 +414,7 @@ func TestGetToken(t *testing.T) {
|
||||
tokenFile.Close()
|
||||
|
||||
// Set BESZEL_AGENT_TOKEN_FILE env var (should take precedence)
|
||||
os.Setenv("BESZEL_AGENT_TOKEN_FILE", tokenFile.Name())
|
||||
defer os.Unsetenv("BESZEL_AGENT_TOKEN_FILE")
|
||||
t.Setenv("BESZEL_AGENT_TOKEN_FILE", tokenFile.Name())
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
@@ -471,8 +422,6 @@ func TestGetToken(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("TOKEN takes precedence over TOKEN_FILE", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Create a temporary token file
|
||||
fileToken := "token-from-file"
|
||||
tokenFile, err := os.CreateTemp("", "token-test-*.txt")
|
||||
@@ -485,12 +434,8 @@ func TestGetToken(t *testing.T) {
|
||||
|
||||
// Set both TOKEN and TOKEN_FILE
|
||||
envToken := "token-from-env"
|
||||
os.Setenv("TOKEN", envToken)
|
||||
os.Setenv("TOKEN_FILE", tokenFile.Name())
|
||||
defer func() {
|
||||
os.Unsetenv("TOKEN")
|
||||
os.Unsetenv("TOKEN_FILE")
|
||||
}()
|
||||
t.Setenv("TOKEN", envToken)
|
||||
t.Setenv("TOKEN_FILE", tokenFile.Name())
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
@@ -498,7 +443,10 @@ func TestGetToken(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("error when neither TOKEN nor TOKEN_FILE is set", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", "")
|
||||
t.Setenv("TOKEN", "")
|
||||
t.Setenv("BESZEL_AGENT_TOKEN_FILE", "")
|
||||
t.Setenv("TOKEN_FILE", "")
|
||||
|
||||
token, err := getToken()
|
||||
assert.Error(t, err)
|
||||
@@ -507,11 +455,8 @@ func TestGetToken(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("error when TOKEN_FILE points to non-existent file", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Set TOKEN_FILE to a non-existent file
|
||||
os.Setenv("TOKEN_FILE", "/non/existent/file.txt")
|
||||
defer os.Unsetenv("TOKEN_FILE")
|
||||
t.Setenv("TOKEN_FILE", "/non/existent/file.txt")
|
||||
|
||||
token, err := getToken()
|
||||
assert.Error(t, err)
|
||||
@@ -520,8 +465,6 @@ func TestGetToken(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("handles empty token file", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
// Create an empty token file
|
||||
tokenFile, err := os.CreateTemp("", "token-test-*.txt")
|
||||
require.NoError(t, err)
|
||||
@@ -529,8 +472,7 @@ func TestGetToken(t *testing.T) {
|
||||
tokenFile.Close()
|
||||
|
||||
// Set TOKEN_FILE env var
|
||||
os.Setenv("TOKEN_FILE", tokenFile.Name())
|
||||
defer os.Unsetenv("TOKEN_FILE")
|
||||
t.Setenv("TOKEN_FILE", tokenFile.Name())
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
@@ -538,8 +480,6 @@ func TestGetToken(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("strips whitespace from TOKEN_FILE", func(t *testing.T) {
|
||||
unsetEnvVars()
|
||||
|
||||
tokenWithWhitespace := " test-token-with-whitespace \n\t"
|
||||
expectedToken := "test-token-with-whitespace"
|
||||
tokenFile, err := os.CreateTemp("", "token-test-*.txt")
|
||||
@@ -550,8 +490,7 @@ func TestGetToken(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
tokenFile.Close()
|
||||
|
||||
os.Setenv("TOKEN_FILE", tokenFile.Name())
|
||||
defer os.Unsetenv("TOKEN_FILE")
|
||||
t.Setenv("TOKEN_FILE", tokenFile.Name())
|
||||
|
||||
token, err := getToken()
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -183,10 +182,6 @@ func TestConnectionManager_TickerManagement(t *testing.T) {
|
||||
|
||||
// TestConnectionManager_WebSocketConnectionFlow tests WebSocket connection logic
|
||||
func TestConnectionManager_WebSocketConnectionFlow(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping WebSocket connection test in short mode")
|
||||
}
|
||||
|
||||
agent := createTestAgent(t)
|
||||
cm := agent.connectionManager
|
||||
|
||||
@@ -196,19 +191,18 @@ func TestConnectionManager_WebSocketConnectionFlow(t *testing.T) {
|
||||
assert.Equal(t, Disconnected, cm.State, "State should remain Disconnected after failed connection")
|
||||
|
||||
// Test with invalid URL
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "invalid-url")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
|
||||
// Test with missing token
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", "1,33%")
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
|
||||
_, err2 := newWebSocketClient(agent)
|
||||
assert.Error(t, err2, "WebSocket client creation should fail without token")
|
||||
assert.Error(t, err2, "WebSocket client creation should fail with invalid URL")
|
||||
|
||||
// Test with missing token
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", "http://localhost:8080")
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", "")
|
||||
|
||||
_, err3 := newWebSocketClient(agent)
|
||||
assert.Error(t, err3, "WebSocket client creation should fail without token")
|
||||
}
|
||||
|
||||
// TestConnectionManager_ReconnectionLogic tests reconnection prevention logic
|
||||
@@ -234,12 +228,8 @@ func TestConnectionManager_ConnectWithRateLimit(t *testing.T) {
|
||||
cm := agent.connectionManager
|
||||
|
||||
// Set up environment for WebSocket client creation
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "ws://localhost:8080")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", "ws://localhost:8080")
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
|
||||
// Create WebSocket client
|
||||
wsClient, err := newWebSocketClient(agent)
|
||||
@@ -285,12 +275,8 @@ func TestConnectionManager_CloseWebSocket(t *testing.T) {
|
||||
}, "Should not panic when closing nil WebSocket client")
|
||||
|
||||
// Set up environment and create WebSocket client
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", "ws://localhost:8080")
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", "ws://localhost:8080")
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", "test-token")
|
||||
|
||||
wsClient, err := newWebSocketClient(agent)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -39,17 +39,7 @@ func TestGetDataDir(t *testing.T) {
|
||||
t.Run("DATA_DIR environment variable", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
|
||||
// Set environment variable
|
||||
oldValue := os.Getenv("DATA_DIR")
|
||||
defer func() {
|
||||
if oldValue == "" {
|
||||
os.Unsetenv("BESZEL_AGENT_DATA_DIR")
|
||||
} else {
|
||||
os.Setenv("BESZEL_AGENT_DATA_DIR", oldValue)
|
||||
}
|
||||
}()
|
||||
|
||||
os.Setenv("BESZEL_AGENT_DATA_DIR", tempDir)
|
||||
t.Setenv("BESZEL_AGENT_DATA_DIR", tempDir)
|
||||
|
||||
result, err := GetDataDir()
|
||||
require.NoError(t, err)
|
||||
@@ -65,17 +55,6 @@ func TestGetDataDir(t *testing.T) {
|
||||
|
||||
// Test fallback behavior (empty dataDir, no env var)
|
||||
t.Run("fallback to default directories", func(t *testing.T) {
|
||||
// Clear DATA_DIR environment variable
|
||||
oldValue := os.Getenv("DATA_DIR")
|
||||
defer func() {
|
||||
if oldValue == "" {
|
||||
os.Unsetenv("DATA_DIR")
|
||||
} else {
|
||||
os.Setenv("DATA_DIR", oldValue)
|
||||
}
|
||||
}()
|
||||
os.Unsetenv("DATA_DIR")
|
||||
|
||||
// This will try platform-specific defaults, which may or may not work
|
||||
// We're mainly testing that it doesn't panic and returns some result
|
||||
result, err := GetDataDir()
|
||||
|
||||
@@ -687,18 +687,8 @@ func TestIsDockerSpecialMountpoint(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInitializeDiskInfoWithCustomNames(t *testing.T) {
|
||||
// Set up environment variables
|
||||
oldEnv := os.Getenv("EXTRA_FILESYSTEMS")
|
||||
defer func() {
|
||||
if oldEnv != "" {
|
||||
os.Setenv("EXTRA_FILESYSTEMS", oldEnv)
|
||||
} else {
|
||||
os.Unsetenv("EXTRA_FILESYSTEMS")
|
||||
}
|
||||
}()
|
||||
|
||||
// Test with custom names
|
||||
os.Setenv("EXTRA_FILESYSTEMS", "sda1__my-storage,/dev/sdb1__backup-drive,nvme0n1p2")
|
||||
t.Setenv("EXTRA_FILESYSTEMS", "sda1__my-storage,/dev/sdb1__backup-drive,nvme0n1p2")
|
||||
|
||||
// Mock disk partitions (we'll just test the parsing logic)
|
||||
// Since the actual disk operations are system-dependent, we'll focus on the parsing
|
||||
@@ -726,7 +716,7 @@ func TestInitializeDiskInfoWithCustomNames(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run("env_"+tc.envValue, func(t *testing.T) {
|
||||
os.Setenv("EXTRA_FILESYSTEMS", tc.envValue)
|
||||
t.Setenv("EXTRA_FILESYSTEMS", tc.envValue)
|
||||
|
||||
// Create mock partitions that would match our test cases
|
||||
partitions := []disk.PartitionStat{}
|
||||
|
||||
@@ -77,6 +77,7 @@ type dockerManager struct {
|
||||
// cacheTimeMs -> DeltaTracker for network bytes sent/received
|
||||
networkSentTrackers map[uint16]*deltatracker.DeltaTracker[string, uint64]
|
||||
networkRecvTrackers map[uint16]*deltatracker.DeltaTracker[string, uint64]
|
||||
lastNetworkReadTime map[uint16]map[string]time.Time // cacheTimeMs -> containerId -> last network read time
|
||||
retrySleep func(time.Duration)
|
||||
}
|
||||
|
||||
@@ -285,7 +286,7 @@ func (dm *dockerManager) cycleNetworkDeltasForCacheTime(cacheTimeMs uint16) {
|
||||
}
|
||||
|
||||
// calculateNetworkStats calculates network sent/receive deltas using DeltaTracker
|
||||
func (dm *dockerManager) calculateNetworkStats(ctr *container.ApiInfo, apiStats *container.ApiStats, stats *container.Stats, initialized bool, name string, cacheTimeMs uint16) (uint64, uint64) {
|
||||
func (dm *dockerManager) calculateNetworkStats(ctr *container.ApiInfo, apiStats *container.ApiStats, name string, cacheTimeMs uint16) (uint64, uint64) {
|
||||
var total_sent, total_recv uint64
|
||||
for _, v := range apiStats.Networks {
|
||||
total_sent += v.TxBytes
|
||||
@@ -304,10 +305,11 @@ func (dm *dockerManager) calculateNetworkStats(ctr *container.ApiInfo, apiStats
|
||||
sent_delta_raw := sentTracker.Delta(ctr.IdShort)
|
||||
recv_delta_raw := recvTracker.Delta(ctr.IdShort)
|
||||
|
||||
// Calculate bytes per second independently for Tx and Rx if we have previous data
|
||||
// Calculate bytes per second using per-cache-time read time to avoid
|
||||
// interference between different cache intervals (e.g. 1000ms vs 60000ms)
|
||||
var sent_delta, recv_delta uint64
|
||||
if initialized {
|
||||
millisecondsElapsed := uint64(time.Since(stats.PrevReadTime).Milliseconds())
|
||||
if prevReadTime, ok := dm.lastNetworkReadTime[cacheTimeMs][ctr.IdShort]; ok {
|
||||
millisecondsElapsed := uint64(time.Since(prevReadTime).Milliseconds())
|
||||
if millisecondsElapsed > 0 {
|
||||
if sent_delta_raw > 0 {
|
||||
sent_delta = sent_delta_raw * 1000 / millisecondsElapsed
|
||||
@@ -542,7 +544,13 @@ func (dm *dockerManager) updateContainerStats(ctr *container.ApiInfo, cacheTimeM
|
||||
}
|
||||
|
||||
// Calculate network stats using DeltaTracker
|
||||
sent_delta, recv_delta := dm.calculateNetworkStats(ctr, res, stats, initialized, name, cacheTimeMs)
|
||||
sent_delta, recv_delta := dm.calculateNetworkStats(ctr, res, name, cacheTimeMs)
|
||||
|
||||
// Store per-cache-time network read time for next rate calculation
|
||||
if dm.lastNetworkReadTime[cacheTimeMs] == nil {
|
||||
dm.lastNetworkReadTime[cacheTimeMs] = make(map[string]time.Time)
|
||||
}
|
||||
dm.lastNetworkReadTime[cacheTimeMs][ctr.IdShort] = time.Now()
|
||||
|
||||
// Store current network values for legacy compatibility
|
||||
var total_sent, total_recv uint64
|
||||
@@ -574,6 +582,9 @@ func (dm *dockerManager) deleteContainerStatsSync(id string) {
|
||||
for ct := range dm.lastCpuReadTime {
|
||||
delete(dm.lastCpuReadTime[ct], id)
|
||||
}
|
||||
for ct := range dm.lastNetworkReadTime {
|
||||
delete(dm.lastNetworkReadTime[ct], id)
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a new http client for Docker or Podman API
|
||||
@@ -659,6 +670,7 @@ func newDockerManager() *dockerManager {
|
||||
lastCpuReadTime: make(map[uint16]map[string]time.Time),
|
||||
networkSentTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
networkRecvTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
lastNetworkReadTime: make(map[uint16]map[string]time.Time),
|
||||
retrySleep: time.Sleep,
|
||||
}
|
||||
|
||||
|
||||
@@ -408,6 +408,7 @@ func TestCalculateNetworkStats(t *testing.T) {
|
||||
dm := &dockerManager{
|
||||
networkSentTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
networkRecvTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
lastNetworkReadTime: make(map[uint16]map[string]time.Time),
|
||||
}
|
||||
|
||||
cacheTimeMs := uint16(30000)
|
||||
@@ -423,6 +424,11 @@ func TestCalculateNetworkStats(t *testing.T) {
|
||||
dm.networkSentTrackers[cacheTimeMs] = sentTracker
|
||||
dm.networkRecvTrackers[cacheTimeMs] = recvTracker
|
||||
|
||||
// Set per-cache-time network read time (1 second ago)
|
||||
dm.lastNetworkReadTime[cacheTimeMs] = map[string]time.Time{
|
||||
"container1": time.Now().Add(-time.Second),
|
||||
}
|
||||
|
||||
ctr := &container.ApiInfo{
|
||||
IdShort: "container1",
|
||||
}
|
||||
@@ -433,12 +439,8 @@ func TestCalculateNetworkStats(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
stats := &container.Stats{
|
||||
PrevReadTime: time.Now().Add(-time.Second), // 1 second ago
|
||||
}
|
||||
|
||||
// Test with initialized container
|
||||
sent, recv := dm.calculateNetworkStats(ctr, apiStats, stats, true, "test-container", cacheTimeMs)
|
||||
sent, recv := dm.calculateNetworkStats(ctr, apiStats, "test-container", cacheTimeMs)
|
||||
|
||||
// Should return calculated byte rates per second
|
||||
assert.GreaterOrEqual(t, sent, uint64(0))
|
||||
@@ -446,12 +448,76 @@ func TestCalculateNetworkStats(t *testing.T) {
|
||||
|
||||
// Cycle and test one-direction change (Tx only) is reflected independently
|
||||
dm.cycleNetworkDeltasForCacheTime(cacheTimeMs)
|
||||
dm.lastNetworkReadTime[cacheTimeMs]["container1"] = time.Now().Add(-time.Second)
|
||||
apiStats.Networks["eth0"] = container.NetworkStats{TxBytes: 2500, RxBytes: 1800} // +500 Tx only
|
||||
sent, recv = dm.calculateNetworkStats(ctr, apiStats, stats, true, "test-container", cacheTimeMs)
|
||||
sent, recv = dm.calculateNetworkStats(ctr, apiStats, "test-container", cacheTimeMs)
|
||||
assert.Greater(t, sent, uint64(0))
|
||||
assert.Equal(t, uint64(0), recv)
|
||||
}
|
||||
|
||||
// TestNetworkStatsCacheTimeIsolation verifies that frequent collections at one cache time
|
||||
// (e.g. 1000ms) don't cause inflated rates at another cache time (e.g. 60000ms).
|
||||
// This was a bug where PrevReadTime was shared, so the 60000ms tracker would see a
|
||||
// large byte delta divided by a tiny elapsed time (set by the 1000ms path).
|
||||
func TestNetworkStatsCacheTimeIsolation(t *testing.T) {
|
||||
dm := &dockerManager{
|
||||
networkSentTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
networkRecvTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
lastNetworkReadTime: make(map[uint16]map[string]time.Time),
|
||||
}
|
||||
|
||||
ctr := &container.ApiInfo{IdShort: "container1"}
|
||||
fastCache := uint16(1000)
|
||||
slowCache := uint16(60000)
|
||||
|
||||
// Baseline for both cache times at T=0 with 100 bytes total
|
||||
baseline := &container.ApiStats{
|
||||
Networks: map[string]container.NetworkStats{
|
||||
"eth0": {TxBytes: 100, RxBytes: 100},
|
||||
},
|
||||
}
|
||||
dm.calculateNetworkStats(ctr, baseline, "test", fastCache)
|
||||
dm.calculateNetworkStats(ctr, baseline, "test", slowCache)
|
||||
|
||||
// Record read times and cycle both
|
||||
now := time.Now()
|
||||
dm.lastNetworkReadTime[fastCache] = map[string]time.Time{"container1": now}
|
||||
dm.lastNetworkReadTime[slowCache] = map[string]time.Time{"container1": now}
|
||||
dm.cycleNetworkDeltasForCacheTime(fastCache)
|
||||
dm.cycleNetworkDeltasForCacheTime(slowCache)
|
||||
|
||||
// Simulate many fast (1000ms) collections over ~5 seconds, each adding 10 bytes
|
||||
totalBytes := uint64(100)
|
||||
for i := 0; i < 5; i++ {
|
||||
totalBytes += 10
|
||||
stats := &container.ApiStats{
|
||||
Networks: map[string]container.NetworkStats{
|
||||
"eth0": {TxBytes: totalBytes, RxBytes: totalBytes},
|
||||
},
|
||||
}
|
||||
// Set fast cache read time to 1 second ago
|
||||
dm.lastNetworkReadTime[fastCache]["container1"] = time.Now().Add(-time.Second)
|
||||
sent, _ := dm.calculateNetworkStats(ctr, stats, "test", fastCache)
|
||||
// Fast cache should see ~10 bytes/sec per interval
|
||||
assert.LessOrEqual(t, sent, uint64(100), "fast cache rate should be reasonable")
|
||||
dm.cycleNetworkDeltasForCacheTime(fastCache)
|
||||
}
|
||||
|
||||
// Now do slow cache collection — total delta is 50 bytes over ~5 seconds
|
||||
// Set slow cache read time to 5 seconds ago (the actual elapsed time)
|
||||
dm.lastNetworkReadTime[slowCache]["container1"] = time.Now().Add(-5 * time.Second)
|
||||
finalStats := &container.ApiStats{
|
||||
Networks: map[string]container.NetworkStats{
|
||||
"eth0": {TxBytes: totalBytes, RxBytes: totalBytes},
|
||||
},
|
||||
}
|
||||
sent, _ := dm.calculateNetworkStats(ctr, finalStats, "test", slowCache)
|
||||
|
||||
// Slow cache rate should be ~10 bytes/sec (50 bytes / 5 seconds), NOT 100x inflated
|
||||
assert.LessOrEqual(t, sent, uint64(100), "slow cache rate should NOT be inflated by fast cache collections")
|
||||
assert.GreaterOrEqual(t, sent, uint64(1), "slow cache should still report some traffic")
|
||||
}
|
||||
|
||||
func TestDockerManagerCreation(t *testing.T) {
|
||||
// Test that dockerManager can be created without panicking
|
||||
dm := &dockerManager{
|
||||
@@ -460,6 +526,7 @@ func TestDockerManagerCreation(t *testing.T) {
|
||||
lastCpuReadTime: make(map[uint16]map[string]time.Time),
|
||||
networkSentTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
networkRecvTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
lastNetworkReadTime: make(map[uint16]map[string]time.Time),
|
||||
}
|
||||
|
||||
assert.NotNil(t, dm)
|
||||
@@ -467,6 +534,7 @@ func TestDockerManagerCreation(t *testing.T) {
|
||||
assert.NotNil(t, dm.lastCpuSystem)
|
||||
assert.NotNil(t, dm.networkSentTrackers)
|
||||
assert.NotNil(t, dm.networkRecvTrackers)
|
||||
assert.NotNil(t, dm.lastNetworkReadTime)
|
||||
}
|
||||
|
||||
func TestCheckDockerVersion(t *testing.T) {
|
||||
@@ -651,6 +719,7 @@ func TestDockerStatsWithMockData(t *testing.T) {
|
||||
lastCpuReadTime: make(map[uint16]map[string]time.Time),
|
||||
networkSentTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
networkRecvTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
lastNetworkReadTime: make(map[uint16]map[string]time.Time),
|
||||
containerStatsMap: make(map[string]*container.Stats),
|
||||
}
|
||||
|
||||
@@ -796,23 +865,22 @@ func TestNetworkStatsCalculationWithRealData(t *testing.T) {
|
||||
dm := &dockerManager{
|
||||
networkSentTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
networkRecvTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
lastNetworkReadTime: make(map[uint16]map[string]time.Time),
|
||||
}
|
||||
|
||||
ctr := &container.ApiInfo{IdShort: "test-container"}
|
||||
cacheTimeMs := uint16(30000) // Test with 30 second cache
|
||||
|
||||
// Use exact timing for deterministic results
|
||||
exactly1000msAgo := time.Now().Add(-1000 * time.Millisecond)
|
||||
stats := &container.Stats{
|
||||
PrevReadTime: exactly1000msAgo,
|
||||
}
|
||||
|
||||
// First call sets baseline
|
||||
sent1, recv1 := dm.calculateNetworkStats(ctr, apiStats1, stats, true, "test", cacheTimeMs)
|
||||
// First call sets baseline (no previous read time, so rates should be 0)
|
||||
sent1, recv1 := dm.calculateNetworkStats(ctr, apiStats1, "test", cacheTimeMs)
|
||||
assert.Equal(t, uint64(0), sent1)
|
||||
assert.Equal(t, uint64(0), recv1)
|
||||
|
||||
// Cycle to establish baseline for this cache time
|
||||
// Record read time and cycle to establish baseline for this cache time
|
||||
exactly1000msAgo := time.Now().Add(-1000 * time.Millisecond)
|
||||
dm.lastNetworkReadTime[cacheTimeMs] = map[string]time.Time{
|
||||
"test-container": exactly1000msAgo,
|
||||
}
|
||||
dm.cycleNetworkDeltasForCacheTime(cacheTimeMs)
|
||||
|
||||
// Calculate expected results precisely
|
||||
@@ -823,7 +891,7 @@ func TestNetworkStatsCalculationWithRealData(t *testing.T) {
|
||||
expectedRecvRate := deltaRecv * 1000 / expectedElapsedMs // Should be exactly 1000000
|
||||
|
||||
// Second call with changed data
|
||||
sent2, recv2 := dm.calculateNetworkStats(ctr, apiStats2, stats, true, "test", cacheTimeMs)
|
||||
sent2, recv2 := dm.calculateNetworkStats(ctr, apiStats2, "test", cacheTimeMs)
|
||||
|
||||
// Should be exactly the expected rates (no tolerance needed)
|
||||
assert.Equal(t, expectedSentRate, sent2)
|
||||
@@ -831,12 +899,13 @@ func TestNetworkStatsCalculationWithRealData(t *testing.T) {
|
||||
|
||||
// Bad speed cap: set absurd delta over 1ms and expect 0 due to cap
|
||||
dm.cycleNetworkDeltasForCacheTime(cacheTimeMs)
|
||||
stats.PrevReadTime = time.Now().Add(-1 * time.Millisecond)
|
||||
dm.lastNetworkReadTime[cacheTimeMs]["test-container"] = time.Now().Add(-1 * time.Millisecond)
|
||||
apiStats1.Networks["eth0"] = container.NetworkStats{TxBytes: 0, RxBytes: 0}
|
||||
apiStats2.Networks["eth0"] = container.NetworkStats{TxBytes: 10 * 1024 * 1024 * 1024, RxBytes: 0} // 10GB delta
|
||||
_, _ = dm.calculateNetworkStats(ctr, apiStats1, stats, true, "test", cacheTimeMs) // baseline
|
||||
_, _ = dm.calculateNetworkStats(ctr, apiStats1, "test", cacheTimeMs) // baseline
|
||||
dm.cycleNetworkDeltasForCacheTime(cacheTimeMs)
|
||||
sent3, recv3 := dm.calculateNetworkStats(ctr, apiStats2, stats, true, "test", cacheTimeMs)
|
||||
dm.lastNetworkReadTime[cacheTimeMs]["test-container"] = time.Now().Add(-1 * time.Millisecond)
|
||||
sent3, recv3 := dm.calculateNetworkStats(ctr, apiStats2, "test", cacheTimeMs)
|
||||
assert.Equal(t, uint64(0), sent3)
|
||||
assert.Equal(t, uint64(0), recv3)
|
||||
}
|
||||
@@ -857,6 +926,7 @@ func TestContainerStatsEndToEndWithRealData(t *testing.T) {
|
||||
lastCpuReadTime: make(map[uint16]map[string]time.Time),
|
||||
networkSentTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
networkRecvTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
lastNetworkReadTime: make(map[uint16]map[string]time.Time),
|
||||
containerStatsMap: make(map[string]*container.Stats),
|
||||
}
|
||||
|
||||
@@ -978,6 +1048,7 @@ func TestDockerStatsWorkflow(t *testing.T) {
|
||||
lastCpuSystem: make(map[uint16]map[string]uint64),
|
||||
networkSentTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
networkRecvTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
lastNetworkReadTime: make(map[uint16]map[string]time.Time),
|
||||
containerStatsMap: make(map[string]*container.Stats),
|
||||
}
|
||||
|
||||
@@ -1242,6 +1313,7 @@ func TestUpdateContainerStatsUsesPodmanInspectHealthFallback(t *testing.T) {
|
||||
lastCpuReadTime: make(map[uint16]map[string]time.Time),
|
||||
networkSentTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
networkRecvTrackers: make(map[uint16]*deltatracker.DeltaTracker[string, uint64]),
|
||||
lastNetworkReadTime: make(map[uint16]map[string]time.Time),
|
||||
}
|
||||
|
||||
ctr := &container.ApiInfo{
|
||||
|
||||
@@ -461,7 +461,7 @@ func (gm *GPUManager) discoverGpuCapabilities() gpuCapabilities {
|
||||
caps.hasNvtop = true
|
||||
}
|
||||
if runtime.GOOS == "darwin" {
|
||||
if _, err := exec.LookPath(macmonCmd); err == nil {
|
||||
if _, err := utils.LookPathHomebrew(macmonCmd); err == nil {
|
||||
caps.hasMacmon = true
|
||||
}
|
||||
if _, err := exec.LookPath(powermetricsCmd); err == nil {
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/agent/utils"
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
)
|
||||
|
||||
@@ -171,7 +172,11 @@ type macmonSample struct {
|
||||
}
|
||||
|
||||
func (gm *GPUManager) collectMacmonPipe() (err error) {
|
||||
cmd := exec.Command(macmonCmd, "pipe", "-i", strconv.Itoa(macmonIntervalMs))
|
||||
macmonPath, err := utils.LookPathHomebrew(macmonCmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd := exec.Command(macmonPath, "pipe", "-i", strconv.Itoa(macmonIntervalMs))
|
||||
// Avoid blocking if macmon writes to stderr.
|
||||
cmd.Stderr = io.Discard
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
|
||||
@@ -1083,8 +1083,6 @@ func TestCalculateGPUAverage(t *testing.T) {
|
||||
|
||||
func TestGPUCapabilitiesAndLegacyPriority(t *testing.T) {
|
||||
// Save original PATH
|
||||
origPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", origPath)
|
||||
hasAmdSysfs := (&GPUManager{}).hasAmdSysfs()
|
||||
|
||||
tests := []struct {
|
||||
@@ -1178,7 +1176,7 @@ echo "[]"`
|
||||
{
|
||||
name: "no gpu tools available",
|
||||
setupCommands: func(_ string) error {
|
||||
os.Setenv("PATH", "")
|
||||
t.Setenv("PATH", "")
|
||||
return nil
|
||||
},
|
||||
wantErr: true,
|
||||
@@ -1188,7 +1186,7 @@ echo "[]"`
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
os.Setenv("PATH", tempDir)
|
||||
t.Setenv("PATH", tempDir)
|
||||
if err := tt.setupCommands(tempDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1234,13 +1232,9 @@ echo "[]"`
|
||||
}
|
||||
|
||||
func TestCollectorStartHelpers(t *testing.T) {
|
||||
// Save original PATH
|
||||
origPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", origPath)
|
||||
|
||||
// Set up temp dir with the commands
|
||||
dir := t.TempDir()
|
||||
os.Setenv("PATH", dir)
|
||||
t.Setenv("PATH", dir)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1370,11 +1364,8 @@ echo '[{"device_name":"NVIDIA Test GPU","temp":"52C","power_draw":"31W","gpu_uti
|
||||
}
|
||||
|
||||
func TestNewGPUManagerPriorityNvtopFallback(t *testing.T) {
|
||||
origPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", origPath)
|
||||
|
||||
dir := t.TempDir()
|
||||
os.Setenv("PATH", dir)
|
||||
t.Setenv("PATH", dir)
|
||||
t.Setenv("BESZEL_AGENT_GPU_COLLECTOR", "nvtop,nvidia-smi")
|
||||
|
||||
nvtopPath := filepath.Join(dir, "nvtop")
|
||||
@@ -1399,11 +1390,8 @@ echo "0, NVIDIA Priority GPU, 45, 512, 2048, 12, 25"`
|
||||
}
|
||||
|
||||
func TestNewGPUManagerPriorityMixedCollectors(t *testing.T) {
|
||||
origPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", origPath)
|
||||
|
||||
dir := t.TempDir()
|
||||
os.Setenv("PATH", dir)
|
||||
t.Setenv("PATH", dir)
|
||||
t.Setenv("BESZEL_AGENT_GPU_COLLECTOR", "intel_gpu_top,rocm-smi")
|
||||
|
||||
intelPath := filepath.Join(dir, "intel_gpu_top")
|
||||
@@ -1433,11 +1421,8 @@ echo '{"card0": {"Temperature (Sensor edge) (C)": "49.0", "Current Socket Graphi
|
||||
}
|
||||
|
||||
func TestNewGPUManagerPriorityNvmlFallbackToNvidiaSmi(t *testing.T) {
|
||||
origPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", origPath)
|
||||
|
||||
dir := t.TempDir()
|
||||
os.Setenv("PATH", dir)
|
||||
t.Setenv("PATH", dir)
|
||||
t.Setenv("BESZEL_AGENT_GPU_COLLECTOR", "nvml,nvidia-smi")
|
||||
|
||||
nvidiaPath := filepath.Join(dir, "nvidia-smi")
|
||||
@@ -1456,11 +1441,8 @@ echo "0, NVIDIA Fallback GPU, 41, 256, 1024, 8, 14"`
|
||||
}
|
||||
|
||||
func TestNewGPUManagerConfiguredCollectorsMustStart(t *testing.T) {
|
||||
origPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", origPath)
|
||||
|
||||
dir := t.TempDir()
|
||||
os.Setenv("PATH", dir)
|
||||
t.Setenv("PATH", dir)
|
||||
|
||||
t.Run("configured valid collector unavailable", func(t *testing.T) {
|
||||
t.Setenv("BESZEL_AGENT_GPU_COLLECTOR", "nvidia-smi")
|
||||
@@ -1480,11 +1462,8 @@ func TestNewGPUManagerConfiguredCollectorsMustStart(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewGPUManagerJetsonIgnoresCollectorConfig(t *testing.T) {
|
||||
origPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", origPath)
|
||||
|
||||
dir := t.TempDir()
|
||||
os.Setenv("PATH", dir)
|
||||
t.Setenv("PATH", dir)
|
||||
t.Setenv("BESZEL_AGENT_GPU_COLLECTOR", "nvidia-smi")
|
||||
|
||||
tegraPath := filepath.Join(dir, "tegrastats")
|
||||
@@ -1719,12 +1698,8 @@ func TestIntelUpdateFromStats(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIntelCollectorStreaming(t *testing.T) {
|
||||
// Save and override PATH
|
||||
origPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", origPath)
|
||||
|
||||
dir := t.TempDir()
|
||||
os.Setenv("PATH", dir)
|
||||
t.Setenv("PATH", dir)
|
||||
|
||||
// Create a fake intel_gpu_top that prints -l format with four samples (first will be skipped) and exits
|
||||
scriptPath := filepath.Join(dir, "intel_gpu_top")
|
||||
|
||||
@@ -2,12 +2,14 @@ package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"path"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/henrygd/beszel/agent/utils"
|
||||
@@ -38,6 +40,11 @@ func (a *Agent) newSensorConfig() *SensorConfig {
|
||||
// Matches sensors.TemperaturesWithContext to allow for panic recovery (gopsutil/issues/1832)
|
||||
type getTempsFn func(ctx context.Context) ([]sensors.TemperatureStat, error)
|
||||
|
||||
var (
|
||||
errTemperatureFetchTimeout = errors.New("temperature collection timed out")
|
||||
temperatureFetchTimeout = 2 * time.Second
|
||||
)
|
||||
|
||||
// newSensorConfigWithEnv creates a SensorConfig with the provided environment variables
|
||||
// sensorsSet indicates if the SENSORS environment variable was explicitly set (even to empty string)
|
||||
func (a *Agent) newSensorConfigWithEnv(primarySensor, sysSensors, sensorsEnvVal string, skipCollection bool) *SensorConfig {
|
||||
@@ -86,10 +93,12 @@ func (a *Agent) updateTemperatures(systemStats *system.Stats) {
|
||||
// reset high temp
|
||||
a.systemInfo.DashboardTemp = 0
|
||||
|
||||
temps, err := a.getTempsWithPanicRecovery(getSensorTemps)
|
||||
temps, err := a.getTempsWithTimeout(getSensorTemps)
|
||||
if err != nil {
|
||||
// retry once on panic (gopsutil/issues/1832)
|
||||
temps, err = a.getTempsWithPanicRecovery(getSensorTemps)
|
||||
if !errors.Is(err, errTemperatureFetchTimeout) {
|
||||
temps, err = a.getTempsWithTimeout(getSensorTemps)
|
||||
}
|
||||
if err != nil {
|
||||
slog.Warn("Error updating temperatures", "err", err)
|
||||
if len(systemStats.Temperatures) > 0 {
|
||||
@@ -152,6 +161,26 @@ func (a *Agent) getTempsWithPanicRecovery(getTemps getTempsFn) (temps []sensors.
|
||||
return
|
||||
}
|
||||
|
||||
func (a *Agent) getTempsWithTimeout(getTemps getTempsFn) ([]sensors.TemperatureStat, error) {
|
||||
type result struct {
|
||||
temps []sensors.TemperatureStat
|
||||
err error
|
||||
}
|
||||
|
||||
resultCh := make(chan result, 1)
|
||||
go func() {
|
||||
temps, err := a.getTempsWithPanicRecovery(getTemps)
|
||||
resultCh <- result{temps: temps, err: err}
|
||||
}()
|
||||
|
||||
select {
|
||||
case res := <-resultCh:
|
||||
return res.temps, res.err
|
||||
case <-time.After(temperatureFetchTimeout):
|
||||
return nil, errTemperatureFetchTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// isValidSensor checks if a sensor is valid based on the sensor name and the sensor config
|
||||
func isValidSensor(sensorName string, config *SensorConfig) bool {
|
||||
// if no sensors configured, everything is valid
|
||||
|
||||
@@ -5,8 +5,8 @@ package agent
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
|
||||
@@ -329,34 +329,10 @@ func TestNewSensorConfigWithEnv(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewSensorConfig(t *testing.T) {
|
||||
// Save original environment variables
|
||||
originalPrimary, hasPrimary := os.LookupEnv("BESZEL_AGENT_PRIMARY_SENSOR")
|
||||
originalSys, hasSys := os.LookupEnv("BESZEL_AGENT_SYS_SENSORS")
|
||||
originalSensors, hasSensors := os.LookupEnv("BESZEL_AGENT_SENSORS")
|
||||
|
||||
// Restore environment variables after the test
|
||||
defer func() {
|
||||
// Clean up test environment variables
|
||||
os.Unsetenv("BESZEL_AGENT_PRIMARY_SENSOR")
|
||||
os.Unsetenv("BESZEL_AGENT_SYS_SENSORS")
|
||||
os.Unsetenv("BESZEL_AGENT_SENSORS")
|
||||
|
||||
// Restore original values if they existed
|
||||
if hasPrimary {
|
||||
os.Setenv("BESZEL_AGENT_PRIMARY_SENSOR", originalPrimary)
|
||||
}
|
||||
if hasSys {
|
||||
os.Setenv("BESZEL_AGENT_SYS_SENSORS", originalSys)
|
||||
}
|
||||
if hasSensors {
|
||||
os.Setenv("BESZEL_AGENT_SENSORS", originalSensors)
|
||||
}
|
||||
}()
|
||||
|
||||
// Set test environment variables
|
||||
os.Setenv("BESZEL_AGENT_PRIMARY_SENSOR", "test_primary")
|
||||
os.Setenv("BESZEL_AGENT_SYS_SENSORS", "/test/path")
|
||||
os.Setenv("BESZEL_AGENT_SENSORS", "test_sensor1,test_*,test_sensor3")
|
||||
t.Setenv("BESZEL_AGENT_PRIMARY_SENSOR", "test_primary")
|
||||
t.Setenv("BESZEL_AGENT_SYS_SENSORS", "/test/path")
|
||||
t.Setenv("BESZEL_AGENT_SENSORS", "test_sensor1,test_*,test_sensor3")
|
||||
|
||||
agent := &Agent{}
|
||||
result := agent.newSensorConfig()
|
||||
@@ -551,3 +527,66 @@ func TestGetTempsWithPanicRecovery(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTempsWithTimeout(t *testing.T) {
|
||||
agent := &Agent{
|
||||
sensorConfig: &SensorConfig{
|
||||
context: context.Background(),
|
||||
},
|
||||
}
|
||||
|
||||
originalTimeout := temperatureFetchTimeout
|
||||
t.Cleanup(func() {
|
||||
temperatureFetchTimeout = originalTimeout
|
||||
})
|
||||
temperatureFetchTimeout = 10 * time.Millisecond
|
||||
|
||||
t.Run("returns temperatures before timeout", func(t *testing.T) {
|
||||
temps, err := agent.getTempsWithTimeout(func(ctx context.Context) ([]sensors.TemperatureStat, error) {
|
||||
return []sensors.TemperatureStat{{SensorKey: "cpu_temp", Temperature: 42}}, nil
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, temps, 1)
|
||||
assert.Equal(t, "cpu_temp", temps[0].SensorKey)
|
||||
})
|
||||
|
||||
t.Run("returns timeout error when collector hangs", func(t *testing.T) {
|
||||
temps, err := agent.getTempsWithTimeout(func(ctx context.Context) ([]sensors.TemperatureStat, error) {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
return []sensors.TemperatureStat{{SensorKey: "cpu_temp", Temperature: 42}}, nil
|
||||
})
|
||||
|
||||
assert.Nil(t, temps)
|
||||
assert.ErrorIs(t, err, errTemperatureFetchTimeout)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpdateTemperaturesSkipsOnTimeout(t *testing.T) {
|
||||
agent := &Agent{
|
||||
systemInfo: system.Info{DashboardTemp: 99},
|
||||
sensorConfig: &SensorConfig{
|
||||
context: context.Background(),
|
||||
},
|
||||
}
|
||||
|
||||
originalTimeout := temperatureFetchTimeout
|
||||
t.Cleanup(func() {
|
||||
temperatureFetchTimeout = originalTimeout
|
||||
getSensorTemps = sensors.TemperaturesWithContext
|
||||
})
|
||||
temperatureFetchTimeout = 10 * time.Millisecond
|
||||
getSensorTemps = func(ctx context.Context) ([]sensors.TemperatureStat, error) {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
stats := &system.Stats{
|
||||
Temperatures: map[string]float64{"stale": 50},
|
||||
}
|
||||
|
||||
agent.updateTemperatures(stats)
|
||||
|
||||
assert.Equal(t, 0.0, agent.systemInfo.DashboardTemp)
|
||||
assert.Equal(t, map[string]float64{}, stats.Temperatures)
|
||||
}
|
||||
|
||||
@@ -183,8 +183,7 @@ func TestStartServer(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStartServerDisableSSH(t *testing.T) {
|
||||
os.Setenv("BESZEL_AGENT_DISABLE_SSH", "true")
|
||||
defer os.Unsetenv("BESZEL_AGENT_DISABLE_SSH")
|
||||
t.Setenv("BESZEL_AGENT_DISABLE_SSH", "true")
|
||||
|
||||
agent, err := NewAgent("")
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1104,32 +1104,21 @@ func (sm *SmartManager) parseSmartForNvme(output []byte) (bool, int) {
|
||||
|
||||
// detectSmartctl checks if smartctl is installed, returns an error if not
|
||||
func (sm *SmartManager) detectSmartctl() (string, error) {
|
||||
isWindows := runtime.GOOS == "windows"
|
||||
|
||||
// Load embedded smartctl.exe for Windows amd64 builds.
|
||||
if isWindows && runtime.GOARCH == "amd64" {
|
||||
if path, err := ensureEmbeddedSmartctl(); err == nil {
|
||||
return path, nil
|
||||
if runtime.GOOS == "windows" {
|
||||
// Load embedded smartctl.exe for Windows amd64 builds.
|
||||
if runtime.GOARCH == "amd64" {
|
||||
if path, err := ensureEmbeddedSmartctl(); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if path, err := exec.LookPath("smartctl"); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
locations := []string{}
|
||||
if isWindows {
|
||||
locations = append(locations,
|
||||
"C:\\Program Files\\smartmontools\\bin\\smartctl.exe",
|
||||
)
|
||||
} else {
|
||||
locations = append(locations, "/opt/homebrew/bin/smartctl")
|
||||
}
|
||||
for _, location := range locations {
|
||||
// Try to find smartctl in the default installation location
|
||||
const location = "C:\\Program Files\\smartmontools\\bin\\smartctl.exe"
|
||||
if _, err := os.Stat(location); err == nil {
|
||||
return location, nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("smartctl not found")
|
||||
|
||||
return utils.LookPathHomebrew("smartctl")
|
||||
}
|
||||
|
||||
// isNvmeControllerPath checks if the path matches an NVMe controller pattern
|
||||
|
||||
@@ -1035,7 +1035,7 @@ func TestRefreshExcludedDevices(t *testing.T) {
|
||||
t.Setenv("EXCLUDE_SMART", tt.envValue)
|
||||
} else {
|
||||
// Ensure env var is not set for empty test
|
||||
os.Unsetenv("EXCLUDE_SMART")
|
||||
t.Setenv("EXCLUDE_SMART", "")
|
||||
}
|
||||
|
||||
sm := &SmartManager{}
|
||||
|
||||
@@ -167,16 +167,12 @@ func TestGetServicePatterns(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Clean up any existing env vars
|
||||
os.Unsetenv("BESZEL_AGENT_SERVICE_PATTERNS")
|
||||
os.Unsetenv("SERVICE_PATTERNS")
|
||||
|
||||
// Set up environment variables
|
||||
if tt.prefixedEnv != "" {
|
||||
os.Setenv("BESZEL_AGENT_SERVICE_PATTERNS", tt.prefixedEnv)
|
||||
t.Setenv("BESZEL_AGENT_SERVICE_PATTERNS", tt.prefixedEnv)
|
||||
}
|
||||
if tt.unprefixedEnv != "" {
|
||||
os.Setenv("SERVICE_PATTERNS", tt.unprefixedEnv)
|
||||
t.Setenv("SERVICE_PATTERNS", tt.unprefixedEnv)
|
||||
}
|
||||
|
||||
// Run the function
|
||||
@@ -184,12 +180,6 @@ func TestGetServicePatterns(t *testing.T) {
|
||||
|
||||
// Verify results
|
||||
assert.Equal(t, tt.expected, result, "Patterns should match expected values")
|
||||
|
||||
// Cleanup
|
||||
if tt.cleanupEnvVars {
|
||||
os.Unsetenv("BESZEL_AGENT_SERVICE_PATTERNS")
|
||||
os.Unsetenv("SERVICE_PATTERNS")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import (
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@@ -86,3 +89,24 @@ func ReadUintFile(path string) (uint64, bool) {
|
||||
}
|
||||
return parsed, true
|
||||
}
|
||||
|
||||
// LookPathHomebrew is like exec.LookPath but also checks Homebrew paths.
|
||||
func LookPathHomebrew(file string) (string, error) {
|
||||
foundPath, lookPathErr := exec.LookPath(file)
|
||||
if lookPathErr == nil {
|
||||
return foundPath, nil
|
||||
}
|
||||
var homebrewPath string
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
homebrewPath = filepath.Join("/opt", "homebrew", "bin", file)
|
||||
case "linux":
|
||||
homebrewPath = filepath.Join("/home", "linuxbrew", ".linuxbrew", "bin", file)
|
||||
}
|
||||
if homebrewPath != "" {
|
||||
if _, err := os.Stat(homebrewPath); err == nil {
|
||||
return homebrewPath, nil
|
||||
}
|
||||
}
|
||||
return "", lookPathErr
|
||||
}
|
||||
|
||||
@@ -134,10 +134,8 @@ func TestGetEnv(t *testing.T) {
|
||||
prefixedKey := "BESZEL_AGENT_" + key
|
||||
|
||||
t.Run("prefixed variable exists", func(t *testing.T) {
|
||||
os.Setenv(prefixedKey, "prefixed_val")
|
||||
os.Setenv(key, "unprefixed_val")
|
||||
defer os.Unsetenv(prefixedKey)
|
||||
defer os.Unsetenv(key)
|
||||
t.Setenv(prefixedKey, "prefixed_val")
|
||||
t.Setenv(key, "unprefixed_val")
|
||||
|
||||
val, exists := GetEnv(key)
|
||||
assert.True(t, exists)
|
||||
@@ -145,9 +143,7 @@ func TestGetEnv(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("only unprefixed variable exists", func(t *testing.T) {
|
||||
os.Unsetenv(prefixedKey)
|
||||
os.Setenv(key, "unprefixed_val")
|
||||
defer os.Unsetenv(key)
|
||||
t.Setenv(key, "unprefixed_val")
|
||||
|
||||
val, exists := GetEnv(key)
|
||||
assert.True(t, exists)
|
||||
@@ -155,9 +151,6 @@ func TestGetEnv(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("neither variable exists", func(t *testing.T) {
|
||||
os.Unsetenv(prefixedKey)
|
||||
os.Unsetenv(key)
|
||||
|
||||
val, exists := GetEnv(key)
|
||||
assert.False(t, exists)
|
||||
assert.Empty(t, val)
|
||||
|
||||
@@ -6,7 +6,7 @@ import "github.com/blang/semver"
|
||||
|
||||
const (
|
||||
// Version is the current version of the application.
|
||||
Version = "0.18.4"
|
||||
Version = "0.18.5"
|
||||
// AppName is the name of the application.
|
||||
AppName = "beszel"
|
||||
)
|
||||
|
||||
41
go.mod
41
go.mod
@@ -6,22 +6,22 @@ require (
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/coreos/go-systemd/v22 v22.7.0
|
||||
github.com/distatus/battery v0.11.0
|
||||
github.com/ebitengine/purego v0.9.1
|
||||
github.com/ebitengine/purego v0.10.0
|
||||
github.com/fxamacker/cbor/v2 v2.9.0
|
||||
github.com/gliderlabs/ssh v0.3.8
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/lxzan/gws v1.8.9
|
||||
github.com/nicholas-fedor/shoutrrr v0.13.2
|
||||
github.com/lxzan/gws v1.9.1
|
||||
github.com/nicholas-fedor/shoutrrr v0.14.1
|
||||
github.com/pocketbase/dbx v1.12.0
|
||||
github.com/pocketbase/pocketbase v0.36.4
|
||||
github.com/shirou/gopsutil/v4 v4.26.1
|
||||
github.com/pocketbase/pocketbase v0.36.7
|
||||
github.com/shirou/gopsutil/v4 v4.26.2
|
||||
github.com/spf13/cast v1.10.0
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/stretchr/testify v1.11.1
|
||||
golang.org/x/crypto v0.48.0
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa
|
||||
golang.org/x/sys v0.41.0
|
||||
golang.org/x/crypto v0.49.0
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90
|
||||
golang.org/x/sys v0.42.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -30,10 +30,10 @@ require (
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/disintegration/imaging v1.6.2 // indirect
|
||||
github.com/dolthub/maphash v0.1.0 // indirect
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/eclipse/paho.golang v0.23.0 // indirect
|
||||
github.com/fatih/color v1.19.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
|
||||
github.com/ganigeorgiev/fexpr v0.5.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
@@ -41,9 +41,10 @@ require (
|
||||
github.com/go-sql-driver/mysql v1.9.1 // indirect
|
||||
github.com/godbus/dbus/v5 v5.2.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.18.4 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 // indirect
|
||||
github.com/klauspost/compress v1.18.5 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20260324052639-156f7da3f749 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||
@@ -54,15 +55,15 @@ require (
|
||||
github.com/tklauser/numcpus v0.11.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
golang.org/x/image v0.36.0 // indirect
|
||||
golang.org/x/net v0.50.0 // indirect
|
||||
golang.org/x/oauth2 v0.35.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/term v0.40.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
golang.org/x/image v0.38.0 // indirect
|
||||
golang.org/x/net v0.52.0 // indirect
|
||||
golang.org/x/oauth2 v0.36.0 // indirect
|
||||
golang.org/x/sync v0.20.0 // indirect
|
||||
golang.org/x/term v0.41.0 // indirect
|
||||
golang.org/x/text v0.35.0 // indirect
|
||||
howett.net/plist v1.0.1 // indirect
|
||||
modernc.org/libc v1.67.6 // indirect
|
||||
modernc.org/libc v1.70.0 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.45.0 // indirect
|
||||
modernc.org/sqlite v1.46.2 // indirect
|
||||
)
|
||||
|
||||
112
go.sum
112
go.sum
@@ -19,16 +19,16 @@ github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/distatus/battery v0.11.0 h1:KJk89gz90Iq/wJtbjjM9yUzBXV+ASV/EG2WOOL7N8lc=
|
||||
github.com/distatus/battery v0.11.0/go.mod h1:KmVkE8A8hpIX4T78QRdMktYpEp35QfOL8A8dwZBxq2k=
|
||||
github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ=
|
||||
github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4=
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8=
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
|
||||
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=
|
||||
github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/eclipse/paho.golang v0.23.0 h1:KHgl2wz6EJo7cMBmkuhpt7C576vP+kpPv7jjvSyR6Mk=
|
||||
github.com/eclipse/paho.golang v0.23.0/go.mod h1:nQRhTkoZv8EAiNs5UU0/WdQIx2NrnWUpL9nsGJTQN04=
|
||||
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
|
||||
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||
@@ -58,10 +58,12 @@ github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArs
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
|
||||
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
|
||||
github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc h1:VBbFa1lDYWEeV5FZKUiYKYT0VxCp9twUmmaq9eb8sXw=
|
||||
github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
@@ -69,24 +71,24 @@ github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf
|
||||
github.com/jarcoal/httpmock v1.4.1 h1:0Ju+VCFuARfFlhVXFc2HxlcQkfB+Xq12/EotHko+x2A=
|
||||
github.com/jarcoal/httpmock v1.4.1/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
|
||||
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
|
||||
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 h1:PTw+yKnXcOFCR6+8hHTyWBeQ/P4Nb7dd4/0ohEcWQuM=
|
||||
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
github.com/lxzan/gws v1.8.9 h1:VU3SGUeWlQrEwfUSfokcZep8mdg/BrUF+y73YYshdBM=
|
||||
github.com/lxzan/gws v1.8.9/go.mod h1:d9yHaR1eDTBHagQC6KY7ycUOaz5KWeqQtP3xu7aMK8Y=
|
||||
github.com/lufia/plan9stats v0.0.0-20260324052639-156f7da3f749 h1:Qj3hTcdWH8uMZDI41HNuTuJN525C7NBrbtH5kSO6fPk=
|
||||
github.com/lufia/plan9stats v0.0.0-20260324052639-156f7da3f749/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
github.com/lxzan/gws v1.9.1 h1:4lbIp4cW0hOLP3ejFHR/uWRy741AURx7oKkNNi2OT9o=
|
||||
github.com/lxzan/gws v1.9.1/go.mod h1:gXHSCPmTGryWJ4icuqy8Yho32E4YIMHH0fkDRYJRbdc=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/ncruces/go-strftime 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.13.2 h1:hfsYBIqSFYGg92pZP5CXk/g7/OJIkLYmiUnRl+AD1IA=
|
||||
github.com/nicholas-fedor/shoutrrr v0.13.2/go.mod h1:ZqzV3gY/Wj6AvWs1etlO7+yKbh4iptSbeL8avBpMQbA=
|
||||
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/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=
|
||||
@@ -96,8 +98,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pocketbase/dbx v1.12.0 h1:/oLErM+A0b4xI0PWTGPqSDVjzix48PqI/bng2l0PzoA=
|
||||
github.com/pocketbase/dbx v1.12.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
|
||||
github.com/pocketbase/pocketbase v0.36.4 h1:zTjRZbp2WfTOJJfb+pFRWa200UaQwxZYt8RzkFMlAZ4=
|
||||
github.com/pocketbase/pocketbase v0.36.4/go.mod h1:9CiezhRudd9FZGa5xZa53QZBTNxc5vvw/FGG+diAECI=
|
||||
github.com/pocketbase/pocketbase v0.36.7 h1:MrViB7BptPYrf2Nt25pJEYBqUdFjuhRKu1p5GTrkvPA=
|
||||
github.com/pocketbase/pocketbase v0.36.7/go.mod h1:qX4HuVjoKXtEg41fSJVM0JLfGWXbBmHxVv/FaE446r4=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
@@ -105,8 +107,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shirou/gopsutil/v4 v4.26.1 h1:TOkEyriIXk2HX9d4isZJtbjXbEjf5qyKPAzbzY0JWSo=
|
||||
github.com/shirou/gopsutil/v4 v4.26.1/go.mod h1:medLI9/UNAb0dOI9Q3/7yWSqKkj00u+1tgY8nvv41pc=
|
||||
github.com/shirou/gopsutil/v4 v4.26.2 h1:X8i6sicvUFih4BmYIGT1m2wwgw2VG9YgrDTi7cIRGUI=
|
||||
github.com/shirou/gopsutil/v4 v4.26.2/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
|
||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||
@@ -115,6 +117,8 @@ github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
|
||||
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
@@ -126,44 +130,44 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
|
||||
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
|
||||
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
||||
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
||||
golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE=
|
||||
golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY=
|
||||
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
|
||||
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
|
||||
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
||||
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
|
||||
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
@@ -175,18 +179,18 @@ howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
|
||||
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||
modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
|
||||
modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc=
|
||||
modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM=
|
||||
modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA=
|
||||
modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
|
||||
modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw=
|
||||
modernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0=
|
||||
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
|
||||
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
|
||||
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE=
|
||||
modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||
modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=
|
||||
modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI=
|
||||
modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE=
|
||||
modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw=
|
||||
modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
@@ -195,8 +199,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.45.0 h1:r51cSGzKpbptxnby+EIIz5fop4VuE4qFoVEjNvWoObs=
|
||||
modernc.org/sqlite v1.45.0/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA=
|
||||
modernc.org/sqlite v1.46.2 h1:gkXQ6R0+AjxFC/fTDaeIVLbNLNrRoOK7YYVz5BKhTcE=
|
||||
modernc.org/sqlite v1.46.2/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
|
||||
@@ -15,6 +15,19 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func setStatusAlertEmail(t *testing.T, hub core.App, userID, email string) {
|
||||
t.Helper()
|
||||
|
||||
userSettings, err := hub.FindFirstRecordByFilter("user_settings", "user={:user}", map[string]any{"user": userID})
|
||||
require.NoError(t, err)
|
||||
|
||||
userSettings.Set("settings", map[string]any{
|
||||
"emails": []string{email},
|
||||
"webhooks": []string{},
|
||||
})
|
||||
require.NoError(t, hub.Save(userSettings))
|
||||
}
|
||||
|
||||
func TestStatusAlerts(t *testing.T) {
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
hub, user := beszelTests.GetHubWithUser(t)
|
||||
@@ -322,6 +335,181 @@ func TestStatusAlertDownFiresAfterDelayExpires(t *testing.T) {
|
||||
assert.True(t, alertRecord.GetBool("triggered"), "alert should be marked triggered after downtime matures")
|
||||
}
|
||||
|
||||
func TestStatusAlertMultipleUsersRespectDifferentMinutes(t *testing.T) {
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
hub, user1 := beszelTests.GetHubWithUser(t)
|
||||
defer hub.Cleanup()
|
||||
|
||||
setStatusAlertEmail(t, hub, user1.Id, "user1@example.com")
|
||||
|
||||
user2, err := beszelTests.CreateUser(hub, "user2@example.com", "password")
|
||||
require.NoError(t, err)
|
||||
_, err = beszelTests.CreateRecord(hub, "user_settings", map[string]any{
|
||||
"user": user2.Id,
|
||||
"settings": map[string]any{
|
||||
"emails": []string{"user2@example.com"},
|
||||
"webhooks": []string{},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
system, err := beszelTests.CreateRecord(hub, "systems", map[string]any{
|
||||
"name": "shared-system",
|
||||
"users": []string{user1.Id, user2.Id},
|
||||
"host": "127.0.0.1",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
system.Set("status", "up")
|
||||
require.NoError(t, hub.SaveNoValidate(system))
|
||||
|
||||
alertUser1, err := beszelTests.CreateRecord(hub, "alerts", map[string]any{
|
||||
"name": "Status",
|
||||
"system": system.Id,
|
||||
"user": user1.Id,
|
||||
"min": 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
alertUser2, err := beszelTests.CreateRecord(hub, "alerts", map[string]any{
|
||||
"name": "Status",
|
||||
"system": system.Id,
|
||||
"user": user2.Id,
|
||||
"min": 2,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
system.Set("status", "down")
|
||||
require.NoError(t, hub.SaveNoValidate(system))
|
||||
|
||||
assert.Equal(t, 2, hub.GetPendingAlertsCount(), "both user alerts should be pending after the system goes down")
|
||||
|
||||
time.Sleep(59 * time.Second)
|
||||
synctest.Wait()
|
||||
assert.Zero(t, hub.TestMailer.TotalSend(), "no messages should be sent before the earliest alert minute elapses")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
synctest.Wait()
|
||||
|
||||
messages := hub.TestMailer.Messages()
|
||||
require.Len(t, messages, 1, "only the first user's alert should send after one minute")
|
||||
require.Len(t, messages[0].To, 1)
|
||||
assert.Equal(t, "user1@example.com", messages[0].To[0].Address)
|
||||
assert.Contains(t, messages[0].Subject, "Connection to shared-system is down")
|
||||
assert.Equal(t, 1, hub.GetPendingAlertsCount(), "the later user alert should still be pending")
|
||||
|
||||
time.Sleep(58 * time.Second)
|
||||
synctest.Wait()
|
||||
assert.Equal(t, 1, hub.TestMailer.TotalSend(), "the second user's alert should still be waiting before two minutes")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
synctest.Wait()
|
||||
|
||||
messages = hub.TestMailer.Messages()
|
||||
require.Len(t, messages, 2, "both users should eventually receive their own status alert")
|
||||
require.Len(t, messages[1].To, 1)
|
||||
assert.Equal(t, "user2@example.com", messages[1].To[0].Address)
|
||||
assert.Contains(t, messages[1].Subject, "Connection to shared-system is down")
|
||||
assert.Zero(t, hub.GetPendingAlertsCount(), "all pending alerts should be consumed after both timers fire")
|
||||
|
||||
alertUser1, err = hub.FindRecordById("alerts", alertUser1.Id)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, alertUser1.GetBool("triggered"), "user1 alert should be marked triggered after delivery")
|
||||
|
||||
alertUser2, err = hub.FindRecordById("alerts", alertUser2.Id)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, alertUser2.GetBool("triggered"), "user2 alert should be marked triggered after delivery")
|
||||
})
|
||||
}
|
||||
|
||||
func TestStatusAlertMultipleUsersRecoveryBetweenMinutesOnlyAlertsEarlierUser(t *testing.T) {
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
hub, user1 := beszelTests.GetHubWithUser(t)
|
||||
defer hub.Cleanup()
|
||||
|
||||
setStatusAlertEmail(t, hub, user1.Id, "user1@example.com")
|
||||
|
||||
user2, err := beszelTests.CreateUser(hub, "user2@example.com", "password")
|
||||
require.NoError(t, err)
|
||||
_, err = beszelTests.CreateRecord(hub, "user_settings", map[string]any{
|
||||
"user": user2.Id,
|
||||
"settings": map[string]any{
|
||||
"emails": []string{"user2@example.com"},
|
||||
"webhooks": []string{},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
system, err := beszelTests.CreateRecord(hub, "systems", map[string]any{
|
||||
"name": "shared-system",
|
||||
"users": []string{user1.Id, user2.Id},
|
||||
"host": "127.0.0.1",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
system.Set("status", "up")
|
||||
require.NoError(t, hub.SaveNoValidate(system))
|
||||
|
||||
alertUser1, err := beszelTests.CreateRecord(hub, "alerts", map[string]any{
|
||||
"name": "Status",
|
||||
"system": system.Id,
|
||||
"user": user1.Id,
|
||||
"min": 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
alertUser2, err := beszelTests.CreateRecord(hub, "alerts", map[string]any{
|
||||
"name": "Status",
|
||||
"system": system.Id,
|
||||
"user": user2.Id,
|
||||
"min": 2,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
system.Set("status", "down")
|
||||
require.NoError(t, hub.SaveNoValidate(system))
|
||||
|
||||
time.Sleep(61 * time.Second)
|
||||
synctest.Wait()
|
||||
|
||||
messages := hub.TestMailer.Messages()
|
||||
require.Len(t, messages, 1, "the first user's down alert should send before recovery")
|
||||
require.Len(t, messages[0].To, 1)
|
||||
assert.Equal(t, "user1@example.com", messages[0].To[0].Address)
|
||||
assert.Contains(t, messages[0].Subject, "Connection to shared-system is down")
|
||||
assert.Equal(t, 1, hub.GetPendingAlertsCount(), "the second user's alert should still be pending")
|
||||
|
||||
system.Set("status", "up")
|
||||
require.NoError(t, hub.SaveNoValidate(system))
|
||||
|
||||
time.Sleep(time.Second)
|
||||
synctest.Wait()
|
||||
|
||||
messages = hub.TestMailer.Messages()
|
||||
require.Len(t, messages, 2, "recovery should notify only the user whose down alert had already triggered")
|
||||
for _, message := range messages {
|
||||
require.Len(t, message.To, 1)
|
||||
assert.Equal(t, "user1@example.com", message.To[0].Address)
|
||||
}
|
||||
assert.Contains(t, messages[1].Subject, "Connection to shared-system is up")
|
||||
assert.Zero(t, hub.GetPendingAlertsCount(), "recovery should cancel the later user's pending alert")
|
||||
|
||||
time.Sleep(61 * time.Second)
|
||||
synctest.Wait()
|
||||
|
||||
messages = hub.TestMailer.Messages()
|
||||
require.Len(t, messages, 2, "user2 should never receive a down alert once recovery cancels the pending timer")
|
||||
|
||||
alertUser1, err = hub.FindRecordById("alerts", alertUser1.Id)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, alertUser1.GetBool("triggered"), "user1 alert should be cleared after recovery")
|
||||
|
||||
alertUser2, err = hub.FindRecordById("alerts", alertUser2.Id)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, alertUser2.GetBool("triggered"), "user2 alert should remain untriggered because it never fired")
|
||||
})
|
||||
}
|
||||
|
||||
func TestStatusAlertDuplicateDownCallIsIdempotent(t *testing.T) {
|
||||
hub, user := beszelTests.GetHubWithUser(t)
|
||||
defer hub.Cleanup()
|
||||
|
||||
@@ -28,8 +28,8 @@ func main() {
|
||||
}
|
||||
|
||||
baseApp := getBaseApp()
|
||||
h := hub.NewHub(baseApp)
|
||||
if err := h.StartHub(); err != nil {
|
||||
hub := hub.NewHub(baseApp)
|
||||
if err := hub.StartHub(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,21 +110,13 @@ func (p *updater) update() (updated bool, err error) {
|
||||
}
|
||||
|
||||
var latest *release
|
||||
var useMirror bool
|
||||
|
||||
// Determine the API endpoint based on UseMirror flag
|
||||
apiURL := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", p.config.Owner, p.config.Repo)
|
||||
apiURL := getApiURL(p.config.UseMirror, p.config.Owner, p.config.Repo)
|
||||
if p.config.UseMirror {
|
||||
useMirror = true
|
||||
apiURL = fmt.Sprintf("https://gh.beszel.dev/repos/%s/%s/releases/latest?api=true", p.config.Owner, p.config.Repo)
|
||||
ColorPrint(ColorYellow, "Using mirror for update.")
|
||||
}
|
||||
|
||||
latest, err = fetchLatestRelease(
|
||||
p.config.Context,
|
||||
p.config.HttpClient,
|
||||
apiURL,
|
||||
)
|
||||
latest, err = FetchLatestRelease(p.config.Context, p.config.HttpClient, apiURL)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -150,7 +142,7 @@ func (p *updater) update() (updated bool, err error) {
|
||||
|
||||
// download the release asset
|
||||
assetPath := filepath.Join(releaseDir, asset.Name)
|
||||
if err := downloadFile(p.config.Context, p.config.HttpClient, asset.DownloadUrl, assetPath, useMirror); err != nil {
|
||||
if err := downloadFile(p.config.Context, p.config.HttpClient, asset.DownloadUrl, assetPath, p.config.UseMirror); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -226,11 +218,11 @@ func (p *updater) update() (updated bool, err error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func fetchLatestRelease(
|
||||
ctx context.Context,
|
||||
client HttpClient,
|
||||
url string,
|
||||
) (*release, error) {
|
||||
func FetchLatestRelease(ctx context.Context, client HttpClient, url string) (*release, error) {
|
||||
if url == "" {
|
||||
url = getApiURL(false, "henrygd", "beszel")
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -375,3 +367,10 @@ func isGlibc() bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getApiURL(useMirror bool, owner, repo string) string {
|
||||
if useMirror {
|
||||
return fmt.Sprintf("https://gh.beszel.dev/repos/%s/%s/releases/latest?api=true", owner, repo)
|
||||
}
|
||||
return fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", owner, repo)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ func createTestHub(t testing.TB) (*Hub, *pbtests.TestApp, error) {
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return NewHub(testApp), testApp, nil
|
||||
return NewHub(testApp), testApp, err
|
||||
}
|
||||
|
||||
// cleanupTestHub stops background system goroutines before tearing down the app.
|
||||
@@ -897,12 +897,8 @@ func TestAgentWebSocketIntegration(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up environment variables for the agent
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", ts.URL)
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", tc.agentToken)
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", ts.URL)
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", tc.agentToken)
|
||||
|
||||
// Start agent in background
|
||||
done := make(chan error, 1)
|
||||
@@ -1080,12 +1076,8 @@ func TestMultipleSystemsWithSameUniversalToken(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up environment variables for the agent
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", ts.URL)
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", universalToken)
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", ts.URL)
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", universalToken)
|
||||
|
||||
// Count systems before connection
|
||||
systemsBefore, err := testApp.FindRecordsByFilter("systems", "users ~ {:userId}", "", -1, 0, map[string]any{"userId": userRecord.Id})
|
||||
@@ -1243,12 +1235,8 @@ func TestPermanentUniversalTokenFromDB(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up environment variables for the agent
|
||||
os.Setenv("BESZEL_AGENT_HUB_URL", ts.URL)
|
||||
os.Setenv("BESZEL_AGENT_TOKEN", universalToken)
|
||||
defer func() {
|
||||
os.Unsetenv("BESZEL_AGENT_HUB_URL")
|
||||
os.Unsetenv("BESZEL_AGENT_TOKEN")
|
||||
}()
|
||||
t.Setenv("BESZEL_AGENT_HUB_URL", ts.URL)
|
||||
t.Setenv("BESZEL_AGENT_TOKEN", universalToken)
|
||||
|
||||
// Start agent in background
|
||||
done := make(chan error, 1)
|
||||
|
||||
361
internal/hub/api.go
Normal file
361
internal/hub/api.go
Normal file
@@ -0,0 +1,361 @@
|
||||
package hub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/google/uuid"
|
||||
"github.com/henrygd/beszel"
|
||||
"github.com/henrygd/beszel/internal/alerts"
|
||||
"github.com/henrygd/beszel/internal/ghupdate"
|
||||
"github.com/henrygd/beszel/internal/hub/config"
|
||||
"github.com/henrygd/beszel/internal/hub/systems"
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/apis"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
)
|
||||
|
||||
// UpdateInfo holds information about the latest update check
|
||||
type UpdateInfo struct {
|
||||
lastCheck time.Time
|
||||
Version string `json:"v"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
// registerMiddlewares registers custom middlewares
|
||||
func (h *Hub) registerMiddlewares(se *core.ServeEvent) {
|
||||
// authorizes request with user matching the provided email
|
||||
authorizeRequestWithEmail := func(e *core.RequestEvent, email string) (err error) {
|
||||
if e.Auth != nil || email == "" {
|
||||
return e.Next()
|
||||
}
|
||||
isAuthRefresh := e.Request.URL.Path == "/api/collections/users/auth-refresh" && e.Request.Method == http.MethodPost
|
||||
e.Auth, err = e.App.FindFirstRecordByData("users", "email", email)
|
||||
if err != nil || !isAuthRefresh {
|
||||
return e.Next()
|
||||
}
|
||||
// auth refresh endpoint, make sure token is set in header
|
||||
token, _ := e.Auth.NewAuthToken()
|
||||
e.Request.Header.Set("Authorization", token)
|
||||
return e.Next()
|
||||
}
|
||||
// authenticate with trusted header
|
||||
if autoLogin, _ := 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 != "" {
|
||||
se.Router.BindFunc(func(e *core.RequestEvent) error {
|
||||
return authorizeRequestWithEmail(e, e.Request.Header.Get(trustedHeader))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// registerApiRoutes registers custom API routes
|
||||
func (h *Hub) registerApiRoutes(se *core.ServeEvent) error {
|
||||
// auth protected routes
|
||||
apiAuth := se.Router.Group("/api/beszel")
|
||||
apiAuth.Bind(apis.RequireAuth())
|
||||
// auth optional routes
|
||||
apiNoAuth := se.Router.Group("/api/beszel")
|
||||
|
||||
// create first user endpoint only needed if no users exist
|
||||
if totalUsers, _ := se.App.CountRecords("users"); totalUsers == 0 {
|
||||
apiNoAuth.POST("/create-user", h.um.CreateFirstUser)
|
||||
}
|
||||
// check if first time setup on login page
|
||||
apiNoAuth.GET("/first-run", func(e *core.RequestEvent) error {
|
||||
total, err := e.App.CountRecords("users")
|
||||
return e.JSON(http.StatusOK, map[string]bool{"firstRun": err == nil && total == 0})
|
||||
})
|
||||
// get public key and version
|
||||
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" {
|
||||
var updateInfo UpdateInfo
|
||||
apiAuth.GET("/update", updateInfo.getUpdate)
|
||||
}
|
||||
// send test notification
|
||||
apiAuth.POST("/test-notification", h.SendTestNotification)
|
||||
// heartbeat status and test
|
||||
apiAuth.GET("/heartbeat-status", h.getHeartbeatStatus)
|
||||
apiAuth.POST("/test-heartbeat", h.testHeartbeat)
|
||||
// get config.yml content
|
||||
apiAuth.GET("/config-yaml", config.GetYamlConfig)
|
||||
// handle agent websocket connection
|
||||
apiNoAuth.GET("/agent-connect", h.handleAgentConnect)
|
||||
// get or create universal tokens
|
||||
apiAuth.GET("/universal-token", h.getUniversalToken)
|
||||
// update / delete user alerts
|
||||
apiAuth.POST("/user-alerts", alerts.UpsertUserAlerts)
|
||||
apiAuth.DELETE("/user-alerts", alerts.DeleteUserAlerts)
|
||||
// refresh SMART devices for a system
|
||||
apiAuth.POST("/smart/refresh", h.refreshSmartData)
|
||||
// get systemd service details
|
||||
apiAuth.GET("/systemd/info", h.getSystemdInfo)
|
||||
// /containers routes
|
||||
if enabled, _ := GetEnv("CONTAINER_DETAILS"); enabled != "false" {
|
||||
// get container logs
|
||||
apiAuth.GET("/containers/logs", h.getContainerLogs)
|
||||
// get container info
|
||||
apiAuth.GET("/containers/info", h.getContainerInfo)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getInfo returns data needed by authenticated users, such as the public key and current version
|
||||
func (h *Hub) getInfo(e *core.RequestEvent) error {
|
||||
type infoResponse struct {
|
||||
Key string `json:"key"`
|
||||
Version string `json:"v"`
|
||||
CheckUpdate bool `json:"cu"`
|
||||
}
|
||||
info := infoResponse{
|
||||
Key: h.pubKey,
|
||||
Version: beszel.Version,
|
||||
}
|
||||
if optIn, _ := GetEnv("CHECK_UPDATES"); optIn == "true" {
|
||||
info.CheckUpdate = true
|
||||
}
|
||||
return e.JSON(http.StatusOK, info)
|
||||
}
|
||||
|
||||
// getUpdate checks for the latest release on GitHub and returns update info if a newer version is available
|
||||
func (info *UpdateInfo) getUpdate(e *core.RequestEvent) error {
|
||||
if time.Since(info.lastCheck) < 6*time.Hour {
|
||||
return e.JSON(http.StatusOK, info)
|
||||
}
|
||||
info.lastCheck = time.Now()
|
||||
latestRelease, err := ghupdate.FetchLatestRelease(context.Background(), http.DefaultClient, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentVersion, err := semver.Parse(strings.TrimPrefix(beszel.Version, "v"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
latestVersion, err := semver.Parse(strings.TrimPrefix(latestRelease.Tag, "v"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if latestVersion.GT(currentVersion) {
|
||||
info.Version = strings.TrimPrefix(latestRelease.Tag, "v")
|
||||
info.Url = latestRelease.Url
|
||||
}
|
||||
return e.JSON(http.StatusOK, info)
|
||||
}
|
||||
|
||||
// GetUniversalToken handles the universal token API endpoint (create, read, delete)
|
||||
func (h *Hub) getUniversalToken(e *core.RequestEvent) error {
|
||||
tokenMap := universalTokenMap.GetMap()
|
||||
userID := e.Auth.Id
|
||||
query := e.Request.URL.Query()
|
||||
token := query.Get("token")
|
||||
enable := query.Get("enable")
|
||||
permanent := query.Get("permanent")
|
||||
|
||||
// helper for deleting any existing permanent token record for this user
|
||||
deletePermanent := func() error {
|
||||
rec, err := h.FindFirstRecordByFilter("universal_tokens", "user = {:user}", dbx.Params{"user": userID})
|
||||
if err != nil {
|
||||
return nil // no record
|
||||
}
|
||||
return h.Delete(rec)
|
||||
}
|
||||
|
||||
// helper for upserting a permanent token record for this user
|
||||
upsertPermanent := func(token string) error {
|
||||
rec, err := h.FindFirstRecordByFilter("universal_tokens", "user = {:user}", dbx.Params{"user": userID})
|
||||
if err == nil {
|
||||
rec.Set("token", token)
|
||||
return h.Save(rec)
|
||||
}
|
||||
|
||||
col, err := h.FindCachedCollectionByNameOrId("universal_tokens")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newRec := core.NewRecord(col)
|
||||
newRec.Set("user", userID)
|
||||
newRec.Set("token", token)
|
||||
return h.Save(newRec)
|
||||
}
|
||||
|
||||
// Disable universal tokens (both ephemeral and permanent)
|
||||
if enable == "0" {
|
||||
tokenMap.RemovebyValue(userID)
|
||||
_ = deletePermanent()
|
||||
return e.JSON(http.StatusOK, map[string]any{"token": token, "active": false, "permanent": false})
|
||||
}
|
||||
|
||||
// Enable universal token (ephemeral or permanent)
|
||||
if enable == "1" {
|
||||
if token == "" {
|
||||
token = uuid.New().String()
|
||||
}
|
||||
|
||||
if permanent == "1" {
|
||||
// make token permanent (persist across restarts)
|
||||
tokenMap.RemovebyValue(userID)
|
||||
if err := upsertPermanent(token); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.JSON(http.StatusOK, map[string]any{"token": token, "active": true, "permanent": true})
|
||||
}
|
||||
|
||||
// default: ephemeral mode (1 hour)
|
||||
_ = deletePermanent()
|
||||
tokenMap.Set(token, userID, time.Hour)
|
||||
return e.JSON(http.StatusOK, map[string]any{"token": token, "active": true, "permanent": false})
|
||||
}
|
||||
|
||||
// Read current state
|
||||
// Prefer permanent token if it exists.
|
||||
if rec, err := h.FindFirstRecordByFilter("universal_tokens", "user = {:user}", dbx.Params{"user": userID}); err == nil {
|
||||
dbToken := rec.GetString("token")
|
||||
// If no token was provided, or the caller is asking about their permanent token, return it.
|
||||
if token == "" || token == dbToken {
|
||||
return e.JSON(http.StatusOK, map[string]any{"token": dbToken, "active": true, "permanent": true})
|
||||
}
|
||||
// Token doesn't match their permanent token (avoid leaking other info)
|
||||
return e.JSON(http.StatusOK, map[string]any{"token": token, "active": false, "permanent": false})
|
||||
}
|
||||
|
||||
// No permanent token; fall back to ephemeral token map.
|
||||
if token == "" {
|
||||
// return existing token if it exists
|
||||
if token, _, ok := tokenMap.GetByValue(userID); ok {
|
||||
return e.JSON(http.StatusOK, map[string]any{"token": token, "active": true, "permanent": false})
|
||||
}
|
||||
// if no token is provided, generate a new one
|
||||
token = uuid.New().String()
|
||||
}
|
||||
|
||||
// Token is considered active only if it belongs to the current user.
|
||||
activeUser, ok := tokenMap.GetOk(token)
|
||||
active := ok && activeUser == userID
|
||||
response := map[string]any{"token": token, "active": active, "permanent": false}
|
||||
return e.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
// getHeartbeatStatus returns current heartbeat configuration and whether it's enabled
|
||||
func (h *Hub) getHeartbeatStatus(e *core.RequestEvent) error {
|
||||
if e.Auth.GetString("role") != "admin" {
|
||||
return e.ForbiddenError("Requires admin role", nil)
|
||||
}
|
||||
if h.hb == nil {
|
||||
return e.JSON(http.StatusOK, map[string]any{
|
||||
"enabled": false,
|
||||
"msg": "Set HEARTBEAT_URL to enable outbound heartbeat monitoring",
|
||||
})
|
||||
}
|
||||
cfg := h.hb.GetConfig()
|
||||
return e.JSON(http.StatusOK, map[string]any{
|
||||
"enabled": true,
|
||||
"url": cfg.URL,
|
||||
"interval": cfg.Interval,
|
||||
"method": cfg.Method,
|
||||
})
|
||||
}
|
||||
|
||||
// testHeartbeat triggers a single heartbeat ping and returns the result
|
||||
func (h *Hub) testHeartbeat(e *core.RequestEvent) error {
|
||||
if e.Auth.GetString("role") != "admin" {
|
||||
return e.ForbiddenError("Requires admin role", nil)
|
||||
}
|
||||
if h.hb == nil {
|
||||
return e.JSON(http.StatusOK, map[string]any{
|
||||
"err": "Heartbeat not configured. Set HEARTBEAT_URL environment variable.",
|
||||
})
|
||||
}
|
||||
if err := h.hb.Send(); err != nil {
|
||||
return e.JSON(http.StatusOK, map[string]any{"err": err.Error()})
|
||||
}
|
||||
return e.JSON(http.StatusOK, map[string]any{"err": false})
|
||||
}
|
||||
|
||||
// containerRequestHandler handles both container logs and info requests
|
||||
func (h *Hub) containerRequestHandler(e *core.RequestEvent, fetchFunc func(*systems.System, string) (string, error), responseKey string) error {
|
||||
systemID := e.Request.URL.Query().Get("system")
|
||||
containerID := e.Request.URL.Query().Get("container")
|
||||
|
||||
if systemID == "" || containerID == "" {
|
||||
return e.JSON(http.StatusBadRequest, map[string]string{"error": "system and container parameters are required"})
|
||||
}
|
||||
if !containerIDPattern.MatchString(containerID) {
|
||||
return e.JSON(http.StatusBadRequest, map[string]string{"error": "invalid container parameter"})
|
||||
}
|
||||
|
||||
system, err := h.sm.GetSystem(systemID)
|
||||
if err != nil {
|
||||
return e.JSON(http.StatusNotFound, map[string]string{"error": "system not found"})
|
||||
}
|
||||
|
||||
data, err := fetchFunc(system, containerID)
|
||||
if err != nil {
|
||||
return e.JSON(http.StatusNotFound, map[string]string{"error": err.Error()})
|
||||
}
|
||||
|
||||
return e.JSON(http.StatusOK, map[string]string{responseKey: data})
|
||||
}
|
||||
|
||||
// getContainerLogs handles GET /api/beszel/containers/logs requests
|
||||
func (h *Hub) getContainerLogs(e *core.RequestEvent) error {
|
||||
return h.containerRequestHandler(e, func(system *systems.System, containerID string) (string, error) {
|
||||
return system.FetchContainerLogsFromAgent(containerID)
|
||||
}, "logs")
|
||||
}
|
||||
|
||||
func (h *Hub) getContainerInfo(e *core.RequestEvent) error {
|
||||
return h.containerRequestHandler(e, func(system *systems.System, containerID string) (string, error) {
|
||||
return system.FetchContainerInfoFromAgent(containerID)
|
||||
}, "info")
|
||||
}
|
||||
|
||||
// getSystemdInfo handles GET /api/beszel/systemd/info requests
|
||||
func (h *Hub) getSystemdInfo(e *core.RequestEvent) error {
|
||||
query := e.Request.URL.Query()
|
||||
systemID := query.Get("system")
|
||||
serviceName := query.Get("service")
|
||||
|
||||
if systemID == "" || serviceName == "" {
|
||||
return e.JSON(http.StatusBadRequest, map[string]string{"error": "system and service parameters are required"})
|
||||
}
|
||||
system, err := h.sm.GetSystem(systemID)
|
||||
if err != nil {
|
||||
return e.JSON(http.StatusNotFound, map[string]string{"error": "system not found"})
|
||||
}
|
||||
details, err := system.FetchSystemdInfoFromAgent(serviceName)
|
||||
if err != nil {
|
||||
return e.JSON(http.StatusNotFound, map[string]string{"error": err.Error()})
|
||||
}
|
||||
e.Response.Header().Set("Cache-Control", "public, max-age=60")
|
||||
return e.JSON(http.StatusOK, map[string]any{"details": details})
|
||||
}
|
||||
|
||||
// refreshSmartData handles POST /api/beszel/smart/refresh requests
|
||||
// Fetches fresh SMART data from the agent and updates the collection
|
||||
func (h *Hub) refreshSmartData(e *core.RequestEvent) error {
|
||||
systemID := e.Request.URL.Query().Get("system")
|
||||
if systemID == "" {
|
||||
return e.JSON(http.StatusBadRequest, map[string]string{"error": "system parameter is required"})
|
||||
}
|
||||
|
||||
system, err := h.sm.GetSystem(systemID)
|
||||
if err != nil {
|
||||
return e.JSON(http.StatusNotFound, map[string]string{"error": "system not found"})
|
||||
}
|
||||
|
||||
// Fetch and save SMART devices
|
||||
if err := system.FetchAndSaveSmartDevices(); err != nil {
|
||||
return e.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
}
|
||||
|
||||
return e.JSON(http.StatusOK, map[string]string{"status": "ok"})
|
||||
}
|
||||
780
internal/hub/api_test.go
Normal file
780
internal/hub/api_test.go
Normal file
@@ -0,0 +1,780 @@
|
||||
package hub_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
beszelTests "github.com/henrygd/beszel/internal/tests"
|
||||
|
||||
"github.com/henrygd/beszel/internal/migrations"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
pbTests "github.com/pocketbase/pocketbase/tests"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// 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 TestApiRoutesAuthentication(t *testing.T) {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
hub.StartHub()
|
||||
|
||||
// Create test user and get auth token
|
||||
user, err := beszelTests.CreateUser(hub, "testuser@example.com", "password123")
|
||||
require.NoError(t, err, "Failed to create test user")
|
||||
|
||||
adminUser, err := beszelTests.CreateRecord(hub, "users", map[string]any{
|
||||
"email": "admin@example.com",
|
||||
"password": "password123",
|
||||
"role": "admin",
|
||||
})
|
||||
require.NoError(t, err, "Failed to create admin user")
|
||||
adminUserToken, err := adminUser.NewAuthToken()
|
||||
|
||||
// superUser, err := beszelTests.CreateRecord(hub, core.CollectionNameSuperusers, map[string]any{
|
||||
// "email": "superuser@example.com",
|
||||
// "password": "password123",
|
||||
// })
|
||||
// require.NoError(t, err, "Failed to create superuser")
|
||||
|
||||
userToken, err := user.NewAuthToken()
|
||||
require.NoError(t, err, "Failed to create auth token")
|
||||
|
||||
// Create test system for user-alerts endpoints
|
||||
system, err := beszelTests.CreateRecord(hub, "systems", map[string]any{
|
||||
"name": "test-system",
|
||||
"users": []string{user.Id},
|
||||
"host": "127.0.0.1",
|
||||
})
|
||||
require.NoError(t, err, "Failed to create test system")
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
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,
|
||||
URL: "/api/beszel/config-yaml",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /config-yaml - with user auth should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/config-yaml",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 403,
|
||||
ExpectedContent: []string{"Requires admin"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /config-yaml - with admin auth should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/config-yaml",
|
||||
Headers: map[string]string{
|
||||
"Authorization": adminUserToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"test-system"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /heartbeat-status - no auth should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/heartbeat-status",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /heartbeat-status - with user auth should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/heartbeat-status",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 403,
|
||||
ExpectedContent: []string{"Requires admin role"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /heartbeat-status - with admin auth should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/heartbeat-status",
|
||||
Headers: map[string]string{
|
||||
"Authorization": adminUserToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{`"enabled":false`},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "POST /test-heartbeat - with user auth should fail",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/test-heartbeat",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 403,
|
||||
ExpectedContent: []string{"Requires admin role"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "POST /test-heartbeat - with admin auth should report disabled state",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/test-heartbeat",
|
||||
Headers: map[string]string{
|
||||
"Authorization": adminUserToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"Heartbeat not configured"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /universal-token - no auth should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/universal-token",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /universal-token - with auth should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/universal-token",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"active", "token", "permanent"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /universal-token - enable permanent should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/universal-token?enable=1&permanent=1&token=permanent-token-123",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"permanent\":true", "permanent-token-123"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "POST /user-alerts - no auth should fail",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/user-alerts",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
Body: jsonReader(map[string]any{
|
||||
"name": "CPU",
|
||||
"value": 80,
|
||||
"min": 10,
|
||||
"systems": []string{system.Id},
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "POST /user-alerts - with auth should succeed",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/user-alerts",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"success\":true"},
|
||||
TestAppFactory: testAppFactory,
|
||||
Body: jsonReader(map[string]any{
|
||||
"name": "CPU",
|
||||
"value": 80,
|
||||
"min": 10,
|
||||
"systems": []string{system.Id},
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "DELETE /user-alerts - no auth should fail",
|
||||
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{system.Id},
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "DELETE /user-alerts - with auth should succeed",
|
||||
Method: http.MethodDelete,
|
||||
URL: "/api/beszel/user-alerts",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"success\":true"},
|
||||
TestAppFactory: testAppFactory,
|
||||
Body: jsonReader(map[string]any{
|
||||
"name": "CPU",
|
||||
"systems": []string{system.Id},
|
||||
}),
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
// Create an alert to delete
|
||||
beszelTests.CreateRecord(app, "alerts", map[string]any{
|
||||
"name": "CPU",
|
||||
"system": system.Id,
|
||||
"user": user.Id,
|
||||
"value": 80,
|
||||
"min": 10,
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/logs - no auth should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/logs?system=test-system&container=test-container",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/logs - with auth but missing system param should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/logs?container=test-container",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{"system and container parameters are required"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/logs - with auth but missing container param should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/logs?system=test-system",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{"system and container parameters are required"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/logs - with auth but invalid system should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/logs?system=invalid-system&container=0123456789ab",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 404,
|
||||
ExpectedContent: []string{"system not found"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/logs - traversal container should fail validation",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/logs?system=" + system.Id + "&container=..%2F..%2Fversion",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{"invalid container parameter"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/info - traversal container should fail validation",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/info?system=" + system.Id + "&container=../../version?x=",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{"invalid container parameter"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/info - non-hex container should fail validation",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/info?system=" + system.Id + "&container=container_name",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{"invalid container parameter"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
|
||||
// Auth Optional Routes - Should work without authentication
|
||||
{
|
||||
Name: "GET /getkey - no auth should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /getkey - with auth should also succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"key\":", "\"v\":"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /info - should return the same as /getkey",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/info",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"key\":", "\"v\":"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /first-run - no auth should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/first-run",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"firstRun\":false"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /first-run - with auth should also succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/first-run",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"firstRun\":false"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /agent-connect - no auth should succeed (websocket upgrade fails but route is accessible)",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/agent-connect",
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "POST /test-notification - invalid auth token should fail",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/test-notification",
|
||||
Body: jsonReader(map[string]any{
|
||||
"url": "generic://127.0.0.1",
|
||||
}),
|
||||
Headers: map[string]string{
|
||||
"Authorization": "invalid-token",
|
||||
},
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "POST /user-alerts - invalid auth token should fail",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/user-alerts",
|
||||
Headers: map[string]string{
|
||||
"Authorization": "invalid-token",
|
||||
},
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
Body: jsonReader(map[string]any{
|
||||
"name": "CPU",
|
||||
"value": 80,
|
||||
"min": 10,
|
||||
"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,
|
||||
},
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
scenario.Test(t)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFirstUserCreation(t *testing.T) {
|
||||
t.Run("CreateUserEndpoint available when no users exist", func(t *testing.T) {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
hub.StartHub()
|
||||
|
||||
testAppFactoryExisting := func(t testing.TB) *pbTests.TestApp {
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenarios := []beszelTests.ApiScenario{
|
||||
{
|
||||
Name: "POST /create-user - should be available when no users exist",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/create-user",
|
||||
Body: jsonReader(map[string]any{
|
||||
"email": "firstuser@example.com",
|
||||
"password": "password123",
|
||||
}),
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"User created"},
|
||||
TestAppFactory: testAppFactoryExisting,
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
userCount, err := hub.CountRecords("users")
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, userCount, "Should start with no users")
|
||||
superusers, err := hub.FindAllRecords(core.CollectionNameSuperusers)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, len(superusers), "Should start with one temporary superuser")
|
||||
require.EqualValues(t, migrations.TempAdminEmail, superusers[0].GetString("email"), "Should have created one temporary superuser")
|
||||
},
|
||||
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
|
||||
userCount, err := hub.CountRecords("users")
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, userCount, "Should have created one user")
|
||||
superusers, err := hub.FindAllRecords(core.CollectionNameSuperusers)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, len(superusers), "Should have created one superuser")
|
||||
require.EqualValues(t, "firstuser@example.com", superusers[0].GetString("email"), "Should have created one superuser")
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "POST /create-user - should not be available when users exist",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/create-user",
|
||||
Body: jsonReader(map[string]any{
|
||||
"email": "firstuser@example.com",
|
||||
"password": "password123",
|
||||
}),
|
||||
ExpectedStatus: 404,
|
||||
ExpectedContent: []string{"wasn't found"},
|
||||
TestAppFactory: testAppFactoryExisting,
|
||||
},
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
scenario.Test(t)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CreateUserEndpoint not available when USER_EMAIL, USER_PASSWORD are set", func(t *testing.T) {
|
||||
t.Setenv("BESZEL_HUB_USER_EMAIL", "me@example.com")
|
||||
t.Setenv("BESZEL_HUB_USER_PASSWORD", "password123")
|
||||
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
hub.StartHub()
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenario := beszelTests.ApiScenario{
|
||||
Name: "POST /create-user - should not be available when USER_EMAIL, USER_PASSWORD are set",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/create-user",
|
||||
ExpectedStatus: 404,
|
||||
ExpectedContent: []string{"wasn't found"},
|
||||
TestAppFactory: testAppFactory,
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
users, err := hub.FindAllRecords("users")
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, len(users), "Should start with one user")
|
||||
require.EqualValues(t, "me@example.com", users[0].GetString("email"), "Should have created one user")
|
||||
superusers, err := hub.FindAllRecords(core.CollectionNameSuperusers)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, len(superusers), "Should start with one superuser")
|
||||
require.EqualValues(t, "me@example.com", superusers[0].GetString("email"), "Should have created one superuser")
|
||||
},
|
||||
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
|
||||
users, err := hub.FindAllRecords("users")
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, len(users), "Should still have one user")
|
||||
require.EqualValues(t, "me@example.com", users[0].GetString("email"), "Should have created one user")
|
||||
superusers, err := hub.FindAllRecords(core.CollectionNameSuperusers)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, len(superusers), "Should still have one superuser")
|
||||
require.EqualValues(t, "me@example.com", superusers[0].GetString("email"), "Should have created one superuser")
|
||||
},
|
||||
}
|
||||
|
||||
scenario.Test(t)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateUserEndpointAvailability(t *testing.T) {
|
||||
t.Run("CreateUserEndpoint available when no users exist", func(t *testing.T) {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
// Ensure no users exist
|
||||
userCount, err := hub.CountRecords("users")
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, userCount, "Should start with no users")
|
||||
|
||||
hub.StartHub()
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenario := beszelTests.ApiScenario{
|
||||
Name: "POST /create-user - should be available when no users exist",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/create-user",
|
||||
Body: jsonReader(map[string]any{
|
||||
"email": "firstuser@example.com",
|
||||
"password": "password123",
|
||||
}),
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"User created"},
|
||||
TestAppFactory: testAppFactory,
|
||||
}
|
||||
|
||||
scenario.Test(t)
|
||||
|
||||
// Verify user was created
|
||||
userCount, err = hub.CountRecords("users")
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, userCount, "Should have created one user")
|
||||
})
|
||||
|
||||
t.Run("CreateUserEndpoint not available when users exist", func(t *testing.T) {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
// Create a user first
|
||||
_, err := beszelTests.CreateUser(hub, "existing@example.com", "password")
|
||||
require.NoError(t, err)
|
||||
|
||||
hub.StartHub()
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenario := beszelTests.ApiScenario{
|
||||
Name: "POST /create-user - should not be available when users exist",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/create-user",
|
||||
Body: jsonReader(map[string]any{
|
||||
"email": "another@example.com",
|
||||
"password": "password123",
|
||||
}),
|
||||
ExpectedStatus: 404,
|
||||
ExpectedContent: []string{"wasn't found"},
|
||||
TestAppFactory: testAppFactory,
|
||||
}
|
||||
|
||||
scenario.Test(t)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAutoLoginMiddleware(t *testing.T) {
|
||||
var hubs []*beszelTests.TestHub
|
||||
|
||||
defer func() {
|
||||
for _, hub := range hubs {
|
||||
hub.Cleanup()
|
||||
}
|
||||
}()
|
||||
|
||||
t.Setenv("AUTO_LOGIN", "user@test.com")
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
hubs = append(hubs, hub)
|
||||
hub.StartHub()
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenarios := []beszelTests.ApiScenario{
|
||||
{
|
||||
Name: "GET /getkey - without auto login should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /getkey - with auto login should fail if no matching user",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /getkey - with auto login should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"key\":", "\"v\":"},
|
||||
TestAppFactory: testAppFactory,
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
beszelTests.CreateUser(app, "user@test.com", "password123")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
scenario.Test(t)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrustedHeaderMiddleware(t *testing.T) {
|
||||
var hubs []*beszelTests.TestHub
|
||||
|
||||
defer func() {
|
||||
for _, hub := range hubs {
|
||||
hub.Cleanup()
|
||||
}
|
||||
}()
|
||||
|
||||
t.Setenv("TRUSTED_AUTH_HEADER", "X-Beszel-Trusted")
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
hubs = append(hubs, hub)
|
||||
hub.StartHub()
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenarios := []beszelTests.ApiScenario{
|
||||
{
|
||||
Name: "GET /getkey - without trusted header should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /getkey - with trusted header should fail if no matching user",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
Headers: map[string]string{
|
||||
"X-Beszel-Trusted": "user@test.com",
|
||||
},
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /getkey - with trusted header should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
Headers: map[string]string{
|
||||
"X-Beszel-Trusted": "user@test.com",
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"key\":", "\"v\":"},
|
||||
TestAppFactory: testAppFactory,
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
beszelTests.CreateUser(app, "user@test.com", "password123")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
scenario.Test(t)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateEndpoint(t *testing.T) {
|
||||
t.Setenv("CHECK_UPDATES", "true")
|
||||
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
hub.StartHub()
|
||||
|
||||
// Create test user and get auth token
|
||||
// user, err := beszelTests.CreateUser(hub, "testuser@example.com", "password123")
|
||||
// require.NoError(t, err, "Failed to create test user")
|
||||
// userToken, err := user.NewAuthToken()
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenarios := []beszelTests.ApiScenario{
|
||||
{
|
||||
Name: "update endpoint shouldn't work without auth",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/update",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
// leave this out for now since it actually makes a request to github
|
||||
// {
|
||||
// Name: "GET /update - with valid auth should succeed",
|
||||
// Method: http.MethodGet,
|
||||
// URL: "/api/beszel/update",
|
||||
// Headers: map[string]string{
|
||||
// "Authorization": userToken,
|
||||
// },
|
||||
// ExpectedStatus: 200,
|
||||
// ExpectedContent: []string{`"v":`},
|
||||
// TestAppFactory: testAppFactory,
|
||||
// },
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
scenario.Test(t)
|
||||
}
|
||||
}
|
||||
128
internal/hub/collections.go
Normal file
128
internal/hub/collections.go
Normal file
@@ -0,0 +1,128 @@
|
||||
package hub
|
||||
|
||||
import "github.com/pocketbase/pocketbase/core"
|
||||
|
||||
type collectionRules struct {
|
||||
list *string
|
||||
view *string
|
||||
create *string
|
||||
update *string
|
||||
delete *string
|
||||
}
|
||||
|
||||
// setCollectionAuthSettings applies Beszel's collection auth settings.
|
||||
func setCollectionAuthSettings(app core.App) error {
|
||||
usersCollection, err := app.FindCollectionByNameOrId("users")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
superusersCollection, err := app.FindCollectionByNameOrId(core.CollectionNameSuperusers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// disable email auth if DISABLE_PASSWORD_AUTH env var is set
|
||||
disablePasswordAuth, _ := 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" {
|
||||
cr := "@request.context = 'oauth2'"
|
||||
usersCollection.CreateRule = &cr
|
||||
} else {
|
||||
usersCollection.CreateRule = nil
|
||||
}
|
||||
|
||||
// enable mfaOtp mfa if MFA_OTP env var is set
|
||||
mfaOtp, _ := GetEnv("MFA_OTP")
|
||||
usersCollection.OTP.Length = 6
|
||||
superusersCollection.OTP.Length = 6
|
||||
usersCollection.OTP.Enabled = mfaOtp == "true"
|
||||
usersCollection.MFA.Enabled = mfaOtp == "true"
|
||||
superusersCollection.OTP.Enabled = mfaOtp == "true" || mfaOtp == "superusers"
|
||||
superusersCollection.MFA.Enabled = mfaOtp == "true" || mfaOtp == "superusers"
|
||||
if err := app.Save(superusersCollection); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := app.Save(usersCollection); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
authenticatedRule := "@request.auth.id != \"\""
|
||||
systemsMemberRule := authenticatedRule + " && users.id ?= @request.auth.id"
|
||||
systemMemberRule := authenticatedRule + " && system.users.id ?= @request.auth.id"
|
||||
|
||||
systemsReadRule := systemsMemberRule
|
||||
systemScopedReadRule := systemMemberRule
|
||||
if shareAllSystems == "true" {
|
||||
systemsReadRule = authenticatedRule
|
||||
systemScopedReadRule = authenticatedRule
|
||||
}
|
||||
systemsWriteRule := systemsReadRule + " && @request.auth.role != \"readonly\""
|
||||
systemScopedWriteRule := systemScopedReadRule + " && @request.auth.role != \"readonly\""
|
||||
|
||||
if err := applyCollectionRules(app, []string{"systems"}, collectionRules{
|
||||
list: &systemsReadRule,
|
||||
view: &systemsReadRule,
|
||||
create: &systemsWriteRule,
|
||||
update: &systemsWriteRule,
|
||||
delete: &systemsWriteRule,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := applyCollectionRules(app, []string{"containers", "container_stats", "system_stats", "systemd_services"}, collectionRules{
|
||||
list: &systemScopedReadRule,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := applyCollectionRules(app, []string{"smart_devices"}, collectionRules{
|
||||
list: &systemScopedReadRule,
|
||||
view: &systemScopedReadRule,
|
||||
delete: &systemScopedWriteRule,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := applyCollectionRules(app, []string{"fingerprints"}, collectionRules{
|
||||
list: &systemScopedReadRule,
|
||||
view: &systemScopedReadRule,
|
||||
create: &systemScopedWriteRule,
|
||||
update: &systemScopedWriteRule,
|
||||
delete: &systemScopedWriteRule,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := applyCollectionRules(app, []string{"system_details"}, collectionRules{
|
||||
list: &systemScopedReadRule,
|
||||
view: &systemScopedReadRule,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyCollectionRules(app core.App, collectionNames []string, rules collectionRules) error {
|
||||
for _, collectionName := range collectionNames {
|
||||
collection, err := app.FindCollectionByNameOrId(collectionName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
collection.ListRule = rules.list
|
||||
collection.ViewRule = rules.view
|
||||
collection.CreateRule = rules.create
|
||||
collection.UpdateRule = rules.update
|
||||
collection.DeleteRule = rules.delete
|
||||
if err := app.Save(collection); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
527
internal/hub/collections_test.go
Normal file
527
internal/hub/collections_test.go
Normal file
@@ -0,0 +1,527 @@
|
||||
//go:build testing
|
||||
|
||||
package hub_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
beszelTests "github.com/henrygd/beszel/internal/tests"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
pbTests "github.com/pocketbase/pocketbase/tests"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCollectionRulesDefault(t *testing.T) {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
const isUserMatchesUser = `@request.auth.id != "" && user = @request.auth.id`
|
||||
|
||||
const isUserInUsers = `@request.auth.id != "" && users.id ?= @request.auth.id`
|
||||
const isUserInUsersNotReadonly = `@request.auth.id != "" && users.id ?= @request.auth.id && @request.auth.role != "readonly"`
|
||||
|
||||
const isUserInSystemUsers = `@request.auth.id != "" && system.users.id ?= @request.auth.id`
|
||||
const isUserInSystemUsersNotReadonly = `@request.auth.id != "" && system.users.id ?= @request.auth.id && @request.auth.role != "readonly"`
|
||||
|
||||
// users collection
|
||||
usersCollection, err := hub.FindCollectionByNameOrId("users")
|
||||
assert.NoError(t, err, "Failed to find users collection")
|
||||
assert.True(t, usersCollection.PasswordAuth.Enabled)
|
||||
assert.Equal(t, usersCollection.PasswordAuth.IdentityFields, []string{"email"})
|
||||
assert.Nil(t, usersCollection.CreateRule)
|
||||
assert.False(t, usersCollection.MFA.Enabled)
|
||||
|
||||
// superusers collection
|
||||
superusersCollection, err := hub.FindCollectionByNameOrId(core.CollectionNameSuperusers)
|
||||
assert.NoError(t, err, "Failed to find superusers collection")
|
||||
assert.True(t, superusersCollection.PasswordAuth.Enabled)
|
||||
assert.Equal(t, superusersCollection.PasswordAuth.IdentityFields, []string{"email"})
|
||||
assert.Nil(t, superusersCollection.CreateRule)
|
||||
assert.False(t, superusersCollection.MFA.Enabled)
|
||||
|
||||
// alerts collection
|
||||
alertsCollection, err := hub.FindCollectionByNameOrId("alerts")
|
||||
require.NoError(t, err, "Failed to find alerts collection")
|
||||
assert.Equal(t, isUserMatchesUser, *alertsCollection.ListRule)
|
||||
assert.Nil(t, alertsCollection.ViewRule)
|
||||
assert.Equal(t, isUserMatchesUser, *alertsCollection.CreateRule)
|
||||
assert.Equal(t, isUserMatchesUser, *alertsCollection.UpdateRule)
|
||||
assert.Equal(t, isUserMatchesUser, *alertsCollection.DeleteRule)
|
||||
|
||||
// alerts_history collection
|
||||
alertsHistoryCollection, err := hub.FindCollectionByNameOrId("alerts_history")
|
||||
require.NoError(t, err, "Failed to find alerts_history collection")
|
||||
assert.Equal(t, isUserMatchesUser, *alertsHistoryCollection.ListRule)
|
||||
assert.Nil(t, alertsHistoryCollection.ViewRule)
|
||||
assert.Nil(t, alertsHistoryCollection.CreateRule)
|
||||
assert.Nil(t, alertsHistoryCollection.UpdateRule)
|
||||
assert.Equal(t, isUserMatchesUser, *alertsHistoryCollection.DeleteRule)
|
||||
|
||||
// containers collection
|
||||
containersCollection, err := hub.FindCollectionByNameOrId("containers")
|
||||
require.NoError(t, err, "Failed to find containers collection")
|
||||
assert.Equal(t, isUserInSystemUsers, *containersCollection.ListRule)
|
||||
assert.Nil(t, containersCollection.ViewRule)
|
||||
assert.Nil(t, containersCollection.CreateRule)
|
||||
assert.Nil(t, containersCollection.UpdateRule)
|
||||
assert.Nil(t, containersCollection.DeleteRule)
|
||||
|
||||
// container_stats collection
|
||||
containerStatsCollection, err := hub.FindCollectionByNameOrId("container_stats")
|
||||
require.NoError(t, err, "Failed to find container_stats collection")
|
||||
assert.Equal(t, isUserInSystemUsers, *containerStatsCollection.ListRule)
|
||||
assert.Nil(t, containerStatsCollection.ViewRule)
|
||||
assert.Nil(t, containerStatsCollection.CreateRule)
|
||||
assert.Nil(t, containerStatsCollection.UpdateRule)
|
||||
assert.Nil(t, containerStatsCollection.DeleteRule)
|
||||
|
||||
// fingerprints collection
|
||||
fingerprintsCollection, err := hub.FindCollectionByNameOrId("fingerprints")
|
||||
require.NoError(t, err, "Failed to find fingerprints collection")
|
||||
assert.Equal(t, isUserInSystemUsers, *fingerprintsCollection.ListRule)
|
||||
assert.Equal(t, isUserInSystemUsers, *fingerprintsCollection.ViewRule)
|
||||
assert.Equal(t, isUserInSystemUsersNotReadonly, *fingerprintsCollection.CreateRule)
|
||||
assert.Equal(t, isUserInSystemUsersNotReadonly, *fingerprintsCollection.UpdateRule)
|
||||
assert.Equal(t, isUserInSystemUsersNotReadonly, *fingerprintsCollection.DeleteRule)
|
||||
|
||||
// quiet_hours collection
|
||||
quietHoursCollection, err := hub.FindCollectionByNameOrId("quiet_hours")
|
||||
require.NoError(t, err, "Failed to find quiet_hours collection")
|
||||
assert.Equal(t, isUserMatchesUser, *quietHoursCollection.ListRule)
|
||||
assert.Equal(t, isUserMatchesUser, *quietHoursCollection.ViewRule)
|
||||
assert.Equal(t, isUserMatchesUser, *quietHoursCollection.CreateRule)
|
||||
assert.Equal(t, isUserMatchesUser, *quietHoursCollection.UpdateRule)
|
||||
assert.Equal(t, isUserMatchesUser, *quietHoursCollection.DeleteRule)
|
||||
|
||||
// smart_devices collection
|
||||
smartDevicesCollection, err := hub.FindCollectionByNameOrId("smart_devices")
|
||||
require.NoError(t, err, "Failed to find smart_devices collection")
|
||||
assert.Equal(t, isUserInSystemUsers, *smartDevicesCollection.ListRule)
|
||||
assert.Equal(t, isUserInSystemUsers, *smartDevicesCollection.ViewRule)
|
||||
assert.Nil(t, smartDevicesCollection.CreateRule)
|
||||
assert.Nil(t, smartDevicesCollection.UpdateRule)
|
||||
assert.Equal(t, isUserInSystemUsersNotReadonly, *smartDevicesCollection.DeleteRule)
|
||||
|
||||
// system_details collection
|
||||
systemDetailsCollection, err := hub.FindCollectionByNameOrId("system_details")
|
||||
require.NoError(t, err, "Failed to find system_details collection")
|
||||
assert.Equal(t, isUserInSystemUsers, *systemDetailsCollection.ListRule)
|
||||
assert.Equal(t, isUserInSystemUsers, *systemDetailsCollection.ViewRule)
|
||||
assert.Nil(t, systemDetailsCollection.CreateRule)
|
||||
assert.Nil(t, systemDetailsCollection.UpdateRule)
|
||||
assert.Nil(t, systemDetailsCollection.DeleteRule)
|
||||
|
||||
// system_stats collection
|
||||
systemStatsCollection, err := hub.FindCollectionByNameOrId("system_stats")
|
||||
require.NoError(t, err, "Failed to find system_stats collection")
|
||||
assert.Equal(t, isUserInSystemUsers, *systemStatsCollection.ListRule)
|
||||
assert.Nil(t, systemStatsCollection.ViewRule)
|
||||
assert.Nil(t, systemStatsCollection.CreateRule)
|
||||
assert.Nil(t, systemStatsCollection.UpdateRule)
|
||||
assert.Nil(t, systemStatsCollection.DeleteRule)
|
||||
|
||||
// systemd_services collection
|
||||
systemdServicesCollection, err := hub.FindCollectionByNameOrId("systemd_services")
|
||||
require.NoError(t, err, "Failed to find systemd_services collection")
|
||||
assert.Equal(t, isUserInSystemUsers, *systemdServicesCollection.ListRule)
|
||||
assert.Nil(t, systemdServicesCollection.ViewRule)
|
||||
assert.Nil(t, systemdServicesCollection.CreateRule)
|
||||
assert.Nil(t, systemdServicesCollection.UpdateRule)
|
||||
assert.Nil(t, systemdServicesCollection.DeleteRule)
|
||||
|
||||
// systems collection
|
||||
systemsCollection, err := hub.FindCollectionByNameOrId("systems")
|
||||
require.NoError(t, err, "Failed to find systems collection")
|
||||
assert.Equal(t, isUserInUsers, *systemsCollection.ListRule)
|
||||
assert.Equal(t, isUserInUsers, *systemsCollection.ViewRule)
|
||||
assert.Equal(t, isUserInUsersNotReadonly, *systemsCollection.CreateRule)
|
||||
assert.Equal(t, isUserInUsersNotReadonly, *systemsCollection.UpdateRule)
|
||||
assert.Equal(t, isUserInUsersNotReadonly, *systemsCollection.DeleteRule)
|
||||
|
||||
// universal_tokens collection
|
||||
universalTokensCollection, err := hub.FindCollectionByNameOrId("universal_tokens")
|
||||
require.NoError(t, err, "Failed to find universal_tokens collection")
|
||||
assert.Nil(t, universalTokensCollection.ListRule)
|
||||
assert.Nil(t, universalTokensCollection.ViewRule)
|
||||
assert.Nil(t, universalTokensCollection.CreateRule)
|
||||
assert.Nil(t, universalTokensCollection.UpdateRule)
|
||||
assert.Nil(t, universalTokensCollection.DeleteRule)
|
||||
|
||||
// user_settings collection
|
||||
userSettingsCollection, err := hub.FindCollectionByNameOrId("user_settings")
|
||||
require.NoError(t, err, "Failed to find user_settings collection")
|
||||
assert.Equal(t, isUserMatchesUser, *userSettingsCollection.ListRule)
|
||||
assert.Nil(t, userSettingsCollection.ViewRule)
|
||||
assert.Equal(t, isUserMatchesUser, *userSettingsCollection.CreateRule)
|
||||
assert.Equal(t, isUserMatchesUser, *userSettingsCollection.UpdateRule)
|
||||
assert.Nil(t, userSettingsCollection.DeleteRule)
|
||||
}
|
||||
|
||||
func TestCollectionRulesShareAllSystems(t *testing.T) {
|
||||
t.Setenv("SHARE_ALL_SYSTEMS", "true")
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
const isUser = `@request.auth.id != ""`
|
||||
const isUserNotReadonly = `@request.auth.id != "" && @request.auth.role != "readonly"`
|
||||
|
||||
const isUserMatchesUser = `@request.auth.id != "" && user = @request.auth.id`
|
||||
|
||||
// alerts collection
|
||||
alertsCollection, err := hub.FindCollectionByNameOrId("alerts")
|
||||
require.NoError(t, err, "Failed to find alerts collection")
|
||||
assert.Equal(t, isUserMatchesUser, *alertsCollection.ListRule)
|
||||
assert.Nil(t, alertsCollection.ViewRule)
|
||||
assert.Equal(t, isUserMatchesUser, *alertsCollection.CreateRule)
|
||||
assert.Equal(t, isUserMatchesUser, *alertsCollection.UpdateRule)
|
||||
assert.Equal(t, isUserMatchesUser, *alertsCollection.DeleteRule)
|
||||
|
||||
// alerts_history collection
|
||||
alertsHistoryCollection, err := hub.FindCollectionByNameOrId("alerts_history")
|
||||
require.NoError(t, err, "Failed to find alerts_history collection")
|
||||
assert.Equal(t, isUserMatchesUser, *alertsHistoryCollection.ListRule)
|
||||
assert.Nil(t, alertsHistoryCollection.ViewRule)
|
||||
assert.Nil(t, alertsHistoryCollection.CreateRule)
|
||||
assert.Nil(t, alertsHistoryCollection.UpdateRule)
|
||||
assert.Equal(t, isUserMatchesUser, *alertsHistoryCollection.DeleteRule)
|
||||
|
||||
// containers collection
|
||||
containersCollection, err := hub.FindCollectionByNameOrId("containers")
|
||||
require.NoError(t, err, "Failed to find containers collection")
|
||||
assert.Equal(t, isUser, *containersCollection.ListRule)
|
||||
assert.Nil(t, containersCollection.ViewRule)
|
||||
assert.Nil(t, containersCollection.CreateRule)
|
||||
assert.Nil(t, containersCollection.UpdateRule)
|
||||
assert.Nil(t, containersCollection.DeleteRule)
|
||||
|
||||
// container_stats collection
|
||||
containerStatsCollection, err := hub.FindCollectionByNameOrId("container_stats")
|
||||
require.NoError(t, err, "Failed to find container_stats collection")
|
||||
assert.Equal(t, isUser, *containerStatsCollection.ListRule)
|
||||
assert.Nil(t, containerStatsCollection.ViewRule)
|
||||
assert.Nil(t, containerStatsCollection.CreateRule)
|
||||
assert.Nil(t, containerStatsCollection.UpdateRule)
|
||||
assert.Nil(t, containerStatsCollection.DeleteRule)
|
||||
|
||||
// fingerprints collection
|
||||
fingerprintsCollection, err := hub.FindCollectionByNameOrId("fingerprints")
|
||||
require.NoError(t, err, "Failed to find fingerprints collection")
|
||||
assert.Equal(t, isUser, *fingerprintsCollection.ListRule)
|
||||
assert.Equal(t, isUser, *fingerprintsCollection.ViewRule)
|
||||
assert.Equal(t, isUserNotReadonly, *fingerprintsCollection.CreateRule)
|
||||
assert.Equal(t, isUserNotReadonly, *fingerprintsCollection.UpdateRule)
|
||||
assert.Equal(t, isUserNotReadonly, *fingerprintsCollection.DeleteRule)
|
||||
|
||||
// quiet_hours collection
|
||||
quietHoursCollection, err := hub.FindCollectionByNameOrId("quiet_hours")
|
||||
require.NoError(t, err, "Failed to find quiet_hours collection")
|
||||
assert.Equal(t, isUserMatchesUser, *quietHoursCollection.ListRule)
|
||||
assert.Equal(t, isUserMatchesUser, *quietHoursCollection.ViewRule)
|
||||
assert.Equal(t, isUserMatchesUser, *quietHoursCollection.CreateRule)
|
||||
assert.Equal(t, isUserMatchesUser, *quietHoursCollection.UpdateRule)
|
||||
assert.Equal(t, isUserMatchesUser, *quietHoursCollection.DeleteRule)
|
||||
|
||||
// smart_devices collection
|
||||
smartDevicesCollection, err := hub.FindCollectionByNameOrId("smart_devices")
|
||||
require.NoError(t, err, "Failed to find smart_devices collection")
|
||||
assert.Equal(t, isUser, *smartDevicesCollection.ListRule)
|
||||
assert.Equal(t, isUser, *smartDevicesCollection.ViewRule)
|
||||
assert.Nil(t, smartDevicesCollection.CreateRule)
|
||||
assert.Nil(t, smartDevicesCollection.UpdateRule)
|
||||
assert.Equal(t, isUserNotReadonly, *smartDevicesCollection.DeleteRule)
|
||||
|
||||
// system_details collection
|
||||
systemDetailsCollection, err := hub.FindCollectionByNameOrId("system_details")
|
||||
require.NoError(t, err, "Failed to find system_details collection")
|
||||
assert.Equal(t, isUser, *systemDetailsCollection.ListRule)
|
||||
assert.Equal(t, isUser, *systemDetailsCollection.ViewRule)
|
||||
assert.Nil(t, systemDetailsCollection.CreateRule)
|
||||
assert.Nil(t, systemDetailsCollection.UpdateRule)
|
||||
assert.Nil(t, systemDetailsCollection.DeleteRule)
|
||||
|
||||
// system_stats collection
|
||||
systemStatsCollection, err := hub.FindCollectionByNameOrId("system_stats")
|
||||
require.NoError(t, err, "Failed to find system_stats collection")
|
||||
assert.Equal(t, isUser, *systemStatsCollection.ListRule)
|
||||
assert.Nil(t, systemStatsCollection.ViewRule)
|
||||
assert.Nil(t, systemStatsCollection.CreateRule)
|
||||
assert.Nil(t, systemStatsCollection.UpdateRule)
|
||||
assert.Nil(t, systemStatsCollection.DeleteRule)
|
||||
|
||||
// systemd_services collection
|
||||
systemdServicesCollection, err := hub.FindCollectionByNameOrId("systemd_services")
|
||||
require.NoError(t, err, "Failed to find systemd_services collection")
|
||||
assert.Equal(t, isUser, *systemdServicesCollection.ListRule)
|
||||
assert.Nil(t, systemdServicesCollection.ViewRule)
|
||||
assert.Nil(t, systemdServicesCollection.CreateRule)
|
||||
assert.Nil(t, systemdServicesCollection.UpdateRule)
|
||||
assert.Nil(t, systemdServicesCollection.DeleteRule)
|
||||
|
||||
// systems collection
|
||||
systemsCollection, err := hub.FindCollectionByNameOrId("systems")
|
||||
require.NoError(t, err, "Failed to find systems collection")
|
||||
assert.Equal(t, isUser, *systemsCollection.ListRule)
|
||||
assert.Equal(t, isUser, *systemsCollection.ViewRule)
|
||||
assert.Equal(t, isUserNotReadonly, *systemsCollection.CreateRule)
|
||||
assert.Equal(t, isUserNotReadonly, *systemsCollection.UpdateRule)
|
||||
assert.Equal(t, isUserNotReadonly, *systemsCollection.DeleteRule)
|
||||
|
||||
// universal_tokens collection
|
||||
universalTokensCollection, err := hub.FindCollectionByNameOrId("universal_tokens")
|
||||
require.NoError(t, err, "Failed to find universal_tokens collection")
|
||||
assert.Nil(t, universalTokensCollection.ListRule)
|
||||
assert.Nil(t, universalTokensCollection.ViewRule)
|
||||
assert.Nil(t, universalTokensCollection.CreateRule)
|
||||
assert.Nil(t, universalTokensCollection.UpdateRule)
|
||||
assert.Nil(t, universalTokensCollection.DeleteRule)
|
||||
|
||||
// user_settings collection
|
||||
userSettingsCollection, err := hub.FindCollectionByNameOrId("user_settings")
|
||||
require.NoError(t, err, "Failed to find user_settings collection")
|
||||
assert.Equal(t, isUserMatchesUser, *userSettingsCollection.ListRule)
|
||||
assert.Nil(t, userSettingsCollection.ViewRule)
|
||||
assert.Equal(t, isUserMatchesUser, *userSettingsCollection.CreateRule)
|
||||
assert.Equal(t, isUserMatchesUser, *userSettingsCollection.UpdateRule)
|
||||
assert.Nil(t, userSettingsCollection.DeleteRule)
|
||||
}
|
||||
|
||||
func TestDisablePasswordAuth(t *testing.T) {
|
||||
t.Setenv("DISABLE_PASSWORD_AUTH", "true")
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
usersCollection, err := hub.FindCollectionByNameOrId("users")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, usersCollection.PasswordAuth.Enabled)
|
||||
}
|
||||
|
||||
func TestUserCreation(t *testing.T) {
|
||||
t.Setenv("USER_CREATION", "true")
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
usersCollection, err := hub.FindCollectionByNameOrId("users")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "@request.context = 'oauth2'", *usersCollection.CreateRule)
|
||||
}
|
||||
|
||||
func TestMFAOtp(t *testing.T) {
|
||||
t.Setenv("MFA_OTP", "true")
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
usersCollection, err := hub.FindCollectionByNameOrId("users")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, usersCollection.OTP.Enabled)
|
||||
assert.True(t, usersCollection.MFA.Enabled)
|
||||
|
||||
superusersCollection, err := hub.FindCollectionByNameOrId(core.CollectionNameSuperusers)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, superusersCollection.OTP.Enabled)
|
||||
assert.True(t, superusersCollection.MFA.Enabled)
|
||||
}
|
||||
|
||||
func TestApiCollectionsAuthRules(t *testing.T) {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
hub.StartHub()
|
||||
|
||||
user1, _ := beszelTests.CreateUser(hub, "user1@example.com", "password")
|
||||
user1Token, _ := user1.NewAuthToken()
|
||||
|
||||
user2, _ := beszelTests.CreateUser(hub, "user2@example.com", "password")
|
||||
// user2Token, _ := user2.NewAuthToken()
|
||||
|
||||
userReadonly, _ := beszelTests.CreateUserWithRole(hub, "userreadonly@example.com", "password", "readonly")
|
||||
userReadonlyToken, _ := userReadonly.NewAuthToken()
|
||||
|
||||
userOneSystem, _ := beszelTests.CreateRecord(hub, "systems", map[string]any{
|
||||
"name": "system1",
|
||||
"users": []string{user1.Id},
|
||||
"host": "127.0.0.1",
|
||||
})
|
||||
|
||||
sharedSystem, _ := beszelTests.CreateRecord(hub, "systems", map[string]any{
|
||||
"name": "system2",
|
||||
"users": []string{user1.Id, user2.Id},
|
||||
"host": "127.0.0.2",
|
||||
})
|
||||
|
||||
userTwoSystem, _ := beszelTests.CreateRecord(hub, "systems", map[string]any{
|
||||
"name": "system3",
|
||||
"users": []string{user2.Id},
|
||||
"host": "127.0.0.2",
|
||||
})
|
||||
|
||||
userRecords, _ := hub.CountRecords("users")
|
||||
assert.EqualValues(t, 3, userRecords, "all users should be created")
|
||||
|
||||
systemRecords, _ := hub.CountRecords("systems")
|
||||
assert.EqualValues(t, 3, systemRecords, "all systems should be created")
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenarios := []beszelTests.ApiScenario{
|
||||
{
|
||||
Name: "Unauthorized user cannot list systems",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/collections/systems/records",
|
||||
ExpectedStatus: 200, // https://github.com/pocketbase/pocketbase/discussions/1570
|
||||
TestAppFactory: testAppFactory,
|
||||
ExpectedContent: []string{`"items":[]`, `"totalItems":0`},
|
||||
NotExpectedContent: []string{userOneSystem.Id, sharedSystem.Id, userTwoSystem.Id},
|
||||
},
|
||||
{
|
||||
Name: "Unauthorized user cannot delete a system",
|
||||
Method: http.MethodDelete,
|
||||
URL: fmt.Sprintf("/api/collections/systems/records/%s", userOneSystem.Id),
|
||||
ExpectedStatus: 404,
|
||||
TestAppFactory: testAppFactory,
|
||||
ExpectedContent: []string{"resource wasn't found"},
|
||||
NotExpectedContent: []string{userOneSystem.Id},
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
systemsCount, _ := app.CountRecords("systems")
|
||||
assert.EqualValues(t, 3, systemsCount, "should have 3 systems before deletion")
|
||||
},
|
||||
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
|
||||
systemsCount, _ := app.CountRecords("systems")
|
||||
assert.EqualValues(t, 3, systemsCount, "should still have 3 systems after failed deletion")
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "User 1 can list their own systems",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/collections/systems/records",
|
||||
Headers: map[string]string{
|
||||
"Authorization": user1Token,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{userOneSystem.Id, sharedSystem.Id},
|
||||
NotExpectedContent: []string{userTwoSystem.Id},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "User 1 cannot list user 2's system",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/collections/systems/records",
|
||||
Headers: map[string]string{
|
||||
"Authorization": user1Token,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{userOneSystem.Id, sharedSystem.Id},
|
||||
NotExpectedContent: []string{userTwoSystem.Id},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "User 1 can see user 2's system if SHARE_ALL_SYSTEMS is enabled",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/collections/systems/records",
|
||||
Headers: map[string]string{
|
||||
"Authorization": user1Token,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{userOneSystem.Id, sharedSystem.Id, userTwoSystem.Id},
|
||||
TestAppFactory: testAppFactory,
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
t.Setenv("SHARE_ALL_SYSTEMS", "true")
|
||||
hub.SetCollectionAuthSettings()
|
||||
},
|
||||
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
|
||||
t.Setenv("SHARE_ALL_SYSTEMS", "")
|
||||
hub.SetCollectionAuthSettings()
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "User 1 can delete their own system",
|
||||
Method: http.MethodDelete,
|
||||
URL: fmt.Sprintf("/api/collections/systems/records/%s", userOneSystem.Id),
|
||||
Headers: map[string]string{
|
||||
"Authorization": user1Token,
|
||||
},
|
||||
ExpectedStatus: 204,
|
||||
TestAppFactory: testAppFactory,
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
systemsCount, _ := app.CountRecords("systems")
|
||||
assert.EqualValues(t, 3, systemsCount, "should have 3 systems before deletion")
|
||||
},
|
||||
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
|
||||
systemsCount, _ := app.CountRecords("systems")
|
||||
assert.EqualValues(t, 2, systemsCount, "should have 2 systems after deletion")
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "User 1 cannot delete user 2's system",
|
||||
Method: http.MethodDelete,
|
||||
URL: fmt.Sprintf("/api/collections/systems/records/%s", userTwoSystem.Id),
|
||||
Headers: map[string]string{
|
||||
"Authorization": user1Token,
|
||||
},
|
||||
ExpectedStatus: 404,
|
||||
TestAppFactory: testAppFactory,
|
||||
ExpectedContent: []string{"resource wasn't found"},
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
systemsCount, _ := app.CountRecords("systems")
|
||||
assert.EqualValues(t, 2, systemsCount)
|
||||
},
|
||||
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
|
||||
systemsCount, _ := app.CountRecords("systems")
|
||||
assert.EqualValues(t, 2, systemsCount)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Readonly cannot delete a system even if SHARE_ALL_SYSTEMS is enabled",
|
||||
Method: http.MethodDelete,
|
||||
URL: fmt.Sprintf("/api/collections/systems/records/%s", sharedSystem.Id),
|
||||
Headers: map[string]string{
|
||||
"Authorization": userReadonlyToken,
|
||||
},
|
||||
ExpectedStatus: 404,
|
||||
ExpectedContent: []string{"resource wasn't found"},
|
||||
TestAppFactory: testAppFactory,
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
t.Setenv("SHARE_ALL_SYSTEMS", "true")
|
||||
hub.SetCollectionAuthSettings()
|
||||
systemsCount, _ := app.CountRecords("systems")
|
||||
assert.EqualValues(t, 2, systemsCount)
|
||||
},
|
||||
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
|
||||
t.Setenv("SHARE_ALL_SYSTEMS", "")
|
||||
hub.SetCollectionAuthSettings()
|
||||
systemsCount, _ := app.CountRecords("systems")
|
||||
assert.EqualValues(t, 2, systemsCount)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "User 1 can delete user 2's system if SHARE_ALL_SYSTEMS is enabled",
|
||||
Method: http.MethodDelete,
|
||||
URL: fmt.Sprintf("/api/collections/systems/records/%s", userTwoSystem.Id),
|
||||
Headers: map[string]string{
|
||||
"Authorization": user1Token,
|
||||
},
|
||||
ExpectedStatus: 204,
|
||||
TestAppFactory: testAppFactory,
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
t.Setenv("SHARE_ALL_SYSTEMS", "true")
|
||||
hub.SetCollectionAuthSettings()
|
||||
systemsCount, _ := app.CountRecords("systems")
|
||||
assert.EqualValues(t, 2, systemsCount)
|
||||
},
|
||||
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
|
||||
t.Setenv("SHARE_ALL_SYSTEMS", "")
|
||||
hub.SetCollectionAuthSettings()
|
||||
systemsCount, _ := app.CountRecords("systems")
|
||||
assert.EqualValues(t, 1, systemsCount)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
scenario.Test(t)
|
||||
}
|
||||
}
|
||||
@@ -4,16 +4,14 @@ package hub
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel"
|
||||
"github.com/henrygd/beszel/internal/alerts"
|
||||
"github.com/henrygd/beszel/internal/hub/config"
|
||||
"github.com/henrygd/beszel/internal/hub/heartbeat"
|
||||
@@ -21,14 +19,12 @@ import (
|
||||
"github.com/henrygd/beszel/internal/records"
|
||||
"github.com/henrygd/beszel/internal/users"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase"
|
||||
"github.com/pocketbase/pocketbase/apis"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// Hub is the application. It embeds the PocketBase app and keeps references to subcomponents.
|
||||
type Hub struct {
|
||||
core.App
|
||||
*alerts.AlertManager
|
||||
@@ -46,18 +42,16 @@ var containerIDPattern = regexp.MustCompile(`^[a-fA-F0-9]{12,64}$`)
|
||||
|
||||
// NewHub creates a new Hub instance with default configuration
|
||||
func NewHub(app core.App) *Hub {
|
||||
hub := &Hub{}
|
||||
hub.App = app
|
||||
|
||||
hub := &Hub{App: app}
|
||||
hub.AlertManager = alerts.NewAlertManager(hub)
|
||||
hub.um = users.NewUserManager(hub)
|
||||
hub.rm = records.NewRecordManager(hub)
|
||||
hub.sm = systems.NewSystemManager(hub)
|
||||
hub.appURL, _ = GetEnv("APP_URL")
|
||||
hub.hb = heartbeat.New(app, GetEnv)
|
||||
if hub.hb != nil {
|
||||
hub.hbStop = make(chan struct{})
|
||||
}
|
||||
_ = onAfterBootstrapAndMigrations(app, hub.initialize)
|
||||
return hub
|
||||
}
|
||||
|
||||
@@ -70,12 +64,28 @@ func GetEnv(key string) (value string, exists bool) {
|
||||
return os.LookupEnv(key)
|
||||
}
|
||||
|
||||
func (h *Hub) StartHub() error {
|
||||
h.App.OnServe().BindFunc(func(e *core.ServeEvent) error {
|
||||
// initialize settings / collections
|
||||
if err := h.initialize(e); err != nil {
|
||||
// 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.
|
||||
// So this ensures that the provided function runs at the right time either way, after DB is ready and migrations are done.
|
||||
func onAfterBootstrapAndMigrations(app core.App, fn func(app core.App) error) error {
|
||||
// pb tests.TestApp is already bootstrapped and doesn't serve
|
||||
if app.IsBootstrapped() {
|
||||
return fn(app)
|
||||
}
|
||||
// Must use OnServe because OnBootstrap appears to run before migrations, even if calling e.Next() before anything else
|
||||
app.OnServe().BindFunc(func(e *core.ServeEvent) error {
|
||||
if err := fn(e.App); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.Next()
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartHub sets up event handlers and starts the PocketBase server
|
||||
func (h *Hub) StartHub() error {
|
||||
h.App.OnServe().BindFunc(func(e *core.ServeEvent) error {
|
||||
// sync systems with config
|
||||
if err := config.SyncSystems(e); err != nil {
|
||||
return err
|
||||
@@ -110,132 +120,29 @@ func (h *Hub) StartHub() error {
|
||||
h.App.OnRecordCreate("users").BindFunc(h.um.InitializeUserRole)
|
||||
h.App.OnRecordCreate("user_settings").BindFunc(h.um.InitializeUserSettings)
|
||||
|
||||
if pb, ok := h.App.(*pocketbase.PocketBase); ok {
|
||||
// log.Println("Starting pocketbase")
|
||||
err := pb.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pb, ok := h.App.(*pocketbase.PocketBase)
|
||||
if !ok {
|
||||
return errors.New("not a pocketbase app")
|
||||
}
|
||||
|
||||
return nil
|
||||
return pb.Start()
|
||||
}
|
||||
|
||||
// initialize sets up initial configuration (collections, settings, etc.)
|
||||
func (h *Hub) initialize(e *core.ServeEvent) error {
|
||||
func (h *Hub) initialize(app core.App) error {
|
||||
// set general settings
|
||||
settings := e.App.Settings()
|
||||
// batch requests (for global alerts)
|
||||
settings := app.Settings()
|
||||
// batch requests (for alerts)
|
||||
settings.Batch.Enabled = true
|
||||
// set URL if BASE_URL env is set
|
||||
if h.appURL != "" {
|
||||
settings.Meta.AppURL = h.appURL
|
||||
// set URL if APP_URL env is set
|
||||
if appURL, isSet := GetEnv("APP_URL"); isSet {
|
||||
h.appURL = appURL
|
||||
settings.Meta.AppURL = appURL
|
||||
}
|
||||
if err := e.App.Save(settings); err != nil {
|
||||
if err := app.Save(settings); err != nil {
|
||||
return err
|
||||
}
|
||||
// set auth settings
|
||||
if err := setCollectionAuthSettings(e.App); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setCollectionAuthSettings sets up default authentication settings for the app
|
||||
func setCollectionAuthSettings(app core.App) error {
|
||||
usersCollection, err := app.FindCollectionByNameOrId("users")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
superusersCollection, err := app.FindCollectionByNameOrId(core.CollectionNameSuperusers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// disable email auth if DISABLE_PASSWORD_AUTH env var is set
|
||||
disablePasswordAuth, _ := 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" {
|
||||
cr := "@request.context = 'oauth2'"
|
||||
usersCollection.CreateRule = &cr
|
||||
} else {
|
||||
usersCollection.CreateRule = nil
|
||||
}
|
||||
|
||||
// enable mfaOtp mfa if MFA_OTP env var is set
|
||||
mfaOtp, _ := GetEnv("MFA_OTP")
|
||||
usersCollection.OTP.Length = 6
|
||||
superusersCollection.OTP.Length = 6
|
||||
usersCollection.OTP.Enabled = mfaOtp == "true"
|
||||
usersCollection.MFA.Enabled = mfaOtp == "true"
|
||||
superusersCollection.OTP.Enabled = mfaOtp == "true" || mfaOtp == "superusers"
|
||||
superusersCollection.MFA.Enabled = mfaOtp == "true" || mfaOtp == "superusers"
|
||||
if err := app.Save(superusersCollection); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := app.Save(usersCollection); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
shareAllSystems, _ := GetEnv("SHARE_ALL_SYSTEMS")
|
||||
|
||||
// allow all users to access systems if SHARE_ALL_SYSTEMS is set
|
||||
systemsCollection, err := app.FindCollectionByNameOrId("systems")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var systemsReadRule string
|
||||
if shareAllSystems == "true" {
|
||||
systemsReadRule = "@request.auth.id != \"\""
|
||||
} else {
|
||||
systemsReadRule = "@request.auth.id != \"\" && users.id ?= @request.auth.id"
|
||||
}
|
||||
updateDeleteRule := systemsReadRule + " && @request.auth.role != \"readonly\""
|
||||
systemsCollection.ListRule = &systemsReadRule
|
||||
systemsCollection.ViewRule = &systemsReadRule
|
||||
systemsCollection.UpdateRule = &updateDeleteRule
|
||||
systemsCollection.DeleteRule = &updateDeleteRule
|
||||
if err := app.Save(systemsCollection); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// allow all users to access all containers if SHARE_ALL_SYSTEMS is set
|
||||
containersCollection, err := app.FindCollectionByNameOrId("containers")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
containersListRule := strings.Replace(systemsReadRule, "users.id", "system.users.id", 1)
|
||||
containersCollection.ListRule = &containersListRule
|
||||
if err := app.Save(containersCollection); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// allow all users to access system-related collections if SHARE_ALL_SYSTEMS is set
|
||||
// these collections all have a "system" relation field
|
||||
systemRelatedCollections := []string{"system_details", "smart_devices", "systemd_services"}
|
||||
for _, collectionName := range systemRelatedCollections {
|
||||
collection, err := app.FindCollectionByNameOrId(collectionName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
collection.ListRule = &containersListRule
|
||||
// set viewRule for collections that need it (system_details, smart_devices)
|
||||
if collection.ViewRule != nil {
|
||||
collection.ViewRule = &containersListRule
|
||||
}
|
||||
// set deleteRule for smart_devices (allows user to dismiss disk warnings)
|
||||
if collectionName == "smart_devices" {
|
||||
deleteRule := containersListRule + " && @request.auth.role != \"readonly\""
|
||||
collection.DeleteRule = &deleteRule
|
||||
}
|
||||
if err := app.Save(collection); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return setCollectionAuthSettings(app)
|
||||
}
|
||||
|
||||
// registerCronJobs sets up scheduled tasks
|
||||
@@ -247,296 +154,7 @@ func (h *Hub) registerCronJobs(_ *core.ServeEvent) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// custom middlewares
|
||||
func (h *Hub) registerMiddlewares(se *core.ServeEvent) {
|
||||
// authorizes request with user matching the provided email
|
||||
authorizeRequestWithEmail := func(e *core.RequestEvent, email string) (err error) {
|
||||
if e.Auth != nil || email == "" {
|
||||
return e.Next()
|
||||
}
|
||||
isAuthRefresh := e.Request.URL.Path == "/api/collections/users/auth-refresh" && e.Request.Method == http.MethodPost
|
||||
e.Auth, err = e.App.FindFirstRecordByData("users", "email", email)
|
||||
if err != nil || !isAuthRefresh {
|
||||
return e.Next()
|
||||
}
|
||||
// auth refresh endpoint, make sure token is set in header
|
||||
token, _ := e.Auth.NewAuthToken()
|
||||
e.Request.Header.Set("Authorization", token)
|
||||
return e.Next()
|
||||
}
|
||||
// authenticate with trusted header
|
||||
if autoLogin, _ := 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 != "" {
|
||||
se.Router.BindFunc(func(e *core.RequestEvent) error {
|
||||
return authorizeRequestWithEmail(e, e.Request.Header.Get(trustedHeader))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// custom api routes
|
||||
func (h *Hub) registerApiRoutes(se *core.ServeEvent) error {
|
||||
// auth protected routes
|
||||
apiAuth := se.Router.Group("/api/beszel")
|
||||
apiAuth.Bind(apis.RequireAuth())
|
||||
// auth optional routes
|
||||
apiNoAuth := se.Router.Group("/api/beszel")
|
||||
|
||||
// create first user endpoint only needed if no users exist
|
||||
if totalUsers, _ := se.App.CountRecords("users"); totalUsers == 0 {
|
||||
apiNoAuth.POST("/create-user", h.um.CreateFirstUser)
|
||||
}
|
||||
// check if first time setup on login page
|
||||
apiNoAuth.GET("/first-run", func(e *core.RequestEvent) error {
|
||||
total, err := e.App.CountRecords("users")
|
||||
return e.JSON(http.StatusOK, map[string]bool{"firstRun": err == nil && total == 0})
|
||||
})
|
||||
// get public key and version
|
||||
apiAuth.GET("/getkey", func(e *core.RequestEvent) error {
|
||||
return e.JSON(http.StatusOK, map[string]string{"key": h.pubKey, "v": beszel.Version})
|
||||
})
|
||||
// send test notification
|
||||
apiAuth.POST("/test-notification", h.SendTestNotification)
|
||||
// heartbeat status and test
|
||||
apiAuth.GET("/heartbeat-status", h.getHeartbeatStatus)
|
||||
apiAuth.POST("/test-heartbeat", h.testHeartbeat)
|
||||
// get config.yml content
|
||||
apiAuth.GET("/config-yaml", config.GetYamlConfig)
|
||||
// handle agent websocket connection
|
||||
apiNoAuth.GET("/agent-connect", h.handleAgentConnect)
|
||||
// get or create universal tokens
|
||||
apiAuth.GET("/universal-token", h.getUniversalToken)
|
||||
// update / delete user alerts
|
||||
apiAuth.POST("/user-alerts", alerts.UpsertUserAlerts)
|
||||
apiAuth.DELETE("/user-alerts", alerts.DeleteUserAlerts)
|
||||
// refresh SMART devices for a system
|
||||
apiAuth.POST("/smart/refresh", h.refreshSmartData)
|
||||
// get systemd service details
|
||||
apiAuth.GET("/systemd/info", h.getSystemdInfo)
|
||||
// /containers routes
|
||||
if enabled, _ := GetEnv("CONTAINER_DETAILS"); enabled != "false" {
|
||||
// get container logs
|
||||
apiAuth.GET("/containers/logs", h.getContainerLogs)
|
||||
// get container info
|
||||
apiAuth.GET("/containers/info", h.getContainerInfo)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handler for universal token API endpoint (create, read, delete)
|
||||
func (h *Hub) getUniversalToken(e *core.RequestEvent) error {
|
||||
tokenMap := universalTokenMap.GetMap()
|
||||
userID := e.Auth.Id
|
||||
query := e.Request.URL.Query()
|
||||
token := query.Get("token")
|
||||
enable := query.Get("enable")
|
||||
permanent := query.Get("permanent")
|
||||
|
||||
// helper for deleting any existing permanent token record for this user
|
||||
deletePermanent := func() error {
|
||||
rec, err := h.FindFirstRecordByFilter("universal_tokens", "user = {:user}", dbx.Params{"user": userID})
|
||||
if err != nil {
|
||||
return nil // no record
|
||||
}
|
||||
return h.Delete(rec)
|
||||
}
|
||||
|
||||
// helper for upserting a permanent token record for this user
|
||||
upsertPermanent := func(token string) error {
|
||||
rec, err := h.FindFirstRecordByFilter("universal_tokens", "user = {:user}", dbx.Params{"user": userID})
|
||||
if err == nil {
|
||||
rec.Set("token", token)
|
||||
return h.Save(rec)
|
||||
}
|
||||
|
||||
col, err := h.FindCachedCollectionByNameOrId("universal_tokens")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newRec := core.NewRecord(col)
|
||||
newRec.Set("user", userID)
|
||||
newRec.Set("token", token)
|
||||
return h.Save(newRec)
|
||||
}
|
||||
|
||||
// Disable universal tokens (both ephemeral and permanent)
|
||||
if enable == "0" {
|
||||
tokenMap.RemovebyValue(userID)
|
||||
_ = deletePermanent()
|
||||
return e.JSON(http.StatusOK, map[string]any{"token": token, "active": false, "permanent": false})
|
||||
}
|
||||
|
||||
// Enable universal token (ephemeral or permanent)
|
||||
if enable == "1" {
|
||||
if token == "" {
|
||||
token = uuid.New().String()
|
||||
}
|
||||
|
||||
if permanent == "1" {
|
||||
// make token permanent (persist across restarts)
|
||||
tokenMap.RemovebyValue(userID)
|
||||
if err := upsertPermanent(token); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.JSON(http.StatusOK, map[string]any{"token": token, "active": true, "permanent": true})
|
||||
}
|
||||
|
||||
// default: ephemeral mode (1 hour)
|
||||
_ = deletePermanent()
|
||||
tokenMap.Set(token, userID, time.Hour)
|
||||
return e.JSON(http.StatusOK, map[string]any{"token": token, "active": true, "permanent": false})
|
||||
}
|
||||
|
||||
// Read current state
|
||||
// Prefer permanent token if it exists.
|
||||
if rec, err := h.FindFirstRecordByFilter("universal_tokens", "user = {:user}", dbx.Params{"user": userID}); err == nil {
|
||||
dbToken := rec.GetString("token")
|
||||
// If no token was provided, or the caller is asking about their permanent token, return it.
|
||||
if token == "" || token == dbToken {
|
||||
return e.JSON(http.StatusOK, map[string]any{"token": dbToken, "active": true, "permanent": true})
|
||||
}
|
||||
// Token doesn't match their permanent token (avoid leaking other info)
|
||||
return e.JSON(http.StatusOK, map[string]any{"token": token, "active": false, "permanent": false})
|
||||
}
|
||||
|
||||
// No permanent token; fall back to ephemeral token map.
|
||||
if token == "" {
|
||||
// return existing token if it exists
|
||||
if token, _, ok := tokenMap.GetByValue(userID); ok {
|
||||
return e.JSON(http.StatusOK, map[string]any{"token": token, "active": true, "permanent": false})
|
||||
}
|
||||
// if no token is provided, generate a new one
|
||||
token = uuid.New().String()
|
||||
}
|
||||
|
||||
// Token is considered active only if it belongs to the current user.
|
||||
activeUser, ok := tokenMap.GetOk(token)
|
||||
active := ok && activeUser == userID
|
||||
response := map[string]any{"token": token, "active": active, "permanent": false}
|
||||
return e.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
// getHeartbeatStatus returns current heartbeat configuration and whether it's enabled
|
||||
func (h *Hub) getHeartbeatStatus(e *core.RequestEvent) error {
|
||||
if e.Auth.GetString("role") != "admin" {
|
||||
return e.ForbiddenError("Requires admin role", nil)
|
||||
}
|
||||
if h.hb == nil {
|
||||
return e.JSON(http.StatusOK, map[string]any{
|
||||
"enabled": false,
|
||||
"msg": "Set HEARTBEAT_URL to enable outbound heartbeat monitoring",
|
||||
})
|
||||
}
|
||||
cfg := h.hb.GetConfig()
|
||||
return e.JSON(http.StatusOK, map[string]any{
|
||||
"enabled": true,
|
||||
"url": cfg.URL,
|
||||
"interval": cfg.Interval,
|
||||
"method": cfg.Method,
|
||||
})
|
||||
}
|
||||
|
||||
// testHeartbeat triggers a single heartbeat ping and returns the result
|
||||
func (h *Hub) testHeartbeat(e *core.RequestEvent) error {
|
||||
if e.Auth.GetString("role") != "admin" {
|
||||
return e.ForbiddenError("Requires admin role", nil)
|
||||
}
|
||||
if h.hb == nil {
|
||||
return e.JSON(http.StatusOK, map[string]any{
|
||||
"err": "Heartbeat not configured. Set HEARTBEAT_URL environment variable.",
|
||||
})
|
||||
}
|
||||
if err := h.hb.Send(); err != nil {
|
||||
return e.JSON(http.StatusOK, map[string]any{"err": err.Error()})
|
||||
}
|
||||
return e.JSON(http.StatusOK, map[string]any{"err": false})
|
||||
}
|
||||
|
||||
// containerRequestHandler handles both container logs and info requests
|
||||
func (h *Hub) containerRequestHandler(e *core.RequestEvent, fetchFunc func(*systems.System, string) (string, error), responseKey string) error {
|
||||
systemID := e.Request.URL.Query().Get("system")
|
||||
containerID := e.Request.URL.Query().Get("container")
|
||||
|
||||
if systemID == "" || containerID == "" {
|
||||
return e.JSON(http.StatusBadRequest, map[string]string{"error": "system and container parameters are required"})
|
||||
}
|
||||
if !containerIDPattern.MatchString(containerID) {
|
||||
return e.JSON(http.StatusBadRequest, map[string]string{"error": "invalid container parameter"})
|
||||
}
|
||||
|
||||
system, err := h.sm.GetSystem(systemID)
|
||||
if err != nil {
|
||||
return e.JSON(http.StatusNotFound, map[string]string{"error": "system not found"})
|
||||
}
|
||||
|
||||
data, err := fetchFunc(system, containerID)
|
||||
if err != nil {
|
||||
return e.JSON(http.StatusNotFound, map[string]string{"error": err.Error()})
|
||||
}
|
||||
|
||||
return e.JSON(http.StatusOK, map[string]string{responseKey: data})
|
||||
}
|
||||
|
||||
// getContainerLogs handles GET /api/beszel/containers/logs requests
|
||||
func (h *Hub) getContainerLogs(e *core.RequestEvent) error {
|
||||
return h.containerRequestHandler(e, func(system *systems.System, containerID string) (string, error) {
|
||||
return system.FetchContainerLogsFromAgent(containerID)
|
||||
}, "logs")
|
||||
}
|
||||
|
||||
func (h *Hub) getContainerInfo(e *core.RequestEvent) error {
|
||||
return h.containerRequestHandler(e, func(system *systems.System, containerID string) (string, error) {
|
||||
return system.FetchContainerInfoFromAgent(containerID)
|
||||
}, "info")
|
||||
}
|
||||
|
||||
// getSystemdInfo handles GET /api/beszel/systemd/info requests
|
||||
func (h *Hub) getSystemdInfo(e *core.RequestEvent) error {
|
||||
query := e.Request.URL.Query()
|
||||
systemID := query.Get("system")
|
||||
serviceName := query.Get("service")
|
||||
|
||||
if systemID == "" || serviceName == "" {
|
||||
return e.JSON(http.StatusBadRequest, map[string]string{"error": "system and service parameters are required"})
|
||||
}
|
||||
system, err := h.sm.GetSystem(systemID)
|
||||
if err != nil {
|
||||
return e.JSON(http.StatusNotFound, map[string]string{"error": "system not found"})
|
||||
}
|
||||
details, err := system.FetchSystemdInfoFromAgent(serviceName)
|
||||
if err != nil {
|
||||
return e.JSON(http.StatusNotFound, map[string]string{"error": err.Error()})
|
||||
}
|
||||
e.Response.Header().Set("Cache-Control", "public, max-age=60")
|
||||
return e.JSON(http.StatusOK, map[string]any{"details": details})
|
||||
}
|
||||
|
||||
// refreshSmartData handles POST /api/beszel/smart/refresh requests
|
||||
// Fetches fresh SMART data from the agent and updates the collection
|
||||
func (h *Hub) refreshSmartData(e *core.RequestEvent) error {
|
||||
systemID := e.Request.URL.Query().Get("system")
|
||||
if systemID == "" {
|
||||
return e.JSON(http.StatusBadRequest, map[string]string{"error": "system parameter is required"})
|
||||
}
|
||||
|
||||
system, err := h.sm.GetSystem(systemID)
|
||||
if err != nil {
|
||||
return e.JSON(http.StatusNotFound, map[string]string{"error": "system not found"})
|
||||
}
|
||||
|
||||
// Fetch and save SMART devices
|
||||
if err := system.FetchAndSaveSmartDevices(); err != nil {
|
||||
return e.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
}
|
||||
|
||||
return e.JSON(http.StatusOK, map[string]string{"status": "ok"})
|
||||
}
|
||||
|
||||
// generates key pair if it doesn't exist and returns signer
|
||||
// GetSSHKey generates key pair if it doesn't exist and returns signer
|
||||
func (h *Hub) GetSSHKey(dataDir string) (ssh.Signer, error) {
|
||||
if h.signer != nil {
|
||||
return h.signer, nil
|
||||
|
||||
@@ -3,36 +3,20 @@
|
||||
package hub_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/henrygd/beszel/internal/migrations"
|
||||
beszelTests "github.com/henrygd/beszel/internal/tests"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
pbTests "github.com/pocketbase/pocketbase/tests"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// 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 TestMakeLink(t *testing.T) {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
|
||||
@@ -265,699 +249,20 @@ func TestGetSSHKey(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestApiRoutesAuthentication(t *testing.T) {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
hub.StartHub()
|
||||
|
||||
// Create test user and get auth token
|
||||
user, err := beszelTests.CreateUser(hub, "testuser@example.com", "password123")
|
||||
require.NoError(t, err, "Failed to create test user")
|
||||
|
||||
adminUser, err := beszelTests.CreateRecord(hub, "users", map[string]any{
|
||||
"email": "admin@example.com",
|
||||
"password": "password123",
|
||||
"role": "admin",
|
||||
})
|
||||
require.NoError(t, err, "Failed to create admin user")
|
||||
adminUserToken, err := adminUser.NewAuthToken()
|
||||
|
||||
// superUser, err := beszelTests.CreateRecord(hub, core.CollectionNameSuperusers, map[string]any{
|
||||
// "email": "superuser@example.com",
|
||||
// "password": "password123",
|
||||
// })
|
||||
// require.NoError(t, err, "Failed to create superuser")
|
||||
|
||||
userToken, err := user.NewAuthToken()
|
||||
require.NoError(t, err, "Failed to create auth token")
|
||||
|
||||
// Create test system for user-alerts endpoints
|
||||
system, err := beszelTests.CreateRecord(hub, "systems", map[string]any{
|
||||
"name": "test-system",
|
||||
"users": []string{user.Id},
|
||||
"host": "127.0.0.1",
|
||||
})
|
||||
require.NoError(t, err, "Failed to create test system")
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
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,
|
||||
URL: "/api/beszel/config-yaml",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /config-yaml - with user auth should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/config-yaml",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 403,
|
||||
ExpectedContent: []string{"Requires admin"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /config-yaml - with admin auth should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/config-yaml",
|
||||
Headers: map[string]string{
|
||||
"Authorization": adminUserToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"test-system"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /heartbeat-status - no auth should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/heartbeat-status",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /heartbeat-status - with user auth should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/heartbeat-status",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 403,
|
||||
ExpectedContent: []string{"Requires admin role"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /heartbeat-status - with admin auth should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/heartbeat-status",
|
||||
Headers: map[string]string{
|
||||
"Authorization": adminUserToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{`"enabled":false`},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "POST /test-heartbeat - with user auth should fail",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/test-heartbeat",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 403,
|
||||
ExpectedContent: []string{"Requires admin role"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "POST /test-heartbeat - with admin auth should report disabled state",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/test-heartbeat",
|
||||
Headers: map[string]string{
|
||||
"Authorization": adminUserToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"Heartbeat not configured"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /universal-token - no auth should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/universal-token",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /universal-token - with auth should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/universal-token",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"active", "token", "permanent"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /universal-token - enable permanent should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/universal-token?enable=1&permanent=1&token=permanent-token-123",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"permanent\":true", "permanent-token-123"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "POST /user-alerts - no auth should fail",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/user-alerts",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
Body: jsonReader(map[string]any{
|
||||
"name": "CPU",
|
||||
"value": 80,
|
||||
"min": 10,
|
||||
"systems": []string{system.Id},
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "POST /user-alerts - with auth should succeed",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/user-alerts",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"success\":true"},
|
||||
TestAppFactory: testAppFactory,
|
||||
Body: jsonReader(map[string]any{
|
||||
"name": "CPU",
|
||||
"value": 80,
|
||||
"min": 10,
|
||||
"systems": []string{system.Id},
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "DELETE /user-alerts - no auth should fail",
|
||||
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{system.Id},
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "DELETE /user-alerts - with auth should succeed",
|
||||
Method: http.MethodDelete,
|
||||
URL: "/api/beszel/user-alerts",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"success\":true"},
|
||||
TestAppFactory: testAppFactory,
|
||||
Body: jsonReader(map[string]any{
|
||||
"name": "CPU",
|
||||
"systems": []string{system.Id},
|
||||
}),
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
// Create an alert to delete
|
||||
beszelTests.CreateRecord(app, "alerts", map[string]any{
|
||||
"name": "CPU",
|
||||
"system": system.Id,
|
||||
"user": user.Id,
|
||||
"value": 80,
|
||||
"min": 10,
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/logs - no auth should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/logs?system=test-system&container=test-container",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/logs - with auth but missing system param should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/logs?container=test-container",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{"system and container parameters are required"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/logs - with auth but missing container param should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/logs?system=test-system",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{"system and container parameters are required"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/logs - with auth but invalid system should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/logs?system=invalid-system&container=0123456789ab",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 404,
|
||||
ExpectedContent: []string{"system not found"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/logs - traversal container should fail validation",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/logs?system=" + system.Id + "&container=..%2F..%2Fversion",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{"invalid container parameter"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/info - traversal container should fail validation",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/info?system=" + system.Id + "&container=../../version?x=",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{"invalid container parameter"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /containers/info - non-hex container should fail validation",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/containers/info?system=" + system.Id + "&container=container_name",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{"invalid container parameter"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
|
||||
// Auth Optional Routes - Should work without authentication
|
||||
{
|
||||
Name: "GET /getkey - no auth should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /getkey - with auth should also succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"key\":", "\"v\":"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /first-run - no auth should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/first-run",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"firstRun\":false"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /first-run - with auth should also succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/first-run",
|
||||
Headers: map[string]string{
|
||||
"Authorization": userToken,
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"firstRun\":false"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /agent-connect - no auth should succeed (websocket upgrade fails but route is accessible)",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/agent-connect",
|
||||
ExpectedStatus: 400,
|
||||
ExpectedContent: []string{},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "POST /test-notification - invalid auth token should fail",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/test-notification",
|
||||
Body: jsonReader(map[string]any{
|
||||
"url": "generic://127.0.0.1",
|
||||
}),
|
||||
Headers: map[string]string{
|
||||
"Authorization": "invalid-token",
|
||||
},
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "POST /user-alerts - invalid auth token should fail",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/user-alerts",
|
||||
Headers: map[string]string{
|
||||
"Authorization": "invalid-token",
|
||||
},
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
Body: jsonReader(map[string]any{
|
||||
"name": "CPU",
|
||||
"value": 80,
|
||||
"min": 10,
|
||||
"systems": []string{system.Id},
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
scenario.Test(t)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFirstUserCreation(t *testing.T) {
|
||||
t.Run("CreateUserEndpoint available when no users exist", func(t *testing.T) {
|
||||
func TestAppUrl(t *testing.T) {
|
||||
t.Run("no APP_URL does't change app url", func(t *testing.T) {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
hub.StartHub()
|
||||
|
||||
testAppFactoryExisting := func(t testing.TB) *pbTests.TestApp {
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenarios := []beszelTests.ApiScenario{
|
||||
{
|
||||
Name: "POST /create-user - should be available when no users exist",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/create-user",
|
||||
Body: jsonReader(map[string]any{
|
||||
"email": "firstuser@example.com",
|
||||
"password": "password123",
|
||||
}),
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"User created"},
|
||||
TestAppFactory: testAppFactoryExisting,
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
userCount, err := hub.CountRecords("users")
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, userCount, "Should start with no users")
|
||||
superusers, err := hub.FindAllRecords(core.CollectionNameSuperusers)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, len(superusers), "Should start with one temporary superuser")
|
||||
require.EqualValues(t, migrations.TempAdminEmail, superusers[0].GetString("email"), "Should have created one temporary superuser")
|
||||
},
|
||||
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
|
||||
userCount, err := hub.CountRecords("users")
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, userCount, "Should have created one user")
|
||||
superusers, err := hub.FindAllRecords(core.CollectionNameSuperusers)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, len(superusers), "Should have created one superuser")
|
||||
require.EqualValues(t, "firstuser@example.com", superusers[0].GetString("email"), "Should have created one superuser")
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "POST /create-user - should not be available when users exist",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/create-user",
|
||||
Body: jsonReader(map[string]any{
|
||||
"email": "firstuser@example.com",
|
||||
"password": "password123",
|
||||
}),
|
||||
ExpectedStatus: 404,
|
||||
ExpectedContent: []string{"wasn't found"},
|
||||
TestAppFactory: testAppFactoryExisting,
|
||||
},
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
scenario.Test(t)
|
||||
}
|
||||
settings := hub.Settings()
|
||||
assert.Equal(t, "http://localhost:8090", settings.Meta.AppURL)
|
||||
})
|
||||
|
||||
t.Run("CreateUserEndpoint not available when USER_EMAIL, USER_PASSWORD are set", func(t *testing.T) {
|
||||
os.Setenv("BESZEL_HUB_USER_EMAIL", "me@example.com")
|
||||
os.Setenv("BESZEL_HUB_USER_PASSWORD", "password123")
|
||||
defer os.Unsetenv("BESZEL_HUB_USER_EMAIL")
|
||||
defer os.Unsetenv("BESZEL_HUB_USER_PASSWORD")
|
||||
|
||||
t.Run("APP_URL changes app url", func(t *testing.T) {
|
||||
t.Setenv("APP_URL", "http://example.com/app")
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
hub.StartHub()
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenario := beszelTests.ApiScenario{
|
||||
Name: "POST /create-user - should not be available when USER_EMAIL, USER_PASSWORD are set",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/create-user",
|
||||
ExpectedStatus: 404,
|
||||
ExpectedContent: []string{"wasn't found"},
|
||||
TestAppFactory: testAppFactory,
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
users, err := hub.FindAllRecords("users")
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, len(users), "Should start with one user")
|
||||
require.EqualValues(t, "me@example.com", users[0].GetString("email"), "Should have created one user")
|
||||
superusers, err := hub.FindAllRecords(core.CollectionNameSuperusers)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, len(superusers), "Should start with one superuser")
|
||||
require.EqualValues(t, "me@example.com", superusers[0].GetString("email"), "Should have created one superuser")
|
||||
},
|
||||
AfterTestFunc: func(t testing.TB, app *pbTests.TestApp, res *http.Response) {
|
||||
users, err := hub.FindAllRecords("users")
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, len(users), "Should still have one user")
|
||||
require.EqualValues(t, "me@example.com", users[0].GetString("email"), "Should have created one user")
|
||||
superusers, err := hub.FindAllRecords(core.CollectionNameSuperusers)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, len(superusers), "Should still have one superuser")
|
||||
require.EqualValues(t, "me@example.com", superusers[0].GetString("email"), "Should have created one superuser")
|
||||
},
|
||||
}
|
||||
|
||||
scenario.Test(t)
|
||||
settings := hub.Settings()
|
||||
assert.Equal(t, "http://example.com/app", settings.Meta.AppURL)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateUserEndpointAvailability(t *testing.T) {
|
||||
t.Run("CreateUserEndpoint available when no users exist", func(t *testing.T) {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
// Ensure no users exist
|
||||
userCount, err := hub.CountRecords("users")
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, userCount, "Should start with no users")
|
||||
|
||||
hub.StartHub()
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenario := beszelTests.ApiScenario{
|
||||
Name: "POST /create-user - should be available when no users exist",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/create-user",
|
||||
Body: jsonReader(map[string]any{
|
||||
"email": "firstuser@example.com",
|
||||
"password": "password123",
|
||||
}),
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"User created"},
|
||||
TestAppFactory: testAppFactory,
|
||||
}
|
||||
|
||||
scenario.Test(t)
|
||||
|
||||
// Verify user was created
|
||||
userCount, err = hub.CountRecords("users")
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, userCount, "Should have created one user")
|
||||
})
|
||||
|
||||
t.Run("CreateUserEndpoint not available when users exist", func(t *testing.T) {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
defer hub.Cleanup()
|
||||
|
||||
// Create a user first
|
||||
_, err := beszelTests.CreateUser(hub, "existing@example.com", "password")
|
||||
require.NoError(t, err)
|
||||
|
||||
hub.StartHub()
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenario := beszelTests.ApiScenario{
|
||||
Name: "POST /create-user - should not be available when users exist",
|
||||
Method: http.MethodPost,
|
||||
URL: "/api/beszel/create-user",
|
||||
Body: jsonReader(map[string]any{
|
||||
"email": "another@example.com",
|
||||
"password": "password123",
|
||||
}),
|
||||
ExpectedStatus: 404,
|
||||
ExpectedContent: []string{"wasn't found"},
|
||||
TestAppFactory: testAppFactory,
|
||||
}
|
||||
|
||||
scenario.Test(t)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAutoLoginMiddleware(t *testing.T) {
|
||||
var hubs []*beszelTests.TestHub
|
||||
|
||||
defer func() {
|
||||
defer os.Unsetenv("AUTO_LOGIN")
|
||||
for _, hub := range hubs {
|
||||
hub.Cleanup()
|
||||
}
|
||||
}()
|
||||
|
||||
os.Setenv("AUTO_LOGIN", "user@test.com")
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
hubs = append(hubs, hub)
|
||||
hub.StartHub()
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenarios := []beszelTests.ApiScenario{
|
||||
{
|
||||
Name: "GET /getkey - without auto login should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /getkey - with auto login should fail if no matching user",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /getkey - with auto login should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"key\":", "\"v\":"},
|
||||
TestAppFactory: testAppFactory,
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
beszelTests.CreateUser(app, "user@test.com", "password123")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
scenario.Test(t)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrustedHeaderMiddleware(t *testing.T) {
|
||||
var hubs []*beszelTests.TestHub
|
||||
|
||||
defer func() {
|
||||
defer os.Unsetenv("TRUSTED_AUTH_HEADER")
|
||||
for _, hub := range hubs {
|
||||
hub.Cleanup()
|
||||
}
|
||||
}()
|
||||
|
||||
os.Setenv("TRUSTED_AUTH_HEADER", "X-Beszel-Trusted")
|
||||
|
||||
testAppFactory := func(t testing.TB) *pbTests.TestApp {
|
||||
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
||||
hubs = append(hubs, hub)
|
||||
hub.StartHub()
|
||||
return hub.TestApp
|
||||
}
|
||||
|
||||
scenarios := []beszelTests.ApiScenario{
|
||||
{
|
||||
Name: "GET /getkey - without trusted header should fail",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /getkey - with trusted header should fail if no matching user",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
Headers: map[string]string{
|
||||
"X-Beszel-Trusted": "user@test.com",
|
||||
},
|
||||
ExpectedStatus: 401,
|
||||
ExpectedContent: []string{"requires valid"},
|
||||
TestAppFactory: testAppFactory,
|
||||
},
|
||||
{
|
||||
Name: "GET /getkey - with trusted header should succeed",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/beszel/getkey",
|
||||
Headers: map[string]string{
|
||||
"X-Beszel-Trusted": "user@test.com",
|
||||
},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContent: []string{"\"key\":", "\"v\":"},
|
||||
TestAppFactory: testAppFactory,
|
||||
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
|
||||
beszelTests.CreateUser(app, "user@test.com", "password123")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
scenario.Test(t)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
package hub
|
||||
|
||||
import "github.com/henrygd/beszel/internal/hub/systems"
|
||||
import (
|
||||
"github.com/henrygd/beszel/internal/hub/systems"
|
||||
)
|
||||
|
||||
// TESTING ONLY: GetSystemManager returns the system manager
|
||||
func (h *Hub) GetSystemManager() *systems.SystemManager {
|
||||
@@ -18,3 +20,7 @@ func (h *Hub) GetPubkey() string {
|
||||
func (h *Hub) SetPubkey(pubkey string) {
|
||||
h.pubKey = pubkey
|
||||
}
|
||||
|
||||
func (h *Hub) SetCollectionAuthSettings() error {
|
||||
return setCollectionAuthSettings(h)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ type subscriptionInfo struct {
|
||||
var (
|
||||
activeSubscriptions = make(map[string]*subscriptionInfo)
|
||||
workerRunning bool
|
||||
realtimeTicker *time.Ticker
|
||||
tickerStopChan chan struct{}
|
||||
realtimeMutex sync.Mutex
|
||||
)
|
||||
@@ -70,7 +69,7 @@ func (sm *SystemManager) onRealtimeSubscribeRequest(e *core.RealtimeSubscribeReq
|
||||
}
|
||||
|
||||
// onRealtimeSubscriptionAdded initializes or starts the realtime worker when the first subscription is added.
|
||||
// It ensures only one worker runs at a time and creates the ticker for periodic data fetching.
|
||||
// It ensures only one worker runs at a time.
|
||||
func (sm *SystemManager) onRealtimeSubscriptionAdded() {
|
||||
realtimeMutex.Lock()
|
||||
defer realtimeMutex.Unlock()
|
||||
@@ -82,11 +81,6 @@ func (sm *SystemManager) onRealtimeSubscriptionAdded() {
|
||||
tickerStopChan = make(chan struct{})
|
||||
go sm.startRealtimeWorker()
|
||||
}
|
||||
|
||||
// If no ticker exists, create one
|
||||
if realtimeTicker == nil {
|
||||
realtimeTicker = time.NewTicker(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// checkSubscriptions stops the realtime worker when there are no active subscriptions.
|
||||
@@ -107,11 +101,6 @@ func (sm *SystemManager) checkSubscriptions() {
|
||||
}
|
||||
}
|
||||
|
||||
if realtimeTicker != nil {
|
||||
realtimeTicker.Stop()
|
||||
realtimeTicker = nil
|
||||
}
|
||||
|
||||
// Mark worker as stopped (will be reset when next subscription comes in)
|
||||
workerRunning = false
|
||||
}
|
||||
@@ -135,17 +124,16 @@ func (sm *SystemManager) removeRealtimeSubscription(subscription string, options
|
||||
// It continuously fetches system data and broadcasts it to subscribed clients via WebSocket.
|
||||
func (sm *SystemManager) startRealtimeWorker() {
|
||||
sm.fetchRealtimeDataAndNotify()
|
||||
tick := time.Tick(1 * time.Second)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-tickerStopChan:
|
||||
return
|
||||
case <-realtimeTicker.C:
|
||||
// Check if ticker is still valid (might have been stopped)
|
||||
if realtimeTicker == nil || len(activeSubscriptions) == 0 {
|
||||
case <-tick:
|
||||
if len(activeSubscriptions) == 0 {
|
||||
return
|
||||
}
|
||||
// slog.Debug("activeSubscriptions", "count", len(activeSubscriptions))
|
||||
sm.fetchRealtimeDataAndNotify()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,9 @@ func (ws *WsConn) Close(msg []byte) {
|
||||
|
||||
// Ping sends a ping frame to keep the connection alive.
|
||||
func (ws *WsConn) Ping() error {
|
||||
if ws.conn == nil {
|
||||
return gws.ErrConnClosed
|
||||
}
|
||||
ws.conn.SetDeadline(time.Now().Add(deadline))
|
||||
return ws.conn.WritePing(nil)
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ func init() {
|
||||
jsonData := `[
|
||||
{
|
||||
"id": "elngm8x1l60zi2v",
|
||||
"listRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"viewRule": "",
|
||||
"createRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"updateRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"deleteRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"listRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"viewRule": null,
|
||||
"createRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"updateRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"deleteRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"name": "alerts",
|
||||
"type": "base",
|
||||
"fields": [
|
||||
@@ -143,11 +143,11 @@ func init() {
|
||||
},
|
||||
{
|
||||
"id": "pbc_1697146157",
|
||||
"listRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"viewRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"listRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"viewRule": null,
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
"deleteRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"deleteRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"name": "alerts_history",
|
||||
"type": "base",
|
||||
"fields": [
|
||||
@@ -261,7 +261,7 @@ func init() {
|
||||
},
|
||||
{
|
||||
"id": "juohu4jipgc13v7",
|
||||
"listRule": "@request.auth.id != \"\"",
|
||||
"listRule": null,
|
||||
"viewRule": null,
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
@@ -351,10 +351,10 @@ func init() {
|
||||
},
|
||||
{
|
||||
"id": "pbc_3663931638",
|
||||
"listRule": "@request.auth.id != \"\" && system.users.id ?= @request.auth.id",
|
||||
"viewRule": "@request.auth.id != \"\" && system.users.id ?= @request.auth.id",
|
||||
"createRule": "@request.auth.id != \"\" && system.users.id ?= @request.auth.id && @request.auth.role != \"readonly\"",
|
||||
"updateRule": "@request.auth.id != \"\" && system.users.id ?= @request.auth.id && @request.auth.role != \"readonly\"",
|
||||
"listRule": null,
|
||||
"viewRule": null,
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"name": "fingerprints",
|
||||
"type": "base",
|
||||
@@ -433,7 +433,7 @@ func init() {
|
||||
},
|
||||
{
|
||||
"id": "ej9oowivz8b2mht",
|
||||
"listRule": "@request.auth.id != \"\"",
|
||||
"listRule": null,
|
||||
"viewRule": null,
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
@@ -523,10 +523,10 @@ func init() {
|
||||
},
|
||||
{
|
||||
"id": "4afacsdnlu8q8r2",
|
||||
"listRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"listRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"viewRule": null,
|
||||
"createRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"updateRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"createRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"updateRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"deleteRule": null,
|
||||
"name": "user_settings",
|
||||
"type": "base",
|
||||
@@ -596,11 +596,11 @@ func init() {
|
||||
},
|
||||
{
|
||||
"id": "2hz5ncl8tizk5nx",
|
||||
"listRule": "@request.auth.id != \"\" && users.id ?= @request.auth.id",
|
||||
"viewRule": "@request.auth.id != \"\" && users.id ?= @request.auth.id",
|
||||
"createRule": "@request.auth.id != \"\" && users.id ?= @request.auth.id && @request.auth.role != \"readonly\"",
|
||||
"updateRule": "@request.auth.id != \"\" && users.id ?= @request.auth.id && @request.auth.role != \"readonly\"",
|
||||
"deleteRule": "@request.auth.id != \"\" && users.id ?= @request.auth.id && @request.auth.role != \"readonly\"",
|
||||
"listRule": null,
|
||||
"viewRule": null,
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"name": "systems",
|
||||
"type": "base",
|
||||
"fields": [
|
||||
@@ -866,7 +866,7 @@ func init() {
|
||||
},
|
||||
{
|
||||
"id": "pbc_1864144027",
|
||||
"listRule": "@request.auth.id != \"\" && system.users.id ?= @request.auth.id",
|
||||
"listRule": null,
|
||||
"viewRule": null,
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
@@ -1159,7 +1159,7 @@ func init() {
|
||||
"CREATE INDEX ` + "`" + `idx_4Z7LuLNdQb` + "`" + ` ON ` + "`" + `systemd_services` + "`" + ` (` + "`" + `system` + "`" + `)",
|
||||
"CREATE INDEX ` + "`" + `idx_pBp1fF837e` + "`" + ` ON ` + "`" + `systemd_services` + "`" + ` (` + "`" + `updated` + "`" + `)"
|
||||
],
|
||||
"listRule": "@request.auth.id != \"\" && system.users.id ?= @request.auth.id",
|
||||
"listRule": null,
|
||||
"name": "systemd_services",
|
||||
"system": false,
|
||||
"type": "base",
|
||||
@@ -1167,8 +1167,8 @@ func init() {
|
||||
"viewRule": null
|
||||
},
|
||||
{
|
||||
"createRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"deleteRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"createRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"deleteRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"fields": [
|
||||
{
|
||||
"autogeneratePattern": "[a-z0-9]{10}",
|
||||
@@ -1252,16 +1252,16 @@ func init() {
|
||||
"CREATE INDEX ` + "`" + `idx_q0iKnRP9v8` + "`" + ` ON ` + "`" + `quiet_hours` + "`" + ` (\n ` + "`" + `user` + "`" + `,\n ` + "`" + `system` + "`" + `\n)",
|
||||
"CREATE INDEX ` + "`" + `idx_6T7ljT7FJd` + "`" + ` ON ` + "`" + `quiet_hours` + "`" + ` (\n ` + "`" + `type` + "`" + `,\n ` + "`" + `end` + "`" + `\n)"
|
||||
],
|
||||
"listRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"listRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"name": "quiet_hours",
|
||||
"system": false,
|
||||
"type": "base",
|
||||
"updateRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
|
||||
"viewRule": "@request.auth.id != \"\" && user.id = @request.auth.id"
|
||||
"updateRule": "@request.auth.id != \"\" && user = @request.auth.id",
|
||||
"viewRule": "@request.auth.id != \"\" && user = @request.auth.id"
|
||||
},
|
||||
{
|
||||
"createRule": null,
|
||||
"deleteRule": "@request.auth.id != \"\" && system.users.id ?= @request.auth.id",
|
||||
"deleteRule": null,
|
||||
"fields": [
|
||||
{
|
||||
"autogeneratePattern": "[a-z0-9]{10}",
|
||||
@@ -1447,16 +1447,16 @@ func init() {
|
||||
"indexes": [
|
||||
"CREATE INDEX ` + "`" + `idx_DZ9yhvgl44` + "`" + ` ON ` + "`" + `smart_devices` + "`" + ` (` + "`" + `system` + "`" + `)"
|
||||
],
|
||||
"listRule": "@request.auth.id != \"\" && system.users.id ?= @request.auth.id",
|
||||
"listRule": null,
|
||||
"name": "smart_devices",
|
||||
"system": false,
|
||||
"type": "base",
|
||||
"updateRule": null,
|
||||
"viewRule": "@request.auth.id != \"\" && system.users.id ?= @request.auth.id"
|
||||
"viewRule": null
|
||||
},
|
||||
{
|
||||
"createRule": "",
|
||||
"deleteRule": "",
|
||||
"createRule": null,
|
||||
"deleteRule": null,
|
||||
"fields": [
|
||||
{
|
||||
"autogeneratePattern": "[a-z0-9]{15}",
|
||||
@@ -1625,12 +1625,12 @@ func init() {
|
||||
],
|
||||
"id": "pbc_3116237454",
|
||||
"indexes": [],
|
||||
"listRule": "@request.auth.id != \"\" && system.users.id ?= @request.auth.id",
|
||||
"name": "system_details",
|
||||
"system": false,
|
||||
"type": "base",
|
||||
"updateRule": "",
|
||||
"viewRule": "@request.auth.id != \"\" && system.users.id ?= @request.auth.id"
|
||||
"updateRule": null,
|
||||
"listRule": null,
|
||||
"viewRule": null
|
||||
},
|
||||
{
|
||||
"createRule": null,
|
||||
|
||||
@@ -7,6 +7,19 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<title>Beszel</title>
|
||||
<style>
|
||||
.dark { background: hsl(220 5.5% 9%); color-scheme: dark; }
|
||||
</style>
|
||||
<script>
|
||||
(function() {
|
||||
try {
|
||||
var theme = localStorage.getItem('ui-theme');
|
||||
var isDark = theme === 'dark' ||
|
||||
(theme !== 'light' && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
document.documentElement.classList.add(isDark ? 'dark' : 'light');
|
||||
} catch (e) {}
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
globalThis.BESZEL = {
|
||||
BASE_PATH: "%BASE_URL%",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "beszel",
|
||||
"private": true,
|
||||
"version": "0.18.4",
|
||||
"version": "0.18.5",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { msg, t } from "@lingui/core/macro"
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { getPagePath } from "@nanostores/router"
|
||||
import { ChevronDownIcon, ExternalLinkIcon, PlusIcon } from "lucide-react"
|
||||
import { ChevronDownIcon, ExternalLinkIcon } from "lucide-react"
|
||||
import { memo, useEffect, useRef, useState } from "react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
@@ -35,28 +34,19 @@ import { DropdownMenu, DropdownMenuTrigger } from "./ui/dropdown-menu"
|
||||
import { AppleIcon, DockerIcon, FreeBsdIcon, TuxIcon, WindowsIcon } from "./ui/icons"
|
||||
import { InputCopy } from "./ui/input-copy"
|
||||
|
||||
export function AddSystemButton({ className }: { className?: string }) {
|
||||
if (isReadOnlyUser()) {
|
||||
return null
|
||||
}
|
||||
const [open, setOpen] = useState(false)
|
||||
// To avoid a refactor of the dialog, we will just keep this function as a "skeleton" for the actual dialog
|
||||
export function AddSystemDialog({ open, setOpen }: { open: boolean; setOpen: (open: boolean) => void }) {
|
||||
const opened = useRef(false)
|
||||
if (open) {
|
||||
opened.current = true
|
||||
}
|
||||
|
||||
if (isReadOnlyUser()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline" className={cn("flex gap-1 max-xs:h-[2.4rem]", className)}>
|
||||
<PlusIcon className="h-4 w-4 450:-ms-1" />
|
||||
<span className="hidden 450:inline">
|
||||
<Trans>
|
||||
Add <span className="hidden sm:inline">System</span>
|
||||
</Trans>
|
||||
</span>
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
{opened.current && <SystemDialog setOpen={setOpen} />}
|
||||
</Dialog>
|
||||
)
|
||||
@@ -276,7 +266,13 @@ export const SystemDialog = ({ setOpen, system }: { setOpen: (open: boolean) =>
|
||||
/>
|
||||
</TabsContent>
|
||||
{/* Save */}
|
||||
<Button>{system ? <Trans>Save system</Trans> : <Trans>Add system</Trans>}</Button>
|
||||
<Button>
|
||||
{system ? (
|
||||
<Trans>Save {{ foo: systemTranslation }}</Trans>
|
||||
) : (
|
||||
<Trans>Add {{ foo: systemTranslation }}</Trans>
|
||||
)}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Tabs>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useMemo } from "react"
|
||||
import { type ReactNode, useEffect, useMemo, useState } from "react"
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
|
||||
import {
|
||||
ChartContainer,
|
||||
@@ -11,18 +11,23 @@ import {
|
||||
import { chartMargin, cn, formatShortDate } from "@/lib/utils"
|
||||
import type { ChartData, SystemStatsRecord } from "@/types"
|
||||
import { useYAxisWidth } from "./hooks"
|
||||
import { AxisDomain } from "recharts/types/util/types"
|
||||
import type { AxisDomain } from "recharts/types/util/types"
|
||||
import { useIntersectionObserver } from "@/lib/use-intersection-observer"
|
||||
|
||||
export type DataPoint = {
|
||||
export type DataPoint<T = SystemStatsRecord> = {
|
||||
label: string
|
||||
dataKey: (data: SystemStatsRecord) => number | undefined
|
||||
dataKey: (data: T) => number | null | undefined
|
||||
color: number | string
|
||||
opacity: number
|
||||
stackId?: string | number
|
||||
order?: number
|
||||
strokeOpacity?: number
|
||||
activeDot?: boolean
|
||||
}
|
||||
|
||||
export default function AreaChartDefault({
|
||||
chartData,
|
||||
customData,
|
||||
max,
|
||||
maxToggled,
|
||||
tickFormatter,
|
||||
@@ -34,96 +39,129 @@ export default function AreaChartDefault({
|
||||
showTotal = false,
|
||||
reverseStackOrder = false,
|
||||
hideYAxis = false,
|
||||
filter,
|
||||
truncate = false,
|
||||
}: // logRender = false,
|
||||
{
|
||||
chartData: ChartData
|
||||
max?: number
|
||||
maxToggled?: boolean
|
||||
tickFormatter: (value: number, index: number) => string
|
||||
contentFormatter: ({ value, payload }: { value: number; payload: SystemStatsRecord }) => string
|
||||
dataPoints?: DataPoint[]
|
||||
domain?: AxisDomain
|
||||
legend?: boolean
|
||||
showTotal?: boolean
|
||||
itemSorter?: (a: any, b: any) => number
|
||||
reverseStackOrder?: boolean
|
||||
hideYAxis?: boolean
|
||||
// logRender?: boolean
|
||||
}) {
|
||||
{
|
||||
chartData: ChartData
|
||||
// biome-ignore lint/suspicious/noExplicitAny: accepts different data source types (systemStats or containerData)
|
||||
customData?: any[]
|
||||
max?: number
|
||||
maxToggled?: boolean
|
||||
tickFormatter: (value: number, index: number) => string
|
||||
// biome-ignore lint/suspicious/noExplicitAny: recharts tooltip item interop
|
||||
contentFormatter: (item: any, key: string) => ReactNode
|
||||
// biome-ignore lint/suspicious/noExplicitAny: accepts DataPoint with different generic types
|
||||
dataPoints?: DataPoint<any>[]
|
||||
domain?: AxisDomain
|
||||
legend?: boolean
|
||||
showTotal?: boolean
|
||||
// biome-ignore lint/suspicious/noExplicitAny: recharts tooltip item interop
|
||||
itemSorter?: (a: any, b: any) => number
|
||||
reverseStackOrder?: boolean
|
||||
hideYAxis?: boolean
|
||||
filter?: string
|
||||
truncate?: boolean
|
||||
// logRender?: boolean
|
||||
}) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
const { isIntersecting, ref } = useIntersectionObserver({ freeze: false })
|
||||
const sourceData = customData ?? chartData.systemStats
|
||||
// Only update the rendered data while the chart is visible
|
||||
const [displayData, setDisplayData] = useState(sourceData)
|
||||
|
||||
// Reduce chart redraws by only updating while visible or when chart time changes
|
||||
useEffect(() => {
|
||||
const shouldPrimeData = sourceData.length && !displayData.length
|
||||
const sourceChanged = sourceData !== displayData
|
||||
const shouldUpdate = shouldPrimeData || (sourceChanged && isIntersecting)
|
||||
if (shouldUpdate) {
|
||||
setDisplayData(sourceData)
|
||||
}
|
||||
}, [displayData, isIntersecting, sourceData])
|
||||
|
||||
// Use a stable key derived from data point identities and visual properties
|
||||
const areasKey = dataPoints?.map((d) => `${d.label}:${d.opacity}`).join("\0")
|
||||
|
||||
const Areas = useMemo(() => {
|
||||
return dataPoints?.map((dataPoint, i) => {
|
||||
let { color } = dataPoint
|
||||
if (typeof color === "number") {
|
||||
color = `var(--chart-${color})`
|
||||
}
|
||||
return (
|
||||
<Area
|
||||
key={dataPoint.label}
|
||||
dataKey={dataPoint.dataKey}
|
||||
name={dataPoint.label}
|
||||
type="monotoneX"
|
||||
fill={color}
|
||||
fillOpacity={dataPoint.opacity}
|
||||
stroke={color}
|
||||
strokeOpacity={dataPoint.strokeOpacity}
|
||||
isAnimationActive={false}
|
||||
stackId={dataPoint.stackId}
|
||||
order={dataPoint.order || i}
|
||||
activeDot={dataPoint.activeDot ?? true}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}, [areasKey, maxToggled])
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: ignore
|
||||
return useMemo(() => {
|
||||
if (chartData.systemStats.length === 0) {
|
||||
if (displayData.length === 0) {
|
||||
return null
|
||||
}
|
||||
// if (logRender) {
|
||||
// console.log("Rendered at", new Date())
|
||||
// console.log("Rendered at", new Date(), "for", dataPoints?.at(0)?.label)
|
||||
// }
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth || hideYAxis,
|
||||
"ps-4": hideYAxis,
|
||||
})}
|
||||
<ChartContainer
|
||||
ref={ref}
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth || hideYAxis,
|
||||
"ps-4": hideYAxis,
|
||||
})}
|
||||
>
|
||||
<AreaChart
|
||||
reverseStackOrder={reverseStackOrder}
|
||||
accessibilityLayer
|
||||
data={displayData}
|
||||
margin={hideYAxis ? { ...chartMargin, left: 5 } : chartMargin}
|
||||
>
|
||||
<AreaChart
|
||||
reverseStackOrder={reverseStackOrder}
|
||||
accessibilityLayer
|
||||
data={chartData.systemStats}
|
||||
margin={hideYAxis ? { ...chartMargin, left: 5 } : chartMargin}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
{!hideYAxis && (
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
width={yAxisWidth}
|
||||
domain={domain ?? [0, max ?? "auto"]}
|
||||
tickFormatter={(value, index) => updateYAxisWidth(tickFormatter(value, index))}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
/>
|
||||
)}
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
animationEasing="ease-out"
|
||||
animationDuration={150}
|
||||
// @ts-expect-error
|
||||
itemSorter={itemSorter}
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={contentFormatter}
|
||||
showTotal={showTotal}
|
||||
/>
|
||||
}
|
||||
<CartesianGrid vertical={false} />
|
||||
{!hideYAxis && (
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
width={yAxisWidth}
|
||||
domain={domain ?? [0, max ?? "auto"]}
|
||||
tickFormatter={(value, index) => updateYAxisWidth(tickFormatter(value, index))}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
/>
|
||||
{dataPoints?.map((dataPoint) => {
|
||||
let { color } = dataPoint
|
||||
if (typeof color === "number") {
|
||||
color = `var(--chart-${color})`
|
||||
}
|
||||
return (
|
||||
<Area
|
||||
key={dataPoint.label}
|
||||
dataKey={dataPoint.dataKey}
|
||||
name={dataPoint.label}
|
||||
type="monotoneX"
|
||||
fill={color}
|
||||
fillOpacity={dataPoint.opacity}
|
||||
stroke={color}
|
||||
isAnimationActive={false}
|
||||
stackId={dataPoint.stackId}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{legend && <ChartLegend content={<ChartLegendContent reverse={reverseStackOrder} />} />}
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)}
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
animationEasing="ease-out"
|
||||
animationDuration={150}
|
||||
// @ts-expect-error
|
||||
itemSorter={itemSorter}
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={contentFormatter}
|
||||
showTotal={showTotal}
|
||||
filter={filter}
|
||||
truncate={truncate}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{Areas}
|
||||
{legend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
)
|
||||
}, [chartData.systemStats.at(-1), yAxisWidth, maxToggled, showTotal])
|
||||
}, [displayData, yAxisWidth, showTotal, filter])
|
||||
}
|
||||
|
||||
@@ -1,215 +0,0 @@
|
||||
// import Spinner from '../spinner'
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { memo, useMemo } from "react"
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
|
||||
import {
|
||||
type ChartConfig,
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
pinnedAxisDomain,
|
||||
xAxis,
|
||||
} from "@/components/ui/chart"
|
||||
import { ChartType, Unit } from "@/lib/enums"
|
||||
import { $containerFilter, $userSettings } from "@/lib/stores"
|
||||
import { chartMargin, cn, decimalString, formatBytes, formatShortDate, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData } from "@/types"
|
||||
import { Separator } from "../ui/separator"
|
||||
import { useYAxisWidth } from "./hooks"
|
||||
|
||||
export default memo(function ContainerChart({
|
||||
dataKey,
|
||||
chartData,
|
||||
chartType,
|
||||
chartConfig,
|
||||
unit = "%",
|
||||
}: {
|
||||
dataKey: string
|
||||
chartData: ChartData
|
||||
chartType: ChartType
|
||||
chartConfig: ChartConfig
|
||||
unit?: string
|
||||
}) {
|
||||
const filter = useStore($containerFilter)
|
||||
const userSettings = useStore($userSettings)
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
|
||||
const { containerData } = chartData
|
||||
|
||||
const isNetChart = chartType === ChartType.Network
|
||||
|
||||
// Filter with set lookup
|
||||
const filteredKeys = useMemo(() => {
|
||||
if (!filter) {
|
||||
return new Set<string>()
|
||||
}
|
||||
const filterTerms = filter
|
||||
.toLowerCase()
|
||||
.split(" ")
|
||||
.filter((term) => term.length > 0)
|
||||
return new Set(
|
||||
Object.keys(chartConfig).filter((key) => {
|
||||
const keyLower = key.toLowerCase()
|
||||
return !filterTerms.some((term) => keyLower.includes(term))
|
||||
})
|
||||
)
|
||||
}, [chartConfig, filter])
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: not necessary
|
||||
const { toolTipFormatter, dataFunction, tickFormatter } = useMemo(() => {
|
||||
const obj = {} as {
|
||||
toolTipFormatter: (item: any, key: string) => React.ReactNode | string
|
||||
dataFunction: (key: string, data: any) => number | null
|
||||
tickFormatter: (value: any) => string
|
||||
}
|
||||
// tick formatter
|
||||
if (chartType === ChartType.CPU) {
|
||||
obj.tickFormatter = (value) => {
|
||||
const val = `${toFixedFloat(value, 2)}%`
|
||||
return updateYAxisWidth(val)
|
||||
}
|
||||
} else {
|
||||
const chartUnit = isNetChart ? userSettings.unitNet : Unit.Bytes
|
||||
obj.tickFormatter = (val) => {
|
||||
const { value, unit } = formatBytes(val, isNetChart, chartUnit, !isNetChart)
|
||||
return updateYAxisWidth(`${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}`)
|
||||
}
|
||||
}
|
||||
// tooltip formatter
|
||||
if (isNetChart) {
|
||||
const getRxTxBytes = (record?: { b?: [number, number]; ns?: number; nr?: number }) => {
|
||||
if (record?.b?.length && record.b.length >= 2) {
|
||||
return [Number(record.b[0]) || 0, Number(record.b[1]) || 0]
|
||||
}
|
||||
return [(record?.ns ?? 0) * 1024 * 1024, (record?.nr ?? 0) * 1024 * 1024]
|
||||
}
|
||||
const formatRxTx = (recv: number, sent: number) => {
|
||||
const { value: receivedValue, unit: receivedUnit } = formatBytes(recv, true, userSettings.unitNet, false)
|
||||
const { value: sentValue, unit: sentUnit } = formatBytes(sent, true, userSettings.unitNet, false)
|
||||
return (
|
||||
<span className="flex">
|
||||
{decimalString(receivedValue)} {receivedUnit}
|
||||
<span className="opacity-70 ms-0.5"> rx </span>
|
||||
<Separator orientation="vertical" className="h-3 mx-1.5 bg-primary/40" />
|
||||
{decimalString(sentValue)} {sentUnit}
|
||||
<span className="opacity-70 ms-0.5"> tx</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
obj.toolTipFormatter = (item: any, key: string) => {
|
||||
try {
|
||||
if (key === "__total__") {
|
||||
let totalSent = 0
|
||||
let totalRecv = 0
|
||||
const payloadData = item?.payload && typeof item.payload === "object" ? item.payload : {}
|
||||
for (const [containerKey, value] of Object.entries(payloadData)) {
|
||||
if (!value || typeof value !== "object") {
|
||||
continue
|
||||
}
|
||||
// Skip filtered out containers
|
||||
if (filteredKeys.has(containerKey)) {
|
||||
continue
|
||||
}
|
||||
const [sent, recv] = getRxTxBytes(value as { b?: [number, number]; ns?: number; nr?: number })
|
||||
totalSent += sent
|
||||
totalRecv += recv
|
||||
}
|
||||
return formatRxTx(totalRecv, totalSent)
|
||||
}
|
||||
const [sent, recv] = getRxTxBytes(item?.payload?.[key])
|
||||
return formatRxTx(recv, sent)
|
||||
} catch (e) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
} else if (chartType === ChartType.Memory) {
|
||||
obj.toolTipFormatter = (item: any) => {
|
||||
const { value, unit } = formatBytes(item.value, false, Unit.Bytes, true)
|
||||
return `${decimalString(value)} ${unit}`
|
||||
}
|
||||
} else {
|
||||
obj.toolTipFormatter = (item: any) => `${decimalString(item.value)}${unit}`
|
||||
}
|
||||
// data function
|
||||
if (isNetChart) {
|
||||
obj.dataFunction = (key: string, data: any) => {
|
||||
const payload = data[key]
|
||||
if (!payload) {
|
||||
return null
|
||||
}
|
||||
const sent = payload?.b?.[0] ?? (payload?.ns ?? 0) * 1024 * 1024
|
||||
const recv = payload?.b?.[1] ?? (payload?.nr ?? 0) * 1024 * 1024
|
||||
return sent + recv
|
||||
}
|
||||
} else {
|
||||
obj.dataFunction = (key: string, data: any) => data[key]?.[dataKey] ?? null
|
||||
}
|
||||
return obj
|
||||
}, [filteredKeys])
|
||||
|
||||
// console.log('rendered at', new Date())
|
||||
|
||||
if (containerData.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<AreaChart
|
||||
accessibilityLayer
|
||||
// syncId={'cpu'}
|
||||
data={containerData}
|
||||
margin={chartMargin}
|
||||
reverseStackOrder={true}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
domain={pinnedAxisDomain()}
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
width={yAxisWidth}
|
||||
tickFormatter={tickFormatter}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
/>
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
animationEasing="ease-out"
|
||||
animationDuration={150}
|
||||
truncate={true}
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
// @ts-expect-error
|
||||
itemSorter={(a, b) => b.value - a.value}
|
||||
content={<ChartTooltipContent filter={filter} contentFormatter={toolTipFormatter} showTotal={true} />}
|
||||
/>
|
||||
{Object.keys(chartConfig).map((key) => {
|
||||
const filtered = filteredKeys.has(key)
|
||||
const fillOpacity = filtered ? 0.05 : 0.4
|
||||
const strokeOpacity = filtered ? 0.1 : 1
|
||||
return (
|
||||
<Area
|
||||
key={key}
|
||||
isAnimationActive={false}
|
||||
dataKey={dataFunction.bind(null, key)}
|
||||
name={key}
|
||||
type="monotoneX"
|
||||
fill={chartConfig[key].color}
|
||||
fillOpacity={fillOpacity}
|
||||
stroke={chartConfig[key].color}
|
||||
strokeOpacity={strokeOpacity}
|
||||
activeDot={{ opacity: filtered ? 0 : 1 }}
|
||||
stackId="a"
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
@@ -1,83 +0,0 @@
|
||||
import { useLingui } from "@lingui/react/macro"
|
||||
import { memo } from "react"
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from "@/components/ui/chart"
|
||||
import { Unit } from "@/lib/enums"
|
||||
import { chartMargin, cn, decimalString, formatBytes, formatShortDate, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData, SystemStatsRecord } from "@/types"
|
||||
import { useYAxisWidth } from "./hooks"
|
||||
|
||||
export default memo(function DiskChart({
|
||||
dataKey,
|
||||
diskSize,
|
||||
chartData,
|
||||
}: {
|
||||
dataKey: string | ((data: SystemStatsRecord) => number | undefined)
|
||||
diskSize: number
|
||||
chartData: ChartData
|
||||
}) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
const { t } = useLingui()
|
||||
|
||||
// round to nearest GB
|
||||
if (diskSize >= 100) {
|
||||
diskSize = Math.round(diskSize)
|
||||
}
|
||||
|
||||
if (chartData.systemStats.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<AreaChart accessibilityLayer data={chartData.systemStats} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
width={yAxisWidth}
|
||||
domain={[0, diskSize]}
|
||||
tickCount={9}
|
||||
minTickGap={6}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickFormatter={(val) => {
|
||||
const { value, unit } = formatBytes(val * 1024, false, Unit.Bytes, true)
|
||||
return updateYAxisWidth(toFixedFloat(value, value >= 10 ? 0 : 1) + " " + unit)
|
||||
}}
|
||||
/>
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
animationEasing="ease-out"
|
||||
animationDuration={150}
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={({ value }) => {
|
||||
const { value: convertedValue, unit } = formatBytes(value * 1024, false, Unit.Bytes, true)
|
||||
return decimalString(convertedValue) + " " + unit
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Area
|
||||
dataKey={dataKey}
|
||||
name={t`Disk Usage`}
|
||||
type="monotoneX"
|
||||
fill="var(--chart-4)"
|
||||
fillOpacity={0.4}
|
||||
stroke="var(--chart-4)"
|
||||
// animationDuration={1200}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
@@ -1,117 +0,0 @@
|
||||
import { memo, useMemo } from "react"
|
||||
import { CartesianGrid, Line, LineChart, YAxis } from "recharts"
|
||||
import {
|
||||
ChartContainer,
|
||||
ChartLegend,
|
||||
ChartLegendContent,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
xAxis,
|
||||
} from "@/components/ui/chart"
|
||||
import { chartMargin, cn, decimalString, formatShortDate, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData, GPUData } from "@/types"
|
||||
import { useYAxisWidth } from "./hooks"
|
||||
import type { DataPoint } from "./line-chart"
|
||||
|
||||
export default memo(function GpuPowerChart({ chartData }: { chartData: ChartData }) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
const packageKey = " package"
|
||||
|
||||
const { gpuData, dataPoints } = useMemo(() => {
|
||||
const dataPoints = [] as DataPoint[]
|
||||
const gpuData = [] as Record<string, GPUData | string>[]
|
||||
const addedKeys = new Map<string, number>()
|
||||
|
||||
const addKey = (key: string, value: number) => {
|
||||
addedKeys.set(key, (addedKeys.get(key) ?? 0) + value)
|
||||
}
|
||||
|
||||
for (const stats of chartData.systemStats) {
|
||||
const gpus = stats.stats?.g ?? {}
|
||||
const data = { created: stats.created } as Record<string, GPUData | string>
|
||||
for (const id in gpus) {
|
||||
const gpu = gpus[id] as GPUData
|
||||
data[gpu.n] = gpu
|
||||
addKey(gpu.n, gpu.p ?? 0)
|
||||
if (gpu.pp) {
|
||||
data[`${gpu.n}${packageKey}`] = gpu
|
||||
addKey(`${gpu.n}${packageKey}`, gpu.pp ?? 0)
|
||||
}
|
||||
}
|
||||
gpuData.push(data)
|
||||
}
|
||||
const sortedKeys = Array.from(addedKeys.entries())
|
||||
.sort(([, a], [, b]) => b - a)
|
||||
.map(([key]) => key)
|
||||
|
||||
for (let i = 0; i < sortedKeys.length; i++) {
|
||||
const id = sortedKeys[i]
|
||||
dataPoints.push({
|
||||
label: id,
|
||||
dataKey: (gpuData: Record<string, GPUData>) => {
|
||||
return id.endsWith(packageKey) ? (gpuData[id]?.pp ?? 0) : (gpuData[id]?.p ?? 0)
|
||||
},
|
||||
color: `hsl(${226 + (((i * 360) / addedKeys.size) % 360)}, 65%, 52%)`,
|
||||
})
|
||||
}
|
||||
return { gpuData, dataPoints }
|
||||
}, [chartData])
|
||||
|
||||
if (chartData.systemStats.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<LineChart accessibilityLayer data={gpuData} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
domain={[0, "auto"]}
|
||||
width={yAxisWidth}
|
||||
tickFormatter={(value) => {
|
||||
const val = toFixedFloat(value, 2)
|
||||
return updateYAxisWidth(`${val}W`)
|
||||
}}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
/>
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
animationEasing="ease-out"
|
||||
animationDuration={150}
|
||||
// @ts-expect-error
|
||||
itemSorter={(a, b) => b.value - a.value}
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={(item) => `${decimalString(item.value)}W`}
|
||||
// indicator="line"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{dataPoints.map((dataPoint) => (
|
||||
<Line
|
||||
key={dataPoint.label}
|
||||
dataKey={dataPoint.dataKey}
|
||||
name={dataPoint.label}
|
||||
type="monotoneX"
|
||||
dot={false}
|
||||
strokeWidth={1.5}
|
||||
stroke={dataPoint.color as string}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
))}
|
||||
{dataPoints.length > 1 && <ChartLegend content={<ChartLegendContent />} />}
|
||||
</LineChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
@@ -1,6 +1,9 @@
|
||||
import { useMemo, useState } from "react"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import type { ChartConfig } from "@/components/ui/chart"
|
||||
import type { ChartData, SystemStats, SystemStatsRecord } from "@/types"
|
||||
import type { DataPoint } from "./area-chart"
|
||||
import { $containerFilter } from "@/lib/stores"
|
||||
|
||||
/** Chart configurations for CPU, memory, and network usage charts */
|
||||
export interface ContainerChartConfigs {
|
||||
@@ -96,9 +99,9 @@ export function useYAxisWidth() {
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => {
|
||||
document.body.appendChild(div)
|
||||
const width = div.offsetWidth + 24
|
||||
const width = div.offsetWidth + 20
|
||||
if (width > yAxisWidth) {
|
||||
setYAxisWidth(div.offsetWidth + 24)
|
||||
setYAxisWidth(width)
|
||||
}
|
||||
document.body.removeChild(div)
|
||||
})
|
||||
@@ -108,6 +111,44 @@ export function useYAxisWidth() {
|
||||
return { yAxisWidth, updateYAxisWidth }
|
||||
}
|
||||
|
||||
/** Subscribes to the container filter store and returns filtered DataPoints for container charts */
|
||||
export function useContainerDataPoints(
|
||||
chartConfig: ChartConfig,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: container data records have dynamic keys
|
||||
dataFn: (key: string, data: Record<string, any>) => number | null
|
||||
) {
|
||||
const filter = useStore($containerFilter)
|
||||
const { dataPoints, filteredKeys } = useMemo(() => {
|
||||
const filterTerms = filter
|
||||
? filter
|
||||
.toLowerCase()
|
||||
.split(" ")
|
||||
.filter((term) => term.length > 0)
|
||||
: []
|
||||
const filtered = new Set<string>()
|
||||
const points = Object.keys(chartConfig).map((key) => {
|
||||
const isFiltered = filterTerms.length > 0 && !filterTerms.some((term) => key.toLowerCase().includes(term))
|
||||
if (isFiltered) filtered.add(key)
|
||||
return {
|
||||
label: key,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: container data records have dynamic keys
|
||||
dataKey: (data: Record<string, any>) => dataFn(key, data),
|
||||
color: chartConfig[key].color ?? "",
|
||||
opacity: isFiltered ? 0.05 : 0.4,
|
||||
strokeOpacity: isFiltered ? 0.1 : 1,
|
||||
activeDot: !isFiltered,
|
||||
stackId: "a",
|
||||
}
|
||||
})
|
||||
return {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: container data records have dynamic keys
|
||||
dataPoints: points as DataPoint<Record<string, any>>[],
|
||||
filteredKeys: filtered,
|
||||
}
|
||||
}, [chartConfig, filter])
|
||||
return { filter, dataPoints, filteredKeys }
|
||||
}
|
||||
|
||||
// Assures consistent colors for network interfaces
|
||||
export function useNetworkInterfaces(interfaces: SystemStats["ni"]) {
|
||||
const keys = Object.keys(interfaces ?? {})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useMemo } from "react"
|
||||
import { type ReactNode, useEffect, useMemo, useState } from "react"
|
||||
import { CartesianGrid, Line, LineChart, YAxis } from "recharts"
|
||||
import {
|
||||
ChartContainer,
|
||||
@@ -11,15 +11,22 @@ import {
|
||||
import { chartMargin, cn, formatShortDate } from "@/lib/utils"
|
||||
import type { ChartData, SystemStatsRecord } from "@/types"
|
||||
import { useYAxisWidth } from "./hooks"
|
||||
import type { AxisDomain } from "recharts/types/util/types"
|
||||
import { useIntersectionObserver } from "@/lib/use-intersection-observer"
|
||||
|
||||
export type DataPoint = {
|
||||
export type DataPoint<T = SystemStatsRecord> = {
|
||||
label: string
|
||||
dataKey: (data: SystemStatsRecord) => number | undefined
|
||||
dataKey: (data: T) => number | null | undefined
|
||||
color: number | string
|
||||
stackId?: string | number
|
||||
order?: number
|
||||
strokeOpacity?: number
|
||||
activeDot?: boolean
|
||||
}
|
||||
|
||||
export default function LineChartDefault({
|
||||
chartData,
|
||||
customData,
|
||||
max,
|
||||
maxToggled,
|
||||
tickFormatter,
|
||||
@@ -28,38 +35,101 @@ export default function LineChartDefault({
|
||||
domain,
|
||||
legend,
|
||||
itemSorter,
|
||||
showTotal = false,
|
||||
reverseStackOrder = false,
|
||||
hideYAxis = false,
|
||||
filter,
|
||||
truncate = false,
|
||||
}: // logRender = false,
|
||||
{
|
||||
chartData: ChartData
|
||||
// biome-ignore lint/suspicious/noExplicitAny: accepts different data source types (systemStats or containerData)
|
||||
customData?: any[]
|
||||
max?: number
|
||||
maxToggled?: boolean
|
||||
tickFormatter: (value: number, index: number) => string
|
||||
contentFormatter: ({ value, payload }: { value: number; payload: SystemStatsRecord }) => string
|
||||
dataPoints?: DataPoint[]
|
||||
domain?: [number, number]
|
||||
// biome-ignore lint/suspicious/noExplicitAny: recharts tooltip item interop
|
||||
contentFormatter: (item: any, key: string) => ReactNode
|
||||
// biome-ignore lint/suspicious/noExplicitAny: accepts DataPoint with different generic types
|
||||
dataPoints?: DataPoint<any>[]
|
||||
domain?: AxisDomain
|
||||
legend?: boolean
|
||||
showTotal?: boolean
|
||||
// biome-ignore lint/suspicious/noExplicitAny: recharts tooltip item interop
|
||||
itemSorter?: (a: any, b: any) => number
|
||||
reverseStackOrder?: boolean
|
||||
hideYAxis?: boolean
|
||||
filter?: string
|
||||
truncate?: boolean
|
||||
// logRender?: boolean
|
||||
}) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
const { isIntersecting, ref } = useIntersectionObserver({ freeze: false })
|
||||
const sourceData = customData ?? chartData.systemStats
|
||||
// Only update the rendered data while the chart is visible
|
||||
const [displayData, setDisplayData] = useState(sourceData)
|
||||
|
||||
// Reduce chart redraws by only updating while visible or when chart time changes
|
||||
useEffect(() => {
|
||||
const shouldPrimeData = sourceData.length && !displayData.length
|
||||
const sourceChanged = sourceData !== displayData
|
||||
const shouldUpdate = shouldPrimeData || (sourceChanged && isIntersecting)
|
||||
if (shouldUpdate) {
|
||||
setDisplayData(sourceData)
|
||||
}
|
||||
}, [displayData, isIntersecting, sourceData])
|
||||
|
||||
// Use a stable key derived from data point identities and visual properties
|
||||
const linesKey = dataPoints?.map((d) => `${d.label}:${d.strokeOpacity ?? ""}`).join("\0")
|
||||
|
||||
const Lines = useMemo(() => {
|
||||
return dataPoints?.map((dataPoint, i) => {
|
||||
let { color } = dataPoint
|
||||
if (typeof color === "number") {
|
||||
color = `var(--chart-${color})`
|
||||
}
|
||||
return (
|
||||
<Line
|
||||
key={dataPoint.label}
|
||||
dataKey={dataPoint.dataKey}
|
||||
name={dataPoint.label}
|
||||
type="monotoneX"
|
||||
dot={false}
|
||||
strokeWidth={1.5}
|
||||
stroke={color}
|
||||
strokeOpacity={dataPoint.strokeOpacity}
|
||||
isAnimationActive={false}
|
||||
// stackId={dataPoint.stackId}
|
||||
order={dataPoint.order || i}
|
||||
// activeDot={dataPoint.activeDot ?? true}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}, [linesKey, maxToggled])
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: ignore
|
||||
return useMemo(() => {
|
||||
if (chartData.systemStats.length === 0) {
|
||||
if (displayData.length === 0) {
|
||||
return null
|
||||
}
|
||||
// if (logRender) {
|
||||
// console.log("Rendered at", new Date())
|
||||
// console.log("Rendered at", new Date(), "for", dataPoints?.at(0)?.label)
|
||||
// }
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
<ChartContainer
|
||||
ref={ref}
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth || hideYAxis,
|
||||
"ps-4": hideYAxis,
|
||||
})}
|
||||
>
|
||||
<LineChart
|
||||
reverseStackOrder={reverseStackOrder}
|
||||
accessibilityLayer
|
||||
data={displayData}
|
||||
margin={hideYAxis ? { ...chartMargin, left: 5 } : chartMargin}
|
||||
>
|
||||
<LineChart accessibilityLayer data={chartData.systemStats} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<CartesianGrid vertical={false} />
|
||||
{!hideYAxis && (
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
@@ -70,41 +140,27 @@ export default function LineChartDefault({
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
/>
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
animationEasing="ease-out"
|
||||
animationDuration={150}
|
||||
// @ts-expect-error
|
||||
itemSorter={itemSorter}
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={contentFormatter}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{dataPoints?.map((dataPoint) => {
|
||||
let { color } = dataPoint
|
||||
if (typeof color === "number") {
|
||||
color = `var(--chart-${color})`
|
||||
}
|
||||
return (
|
||||
<Line
|
||||
key={dataPoint.label}
|
||||
dataKey={dataPoint.dataKey}
|
||||
name={dataPoint.label}
|
||||
type="monotoneX"
|
||||
dot={false}
|
||||
strokeWidth={1.5}
|
||||
stroke={color}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{legend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
</LineChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)}
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
animationEasing="ease-out"
|
||||
animationDuration={150}
|
||||
// @ts-expect-error
|
||||
itemSorter={itemSorter}
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={contentFormatter}
|
||||
showTotal={showTotal}
|
||||
filter={filter}
|
||||
truncate={truncate}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{Lines}
|
||||
{legend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
</LineChart>
|
||||
</ChartContainer>
|
||||
)
|
||||
}, [chartData.systemStats.at(-1), yAxisWidth, maxToggled])
|
||||
}, [displayData, yAxisWidth, showTotal, filter, chartData.chartTime])
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { memo } from "react"
|
||||
import { CartesianGrid, Line, LineChart, YAxis } from "recharts"
|
||||
import {
|
||||
ChartContainer,
|
||||
ChartLegend,
|
||||
ChartLegendContent,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
xAxis,
|
||||
} from "@/components/ui/chart"
|
||||
import { chartMargin, cn, decimalString, formatShortDate, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData, SystemStats } from "@/types"
|
||||
import { useYAxisWidth } from "./hooks"
|
||||
|
||||
export default memo(function LoadAverageChart({ chartData }: { chartData: ChartData }) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
|
||||
const keys: { color: string; label: string }[] = [
|
||||
{
|
||||
color: "hsl(271, 81%, 60%)", // Purple
|
||||
label: t({ message: `1 min`, comment: "Load average" }),
|
||||
},
|
||||
{
|
||||
color: "hsl(217, 91%, 60%)", // Blue
|
||||
label: t({ message: `5 min`, comment: "Load average" }),
|
||||
},
|
||||
{
|
||||
color: "hsl(25, 95%, 53%)", // Orange
|
||||
label: t({ message: `15 min`, comment: "Load average" }),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<LineChart accessibilityLayer data={chartData.systemStats} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
domain={[0, "auto"]}
|
||||
width={yAxisWidth}
|
||||
tickFormatter={(value) => {
|
||||
return updateYAxisWidth(String(toFixedFloat(value, 2)))
|
||||
}}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
/>
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
animationEasing="ease-out"
|
||||
animationDuration={150}
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={(item) => decimalString(item.value)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{keys.map(({ color, label }, i) => (
|
||||
<Line
|
||||
key={label}
|
||||
dataKey={(value: { stats: SystemStats }) => value.stats?.la?.[i]}
|
||||
name={label}
|
||||
type="monotoneX"
|
||||
dot={false}
|
||||
strokeWidth={1.5}
|
||||
stroke={color}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
))}
|
||||
<ChartLegend content={<ChartLegendContent />} />
|
||||
</LineChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
@@ -1,108 +0,0 @@
|
||||
import { useLingui } from "@lingui/react/macro"
|
||||
import { memo } from "react"
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from "@/components/ui/chart"
|
||||
import { Unit } from "@/lib/enums"
|
||||
import { chartMargin, cn, decimalString, formatBytes, formatShortDate, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData } from "@/types"
|
||||
import { useYAxisWidth } from "./hooks"
|
||||
|
||||
export default memo(function MemChart({ chartData, showMax }: { chartData: ChartData; showMax: boolean }) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
const { t } = useLingui()
|
||||
|
||||
const totalMem = toFixedFloat(chartData.systemStats.at(-1)?.stats.m ?? 0, 1)
|
||||
|
||||
// console.log('rendered at', new Date())
|
||||
|
||||
if (chartData.systemStats.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* {!yAxisSet && <Spinner />} */}
|
||||
<ChartContainer
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<AreaChart accessibilityLayer data={chartData.systemStats} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
{totalMem && (
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
// use "ticks" instead of domain / tickcount if need more control
|
||||
domain={[0, totalMem]}
|
||||
tickCount={9}
|
||||
className="tracking-tighter"
|
||||
width={yAxisWidth}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickFormatter={(value) => {
|
||||
const { value: convertedValue, unit } = formatBytes(value * 1024, false, Unit.Bytes, true)
|
||||
return updateYAxisWidth(toFixedFloat(convertedValue, value >= 10 ? 0 : 1) + " " + unit)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
// cursor={false}
|
||||
animationEasing="ease-out"
|
||||
animationDuration={150}
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
// @ts-expect-error
|
||||
itemSorter={(a, b) => a.order - b.order}
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={({ value }) => {
|
||||
// mem values are supplied as GB
|
||||
const { value: convertedValue, unit } = formatBytes(value * 1024, false, Unit.Bytes, true)
|
||||
return decimalString(convertedValue, convertedValue >= 100 ? 1 : 2) + " " + unit
|
||||
}}
|
||||
showTotal={true}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Area
|
||||
name={t`Used`}
|
||||
order={3}
|
||||
dataKey={({ stats }) => (showMax ? stats?.mm : stats?.mu)}
|
||||
type="monotoneX"
|
||||
fill="var(--chart-2)"
|
||||
fillOpacity={0.4}
|
||||
stroke="var(--chart-2)"
|
||||
stackId="1"
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
{/* {chartData.systemStats.at(-1)?.stats.mz && ( */}
|
||||
<Area
|
||||
name="ZFS ARC"
|
||||
order={2}
|
||||
dataKey={({ stats }) => (showMax ? null : stats?.mz)}
|
||||
type="monotoneX"
|
||||
fill="hsla(175 60% 45% / 0.8)"
|
||||
fillOpacity={0.5}
|
||||
stroke="hsla(175 60% 45% / 0.8)"
|
||||
stackId="1"
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
{/* )} */}
|
||||
<Area
|
||||
name={t`Cache / Buffers`}
|
||||
order={1}
|
||||
dataKey={({ stats }) => (showMax ? null : stats?.mb)}
|
||||
type="monotoneX"
|
||||
fill="hsla(160 60% 45% / 0.5)"
|
||||
fillOpacity={0.4}
|
||||
stroke="hsla(160 60% 45% / 0.5)"
|
||||
stackId="1"
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
{/* <ChartLegend content={<ChartLegendContent />} /> */}
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
@@ -1,70 +0,0 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { memo } from "react"
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from "@/components/ui/chart"
|
||||
import { $userSettings } from "@/lib/stores"
|
||||
import { chartMargin, cn, decimalString, formatBytes, formatShortDate, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData } from "@/types"
|
||||
import { useYAxisWidth } from "./hooks"
|
||||
|
||||
export default memo(function SwapChart({ chartData }: { chartData: ChartData }) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
const userSettings = useStore($userSettings)
|
||||
|
||||
if (chartData.systemStats.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<AreaChart accessibilityLayer data={chartData.systemStats} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
domain={[0, () => toFixedFloat(chartData.systemStats.at(-1)?.stats.s ?? 0.04, 2)]}
|
||||
width={yAxisWidth}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickFormatter={(value) => {
|
||||
const { value: convertedValue, unit } = formatBytes(value * 1024, false, userSettings.unitDisk, true)
|
||||
return updateYAxisWidth(toFixedFloat(convertedValue, value >= 10 ? 0 : 1) + " " + unit)
|
||||
}}
|
||||
/>
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
animationEasing="ease-out"
|
||||
animationDuration={150}
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={({ value }) => {
|
||||
// mem values are supplied as GB
|
||||
const { value: convertedValue, unit } = formatBytes(value * 1024, false, userSettings.unitDisk, true)
|
||||
return decimalString(convertedValue, convertedValue >= 100 ? 1 : 2) + " " + unit
|
||||
}}
|
||||
// indicator="line"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Area
|
||||
dataKey="stats.su"
|
||||
name={t`Used`}
|
||||
type="monotoneX"
|
||||
fill="var(--chart-2)"
|
||||
fillOpacity={0.4}
|
||||
stroke="var(--chart-2)"
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
@@ -1,117 +0,0 @@
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { memo, useMemo } from "react"
|
||||
import { CartesianGrid, Line, LineChart, YAxis } from "recharts"
|
||||
import {
|
||||
ChartContainer,
|
||||
ChartLegend,
|
||||
ChartLegendContent,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
xAxis,
|
||||
} from "@/components/ui/chart"
|
||||
import { $temperatureFilter, $userSettings } from "@/lib/stores"
|
||||
import { chartMargin, cn, decimalString, formatShortDate, formatTemperature, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData } from "@/types"
|
||||
import { useYAxisWidth } from "./hooks"
|
||||
|
||||
export default memo(function TemperatureChart({ chartData }: { chartData: ChartData }) {
|
||||
const filter = useStore($temperatureFilter)
|
||||
const userSettings = useStore($userSettings)
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
|
||||
if (chartData.systemStats.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
/** Format temperature data for chart and assign colors */
|
||||
const newChartData = useMemo(() => {
|
||||
const newChartData = { data: [], colors: {} } as {
|
||||
data: Record<string, number | string>[]
|
||||
colors: Record<string, string>
|
||||
}
|
||||
const tempSums = {} as Record<string, number>
|
||||
for (const data of chartData.systemStats) {
|
||||
const newData = { created: data.created } as Record<string, number | string>
|
||||
const keys = Object.keys(data.stats?.t ?? {})
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i]
|
||||
newData[key] = data.stats.t![key]
|
||||
tempSums[key] = (tempSums[key] ?? 0) + newData[key]
|
||||
}
|
||||
newChartData.data.push(newData)
|
||||
}
|
||||
const keys = Object.keys(tempSums).sort((a, b) => tempSums[b] - tempSums[a])
|
||||
for (const key of keys) {
|
||||
newChartData.colors[key] = `hsl(${((keys.indexOf(key) * 360) / keys.length) % 360}, 60%, 55%)`
|
||||
}
|
||||
return newChartData
|
||||
}, [chartData])
|
||||
|
||||
const colors = Object.keys(newChartData.colors)
|
||||
|
||||
// console.log('rendered at', new Date())
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<LineChart accessibilityLayer data={newChartData.data} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
domain={["auto", "auto"]}
|
||||
width={yAxisWidth}
|
||||
tickFormatter={(val) => {
|
||||
const { value, unit } = formatTemperature(val, userSettings.unitTemp)
|
||||
return updateYAxisWidth(toFixedFloat(value, 2) + " " + unit)
|
||||
}}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
/>
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
animationEasing="ease-out"
|
||||
animationDuration={150}
|
||||
// @ts-expect-error
|
||||
itemSorter={(a, b) => b.value - a.value}
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={(item) => {
|
||||
const { value, unit } = formatTemperature(item.value, userSettings.unitTemp)
|
||||
return decimalString(value) + " " + unit
|
||||
}}
|
||||
filter={filter}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{colors.map((key) => {
|
||||
const filterTerms = filter ? filter.toLowerCase().split(" ").filter(term => term.length > 0) : []
|
||||
const filtered = filterTerms.length > 0 && !filterTerms.some(term => key.toLowerCase().includes(term))
|
||||
const strokeOpacity = filtered ? 0.1 : 1
|
||||
return (
|
||||
<Line
|
||||
key={key}
|
||||
dataKey={key}
|
||||
name={key}
|
||||
type="monotoneX"
|
||||
dot={false}
|
||||
strokeWidth={1.5}
|
||||
stroke={newChartData.colors[key]}
|
||||
strokeOpacity={strokeOpacity}
|
||||
activeDot={{ opacity: filtered ? 0 : 1 }}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{colors.length < 12 && <ChartLegend content={<ChartLegendContent />} />}
|
||||
</LineChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
@@ -163,9 +163,9 @@ export default function ContainersTable({ systemId }: { systemId?: string }) {
|
||||
const visibleColumns = table.getVisibleLeafColumns()
|
||||
|
||||
return (
|
||||
<Card className="p-6 @container w-full">
|
||||
<CardHeader className="p-0 mb-4">
|
||||
<div className="grid md:flex gap-5 w-full items-end">
|
||||
<Card className="@container w-full px-3 py-5 sm:py-6 sm:px-6">
|
||||
<CardHeader className="p-0 mb-3 sm:mb-4">
|
||||
<div className="grid md:flex gap-x-5 gap-y-3 w-full items-end">
|
||||
<div className="px-2 sm:px-1">
|
||||
<CardTitle className="mb-2">
|
||||
<Trans>All Containers</Trans>
|
||||
@@ -462,7 +462,6 @@ function ContainerSheet({
|
||||
function ContainersTableHead({ table }: { table: TableType<ContainerRecord> }) {
|
||||
return (
|
||||
<TableHeader className="sticky top-0 z-50 w-full border-b-2">
|
||||
<div className="absolute -top-2 left-0 w-full h-4 bg-table-header z-50"></div>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { GithubIcon } from "lucide-react"
|
||||
import { $newVersion } from "@/lib/stores"
|
||||
import { Separator } from "./ui/separator"
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
|
||||
export function FooterRepoLink() {
|
||||
const newVersion = useStore($newVersion)
|
||||
return (
|
||||
<div className="flex gap-1.5 justify-end items-center pe-3 sm:pe-6 mt-3.5 mb-4 text-xs opacity-80">
|
||||
<a
|
||||
@@ -21,6 +25,19 @@ export function FooterRepoLink() {
|
||||
>
|
||||
Beszel {globalThis.BESZEL.HUB_VERSION}
|
||||
</a>
|
||||
{newVersion?.v && (
|
||||
<>
|
||||
<Separator orientation="vertical" className="h-2.5 bg-muted-foreground opacity-70" />
|
||||
<a
|
||||
href={newVersion.url}
|
||||
target="_blank"
|
||||
className="text-yellow-500 hover:text-yellow-400 duration-75"
|
||||
rel="noopener"
|
||||
>
|
||||
<Trans context="New version available">{newVersion.v} available</Trans>
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Trans, useLingui } from "@lingui/react/macro"
|
||||
import { LanguagesIcon } from "lucide-react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { buttonVariants } from "@/components/ui/button"
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
|
||||
import { dynamicActivate } from "@/lib/i18n"
|
||||
import languages from "@/lib/languages"
|
||||
@@ -14,31 +14,29 @@ export function LangToggle() {
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant={"ghost"} size="icon" className="hidden sm:flex">
|
||||
<LanguagesIcon className="absolute h-[1.2rem] w-[1.2rem] light:opacity-85" />
|
||||
<span className="sr-only">{LangTrans}</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{LangTrans}</TooltipContent>
|
||||
</Tooltip>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="grid grid-cols-3">
|
||||
{languages.map(([lang, label, e]) => (
|
||||
<DropdownMenuItem
|
||||
key={lang}
|
||||
className={cn("px-2.5 flex gap-2.5 cursor-pointer", lang === i18n.locale && "bg-accent/70 font-medium")}
|
||||
onClick={() => dynamicActivate(lang)}
|
||||
>
|
||||
<span>
|
||||
{e || <code className="font-mono bg-muted text-[.65em] w-5 h-4 grid place-items-center">{lang}</code>}
|
||||
</span>{" "}
|
||||
{label}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<DropdownMenuTrigger className={cn(buttonVariants({ variant: "ghost", size: "icon" }))}>
|
||||
<LanguagesIcon className="absolute h-[1.2rem] w-[1.2rem] light:opacity-85" />
|
||||
<span className="sr-only">{LangTrans}</span>
|
||||
<TooltipContent>{LangTrans}</TooltipContent>
|
||||
</DropdownMenuTrigger>
|
||||
</TooltipTrigger>
|
||||
<DropdownMenuContent className="grid grid-cols-3">
|
||||
{languages.map(([lang, label, e]) => (
|
||||
<DropdownMenuItem
|
||||
key={lang}
|
||||
className={cn("px-2.5 flex gap-2.5 cursor-pointer", lang === i18n.locale && "bg-accent/70 font-medium")}
|
||||
onClick={() => dynamicActivate(lang)}
|
||||
>
|
||||
<span>
|
||||
{e || <code className="font-mono bg-muted text-[.65em] w-5 h-4 grid place-items-center">{lang}</code>}
|
||||
</span>{" "}
|
||||
{label}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</Tooltip>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export function ModeToggle() {
|
||||
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant={"ghost"}
|
||||
size="icon"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import { getPagePath } from "@nanostores/router"
|
||||
import {
|
||||
@@ -6,6 +7,8 @@ import {
|
||||
HardDriveIcon,
|
||||
LogOutIcon,
|
||||
LogsIcon,
|
||||
MenuIcon,
|
||||
PlusIcon,
|
||||
SearchIcon,
|
||||
ServerIcon,
|
||||
SettingsIcon,
|
||||
@@ -21,15 +24,18 @@ import {
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
import { isAdmin, isReadOnlyUser, logOut, pb } from "@/lib/api"
|
||||
import { cn, runOnce } from "@/lib/utils"
|
||||
import { AddSystemButton } from "./add-system"
|
||||
import { AddSystemDialog } from "./add-system"
|
||||
import { LangToggle } from "./lang-toggle"
|
||||
import { Logo } from "./logo"
|
||||
import { ModeToggle } from "./mode-toggle"
|
||||
import { $router, basePath, Link, prependBasePath } from "./router"
|
||||
import { $router, basePath, Link, navigate, prependBasePath } from "./router"
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"
|
||||
|
||||
const CommandPalette = lazy(() => import("./command-palette"))
|
||||
@@ -37,8 +43,20 @@ const CommandPalette = lazy(() => import("./command-palette"))
|
||||
const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0
|
||||
|
||||
export default function Navbar() {
|
||||
const [addSystemDialogOpen, setAddSystemDialogOpen] = useState(false)
|
||||
const [commandPaletteOpen, setCommandPaletteOpen] = useState(false)
|
||||
|
||||
const AdminLinks = AdminDropdownGroup()
|
||||
|
||||
const systemTranslation = t`System`
|
||||
|
||||
return (
|
||||
<div className="flex items-center h-14 md:h-16 bg-card px-4 pe-3 sm:px-6 border border-border/60 bt-0 rounded-md my-4">
|
||||
<Suspense>
|
||||
<CommandPalette open={commandPaletteOpen} setOpen={setCommandPaletteOpen} />
|
||||
</Suspense>
|
||||
<AddSystemDialog open={addSystemDialogOpen} setOpen={setAddSystemDialogOpen} />
|
||||
|
||||
<Link
|
||||
href={basePath}
|
||||
aria-label="Home"
|
||||
@@ -47,10 +65,93 @@ export default function Navbar() {
|
||||
>
|
||||
<Logo className="h-[1.1rem] md:h-5 fill-foreground" />
|
||||
</Link>
|
||||
<SearchButton />
|
||||
<Button
|
||||
variant="outline"
|
||||
className="hidden md:block text-sm text-muted-foreground px-4"
|
||||
onClick={() => setCommandPaletteOpen(true)}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<SearchIcon className="me-1.5 h-4 w-4" />
|
||||
<Trans>Search</Trans>
|
||||
<span className="flex items-center ms-3.5">
|
||||
<Kbd>{isMac ? "⌘" : "Ctrl"}</Kbd>
|
||||
<Kbd>K</Kbd>
|
||||
</span>
|
||||
</span>
|
||||
</Button>
|
||||
|
||||
{/* mobile menu */}
|
||||
<div className="ms-auto flex items-center text-xl md:hidden">
|
||||
<ModeToggle />
|
||||
<Button variant="ghost" size="icon" onClick={() => setCommandPaletteOpen(true)}>
|
||||
<SearchIcon className="h-[1.2rem] w-[1.2rem]" />
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
onMouseEnter={() => import("@/components/routes/settings/general")}
|
||||
className="ms-3"
|
||||
aria-label="Open Menu"
|
||||
>
|
||||
<MenuIcon />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuLabel className="max-w-40 truncate">{pb.authStore.record?.email}</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
onClick={() => navigate(getPagePath($router, "containers"))}
|
||||
className="flex items-center"
|
||||
>
|
||||
<ContainerIcon className="h-4 w-4 me-2.5" strokeWidth={1.5} />
|
||||
<Trans>All Containers</Trans>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => navigate(getPagePath($router, "smart"))} className="flex items-center">
|
||||
<HardDriveIcon className="h-4 w-4 me-2.5" strokeWidth={1.5} />
|
||||
<span>S.M.A.R.T.</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => navigate(getPagePath($router, "settings", { name: "general" }))}
|
||||
className="flex items-center"
|
||||
>
|
||||
<SettingsIcon className="h-4 w-4 me-2.5" />
|
||||
<Trans>Settings</Trans>
|
||||
</DropdownMenuItem>
|
||||
{isAdmin() && (
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<UserIcon className="h-4 w-4 me-2.5" />
|
||||
<Trans>Admin</Trans>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent>{AdminLinks}</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
)}
|
||||
<DropdownMenuItem
|
||||
className="flex items-center"
|
||||
onSelect={() => {
|
||||
setAddSystemDialogOpen(true)
|
||||
}}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4 me-2.5" />
|
||||
<Trans>Add {{ foo: systemTranslation }}</Trans>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem onSelect={logOut} className="flex items-center">
|
||||
<LogOutIcon className="h-4 w-4 me-2.5" />
|
||||
<Trans>Log Out</Trans>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
{/* desktop nav */}
|
||||
{/** biome-ignore lint/a11y/noStaticElementInteractions: ignore */}
|
||||
<div className="flex items-center ms-auto" onMouseEnter={() => import("@/components/routes/settings/general")}>
|
||||
<div
|
||||
className="hidden md:flex items-center ms-auto"
|
||||
onMouseEnter={() => import("@/components/routes/settings/general")}
|
||||
>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Link
|
||||
@@ -102,45 +203,12 @@ export default function Navbar() {
|
||||
<DropdownMenuContent align={isReadOnlyUser() ? "end" : "center"} className="min-w-44">
|
||||
<DropdownMenuLabel>{pb.authStore.record?.email}</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
{isAdmin() && (
|
||||
<>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href={prependBasePath("/_/")} target="_blank">
|
||||
<UsersIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Users</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href={prependBasePath("/_/#/collections?collection=systems")} target="_blank">
|
||||
<ServerIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Systems</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href={prependBasePath("/_/#/logs")} target="_blank">
|
||||
<LogsIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Logs</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href={prependBasePath("/_/#/settings/backups")} target="_blank">
|
||||
<DatabaseBackupIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Backups</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuGroup>
|
||||
{isAdmin() && (
|
||||
<>
|
||||
{AdminLinks}
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
<DropdownMenuItem onSelect={logOut}>
|
||||
<LogOutIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
@@ -149,7 +217,10 @@ export default function Navbar() {
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<AddSystemButton className="ms-2" />
|
||||
<Button variant="outline" className="flex gap-1 ms-2" onClick={() => setAddSystemDialogOpen(true)}>
|
||||
<PlusIcon className="h-4 w-4 -ms-1" />
|
||||
<Trans>Add {{ foo: systemTranslation }}</Trans>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -161,28 +232,41 @@ const Kbd = ({ children }: { children: React.ReactNode }) => (
|
||||
</kbd>
|
||||
)
|
||||
|
||||
function SearchButton() {
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
function AdminDropdownGroup() {
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="hidden md:block text-sm text-muted-foreground px-4"
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<SearchIcon className="me-1.5 h-4 w-4" />
|
||||
<Trans>Search</Trans>
|
||||
<span className="flex items-center ms-3.5">
|
||||
<Kbd>{isMac ? "⌘" : "Ctrl"}</Kbd>
|
||||
<Kbd>K</Kbd>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href={prependBasePath("/_/")} target="_blank">
|
||||
<UsersIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Users</Trans>
|
||||
</span>
|
||||
</span>
|
||||
</Button>
|
||||
<Suspense>
|
||||
<CommandPalette open={open} setOpen={setOpen} />
|
||||
</Suspense>
|
||||
</>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href={prependBasePath("/_/#/collections?collection=systems")} target="_blank">
|
||||
<ServerIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Systems</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href={prependBasePath("/_/#/logs")} target="_blank">
|
||||
<LogsIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Logs</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href={prependBasePath("/_/#/settings/backups")} target="_blank">
|
||||
<DatabaseBackupIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Backups</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -134,10 +134,10 @@ export function QuietHours() {
|
||||
const startMinutes = startDate.getUTCHours() * 60 + startDate.getUTCMinutes()
|
||||
const endMinutes = endDate.getUTCHours() * 60 + endDate.getUTCMinutes()
|
||||
|
||||
// Convert UTC to local time offset
|
||||
const offset = now.getTimezoneOffset()
|
||||
const localStartMinutes = (startMinutes - offset + 1440) % 1440
|
||||
const localEndMinutes = (endMinutes - offset + 1440) % 1440
|
||||
// Convert UTC to local time using the stored date's offset, not the current date's offset
|
||||
// This avoids DST mismatch when records were saved in a different DST period
|
||||
const localStartMinutes = (startMinutes - startDate.getTimezoneOffset() + 1440) % 1440
|
||||
const localEndMinutes = (endMinutes - endDate.getTimezoneOffset() + 1440) % 1440
|
||||
|
||||
// Handle cases where window spans midnight
|
||||
if (localStartMinutes <= localEndMinutes) {
|
||||
@@ -347,12 +347,13 @@ function QuietHoursDialog({
|
||||
|
||||
if (windowType === "daily") {
|
||||
// For daily windows, convert local time to UTC
|
||||
// Create a date with the time in local timezone, then convert to UTC
|
||||
const startDate = new Date(`2000-01-01T${startTime}:00`)
|
||||
// Use today's date so the current DST offset is applied (not a fixed historical date)
|
||||
const today = new Date().toISOString().split("T")[0]
|
||||
const startDate = new Date(`${today}T${startTime}:00`)
|
||||
startValue = startDate.toISOString()
|
||||
|
||||
if (endTime) {
|
||||
const endDate = new Date(`2000-01-01T${endTime}:00`)
|
||||
const endDate = new Date(`${today}T${endTime}:00`)
|
||||
endValue = endDate.toISOString()
|
||||
}
|
||||
} else {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
133
internal/site/src/components/routes/system/chart-card.tsx
Normal file
133
internal/site/src/components/routes/system/chart-card.tsx
Normal file
@@ -0,0 +1,133 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { Trans, useLingui } from "@lingui/react/macro"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { XIcon } from "lucide-react"
|
||||
import React, { type JSX, memo, useCallback, useEffect, useState } from "react"
|
||||
import { $containerFilter, $maxValues } from "@/lib/stores"
|
||||
import { useIntersectionObserver } from "@/lib/use-intersection-observer"
|
||||
import { cn } from "@/lib/utils"
|
||||
import Spinner from "../../spinner"
|
||||
import { Button } from "../../ui/button"
|
||||
import { Card, CardDescription, CardHeader, CardTitle } from "../../ui/card"
|
||||
import { ChartAverage, ChartMax } from "../../ui/icons"
|
||||
import { Input } from "../../ui/input"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/select"
|
||||
|
||||
export function FilterBar({ store = $containerFilter }: { store?: typeof $containerFilter }) {
|
||||
const storeValue = useStore(store)
|
||||
const [inputValue, setInputValue] = useState(storeValue)
|
||||
const { t } = useLingui()
|
||||
|
||||
useEffect(() => {
|
||||
setInputValue(storeValue)
|
||||
}, [storeValue])
|
||||
|
||||
useEffect(() => {
|
||||
if (inputValue === storeValue) {
|
||||
return
|
||||
}
|
||||
const handle = window.setTimeout(() => store.set(inputValue), 80)
|
||||
return () => clearTimeout(handle)
|
||||
}, [inputValue, storeValue, store])
|
||||
|
||||
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value
|
||||
setInputValue(value)
|
||||
}, [])
|
||||
|
||||
const handleClear = useCallback(() => {
|
||||
setInputValue("")
|
||||
store.set("")
|
||||
}, [store])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
placeholder={t`Filter...`}
|
||||
className="ps-4 pe-8 w-full sm:w-44"
|
||||
onChange={handleChange}
|
||||
value={inputValue}
|
||||
/>
|
||||
{inputValue && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
aria-label="Clear"
|
||||
className="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7 text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100"
|
||||
onClick={handleClear}
|
||||
>
|
||||
<XIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const SelectAvgMax = memo(({ max }: { max: boolean }) => {
|
||||
const Icon = max ? ChartMax : ChartAverage
|
||||
return (
|
||||
<Select value={max ? "max" : "avg"} onValueChange={(e) => $maxValues.set(e === "max")}>
|
||||
<SelectTrigger className="relative ps-10 pe-5 w-full sm:w-44">
|
||||
<Icon className="h-4 w-4 absolute start-4 top-1/2 -translate-y-1/2 opacity-85" />
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem key="avg" value="avg">
|
||||
<Trans>Average</Trans>
|
||||
</SelectItem>
|
||||
<SelectItem key="max" value="max">
|
||||
<Trans comment="Chart select field. Please try to keep this short.">Max 1 min</Trans>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)
|
||||
})
|
||||
|
||||
export function ChartCard({
|
||||
title,
|
||||
description,
|
||||
children,
|
||||
grid,
|
||||
empty,
|
||||
cornerEl,
|
||||
legend,
|
||||
className,
|
||||
}: {
|
||||
title: string
|
||||
description: string
|
||||
children: React.ReactNode
|
||||
grid?: boolean
|
||||
empty?: boolean
|
||||
cornerEl?: JSX.Element | null
|
||||
legend?: boolean
|
||||
className?: string
|
||||
}) {
|
||||
const { isIntersecting, ref } = useIntersectionObserver()
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={cn(
|
||||
"px-3 py-5 sm:py-6 sm:px-6 odd:last-of-type:col-span-full min-h-full",
|
||||
{ "col-span-full": !grid },
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
>
|
||||
<CardHeader className="gap-1.5 relative p-0 mb-3 sm:mb-4">
|
||||
<CardTitle>{title}</CardTitle>
|
||||
<CardDescription>{description}</CardDescription>
|
||||
{cornerEl && <div className="grid sm:justify-end sm:absolute sm:top-0 sm:end-0 my-1 sm:my-0">{cornerEl}</div>}
|
||||
</CardHeader>
|
||||
<div className={cn("ps-0 -me-1 -ms-3.5 relative group", legend ? "h-54 md:h-56" : "h-48 md:h-52")}>
|
||||
{
|
||||
<Spinner
|
||||
msg={empty ? t`Waiting for enough records to display` : undefined}
|
||||
className="group-has-[.opacity-100]:invisible duration-100"
|
||||
/>
|
||||
}
|
||||
{isIntersecting && children}
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
116
internal/site/src/components/routes/system/chart-data.ts
Normal file
116
internal/site/src/components/routes/system/chart-data.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { timeTicks } from "d3-time"
|
||||
import { getPbTimestamp, pb } from "@/lib/api"
|
||||
import { chartTimeData } from "@/lib/utils"
|
||||
import type { ChartData, ChartTimes, ContainerStatsRecord, SystemStatsRecord } from "@/types"
|
||||
|
||||
type ChartTimeData = {
|
||||
time: number
|
||||
data: {
|
||||
ticks: number[]
|
||||
domain: number[]
|
||||
}
|
||||
chartTime: ChartTimes
|
||||
}
|
||||
|
||||
export const cache = new Map<
|
||||
string,
|
||||
ChartTimeData | SystemStatsRecord[] | ContainerStatsRecord[] | ChartData["containerData"]
|
||||
>()
|
||||
|
||||
// create ticks and domain for charts
|
||||
export function getTimeData(chartTime: ChartTimes, lastCreated: number) {
|
||||
const cached = cache.get("td") as ChartTimeData | undefined
|
||||
if (cached && cached.chartTime === chartTime) {
|
||||
if (!lastCreated || cached.time >= lastCreated) {
|
||||
return cached.data
|
||||
}
|
||||
}
|
||||
|
||||
// const buffer = chartTime === "1m" ? 400 : 20_000
|
||||
const now = new Date(Date.now())
|
||||
const startTime = chartTimeData[chartTime].getOffset(now)
|
||||
const ticks = timeTicks(startTime, now, chartTimeData[chartTime].ticks ?? 12).map((date) => date.getTime())
|
||||
const data = {
|
||||
ticks,
|
||||
domain: [chartTimeData[chartTime].getOffset(now).getTime(), now.getTime()],
|
||||
}
|
||||
cache.set("td", { time: now.getTime(), data, chartTime })
|
||||
return data
|
||||
}
|
||||
|
||||
/** Append new records onto prev with gap detection. Converts string `created` values to ms timestamps in place.
|
||||
* Pass `maxLen` to cap the result length in one copy instead of slicing again after the call. */
|
||||
export function appendData<T extends { created: string | number | null }>(
|
||||
prev: T[],
|
||||
newRecords: T[],
|
||||
expectedInterval: number,
|
||||
maxLen?: number
|
||||
): T[] {
|
||||
if (!newRecords.length) return prev
|
||||
// Pre-trim prev so the single slice() below is the only copy we make
|
||||
const trimmed = maxLen && prev.length >= maxLen ? prev.slice(-(maxLen - newRecords.length)) : prev
|
||||
const result = trimmed.slice()
|
||||
let prevTime = (trimmed.at(-1)?.created as number) ?? 0
|
||||
for (const record of newRecords) {
|
||||
if (record.created !== null) {
|
||||
if (typeof record.created === "string") {
|
||||
record.created = new Date(record.created).getTime()
|
||||
}
|
||||
if (prevTime && (record.created as number) - prevTime > expectedInterval * 1.5) {
|
||||
result.push({ created: null, ...("stats" in record ? { stats: null } : {}) } as T)
|
||||
}
|
||||
prevTime = record.created as number
|
||||
}
|
||||
result.push(record)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export async function getStats<T extends SystemStatsRecord | ContainerStatsRecord>(
|
||||
collection: string,
|
||||
systemId: string,
|
||||
chartTime: ChartTimes
|
||||
): Promise<T[]> {
|
||||
const cachedStats = cache.get(`${systemId}_${chartTime}_${collection}`) as T[] | undefined
|
||||
const lastCached = cachedStats?.at(-1)?.created as number
|
||||
return await pb.collection<T>(collection).getFullList({
|
||||
filter: pb.filter("system={:id} && created > {:created} && type={:type}", {
|
||||
id: systemId,
|
||||
created: getPbTimestamp(chartTime, lastCached ? new Date(lastCached + 1000) : undefined),
|
||||
type: chartTimeData[chartTime].type,
|
||||
}),
|
||||
fields: "created,stats",
|
||||
sort: "created",
|
||||
})
|
||||
}
|
||||
|
||||
export function makeContainerData(containers: ContainerStatsRecord[]): ChartData["containerData"] {
|
||||
const result = [] as ChartData["containerData"]
|
||||
for (const { created, stats } of containers) {
|
||||
if (!created) {
|
||||
result.push({ created: null } as ChartData["containerData"][0])
|
||||
continue
|
||||
}
|
||||
result.push(makeContainerPoint(new Date(created).getTime(), stats))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/** Transform a single realtime container stats message into a ChartDataContainer point. */
|
||||
export function makeContainerPoint(
|
||||
created: number,
|
||||
stats: ContainerStatsRecord["stats"]
|
||||
): ChartData["containerData"][0] {
|
||||
const point: ChartData["containerData"][0] = { created } as ChartData["containerData"][0]
|
||||
for (const container of stats) {
|
||||
;(point as Record<string, unknown>)[container.n] = container
|
||||
}
|
||||
return point
|
||||
}
|
||||
|
||||
export function dockerOrPodman(str: string, isPodman: boolean): string {
|
||||
if (isPodman) {
|
||||
return str.replace("docker", "podman").replace("Docker", "Podman")
|
||||
}
|
||||
return str
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import AreaChartDefault from "@/components/charts/area-chart"
|
||||
import { useContainerDataPoints } from "@/components/charts/hooks"
|
||||
import { decimalString, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartConfig } from "@/components/ui/chart"
|
||||
import type { ChartData } from "@/types"
|
||||
import { pinnedAxisDomain } from "@/components/ui/chart"
|
||||
import CpuCoresSheet from "../cpu-sheet"
|
||||
import { ChartCard, FilterBar, SelectAvgMax } from "../chart-card"
|
||||
import { dockerOrPodman } from "../chart-data"
|
||||
|
||||
export function CpuChart({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
showMax,
|
||||
isLongerChart,
|
||||
maxValues,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
showMax: boolean
|
||||
isLongerChart: boolean
|
||||
maxValues: boolean
|
||||
}) {
|
||||
const maxValSelect = isLongerChart ? <SelectAvgMax max={maxValues} /> : null
|
||||
|
||||
return (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`CPU Usage`}
|
||||
description={t`Average system-wide CPU utilization`}
|
||||
cornerEl={
|
||||
<div className="flex gap-2">
|
||||
{maxValSelect}
|
||||
<CpuCoresSheet chartData={chartData} dataEmpty={dataEmpty} grid={grid} maxValues={maxValues} />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
maxToggled={showMax}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t`CPU Usage`,
|
||||
dataKey: ({ stats }) => (showMax ? stats?.cpum : stats?.cpu),
|
||||
color: 1,
|
||||
opacity: 0.4,
|
||||
},
|
||||
]}
|
||||
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
||||
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
||||
domain={pinnedAxisDomain()}
|
||||
/>
|
||||
</ChartCard>
|
||||
)
|
||||
}
|
||||
|
||||
export function ContainerCpuChart({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
isPodman,
|
||||
cpuConfig,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
isPodman: boolean
|
||||
cpuConfig: ChartConfig
|
||||
}) {
|
||||
const { filter, dataPoints } = useContainerDataPoints(cpuConfig, (key, data) => data[key]?.c ?? null)
|
||||
|
||||
return (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={dockerOrPodman(t`Docker CPU Usage`, isPodman)}
|
||||
description={t`Average CPU utilization of containers`}
|
||||
cornerEl={<FilterBar />}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
customData={chartData.containerData}
|
||||
dataPoints={dataPoints}
|
||||
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
||||
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
||||
domain={pinnedAxisDomain()}
|
||||
showTotal={true}
|
||||
reverseStackOrder={true}
|
||||
filter={filter}
|
||||
truncate={true}
|
||||
itemSorter={(a, b) => b.value - a.value}
|
||||
/>
|
||||
</ChartCard>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import AreaChartDefault from "@/components/charts/area-chart"
|
||||
import { $userSettings } from "@/lib/stores"
|
||||
import { decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData, SystemStatsRecord } from "@/types"
|
||||
import { ChartCard, SelectAvgMax } from "../chart-card"
|
||||
import { Unit } from "@/lib/enums"
|
||||
|
||||
export function DiskCharts({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
showMax,
|
||||
isLongerChart,
|
||||
maxValues,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
showMax: boolean
|
||||
isLongerChart: boolean
|
||||
maxValues: boolean
|
||||
systemStats: SystemStatsRecord[]
|
||||
}) {
|
||||
const maxValSelect = isLongerChart ? <SelectAvgMax max={maxValues} /> : null
|
||||
const userSettings = $userSettings.get()
|
||||
|
||||
let diskSize = chartData.systemStats?.at(-1)?.stats.d ?? NaN
|
||||
// round to nearest GB
|
||||
if (diskSize >= 100) {
|
||||
diskSize = Math.round(diskSize)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ChartCard empty={dataEmpty} grid={grid} title={t`Disk Usage`} description={t`Usage of root partition`}>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
domain={[0, diskSize]}
|
||||
tickFormatter={(val) => {
|
||||
const { value, unit } = formatBytes(val * 1024, false, Unit.Bytes, true)
|
||||
return `${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}`
|
||||
}}
|
||||
contentFormatter={({ value }) => {
|
||||
const { value: convertedValue, unit } = formatBytes(value * 1024, false, Unit.Bytes, true)
|
||||
return `${decimalString(convertedValue)} ${unit}`
|
||||
}}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t`Disk Usage`,
|
||||
color: 4,
|
||||
opacity: 0.4,
|
||||
dataKey: ({ stats }) => stats?.du,
|
||||
},
|
||||
]}
|
||||
></AreaChartDefault>
|
||||
</ChartCard>
|
||||
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`Disk I/O`}
|
||||
description={t`Throughput of root filesystem`}
|
||||
cornerEl={maxValSelect}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
maxToggled={showMax}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t({ message: "Write", comment: "Disk write" }),
|
||||
dataKey: ({ stats }: SystemStatsRecord) => {
|
||||
if (showMax) {
|
||||
return stats?.dio?.[1] ?? (stats?.dwm ?? 0) * 1024 * 1024
|
||||
}
|
||||
return stats?.dio?.[1] ?? (stats?.dw ?? 0) * 1024 * 1024
|
||||
},
|
||||
color: 3,
|
||||
opacity: 0.3,
|
||||
},
|
||||
{
|
||||
label: t({ message: "Read", comment: "Disk read" }),
|
||||
dataKey: ({ stats }: SystemStatsRecord) => {
|
||||
if (showMax) {
|
||||
return stats?.diom?.[0] ?? (stats?.drm ?? 0) * 1024 * 1024
|
||||
}
|
||||
return stats?.dio?.[0] ?? (stats?.dr ?? 0) * 1024 * 1024
|
||||
},
|
||||
color: 1,
|
||||
opacity: 0.3,
|
||||
},
|
||||
]}
|
||||
tickFormatter={(val) => {
|
||||
const { value, unit } = formatBytes(val, true, userSettings.unitDisk, false)
|
||||
return `${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}`
|
||||
}}
|
||||
contentFormatter={({ value }) => {
|
||||
const { value: convertedValue, unit } = formatBytes(value, true, userSettings.unitDisk, false)
|
||||
return `${decimalString(convertedValue, convertedValue >= 100 ? 1 : 2)} ${unit}`
|
||||
}}
|
||||
showTotal={true}
|
||||
/>
|
||||
</ChartCard>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import AreaChartDefault from "@/components/charts/area-chart"
|
||||
import { $userSettings } from "@/lib/stores"
|
||||
import { decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData, SystemStatsRecord } from "@/types"
|
||||
import { ChartCard, SelectAvgMax } from "../chart-card"
|
||||
import { Unit } from "@/lib/enums"
|
||||
|
||||
export function ExtraFsCharts({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
showMax,
|
||||
isLongerChart,
|
||||
maxValues,
|
||||
systemStats,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
showMax: boolean
|
||||
isLongerChart: boolean
|
||||
maxValues: boolean
|
||||
systemStats: SystemStatsRecord[]
|
||||
}) {
|
||||
const maxValSelect = isLongerChart ? <SelectAvgMax max={maxValues} /> : null
|
||||
const userSettings = $userSettings.get()
|
||||
const extraFs = systemStats.at(-1)?.stats.efs
|
||||
if (!extraFs || Object.keys(extraFs).length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid xl:grid-cols-2 gap-4">
|
||||
{Object.keys(extraFs).map((extraFsName) => {
|
||||
let diskSize = systemStats.at(-1)?.stats.efs?.[extraFsName].d ?? NaN
|
||||
// round to nearest GB
|
||||
if (diskSize >= 100) {
|
||||
diskSize = Math.round(diskSize)
|
||||
}
|
||||
return (
|
||||
<div key={extraFsName} className="contents">
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={`${extraFsName} ${t`Usage`}`}
|
||||
description={t`Disk usage of ${extraFsName}`}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
domain={[0, diskSize]}
|
||||
tickFormatter={(val) => {
|
||||
const { value, unit } = formatBytes(val * 1024, false, Unit.Bytes, true)
|
||||
return `${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}`
|
||||
}}
|
||||
contentFormatter={({ value }) => {
|
||||
const { value: convertedValue, unit } = formatBytes(value * 1024, false, Unit.Bytes, true)
|
||||
return `${decimalString(convertedValue)} ${unit}`
|
||||
}}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t`Disk Usage`,
|
||||
color: 4,
|
||||
opacity: 0.4,
|
||||
dataKey: ({ stats }) => stats?.efs?.[extraFsName]?.du,
|
||||
},
|
||||
]}
|
||||
></AreaChartDefault>
|
||||
</ChartCard>
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={`${extraFsName} I/O`}
|
||||
description={t`Throughput of ${extraFsName}`}
|
||||
cornerEl={maxValSelect}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
showTotal={true}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t`Write`,
|
||||
dataKey: ({ stats }) => {
|
||||
if (showMax) {
|
||||
return stats?.efs?.[extraFsName]?.wbm || (stats?.efs?.[extraFsName]?.wm ?? 0) * 1024 * 1024
|
||||
}
|
||||
return stats?.efs?.[extraFsName]?.wb || (stats?.efs?.[extraFsName]?.w ?? 0) * 1024 * 1024
|
||||
},
|
||||
color: 3,
|
||||
opacity: 0.3,
|
||||
},
|
||||
{
|
||||
label: t`Read`,
|
||||
dataKey: ({ stats }) => {
|
||||
if (showMax) {
|
||||
return stats?.efs?.[extraFsName]?.rbm ?? (stats?.efs?.[extraFsName]?.rm ?? 0) * 1024 * 1024
|
||||
}
|
||||
return stats?.efs?.[extraFsName]?.rb ?? (stats?.efs?.[extraFsName]?.r ?? 0) * 1024 * 1024
|
||||
},
|
||||
color: 1,
|
||||
opacity: 0.3,
|
||||
},
|
||||
]}
|
||||
maxToggled={showMax}
|
||||
tickFormatter={(val) => {
|
||||
const { value, unit } = formatBytes(val, true, userSettings.unitDisk, false)
|
||||
return `${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}`
|
||||
}}
|
||||
contentFormatter={({ value }) => {
|
||||
const { value: convertedValue, unit } = formatBytes(value, true, userSettings.unitDisk, false)
|
||||
return `${decimalString(convertedValue, convertedValue >= 100 ? 1 : 2)} ${unit}`
|
||||
}}
|
||||
/>
|
||||
</ChartCard>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
232
internal/site/src/components/routes/system/charts/gpu-charts.tsx
Normal file
232
internal/site/src/components/routes/system/charts/gpu-charts.tsx
Normal file
@@ -0,0 +1,232 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { useRef, useMemo } from "react"
|
||||
import AreaChartDefault, { type DataPoint } from "@/components/charts/area-chart"
|
||||
import LineChartDefault from "@/components/charts/line-chart"
|
||||
import { Unit } from "@/lib/enums"
|
||||
import { cn, decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData, GPUData, SystemStatsRecord } from "@/types"
|
||||
import { ChartCard } from "../chart-card"
|
||||
|
||||
/** GPU power draw chart for the main grid */
|
||||
export function GpuPowerChart({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
}) {
|
||||
const packageKey = " package"
|
||||
const statsRef = useRef(chartData.systemStats)
|
||||
statsRef.current = chartData.systemStats
|
||||
|
||||
// Derive GPU power config key (cheap per render)
|
||||
let gpuPowerKey = ""
|
||||
for (let i = chartData.systemStats.length - 1; i >= 0; i--) {
|
||||
const gpus = chartData.systemStats[i].stats?.g
|
||||
if (gpus) {
|
||||
const parts: string[] = []
|
||||
for (const id in gpus) {
|
||||
const gpu = gpus[id] as GPUData
|
||||
if (gpu.p !== undefined) parts.push(`${id}:${gpu.n}`)
|
||||
if (gpu.pp !== undefined) parts.push(`${id}:${gpu.n}${packageKey}`)
|
||||
}
|
||||
gpuPowerKey = parts.sort().join("\0")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const dataPoints = useMemo((): DataPoint[] => {
|
||||
if (!gpuPowerKey) return []
|
||||
const totals = new Map<string, { label: string; gpuId: string; isPackage: boolean; total: number }>()
|
||||
for (const record of statsRef.current) {
|
||||
const gpus = record.stats?.g
|
||||
if (!gpus) continue
|
||||
for (const id in gpus) {
|
||||
const gpu = gpus[id] as GPUData
|
||||
const key = gpu.n
|
||||
const existing = totals.get(key)
|
||||
if (existing) {
|
||||
existing.total += gpu.p ?? 0
|
||||
} else {
|
||||
totals.set(key, { label: gpu.n, gpuId: id, isPackage: false, total: gpu.p ?? 0 })
|
||||
}
|
||||
if (gpu.pp !== undefined) {
|
||||
const pkgKey = `${gpu.n}${packageKey}`
|
||||
const existingPkg = totals.get(pkgKey)
|
||||
if (existingPkg) {
|
||||
existingPkg.total += gpu.pp
|
||||
} else {
|
||||
totals.set(pkgKey, { label: pkgKey, gpuId: id, isPackage: true, total: gpu.pp })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const sorted = Array.from(totals.values()).sort((a, b) => b.total - a.total)
|
||||
return sorted.map(
|
||||
(entry, i): DataPoint => ({
|
||||
label: entry.label,
|
||||
dataKey: (data: SystemStatsRecord) => {
|
||||
const gpu = data.stats?.g?.[entry.gpuId]
|
||||
return entry.isPackage ? (gpu?.pp ?? 0) : (gpu?.p ?? 0)
|
||||
},
|
||||
color: `hsl(${226 + (((i * 360) / sorted.length) % 360)}, 65%, 52%)`,
|
||||
opacity: 1,
|
||||
})
|
||||
)
|
||||
}, [gpuPowerKey])
|
||||
|
||||
return (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`GPU Power Draw`}
|
||||
description={t`Average power consumption of GPUs`}
|
||||
>
|
||||
<LineChartDefault
|
||||
legend={dataPoints.length > 1}
|
||||
chartData={chartData}
|
||||
dataPoints={dataPoints}
|
||||
itemSorter={(a: { value: number }, b: { value: number }) => b.value - a.value}
|
||||
tickFormatter={(val) => `${toFixedFloat(val, 2)}W`}
|
||||
contentFormatter={({ value }) => `${decimalString(value)}W`}
|
||||
/>
|
||||
</ChartCard>
|
||||
)
|
||||
}
|
||||
|
||||
/** GPU detail grid (engines + per-GPU usage/VRAM) — rendered outside the main 2-col grid */
|
||||
export function GpuDetailCharts({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
lastGpus,
|
||||
hasGpuEnginesData,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
lastGpus: Record<string, GPUData>
|
||||
hasGpuEnginesData: boolean
|
||||
}) {
|
||||
return (
|
||||
<div className="grid xl:grid-cols-2 gap-4">
|
||||
{hasGpuEnginesData && (
|
||||
<ChartCard
|
||||
legend={true}
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`GPU Engines`}
|
||||
description={t`Average utilization of GPU engines`}
|
||||
>
|
||||
<GpuEnginesChart chartData={chartData} />
|
||||
</ChartCard>
|
||||
)}
|
||||
{Object.keys(lastGpus).map((id) => {
|
||||
const gpu = lastGpus[id] as GPUData
|
||||
return (
|
||||
<div key={id} className="contents">
|
||||
<ChartCard
|
||||
className={cn(grid && "!col-span-1")}
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={`${gpu.n} ${t`Usage`}`}
|
||||
description={t`Average utilization of ${gpu.n}`}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t`Usage`,
|
||||
dataKey: ({ stats }) => stats?.g?.[id]?.u ?? 0,
|
||||
color: 1,
|
||||
opacity: 0.35,
|
||||
},
|
||||
]}
|
||||
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
||||
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
||||
/>
|
||||
</ChartCard>
|
||||
|
||||
{(gpu.mt ?? 0) > 0 && (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={`${gpu.n} VRAM`}
|
||||
description={t`Precise utilization at the recorded time`}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t`Usage`,
|
||||
dataKey: ({ stats }) => stats?.g?.[id]?.mu ?? 0,
|
||||
color: 2,
|
||||
opacity: 0.25,
|
||||
},
|
||||
]}
|
||||
max={gpu.mt}
|
||||
tickFormatter={(val) => {
|
||||
const { value, unit } = formatBytes(val, false, Unit.Bytes, true)
|
||||
return `${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}`
|
||||
}}
|
||||
contentFormatter={({ value }) => {
|
||||
const { value: convertedValue, unit } = formatBytes(value, false, Unit.Bytes, true)
|
||||
return `${decimalString(convertedValue)} ${unit}`
|
||||
}}
|
||||
/>
|
||||
</ChartCard>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function GpuEnginesChart({ chartData }: { chartData: ChartData }) {
|
||||
// Derive stable engine config key (cheap per render)
|
||||
let enginesKey = ""
|
||||
for (let i = chartData.systemStats.length - 1; i >= 0; i--) {
|
||||
const gpus = chartData.systemStats[i].stats?.g
|
||||
if (!gpus) continue
|
||||
for (const id in gpus) {
|
||||
if (gpus[id].e) {
|
||||
enginesKey = id + "\0" + Object.keys(gpus[id].e).sort().join("\0")
|
||||
break
|
||||
}
|
||||
}
|
||||
if (enginesKey) break
|
||||
}
|
||||
|
||||
const { gpuId, dataPoints } = useMemo((): { gpuId: string | null; dataPoints: DataPoint[] } => {
|
||||
if (!enginesKey) return { gpuId: null, dataPoints: [] }
|
||||
const parts = enginesKey.split("\0")
|
||||
const gId = parts[0]
|
||||
const engineNames = parts.slice(1)
|
||||
return {
|
||||
gpuId: gId,
|
||||
dataPoints: engineNames.map((engine, i) => ({
|
||||
label: engine,
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.g?.[gId]?.e?.[engine] ?? 0,
|
||||
color: `hsl(${140 + (((i * 360) / engineNames.length) % 360)}, 65%, 52%)`,
|
||||
opacity: 0.35,
|
||||
})),
|
||||
}
|
||||
}, [enginesKey])
|
||||
|
||||
if (!gpuId) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<LineChartDefault
|
||||
legend={true}
|
||||
chartData={chartData}
|
||||
dataPoints={dataPoints}
|
||||
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
||||
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import type { ChartData } from "@/types"
|
||||
import { ChartCard } from "../chart-card"
|
||||
import LineChartDefault from "@/components/charts/line-chart"
|
||||
import { decimalString, toFixedFloat } from "@/lib/utils"
|
||||
|
||||
export function LoadAverageChart({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
}) {
|
||||
const { major, minor } = chartData.agentVersion
|
||||
if (major === 0 && minor <= 12) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`Load Average`}
|
||||
description={t`System load averages over time`}
|
||||
legend={true}
|
||||
>
|
||||
<LineChartDefault
|
||||
chartData={chartData}
|
||||
contentFormatter={(item) => decimalString(item.value)}
|
||||
tickFormatter={(value) => {
|
||||
return String(toFixedFloat(value, 2))
|
||||
}}
|
||||
legend={true}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t({ message: `1 min`, comment: "Load average" }),
|
||||
color: "hsl(271, 81%, 60%)", // Purple
|
||||
dataKey: ({ stats }) => stats?.la?.[0],
|
||||
},
|
||||
{
|
||||
label: t({ message: `5 min`, comment: "Load average" }),
|
||||
color: "hsl(217, 91%, 60%)", // Blue
|
||||
dataKey: ({ stats }) => stats?.la?.[1],
|
||||
},
|
||||
{
|
||||
label: t({ message: `15 min`, comment: "Load average" }),
|
||||
color: "hsl(25, 95%, 53%)", // Orange
|
||||
dataKey: ({ stats }) => stats?.la?.[2],
|
||||
},
|
||||
]}
|
||||
></LineChartDefault>
|
||||
</ChartCard>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import AreaChartDefault from "@/components/charts/area-chart"
|
||||
import { useContainerDataPoints } from "@/components/charts/hooks"
|
||||
import { Unit } from "@/lib/enums"
|
||||
import type { ChartConfig } from "@/components/ui/chart"
|
||||
import type { ChartData, SystemStatsRecord } from "@/types"
|
||||
import { ChartCard, FilterBar, SelectAvgMax } from "../chart-card"
|
||||
import { dockerOrPodman } from "../chart-data"
|
||||
import { decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
|
||||
import { pinnedAxisDomain } from "@/components/ui/chart"
|
||||
|
||||
export function MemoryChart({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
showMax,
|
||||
isLongerChart,
|
||||
maxValues,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
showMax: boolean
|
||||
isLongerChart: boolean
|
||||
maxValues: boolean
|
||||
}) {
|
||||
const maxValSelect = isLongerChart ? <SelectAvgMax max={maxValues} /> : null
|
||||
const totalMem = toFixedFloat(chartData.systemStats.at(-1)?.stats.m ?? 0, 1)
|
||||
|
||||
return (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`Memory Usage`}
|
||||
description={t`Precise utilization at the recorded time`}
|
||||
cornerEl={maxValSelect}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
domain={[0, totalMem]}
|
||||
itemSorter={(a, b) => a.order - b.order}
|
||||
maxToggled={showMax}
|
||||
showTotal={true}
|
||||
tickFormatter={(value) => {
|
||||
const { value: convertedValue, unit } = formatBytes(value * 1024, false, Unit.Bytes, true)
|
||||
return `${toFixedFloat(convertedValue, value >= 10 ? 0 : 1)} ${unit}`
|
||||
}}
|
||||
contentFormatter={({ value }) => {
|
||||
const { value: convertedValue, unit } = formatBytes(value * 1024, false, Unit.Bytes, true)
|
||||
return `${decimalString(convertedValue, convertedValue >= 100 ? 1 : 2)} ${unit}`
|
||||
}}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t`Used`,
|
||||
dataKey: ({ stats }) => (showMax ? stats?.mm : stats?.mu),
|
||||
color: 2,
|
||||
opacity: 0.4,
|
||||
stackId: "1",
|
||||
order: 3,
|
||||
},
|
||||
{
|
||||
label: "ZFS ARC",
|
||||
dataKey: ({ stats }) => (showMax ? null : stats?.mz),
|
||||
color: "hsla(175 60% 45% / 0.8)",
|
||||
opacity: 0.5,
|
||||
order: 2,
|
||||
},
|
||||
{
|
||||
label: t`Cache / Buffers`,
|
||||
dataKey: ({ stats }) => (showMax ? null : stats?.mb),
|
||||
color: "hsla(160 60% 45% / 0.5)",
|
||||
opacity: 0.4,
|
||||
stackId: "1",
|
||||
order: 1,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</ChartCard>
|
||||
)
|
||||
}
|
||||
|
||||
export function ContainerMemoryChart({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
isPodman,
|
||||
memoryConfig,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
isPodman: boolean
|
||||
memoryConfig: ChartConfig
|
||||
}) {
|
||||
const { filter, dataPoints } = useContainerDataPoints(memoryConfig, (key, data) => data[key]?.m ?? null)
|
||||
|
||||
return (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={dockerOrPodman(t`Docker Memory Usage`, isPodman)}
|
||||
description={dockerOrPodman(t`Memory usage of docker containers`, isPodman)}
|
||||
cornerEl={<FilterBar />}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
customData={chartData.containerData}
|
||||
dataPoints={dataPoints}
|
||||
tickFormatter={(val) => {
|
||||
const { value, unit } = formatBytes(val, false, Unit.Bytes, true)
|
||||
return `${toFixedFloat(value, val >= 10 ? 0 : 1)} ${unit}`
|
||||
}}
|
||||
contentFormatter={(item) => {
|
||||
const { value, unit } = formatBytes(item.value, false, Unit.Bytes, true)
|
||||
return `${decimalString(value)} ${unit}`
|
||||
}}
|
||||
domain={pinnedAxisDomain()}
|
||||
showTotal={true}
|
||||
reverseStackOrder={true}
|
||||
filter={filter}
|
||||
truncate={true}
|
||||
itemSorter={(a, b) => b.value - a.value}
|
||||
/>
|
||||
</ChartCard>
|
||||
)
|
||||
}
|
||||
|
||||
export function SwapChart({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
systemStats,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
systemStats: SystemStatsRecord[]
|
||||
}) {
|
||||
// const userSettings = useStore($userSettings)
|
||||
|
||||
const hasSwapData = (systemStats.at(-1)?.stats.su ?? 0) > 0
|
||||
if (!hasSwapData) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<ChartCard empty={dataEmpty} grid={grid} title={t`Swap Usage`} description={t`Swap space used by the system`}>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
domain={[0, () => toFixedFloat(chartData.systemStats.at(-1)?.stats.s ?? 0.04, 2)]}
|
||||
contentFormatter={({ value }) => {
|
||||
// mem values are supplied as GB
|
||||
const { value: convertedValue, unit } = formatBytes(value * 1024, false, Unit.Bytes, true)
|
||||
return `${decimalString(convertedValue, convertedValue >= 100 ? 1 : 2)} ${unit}`
|
||||
}}
|
||||
tickFormatter={(value) => {
|
||||
const { value: convertedValue, unit } = formatBytes(value * 1024, false, Unit.Bytes, true)
|
||||
return `${toFixedFloat(convertedValue, value >= 10 ? 0 : 1)} ${unit}`
|
||||
}}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t`Used`,
|
||||
dataKey: ({ stats }) => stats?.su,
|
||||
color: 2,
|
||||
opacity: 0.4,
|
||||
},
|
||||
]}
|
||||
></AreaChartDefault>
|
||||
</ChartCard>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
import { useMemo } from "react"
|
||||
import { t } from "@lingui/core/macro"
|
||||
import AreaChartDefault from "@/components/charts/area-chart"
|
||||
import { useContainerDataPoints } from "@/components/charts/hooks"
|
||||
import { $userSettings } from "@/lib/stores"
|
||||
import { decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartConfig } from "@/components/ui/chart"
|
||||
import { pinnedAxisDomain } from "@/components/ui/chart"
|
||||
import type { ChartData, SystemStatsRecord } from "@/types"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import NetworkSheet from "../network-sheet"
|
||||
import { ChartCard, FilterBar, SelectAvgMax } from "../chart-card"
|
||||
import { dockerOrPodman } from "../chart-data"
|
||||
|
||||
export function BandwidthChart({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
showMax,
|
||||
isLongerChart,
|
||||
maxValues,
|
||||
systemStats,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
showMax: boolean
|
||||
isLongerChart: boolean
|
||||
maxValues: boolean
|
||||
systemStats: SystemStatsRecord[]
|
||||
}) {
|
||||
const maxValSelect = isLongerChart ? <SelectAvgMax max={maxValues} /> : null
|
||||
const userSettings = $userSettings.get()
|
||||
|
||||
return (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`Bandwidth`}
|
||||
cornerEl={
|
||||
<div className="flex gap-2">
|
||||
{maxValSelect}
|
||||
<NetworkSheet chartData={chartData} dataEmpty={dataEmpty} grid={grid} maxValues={maxValues} />
|
||||
</div>
|
||||
}
|
||||
description={t`Network traffic of public interfaces`}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
maxToggled={showMax}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t`Sent`,
|
||||
dataKey(data: SystemStatsRecord) {
|
||||
if (showMax) {
|
||||
return data?.stats?.bm?.[0] ?? (data?.stats?.nsm ?? 0) * 1024 * 1024
|
||||
}
|
||||
return data?.stats?.b?.[0] ?? (data?.stats?.ns ?? 0) * 1024 * 1024
|
||||
},
|
||||
color: 5,
|
||||
opacity: 0.2,
|
||||
},
|
||||
{
|
||||
label: t`Received`,
|
||||
dataKey(data: SystemStatsRecord) {
|
||||
if (showMax) {
|
||||
return data?.stats?.bm?.[1] ?? (data?.stats?.nrm ?? 0) * 1024 * 1024
|
||||
}
|
||||
return data?.stats?.b?.[1] ?? (data?.stats?.nr ?? 0) * 1024 * 1024
|
||||
},
|
||||
color: 2,
|
||||
opacity: 0.2,
|
||||
},
|
||||
]
|
||||
// try to place the lesser number in front for better visibility
|
||||
.sort(() => (systemStats.at(-1)?.stats.b?.[1] ?? 0) - (systemStats.at(-1)?.stats.b?.[0] ?? 0))}
|
||||
tickFormatter={(val) => {
|
||||
const { value, unit } = formatBytes(val, true, userSettings.unitNet, false)
|
||||
return `${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}`
|
||||
}}
|
||||
contentFormatter={(data) => {
|
||||
const { value, unit } = formatBytes(data.value, true, userSettings.unitNet, false)
|
||||
return `${decimalString(value, value >= 100 ? 1 : 2)} ${unit}`
|
||||
}}
|
||||
showTotal={true}
|
||||
/>
|
||||
</ChartCard>
|
||||
)
|
||||
}
|
||||
|
||||
export function ContainerNetworkChart({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
isPodman,
|
||||
networkConfig,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
isPodman: boolean
|
||||
networkConfig: ChartConfig
|
||||
}) {
|
||||
const userSettings = $userSettings.get()
|
||||
const { filter, dataPoints, filteredKeys } = useContainerDataPoints(networkConfig, (key, data) => {
|
||||
const payload = data[key]
|
||||
if (!payload) return null
|
||||
const sent = payload?.b?.[0] ?? (payload?.ns ?? 0) * 1024 * 1024
|
||||
const recv = payload?.b?.[1] ?? (payload?.nr ?? 0) * 1024 * 1024
|
||||
return sent + recv
|
||||
})
|
||||
|
||||
const contentFormatter = useMemo(() => {
|
||||
const getRxTxBytes = (record?: { b?: [number, number]; ns?: number; nr?: number }) => {
|
||||
if (record?.b?.length && record.b.length >= 2) {
|
||||
return [Number(record.b[0]) || 0, Number(record.b[1]) || 0]
|
||||
}
|
||||
return [(record?.ns ?? 0) * 1024 * 1024, (record?.nr ?? 0) * 1024 * 1024]
|
||||
}
|
||||
const formatRxTx = (recv: number, sent: number) => {
|
||||
const { value: receivedValue, unit: receivedUnit } = formatBytes(recv, true, userSettings.unitNet, false)
|
||||
const { value: sentValue, unit: sentUnit } = formatBytes(sent, true, userSettings.unitNet, false)
|
||||
return (
|
||||
<span className="flex">
|
||||
{decimalString(receivedValue)} {receivedUnit}
|
||||
<span className="opacity-70 ms-0.5"> rx </span>
|
||||
<Separator orientation="vertical" className="h-3 mx-1.5 bg-primary/40" />
|
||||
{decimalString(sentValue)} {sentUnit}
|
||||
<span className="opacity-70 ms-0.5"> tx</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
// biome-ignore lint/suspicious/noExplicitAny: recharts tooltip item
|
||||
return (item: any, key: string) => {
|
||||
try {
|
||||
if (key === "__total__") {
|
||||
let totalSent = 0
|
||||
let totalRecv = 0
|
||||
const payloadData = item?.payload && typeof item.payload === "object" ? item.payload : {}
|
||||
for (const [containerKey, value] of Object.entries(payloadData)) {
|
||||
if (!value || typeof value !== "object") continue
|
||||
if (filteredKeys.has(containerKey)) continue
|
||||
const [sent, recv] = getRxTxBytes(value as { b?: [number, number]; ns?: number; nr?: number })
|
||||
totalSent += sent
|
||||
totalRecv += recv
|
||||
}
|
||||
return formatRxTx(totalRecv, totalSent)
|
||||
}
|
||||
const [sent, recv] = getRxTxBytes(item?.payload?.[key])
|
||||
return formatRxTx(recv, sent)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}, [filteredKeys, userSettings.unitNet])
|
||||
|
||||
return (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={dockerOrPodman(t`Docker Network I/O`, isPodman)}
|
||||
description={dockerOrPodman(t`Network traffic of docker containers`, isPodman)}
|
||||
cornerEl={<FilterBar />}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
customData={chartData.containerData}
|
||||
dataPoints={dataPoints}
|
||||
tickFormatter={(val) => {
|
||||
const { value, unit } = formatBytes(val, true, userSettings.unitNet, false)
|
||||
return `${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}`
|
||||
}}
|
||||
contentFormatter={contentFormatter}
|
||||
domain={pinnedAxisDomain()}
|
||||
showTotal={true}
|
||||
reverseStackOrder={true}
|
||||
filter={filter}
|
||||
truncate={true}
|
||||
itemSorter={(a, b) => b.value - a.value}
|
||||
/>
|
||||
</ChartCard>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import AreaChartDefault from "@/components/charts/area-chart"
|
||||
import { batteryStateTranslations } from "@/lib/i18n"
|
||||
import { $temperatureFilter, $userSettings } from "@/lib/stores"
|
||||
import { cn, decimalString, formatTemperature, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData, SystemStatsRecord } from "@/types"
|
||||
import { ChartCard, FilterBar } from "../chart-card"
|
||||
import LineChartDefault from "@/components/charts/line-chart"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { useRef, useMemo, useState, useEffect } from "react"
|
||||
|
||||
export function BatteryChart({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
maxValues,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
maxValues: boolean
|
||||
}) {
|
||||
const showBatteryChart = chartData.systemStats.at(-1)?.stats.bat
|
||||
|
||||
if (!showBatteryChart) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`Battery`}
|
||||
description={`${t({
|
||||
message: "Current state",
|
||||
comment: "Context: Battery state",
|
||||
})}: ${batteryStateTranslations[chartData.systemStats.at(-1)?.stats.bat?.[1] ?? 0]()}`}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
maxToggled={maxValues}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t`Charge`,
|
||||
dataKey: ({ stats }) => stats?.bat?.[0],
|
||||
color: 1,
|
||||
opacity: 0.35,
|
||||
},
|
||||
]}
|
||||
domain={[0, 100]}
|
||||
tickFormatter={(val) => `${val}%`}
|
||||
contentFormatter={({ value }) => `${value}%`}
|
||||
/>
|
||||
</ChartCard>
|
||||
)
|
||||
}
|
||||
|
||||
export function TemperatureChart({
|
||||
chartData,
|
||||
grid,
|
||||
dataEmpty,
|
||||
setPageBottomExtraMargin,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
dataEmpty: boolean
|
||||
setPageBottomExtraMargin?: (margin: number) => void
|
||||
}) {
|
||||
const showTempChart = chartData.systemStats.at(-1)?.stats.t
|
||||
|
||||
const filter = useStore($temperatureFilter)
|
||||
const userSettings = useStore($userSettings)
|
||||
|
||||
const statsRef = useRef(chartData.systemStats)
|
||||
statsRef.current = chartData.systemStats
|
||||
|
||||
// Derive sensor names key from latest data point
|
||||
let sensorNamesKey = ""
|
||||
for (let i = chartData.systemStats.length - 1; i >= 0; i--) {
|
||||
const t = chartData.systemStats[i].stats?.t
|
||||
if (t) {
|
||||
sensorNamesKey = Object.keys(t).sort().join("\0")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Only recompute colors and dataKey functions when sensor names change
|
||||
const { colorMap, dataKeys, sortedKeys } = useMemo(() => {
|
||||
const stats = statsRef.current
|
||||
const tempSums = {} as Record<string, number>
|
||||
for (const data of stats) {
|
||||
const t = data.stats?.t
|
||||
if (!t) continue
|
||||
for (const key of Object.keys(t)) {
|
||||
tempSums[key] = (tempSums[key] ?? 0) + t[key]
|
||||
}
|
||||
}
|
||||
const sorted = Object.keys(tempSums).sort((a, b) => tempSums[b] - tempSums[a])
|
||||
const colorMap = {} as Record<string, string>
|
||||
const dataKeys = {} as Record<string, (d: SystemStatsRecord) => number | undefined>
|
||||
for (let i = 0; i < sorted.length; i++) {
|
||||
const key = sorted[i]
|
||||
colorMap[key] = `hsl(${((i * 360) / sorted.length) % 360}, 60%, 55%)`
|
||||
dataKeys[key] = (d: SystemStatsRecord) => d.stats?.t?.[key]
|
||||
}
|
||||
return { colorMap, dataKeys, sortedKeys: sorted }
|
||||
}, [sensorNamesKey])
|
||||
|
||||
const dataPoints = useMemo(() => {
|
||||
return sortedKeys.map((key) => {
|
||||
const filterTerms = filter
|
||||
? filter
|
||||
.toLowerCase()
|
||||
.split(" ")
|
||||
.filter((term) => term.length > 0)
|
||||
: []
|
||||
const filtered = filterTerms.length > 0 && !filterTerms.some((term) => key.toLowerCase().includes(term))
|
||||
const strokeOpacity = filtered ? 0.1 : 1
|
||||
return {
|
||||
label: key,
|
||||
dataKey: dataKeys[key],
|
||||
color: colorMap[key],
|
||||
opacity: strokeOpacity,
|
||||
}
|
||||
})
|
||||
}, [sortedKeys, filter, dataKeys, colorMap])
|
||||
|
||||
// test with lots of data points
|
||||
// const totalPoints = 50
|
||||
// if (dataPoints.length > 0 && dataPoints.length < totalPoints) {
|
||||
// let i = 0
|
||||
// while (dataPoints.length < totalPoints) {
|
||||
// dataPoints.push({
|
||||
// label: `Test ${++i}`,
|
||||
// dataKey: () => 0,
|
||||
// color: "red",
|
||||
// opacity: 1,
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
const chartRef = useRef<HTMLDivElement>(null)
|
||||
const [addMargin, setAddMargin] = useState(false)
|
||||
const marginPx = (dataPoints.length - 13) * 18
|
||||
|
||||
useEffect(() => {
|
||||
if (setPageBottomExtraMargin && dataPoints.length > 13 && chartRef.current) {
|
||||
const checkPosition = () => {
|
||||
if (!chartRef.current) return
|
||||
const rect = chartRef.current.getBoundingClientRect()
|
||||
const actualScrollHeight = addMargin
|
||||
? document.documentElement.scrollHeight - marginPx
|
||||
: document.documentElement.scrollHeight
|
||||
const distanceToBottom = actualScrollHeight - (rect.bottom + window.scrollY)
|
||||
|
||||
if (distanceToBottom < 250) {
|
||||
setAddMargin(true)
|
||||
setPageBottomExtraMargin(marginPx)
|
||||
} else {
|
||||
setAddMargin(false)
|
||||
setPageBottomExtraMargin(0)
|
||||
}
|
||||
}
|
||||
checkPosition()
|
||||
const timer = setTimeout(checkPosition, 500)
|
||||
return () => {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
} else if (addMargin) {
|
||||
setAddMargin(false)
|
||||
if (setPageBottomExtraMargin) setPageBottomExtraMargin(0)
|
||||
}
|
||||
}, [dataPoints.length, addMargin, marginPx, setPageBottomExtraMargin])
|
||||
|
||||
if (!showTempChart) {
|
||||
return null
|
||||
}
|
||||
|
||||
const legend = dataPoints.length < 12
|
||||
|
||||
return (
|
||||
<div ref={chartRef} className={cn("odd:last-of-type:col-span-full", { "col-span-full": !grid })}>
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`Temperature`}
|
||||
description={t`Temperatures of system sensors`}
|
||||
cornerEl={<FilterBar store={$temperatureFilter} />}
|
||||
legend={legend}
|
||||
>
|
||||
<LineChartDefault
|
||||
chartData={chartData}
|
||||
itemSorter={(a, b) => b.value - a.value}
|
||||
domain={["auto", "auto"]}
|
||||
legend={legend}
|
||||
tickFormatter={(val) => {
|
||||
const { value, unit } = formatTemperature(val, userSettings.unitTemp)
|
||||
return `${toFixedFloat(value, 2)} ${unit}`
|
||||
}}
|
||||
contentFormatter={(item) => {
|
||||
const { value, unit } = formatTemperature(item.value, userSettings.unitTemp)
|
||||
return `${decimalString(value)} ${unit}`
|
||||
}}
|
||||
dataPoints={dataPoints}
|
||||
></LineChartDefault>
|
||||
</ChartCard>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { MoreHorizontalIcon } from "lucide-react"
|
||||
import { memo, useRef, useState } from "react"
|
||||
import AreaChartDefault, { DataPoint } from "@/components/charts/area-chart"
|
||||
import AreaChartDefault, { type DataPoint } from "@/components/charts/area-chart"
|
||||
import ChartTimeSelect from "@/components/charts/chart-time-select"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"
|
||||
import { DialogTitle } from "@/components/ui/dialog"
|
||||
import { compareSemVer, decimalString, parseSemVer, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData, SystemStatsRecord } from "@/types"
|
||||
import { ChartCard } from "../system"
|
||||
import { ChartCard } from "./chart-card"
|
||||
|
||||
const minAgentVersion = parseSemVer("0.15.3")
|
||||
|
||||
@@ -42,41 +42,54 @@ export default memo(function CpuCoresSheet({
|
||||
const numCores = cpus.length
|
||||
const hasBreakdown = (latest?.cpub?.length ?? 0) > 0
|
||||
|
||||
// make sure all individual core data points have the same y axis domain to make relative comparison easier
|
||||
let highestCpuCorePct = 1
|
||||
if (hasOpened.current) {
|
||||
for (let i = 0; i < numCores; i++) {
|
||||
for (let j = 0; j < chartData.systemStats.length; j++) {
|
||||
const pct = chartData.systemStats[j].stats?.cpus?.[i] ?? 0
|
||||
if (pct > highestCpuCorePct) {
|
||||
highestCpuCorePct = pct
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const breakdownDataPoints = [
|
||||
{
|
||||
label: "System",
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.cpub?.[1],
|
||||
color: 3,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
stackId: "a",
|
||||
},
|
||||
{
|
||||
label: "User",
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.cpub?.[0],
|
||||
color: 1,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
stackId: "a",
|
||||
},
|
||||
{
|
||||
label: "IOWait",
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.cpub?.[2],
|
||||
color: 4,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
stackId: "a",
|
||||
},
|
||||
{
|
||||
label: "Steal",
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.cpub?.[3],
|
||||
color: 5,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
stackId: "a",
|
||||
},
|
||||
{
|
||||
label: "Idle",
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.cpub?.[4],
|
||||
color: 2,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
stackId: "a",
|
||||
},
|
||||
{
|
||||
label: t`Other`,
|
||||
@@ -86,11 +99,10 @@ export default memo(function CpuCoresSheet({
|
||||
},
|
||||
color: `hsl(80, 65%, 52%)`,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
stackId: "a",
|
||||
},
|
||||
] as DataPoint[]
|
||||
|
||||
|
||||
return (
|
||||
<Sheet open={cpuCoresOpen} onOpenChange={setCpuCoresOpen}>
|
||||
<DialogTitle className="sr-only">{t`CPU Usage`}</DialogTitle>
|
||||
@@ -99,7 +111,7 @@ export default memo(function CpuCoresSheet({
|
||||
title={t`View more`}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="shrink-0 max-sm:absolute max-sm:top-3 max-sm:end-3"
|
||||
className="shrink-0 max-sm:absolute max-sm:top-0 max-sm:end-0"
|
||||
>
|
||||
<MoreHorizontalIcon />
|
||||
</Button>
|
||||
@@ -151,7 +163,7 @@ export default memo(function CpuCoresSheet({
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.cpus?.[i] ?? 1 / (stats?.cpus?.length ?? 1),
|
||||
color: `hsl(${226 + (((i * 360) / Math.max(1, numCores)) % 360)}, var(--chart-saturation), var(--chart-lightness))`,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
stackId: "a",
|
||||
}))}
|
||||
tickFormatter={(val) => `${val}%`}
|
||||
contentFormatter={({ value }) => `${value}%`}
|
||||
@@ -174,7 +186,7 @@ export default memo(function CpuCoresSheet({
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
maxToggled={maxValues}
|
||||
legend={false}
|
||||
domain={[0, highestCpuCorePct]}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t`Usage`,
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
import { plural } from "@lingui/core/macro"
|
||||
import { useLingui } from "@lingui/react/macro"
|
||||
import { Trans, useLingui } from "@lingui/react/macro"
|
||||
import {
|
||||
AppleIcon,
|
||||
ChevronRightSquareIcon,
|
||||
ClockArrowUp,
|
||||
CpuIcon,
|
||||
GlobeIcon,
|
||||
LayoutGridIcon,
|
||||
MemoryStickIcon,
|
||||
MonitorIcon,
|
||||
Rows,
|
||||
Settings2Icon,
|
||||
} from "lucide-react"
|
||||
import { useMemo } from "react"
|
||||
import ChartTimeSelect from "@/components/charts/chart-time-select"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card } from "@/components/ui/card"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
import { FreeBsdIcon, TuxIcon, WebSocketIcon, WindowsIcon } from "@/components/ui/icons"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
|
||||
@@ -27,12 +35,16 @@ export default function InfoBar({
|
||||
chartData,
|
||||
grid,
|
||||
setGrid,
|
||||
displayMode,
|
||||
setDisplayMode,
|
||||
details,
|
||||
}: {
|
||||
system: SystemRecord
|
||||
chartData: ChartData
|
||||
grid: boolean
|
||||
setGrid: (grid: boolean) => void
|
||||
displayMode: "default" | "tabs"
|
||||
setDisplayMode: (mode: "default" | "tabs") => void
|
||||
details: SystemDetailsRecord | null
|
||||
}) {
|
||||
const { t } = useLingui()
|
||||
@@ -123,10 +135,10 @@ export default function InfoBar({
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<div className="grid xl:flex gap-4 px-4 sm:px-6 pt-3 sm:pt-4 pb-5">
|
||||
<div>
|
||||
<h1 className="text-[1.6rem] font-semibold mb-1.5">{system.name}</h1>
|
||||
<div className="flex flex-wrap items-center gap-3 gap-y-2 text-sm opacity-90">
|
||||
<div className="grid xl:flex xl:gap-4 px-4 sm:px-6 pt-3 sm:pt-4 pb-5">
|
||||
<div className="min-w-0">
|
||||
<h1 className="text-2xl sm:text-[1.6rem] font-semibold mb-1.5">{system.name}</h1>
|
||||
<div className="flex xl:flex-wrap items-center py-4 xl:p-0 -mt-3 xl:mt-1 gap-3 text-sm text-nowrap opacity-90 overflow-x-auto scrollbar-hide -mx-4 px-4 xl:mx-0">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="capitalize flex gap-2 items-center">
|
||||
@@ -190,24 +202,53 @@ export default function InfoBar({
|
||||
</div>
|
||||
<div className="xl:ms-auto flex items-center gap-2 max-sm:-mb-1">
|
||||
<ChartTimeSelect className="w-full xl:w-40" agentVersion={chartData.agentVersion} />
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
aria-label={t`Toggle grid`}
|
||||
aria-label={t`Settings`}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="hidden xl:flex p-0 text-primary"
|
||||
onClick={() => setGrid(!grid)}
|
||||
>
|
||||
{grid ? (
|
||||
<LayoutGridIcon className="h-[1.2rem] w-[1.2rem] opacity-75" />
|
||||
) : (
|
||||
<Rows className="h-[1.3rem] w-[1.3rem] opacity-75" />
|
||||
)}
|
||||
<Settings2Icon className="size-4 opacity-90" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{t`Toggle grid`}</TooltipContent>
|
||||
</Tooltip>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="min-w-44">
|
||||
<DropdownMenuLabel className="px-3.5">
|
||||
<Trans context="Layout display options">Display</Trans>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuRadioGroup
|
||||
className="px-1 pb-1"
|
||||
value={displayMode}
|
||||
onValueChange={(v) => setDisplayMode(v as "default" | "tabs")}
|
||||
>
|
||||
<DropdownMenuRadioItem value="default" onSelect={(e) => e.preventDefault()}>
|
||||
<Trans context="Default system layout option">Default</Trans>
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="tabs" onSelect={(e) => e.preventDefault()}>
|
||||
<Trans context="Tabs system layout option">Tabs</Trans>
|
||||
</DropdownMenuRadioItem>
|
||||
</DropdownMenuRadioGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuLabel className="px-3.5">
|
||||
<Trans>Chart width</Trans>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuRadioGroup
|
||||
className="px-1 pb-1"
|
||||
value={grid ? "grid" : "full"}
|
||||
onValueChange={(v) => setGrid(v === "grid")}
|
||||
>
|
||||
<DropdownMenuRadioItem value="grid" onSelect={(e) => e.preventDefault()}>
|
||||
<Trans>Grid</Trans>
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="full" onSelect={(e) => e.preventDefault()}>
|
||||
<Trans>Full</Trans>
|
||||
</DropdownMenuRadioItem>
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
36
internal/site/src/components/routes/system/lazy-tables.tsx
Normal file
36
internal/site/src/components/routes/system/lazy-tables.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { lazy } from "react"
|
||||
import { useIntersectionObserver } from "@/lib/use-intersection-observer"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const ContainersTable = lazy(() => import("../../containers-table/containers-table"))
|
||||
|
||||
export function LazyContainersTable({ systemId }: { systemId: string }) {
|
||||
const { isIntersecting, ref } = useIntersectionObserver({ rootMargin: "90px" })
|
||||
return (
|
||||
<div ref={ref} className={cn(isIntersecting && "contents")}>
|
||||
{isIntersecting && <ContainersTable systemId={systemId} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const SmartTable = lazy(() => import("./smart-table"))
|
||||
|
||||
export function LazySmartTable({ systemId }: { systemId: string }) {
|
||||
const { isIntersecting, ref } = useIntersectionObserver({ rootMargin: "90px" })
|
||||
return (
|
||||
<div ref={ref} className={cn(isIntersecting && "contents")}>
|
||||
{isIntersecting && <SmartTable systemId={systemId} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const SystemdTable = lazy(() => import("../../systemd-table/systemd-table"))
|
||||
|
||||
export function LazySystemdTable({ systemId }: { systemId: string }) {
|
||||
const { isIntersecting, ref } = useIntersectionObserver()
|
||||
return (
|
||||
<div ref={ref} className={cn(isIntersecting && "contents")}>
|
||||
{isIntersecting && <SystemdTable systemId={systemId} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import { DialogTitle } from "@/components/ui/dialog"
|
||||
import { $userSettings } from "@/lib/stores"
|
||||
import { decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
|
||||
import type { ChartData } from "@/types"
|
||||
import { ChartCard } from "../system"
|
||||
import { ChartCard } from "./chart-card"
|
||||
|
||||
export default memo(function NetworkSheet({
|
||||
chartData,
|
||||
@@ -46,7 +46,7 @@ export default memo(function NetworkSheet({
|
||||
title={t`View more`}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="shrink-0 max-sm:absolute max-sm:top-3 max-sm:end-3"
|
||||
className="shrink-0 max-sm:absolute max-sm:top-0 max-sm:end-0"
|
||||
>
|
||||
<MoreHorizontalIcon />
|
||||
</Button>
|
||||
|
||||
@@ -146,7 +146,9 @@ export const createColumns = (
|
||||
{
|
||||
accessorKey: "model",
|
||||
sortingFn: (a, b) => a.original.model.localeCompare(b.original.model),
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Model`} Icon={Box} />,
|
||||
header: ({ column }) => (
|
||||
<HeaderButton column={column} name={t({ message: "Model", comment: "Device model" })} Icon={Box} />
|
||||
),
|
||||
cell: ({ getValue }) => (
|
||||
<div
|
||||
className="max-w-48 truncate ms-1"
|
||||
@@ -532,9 +534,9 @@ export default function DisksTable({ systemId }: { systemId?: string }) {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Card className="p-6 @container w-full">
|
||||
<CardHeader className="p-0 mb-4">
|
||||
<div className="grid md:flex gap-5 w-full items-end">
|
||||
<Card className="@container w-full px-3 py-5 sm:py-6 sm:px-6">
|
||||
<CardHeader className="p-0 mb-3 sm:mb-4">
|
||||
<div className="grid md:flex gap-x-5 gap-y-3 w-full items-end">
|
||||
<div className="px-2 sm:px-1">
|
||||
<CardTitle className="mb-2">S.M.A.R.T.</CardTitle>
|
||||
<CardDescription className="flex">
|
||||
@@ -620,11 +622,13 @@ const SmartDevicesTable = memo(function SmartDevicesTable({
|
||||
return <SmartDeviceTableRow key={row.id} row={row} virtualRow={virtualRow} openSheet={openSheet} />
|
||||
})
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={colLength} className="h-24 text-center pointer-events-none">
|
||||
{data ? t`No results.` : <LoaderCircleIcon className="animate-spin size-10 opacity-60 mx-auto" />}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableCell colSpan={colLength} className="h-37 text-center pointer-events-none">
|
||||
{data ? (
|
||||
<Trans>No results.</Trans>
|
||||
) : (
|
||||
<LoaderCircleIcon className="animate-spin size-10 opacity-60 mx-auto" />
|
||||
)}
|
||||
</TableCell>
|
||||
)}
|
||||
</TableBody>
|
||||
</table>
|
||||
@@ -636,7 +640,6 @@ const SmartDevicesTable = memo(function SmartDevicesTable({
|
||||
function SmartTableHead({ table }: { table: TableType<SmartDeviceRecord> }) {
|
||||
return (
|
||||
<TableHeader className="sticky top-0 z-50 w-full border-b-2">
|
||||
<div className="absolute -top-2 left-0 w-full h-4 bg-table-header z-50"></div>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => (
|
||||
|
||||
344
internal/site/src/components/routes/system/use-system-data.ts
Normal file
344
internal/site/src/components/routes/system/use-system-data.ts
Normal file
@@ -0,0 +1,344 @@
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { getPagePath } from "@nanostores/router"
|
||||
import { subscribeKeys } from "nanostores"
|
||||
import { useEffect, useMemo, useRef, useState } from "react"
|
||||
import { useContainerChartConfigs } from "@/components/charts/hooks"
|
||||
import { pb } from "@/lib/api"
|
||||
import { SystemStatus } from "@/lib/enums"
|
||||
import {
|
||||
$allSystemsById,
|
||||
$allSystemsByName,
|
||||
$chartTime,
|
||||
$containerFilter,
|
||||
$direction,
|
||||
$maxValues,
|
||||
$systems,
|
||||
$userSettings,
|
||||
} from "@/lib/stores"
|
||||
import { chartTimeData, listen, parseSemVer, useBrowserStorage } from "@/lib/utils"
|
||||
import type {
|
||||
ChartData,
|
||||
ContainerStatsRecord,
|
||||
SystemDetailsRecord,
|
||||
SystemInfo,
|
||||
SystemRecord,
|
||||
SystemStats,
|
||||
SystemStatsRecord,
|
||||
} from "@/types"
|
||||
import { $router, navigate } from "../../router"
|
||||
import { appendData, cache, getStats, getTimeData, makeContainerData, makeContainerPoint } from "./chart-data"
|
||||
|
||||
export function useSystemData(id: string) {
|
||||
const direction = useStore($direction)
|
||||
const systems = useStore($systems)
|
||||
const chartTime = useStore($chartTime)
|
||||
const maxValues = useStore($maxValues)
|
||||
const [grid, setGrid] = useBrowserStorage("grid", true)
|
||||
const [displayMode, setDisplayMode] = useBrowserStorage<"default" | "tabs">("displayMode", "default")
|
||||
const [activeTab, setActiveTabRaw] = useState("core")
|
||||
const [mountedTabs, setMountedTabs] = useState(() => new Set<string>(["core"]))
|
||||
const tabsRef = useRef<string[]>(["core", "disk"])
|
||||
|
||||
function setActiveTab(tab: string) {
|
||||
setActiveTabRaw(tab)
|
||||
setMountedTabs((prev) => (prev.has(tab) ? prev : new Set([...prev, tab])))
|
||||
}
|
||||
const [system, setSystem] = useState({} as SystemRecord)
|
||||
const [systemStats, setSystemStats] = useState([] as SystemStatsRecord[])
|
||||
const [containerData, setContainerData] = useState([] as ChartData["containerData"])
|
||||
const persistChartTime = useRef(false)
|
||||
const statsRequestId = useRef(0)
|
||||
const [chartLoading, setChartLoading] = useState(true)
|
||||
const [details, setDetails] = useState<SystemDetailsRecord>({} as SystemDetailsRecord)
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (!persistChartTime.current) {
|
||||
$chartTime.set($userSettings.get().chartTime)
|
||||
}
|
||||
persistChartTime.current = false
|
||||
setSystemStats([])
|
||||
setContainerData([])
|
||||
setDetails({} as SystemDetailsRecord)
|
||||
$containerFilter.set("")
|
||||
}
|
||||
}, [id])
|
||||
|
||||
// find matching system and update when it changes
|
||||
useEffect(() => {
|
||||
if (!systems.length) {
|
||||
return
|
||||
}
|
||||
// allow old system-name slug to work
|
||||
const store = $allSystemsById.get()[id] ? $allSystemsById : $allSystemsByName
|
||||
return subscribeKeys(store, [id], (newSystems) => {
|
||||
const sys = newSystems[id]
|
||||
if (sys) {
|
||||
setSystem(sys)
|
||||
document.title = `${sys?.name} / Beszel`
|
||||
}
|
||||
})
|
||||
}, [id, systems.length])
|
||||
|
||||
// hide 1m chart time if system agent version is less than 0.13.0
|
||||
useEffect(() => {
|
||||
if (parseSemVer(system?.info?.v) < parseSemVer("0.13.0")) {
|
||||
$chartTime.set("1h")
|
||||
}
|
||||
}, [system?.info?.v])
|
||||
|
||||
// fetch system details
|
||||
useEffect(() => {
|
||||
// if system.info.m exists, agent is old version without system details
|
||||
if (!system.id || system.info?.m) {
|
||||
return
|
||||
}
|
||||
pb.collection<SystemDetailsRecord>("system_details")
|
||||
.getOne(system.id, {
|
||||
fields: "hostname,kernel,cores,threads,cpu,os,os_name,arch,memory,podman",
|
||||
headers: {
|
||||
"Cache-Control": "public, max-age=60",
|
||||
},
|
||||
})
|
||||
.then(setDetails)
|
||||
}, [system.id])
|
||||
|
||||
// subscribe to realtime metrics if chart time is 1m
|
||||
useEffect(() => {
|
||||
let unsub = () => {}
|
||||
if (!system.id || chartTime !== "1m") {
|
||||
return
|
||||
}
|
||||
if (system.status !== SystemStatus.Up || parseSemVer(system?.info?.v).minor < 13) {
|
||||
$chartTime.set("1h")
|
||||
return
|
||||
}
|
||||
let isFirst = true
|
||||
pb.realtime
|
||||
.subscribe(
|
||||
`rt_metrics`,
|
||||
(data: { container: ContainerStatsRecord[]; info: SystemInfo; stats: SystemStats }) => {
|
||||
const now = Date.now()
|
||||
const statsPoint = { created: now, stats: data.stats } as SystemStatsRecord
|
||||
const containerPoint =
|
||||
data.container?.length > 0
|
||||
? makeContainerPoint(now, data.container as unknown as ContainerStatsRecord["stats"])
|
||||
: null
|
||||
// on first message, make sure we clear out data from other time periods
|
||||
if (isFirst) {
|
||||
isFirst = false
|
||||
setSystemStats([statsPoint])
|
||||
setContainerData(containerPoint ? [containerPoint] : [])
|
||||
return
|
||||
}
|
||||
setSystemStats((prev) => appendData(prev, [statsPoint], 1000, 60))
|
||||
if (containerPoint) {
|
||||
setContainerData((prev) => appendData(prev, [containerPoint], 1000, 60))
|
||||
}
|
||||
},
|
||||
{ query: { system: system.id } }
|
||||
)
|
||||
.then((us) => {
|
||||
unsub = us
|
||||
})
|
||||
return () => {
|
||||
unsub?.()
|
||||
}
|
||||
}, [chartTime, system.id])
|
||||
|
||||
const agentVersion = useMemo(() => parseSemVer(system?.info?.v), [system?.info?.v])
|
||||
|
||||
const chartData: ChartData = useMemo(() => {
|
||||
const lastCreated = Math.max(
|
||||
(systemStats.at(-1)?.created as number) ?? 0,
|
||||
(containerData.at(-1)?.created as number) ?? 0
|
||||
)
|
||||
return {
|
||||
systemStats,
|
||||
containerData,
|
||||
chartTime,
|
||||
orientation: direction === "rtl" ? "right" : "left",
|
||||
...getTimeData(chartTime, lastCreated),
|
||||
agentVersion,
|
||||
}
|
||||
}, [systemStats, containerData, direction])
|
||||
|
||||
// Share chart config computation for all container charts
|
||||
const containerChartConfigs = useContainerChartConfigs(containerData)
|
||||
|
||||
// get stats when system "changes." (Not just system to system,
|
||||
// also when new info comes in via systemManager realtime connection, indicating an update)
|
||||
useEffect(() => {
|
||||
if (!system.id || !chartTime || chartTime === "1m") {
|
||||
return
|
||||
}
|
||||
|
||||
const systemId = system.id
|
||||
const { expectedInterval } = chartTimeData[chartTime]
|
||||
const ss_cache_key = `${systemId}_${chartTime}_system_stats`
|
||||
const cs_cache_key = `${systemId}_${chartTime}_container_stats`
|
||||
const requestId = ++statsRequestId.current
|
||||
|
||||
const cachedSystemStats = cache.get(ss_cache_key) as SystemStatsRecord[] | undefined
|
||||
const cachedContainerData = cache.get(cs_cache_key) as ChartData["containerData"] | undefined
|
||||
|
||||
// Render from cache immediately if available
|
||||
if (cachedSystemStats?.length) {
|
||||
setSystemStats(cachedSystemStats)
|
||||
setContainerData(cachedContainerData || [])
|
||||
setChartLoading(false)
|
||||
|
||||
// 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) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
setChartLoading(true)
|
||||
}
|
||||
|
||||
Promise.allSettled([
|
||||
getStats<SystemStatsRecord>("system_stats", systemId, chartTime),
|
||||
getStats<ContainerStatsRecord>("container_stats", systemId, chartTime),
|
||||
]).then(([systemStats, containerStats]) => {
|
||||
// If another request has been made since this one, ignore the results
|
||||
if (requestId !== statsRequestId.current) {
|
||||
return
|
||||
}
|
||||
|
||||
setChartLoading(false)
|
||||
|
||||
// make new system stats
|
||||
let systemData = (cache.get(ss_cache_key) || []) as SystemStatsRecord[]
|
||||
if (systemStats.status === "fulfilled" && systemStats.value.length) {
|
||||
systemData = appendData(systemData, systemStats.value, expectedInterval, 100)
|
||||
cache.set(ss_cache_key, systemData)
|
||||
}
|
||||
setSystemStats(systemData)
|
||||
// make new container stats
|
||||
let containerData = (cache.get(cs_cache_key) || []) as ChartData["containerData"]
|
||||
if (containerStats.status === "fulfilled" && containerStats.value.length) {
|
||||
containerData = appendData(containerData, makeContainerData(containerStats.value), expectedInterval, 100)
|
||||
cache.set(cs_cache_key, containerData)
|
||||
}
|
||||
setContainerData(containerData)
|
||||
})
|
||||
}, [system, chartTime])
|
||||
|
||||
// keyboard navigation between systems
|
||||
// in tabs mode: arrow keys switch tabs, shift+arrow switches systems
|
||||
// in default mode: arrow keys switch systems
|
||||
useEffect(() => {
|
||||
if (!systems.length) {
|
||||
return
|
||||
}
|
||||
const handleKeyUp = (e: KeyboardEvent) => {
|
||||
if (
|
||||
e.target instanceof HTMLInputElement ||
|
||||
e.target instanceof HTMLTextAreaElement ||
|
||||
e.ctrlKey ||
|
||||
e.metaKey ||
|
||||
e.altKey
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const isLeft = e.key === "ArrowLeft" || e.key === "h"
|
||||
const isRight = e.key === "ArrowRight" || e.key === "l"
|
||||
if (!isLeft && !isRight) {
|
||||
return
|
||||
}
|
||||
|
||||
// in tabs mode, plain arrows switch tabs, shift+arrows switch systems
|
||||
if (displayMode === "tabs") {
|
||||
if (!e.shiftKey) {
|
||||
// skip if focused in tablist (Radix handles it natively)
|
||||
if (e.target instanceof HTMLElement && e.target.closest('[role="tablist"]')) {
|
||||
return
|
||||
}
|
||||
const tabs = tabsRef.current
|
||||
const currentIdx = tabs.indexOf(activeTab)
|
||||
const nextIdx = isLeft ? (currentIdx - 1 + tabs.length) % tabs.length : (currentIdx + 1) % tabs.length
|
||||
setActiveTab(tabs[nextIdx])
|
||||
return
|
||||
}
|
||||
} else if (e.shiftKey) {
|
||||
return
|
||||
}
|
||||
|
||||
const currentIndex = systems.findIndex((s) => s.id === id)
|
||||
if (currentIndex === -1 || systems.length <= 1) {
|
||||
return
|
||||
}
|
||||
if (isLeft) {
|
||||
const prevIndex = (currentIndex - 1 + systems.length) % systems.length
|
||||
persistChartTime.current = true
|
||||
setActiveTabRaw("core")
|
||||
setMountedTabs(new Set(["core"]))
|
||||
return navigate(getPagePath($router, "system", { id: systems[prevIndex].id }))
|
||||
}
|
||||
if (isRight) {
|
||||
const nextIndex = (currentIndex + 1) % systems.length
|
||||
persistChartTime.current = true
|
||||
setActiveTabRaw("core")
|
||||
setMountedTabs(new Set(["core"]))
|
||||
return navigate(getPagePath($router, "system", { id: systems[nextIndex].id }))
|
||||
}
|
||||
}
|
||||
return listen(document, "keyup", handleKeyUp)
|
||||
}, [id, systems, displayMode, activeTab])
|
||||
|
||||
// derived values
|
||||
const isLongerChart = !["1m", "1h"].includes(chartTime)
|
||||
const showMax = maxValues && isLongerChart
|
||||
const dataEmpty = !chartLoading && chartData.systemStats.length === 0
|
||||
const lastGpus = systemStats.at(-1)?.stats?.g
|
||||
const isPodman = details?.podman ?? system.info?.p ?? false
|
||||
|
||||
let hasGpuData = false
|
||||
let hasGpuEnginesData = false
|
||||
let hasGpuPowerData = false
|
||||
|
||||
if (lastGpus) {
|
||||
hasGpuData = Object.keys(lastGpus).length > 0
|
||||
for (let i = 0; i < systemStats.length && (!hasGpuEnginesData || !hasGpuPowerData); i++) {
|
||||
const gpus = systemStats[i].stats?.g
|
||||
if (!gpus) continue
|
||||
for (const id in gpus) {
|
||||
if (!hasGpuEnginesData && gpus[id].e !== undefined) {
|
||||
hasGpuEnginesData = true
|
||||
}
|
||||
if (!hasGpuPowerData && (gpus[id].p !== undefined || gpus[id].pp !== undefined)) {
|
||||
hasGpuPowerData = true
|
||||
}
|
||||
if (hasGpuEnginesData && hasGpuPowerData) break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
system,
|
||||
systemStats,
|
||||
containerData,
|
||||
chartData,
|
||||
containerChartConfigs,
|
||||
details,
|
||||
grid,
|
||||
setGrid,
|
||||
displayMode,
|
||||
setDisplayMode,
|
||||
activeTab,
|
||||
setActiveTab,
|
||||
mountedTabs,
|
||||
tabsRef,
|
||||
maxValues,
|
||||
isLongerChart,
|
||||
showMax,
|
||||
dataEmpty,
|
||||
isPodman,
|
||||
lastGpus,
|
||||
hasGpuData,
|
||||
hasGpuEnginesData,
|
||||
hasGpuPowerData,
|
||||
}
|
||||
}
|
||||
@@ -154,9 +154,9 @@ export default function SystemdTable({ systemId }: { systemId?: string }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="p-6 @container w-full">
|
||||
<CardHeader className="p-0 mb-4">
|
||||
<div className="grid md:flex gap-5 w-full items-end">
|
||||
<Card className="@container w-full px-3 py-5 sm:py-6 sm:px-6">
|
||||
<CardHeader className="p-0 mb-3 sm:mb-4">
|
||||
<div className="grid md:flex gap-x-5 gap-y-3 w-full items-end">
|
||||
<div className="px-2 sm:px-1">
|
||||
<CardTitle className="mb-2">
|
||||
<Trans>Systemd Services</Trans>
|
||||
@@ -614,7 +614,6 @@ function SystemdSheet({
|
||||
function SystemdTableHead({ table }: { table: TableType<SystemdRecord> }) {
|
||||
return (
|
||||
<TableHeader className="sticky top-0 z-50 w-full border-b-2">
|
||||
<div className="absolute -top-2 left-0 w-full h-4 bg-table-header z-50"></div>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
|
||||
@@ -184,7 +184,8 @@ export function SystemsTableColumns(viewMode: "table" | "grid"): ColumnDef<Syste
|
||||
accessorFn: ({ info }) => info.dp || undefined,
|
||||
id: "disk",
|
||||
name: () => t`Disk`,
|
||||
cell: DiskCellWithMultiple,
|
||||
cell: (info: CellContext<SystemRecord, unknown>) =>
|
||||
info.row.original.info.efs ? DiskCellWithMultiple(info) : TableCellWithMeter(info),
|
||||
Icon: HardDriveIcon,
|
||||
header: sortableHeader,
|
||||
},
|
||||
@@ -479,11 +480,6 @@ function DiskCellWithMultiple(info: CellContext<SystemRecord, unknown>) {
|
||||
const { colorWarn = 65, colorCrit = 90 } = useStore($userSettings, { keys: ["colorWarn", "colorCrit"] })
|
||||
const { info: sysInfo, status, id } = info.row.original
|
||||
const extraFs = Object.entries(sysInfo.efs ?? {})
|
||||
|
||||
if (extraFs.length === 0) {
|
||||
return TableCellWithMeter(info)
|
||||
}
|
||||
|
||||
const rootDiskPct = sysInfo.dp
|
||||
|
||||
// sort extra disks by percentage descending
|
||||
|
||||
@@ -134,8 +134,8 @@ export default function SystemsTable() {
|
||||
|
||||
const CardHead = useMemo(() => {
|
||||
return (
|
||||
<CardHeader className="pb-4.5 px-2 sm:px-6 max-sm:pt-5 max-sm:pb-1">
|
||||
<div className="grid md:flex gap-5 w-full items-end">
|
||||
<CardHeader className="p-0 mb-3 sm:mb-4">
|
||||
<div className="grid md:flex gap-x-5 gap-y-3 w-full items-end">
|
||||
<div className="px-2 sm:px-1">
|
||||
<CardTitle className="mb-2">
|
||||
<Trans>All Systems</Trans>
|
||||
@@ -302,29 +302,27 @@ export default function SystemsTable() {
|
||||
])
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Card className="w-full px-3 py-5 sm:py-6 sm:px-6">
|
||||
{CardHead}
|
||||
<div className="p-6 pt-0 max-sm:py-3 max-sm:px-2">
|
||||
{viewMode === "table" ? (
|
||||
// table layout
|
||||
<div className="rounded-md">
|
||||
<AllSystemsTable table={table} rows={rows} colLength={visibleColumns.length} />
|
||||
</div>
|
||||
) : (
|
||||
// grid layout
|
||||
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{rows?.length ? (
|
||||
rows.map((row) => {
|
||||
return <SystemCard key={row.original.id} row={row} table={table} colLength={visibleColumns.length} />
|
||||
})
|
||||
) : (
|
||||
<div className="col-span-full text-center py-8">
|
||||
<Trans>No systems found.</Trans>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{viewMode === "table" ? (
|
||||
// table layout
|
||||
<div className="rounded-md">
|
||||
<AllSystemsTable table={table} rows={rows} colLength={visibleColumns.length} />
|
||||
</div>
|
||||
) : (
|
||||
// grid layout
|
||||
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{rows?.length ? (
|
||||
rows.map((row) => {
|
||||
return <SystemCard key={row.original.id} row={row} table={table} colLength={visibleColumns.length} />
|
||||
})
|
||||
) : (
|
||||
<div className="col-span-full text-center py-8">
|
||||
<Trans>No systems found.</Trans>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -391,7 +389,6 @@ function SystemsTableHead({ table }: { table: TableType<SystemRecord> }) {
|
||||
const { t } = useLingui()
|
||||
return (
|
||||
<TableHeader className="sticky top-0 z-50 w-full border-b-2">
|
||||
<div className="absolute -top-2 left-0 w-full h-4 bg-table-header z-50"></div>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
|
||||
@@ -18,7 +18,11 @@ CardHeader.displayName = "CardHeader"
|
||||
|
||||
const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<h3 ref={ref} className={cn("text-2xl font-semibold leading-none tracking-tight", className)} {...props} />
|
||||
<h3
|
||||
ref={ref}
|
||||
className={cn("text-[1.4em] sm:text-2xl font-semibold leading-none tracking-tight", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)
|
||||
CardTitle.displayName = "CardTitle"
|
||||
|
||||
@@ -25,7 +25,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex select-none items-center rounded-sm px-2.5 py-1.5 text-sm outline-hidden focus:bg-accent/70 data-[state=open]:bg-accent/70",
|
||||
"flex select-none items-center rounded-sm px-2.5 py-1.5 text-[.95em] outline-hidden focus:bg-accent/70 data-[state=open]:bg-accent/70",
|
||||
inset && "ps-8",
|
||||
className
|
||||
)}
|
||||
@@ -79,7 +79,7 @@ const DropdownMenuItem = React.forwardRef<
|
||||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"cursor-pointer relative flex select-none items-center rounded-sm px-2.5 py-1.5 text-sm outline-hidden focus:bg-accent/70 focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
"cursor-pointer relative flex select-none items-center rounded-sm px-2.5 py-1.5 text-[.95em] outline-hidden focus:bg-accent/70 focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
inset && "ps-8",
|
||||
className
|
||||
)}
|
||||
@@ -95,7 +95,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 ps-8 pe-2.5 text-sm outline-hidden focus:bg-accent/70 focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 ps-8 pe-2.5 text-[.95em] outline-hidden focus:bg-accent/70 focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
@@ -118,7 +118,7 @@ const DropdownMenuRadioItem = React.forwardRef<
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 ps-8 pe-2.5 text-sm outline-hidden focus:bg-accent/70 focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 ps-8 pe-2.5 text-[.95em] outline-hidden focus:bg-accent/70 focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -141,7 +141,7 @@ const DropdownMenuLabel = React.forwardRef<
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn("px-2.5 py-1.5 text-sm font-semibold", inset && "ps-8", className)}
|
||||
className={cn("px-2.5 py-1.5 text-[.95em] font-semibold", inset && "ps-8", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
@@ -27,7 +27,7 @@ const TabsTrigger = React.forwardRef<
|
||||
<TabsPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-xs cursor-pointer",
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-xs cursor-pointer hover:text-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -147,6 +147,12 @@
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* cosmetic patch for half pixel gap in table headers when scrolling content shows at top */
|
||||
thead.sticky:before {
|
||||
content: "";
|
||||
@apply absolute -top-2 left-0 w-full h-4 bg-table-header z-50
|
||||
}
|
||||
}
|
||||
|
||||
@utility container {
|
||||
@@ -163,6 +169,14 @@
|
||||
min-width: 30.3rem;
|
||||
}
|
||||
|
||||
@utility scrollbar-hide {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.recharts-tooltip-wrapper {
|
||||
z-index: 51;
|
||||
@apply tabular-nums;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { atom, computed, listenKeys, map, type ReadableAtom } from "nanostores"
|
||||
import type { AlertMap, ChartTimes, SystemRecord, UserSettings } from "@/types"
|
||||
import type { AlertMap, ChartTimes, SystemRecord, UpdateInfo, UserSettings } from "@/types"
|
||||
import { pb } from "./api"
|
||||
import { Unit } from "./enums"
|
||||
|
||||
@@ -28,6 +28,9 @@ export const $alerts = map<AlertMap>({})
|
||||
/** SSH public key */
|
||||
export const $publicKey = atom("")
|
||||
|
||||
/** New version info if an update is available, otherwise undefined */
|
||||
export const $newVersion = atom<UpdateInfo | undefined>()
|
||||
|
||||
/** Chart time period */
|
||||
export const $chartTime = atom<ChartTimes>("1h")
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: ar\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\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"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,7 +55,7 @@ msgid "1 hour"
|
||||
msgstr "1 ساعة"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "دقيقة واحدة"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "12 ساعة"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 دقيقة"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "30 يومًا"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 دقائق"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "الحالة النشطة"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "إضافة {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "إضافة <0>نظام</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "إضافة نظام"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "إضافة رابط"
|
||||
@@ -134,6 +135,7 @@ msgstr "تعديل عرض التخطيط الرئيسي"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "مسؤول"
|
||||
|
||||
@@ -163,6 +165,7 @@ msgstr "التنبيهات"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "جميع الحاويات"
|
||||
@@ -188,11 +191,11 @@ msgstr "هل أنت متأكد؟"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "النسخ التلقائي يتطلب سياقًا آمنًا."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "متوسط"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "متوسط استخدام وحدة المعالجة المركزية للحاويات"
|
||||
|
||||
@@ -206,20 +209,20 @@ msgstr "المتوسط ينخفض أقل من <0>{value}{0}</0>"
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "المتوسط يتجاوز <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "متوسط استهلاك طاقة وحدة معالجة الرسوميات"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "متوسط استخدام وحدة المعالجة المركزية على مستوى النظام"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "متوسط استخدام {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "متوسط استغلال محركات GPU"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "متوسط استغلال محركات GPU"
|
||||
msgid "Backups"
|
||||
msgstr "النسخ الاحتياطية"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "عرض النطاق الترددي"
|
||||
@@ -238,7 +241,7 @@ msgstr "عرض النطاق الترددي"
|
||||
msgid "Bat"
|
||||
msgstr "بطارية"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "البطارية"
|
||||
@@ -288,7 +291,7 @@ msgstr "حالة التمهيد"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "بايت (كيلوبايت/ثانية، ميجابايت/ثانية، جيجابايت/ثانية)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "ذاكرة التخزين المؤقت / المخازن المؤقتة"
|
||||
|
||||
@@ -334,7 +337,7 @@ msgstr "تغيير وحدات عرض المقاييس."
|
||||
msgid "Change general application options."
|
||||
msgstr "تغيير خيارات التطبيق العامة."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "الشحن"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "قيد الشحن"
|
||||
msgid "Chart options"
|
||||
msgstr "خيارات الرسم البياني"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "عرض الرسم البياني"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "تحقق من {email} للحصول على رابط إعادة التعيين."
|
||||
@@ -407,6 +414,10 @@ msgstr "التعارضات"
|
||||
msgid "Connection is down"
|
||||
msgstr "الاتصال مقطوع"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "الحاويات"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,6 +473,11 @@ msgstr "انسخ محتوى <0>docker-compose.yml</0> للوكيل أدناه،
|
||||
msgid "Copy YAML"
|
||||
msgstr "نسخ YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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
|
||||
@@ -484,8 +500,8 @@ msgstr "وقت المعالج"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "تفصيل وقت المعالج"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "الرفع التراكمي"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "الحالة الحالية"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "الدورات"
|
||||
msgid "Daily"
|
||||
msgstr "يوميًا"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "الفترة الزمنية الافتراضية"
|
||||
@@ -563,11 +584,12 @@ msgstr "الجهاز"
|
||||
msgid "Discharging"
|
||||
msgstr "قيد التفريغ"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "القرص"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "إدخال/إخراج القرص"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "إدخال/إخراج القرص"
|
||||
msgid "Disk unit"
|
||||
msgstr "وحدة القرص"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "استخدام القرص لـ {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "استخدام المعالج للدوكر"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "استخدام الذاكرة للدوكر"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "إدخال/إخراج الشبكة للدوكر"
|
||||
|
||||
@@ -770,7 +798,7 @@ msgstr "فشل: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "أمر FreeBSD"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "ممتلئة"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "عالمي"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr "معالج الرسوميات"
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "محركات GPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "استهلاك طاقة وحدة معالجة الرسوميات"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "استهلاك طاقة وحدة معالجة الرسوميات"
|
||||
msgid "GPU Usage"
|
||||
msgstr "استخدام وحدة معالجة الرسوميات"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "شبكة"
|
||||
@@ -912,7 +946,7 @@ msgstr "دورة الحياة"
|
||||
msgid "limit"
|
||||
msgstr "الحد"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "متوسط التحميل"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "حالة التحميل"
|
||||
msgid "Loading..."
|
||||
msgstr "جاري التحميل..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "تسجيل الخروج"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "تعليمات الإعداد اليدوي"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "الحد الأقصى دقيقة"
|
||||
|
||||
@@ -999,15 +1034,16 @@ msgstr "حد الذاكرة"
|
||||
msgid "Memory Peak"
|
||||
msgstr "ذروة الذاكرة"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "استخدام الذاكرة"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "استخدام الذاكرة لحاويات دوكر"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "الموديل"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "الاسم"
|
||||
msgid "Net"
|
||||
msgstr "الشبكة"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "حركة مرور الشبكة لحاويات الدوكر"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1220,13 +1256,18 @@ msgstr "يرجى تسجيل الدخول إلى حسابك"
|
||||
msgid "Port"
|
||||
msgstr "المنفذ"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "تشغيل الطاقة"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "الاستخدام الدقيق في الوقت المسجل"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "ساعات الهدوء"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "قراءة"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "تم الاستلام"
|
||||
|
||||
@@ -1326,6 +1367,10 @@ msgstr "تفاصيل S.M.A.R.T."
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "اختبار S.M.A.R.T. الذاتي"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "حفظ {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "احفظ العنوان باستخدام مفتاح الإدخال أو الفاصلة. اتركه فارغًا لتعطيل إشعارات البريد الإشباكي."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "احفظ العنوان باستخدام مفتاح الإدخال أو
|
||||
msgid "Save Settings"
|
||||
msgstr "حفظ الإعدادات"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "احفظ النظام"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "محفوظ في قاعدة البيانات ولا ينتهي حتى تقوم بتعطيله."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "أرسل pings صادرة دورية إلى خدمة مراقبة خار
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "إرسال نبضة قلب اختبارية"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "تم الإرسال"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "الرقم التسلسلي"
|
||||
msgid "Service Details"
|
||||
msgstr "تفاصيل الخدمة"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "الخدمات"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "قم بتعيين متغيرات البيئة التالية على مر
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "الإعدادات"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "الحالة"
|
||||
msgid "Sub State"
|
||||
msgstr "الحالة الفرعية"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "مساحة التبديل المستخدمة من قبل النظام"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "استخدام التبديل"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "استخدام التبديل"
|
||||
msgid "System"
|
||||
msgstr "النظام"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "متوسط تحميل النظام مع مرور الوقت"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "يمكن إدارة الأنظمة في ملف <0>config.yml</0> داخ
|
||||
msgid "Table"
|
||||
msgstr "جدول"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "المهام"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "المهام"
|
||||
msgid "Temp"
|
||||
msgstr "درجة الحرارة"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "درجة الحرارة"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "درجة الحرارة"
|
||||
msgid "Temperature unit"
|
||||
msgstr "وحدة درجة الحرارة"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "درجات حرارة مستشعرات النظام"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ msgstr "لا يمكن التراجع عن هذا الإجراء. سيؤدي ذل
|
||||
msgid "This will permanently delete all selected records from the database."
|
||||
msgstr "سيؤدي هذا إلى حذف جميع السجلات المحددة من قاعدة البيانات بشكل دائم."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "معدل نقل {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "معدل نقل نظام الملفات الجذر"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "تنسيق الوقت"
|
||||
msgid "To email(s)"
|
||||
msgstr "إلى البريد الإشباكي"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "تبديل الشبكة"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1730,20 +1775,20 @@ msgstr "رفع"
|
||||
msgid "Uptime"
|
||||
msgstr "مدة التشغيل"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "الاستخدام"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "استخدام القسم الجذر"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "مستخدم"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "عرض أحدث 200 تنبيه."
|
||||
msgid "Visible Fields"
|
||||
msgstr "الأعمدة الظاهرة"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "في انتظار وجود سجلات كافية للعرض"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "أمر ويندوز"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "كتابة"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: bg\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Bulgarian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,7 +55,7 @@ msgid "1 hour"
|
||||
msgstr "1 час"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 минута"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "12 часа"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 минути"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "30 дни"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 минути"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Активно състояние"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Добави {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Добави <0>Система</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Добави система"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Добави URL"
|
||||
@@ -134,6 +135,7 @@ msgstr "Настройка ширината на основния макет"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Администратор"
|
||||
|
||||
@@ -163,6 +165,7 @@ msgstr "Тревоги"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Всички контейнери"
|
||||
@@ -188,11 +191,11 @@ msgstr "Сигурни ли сте?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Автоматичното копиране изисква защитен контескт."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Средно"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Средно използване на процесора на контейнерите"
|
||||
|
||||
@@ -206,20 +209,20 @@ msgstr "Средната стойност пада под <0>{value}{0}</0>"
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Средната стойност надхвърля <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Средна консумация на ток от графични карти"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Средно използване на процесора на цялата система"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Средно използване на {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Средно използване на GPU двигатели"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Средно използване на GPU двигатели"
|
||||
msgid "Backups"
|
||||
msgstr "Архиви"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bandwidth на мрежата"
|
||||
@@ -238,7 +241,7 @@ msgstr "Bandwidth на мрежата"
|
||||
msgid "Bat"
|
||||
msgstr "Бат"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Батерия"
|
||||
@@ -288,7 +291,7 @@ msgstr "Състояние при зареждане"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Байта (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Кеш / Буфери"
|
||||
|
||||
@@ -334,7 +337,7 @@ msgstr "Промяна на единиците за показване на ме
|
||||
msgid "Change general application options."
|
||||
msgstr "Смени общите опции на приложението."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Заряд"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Зареждане"
|
||||
msgid "Chart options"
|
||||
msgstr "Опции на диаграмата"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Ширина на графиката"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Провери {email} за линк за нулиране."
|
||||
@@ -357,7 +364,7 @@ msgstr "Провери log-овете за повече информация."
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Check your monitoring service"
|
||||
msgstr "Проверете вашата услуга за мониторинг"
|
||||
msgstr "Проверете мониторинг услугата си"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Check your notification service"
|
||||
@@ -407,6 +414,10 @@ msgstr "Конфликти"
|
||||
msgid "Connection is down"
|
||||
msgstr "Връзката е прекъсната"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Контейнери"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,6 +473,11 @@ msgstr "Копирайте съдържанието на<0>docker-compose.yml</0
|
||||
msgid "Copy YAML"
|
||||
msgstr "Копирай YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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
|
||||
@@ -484,8 +500,8 @@ msgstr "Време на CPU"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Разбивка на времето на CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Кумулативно качване"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Текущо състояние"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Цикли"
|
||||
msgid "Daily"
|
||||
msgstr "Дневно"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Времеви диапазон по подразбиране"
|
||||
@@ -563,11 +584,12 @@ msgstr "Устройство"
|
||||
msgid "Discharging"
|
||||
msgstr "Разреждане"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Диск"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Диск I/O"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "Диск I/O"
|
||||
msgid "Disk unit"
|
||||
msgstr "Единица за диск"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Изполване на диск от {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Използване на процесор от docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Изполване на памет от docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Мрежов I/O използван от docker"
|
||||
|
||||
@@ -770,7 +798,7 @@ msgstr "Неуспешни: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "FreeBSD команда"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Пълна"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "Глобален"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU двигатели"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Консумация на ток от графична карта"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "Консумация на ток от графична карта"
|
||||
msgid "GPU Usage"
|
||||
msgstr "Употреба на GPU"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Мрежово"
|
||||
@@ -836,7 +870,7 @@ msgstr "Здраве"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -912,7 +946,7 @@ msgstr "Жизнен цикъл"
|
||||
msgid "limit"
|
||||
msgstr "лимит"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Средно натоварване"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Състояние на зареждане"
|
||||
msgid "Loading..."
|
||||
msgstr "Зареждане..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Изход"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Инструкции за ръчна настройка"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Максимум 1 минута"
|
||||
|
||||
@@ -999,15 +1034,16 @@ msgstr "Лимит на памет"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Пик на памет"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Употреба на паметта"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Използването на памет от docker контейнерите"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Модел"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Име"
|
||||
msgid "Net"
|
||||
msgstr "Мрежа"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Мрежов трафик на docker контейнери"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1220,13 +1256,18 @@ msgstr "Моля влез в акаунта ти"
|
||||
msgid "Port"
|
||||
msgstr "Порт"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Включване"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Точно използване в записаното време"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Тихи часове"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Прочети"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Получени"
|
||||
|
||||
@@ -1326,6 +1367,10 @@ msgstr "S.M.A.R.T. Детайли"
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. Самотест"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Запази {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Запази адреса с enter или запетая. Остави празно за да изключиш нотификациите чрез имейл."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Запази адреса с enter или запетая. Остави
|
||||
msgid "Save Settings"
|
||||
msgstr "Запази настройките"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Запази система"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Запазен е в базата данни и не изтича, докато не го деактивирате."
|
||||
@@ -1377,7 +1418,7 @@ msgstr "Избери {foo}"
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Send a single heartbeat ping to verify your endpoint is working."
|
||||
msgstr "Изпратете единичен heartbeat пинг, за да проверите дали вашата крайна точка работи."
|
||||
msgstr "Изпратете единичен heartbeat пинг, за да се уверите, че крайната Ви точка работи."
|
||||
|
||||
#: 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."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Изпращайте периодични изходящи пингов
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Изпращане на тестов heartbeat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Изпратени"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Сериен номер"
|
||||
msgid "Service Details"
|
||||
msgstr "Детайли на услугата"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Услуги"
|
||||
@@ -1409,13 +1451,15 @@ 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
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Настройки"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "Статус"
|
||||
msgid "Sub State"
|
||||
msgstr "Подсъстояние"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Изполван swap от системата"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Използване на swap"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "Използване на swap"
|
||||
msgid "System"
|
||||
msgstr "Система"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Средно натоварване на системата във времето"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "Системите могат да бъдат управлявани в
|
||||
msgid "Table"
|
||||
msgstr "Таблица"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Задачи"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "Задачи"
|
||||
msgid "Temp"
|
||||
msgstr "Температура"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Температура"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "Температура"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Единица за температура"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Температири на системни сензори"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ msgstr "Това действие не може да бъде отменено.
|
||||
msgid "This will permanently delete all selected records from the database."
|
||||
msgstr "Това ще доведе до трайно изтриване на всички избрани записи от базата данни."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Пропускателна способност на {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Пропускателна способност на root файловата система"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Формат на времето"
|
||||
msgid "To email(s)"
|
||||
msgstr "До имейл(ите)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Превключване на мрежа"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1728,22 +1773,22 @@ msgstr "Качване"
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Uptime"
|
||||
msgstr "Uptime"
|
||||
msgstr "Време на работа"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Употреба"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Употреба на root partition-а"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Използвани"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Прегледайте последните си 200 сигнала."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Видими полета"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Изчаква се за достатъчно записи за показване"
|
||||
|
||||
@@ -1799,11 +1844,11 @@ msgstr "Webhook / Пуш нотификации"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "When enabled, this token allows agents to self-register without prior system creation."
|
||||
msgstr "Когато е активиран, този символ позволява на агентите да се регистрират сами без предварително създаване на система."
|
||||
msgstr "Когато е активиран, този токен позволява на агентите да се регистрират сами без предварително създаване на система."
|
||||
|
||||
#: 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 полезен товар с резюме на състоянието на системата, списък на спрените системи и задействаните предупреждения."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Команда Windows"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Запиши"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: cs\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Czech\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 3;\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,9 +55,9 @@ msgid "1 hour"
|
||||
msgstr "1 hodina"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 minute"
|
||||
@@ -66,9 +72,9 @@ msgid "12 hours"
|
||||
msgstr "12 hodin"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "24 hours"
|
||||
@@ -79,9 +85,9 @@ msgid "30 days"
|
||||
msgstr "30 dní"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 min"
|
||||
msgstr ""
|
||||
|
||||
#. Table column
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Aktivní stav"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Přidat {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Přidat <0>Systém</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Přidat systém"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Přidat URL"
|
||||
@@ -134,6 +135,7 @@ msgstr "Upravit šířku hlavního rozvržení"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Administrátor"
|
||||
|
||||
@@ -147,7 +149,7 @@ msgstr "Po nastavení proměnných prostředí restartujte hub Beszel, aby se zm
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -163,6 +165,7 @@ msgstr "Výstrahy"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Všechny kontejnery"
|
||||
@@ -188,11 +191,11 @@ msgstr "Jste si jistý?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatická kopie vyžaduje zabezpečený kontext."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Průměr"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Průměrné využití CPU kontejnerů"
|
||||
|
||||
@@ -206,20 +209,20 @@ 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.tsx
|
||||
#: 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.tsx
|
||||
#: 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"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Průměrné využití {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Průměrné využití GPU engine"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Průměrné využití GPU engine"
|
||||
msgid "Backups"
|
||||
msgstr "Zálohy"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Přenos"
|
||||
@@ -236,9 +239,9 @@ msgstr "Přenos"
|
||||
#. Battery label in systems table header
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Bat"
|
||||
msgstr "Bat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Baterie"
|
||||
@@ -288,7 +291,7 @@ msgstr "Stav zavádění"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Byty (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / vyrovnávací paměť"
|
||||
|
||||
@@ -334,7 +337,7 @@ msgstr "Změnit jednotky zobrazení metrik."
|
||||
msgid "Change general application options."
|
||||
msgstr "Změnit obecné nastavení aplikace."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Nabíjení"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Nabíjení"
|
||||
msgid "Chart options"
|
||||
msgstr "Možnosti grafu"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Šířka grafu"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Zkontrolujte {email} pro odkaz na obnovení."
|
||||
@@ -407,6 +414,10 @@ msgstr "Konflikty"
|
||||
msgid "Connection is down"
|
||||
msgstr "Připojení je nedostupné"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Kontejnery"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,6 +473,11 @@ msgstr "Zkopírujte obsah <0>docker-compose.yml</0> pro agenta níže nebo autom
|
||||
msgid "Copy YAML"
|
||||
msgstr "Kopírovat YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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
|
||||
@@ -484,8 +500,8 @@ msgstr "Čas CPU"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Rozdělení času CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Kumulativní odeslání"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Aktuální stav"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Cykly"
|
||||
msgid "Daily"
|
||||
msgstr "Denně"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Výchozí doba"
|
||||
@@ -552,7 +573,7 @@ msgstr "Popis"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Detail"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
@@ -563,37 +584,44 @@ msgstr "Zařízení"
|
||||
msgid "Discharging"
|
||||
msgstr "Vybíjení"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
msgstr "I/O disku"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Disk unit"
|
||||
msgstr "Disková jednotka"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Využití disku {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Využití CPU Dockeru"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Využití paměti Dockeru"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Síťové I/O Dockeru"
|
||||
|
||||
@@ -770,7 +798,7 @@ msgstr "Neúspěšné: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -783,7 +811,7 @@ msgstr "Otisk"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "FreeBSD příkaz"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Plná"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "Globální"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU enginy"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Spotřeba energie GPU"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "Spotřeba energie GPU"
|
||||
msgid "GPU Usage"
|
||||
msgstr "Využití GPU"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Mřížka"
|
||||
@@ -836,7 +870,7 @@ msgstr "Zdraví"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -884,7 +918,7 @@ msgstr "Neaktivní"
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Interval"
|
||||
msgstr "Interval"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Invalid email address."
|
||||
@@ -910,9 +944,9 @@ msgstr "Životní cyklus"
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "limit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Průměrné vytížení"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Stav načtení"
|
||||
msgid "Loading..."
|
||||
msgstr "Načítání..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Odhlásit"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Pokyny k manuálnímu nastavení"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max. 1 min"
|
||||
|
||||
@@ -999,18 +1034,19 @@ msgstr "Limit paměti"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Špička paměti"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Využití paměti"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Využití paměti docker kontejnerů"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Název"
|
||||
msgid "Net"
|
||||
msgstr "Síť"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Síťový provoz kontejnerů docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1218,15 +1254,20 @@ msgstr "Přihlaste se prosím k vašemu účtu"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Zapnutí"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Přesné využití v zaznamenaném čase"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Tiché hodiny"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Číst"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Přijato"
|
||||
|
||||
@@ -1326,6 +1367,10 @@ msgstr "S.M.A.R.T. Detaily"
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. Vlastní test"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Uložit {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Adresu uložte pomocí klávesy enter nebo čárky. Pro deaktivaci e-mailových oznámení ponechte prázdné pole."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Adresu uložte pomocí klávesy enter nebo čárky. Pro deaktivaci e-mai
|
||||
msgid "Save Settings"
|
||||
msgstr "Uložit nastavení"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Uložit systém"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Uložen v databázi a nevyprší, dokud jej nezablokujete."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Odesílejte periodické odchozí pingy na externí monitorovací službu
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Odeslat testovací heartbeat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Odeslat"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Sériové číslo"
|
||||
msgid "Service Details"
|
||||
msgstr "Detaily služby"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Služby"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Pro povolení monitorování heartbeat nastavte na hubu Beszel následuj
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Nastavení"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "Stav"
|
||||
msgid "Sub State"
|
||||
msgstr "Podstav"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap prostor využívaný systémem"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap využití"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "Swap využití"
|
||||
msgid "System"
|
||||
msgstr "Systém"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Průměry zatížení systému v průběhu času"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "Systémy lze spravovat v souboru <0>config.yml</0> uvnitř datového adr
|
||||
msgid "Table"
|
||||
msgstr "Tabulka"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Úlohy"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "Úlohy"
|
||||
msgid "Temp"
|
||||
msgstr "Teplota"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Teplota"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "Teplota"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Jednotky teploty"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Teploty systémových senzorů"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Propustnost {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Propustnost kořenového souborového systému"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Formát času"
|
||||
msgid "To email(s)"
|
||||
msgstr "Na email(y)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Přepnout mřížku"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1581,7 +1626,7 @@ msgstr "Přepnout motiv"
|
||||
#: 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
|
||||
@@ -1728,22 +1773,22 @@ msgstr "Odeslání"
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Uptime"
|
||||
msgstr "Uptime"
|
||||
msgstr "Doba provozu"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Využití"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Využití kořenového oddílu"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Využito"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Zobrazit vašich 200 nejnovějších upozornění."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Viditelné sloupce"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Čeká se na dostatek záznamů k zobrazení"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Windows příkaz"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Psát"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: da\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Danish\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,7 +55,7 @@ msgid "1 hour"
|
||||
msgstr "1 time"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 minut"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "12 timer"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 minutter"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "30 dage"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 minutter"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Aktiv tilstand"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Tilføj {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Tilføj <0>System</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Tilføj system"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Tilføj URL"
|
||||
@@ -134,6 +135,7 @@ msgstr "Juster bredden af hovedlayoutet"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Administrator"
|
||||
|
||||
@@ -147,7 +149,7 @@ msgstr "Efter indstilling af miljøvariablerne skal du genstarte din Beszel-hub
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -163,6 +165,7 @@ msgstr "Alarmer"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Alle containere"
|
||||
@@ -188,11 +191,11 @@ msgstr "Er du sikker?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatisk kopiering kræver en sikker kontekst."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Gennemsnitlig"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Gennemsnitlig CPU udnyttelse af containere"
|
||||
|
||||
@@ -206,20 +209,20 @@ 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.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Gennemsnitlig systembaseret CPU-udnyttelse"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Gennemsnitlig udnyttelse af {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Gennemsnitlig udnyttelse af GPU-enheder"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Gennemsnitlig udnyttelse af GPU-enheder"
|
||||
msgid "Backups"
|
||||
msgstr "Sikkerhedskopier"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Båndbredde"
|
||||
@@ -236,9 +239,9 @@ msgstr "Båndbredde"
|
||||
#. Battery label in systems table header
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Bat"
|
||||
msgstr "Bat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Batteri"
|
||||
@@ -277,7 +280,7 @@ msgstr "Binær"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
@@ -286,9 +289,9 @@ msgstr "Opstartstilstand"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffere"
|
||||
|
||||
@@ -324,7 +327,7 @@ msgstr "Forsigtig - muligt tab af data"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr "Celsius (°C)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
@@ -334,7 +337,7 @@ msgstr "Ændre viste enheder for målinger."
|
||||
msgid "Change general application options."
|
||||
msgstr "Skift generelle applikationsindstillinger."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Opladning"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Oplader"
|
||||
msgid "Chart options"
|
||||
msgstr "Diagrammuligheder"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Grafbredde"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Tjek {email} for et nulstillingslink."
|
||||
@@ -407,6 +414,10 @@ msgstr "Konflikter"
|
||||
msgid "Connection is down"
|
||||
msgstr "Forbindelsen er nede"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Containere"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,11 +473,16 @@ msgstr "Kopier <0>docker-compose.yml</0> indholdet for agenten nedenfor, eller r
|
||||
msgid "Copy YAML"
|
||||
msgstr "Kopier YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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"
|
||||
@@ -474,7 +490,7 @@ msgstr "CPU-kerner"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "CPU Peak"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
@@ -484,8 +500,8 @@ msgstr "CPU tid"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU-tidsfordeling"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Kumulativ upload"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Nuværende tilstand"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Cykler"
|
||||
msgid "Daily"
|
||||
msgstr "Dagligt"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Standard tidsperiode"
|
||||
@@ -563,37 +584,44 @@ msgstr "Enhed"
|
||||
msgid "Discharging"
|
||||
msgstr "Aflader"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Disk unit"
|
||||
msgstr "Diskenhed"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Diskforbrug af {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU forbrug"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker Hukommelsesforbrug"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker Netværk I/O"
|
||||
|
||||
@@ -636,7 +664,7 @@ msgstr "Rediger {foo}"
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
#: src/components/login/otp-forms.tsx
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Email notifications"
|
||||
@@ -731,7 +759,7 @@ msgstr "Eksporter din nuværende systemkonfiguration."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Failed"
|
||||
@@ -770,12 +798,12 @@ msgstr "Mislykkedes: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Fingerprint"
|
||||
@@ -783,7 +811,7 @@ msgstr "Fingeraftryk"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "FreeBSD kommando"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Fuldt opladt"
|
||||
@@ -812,13 +841,17 @@ msgstr "Generelt"
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Global"
|
||||
msgstr "Global"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU-enheder"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU Strøm Træk"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "GPU Strøm Træk"
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU-forbrug"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Gitter"
|
||||
@@ -836,7 +870,7 @@ msgstr "Sundhed"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -884,7 +918,7 @@ msgstr "Inaktiv"
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Interval"
|
||||
msgstr "Interval"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Invalid email address."
|
||||
@@ -912,7 +946,7 @@ msgstr "Livscyklus"
|
||||
msgid "limit"
|
||||
msgstr "grænse"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Belastning Gennemsnitlig"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Indlæsningstilstand"
|
||||
msgid "Loading..."
|
||||
msgstr "Indlæser..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Log ud"
|
||||
@@ -958,7 +993,7 @@ msgstr "Loginforsøg mislykkedes"
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Logs"
|
||||
msgstr "Logs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Manuel opsætningsvejledning"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Maks. 1 min"
|
||||
|
||||
@@ -999,18 +1034,19 @@ msgstr "Hukommelsesgrænse"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Hukommelsesspids"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Hukommelsesforbrug"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Hukommelsesforbrug af dockercontainere"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
@@ -1023,13 +1059,13 @@ msgstr "Navn"
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Net"
|
||||
msgstr "Net"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Netværkstrafik af dockercontainere"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1152,7 +1188,7 @@ msgstr "Tidligere"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Paused"
|
||||
@@ -1177,7 +1213,7 @@ msgstr "Procentdel af tid brugt i hver tilstand"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Permanent"
|
||||
msgstr "Permanent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Persistence"
|
||||
@@ -1218,15 +1254,20 @@ msgstr "Log venligst ind på din konto"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Tænd"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Præcis udnyttelse på det registrerede tidspunkt"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Stille timer"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Læs"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Modtaget"
|
||||
|
||||
@@ -1304,7 +1345,7 @@ msgstr "Genoptag"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
@@ -1326,6 +1367,10 @@ msgstr "S.M.A.R.T.-detaljer"
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. selvtest"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Gem {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Gem adresse ved hjælp af enter eller komma. Lad feltet stå tomt for at deaktivere e-mail-meddelelser."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Gem adresse ved hjælp af enter eller komma. Lad feltet stå tomt for at
|
||||
msgid "Save Settings"
|
||||
msgstr "Gem indstillinger"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Gem system"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Gemt i databasen og udløber ikke, før du deaktiverer det."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Send periodiske udgående pings til en ekstern overvågningstjeneste, s
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Send test-heartbeat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Sendt"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Serienummer"
|
||||
msgid "Service Details"
|
||||
msgstr "Tjenestedetaljer"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Tjenester"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Indstil følgende miljøvariabler på din Beszel-hub for at aktivere hea
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Indstillinger"
|
||||
|
||||
@@ -1453,23 +1497,24 @@ msgstr "Tilstand"
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Undertilstand"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap plads brugt af systemet"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap forbrug"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1479,15 +1524,15 @@ msgstr "Swap forbrug"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Gennemsnitlig system belastning over tid"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Systemd Services"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
@@ -1501,6 +1546,11 @@ msgstr "Systemer kan være administreres i filen <0>config.yml</0> i din datamap
|
||||
msgid "Table"
|
||||
msgstr "Tabel"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Opgaver"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "Opgaver"
|
||||
msgid "Temp"
|
||||
msgstr "Temperatur"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatur"
|
||||
@@ -1520,13 +1570,13 @@ msgstr "Temperatur"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Temperaturenhed"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturer i systemsensorer"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Test heartbeat"
|
||||
@@ -1552,11 +1602,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Gennemløb af {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Gennemløb af rodfilsystemet"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Tidsformat"
|
||||
msgid "To email(s)"
|
||||
msgstr "Til email(s)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Slå gitter til/fra"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1671,7 +1716,7 @@ msgstr "Udløser når brugen af en disk overstiger en tærskel"
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
@@ -1730,20 +1775,20 @@ msgstr "Overfør"
|
||||
msgid "Uptime"
|
||||
msgstr "Oppetid"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Forbrug"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Brug af rodpartition"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Brugt"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Se dine 200 nyeste alarmer."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Synlige felter"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Venter på nok posteringer til at vise"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Windows-kommando"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Skriv"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: de\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-14 20:37\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: German\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,7 +55,7 @@ msgid "1 hour"
|
||||
msgstr "1 Stunde"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 Min"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "12 Stunden"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 Min"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "30 Tage"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 Min"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Aktiver Zustand"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "{foo} hinzufügen"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>System</0> hinzufügen"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "System hinzufügen"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "URL hinzufügen"
|
||||
@@ -134,8 +135,9 @@ msgstr "Breite des Hauptlayouts anpassen"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
@@ -147,7 +149,7 @@ msgstr "Starten Sie nach dem Festlegen der Umgebungsvariablen Ihren Beszel-Hub n
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -163,6 +165,7 @@ msgstr "Warnungen"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Alle Container"
|
||||
@@ -188,11 +191,11 @@ msgstr "Bist du sicher?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatisches Kopieren erfordert einen sicheren Kontext."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Durchschnitt"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Durchschnittliche CPU-Auslastung der Container"
|
||||
|
||||
@@ -206,29 +209,29 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Durchschnittlicher Stromverbrauch der GPUs"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Durchschnittliche systemweite CPU-Auslastung"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Durchschnittliche Auslastung von {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Durchschnittliche Auslastung der GPU-Engines"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Backups"
|
||||
msgstr "Backups"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bandbreite"
|
||||
@@ -236,9 +239,9 @@ msgstr "Bandbreite"
|
||||
#. Battery label in systems table header
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Bat"
|
||||
msgstr "Bat"
|
||||
msgstr "Batt"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Batterie"
|
||||
@@ -277,7 +280,7 @@ msgstr "Binär"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
@@ -286,9 +289,9 @@ msgstr "Boot-Zustand"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Puffer"
|
||||
|
||||
@@ -324,7 +327,7 @@ msgstr "Vorsicht - potenzieller Datenverlust"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr "Celsius (°C)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
@@ -334,7 +337,7 @@ msgstr "Anzeigeeinheiten der Werte ändern."
|
||||
msgid "Change general application options."
|
||||
msgstr "Allgemeine Anwendungsoptionen ändern."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Ladung"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Wird geladen"
|
||||
msgid "Chart options"
|
||||
msgstr "Diagrammoptionen"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Diagrammbreite"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Überprüfe {email} auf einen Link zum Zurücksetzen."
|
||||
@@ -407,6 +414,10 @@ msgstr "Konflikte"
|
||||
msgid "Connection is down"
|
||||
msgstr "Verbindung unterbrochen"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Container"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,11 +473,16 @@ msgstr "Kopiere den<0>docker-compose.yml</0> Inhalt für den Agent unten oder re
|
||||
msgid "Copy YAML"
|
||||
msgstr "YAML kopieren"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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"
|
||||
@@ -484,8 +500,8 @@ msgstr "CPU-Zeit"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU-Zeit-Aufschlüsselung"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Kumulativer Upload"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Aktueller Zustand"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Zyklen"
|
||||
msgid "Daily"
|
||||
msgstr "Täglich"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Standardzeitraum"
|
||||
@@ -563,11 +584,12 @@ msgstr "Gerät"
|
||||
msgid "Discharging"
|
||||
msgstr "Wird entladen"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Festplatte"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Festplatten-I/O"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "Festplatten-I/O"
|
||||
msgid "Disk unit"
|
||||
msgstr "Festplatteneinheit"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Festplattennutzung von {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker-CPU-Auslastung"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker-Arbeitsspeichernutzung"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker-Netzwerk-I/O"
|
||||
|
||||
@@ -731,7 +759,7 @@ msgstr "Exportiere die aktuelle Systemkonfiguration."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Failed"
|
||||
@@ -770,12 +798,12 @@ msgstr "Fehlgeschlagen: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Fingerprint"
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "FreeBSD Befehl"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Voll"
|
||||
@@ -812,13 +841,17 @@ msgstr "Allgemein"
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Global"
|
||||
msgstr "Global"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU-Engines"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU-Leistungsaufnahme"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "GPU-Leistungsaufnahme"
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU-Auslastung"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Raster"
|
||||
@@ -836,7 +870,7 @@ msgstr "Gesundheit"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -854,7 +888,7 @@ msgstr "Homebrew-Befehl"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "HTTP Method"
|
||||
@@ -876,7 +910,7 @@ msgstr "Wenn du das Passwort für dein Administratorkonto verloren hast, kannst
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Docker image"
|
||||
msgid "Image"
|
||||
msgstr "Image"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Inactive"
|
||||
@@ -912,7 +946,7 @@ msgstr "Lebenszyklus"
|
||||
msgid "limit"
|
||||
msgstr "Limit"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Durchschnittliche Systemlast"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Ladezustand"
|
||||
msgid "Loading..."
|
||||
msgstr "Lädt..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Abmelden"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Anleitung zur manuellen Einrichtung"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 Min"
|
||||
|
||||
@@ -999,15 +1034,16 @@ msgstr "Arbeitsspeicherlimit"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Arbeitsspeicher-Spitze"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Arbeitsspeichernutzung"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Arbeitsspeichernutzung der Docker-Container"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modell"
|
||||
@@ -1018,18 +1054,18 @@ msgstr "Modell"
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Net"
|
||||
msgstr "Netzwerk"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Netzwerkverkehr der Docker-Container"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1152,7 +1188,7 @@ msgstr "Vergangen"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Paused"
|
||||
@@ -1177,7 +1213,7 @@ msgstr "Prozentsatz der Zeit in jedem Zustand"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Permanent"
|
||||
msgstr "Permanent"
|
||||
msgstr "Dauerhaft"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Persistence"
|
||||
@@ -1218,15 +1254,20 @@ msgstr "Bitte melde dich bei deinem Konto an"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Eingeschaltet"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Genaue Nutzung zum aufgezeichneten Zeitpunkt"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Ruhezeiten"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Lesen"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Empfangen"
|
||||
|
||||
@@ -1304,7 +1345,7 @@ msgstr "Fortsetzen"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
@@ -1326,6 +1367,10 @@ msgstr "S.M.A.R.T.-Details"
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T.-Selbsttest"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "{foo} speichern"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Adresse mit der Enter-Taste oder Komma speichern. Leer lassen, um E-Mail-Benachrichtigungen zu deaktivieren."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Adresse mit der Enter-Taste oder Komma speichern. Leer lassen, um E-Mail
|
||||
msgid "Save Settings"
|
||||
msgstr "Einstellungen speichern"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "System speichern"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "In der Datenbank gespeichert und läuft nicht ab, bis Sie es deaktivieren."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Senden Sie regelmäßige ausgehende Pings an einen externen Überwachung
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Test-Heartbeat senden"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Gesendet"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Seriennummer"
|
||||
msgid "Service Details"
|
||||
msgstr "Servicedetails"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Dienste"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Legen Sie die folgenden Umgebungsvariablen auf Ihrem Beszel-Hub fest, um
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
@@ -1453,23 +1497,24 @@ msgstr "Status"
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Unterzustand"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Vom System genutzter Swap-Speicher"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap-Nutzung"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1479,9 +1524,9 @@ msgstr "Swap-Nutzung"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Systemlastdurchschnitt im Zeitverlauf"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "Systeme können in einer <0>config.yml</0>-Datei im Datenverzeichnis ver
|
||||
msgid "Table"
|
||||
msgstr "Tabelle"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Aufgaben"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "Aufgaben"
|
||||
msgid "Temp"
|
||||
msgstr "Temperatur"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatur"
|
||||
@@ -1520,13 +1570,13 @@ msgstr "Temperatur"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Temperatureinheit"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturen der Systemsensoren"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Test heartbeat"
|
||||
@@ -1552,11 +1602,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Durchsatz von {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Durchsatz des Root-Dateisystems"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Zeitformat"
|
||||
msgid "To email(s)"
|
||||
msgstr "An E-Mail(s)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Raster umschalten"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1581,7 +1626,7 @@ msgstr "Darstellung umschalten"
|
||||
#: 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
|
||||
@@ -1730,20 +1775,20 @@ msgstr "Hochladen"
|
||||
msgid "Uptime"
|
||||
msgstr "Betriebszeit"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Nutzung"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Nutzung der Root-Partition"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Verwendet"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Sieh dir die neusten 200 Alarme an."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Sichtbare Spalten"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Warten auf genügend Datensätze zur Anzeige"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Windows-Befehl"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Schreiben"
|
||||
|
||||
|
||||
@@ -13,6 +13,12 @@ msgstr ""
|
||||
"Language-Team: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr "{0} available"
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -44,7 +50,7 @@ msgid "1 hour"
|
||||
msgstr "1 hour"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 min"
|
||||
|
||||
@@ -61,7 +67,7 @@ msgid "12 hours"
|
||||
msgstr "12 hours"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 min"
|
||||
|
||||
@@ -74,7 +80,7 @@ msgid "30 days"
|
||||
msgstr "30 days"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 min"
|
||||
|
||||
@@ -102,19 +108,14 @@ msgid "Active state"
|
||||
msgstr "Active state"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Add {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Add <0>System</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Add system"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Add URL"
|
||||
@@ -129,6 +130,7 @@ msgstr "Adjust the width of the main layout"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
@@ -158,6 +160,7 @@ msgstr "Alerts"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "All Containers"
|
||||
@@ -183,11 +186,11 @@ msgstr "Are you sure?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatic copy requires a secure context."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Average"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Average CPU utilization of containers"
|
||||
|
||||
@@ -201,20 +204,20 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Average power consumption of GPUs"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Average system-wide CPU utilization"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Average utilization of {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Average utilization of GPU engines"
|
||||
|
||||
@@ -223,7 +226,7 @@ msgstr "Average utilization of GPU engines"
|
||||
msgid "Backups"
|
||||
msgstr "Backups"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bandwidth"
|
||||
@@ -233,7 +236,7 @@ msgstr "Bandwidth"
|
||||
msgid "Bat"
|
||||
msgstr "Bat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Battery"
|
||||
@@ -283,7 +286,7 @@ msgstr "Boot state"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Bytes (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffers"
|
||||
|
||||
@@ -329,7 +332,7 @@ msgstr "Change display units for metrics."
|
||||
msgid "Change general application options."
|
||||
msgstr "Change general application options."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Charge"
|
||||
|
||||
@@ -342,6 +345,10 @@ msgstr "Charging"
|
||||
msgid "Chart options"
|
||||
msgstr "Chart options"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Chart width"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Check {email} for a reset link."
|
||||
@@ -402,6 +409,10 @@ msgstr "Conflicts"
|
||||
msgid "Connection is down"
|
||||
msgstr "Connection is down"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Containers"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -457,6 +468,11 @@ msgstr "Copy the<0>docker-compose.yml</0> content for the agent below, or regist
|
||||
msgid "Copy YAML"
|
||||
msgstr "Copy YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
msgstr "Core"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -479,8 +495,8 @@ msgstr "CPU time"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU Time Breakdown"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -512,7 +528,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Cumulative Upload"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Current state"
|
||||
|
||||
@@ -526,6 +542,11 @@ msgstr "Cycles"
|
||||
msgid "Daily"
|
||||
msgstr "Daily"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr "Default"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Default time period"
|
||||
@@ -558,11 +579,12 @@ msgstr "Device"
|
||||
msgid "Discharging"
|
||||
msgstr "Discharging"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
|
||||
@@ -570,25 +592,31 @@ msgstr "Disk I/O"
|
||||
msgid "Disk unit"
|
||||
msgstr "Disk unit"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Disk usage of {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr "Display"
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU Usage"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker Memory Usage"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker Network I/O"
|
||||
|
||||
@@ -765,7 +793,7 @@ msgstr "Failed: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -795,6 +823,7 @@ msgid "FreeBSD command"
|
||||
msgstr "FreeBSD command"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Full"
|
||||
@@ -810,10 +839,14 @@ msgid "Global"
|
||||
msgstr "Global"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr "GPU"
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU Engines"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU Power Draw"
|
||||
|
||||
@@ -821,6 +854,7 @@ msgstr "GPU Power Draw"
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU Usage"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Grid"
|
||||
@@ -907,7 +941,7 @@ msgstr "Lifecycle"
|
||||
msgid "limit"
|
||||
msgstr "limit"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Load Average"
|
||||
|
||||
@@ -936,6 +970,7 @@ msgstr "Load state"
|
||||
msgid "Loading..."
|
||||
msgstr "Loading..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Log Out"
|
||||
@@ -973,7 +1008,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Manual setup instructions"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
@@ -994,15 +1029,16 @@ msgstr "Memory limit"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Memory Peak"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Memory Usage"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Memory usage of docker containers"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
@@ -1020,11 +1056,11 @@ msgstr "Name"
|
||||
msgid "Net"
|
||||
msgstr "Net"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Network traffic of docker containers"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1215,13 +1251,18 @@ msgstr "Please sign in to your account"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr "Ports"
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Power On"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Precise utilization at the recorded time"
|
||||
|
||||
@@ -1243,12 +1284,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Quiet Hours"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Read"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Received"
|
||||
|
||||
@@ -1321,6 +1362,10 @@ msgstr "S.M.A.R.T. Details"
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. Self-Test"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Save {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
@@ -1330,10 +1375,6 @@ msgstr "Save address using enter key or comma. Leave blank to disable email noti
|
||||
msgid "Save Settings"
|
||||
msgstr "Save Settings"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Save system"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Saved in the database and does not expire until you disable it."
|
||||
@@ -1382,7 +1423,7 @@ msgstr "Send periodic outbound pings to an external monitoring service so you ca
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Send test heartbeat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Sent"
|
||||
|
||||
@@ -1394,6 +1435,7 @@ msgstr "Serial Number"
|
||||
msgid "Service Details"
|
||||
msgstr "Service Details"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Services"
|
||||
@@ -1409,8 +1451,10 @@ msgstr "Set the following environment variables on your Beszel hub to enable hea
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Settings"
|
||||
|
||||
@@ -1454,17 +1498,18 @@ msgstr "Status"
|
||||
msgid "Sub State"
|
||||
msgstr "Sub State"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap space used by the system"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap Usage"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1476,7 +1521,7 @@ msgstr "Swap Usage"
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "System load averages over time"
|
||||
|
||||
@@ -1496,6 +1541,11 @@ msgstr "Systems may be managed in a <0>config.yml</0> file inside your data dire
|
||||
msgid "Table"
|
||||
msgstr "Table"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr "Tabs"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Tasks"
|
||||
@@ -1506,7 +1556,7 @@ msgstr "Tasks"
|
||||
msgid "Temp"
|
||||
msgstr "Temp"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Temperature"
|
||||
@@ -1515,7 +1565,7 @@ msgstr "Temperature"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Temperature unit"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperatures of system sensors"
|
||||
|
||||
@@ -1547,11 +1597,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Throughput of {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Throughput of root filesystem"
|
||||
|
||||
@@ -1563,11 +1613,6 @@ msgstr "Time format"
|
||||
msgid "To email(s)"
|
||||
msgstr "To email(s)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Toggle grid"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1725,20 +1770,20 @@ msgstr "Upload"
|
||||
msgid "Uptime"
|
||||
msgstr "Uptime"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Usage"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Usage of root partition"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Used"
|
||||
|
||||
@@ -1768,7 +1813,7 @@ msgstr "View your 200 most recent alerts."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Visible Fields"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Waiting for enough records to display"
|
||||
|
||||
@@ -1807,8 +1852,8 @@ msgid "Windows command"
|
||||
msgstr "Windows command"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Write"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: es\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Spanish\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,9 +55,9 @@ msgid "1 hour"
|
||||
msgstr "1 hora"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 minute"
|
||||
@@ -66,9 +72,9 @@ msgid "12 hours"
|
||||
msgstr "12 horas"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "24 hours"
|
||||
@@ -79,9 +85,9 @@ msgid "30 days"
|
||||
msgstr "30 días"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 min"
|
||||
msgstr ""
|
||||
|
||||
#. Table column
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Estado activo"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Agregar {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Agregar <0>sistema</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Agregar sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Agregar URL"
|
||||
@@ -134,6 +135,7 @@ msgstr "Ajustar el ancho del diseño principal"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Administrador"
|
||||
|
||||
@@ -163,6 +165,7 @@ msgstr "Alertas"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Todos los contenedores"
|
||||
@@ -188,11 +191,11 @@ msgstr "¿Estás seguro?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "La copia automática requiere un contexto seguro."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Promedio"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Utilización promedio de CPU de los contenedores"
|
||||
|
||||
@@ -206,20 +209,20 @@ 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.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Utilización promedio de CPU del sistema"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Uso promedio de {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Utilización promedio de motores GPU"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Utilización promedio de motores GPU"
|
||||
msgid "Backups"
|
||||
msgstr "Copias de seguridad"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Ancho de banda"
|
||||
@@ -236,9 +239,9 @@ msgstr "Ancho de banda"
|
||||
#. Battery label in systems table header
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Bat"
|
||||
msgstr "Bat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Batería"
|
||||
@@ -288,7 +291,7 @@ msgstr "Estado de arranque"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Bytes (kB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Caché / Buffers"
|
||||
|
||||
@@ -324,7 +327,7 @@ msgstr "Precaución - posible pérdida de datos"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr "Celsius (°C)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
@@ -334,7 +337,7 @@ msgstr "Cambiar las unidades de visualización de las métricas."
|
||||
msgid "Change general application options."
|
||||
msgstr "Cambiar las opciones generales de la aplicación."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Carga"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Cargando"
|
||||
msgid "Chart options"
|
||||
msgstr "Opciones de gráficos"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Ancho del gráfico"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Revisa {email} para un enlace de restablecimiento."
|
||||
@@ -407,6 +414,10 @@ msgstr "Conflictos"
|
||||
msgid "Connection is down"
|
||||
msgstr "La conexión está caída"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Contenedores"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,11 +473,16 @@ msgstr "Copia el contenido del<0>docker-compose.yml</0> para el agente a continu
|
||||
msgid "Copy YAML"
|
||||
msgstr "Copiar YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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"
|
||||
@@ -484,8 +500,8 @@ msgstr "Tiempo de CPU"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Desglose de tiempo de CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Carga acumulada"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Estado actual"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Ciclos"
|
||||
msgid "Daily"
|
||||
msgstr "Diariamente"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Periodo de tiempo predeterminado"
|
||||
@@ -563,11 +584,12 @@ msgstr "Dispositivo"
|
||||
msgid "Discharging"
|
||||
msgstr "Descargando"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Disco"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "E/S de Disco"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "E/S de Disco"
|
||||
msgid "Disk unit"
|
||||
msgstr "Unidad de disco"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Uso de disco de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Uso de CPU de Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Uso de memoria de Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "E/S de red de Docker"
|
||||
|
||||
@@ -688,7 +716,7 @@ msgstr "Efímero"
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Error"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Example:"
|
||||
@@ -731,7 +759,7 @@ msgstr "Exporta la configuración actual de sus sistemas."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Failed"
|
||||
@@ -770,7 +798,7 @@ msgstr "Fallidos: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -783,7 +811,7 @@ msgstr "Huella dactilar"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "Comando FreeBSD"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Llena"
|
||||
@@ -808,17 +837,21 @@ msgstr "Llena"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "General"
|
||||
msgstr "General"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Global"
|
||||
msgstr "Global"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "Motores GPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Consumo de energía de la GPU"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "Consumo de energía de la GPU"
|
||||
msgid "GPU Usage"
|
||||
msgstr "Uso de GPU"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Cuadrícula"
|
||||
@@ -836,7 +870,7 @@ msgstr "Estado"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -912,7 +946,7 @@ msgstr "Ciclo de vida"
|
||||
msgid "limit"
|
||||
msgstr "límite"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Carga media"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Estado de carga"
|
||||
msgid "Loading..."
|
||||
msgstr "Cargando..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Cerrar sesión"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Instrucciones manuales de configuración"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Máx. 1 min"
|
||||
|
||||
@@ -999,15 +1034,16 @@ msgstr "Límite de memoria"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Pico de memoria"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Uso de memoria"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Uso de memoria de los contenedores Docker"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modelo"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Nombre"
|
||||
msgid "Net"
|
||||
msgstr "Red"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Tráfico de red de los contenedores Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1045,7 +1081,7 @@ msgstr "Unidad de red"
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "No"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
@@ -1220,13 +1256,18 @@ msgstr "Por favor, inicia sesión en tu cuenta"
|
||||
msgid "Port"
|
||||
msgstr "Puerto"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Encendido"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilización precisa en el momento registrado"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Horas de silencio"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Lectura"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Recibido"
|
||||
|
||||
@@ -1326,6 +1367,10 @@ msgstr "Detalles S.M.A.R.T."
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "Autoprueba S.M.A.R.T."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Guardar {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Guarda la dirección usando la tecla enter o coma. Deja en blanco para desactivar las notificaciones por correo."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Guarda la dirección usando la tecla enter o coma. Deja en blanco para d
|
||||
msgid "Save Settings"
|
||||
msgstr "Guardar configuración"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Guardar sistema"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Guardado en la base de datos y no expira hasta que lo desactives."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Envíe pings salientes periódicos a un servicio de monitorización exte
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Enviar latido de prueba"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Enviado"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Número de serie"
|
||||
msgid "Service Details"
|
||||
msgstr "Detalles del servicio"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Servicios"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Configure las siguientes variables de entorno en su hub Beszel para habi
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Configuración"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "Estado"
|
||||
msgid "Sub State"
|
||||
msgstr "Subestado"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Espacio de swap utilizado por el sistema"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Uso de swap"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "Uso de swap"
|
||||
msgid "System"
|
||||
msgstr "Sistema"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Promedios de carga del sistema a lo largo del tiempo"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "Los sistemas pueden ser gestionados en un archivo <0>config.yml</0> dent
|
||||
msgid "Table"
|
||||
msgstr "Tabla"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Tareas"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "Tareas"
|
||||
msgid "Temp"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "Temperatura"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Unidad de temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturas de los sensores del sistema"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Rendimiento de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Rendimiento del sistema de archivos raíz"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Formato de hora"
|
||||
msgid "To email(s)"
|
||||
msgstr "A correo(s)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Alternar cuadrícula"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1581,7 +1626,7 @@ msgstr "Alternar tema"
|
||||
#: 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
|
||||
@@ -1600,7 +1645,7 @@ msgstr "Los tokens y las huellas digitales se utilizan para autenticar las conex
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
@@ -1613,7 +1658,7 @@ msgstr "Datos totales enviados por cada interfaz"
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Total: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
@@ -1728,22 +1773,22 @@ msgstr "Cargar"
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Uptime"
|
||||
msgstr "Uptime"
|
||||
msgstr "Tiempo de actividad"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Uso"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Uso de la partición raíz"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Usado"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Ver tus 200 alertas más recientes."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Columnas visibles"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Esperando suficientes registros para mostrar"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Comando Windows"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Escritura"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: fa\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Persian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,7 +55,7 @@ msgid "1 hour"
|
||||
msgstr "۱ ساعت"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "۱ دقیقه"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "۱۲ ساعت"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "۱۵ دقیقه"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "۳۰ روز"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "۵ دقیقه"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "وضعیت فعال"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "افزودن {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "افزودن <0>سیستم</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "افزودن سیستم"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "افزودن آدرس اینترنتی"
|
||||
@@ -134,6 +135,7 @@ msgstr "تنظیم عرض چیدمان اصلی"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "مدیر"
|
||||
|
||||
@@ -163,6 +165,7 @@ msgstr "هشدارها"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "همه کانتینرها"
|
||||
@@ -188,11 +191,11 @@ msgstr "آیا مطمئن هستید؟"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "کپی خودکار نیاز به یک زمینه امن دارد."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "میانگین"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "میانگین استفاده از CPU کانتینرها"
|
||||
|
||||
@@ -206,20 +209,20 @@ msgstr "میانگین به زیر <0>{value}{0}</0> میافتد"
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "میانگین از <0>{value}{0}</0> فراتر رفته است"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "میانگین مصرف برق پردازندههای گرافیکی"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "میانگین استفاده از CPU در کل سیستم"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "میانگین استفاده از {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "میانگین استفاده از موتورهای GPU"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "میانگین استفاده از موتورهای GPU"
|
||||
msgid "Backups"
|
||||
msgstr "پشتیبانگیریها"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "پهنای باند"
|
||||
@@ -238,7 +241,7 @@ msgstr "پهنای باند"
|
||||
msgid "Bat"
|
||||
msgstr "باتری"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "باتری"
|
||||
@@ -288,7 +291,7 @@ msgstr "وضعیت بوت"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "بایت (کیلوبایت بر ثانیه، مگابایت بر ثانیه، گیگابایت بر ثانیه)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "حافظه پنهان / بافرها"
|
||||
|
||||
@@ -334,7 +337,7 @@ msgstr "تغییر واحدهای نمایش برای معیارها."
|
||||
msgid "Change general application options."
|
||||
msgstr "تغییر گزینههای کلی برنامه."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "شارژ"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "در حال شارژ"
|
||||
msgid "Chart options"
|
||||
msgstr "گزینههای نمودار"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "عرض نمودار"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "ایمیل {email} خود را برای لینک بازنشانی بررسی کنید."
|
||||
@@ -407,6 +414,10 @@ msgstr "تعارضها"
|
||||
msgid "Connection is down"
|
||||
msgstr "اتصال قطع است"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "کانتینرها"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,6 +473,11 @@ msgstr "محتوای <0>docker-compose.yml</0> عامل زیر را کپی کن
|
||||
msgid "Copy YAML"
|
||||
msgstr "کپی YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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
|
||||
@@ -484,8 +500,8 @@ msgstr "زمان CPU"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "تجزیه زمان CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "آپلود تجمعی"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "وضعیت فعلی"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "چرخهها"
|
||||
msgid "Daily"
|
||||
msgstr "روزانه"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "بازه زمانی پیشفرض"
|
||||
@@ -563,11 +584,12 @@ msgstr "دستگاه"
|
||||
msgid "Discharging"
|
||||
msgstr "در حال تخلیه"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "دیسک"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "ورودی/خروجی دیسک"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "ورودی/خروجی دیسک"
|
||||
msgid "Disk unit"
|
||||
msgstr "واحد دیسک"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "میزان استفاده از دیسک {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "میزان استفاده از CPU داکر"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "میزان استفاده از حافظه داکر"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "ورودی/خروجی شبکه داکر"
|
||||
|
||||
@@ -770,7 +798,7 @@ msgstr "ناموفق: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "دستور FreeBSD"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "پر"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "جهانی"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr "پردازنده گرافیکی"
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "موتورهای GPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "مصرف برق پردازنده گرافیکی"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "مصرف برق پردازنده گرافیکی"
|
||||
msgid "GPU Usage"
|
||||
msgstr "میزان استفاده از GPU"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "جدول"
|
||||
@@ -912,7 +946,7 @@ msgstr "چرخه حیات"
|
||||
msgid "limit"
|
||||
msgstr "محدودیت"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "میانگین بار"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "وضعیت بارگذاری"
|
||||
msgid "Loading..."
|
||||
msgstr "در حال بارگذاری..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "خروج"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "دستورالعملهای راهاندازی دستی"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "حداکثر ۱ دقیقه"
|
||||
|
||||
@@ -999,15 +1034,16 @@ msgstr "محدودیت حافظه"
|
||||
msgid "Memory Peak"
|
||||
msgstr "حداکثر حافظه"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "میزان استفاده از حافظه"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "میزان استفاده از حافظه کانتینرهای داکر"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "مدل"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "نام"
|
||||
msgid "Net"
|
||||
msgstr "شبکه"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "ترافیک شبکه کانتینرهای داکر"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1220,13 +1256,18 @@ msgstr "لطفاً به حساب کاربری خود وارد شوید"
|
||||
msgid "Port"
|
||||
msgstr "پورت"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "روشن کردن"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "میزان دقیق استفاده در زمان ثبت شده"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "ساعات آرام"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "خواندن"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "دریافت شد"
|
||||
|
||||
@@ -1326,6 +1367,10 @@ msgstr "جزئیات S.M.A.R.T"
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "تست خود S.M.A.R.T"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "ذخیره {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "آدرس را با استفاده از کلید Enter یا کاما ذخیره کنید. برای غیرفعال کردن اعلانهای ایمیلی، خالی بگذارید."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "آدرس را با استفاده از کلید Enter یا کاما ذخ
|
||||
msgid "Save Settings"
|
||||
msgstr "ذخیره تنظیمات"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "ذخیره سیستم"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "در پایگاه داده ذخیره شده و تا زمانی که آن را غیرفعال نکنید، منقضی نمیشود."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "پینگهای خروجی دورهای را به یک سرویس
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "ارسال ضربان قلب آزمایشی"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "ارسال شد"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "شماره سریال"
|
||||
msgid "Service Details"
|
||||
msgstr "جزئیات سرویس"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "سرویسها"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "متغیرهای محیطی زیر را در هاب Beszel خود تنظ
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "تنظیمات"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "وضعیت"
|
||||
msgid "Sub State"
|
||||
msgstr "وضعیت فرعی"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "فضای Swap استفاده شده توسط سیستم"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "میزان استفاده از Swap"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "میزان استفاده از Swap"
|
||||
msgid "System"
|
||||
msgstr "سیستم"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "میانگین بار سیستم در طول زمان"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "سیستمها ممکن است در یک فایل <0>config.yml</0>
|
||||
msgid "Table"
|
||||
msgstr "جدول"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "وظایف"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "وظایف"
|
||||
msgid "Temp"
|
||||
msgstr "دما"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "دما"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "دما"
|
||||
msgid "Temperature unit"
|
||||
msgstr "واحد دما"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "دمای حسگرهای سیستم"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ msgstr "این عمل قابل برگشت نیست. این کار تمام رک
|
||||
msgid "This will permanently delete all selected records from the database."
|
||||
msgstr "این کار تمام رکوردهای انتخاب شده را برای همیشه از پایگاه داده حذف خواهد کرد."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "توان عملیاتی {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "توان عملیاتی سیستم فایل ریشه"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "فرمت زمان"
|
||||
msgid "To email(s)"
|
||||
msgstr "به ایمیل(ها)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "تغییر نمایش جدول"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1730,20 +1775,20 @@ msgstr "آپلود"
|
||||
msgid "Uptime"
|
||||
msgstr "آپتایم"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "میزان استفاده"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "میزان استفاده از پارتیشن ریشه"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "استفاده شده"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "۲۰۰ هشدار اخیر خود را مشاهده کنید."
|
||||
msgid "Visible Fields"
|
||||
msgstr "فیلدهای قابل مشاهده"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "در انتظار رکوردهای کافی برای نمایش"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "دستور Windows"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "نوشتن"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: fr\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: French\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
@@ -18,11 +18,17 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "{0} of {1} row(s) selected."
|
||||
msgstr "{0} sur {1} ligne(s) sélectionnée(s)."
|
||||
msgstr "{0} sur {1} ligne(s) sectionner."
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "{cores, plural, one {# core} other {# cores}}"
|
||||
@@ -49,13 +55,13 @@ msgid "1 hour"
|
||||
msgstr "1 heure"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 minute"
|
||||
msgstr "1 minute"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 week"
|
||||
@@ -66,9 +72,9 @@ msgid "12 hours"
|
||||
msgstr "12 heures"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "24 hours"
|
||||
@@ -79,9 +85,9 @@ msgid "30 days"
|
||||
msgstr "30 jours"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 min"
|
||||
msgstr ""
|
||||
|
||||
#. Table column
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -89,14 +95,14 @@ msgstr "5 min"
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Actions"
|
||||
msgstr "Actions"
|
||||
msgstr ""
|
||||
|
||||
#: 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 "Active"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Active Alerts"
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "État actif"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Ajouter {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Ajouter <0>un Système</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Ajouter un système"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Ajouter l’URL"
|
||||
@@ -134,8 +135,9 @@ msgstr "Ajuster la largeur de la mise en page principale"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
@@ -147,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 "Agent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -163,6 +165,7 @@ msgstr "Alertes"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Tous les conteneurs"
|
||||
@@ -188,11 +191,11 @@ msgstr "Êtes-vous sûr ?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "La copie automatique nécessite un contexte sécurisé."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Moyenne"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Utilisation moyenne du CPU des conteneurs"
|
||||
|
||||
@@ -206,20 +209,20 @@ 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.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Utilisation moyenne du CPU à l'échelle du système"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Utilisation moyenne de {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Utilisation moyenne des moteurs GPU"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Utilisation moyenne des moteurs GPU"
|
||||
msgid "Backups"
|
||||
msgstr "Sauvegardes"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bande passante"
|
||||
@@ -236,9 +239,9 @@ msgstr "Bande passante"
|
||||
#. Battery label in systems table header
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Bat"
|
||||
msgstr "Bat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Batterie"
|
||||
@@ -277,7 +280,7 @@ msgstr "Binaire"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
@@ -286,9 +289,9 @@ 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 "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Tampons"
|
||||
|
||||
@@ -324,7 +327,7 @@ msgstr "Attention - perte de données potentielle"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr "Celsius (°C)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
@@ -334,9 +337,9 @@ msgstr "Ajuster les unités d'affichage pour les métriques."
|
||||
msgid "Change general application options."
|
||||
msgstr "Modifier les options générales de l'application."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Charge"
|
||||
msgstr ""
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
@@ -347,6 +350,10 @@ msgstr "En charge"
|
||||
msgid "Chart options"
|
||||
msgstr "Options de graphique"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Largeur du graphique"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Vérifiez {email} pour un lien de réinitialisation."
|
||||
@@ -407,6 +414,10 @@ msgstr "Conflits"
|
||||
msgid "Connection is down"
|
||||
msgstr "Connexion interrompue"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Conteneurs"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,11 +473,16 @@ msgstr "Copiez le contenu du<0>docker-compose.yml</0> pour l'agent ci-dessous, o
|
||||
msgid "Copy YAML"
|
||||
msgstr "Copier YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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"
|
||||
@@ -484,8 +500,8 @@ msgstr "Temps CPU"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Répartition du temps CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,20 +533,25 @@ msgid "Cumulative Upload"
|
||||
msgstr "Téléversement cumulatif"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "État actuel"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Cycles"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Daily"
|
||||
msgstr "Quotidien"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Période par défaut"
|
||||
@@ -548,7 +569,7 @@ msgstr "Supprimer l'empreinte"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
@@ -563,11 +584,12 @@ msgstr "Appareil"
|
||||
msgid "Discharging"
|
||||
msgstr "En décharge"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Disque"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Entrée/Sortie disque"
|
||||
|
||||
@@ -575,32 +597,38 @@ msgstr "Entrée/Sortie disque"
|
||||
msgid "Disk unit"
|
||||
msgstr "Unité disque"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Utilisation du disque de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Utilisation du CPU Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Utilisation de la mémoire Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Entrée/Sortie réseau Docker"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Documentation"
|
||||
msgstr ""
|
||||
|
||||
#. Context: System is down
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
@@ -636,7 +664,7 @@ msgstr "Modifier {foo}"
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
#: src/components/login/otp-forms.tsx
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Email notifications"
|
||||
@@ -731,7 +759,7 @@ msgstr "Exportez la configuration actuelle de vos systèmes."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Failed"
|
||||
@@ -770,7 +798,7 @@ msgstr "Échec : {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "Commande FreeBSD"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Pleine"
|
||||
@@ -812,13 +841,17 @@ msgstr "Général"
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Global"
|
||||
msgstr "Global"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "Moteurs GPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Consommation du GPU"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "Consommation du GPU"
|
||||
msgid "GPU Usage"
|
||||
msgstr "Utilisation GPU"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Grille"
|
||||
@@ -836,7 +870,7 @@ msgstr "Santé"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -876,7 +910,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 "Image"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Inactive"
|
||||
@@ -912,7 +946,7 @@ msgstr "Cycle de vie"
|
||||
msgid "limit"
|
||||
msgstr "limite"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Charge moyenne"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "État de charge"
|
||||
msgid "Loading..."
|
||||
msgstr "Chargement..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Déconnexion"
|
||||
@@ -978,9 +1013,9 @@ msgid "Manual setup instructions"
|
||||
msgstr "Guide pour une installation manuelle"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
@@ -999,15 +1034,16 @@ msgstr "Limite mémoire"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Pic mémoire"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Utilisation de la mémoire"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Utilisation de la mémoire des conteneurs Docker"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modèle"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Nom"
|
||||
msgid "Net"
|
||||
msgstr "Rés"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Trafic réseau des conteneurs Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1074,7 +1110,7 @@ msgstr "Aucun système trouvé."
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Notifications"
|
||||
msgstr "Notifications"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
@@ -1117,7 +1153,7 @@ msgstr "Écraser les alertes existantes"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Page"
|
||||
msgstr "Page"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getState().pagination.pageIndex + 1
|
||||
#. placeholder {1}: table.getPageCount()
|
||||
@@ -1152,7 +1188,7 @@ msgstr "Passé"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Paused"
|
||||
@@ -1177,7 +1213,7 @@ msgstr "Pourcentage de temps passé dans chaque état"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Permanent"
|
||||
msgstr "Permanent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Persistence"
|
||||
@@ -1218,15 +1254,20 @@ msgstr "Veuillez vous connecter à votre compte"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Allumage"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilisation précise au moment enregistré"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Heures calmes"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Lecture"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Reçu"
|
||||
|
||||
@@ -1326,6 +1367,10 @@ msgstr "Détails S.M.A.R.T."
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "Auto-test S.M.A.R.T."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Enregistrer {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Enregistrez l'adresse en utilisant la touche Entrée ou la virgule. Laissez vide pour désactiver les notifications par email."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Enregistrez l'adresse en utilisant la touche Entrée ou la virgule. Lais
|
||||
msgid "Save Settings"
|
||||
msgstr "Enregistrer les paramètres"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Sauvegarder le système"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Enregistré dans la base de données et n'expire pas tant que vous ne le désactivez pas."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Envoyez des pings sortants périodiques vers un service de surveillance
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Envoyer un heartbeat de test"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Envoyé"
|
||||
|
||||
@@ -1399,9 +1440,10 @@ msgstr "Numéro de série"
|
||||
msgid "Service Details"
|
||||
msgstr "Détails du service"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Services"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Définissez les variables d'environnement suivantes sur votre hub Beszel
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Paramètres"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "Statut"
|
||||
msgid "Sub State"
|
||||
msgstr "Sous-état"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Espace Swap utilisé par le système"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Utilisation du swap"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "Utilisation du swap"
|
||||
msgid "System"
|
||||
msgstr "Système"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Charges moyennes du système dans le temps"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "Les systèmes peuvent être gérés dans un fichier <0>config.yml</0> à
|
||||
msgid "Table"
|
||||
msgstr "Tableau"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Tâches"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "Tâches"
|
||||
msgid "Temp"
|
||||
msgstr "Temp."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Température"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "Température"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Unité de température"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Températures des capteurs du système"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Débit de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Débit du système de fichiers racine"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Format d'heure"
|
||||
msgid "To email(s)"
|
||||
msgstr "Aux email(s)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Basculer la grille"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1581,7 +1626,7 @@ msgstr "Changer le thème"
|
||||
#: 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
|
||||
@@ -1600,7 +1645,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 "Total"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
@@ -1671,7 +1716,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 "Type"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
@@ -1728,22 +1773,22 @@ msgstr "Téléverser"
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Uptime"
|
||||
msgstr "Uptime"
|
||||
msgstr "Temps de fonctionnement"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Utilisation"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Utilisation de la partition racine"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Utilisé"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Voir vos 200 dernières alertes."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Colonnes visibles"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "En attente de suffisamment d'enregistrements à afficher"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Commande Windows"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Écriture"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: he\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\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"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,7 +55,7 @@ msgid "1 hour"
|
||||
msgstr "שעה"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "דקה אחת"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "12 שעות"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 דק'"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "30 ימים"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 דק'"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "מצב פעיל"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "הוסף {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "הוסף <0>מערכת</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "הוסף מערכת"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "הוסף URL"
|
||||
@@ -134,6 +135,7 @@ msgstr "התאם את רוחב הפריסה הראשית"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "מנהל"
|
||||
|
||||
@@ -163,6 +165,7 @@ msgstr "התראות"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "כל הקונטיינרים"
|
||||
@@ -188,11 +191,11 @@ msgstr "האם אתה בטוח?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "העתקה אוטומטית דורשת הקשר מאובטח."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "ממוצע"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "ניצול ממוצע של CPU בקונטיינרים"
|
||||
|
||||
@@ -206,20 +209,20 @@ msgstr "הממוצע יורד מתחת ל-<0>{value}{0}</0>"
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "הממוצע עולה על <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "צריכת חשמל ממוצעת של GPUs"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "ניצול ממוצע כלל-מערכתי של CPU"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "ניצול ממוצע של {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "ניצול ממוצע של מנועי GPU"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "ניצול ממוצע של מנועי GPU"
|
||||
msgid "Backups"
|
||||
msgstr "גיבויים"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "רוחב פס"
|
||||
@@ -238,7 +241,7 @@ msgstr "רוחב פס"
|
||||
msgid "Bat"
|
||||
msgstr "סוללה"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "סוללה"
|
||||
@@ -288,7 +291,7 @@ msgstr "מצב אתחול"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "בתים (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "מטמון / חוצצים"
|
||||
|
||||
@@ -334,7 +337,7 @@ msgstr "שנה יחידות תצוגה עבור מדדים."
|
||||
msgid "Change general application options."
|
||||
msgstr "שנה אפשרויות כלליות של היישום."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "טעינה"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "בטעינה"
|
||||
msgid "Chart options"
|
||||
msgstr "אפשרויות גרף"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "רוחב תרשים"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "בדוק את {email} לקישור איפוס."
|
||||
@@ -407,6 +414,10 @@ msgstr "התנגשויות"
|
||||
msgid "Connection is down"
|
||||
msgstr "החיבור נפל"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "קונטיינרים"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,6 +473,11 @@ msgstr "העתק את תוכן ה-<0>docker-compose.yml</0> עבור הסוכן
|
||||
msgid "Copy YAML"
|
||||
msgstr "העתק YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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
|
||||
@@ -484,8 +500,8 @@ msgstr "זמן CPU"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "פירוט זמן CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "העלאה מצטברת"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "מצב נוכחי"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "מחזורים"
|
||||
msgid "Daily"
|
||||
msgstr "יומי"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "תקופת זמן ברירת מחדל"
|
||||
@@ -563,11 +584,12 @@ msgstr "התקן"
|
||||
msgid "Discharging"
|
||||
msgstr "בפריקה"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "דיסק"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "דיסק I/O"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "דיסק I/O"
|
||||
msgid "Disk unit"
|
||||
msgstr "יחידת דיסק"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "שימוש בדיסק של {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "שימוש CPU של Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "שימוש זיכרון של Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "I/O של רשת Docker"
|
||||
|
||||
@@ -770,7 +798,7 @@ msgstr "נכשל: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "פקודת FreeBSD"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "מלא"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "גלובלי"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr "מעבד גרפי"
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "מנועי GPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "צריכת חשמל GPU"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "צריכת חשמל GPU"
|
||||
msgid "GPU Usage"
|
||||
msgstr "שימוש GPU"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "רשת"
|
||||
@@ -912,7 +946,7 @@ msgstr "מחזור חיים"
|
||||
msgid "limit"
|
||||
msgstr "גבול"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "ממוצע עומס"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "מצב עומס"
|
||||
msgid "Loading..."
|
||||
msgstr "טוען..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "התנתק"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "הוראות התקנה ידניות"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "מקס 1 דק'"
|
||||
|
||||
@@ -999,15 +1034,16 @@ msgstr "גבול זיכרון"
|
||||
msgid "Memory Peak"
|
||||
msgstr "שיא זיכרון"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "שימוש בזיכרון"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "שימוש בזיכרון של קונטיינרים של Docker"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "דגם"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "שם"
|
||||
msgid "Net"
|
||||
msgstr "רשת"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "תעבורת רשת של קונטיינרים של Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1220,13 +1256,18 @@ msgstr "אנא התחבר לחשבון שלך"
|
||||
msgid "Port"
|
||||
msgstr "פורט"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "הפעלה"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "ניצול מדויק בזמן הרשום"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "שעות שקט"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "קריאה"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "התקבל"
|
||||
|
||||
@@ -1326,6 +1367,10 @@ msgstr "פרטי S.M.A.R.T."
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "בדיקה עצמית S.M.A.R.T."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "שמור {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "שמור כתובת באמצעות מקש enter או פסיק. השאר ריק כדי להשבית התראות אימייל."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "שמור כתובת באמצעות מקש enter או פסיק. השאר
|
||||
msgid "Save Settings"
|
||||
msgstr "שמור הגדרות"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "שמור מערכת"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "נשמר במסד הנתונים ולא פג תוקף עד שתבטל אותו."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "שלח פינגים יוצאים תקופתיים לשירות ניטו
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "שלח פעימת לב לבדיקה"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "נשלח"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "מספר סידורי"
|
||||
msgid "Service Details"
|
||||
msgstr "פרטי שירות"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "שירותים"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "הגדר את משתני הסביבה הבאים ב-Beszel hub שלך כ
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "הגדרות"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "סטטוס"
|
||||
msgid "Sub State"
|
||||
msgstr "מצב משני"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "שטח swap בשימוש על ידי המערכת"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "שימוש ב-Swap"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "שימוש ב-Swap"
|
||||
msgid "System"
|
||||
msgstr "מערכת"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "ממוצעי עומס מערכת לאורך זמן"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "מערכות יכולות להיות מנוהלות בקובץ <0>config
|
||||
msgid "Table"
|
||||
msgstr "טבלה"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "משימות"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "משימות"
|
||||
msgid "Temp"
|
||||
msgstr "טמפ'"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "טמפרטורה"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "טמפרטורה"
|
||||
msgid "Temperature unit"
|
||||
msgstr "יחידת טמפרטורה"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "טמפרטורות של חיישני המערכת"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ msgstr "פעולה זו לא ניתנת לביטול. פעולה זו תמחק
|
||||
msgid "This will permanently delete all selected records from the database."
|
||||
msgstr "פעולה זו תמחק לצמיתות את כל הרשומות שנבחרו ממסד הנתונים."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "תפוקה של {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "תפוקה של מערכת הקבצים הראשית"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "פורמט זמן"
|
||||
msgid "To email(s)"
|
||||
msgstr "לאימייל(ים)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "החלף רשת"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1730,20 +1775,20 @@ msgstr "העלאה"
|
||||
msgid "Uptime"
|
||||
msgstr "זמן פעילות"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "שימוש"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "שימוש במחיצה הראשית"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "בשימוש"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "צפה ב-200 ההתראות האחרונות שלך."
|
||||
msgid "Visible Fields"
|
||||
msgstr "שדות גלויים"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "ממתין לרשומות מספיקות לתצוגה"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "פקודת Windows"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "כתיבה"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: hr\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\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"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,7 +55,7 @@ msgid "1 hour"
|
||||
msgstr "1 sat"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 minut"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "12 sati"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 minuta"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "30 dana"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 minuta"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Aktivno stanje"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Dodaj {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Dodaj <0>Sustav</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Dodaj sustav"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Dodaj URL"
|
||||
@@ -134,8 +135,9 @@ msgstr "Prilagodite širinu glavnog rasporeda"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
@@ -147,7 +149,7 @@ msgstr "Nakon postavljanja varijabli okruženja, ponovno pokrenite svoj Beszel h
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -163,6 +165,7 @@ msgstr "Upozorenja"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Svi spremnici"
|
||||
@@ -188,11 +191,11 @@ msgstr "Jeste li sigurni?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatsko kopiranje zahtijeva siguran kontekst."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Prosjek"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Prosječna iskorištenost procesora u spremnicima"
|
||||
|
||||
@@ -206,20 +209,20 @@ 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.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Prosječna iskorištenost procesora u cijelom sustavu"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Prosječna iskorištenost {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Prosječna iskorištenost grafičkih procesora"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Prosječna iskorištenost grafičkih procesora"
|
||||
msgid "Backups"
|
||||
msgstr "Sigurnosne kopije"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Mrežna Propusnost"
|
||||
@@ -236,9 +239,9 @@ msgstr "Mrežna Propusnost"
|
||||
#. Battery label in systems table header
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Bat"
|
||||
msgstr "Bat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Baterija"
|
||||
@@ -288,7 +291,7 @@ msgstr "Stanje pokretanja"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Bajtovi (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Predmemorija / Međuspremnici"
|
||||
|
||||
@@ -324,7 +327,7 @@ msgstr "Oprez - mogući gubitak podataka"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr "Celsius (°C)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
@@ -334,7 +337,7 @@ msgstr "Promijenite mjerene jedinice korištene za prikazivanje podataka."
|
||||
msgid "Change general application options."
|
||||
msgstr "Promijenite opće opcije aplikacije."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Punjenje"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Puni se"
|
||||
msgid "Chart options"
|
||||
msgstr "Postavke grafikona"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Širina grafikona"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Provjerite {email} za pristup poveznici za resetiranje."
|
||||
@@ -407,6 +414,10 @@ msgstr "Sukobi"
|
||||
msgid "Connection is down"
|
||||
msgstr "Veza je pala"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Kontejneri"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,6 +473,11 @@ msgstr "Kopirajte sadržaj <0>docker-compose.yml</0> datoteke za opisanog agenta
|
||||
msgid "Copy YAML"
|
||||
msgstr "Kopiraj YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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
|
||||
@@ -484,8 +500,8 @@ msgstr "CPU vrijeme"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Raspodjela CPU vremena"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Kumulativno otpremanje"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Trenutno stanje"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Ciklusi"
|
||||
msgid "Daily"
|
||||
msgstr "Dnevno"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Zadano vremensko razdoblje"
|
||||
@@ -563,37 +584,44 @@ msgstr "Uređaj"
|
||||
msgid "Discharging"
|
||||
msgstr "Prazni se"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Disk unit"
|
||||
msgstr "Mjerna jedinica za disk"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Iskorištenost diska od {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Iskorištenost Docker procesora"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Iskorištenost Docker memorije"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker mrežni I/O"
|
||||
|
||||
@@ -636,7 +664,7 @@ msgstr "Uredi {foo}"
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
#: src/components/login/otp-forms.tsx
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Email notifications"
|
||||
@@ -770,7 +798,7 @@ msgstr "Neuspjelo: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "FreeBSD naredba"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Puno"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "Globalno"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "Grafički procesori"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Energetska potrošnja grafičkog procesora"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "Energetska potrošnja grafičkog procesora"
|
||||
msgid "GPU Usage"
|
||||
msgstr "Iskorištenost GPU-a"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Rešetka"
|
||||
@@ -836,7 +870,7 @@ msgstr "Zdravlje"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -854,7 +888,7 @@ msgstr "Homebrew naredba"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "HTTP Method"
|
||||
@@ -884,7 +918,7 @@ msgstr "Neaktivno"
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Interval"
|
||||
msgstr "Interval"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Invalid email address."
|
||||
@@ -912,7 +946,7 @@ msgstr "Životni ciklus"
|
||||
msgid "limit"
|
||||
msgstr "ograničenje"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Prosječno Opterećenje"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Stanje učitavanja"
|
||||
msgid "Loading..."
|
||||
msgstr "Učitavanje..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Odjava"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Upute za ručno postavljanje"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Maksimalno 1 minuta"
|
||||
|
||||
@@ -999,18 +1034,19 @@ msgstr "Ograničenje memorije"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Vrhunac memorije"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Iskorištenost memorije"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Iskorištenost memorije Docker spremnika"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Ime"
|
||||
msgid "Net"
|
||||
msgstr "Mreža"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Mrežni promet Docker spremnika"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1218,17 +1254,22 @@ msgstr "Molimo prijavite se u svoj račun"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Uključivanje"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Precizno iskorištenje u zabilježenom vremenu"
|
||||
msgstr "Precizno iskorištenje u zabilježenom trenutku"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Preferred Language"
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Tihi sati"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Pročitaj"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Primljeno"
|
||||
|
||||
@@ -1326,19 +1367,19 @@ msgstr "S.M.A.R.T. Detalji"
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. Samotestiranje"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Spremi {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Spremite adresu pomoću tipke enter ili zareza. Ostavite prazno kako biste onemogućili obavijesti e-poštom."
|
||||
msgstr "Spremite adresu pomoću tipke enter ili zarez. Ostavite prazno kako biste onemogućili obavijesti e-poštom."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save Settings"
|
||||
msgstr "Spremi Postavke"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Spremi sustav"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Spremljeno u bazi podataka i ne istječe dok ga ne onemogućite."
|
||||
@@ -1361,7 +1402,7 @@ msgstr "Pretraži"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Pretraži za sisteme ili postavke..."
|
||||
msgstr "Pretraži sustave ili postavke..."
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Seconds between pings (default: 60)"
|
||||
@@ -1369,7 +1410,7 @@ msgstr "Sekunde između pingova (zadano: 60)"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Pogledajte <0>postavke obavijesti</0> da biste konfigurirali način primanja upozorenja."
|
||||
msgstr "Pogledajte <0>postavke obavijesti</0> kako biste konfigurirali način primanja upozorenja."
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Select {foo}"
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Šaljite povremene odlazne pingove vanjskoj usluzi nadzora kako biste mo
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Pošalji testni heartbeat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Poslano"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Serijski broj"
|
||||
msgid "Service Details"
|
||||
msgstr "Detalji usluge"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Usluge"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Postavite sljedeće varijable okruženja na svom Beszel hubu kako biste
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Postavke"
|
||||
|
||||
@@ -1453,23 +1497,24 @@ msgstr "Stanje"
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Podstanje"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap prostor uzet od strane sistema"
|
||||
msgstr "Swap prostor kojeg je zauzeo sustav"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap Iskorištenost"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1479,9 +1524,9 @@ msgstr "Swap Iskorištenost"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "System"
|
||||
msgstr "Sistem"
|
||||
msgstr "Sustav"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Prosječno opterećenje sustava kroz vrijeme"
|
||||
|
||||
@@ -1495,12 +1540,17 @@ msgstr "Sustavi"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Sistemima se može upravljati u <0>config.yml</0> datoteci unutar data direktorija."
|
||||
msgstr "Sustavima se može upravljati pomoću <0>config.yml</0> datoteke unutar data mape."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Table"
|
||||
msgstr "Tablica"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Zadaci"
|
||||
@@ -1509,9 +1559,9 @@ msgstr "Zadaci"
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
@@ -1520,13 +1570,13 @@ msgstr "Temperatura"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Mjerna jedinica za temperaturu"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperature sistemskih senzora"
|
||||
msgstr "Temperature sustavnih mjerila"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Testni <0>URL</0>"
|
||||
msgstr "Probni <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Test heartbeat"
|
||||
@@ -1534,7 +1584,7 @@ msgstr "Testiraj heartbeat"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Test notification sent"
|
||||
msgstr "Testna obavijest poslana"
|
||||
msgstr "Probna obavijest poslana"
|
||||
|
||||
#: 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."
|
||||
@@ -1546,17 +1596,17 @@ msgstr "Zatim se prijavite u backend i resetirajte lozinku korisničkog računa
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Ova radnja se ne može poništiti. Ovo će trajno izbrisati sve trenutne zapise za {name} iz baze podataka."
|
||||
msgstr "Ova radnja ne može se poništiti. Svi trenutni zapisi za {name} bit će trajno izbrisani iz baze podataka."
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Protok {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Protok root datotečnog sustava"
|
||||
|
||||
@@ -1566,12 +1616,7 @@ msgstr "Format vremena"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "To email(s)"
|
||||
msgstr "Primaoci e-pošte"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Uključi/isključi rešetku"
|
||||
msgstr "Primaoci emaila"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
@@ -1581,7 +1626,7 @@ msgstr "Uključi/isključi temu"
|
||||
#: 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
|
||||
@@ -1645,7 +1690,7 @@ msgstr "Pokreće se kada razina baterije padne ispod praga"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Pokreće se kada kombinacija gore/dolje premaši prag"
|
||||
msgstr "Pokreće se kada kumulativna propusnost gore/dolje premaši prag"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
@@ -1661,7 +1706,7 @@ msgstr "Pokreće se kada iskorištenost memorije premaši prag"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Pokreće se kada se status sistema promijeni"
|
||||
msgstr "Pokreće se kada se status sustava promijeni"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
@@ -1690,7 +1735,7 @@ msgstr "Sveopći token"
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Unknown"
|
||||
msgstr "Nepoznata"
|
||||
msgstr "Nepoznato"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
@@ -1728,22 +1773,22 @@ msgstr "Otpremi"
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Uptime"
|
||||
msgstr "Uptime"
|
||||
msgstr "Vrijeme rada"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Iskorištenost"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Iskorištenost root datotečnog sustava"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Iskorišteno"
|
||||
|
||||
@@ -1773,13 +1818,13 @@ msgstr "Pogledajte posljednjih 200 upozorenja."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Vidljiva polja"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Čeka se na više podataka prije prikaza"
|
||||
msgstr "Potrebno je više podataka za prikaz"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Želite li nam pomoći da naše prijevode učinimo još boljim? Posjetite <0>Crowdin</0> za više detalja."
|
||||
msgstr "Želite li nam pomoći poboljšati prijevode? Posjetite <0>Crowdin</0> za više detalja."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Windows naredba"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Piši"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: hu\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Hungarian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,7 +55,7 @@ msgid "1 hour"
|
||||
msgstr "1 óra"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 perc"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "12 óra"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 perc"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "30 nap"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 perc"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Aktív állapot"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Hozzáadás {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>Rendszer</0> Hozzáadása"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Rendszer hozzáadása"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "URL hozzáadása"
|
||||
@@ -134,6 +135,7 @@ msgstr "A fő elrendezés szélességének beállítása"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Adminisztráció"
|
||||
|
||||
@@ -163,6 +165,7 @@ msgstr "Riasztások"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Minden konténer"
|
||||
@@ -188,11 +191,11 @@ msgstr "Biztos vagy benne?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Az automatikus másolás biztonságos környezetet igényel."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Átlag"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Konténerek átlagos CPU kihasználtsága"
|
||||
|
||||
@@ -206,20 +209,20 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "GPU-k átlagos energiafogyasztása"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Rendszerszintű CPU átlagos kihasználtság"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "{0} átlagos kihasználtsága"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "GPU-k átlagos kihasználtsága"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "GPU-k átlagos kihasználtsága"
|
||||
msgid "Backups"
|
||||
msgstr "Biztonsági mentések"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Sávszélesség"
|
||||
@@ -238,7 +241,7 @@ msgstr "Sávszélesség"
|
||||
msgid "Bat"
|
||||
msgstr "Akku"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Akkumulátor"
|
||||
@@ -288,7 +291,7 @@ msgstr "Indítási állapot"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Byte-ok (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Gyorsítótár / Pufferelések"
|
||||
|
||||
@@ -324,7 +327,7 @@ msgstr "Figyelem - potenciális adatvesztés"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr "Celsius (°C)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
@@ -334,7 +337,7 @@ msgstr "A mértékegységek megjelenítésének megváltoztatása."
|
||||
msgid "Change general application options."
|
||||
msgstr "Általános alkalmazásbeállítások módosítása."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Töltés"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Töltődik"
|
||||
msgid "Chart options"
|
||||
msgstr "Diagram beállítások"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Grafikon szélessége"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Ellenőrizd a {email} címet a visszaállító linkért."
|
||||
@@ -407,6 +414,10 @@ msgstr "Konfliktusok"
|
||||
msgid "Connection is down"
|
||||
msgstr "Kapcsolat megszakadt"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Konténerek"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,11 +473,16 @@ msgstr "Másold az alábbi ügynök <0>docker-compose.yml</0> tartalmát, vagy r
|
||||
msgid "Copy YAML"
|
||||
msgstr "YAML másolása"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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"
|
||||
@@ -484,8 +500,8 @@ msgstr "CPU idő"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU idő felbontása"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Kumulatív feltöltés"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Jelenlegi állapot"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Ciklusok"
|
||||
msgid "Daily"
|
||||
msgstr "Napi"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Alapértelmezett időszak"
|
||||
@@ -563,11 +584,12 @@ msgstr "Eszköz"
|
||||
msgid "Discharging"
|
||||
msgstr "Kisül"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Lemez"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Lemez I/O"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "Lemez I/O"
|
||||
msgid "Disk unit"
|
||||
msgstr "Lemez mértékegysége"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Lemezhasználat a {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU használat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker memória használat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker hálózat I/O"
|
||||
|
||||
@@ -636,7 +664,7 @@ msgstr "Szerkesztés {foo}"
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
#: src/components/login/otp-forms.tsx
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Email notifications"
|
||||
@@ -731,7 +759,7 @@ msgstr "Exportálja a jelenlegi rendszerkonfigurációt."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Failed"
|
||||
@@ -770,7 +798,7 @@ msgstr "Sikertelen: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -783,7 +811,7 @@ msgstr "Ujjlenyomat"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "FreeBSD parancs"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Tele"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "Globális"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU-k"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU áramfelvétele"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "GPU áramfelvétele"
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU használat"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Rács"
|
||||
@@ -836,7 +870,7 @@ msgstr "Egészség"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -912,7 +946,7 @@ msgstr "Életciklus"
|
||||
msgid "limit"
|
||||
msgstr "korlát"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Terhelési átlag"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Betöltési állapot"
|
||||
msgid "Loading..."
|
||||
msgstr "Betöltés..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Kijelentkezés"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Manuális beállítási lépések"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Maximum 1 perc"
|
||||
|
||||
@@ -999,15 +1034,16 @@ msgstr "Memória korlát"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Memória csúcs"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Memóriahasználat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Docker konténerek memória használata"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modell"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Név"
|
||||
msgid "Net"
|
||||
msgstr "Hálózat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Docker konténerek hálózati forgalma"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1218,15 +1254,20 @@ msgstr "Kérjük, jelentkezzen be a fiókjába"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Bekapcsolás"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Pontos kihasználás a rögzített időpontban"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Csendes órák"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Olvasás"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Fogadott"
|
||||
|
||||
@@ -1326,6 +1367,10 @@ msgstr "S.M.A.R.T. Részletek"
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. Önteszt"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "{foo} mentése"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Mentse el a címet az Enter billentyű vagy a vessző használatával. Hagyja üresen az e-mail értesítések letiltásához."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Mentse el a címet az Enter billentyű vagy a vessző használatával. H
|
||||
msgid "Save Settings"
|
||||
msgstr "Beállítások mentése"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Rendszer mentése"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Elmentve az adatbázisban és nem jár le, amíg ki nem kapcsolod."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Küldjön időszakos kimenő pingeket egy külső megfigyelő szolgálta
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Teszt heartbeat küldése"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Elküldve"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Sorozatszám"
|
||||
msgid "Service Details"
|
||||
msgstr "Szolgáltatás részletei"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Szolgáltatások"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Állítsa be a következő környezeti változókat a Beszel hubon a hea
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Beállítások"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "Állapot"
|
||||
msgid "Sub State"
|
||||
msgstr "Részállapot"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Rendszer által használt swap terület"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap használat"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "Swap használat"
|
||||
msgid "System"
|
||||
msgstr "Rendszer"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Rendszer terhelési átlaga"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "A rendszereket egy <0>config.yml</0> fájlban lehet kezelni az adatköny
|
||||
msgid "Table"
|
||||
msgstr "Tábla"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Feladatok"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "Feladatok"
|
||||
msgid "Temp"
|
||||
msgstr "Hőmérséklet"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Hőmérséklet"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "Hőmérséklet"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Hőmérséklet mértékegysége"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "A rendszer érzékelőinek hőmérséklete"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "A {extraFsName} átviteli teljesítménye"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "A gyökér fájlrendszer átviteli teljesítménye"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Időformátum"
|
||||
msgid "To email(s)"
|
||||
msgstr "E-mailben"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Rács ki- és bekapcsolása"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1581,7 +1626,7 @@ msgstr "Téma váltása"
|
||||
#: 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
|
||||
@@ -1730,20 +1775,20 @@ msgstr "Feltöltés"
|
||||
msgid "Uptime"
|
||||
msgstr "Üzemidő"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Használat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Root partíció kihasználtsága"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Felhasznált"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Legfrissebb 200 riasztásod áttekintése."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Látható mezők"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Elegendő rekordra várva a megjelenítéshez"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Windows parancs"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Írás"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: id\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Indonesian\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,7 +55,7 @@ msgid "1 hour"
|
||||
msgstr "1 jam"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 mnt"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "12 jam"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 menit"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "30 hari"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 mnt"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Status aktif"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Tambah {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Tambah <0>Sistem</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Tambah sistem"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Tambah URL"
|
||||
@@ -134,8 +135,9 @@ msgstr "Sesuaikan lebar layar utama"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
@@ -163,6 +165,7 @@ msgstr "Peringatan"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Semua Container"
|
||||
@@ -188,11 +191,11 @@ msgstr "Apakah anda yakin?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Copy memerlukan https."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Rata-rata"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Rata-rata utilisasi CPU untuk semua kontainer"
|
||||
|
||||
@@ -206,20 +209,20 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Rata-rata konsumsi daya GPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Rata-rata utilisasi CPU seluruh sistem"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Rata-rata utilisasi {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Rata-rata utilisasi GPU"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Rata-rata utilisasi GPU"
|
||||
msgid "Backups"
|
||||
msgstr "Cadangan"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bandwith"
|
||||
@@ -238,7 +241,7 @@ msgstr "Bandwith"
|
||||
msgid "Bat"
|
||||
msgstr "Baterai"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Baterai"
|
||||
@@ -288,9 +291,9 @@ msgstr "Status memulai"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Byte (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffers"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
@@ -324,7 +327,7 @@ msgstr "Perhatian - potensi kehilangan data"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr "Celsius (°C)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
@@ -334,7 +337,7 @@ msgstr "Ubah tampilan satuan untuk metrik."
|
||||
msgid "Change general application options."
|
||||
msgstr "Ubah pengaturan umum aplikasi."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Isi baterai"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Sedang mengisi"
|
||||
msgid "Chart options"
|
||||
msgstr "Pilihan grafik"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Lebar grafik"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Periksa {email} untuk tautan atur ulang password."
|
||||
@@ -407,6 +414,10 @@ msgstr "Konflik"
|
||||
msgid "Connection is down"
|
||||
msgstr "Koneksi terputus"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Kontainer"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,11 +473,16 @@ msgstr "Salin konten <0>docker-compose.yml</0> untuk agen di bawah, atau daftark
|
||||
msgid "Copy YAML"
|
||||
msgstr "Salin YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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"
|
||||
@@ -484,8 +500,8 @@ msgstr "Waktu CPU"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Rincian Waktu CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Akumulasi Upload"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Status saat ini"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Siklus"
|
||||
msgid "Daily"
|
||||
msgstr "Harian"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Standar waktu"
|
||||
@@ -552,7 +573,7 @@ msgstr "Deskripsi"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Detail"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
@@ -563,39 +584,46 @@ msgstr "Perangkat"
|
||||
msgid "Discharging"
|
||||
msgstr "Sedang tidak di charge"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
msgstr "I/O Disk"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Disk unit"
|
||||
msgstr "Unit disk"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Penggunaan disk dari {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Penggunaan CPU Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Penggunaan Memori Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker Network I/O"
|
||||
msgstr "I/O Jaringan Docker"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
@@ -636,7 +664,7 @@ msgstr "Ubah {foo}"
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
#: src/components/login/otp-forms.tsx
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Email notifications"
|
||||
@@ -688,7 +716,7 @@ msgstr "Sementara"
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Error"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Example:"
|
||||
@@ -731,7 +759,7 @@ msgstr "Export konfigurasi sistem anda saat ini."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Failed"
|
||||
@@ -770,7 +798,7 @@ msgstr "Gagal: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -783,7 +811,7 @@ msgstr "Sidik jari"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "Perintah FreeBSD"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Penuh"
|
||||
@@ -812,13 +841,17 @@ msgstr "Umum"
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Global"
|
||||
msgstr "Global"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Konsumsi Daya GPU"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "Konsumsi Daya GPU"
|
||||
msgid "GPU Usage"
|
||||
msgstr "Penggunaan GPU"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Kartu"
|
||||
@@ -836,7 +870,7 @@ msgstr "Kesehatan"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -854,7 +888,7 @@ msgstr "Perintah Homebrew"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "HTTP Method"
|
||||
@@ -867,7 +901,7 @@ msgstr "Metode HTTP: POST, GET, atau HEAD (default: POST)"
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Idle"
|
||||
msgstr "Idle"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
@@ -876,7 +910,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 "Image"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Inactive"
|
||||
@@ -884,7 +918,7 @@ msgstr "Tidak aktif"
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Interval"
|
||||
msgstr "Interval"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Invalid email address."
|
||||
@@ -912,7 +946,7 @@ msgstr "Siklus hidup"
|
||||
msgid "limit"
|
||||
msgstr "batas"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Rata-rata Beban"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Beban saat ini"
|
||||
msgid "Loading..."
|
||||
msgstr "Memuat..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Keluar"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Instruksi setup manual"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Maks 1 mnt"
|
||||
|
||||
@@ -999,18 +1034,19 @@ msgstr "Batas memori"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Puncak Memori"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Penggunaan Memori"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Penggunaan memori kontainer docker"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Nama"
|
||||
msgid "Net"
|
||||
msgstr "Jaringan"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Trafik jaringan kontainer docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1218,15 +1254,20 @@ msgstr "Silakan masuk ke akun anda"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Dihidupkan"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilisasi tepat pada waktu yang direkam"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Jam Tenang"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Baca"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Diterima"
|
||||
|
||||
@@ -1304,7 +1345,7 @@ msgstr "Lanjutkan"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
@@ -1326,6 +1367,10 @@ msgstr "Detail S.M.A.R.T."
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "Self-Test S.M.A.R.T."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Simpan {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Simpan alamat menggunakan tombol enter atau koma. Biarkan kosong untuk menonaktifkan notifikasi email."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Simpan alamat menggunakan tombol enter atau koma. Biarkan kosong untuk m
|
||||
msgid "Save Settings"
|
||||
msgstr "Simpan Pengaturan"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Simpan sistem"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Disimpan di database dan tidak kedaluwarsa sampai Anda menonaktifkannya."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Kirim ping keluar secara berkala ke layanan pemantauan eksternal sehingg
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Kirim tes heartbeat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Dikirim"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Nomor Seri"
|
||||
msgid "Service Details"
|
||||
msgstr "Detail Layanan"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Layanan"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Setel variabel lingkungan berikut di hub Beszel Anda untuk mengaktifkan
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Pengaturan"
|
||||
|
||||
@@ -1453,23 +1497,24 @@ msgstr "Status"
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Sub Status"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Ruang swap yang digunakan oleh sistem"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Penggunaan Swap"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "Penggunaan Swap"
|
||||
msgid "System"
|
||||
msgstr "Sistem"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Rata-rata beban sistem dari waktu ke waktu"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "Sistem dapat dikelola dalam file <0>config.yml</0> di dalam direktori da
|
||||
msgid "Table"
|
||||
msgstr "Tabel"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Tugas"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "Tugas"
|
||||
msgid "Temp"
|
||||
msgstr "Temperatur"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatur"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "Temperatur"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Unit temperatur"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperatur sensor sistem"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Throughput dari {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Throughput dari filesystem root"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Format waktu"
|
||||
msgid "To email(s)"
|
||||
msgstr "Ke email"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Ganti tampilan"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1581,7 +1626,7 @@ msgstr "Ganti tema"
|
||||
#: 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
|
||||
@@ -1600,7 +1645,7 @@ msgstr "Token dan Fingerprint digunakan untuk mengautentikasi koneksi WebSocket
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
@@ -1613,7 +1658,7 @@ msgstr "Total data yang dikirim untuk setiap antarmuka"
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Total: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
@@ -1730,20 +1775,20 @@ msgstr "Unggah"
|
||||
msgid "Uptime"
|
||||
msgstr "Waktu aktif"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Penggunaan"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Penggunaan partisi root"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Digunakan"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Lihat 200 peringatan terbaru anda."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Metrik yang Terlihat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Menunggu cukup record untuk ditampilkan"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Perintah Windows"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Tulis"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: it\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Italian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,9 +55,9 @@ msgid "1 hour"
|
||||
msgstr "1 ora"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 minute"
|
||||
@@ -66,9 +72,9 @@ msgid "12 hours"
|
||||
msgstr "12 ore"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "24 hours"
|
||||
@@ -79,9 +85,9 @@ msgid "30 days"
|
||||
msgstr "30 giorni"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 min"
|
||||
msgstr ""
|
||||
|
||||
#. Table column
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Stato attivo"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Aggiungi {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Aggiungi <0>Sistema</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Aggiungi sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Aggiungi URL"
|
||||
@@ -134,6 +135,7 @@ msgstr "Regola la larghezza del layout principale"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Amministratore"
|
||||
|
||||
@@ -163,6 +165,7 @@ msgstr "Avvisi"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Tutti i contenitori"
|
||||
@@ -188,11 +191,11 @@ msgstr "Sei sicuro?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "La copia automatica richiede un contesto sicuro."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Media"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Utilizzo medio della CPU dei container"
|
||||
|
||||
@@ -206,20 +209,20 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Consumo energetico medio delle GPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Utilizzo medio della CPU a livello di sistema"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Utilizzo medio di {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Utilizzo medio dei motori GPU"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Utilizzo medio dei motori GPU"
|
||||
msgid "Backups"
|
||||
msgstr "Backup"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Larghezza di banda"
|
||||
@@ -236,9 +239,9 @@ msgstr "Larghezza di banda"
|
||||
#. Battery label in systems table header
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Bat"
|
||||
msgstr "Bat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Batteria"
|
||||
@@ -288,7 +291,7 @@ msgstr "Stato di avvio"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Byte (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffer"
|
||||
|
||||
@@ -324,7 +327,7 @@ msgstr "Attenzione - possibile perdita di dati"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr "Celsius (°C)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
@@ -334,7 +337,7 @@ msgstr "Modifica le unità di visualizzazione per le metriche."
|
||||
msgid "Change general application options."
|
||||
msgstr "Modifica le opzioni generali dell'applicazione."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Carica"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "In carica"
|
||||
msgid "Chart options"
|
||||
msgstr "Opzioni del grafico"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Larghezza grafico"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Controlla {email} per un link di reset."
|
||||
@@ -407,6 +414,10 @@ msgstr "Conflitti"
|
||||
msgid "Connection is down"
|
||||
msgstr "La connessione è interrotta"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Container"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,11 +473,16 @@ msgstr "Copia il contenuto<0>docker-compose.yml</0> per l'agente qui sotto, o re
|
||||
msgid "Copy YAML"
|
||||
msgstr "Copia YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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"
|
||||
@@ -484,8 +500,8 @@ msgstr "Tempo CPU"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Suddivisione tempo CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Upload cumulativo"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Stato attuale"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Cicli"
|
||||
msgid "Daily"
|
||||
msgstr "Giornaliero"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Periodo di tempo predefinito"
|
||||
@@ -563,11 +584,12 @@ msgstr "Dispositivo"
|
||||
msgid "Discharging"
|
||||
msgstr "In scarica"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Disco"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "I/O Disco"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "I/O Disco"
|
||||
msgid "Disk unit"
|
||||
msgstr "Unità disco"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Utilizzo del disco di {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Utilizzo CPU Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Utilizzo Memoria Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "I/O di Rete Docker"
|
||||
|
||||
@@ -636,7 +664,7 @@ msgstr "Modifica {foo}"
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
#: src/components/login/otp-forms.tsx
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Email notifications"
|
||||
@@ -731,7 +759,7 @@ msgstr "Esporta la configurazione attuale dei tuoi sistemi."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Failed"
|
||||
@@ -770,7 +798,7 @@ msgstr "Fallito: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -783,7 +811,7 @@ msgstr "Impronta digitale"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "Comando FreeBSD"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Piena"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "Globale"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "Motori GPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Consumo della GPU"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "Consumo della GPU"
|
||||
msgid "GPU Usage"
|
||||
msgstr "Utilizzo GPU"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Griglia"
|
||||
@@ -836,7 +870,7 @@ msgstr "Stato"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -854,7 +888,7 @@ msgstr "Comando Homebrew"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "HTTP Method"
|
||||
@@ -912,7 +946,7 @@ msgstr "Ciclo di vita"
|
||||
msgid "limit"
|
||||
msgstr "limite"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Carico medio"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Stato di caricamento"
|
||||
msgid "Loading..."
|
||||
msgstr "Caricamento..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Disconnetti"
|
||||
@@ -978,9 +1013,9 @@ msgid "Manual setup instructions"
|
||||
msgstr "Istruzioni di configurazione manuale"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
@@ -999,15 +1034,16 @@ msgstr "Limite memoria"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Picco memoria"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Utilizzo Memoria"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Utilizzo della memoria dei container Docker"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modello"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Nome"
|
||||
msgid "Net"
|
||||
msgstr "Rete"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Traffico di rete dei container Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1045,7 +1081,7 @@ msgstr "Unità rete"
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "No"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
@@ -1132,7 +1168,7 @@ msgstr "Pagine / Impostazioni"
|
||||
#: src/components/login/auth-form.tsx
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Password"
|
||||
msgstr "Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Password must be at least 8 characters."
|
||||
@@ -1220,13 +1256,18 @@ msgstr "Si prega di accedere al proprio account"
|
||||
msgid "Port"
|
||||
msgstr "Porta"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Accensione"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilizzo preciso al momento registrato"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Ore silenziose"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Lettura"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Ricevuto"
|
||||
|
||||
@@ -1304,7 +1345,7 @@ msgstr "Riprendi"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
@@ -1326,6 +1367,10 @@ msgstr "Dettagli S.M.A.R.T."
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "Autotest S.M.A.R.T."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Salva {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Salva l'indirizzo usando il tasto invio o la virgola. Lascia vuoto per disabilitare le notifiche email."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Salva l'indirizzo usando il tasto invio o la virgola. Lascia vuoto per d
|
||||
msgid "Save Settings"
|
||||
msgstr "Salva Impostazioni"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Salva sistema"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Salvato nel database e non scade finché non lo disabiliti."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Invia ping in uscita periodici a un servizio di monitoraggio esterno in
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Invia heartbeat di prova"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Inviato"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Numero di serie"
|
||||
msgid "Service Details"
|
||||
msgstr "Dettagli servizio"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Servizi"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Imposta le seguenti variabili d'ambiente sul tuo Beszel hub per abilitar
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Impostazioni"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "Stato"
|
||||
msgid "Sub State"
|
||||
msgstr "Sotto-stato"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Spazio di swap utilizzato dal sistema"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Utilizzo Swap"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "Utilizzo Swap"
|
||||
msgid "System"
|
||||
msgstr "Sistema"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Medie di carico del sistema nel tempo"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "I sistemi possono essere gestiti in un file <0>config.yml</0> all'intern
|
||||
msgid "Table"
|
||||
msgstr "Tabella"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Attività"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "Attività"
|
||||
msgid "Temp"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
@@ -1520,17 +1570,17 @@ msgstr "Temperatura"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Unità temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperature dei sensori di sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Test heartbeat"
|
||||
msgstr "Test heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Test notification sent"
|
||||
@@ -1552,11 +1602,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Throughput di {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Throughput del filesystem root"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Formato orario"
|
||||
msgid "To email(s)"
|
||||
msgstr "A email(s)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Attiva/disattiva griglia"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1581,7 +1626,7 @@ msgstr "Attiva/disattiva tema"
|
||||
#: 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
|
||||
@@ -1728,22 +1773,22 @@ msgstr "Carica"
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Uptime"
|
||||
msgstr "Uptime"
|
||||
msgstr "Tempo di attività"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Utilizzo"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Utilizzo della partizione root"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Utilizzato"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Visualizza i tuoi 200 avvisi più recenti."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Colonne visibili"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "In attesa di abbastanza record da visualizzare"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Comando Windows"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Scrittura"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: ja\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Japanese\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,7 +55,7 @@ msgid "1 hour"
|
||||
msgstr "1時間"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1分"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "12時間"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15分"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "30日間"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5分"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "アクティブ状態"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "{foo}を追加"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>システム</0>を追加"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "システムを追加"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "URLを追加"
|
||||
@@ -134,6 +135,7 @@ msgstr "メインレイアウトの幅を調整"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "管理者"
|
||||
|
||||
@@ -163,6 +165,7 @@ msgstr "アラート"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "すべてのコンテナ"
|
||||
@@ -188,11 +191,11 @@ msgstr "よろしいですか?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "自動コピーには安全なコンテキストが必要です。"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "平均"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "コンテナの平均CPU使用率"
|
||||
|
||||
@@ -206,20 +209,20 @@ msgstr "平均が<0>{value}{0}</0>を下回っています"
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "平均が<0>{value}{0}</0>を超えています"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "GPUの平均消費電力"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "システム全体の平均CPU使用率"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "{0}の平均使用率"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "GPUエンジンの平均使用率"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "GPUエンジンの平均使用率"
|
||||
msgid "Backups"
|
||||
msgstr "バックアップ"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "帯域幅"
|
||||
@@ -238,7 +241,7 @@ msgstr "帯域幅"
|
||||
msgid "Bat"
|
||||
msgstr "バッテリー"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "バッテリー"
|
||||
@@ -288,7 +291,7 @@ msgstr "ブート状態"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "バイト (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "キャッシュ / バッファ"
|
||||
|
||||
@@ -334,7 +337,7 @@ msgstr "メトリックの表示単位を変更します。"
|
||||
msgid "Change general application options."
|
||||
msgstr "一般的なアプリケーションオプションを変更します。"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "充電"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "充電中"
|
||||
msgid "Chart options"
|
||||
msgstr "チャートオプション"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "チャートの幅"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "{email}を確認してリセットリンクを探してください。"
|
||||
@@ -407,6 +414,10 @@ msgstr "競合"
|
||||
msgid "Connection is down"
|
||||
msgstr "接続が切断されました"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "コンテナ"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,11 +473,16 @@ msgstr "下記のエージェントの<0>docker-compose.yml</0>内容をコピ
|
||||
msgid "Copy YAML"
|
||||
msgstr "YAMLをコピー"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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"
|
||||
@@ -484,8 +500,8 @@ msgstr "CPU時間"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU 時間の内訳"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "累積アップロード"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "現在の状態"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "サイクル"
|
||||
msgid "Daily"
|
||||
msgstr "毎日"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "デフォルトの期間"
|
||||
@@ -563,11 +584,12 @@ msgstr "デバイス"
|
||||
msgid "Discharging"
|
||||
msgstr "放電中"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "ディスク"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "ディスクI/O"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "ディスクI/O"
|
||||
msgid "Disk unit"
|
||||
msgstr "ディスク単位"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "{extraFsName}のディスク使用率"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU使用率"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Dockerメモリ使用率"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "DockerネットワークI/O"
|
||||
|
||||
@@ -770,7 +798,7 @@ msgstr "失敗: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "FreeBSD コマンド"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "満充電"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "グローバル"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPUエンジン"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPUの消費電力"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "GPUの消費電力"
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU使用率"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "グリッド"
|
||||
@@ -912,7 +946,7 @@ msgstr "ライフサイクル"
|
||||
msgid "limit"
|
||||
msgstr "制限"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "負荷平均"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "ロード状態"
|
||||
msgid "Loading..."
|
||||
msgstr "読み込み中..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "ログアウト"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "手動セットアップの手順"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "最大1分"
|
||||
|
||||
@@ -999,15 +1034,16 @@ msgstr "メモリ制限"
|
||||
msgid "Memory Peak"
|
||||
msgstr "メモリピーク"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "メモリ使用率"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Dockerコンテナのメモリ使用率"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "モデル"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "名前"
|
||||
msgid "Net"
|
||||
msgstr "帯域"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Dockerコンテナのネットワークトラフィック"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1220,13 +1256,18 @@ msgstr "アカウントにサインインしてください"
|
||||
msgid "Port"
|
||||
msgstr "ポート"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "電源オン"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "記録された時点での正確な利用"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "サイレント時間"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "読み取り"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "受信"
|
||||
|
||||
@@ -1326,6 +1367,10 @@ msgstr "S.M.A.R.T.詳細"
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T.セルフテスト"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "{foo} を保存"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Enterキーまたはカンマを使用してアドレスを保存します。空白のままにするとメール通知が無効になります。"
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Enterキーまたはカンマを使用してアドレスを保存しま
|
||||
msgid "Save Settings"
|
||||
msgstr "設定を保存"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "システムを保存"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "データベースに保存され、無効にするまで有効期限が切れません。"
|
||||
@@ -1387,7 +1428,7 @@ msgstr "外部監視サービスに定期的にアウトバウンド ping を送
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "テストハートビートを送信"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "送信"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "シリアル番号"
|
||||
msgid "Service Details"
|
||||
msgstr "サービス詳細"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "サービス"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "ハートビート監視を有効にするには、Beszel ハブで次
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "設定"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "ステータス"
|
||||
msgid "Sub State"
|
||||
msgstr "サブ状態"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "システムが使用するスワップ領域"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "スワップ使用量"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "スワップ使用量"
|
||||
msgid "System"
|
||||
msgstr "システム"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "システムの負荷平均の推移"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "システムはデータディレクトリ内の<0>config.yml</0>ファ
|
||||
msgid "Table"
|
||||
msgstr "テーブル"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "タスク"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "タスク"
|
||||
msgid "Temp"
|
||||
msgstr "温度"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "温度"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "温度"
|
||||
msgid "Temperature unit"
|
||||
msgstr "温度単位"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "システムセンサーの温度"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ msgstr "この操作は元に戻せません。これにより、データベー
|
||||
msgid "This will permanently delete all selected records from the database."
|
||||
msgstr "これにより、選択したすべてのレコードがデータベースから完全に削除されます。"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "{extraFsName}のスループット"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "ルートファイルシステムのスループット"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "時間形式"
|
||||
msgid "To email(s)"
|
||||
msgstr "宛先メールアドレス"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "グリッドを切り替え"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1730,20 +1775,20 @@ msgstr "アップロード"
|
||||
msgid "Uptime"
|
||||
msgstr "稼働時間"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "使用量"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "ルートパーティションの使用量"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "使用中"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "直近200件のアラートを表示します。"
|
||||
msgid "Visible Fields"
|
||||
msgstr "表示列"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "表示するのに十分なレコードを待っています"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Windows コマンド"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "書き込み"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: ko\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Korean\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,7 +55,7 @@ msgid "1 hour"
|
||||
msgstr "1시간"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1분"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "12시간"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15분"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "30일"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5분"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "활성 상태"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "{foo} 추가"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>시스템</0> 추가"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "시스템 추가"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "URL 추가"
|
||||
@@ -134,6 +135,7 @@ msgstr "메인 레이아웃 너비 조정"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "관리자"
|
||||
|
||||
@@ -163,6 +165,7 @@ msgstr "알림"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "모든 컨테이너"
|
||||
@@ -188,11 +191,11 @@ msgstr "확실합니까?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "자동 복사는 안전한 컨텍스트가 필요합니다."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "평균"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Docker 컨테이너의 평균 CPU 사용량"
|
||||
|
||||
@@ -206,20 +209,20 @@ msgstr "평균이 <0>{value}{0}</0> 아래로 떨어집니다"
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "평균이 <0>{value}{0}</0>을(를) 초과합니다"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "GPU들의 평균 전원 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "시스템 전체의 평균 CPU 사용량"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "평균 {0} 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "GPU 엔진 평균 사용량"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "GPU 엔진 평균 사용량"
|
||||
msgid "Backups"
|
||||
msgstr "백업"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "대역폭"
|
||||
@@ -238,7 +241,7 @@ msgstr "대역폭"
|
||||
msgid "Bat"
|
||||
msgstr "배터리"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "배터리"
|
||||
@@ -288,7 +291,7 @@ msgstr "부팅 상태"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "바이트 (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "캐시 / 버퍼"
|
||||
|
||||
@@ -334,7 +337,7 @@ msgstr "메트릭의 표시 단위를 변경합니다."
|
||||
msgid "Change general application options."
|
||||
msgstr "일반 애플리케이션 옵션 변경."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "충전"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "충전 중"
|
||||
msgid "Chart options"
|
||||
msgstr "차트 옵션"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "차트 너비"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "{email}에서 재설정 링크를 확인하세요."
|
||||
@@ -407,6 +414,10 @@ msgstr "충돌"
|
||||
msgid "Connection is down"
|
||||
msgstr "연결이 끊겼습니다"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "컨테이너"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,11 +473,16 @@ msgstr "아래 에이전트의 <0>docker-compose.yml</0> 내용을 복사하거
|
||||
msgid "Copy YAML"
|
||||
msgstr "YAML 복사"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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"
|
||||
@@ -484,8 +500,8 @@ msgstr "CPU 시간"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU 시간 분배"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "누적 업로드"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "현재 상태"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "사이클"
|
||||
msgid "Daily"
|
||||
msgstr "매일"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "기본 기간"
|
||||
@@ -563,11 +584,12 @@ msgstr "장치"
|
||||
msgid "Discharging"
|
||||
msgstr "방전 중"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "디스크"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "디스크 I/O"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "디스크 I/O"
|
||||
msgid "Disk unit"
|
||||
msgstr "디스크 단위"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "{extraFsName}의 디스크 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker 메모리 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker 네트워크 I/O"
|
||||
|
||||
@@ -703,7 +731,7 @@ msgstr "마지막 {2, plural, one {# 분} other {# 분}} 동안 {0}{1} 초과"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "실행 메인 PID"
|
||||
msgstr "Exec 주 PID"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
@@ -770,7 +798,7 @@ msgstr "실패: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "FreeBSD 명령어"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "가득"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "전역"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU 엔진들"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU 전원 사용량"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "GPU 전원 사용량"
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU 사용량"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "그리드"
|
||||
@@ -912,7 +946,7 @@ msgstr "생명주기"
|
||||
msgid "limit"
|
||||
msgstr "제한"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "부하 평균"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "로드 상태"
|
||||
msgid "Loading..."
|
||||
msgstr "로딩 중..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "로그아웃"
|
||||
@@ -966,7 +1001,7 @@ msgstr "알림을 생성하려 하시나요? 시스템 테이블의 종 <0/> 아
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "메인 PID"
|
||||
msgstr "주 PID"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "수동 설정 방법"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "1분간 최댓값"
|
||||
|
||||
@@ -999,15 +1034,16 @@ msgstr "메모리 제한"
|
||||
msgid "Memory Peak"
|
||||
msgstr "메모리 최대값"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "메모리 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Docker 컨테이너의 메모리 사용량"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "모델"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "이름"
|
||||
msgid "Net"
|
||||
msgstr "네트워크"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Docker 컨테이너의 네트워크 트래픽"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1220,13 +1256,18 @@ msgstr "계정에 로그인하세요."
|
||||
msgid "Port"
|
||||
msgstr "포트"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "전원 켜기"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "기록된 시간의 정확한 사용량"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "조용한 시간"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "읽기"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "수신됨"
|
||||
|
||||
@@ -1304,7 +1345,7 @@ msgstr "재개"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "루트"
|
||||
msgstr "최상위"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
@@ -1326,6 +1367,10 @@ msgstr "S.M.A.R.T. 세부 정보"
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. 자체 테스트"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "{foo} 저장"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Enter 키 또는 쉼표를 사용하여 주소를 저장하세요. 이메일 알림을 비활성화하려면 비워 두세요."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Enter 키 또는 쉼표를 사용하여 주소를 저장하세요. 이
|
||||
msgid "Save Settings"
|
||||
msgstr "설정 저장"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "시스템 저장"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "데이터베이스에 저장되며 비활성화할 때까지 만료되지 않습니다."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "외부 모니터링 서비스에 주기적으로 아웃바운드 핑을
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "테스트 하트비트 전송"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "보냄"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "시리얼 번호"
|
||||
msgid "Service Details"
|
||||
msgstr "서비스 세부 정보"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "서비스"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "하트비트 모니터링을 활성화하려면 Beszel 허브에 다음
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "설정"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "상태"
|
||||
msgid "Sub State"
|
||||
msgstr "하위 상태"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "시스템에서 사용된 스왑 공간"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "스왑 사용량"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "스왑 사용량"
|
||||
msgid "System"
|
||||
msgstr "시스템"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "시간에 따른 시스템 부하 평균"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "시스템은 데이터 디렉토리 내의 <0>config.yml</0> 파일에
|
||||
msgid "Table"
|
||||
msgstr "표"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "작업"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "작업"
|
||||
msgid "Temp"
|
||||
msgstr "온도"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "온도"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "온도"
|
||||
msgid "Temperature unit"
|
||||
msgstr "온도 단위"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "시스템 센서의 온도"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ msgstr "이 작업은 되돌릴 수 없습니다. 데이터베이스에서 {name
|
||||
msgid "This will permanently delete all selected records from the database."
|
||||
msgstr "선택한 모든 레코드를 데이터베이스에서 영구적으로 삭제합니다."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "{extraFsName}의 처리량"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "루트 파일 시스템의 처리량"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "시간 형식"
|
||||
msgid "To email(s)"
|
||||
msgstr "받는사람(들)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "그리드 전환"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1675,7 +1720,7 @@ msgstr "유형"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "유닛 파일"
|
||||
msgstr "Unit 파일"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
@@ -1728,22 +1773,22 @@ msgstr "업로드"
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Uptime"
|
||||
msgstr "가동시간"
|
||||
msgstr "가동 시간"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "사용량"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "루트 파티션의 사용량"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "사용됨"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "최근 200개의 알림을 봅니다."
|
||||
msgid "Visible Fields"
|
||||
msgstr "표시할 열"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "표시할 충분한 기록을 기다리는 중"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Windows 명령어"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "쓰기"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: nl\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-02-19 19:40\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Dutch\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -42,14 +48,14 @@ msgstr "{count, plural, one {{countString} minuut} other {{countString} minuten}
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "{threads, plural, one {# thread} other {# threads}}"
|
||||
msgstr "{threads, plural, one {# thread} other {# threads}}"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 uur"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 minuut"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "12 uren"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 minuten"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "30 dagen"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 minuten"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Actieve status"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Voeg {foo} toe"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Voeg <0>Systeem</0> toe"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Voeg systeem toe"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Voeg URL toe"
|
||||
@@ -134,6 +135,7 @@ msgstr "Breedte van het hoofdlayout aanpassen"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Administrator"
|
||||
|
||||
@@ -147,7 +149,7 @@ msgstr "Start na het instellen van de omgevingsvariabelen je Beszel-hub opnieuw
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -163,6 +165,7 @@ msgstr "Waarschuwingen"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Alle containers"
|
||||
@@ -188,11 +191,11 @@ msgstr "Weet je het zeker?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatisch kopiëren vereist een veilige context."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Gemiddelde"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Gemiddeld CPU-gebruik van containers"
|
||||
|
||||
@@ -206,20 +209,20 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Gemiddeld stroomverbruik van GPU's"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Gemiddeld systeembrede CPU-gebruik"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Gemiddeld gebruik van {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Gemiddeld gebruik van GPU-engines"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Gemiddeld gebruik van GPU-engines"
|
||||
msgid "Backups"
|
||||
msgstr "Back-ups"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bandbreedte"
|
||||
@@ -236,9 +239,9 @@ msgstr "Bandbreedte"
|
||||
#. Battery label in systems table header
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Bat"
|
||||
msgstr "Bat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Batterij"
|
||||
@@ -277,7 +280,7 @@ msgstr "Binair"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
@@ -286,11 +289,11 @@ msgstr "Opstartstatus"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffers"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
@@ -324,7 +327,7 @@ msgstr "Opgelet - potentieel gegevensverlies"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr "Celsius (°C)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
@@ -334,7 +337,7 @@ msgstr "Verander statistiek eenheden."
|
||||
msgid "Change general application options."
|
||||
msgstr "Wijzig algemene applicatie opties."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Lading"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Opladen"
|
||||
msgid "Chart options"
|
||||
msgstr "Grafiekopties"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Grafiekbreedte"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Controleer {email} op een reset link."
|
||||
@@ -407,6 +414,10 @@ msgstr "Conflicten"
|
||||
msgid "Connection is down"
|
||||
msgstr "Verbinding is niet actief"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,11 +473,16 @@ msgstr "Kopieer de<0>docker-compose.yml</0> inhoud voor de agent hieronder, of r
|
||||
msgid "Copy YAML"
|
||||
msgstr "YAML kopiëren"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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"
|
||||
@@ -484,8 +500,8 @@ msgstr "CPU-tijd"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU-tijdverdeling"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Cumulatieve upload"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Huidige status"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Cycli"
|
||||
msgid "Daily"
|
||||
msgstr "Dagelijks"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Standaard tijdsduur"
|
||||
@@ -563,11 +584,12 @@ msgstr "Apparaat"
|
||||
msgid "Discharging"
|
||||
msgstr "Ontladen"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Schijf"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Schijf I/O"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "Schijf I/O"
|
||||
msgid "Disk unit"
|
||||
msgstr "Schijf eenheid"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Schijfgebruik van {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU-gebruik"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker geheugengebruik"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker netwerk I/O"
|
||||
|
||||
@@ -731,7 +759,7 @@ msgstr "Exporteer je huidige systeemconfiguratie."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Failed"
|
||||
@@ -770,7 +798,7 @@ msgstr "Mislukt: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -783,7 +811,7 @@ msgstr "Vingerafdruk"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "FreeBSD commando"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Vol"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "Globaal"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU-engines"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU stroomverbruik"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "GPU stroomverbruik"
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU-gebruik"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Raster"
|
||||
@@ -836,7 +870,7 @@ msgstr "Gezondheid"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -876,7 +910,7 @@ msgstr "Als je het wachtwoord voor je beheerdersaccount bent kwijtgeraakt, kan j
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Docker image"
|
||||
msgid "Image"
|
||||
msgstr "Afbeelding"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Inactive"
|
||||
@@ -884,7 +918,7 @@ msgstr "Inactief"
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Interval"
|
||||
msgstr "Interval"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Invalid email address."
|
||||
@@ -912,7 +946,7 @@ msgstr "Levenscyclus"
|
||||
msgid "limit"
|
||||
msgstr "limiet"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Gemiddelde Belasting"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Laadstatus"
|
||||
msgid "Loading..."
|
||||
msgstr "Laden..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Afmelden"
|
||||
@@ -978,9 +1013,9 @@ msgid "Manual setup instructions"
|
||||
msgstr "Handmatige installatie-instructies"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
@@ -999,18 +1034,19 @@ msgstr "Geheugenlimiet"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Geheugenpiek"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Geheugengebruik"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Geheugengebruik van docker containers"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Naam"
|
||||
msgid "Net"
|
||||
msgstr "Netwerk"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Netwerkverkeer van docker containers"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1220,13 +1256,18 @@ msgstr "Meld je aan bij je account"
|
||||
msgid "Port"
|
||||
msgstr "Poort"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Inschakelen"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Nauwkeurig gebruik op de opgenomen tijd"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Stille uren"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Lezen"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Ontvangen"
|
||||
|
||||
@@ -1304,7 +1345,7 @@ msgstr "Hervatten"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
@@ -1326,6 +1367,10 @@ msgstr "S.M.A.R.T.-details"
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. Zelf-test"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "{foo} opslaan"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Bewaar het adres met de enter-toets of komma. Laat leeg om e-mailmeldingen uit te schakelen."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Bewaar het adres met de enter-toets of komma. Laat leeg om e-mailmelding
|
||||
msgid "Save Settings"
|
||||
msgstr "Instellingen opslaan"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Systeem bewaren"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Opgeslagen in de database en verloopt niet totdat u het uitschakelt."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Stuur periodieke uitgaande pings naar een externe monitoringservice, zod
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Stuur test-heartbeat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Verzonden"
|
||||
|
||||
@@ -1399,9 +1440,10 @@ msgstr "Serienummer"
|
||||
msgid "Service Details"
|
||||
msgstr "Servicedetails"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Services"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Stel de volgende omgevingsvariabelen in op je Beszel-hub om heartbeat-mo
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Instellingen"
|
||||
|
||||
@@ -1453,23 +1497,24 @@ msgstr "Status"
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Substatus"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap ruimte gebruikt door het systeem"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap gebruik"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "Swap gebruik"
|
||||
msgid "System"
|
||||
msgstr "Systeem"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Gemiddelde systeembelasting na verloop van tijd"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "Systemen kunnen worden beheerd in een <0>config.yml</0> bestand in je da
|
||||
msgid "Table"
|
||||
msgstr "Tabel"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Taken"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "Taken"
|
||||
msgid "Temp"
|
||||
msgstr "Temperatuur"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatuur"
|
||||
@@ -1520,13 +1570,13 @@ msgstr "Temperatuur"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Temperatuureenheid"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperatuur van systeem sensoren"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Test heartbeat"
|
||||
@@ -1552,11 +1602,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Doorvoer van {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Doorvoer van het root bestandssysteem"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Tijdnotatie"
|
||||
msgid "To email(s)"
|
||||
msgstr "Naar e-mail(s)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Schakel raster"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1581,7 +1626,7 @@ msgstr "Schakel thema"
|
||||
#: 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
|
||||
@@ -1621,7 +1666,7 @@ msgstr "Geactiveerd door"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Triggers"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
@@ -1671,7 +1716,7 @@ msgstr "Triggert wanneer het gebruik van een schijf een drempelwaarde overschrij
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
@@ -1730,20 +1775,20 @@ msgstr "Uploaden"
|
||||
msgid "Uptime"
|
||||
msgstr "Actief"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Gebruik"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Gebruik van root-partitie"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Gebruikt"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Bekijk je 200 meest recente meldingen."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Zichtbare kolommen"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Wachtend op genoeg records om weer te geven"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Windows-commando"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Schrijven"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: no\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Norwegian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,9 +55,9 @@ msgid "1 hour"
|
||||
msgstr "1 time"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 minute"
|
||||
@@ -66,9 +72,9 @@ msgid "12 hours"
|
||||
msgstr "12 timer"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "24 hours"
|
||||
@@ -79,9 +85,9 @@ msgid "30 days"
|
||||
msgstr "30 dager"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 min"
|
||||
msgstr ""
|
||||
|
||||
#. Table column
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Aktiv tilstand"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Legg til {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Legg til <0>System</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Legg til system"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Legg Til URL"
|
||||
@@ -134,8 +135,9 @@ msgstr "Juster bredden på hovedlayouten"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
@@ -147,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 "Agent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -163,6 +165,7 @@ msgstr "Alarmer"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Alle containere"
|
||||
@@ -188,11 +191,11 @@ msgstr "Er du sikker?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatisk kopiering krever en sikker kontekst."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Gjennomsnitt"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Gjennomsnittlig CPU-utnyttelse av konteinere"
|
||||
|
||||
@@ -206,20 +209,20 @@ 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.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Gjennomsnittlig CPU-utnyttelse for hele systemet"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Gjennomsnittlig utnyttelse av {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Gjennomsnittlig utnyttelse av GPU-motorer"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Gjennomsnittlig utnyttelse av GPU-motorer"
|
||||
msgid "Backups"
|
||||
msgstr "Sikkerhetskopier"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Båndbredde"
|
||||
@@ -238,7 +241,7 @@ msgstr "Båndbredde"
|
||||
msgid "Bat"
|
||||
msgstr "Batteri"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Batteri"
|
||||
@@ -277,7 +280,7 @@ msgstr "Binær"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
@@ -286,9 +289,9 @@ msgstr "Oppstartstilstand"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffere"
|
||||
|
||||
@@ -324,7 +327,7 @@ msgstr "Advarsel - potensielt tap av data"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr "Celsius (°C)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
@@ -334,7 +337,7 @@ msgstr "Endre måleenheter for målinger."
|
||||
msgid "Change general application options."
|
||||
msgstr "Endre generelle program-innstillinger."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Lading"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Lader"
|
||||
msgid "Chart options"
|
||||
msgstr "Diagraminnstillinger"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Grafbredde"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Sjekk {email} for en nullstillings-link."
|
||||
@@ -407,6 +414,10 @@ msgstr "Konflikter"
|
||||
msgid "Connection is down"
|
||||
msgstr "Tilkoblingen er nede"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Containere"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,11 +473,16 @@ msgstr "Kopier <0>docker-compose.yml</0> for agenten nedenfor, eller registrer a
|
||||
msgid "Copy YAML"
|
||||
msgstr "Kopier YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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"
|
||||
@@ -484,8 +500,8 @@ msgstr "CPU-tid"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU-tidsoppdeling"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Kumulativ opplasting"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Nåværende tilstand"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Sykluser"
|
||||
msgid "Daily"
|
||||
msgstr "Daglig"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Standard tidsperiode"
|
||||
@@ -563,37 +584,44 @@ msgstr "Enhet"
|
||||
msgid "Discharging"
|
||||
msgstr "Lader ut"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Disk unit"
|
||||
msgstr "Diskenhet"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Diskbruk av {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU-bruk"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker Minnebruk"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker Nettverks-I/O"
|
||||
|
||||
@@ -731,7 +759,7 @@ msgstr "Eksporter din nåværende systemkonfigurasjon"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Failed"
|
||||
@@ -770,12 +798,12 @@ msgstr "Mislyktes: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Fingerprint"
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "FreeBSD kommando"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Fullt"
|
||||
@@ -812,13 +841,17 @@ msgstr "Generelt"
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Global"
|
||||
msgstr "Global"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU-motorer"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU Effektforbruk"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "GPU Effektforbruk"
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU-bruk"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Rutenett"
|
||||
@@ -836,7 +870,7 @@ msgstr "Helse"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -876,7 +910,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 "Image"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Inactive"
|
||||
@@ -912,7 +946,7 @@ msgstr "Livssyklus"
|
||||
msgid "limit"
|
||||
msgstr "grense"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Snittbelastning Last"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Lastetilstand"
|
||||
msgid "Loading..."
|
||||
msgstr "Laster..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Logg Ut"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Instruks for Manuell Installasjon"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Maks 1 min"
|
||||
|
||||
@@ -999,15 +1034,16 @@ msgstr "Minnegrense"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Minne-topp"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Minnebruk"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Minnebruk av docker-konteinere"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modell"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Navn"
|
||||
msgid "Net"
|
||||
msgstr "Nett"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Nettverkstrafikk av docker-konteinere"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1152,7 +1188,7 @@ msgstr "Fortid"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Paused"
|
||||
@@ -1177,7 +1213,7 @@ msgstr "Prosentandel av tid brukt i hver tilstand"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Permanent"
|
||||
msgstr "Permanent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Persistence"
|
||||
@@ -1218,15 +1254,20 @@ msgstr "Vennligst logg inn på kontoen din"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Påslag"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Nøyaktig utnyttelse på registrert tidspunkt"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Stille timer"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Lesing"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Mottatt"
|
||||
|
||||
@@ -1326,6 +1367,10 @@ msgstr "S.M.A.R.T.-detaljer"
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. selvtest"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Lagre {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Lagre adressen med Enter-tasten eller komma. La feltet være tomt for å deaktivere e-postvarsler."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Lagre adressen med Enter-tasten eller komma. La feltet være tomt for å
|
||||
msgid "Save Settings"
|
||||
msgstr "Lagre Innstillinger"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Lagre system"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Lagret i databasen og utløper ikke før du deaktiverer det."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Send periodiske utgående pinger til en ekstern overvåkingstjeneste sli
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Send test-heartbeat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Sendt"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Serienummer"
|
||||
msgid "Service Details"
|
||||
msgstr "Tjenestedetaljer"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Tjenester"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Angi følgende miljøvariabler på Beszel-huben din for å aktivere hear
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Innstillinger"
|
||||
|
||||
@@ -1453,23 +1497,24 @@ msgstr "Tilstand"
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Undertilstand"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap-plass i bruk av systemet"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap-bruk"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1479,9 +1524,9 @@ msgstr "Swap-bruk"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Systembelastning gjennomsnitt over tid"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "Systemer kan håndteres i en <0>config.yml</0>-fil i din data-katalog."
|
||||
msgid "Table"
|
||||
msgstr "Tabell"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Oppgaver"
|
||||
@@ -1509,9 +1559,9 @@ msgstr "Oppgaver"
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatur"
|
||||
@@ -1520,13 +1570,13 @@ msgstr "Temperatur"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Temperaturenhet"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturer på system-sensorer"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Test heartbeat"
|
||||
@@ -1552,11 +1602,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Gjennomstrømning av {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Gjennomstrømning av rot-filsystemet"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Tidsformat"
|
||||
msgid "To email(s)"
|
||||
msgstr "Til e-postadresse(r)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Rutenett av/på"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1581,7 +1626,7 @@ msgstr "Tema av/på"
|
||||
#: 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
|
||||
@@ -1671,7 +1716,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 "Type"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
@@ -1685,7 +1730,7 @@ msgstr "Enhetspreferanser"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Universal token"
|
||||
msgstr "Universal token"
|
||||
msgstr ""
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
@@ -1730,20 +1775,20 @@ msgstr "Last opp"
|
||||
msgid "Uptime"
|
||||
msgstr "Oppetid"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Forbruk"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Forbruk av rot-partisjon"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Brukt"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Vis de 200 siste varslene."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Synlige Felter"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Venter på nok registreringer til å vise"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Windows-kommando"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Skriving"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: pl\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\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"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,9 +55,9 @@ msgid "1 hour"
|
||||
msgstr "1 godzina"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 minute"
|
||||
@@ -66,9 +72,9 @@ msgid "12 hours"
|
||||
msgstr "12 godzin"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "24 hours"
|
||||
@@ -79,9 +85,9 @@ msgid "30 days"
|
||||
msgstr "30 dni"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 min"
|
||||
msgstr ""
|
||||
|
||||
#. Table column
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Stan aktywny"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Dodaj {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Dodaj <0>system</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Dodaj system"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Dodaj URL"
|
||||
@@ -134,8 +135,9 @@ msgstr "Dostosuj szerokość widoku"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
@@ -147,7 +149,7 @@ msgstr "Po ustawieniu zmiennych środowiskowych zrestartuj hub Beszel, aby zmian
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -163,6 +165,7 @@ msgstr "Alerty"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Wszystkie kontenery"
|
||||
@@ -188,11 +191,11 @@ msgstr "Czy jesteś pewien?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatyczne kopiowanie wymaga bezpiecznego kontekstu."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Średnia"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Średnie wykorzystanie CPU przez kontenery"
|
||||
|
||||
@@ -206,20 +209,20 @@ 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.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Średnie wykorzystanie CPU w całym systemie"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Średnie użycie {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Średnie wykorzystanie silników GPU"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Średnie wykorzystanie silników GPU"
|
||||
msgid "Backups"
|
||||
msgstr "Kopie zapasowe"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Przepustowość"
|
||||
@@ -238,7 +241,7 @@ msgstr "Przepustowość"
|
||||
msgid "Bat"
|
||||
msgstr "Bateria"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Bateria"
|
||||
@@ -288,7 +291,7 @@ msgstr "Stan rozruchu"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Bajty (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Pamięć podręczna / Bufory"
|
||||
|
||||
@@ -334,7 +337,7 @@ msgstr "Zmień jednostki wyświetlania dla metryk."
|
||||
msgid "Change general application options."
|
||||
msgstr "Zmień ogólne ustawienia aplikacji."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Ładowanie"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Ładuje się"
|
||||
msgid "Chart options"
|
||||
msgstr "Wykresy"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Szerokość wykresu"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Sprawdź {email}, aby uzyskać link do resetowania."
|
||||
@@ -407,6 +414,10 @@ msgstr "Konflikty"
|
||||
msgid "Connection is down"
|
||||
msgstr "Brak połączenia"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Kontenery"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,6 +473,11 @@ msgstr "Skopiuj poniżej zawartość pliku <0>docker-compose.yml</0> dla agenta
|
||||
msgid "Copy YAML"
|
||||
msgstr "Kopiuj YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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
|
||||
@@ -484,8 +500,8 @@ msgstr "Czas CPU"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Podział czasu CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Wysyłanie łącznie"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Aktualny stan"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Cykle"
|
||||
msgid "Daily"
|
||||
msgstr "Codziennie"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Domyślny przedział czasu"
|
||||
@@ -563,11 +584,12 @@ msgstr "Urządzenie"
|
||||
msgid "Discharging"
|
||||
msgstr "Rozładowuje się"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Dysk"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Dysk I/O"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "Dysk I/O"
|
||||
msgid "Disk unit"
|
||||
msgstr "Jednostka dysku"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Wykorzystanie dysku {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Użycie CPU przez Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Użycie pamięci przez Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Sieć Docker I/O"
|
||||
|
||||
@@ -731,7 +759,7 @@ msgstr "Eksportuj aktualną konfigurację systemów."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Failed"
|
||||
@@ -770,7 +798,7 @@ msgstr "Nieudane: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "Polecenie FreeBSD"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Pełna"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "Globalny"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "Silniki GPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Moc GPU"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "Moc GPU"
|
||||
msgid "GPU Usage"
|
||||
msgstr "Użycie GPU"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Siatka"
|
||||
@@ -836,7 +870,7 @@ msgstr "Kondycja"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -910,9 +944,9 @@ msgstr "Cykl życia"
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "limit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Średnie obciążenie"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Stan obciążenia"
|
||||
msgid "Loading..."
|
||||
msgstr "Ładowanie..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Wyloguj"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Instrukcja ręcznej konfiguracji"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Maks. 1 min"
|
||||
|
||||
@@ -999,18 +1034,19 @@ msgstr "Limit pamięci"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Szczyt pamięci"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Użycie pamięci"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Użycie pamięci przez kontenery Docker."
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Nazwa"
|
||||
msgid "Net"
|
||||
msgstr "Sieć"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Ruch sieciowy kontenerów Docker."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1218,15 +1254,20 @@ msgstr "Zaloguj się na swoje konto"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Włączony"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Dokładne wykorzystanie w zarejestrowanym czasie"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Godziny ciszy"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Odczyt"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Otrzymane"
|
||||
|
||||
@@ -1304,7 +1345,7 @@ msgstr "Wznów"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
@@ -1326,6 +1367,10 @@ msgstr "Szczegóły S.M.A.R.T."
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "Samodiagnostyka S.M.A.R.T."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Zapisz {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Zapisz adres, używając klawisza enter lub przecinka. Pozostaw puste, aby wyłączyć powiadomienia e-mail."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Zapisz adres, używając klawisza enter lub przecinka. Pozostaw puste, a
|
||||
msgid "Save Settings"
|
||||
msgstr "Zapisz ustawienia"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Zapisz system"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Zapisany w bazie danych. Nie wygasa, dopóki go nie wyłączysz."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Wysyłaj okresowe pingi wychodzące do zewnętrznej usługi monitorowani
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Wyślij testowy heartbeat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Wysłane"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Numer seryjny"
|
||||
msgid "Service Details"
|
||||
msgstr "Szczegóły usługi"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Usługi"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Ustaw następujące zmienne środowiskowe w hubie Beszel, aby włączyć
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Ustawienia"
|
||||
|
||||
@@ -1453,23 +1497,24 @@ msgstr "Stan"
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Stan podrzędny"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Pamięć wymiany używana przez system"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Użycie pamięci wymiany"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1479,9 +1524,9 @@ msgstr "Użycie pamięci wymiany"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Średnie obciążenie systemu w czasie"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "Systemy mogą być zarządzane w pliku <0>config.yml</0> znajdującym si
|
||||
msgid "Table"
|
||||
msgstr "Tabela"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Zadania"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "Zadania"
|
||||
msgid "Temp"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
@@ -1520,13 +1570,13 @@ msgstr "Temperatura"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Jednostka temperatury"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperatury czujników systemowych."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Test heartbeat"
|
||||
@@ -1552,11 +1602,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Przepustowość {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Przepustowość głównego systemu plików"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Format czasu"
|
||||
msgid "To email(s)"
|
||||
msgstr "Do e-mail(ów)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Przełącz widok"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1581,7 +1626,7 @@ msgstr "Zmień motyw"
|
||||
#: 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
|
||||
@@ -1728,22 +1773,22 @@ msgstr "Wysyłanie"
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Uptime"
|
||||
msgstr "Uptime"
|
||||
msgstr "Czas pracy"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Wykorzystanie"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Użycie partycji głównej"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Używane"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Wyświetl 200 ostatnich alertów."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Widoczne kolumny"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Oczekiwanie na wystarczającą liczbę rekordów do wyświetlenia"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Polecenie Windows"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Zapis"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: pt\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-03-27 19:17\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Portuguese\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -42,16 +48,16 @@ msgstr "{count, plural, one {{countString} minuto} other {{countString} minutos}
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "{threads, plural, one {# thread} other {# threads}}"
|
||||
msgstr "{threads, plural, one {# thread} other {# threads}}"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 hora"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 minute"
|
||||
@@ -66,9 +72,9 @@ msgid "12 hours"
|
||||
msgstr "12 horas"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "24 hours"
|
||||
@@ -79,9 +85,9 @@ msgid "30 days"
|
||||
msgstr "30 dias"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 min"
|
||||
msgstr ""
|
||||
|
||||
#. Table column
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Estado ativo"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Adicionar {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Adicionar <0>Sistema</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Adicionar sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Adicionar URL"
|
||||
@@ -134,8 +135,9 @@ msgstr "Ajustar a largura do layout principal"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
@@ -163,6 +165,7 @@ msgstr "Alertas"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Todos os Contêineres"
|
||||
@@ -188,11 +191,11 @@ msgstr "Tem certeza?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "A cópia automática requer um contexto seguro."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Média"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Utilização média de CPU dos contêineres"
|
||||
|
||||
@@ -206,20 +209,20 @@ 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.tsx
|
||||
#: 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.tsx
|
||||
#: 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"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Utilização média de {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Utilização média dos motores GPU"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Utilização média dos motores GPU"
|
||||
msgid "Backups"
|
||||
msgstr "Cópias de segurança"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Largura de Banda"
|
||||
@@ -236,9 +239,9 @@ msgstr "Largura de Banda"
|
||||
#. Battery label in systems table header
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Bat"
|
||||
msgstr "Bat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Bateria"
|
||||
@@ -277,7 +280,7 @@ msgstr "Binário"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
@@ -286,11 +289,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 "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffers"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
@@ -324,7 +327,7 @@ msgstr "Cuidado - possível perda de dados"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr "Celsius (°C)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
@@ -334,7 +337,7 @@ msgstr "Alterar unidades de exibição para métricas."
|
||||
msgid "Change general application options."
|
||||
msgstr "Alterar opções gerais do aplicativo."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Carga"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Carregando"
|
||||
msgid "Chart options"
|
||||
msgstr "Opções de gráfico"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Largura do gráfico"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Verifique {email} para um link de redefinição."
|
||||
@@ -407,6 +414,10 @@ msgstr "Conflitos"
|
||||
msgid "Connection is down"
|
||||
msgstr "A conexão está inativa"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Contentores"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,11 +473,16 @@ msgstr "Copie o conteúdo do <0>docker-compose.yml</0> do agente abaixo, ou regi
|
||||
msgid "Copy YAML"
|
||||
msgstr "Copiar YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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"
|
||||
@@ -484,8 +500,8 @@ msgstr "Tempo de CPU"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Distribuição do Tempo de CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Upload cumulativo"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Estado atual"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Ciclos"
|
||||
msgid "Daily"
|
||||
msgstr "Diariamente"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Período de tempo padrão"
|
||||
@@ -563,11 +584,12 @@ msgstr "Dispositivo"
|
||||
msgid "Discharging"
|
||||
msgstr "Descarregando"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Disco"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "E/S de Disco"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "E/S de Disco"
|
||||
msgid "Disk unit"
|
||||
msgstr "Unidade de disco"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Uso de disco de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Uso de CPU do Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Uso de Memória do Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "E/S de Rede do Docker"
|
||||
|
||||
@@ -636,7 +664,7 @@ msgstr "Editar {foo}"
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
#: src/components/login/otp-forms.tsx
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Email notifications"
|
||||
@@ -731,7 +759,7 @@ msgstr "Exporte a configuração atual dos seus sistemas."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Failed"
|
||||
@@ -770,7 +798,7 @@ msgstr "Falhou: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -783,7 +811,7 @@ msgstr "Impressão digital"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "Comando FreeBSD"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Cheia"
|
||||
@@ -812,13 +841,17 @@ msgstr "Geral"
|
||||
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Global"
|
||||
msgstr "Global"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "Motores GPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Consumo de Energia da GPU"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "Consumo de Energia da GPU"
|
||||
msgid "GPU Usage"
|
||||
msgstr "Uso de GPU"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Grade"
|
||||
@@ -836,7 +870,7 @@ msgstr "Saúde"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -854,7 +888,7 @@ msgstr "Comando Homebrew"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "HTTP Method"
|
||||
@@ -912,7 +946,7 @@ msgstr "Ciclo de vida"
|
||||
msgid "limit"
|
||||
msgstr "limite"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Carga Média"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Estado de carga"
|
||||
msgid "Loading..."
|
||||
msgstr "Carregando..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Sair"
|
||||
@@ -958,7 +993,7 @@ msgstr "Tentativa de login falhou"
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Logs"
|
||||
msgstr "Logs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Instruções de configuração manual"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Máx 1 min"
|
||||
|
||||
@@ -999,15 +1034,16 @@ msgstr "Limite de memória"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Pico de memória"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Uso de Memória"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Uso de memória dos contêineres Docker"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modelo"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Nome"
|
||||
msgid "Net"
|
||||
msgstr "Rede"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Tráfego de rede dos contêineres Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1220,13 +1256,18 @@ msgstr "Por favor, entre na sua conta"
|
||||
msgid "Port"
|
||||
msgstr "Porta"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Ligado"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilização precisa no momento registrado"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Horas Silenciosas"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Ler"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Recebido"
|
||||
|
||||
@@ -1304,7 +1345,7 @@ msgstr "Retomar"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
@@ -1326,6 +1367,10 @@ msgstr "Detalhes S.M.A.R.T."
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "Auto-teste S.M.A.R.T."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Guardar {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Salve o endereço usando a tecla enter ou vírgula. Deixe em branco para desativar notificações por email."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Salve o endereço usando a tecla enter ou vírgula. Deixe em branco para
|
||||
msgid "Save Settings"
|
||||
msgstr "Guardar Definições"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Guardar Sistema"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Salvo no banco de dados e não expira até você desativá-lo."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Envie pings de saída periódicos para um serviço de monitorização ex
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Enviar heartbeat de teste"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Enviado"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Número de Série"
|
||||
msgid "Service Details"
|
||||
msgstr "Detalhes do serviço"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Serviços"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Defina as seguintes variáveis de ambiente no seu hub do Beszel para ati
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Configurações"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "Estado"
|
||||
msgid "Sub State"
|
||||
msgstr "Subestado"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Espaço de swap usado pelo sistema"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Uso de Swap"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "Uso de Swap"
|
||||
msgid "System"
|
||||
msgstr "Sistema"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Médias de carga do sistema ao longo do tempo"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "Os sistemas podem ser gerenciados em um arquivo <0>config.yml</0> dentro
|
||||
msgid "Table"
|
||||
msgstr "Tabela"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Tarefas"
|
||||
@@ -1509,9 +1559,9 @@ msgstr "Tarefas"
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Temp"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "Temperatura"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Unidade de temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturas dos sensores do sistema"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Taxa de transferência de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Taxa de transferência do sistema de arquivos raiz"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Formato de hora"
|
||||
msgid "To email(s)"
|
||||
msgstr "Para email(s)"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Alternar grade"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1581,7 +1626,7 @@ msgstr "Alternar tema"
|
||||
#: 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
|
||||
@@ -1600,7 +1645,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 "Total"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
@@ -1613,7 +1658,7 @@ msgstr "Dados totais enviados para cada interface"
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Total: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
@@ -1728,22 +1773,22 @@ msgstr "Carregar"
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Uptime"
|
||||
msgstr "Uptime"
|
||||
msgstr "Tempo de Atividade"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Uso"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Uso da partição raiz"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Usado"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Veja os seus 200 alertas mais recentes."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Campos Visíveis"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Aguardando registros suficientes para exibir"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Comando Windows"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Escrever"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: ru\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2026-01-31 21:16\n"
|
||||
"PO-Revision-Date: 2026-02-21 09:46\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"
|
||||
@@ -18,6 +18,12 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: newVersion.v
|
||||
#: src/components/footer-repo-link.tsx
|
||||
msgctxt "New version available"
|
||||
msgid "{0} available"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -49,7 +55,7 @@ msgid "1 hour"
|
||||
msgstr "1 час"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 мин"
|
||||
|
||||
@@ -66,7 +72,7 @@ msgid "12 hours"
|
||||
msgstr "12 часов"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 мин"
|
||||
|
||||
@@ -79,7 +85,7 @@ msgid "30 days"
|
||||
msgstr "30 дней"
|
||||
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 мин"
|
||||
|
||||
@@ -107,19 +113,14 @@ msgid "Active state"
|
||||
msgstr "Активное состояние"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
msgid "Add {foo}"
|
||||
msgstr "Добавить {foo}"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Добавить <0>Систему</0>"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add system"
|
||||
msgstr "Добавить систему"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Add URL"
|
||||
msgstr "Добавить URL"
|
||||
@@ -134,6 +135,7 @@ msgstr "Настроить ширину основного макета"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Администратор"
|
||||
|
||||
@@ -163,6 +165,7 @@ msgstr "Оповещения"
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Все контейнеры"
|
||||
@@ -188,11 +191,11 @@ msgstr "Вы уверены?"
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Автоматическое копирование требует безопасного контекста."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Average"
|
||||
msgstr "Среднее"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Среднее использование CPU контейнерами"
|
||||
|
||||
@@ -206,20 +209,20 @@ msgstr "Среднее опускается ниже <0>{value}{0}</0>"
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Среднее превышает <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average power consumption of GPUs"
|
||||
msgstr "Среднее потребление мощности всеми GPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Среднее использование CPU по всей системе"
|
||||
|
||||
#. placeholder {0}: gpu.n
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of {0}"
|
||||
msgstr "Среднее использование {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Средняя загрузка GPU движков"
|
||||
|
||||
@@ -228,7 +231,7 @@ msgstr "Средняя загрузка GPU движков"
|
||||
msgid "Backups"
|
||||
msgstr "Резервные копии"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Bandwidth"
|
||||
msgstr "Пропускная способность"
|
||||
@@ -238,7 +241,7 @@ msgstr "Пропускная способность"
|
||||
msgid "Bat"
|
||||
msgstr "Батарея"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Battery"
|
||||
msgstr "Батарея"
|
||||
@@ -288,7 +291,7 @@ msgstr "Состояние загрузки"
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr "Байты (Кбайт/с, Мбайт/с, Гбайт/с)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Кэш / Буферы"
|
||||
|
||||
@@ -334,7 +337,7 @@ msgstr "Изменить единицы измерения для метрик."
|
||||
msgid "Change general application options."
|
||||
msgstr "Изменить общие параметры приложения."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Charge"
|
||||
msgstr "Заряд"
|
||||
|
||||
@@ -347,6 +350,10 @@ msgstr "Заряжается"
|
||||
msgid "Chart options"
|
||||
msgstr "Параметры графиков"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Chart width"
|
||||
msgstr "Ширина графика"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Проверьте {email} для получения ссылки на сброс."
|
||||
@@ -407,6 +414,10 @@ msgstr "Конфликты"
|
||||
msgid "Connection is down"
|
||||
msgstr "Нет соединения"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Containers"
|
||||
msgstr "Контейнеры"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Continue"
|
||||
@@ -462,6 +473,11 @@ msgstr "Скопируйте содержимое <0>docker-compose.yml</0> дл
|
||||
msgid "Copy YAML"
|
||||
msgstr "Скопировать YAML"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgctxt "Core system metrics"
|
||||
msgid "Core"
|
||||
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
|
||||
@@ -484,8 +500,8 @@ msgstr "Время CPU"
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Распределение времени ЦП"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
@@ -517,7 +533,7 @@ msgid "Cumulative Upload"
|
||||
msgstr "Совокупная отдача"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Current state"
|
||||
msgstr "Текущее состояние"
|
||||
|
||||
@@ -531,6 +547,11 @@ msgstr "Циклы"
|
||||
msgid "Daily"
|
||||
msgstr "Ежедневно"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Default system layout option"
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
msgstr "Период по умолчанию"
|
||||
@@ -563,11 +584,12 @@ msgstr "Устройство"
|
||||
msgid "Discharging"
|
||||
msgstr "Разряжается"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Disk"
|
||||
msgstr "Диск"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Disk I/O"
|
||||
msgstr "Дисковый ввод/вывод"
|
||||
|
||||
@@ -575,25 +597,31 @@ msgstr "Дисковый ввод/вывод"
|
||||
msgid "Disk unit"
|
||||
msgstr "Единицы измерения дисковой активности"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: 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.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Использование диска {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Layout display options"
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/cpu-charts.tsx
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Использование CPU Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Использование памяти Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Сетевой ввод/вывод Docker"
|
||||
|
||||
@@ -770,7 +798,7 @@ msgstr "Неудачно: {0}"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -800,6 +828,7 @@ msgid "FreeBSD command"
|
||||
msgstr "Команда FreeBSD"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Полная"
|
||||
@@ -815,10 +844,14 @@ msgid "Global"
|
||||
msgstr "Глобально"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU движки"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Потребляемая мощность GPU"
|
||||
|
||||
@@ -826,6 +859,7 @@ msgstr "Потребляемая мощность GPU"
|
||||
msgid "GPU Usage"
|
||||
msgstr "Использование GPU"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Сетка"
|
||||
@@ -836,7 +870,7 @@ msgstr "Здоровье"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Heartbeat"
|
||||
msgstr "Heartbeat"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/heartbeat.tsx
|
||||
msgid "Heartbeat Monitoring"
|
||||
@@ -912,7 +946,7 @@ msgstr "Жизненный цикл"
|
||||
msgid "limit"
|
||||
msgstr "лимит"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Средняя загрузка"
|
||||
|
||||
@@ -941,6 +975,7 @@ msgstr "Состояние загрузки"
|
||||
msgid "Loading..."
|
||||
msgstr "Загрузка..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Выйти"
|
||||
@@ -978,7 +1013,7 @@ msgid "Manual setup instructions"
|
||||
msgstr "Инструкции по ручной настройке"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Max 1 min"
|
||||
msgstr "Макс 1 мин"
|
||||
|
||||
@@ -999,15 +1034,16 @@ msgstr "Лимит памяти"
|
||||
msgid "Memory Peak"
|
||||
msgstr "Пик памяти"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
msgstr "Использование памяти"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Использование памяти контейнерами Docker"
|
||||
|
||||
#. Device model
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Модель"
|
||||
@@ -1025,11 +1061,11 @@ msgstr "Имя"
|
||||
msgid "Net"
|
||||
msgstr "Сеть"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Сетевой трафик контейнеров Docker"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
@@ -1220,13 +1256,18 @@ msgstr "Пожалуйста, войдите в свою учетную запи
|
||||
msgid "Port"
|
||||
msgstr "Порт"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Container ports"
|
||||
msgid "Ports"
|
||||
msgstr ""
|
||||
|
||||
#. Power On Time
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Power On"
|
||||
msgstr "Включение питания"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/gpu-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Точное использование в записанное время"
|
||||
|
||||
@@ -1248,12 +1289,12 @@ msgid "Quiet Hours"
|
||||
msgstr "Тихие часы"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Read"
|
||||
msgstr "Чтение"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Received"
|
||||
msgstr "Получено"
|
||||
|
||||
@@ -1326,6 +1367,10 @@ msgstr "Детали S.M.A.R.T."
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "Самотестирование S.M.A.R.T."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save {foo}"
|
||||
msgstr "Сохранить {foo}"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Сохраните адрес, используя клавишу ввода или запятую. Оставьте пустым, чтобы отключить уведомления по электронной почте."
|
||||
@@ -1335,10 +1380,6 @@ msgstr "Сохраните адрес, используя клавишу вво
|
||||
msgid "Save Settings"
|
||||
msgstr "Сохранить настройки"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "Сохранить систему"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Saved in the database and does not expire until you disable it."
|
||||
msgstr "Сохранено в базе данных и не истекает, пока вы его не отключите."
|
||||
@@ -1387,7 +1428,7 @@ msgstr "Отправляйте периодические исходящие п
|
||||
msgid "Send test heartbeat"
|
||||
msgstr "Отправить тестовый heartbeat"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/network-charts.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Отправлено"
|
||||
|
||||
@@ -1399,6 +1440,7 @@ msgstr "Серийный номер"
|
||||
msgid "Service Details"
|
||||
msgstr "Детали сервиса"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Services"
|
||||
msgstr "Службы"
|
||||
@@ -1414,8 +1456,10 @@ msgstr "Установите следующие переменные окруж
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Settings"
|
||||
msgstr "Настройки"
|
||||
|
||||
@@ -1459,17 +1503,18 @@ msgstr "Статус"
|
||||
msgid "Sub State"
|
||||
msgstr "Подсостояние"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Используемое системой пространство подкачки"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Swap Usage"
|
||||
msgstr "Использование подкачки"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/navbar.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
#: src/components/routes/settings/quiet-hours.tsx
|
||||
@@ -1481,7 +1526,7 @@ msgstr "Использование подкачки"
|
||||
msgid "System"
|
||||
msgstr "Система"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/load-average-chart.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Средняя загрузка системы за время"
|
||||
|
||||
@@ -1501,6 +1546,11 @@ msgstr "Системы могут управляться в файле <0>config
|
||||
msgid "Table"
|
||||
msgstr "Таблица"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgctxt "Tabs system layout option"
|
||||
msgid "Tabs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Задачи"
|
||||
@@ -1511,7 +1561,7 @@ msgstr "Задачи"
|
||||
msgid "Temp"
|
||||
msgstr "Темп"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Temperature"
|
||||
msgstr "Температура"
|
||||
@@ -1520,7 +1570,7 @@ msgstr "Температура"
|
||||
msgid "Temperature unit"
|
||||
msgstr "Единицы измерения температуры"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/sensor-charts.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Температуры датчиков системы"
|
||||
|
||||
@@ -1552,11 +1602,11 @@ msgstr "Это действие не может быть отменено. Эт
|
||||
msgid "This will permanently delete all selected records from the database."
|
||||
msgstr "Это навсегда удалит все выбранные записи из базы данных."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Пропускная способность {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Пропускная способность корневой файловой системы"
|
||||
|
||||
@@ -1568,11 +1618,6 @@ msgstr "Формат времени"
|
||||
msgid "To email(s)"
|
||||
msgstr "На электронную почту"
|
||||
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
msgid "Toggle grid"
|
||||
msgstr "Переключить сетку"
|
||||
|
||||
#: src/components/mode-toggle.tsx
|
||||
#: src/components/mode-toggle.tsx
|
||||
msgid "Toggle theme"
|
||||
@@ -1728,22 +1773,22 @@ msgstr "Отдача"
|
||||
#: src/components/routes/system/info-bar.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Uptime"
|
||||
msgstr "Uptime"
|
||||
msgstr "Время работы"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-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
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Использование"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Использование корневого раздела"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
#: src/components/charts/swap-chart.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
#: src/components/routes/system/charts/memory-charts.tsx
|
||||
msgid "Used"
|
||||
msgstr "Использовано"
|
||||
|
||||
@@ -1773,7 +1818,7 @@ msgstr "Просмотреть 200 последних оповещений."
|
||||
msgid "Visible Fields"
|
||||
msgstr "Видимые столбцы"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/chart-card.tsx
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Ожидание достаточного количества записей для отображения"
|
||||
|
||||
@@ -1812,8 +1857,8 @@ msgid "Windows command"
|
||||
msgstr "Команда Windows"
|
||||
|
||||
#. Disk write
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/charts/disk-charts.tsx
|
||||
#: src/components/routes/system/charts/extra-fs-charts.tsx
|
||||
msgid "Write"
|
||||
msgstr "Запись"
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user