mirror of
https://github.com/henrygd/beszel.git
synced 2026-04-12 07:51:50 +02:00
Compare commits
79 Commits
962613df7c
...
v0.16.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7915b9d0e | ||
|
|
4443b606f6 | ||
|
|
6c20a98651 | ||
|
|
b722ccc5bc | ||
|
|
db0315394b | ||
|
|
a7ef1235f4 | ||
|
|
f64a361c60 | ||
|
|
aaa788bc2f | ||
|
|
3eede6bead | ||
|
|
02abfbcb54 | ||
|
|
01d20562f0 | ||
|
|
cbe6ee6499 | ||
|
|
9a61ea8356 | ||
|
|
1af7ff600f | ||
|
|
02d594cc82 | ||
|
|
7d0b5c1c67 | ||
|
|
d3dc8a7af0 | ||
|
|
d67fefe7c5 | ||
|
|
4d364c5e4d | ||
|
|
954400ea45 | ||
|
|
04b6067e64 | ||
|
|
d77ee5554f | ||
|
|
2e034bdead | ||
|
|
fc0947aa04 | ||
|
|
1d546a4091 | ||
|
|
f60b3bbbfb | ||
|
|
8e99b9f1ad | ||
|
|
fa5ed2bc11 | ||
|
|
21d961ab97 | ||
|
|
aaa93b84d2 | ||
|
|
6a562ce03b | ||
|
|
3dbc48727e | ||
|
|
85ac2e5e9a | ||
|
|
af6bd4e505 | ||
|
|
e54c4b3499 | ||
|
|
078c88f825 | ||
|
|
85169b6c5e | ||
|
|
d0ff8ee2c0 | ||
|
|
e898768997 | ||
|
|
0f5b504f23 | ||
|
|
365d291393 | ||
|
|
3dbab24c0f | ||
|
|
1f67fb7c8d | ||
|
|
219e09fc78 | ||
|
|
cd9c2bd9ab | ||
|
|
9f969d843c | ||
|
|
b22a6472fc | ||
|
|
d231ace28e | ||
|
|
473cb7f437 | ||
|
|
783ed9f456 | ||
|
|
9a9a89ee50 | ||
|
|
5122d0341d | ||
|
|
81731689da | ||
|
|
b3e9857448 | ||
|
|
2eda9eb0e3 | ||
|
|
82a5df5048 | ||
|
|
f11564a7ac | ||
|
|
9df4d29236 | ||
|
|
1452817423 | ||
|
|
c57e496f5e | ||
|
|
6287f7003c | ||
|
|
37037b1f4e | ||
|
|
7cf123a99e | ||
|
|
97394e775f | ||
|
|
d5c381188b | ||
|
|
b107d12a62 | ||
|
|
e646f2c1fc | ||
|
|
b18528d24a | ||
|
|
a6e64df399 | ||
|
|
66ba21dd41 | ||
|
|
1851e7a111 | ||
|
|
74b78e96b3 | ||
|
|
a9657f9c00 | ||
|
|
1dee63a0eb | ||
|
|
d608cf0955 | ||
|
|
b9139a1f9b | ||
|
|
7f372c46db | ||
|
|
40010ad9b9 | ||
|
|
5927f45a4a |
101
.github/workflows/docker-images.yml
vendored
101
.github/workflows/docker-images.yml
vendored
@@ -12,65 +12,139 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# henrygd/beszel
|
||||
- image: henrygd/beszel
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_hub
|
||||
registry: docker.io
|
||||
username_secret: DOCKERHUB_USERNAME
|
||||
password_secret: DOCKERHUB_TOKEN
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=raw,value={{sha}},enable=${{ github.ref_type != 'tag' }}
|
||||
|
||||
# henrygd/beszel-agent
|
||||
- image: henrygd/beszel-agent
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_agent
|
||||
registry: docker.io
|
||||
username_secret: DOCKERHUB_USERNAME
|
||||
password_secret: DOCKERHUB_TOKEN
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=raw,value=latest
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=raw,value={{sha}},enable=${{ github.ref_type != 'tag' }}
|
||||
|
||||
# henrygd/beszel-agent-nvidia
|
||||
- image: henrygd/beszel-agent-nvidia
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_agent_nvidia
|
||||
platforms: linux/amd64
|
||||
registry: docker.io
|
||||
username_secret: DOCKERHUB_USERNAME
|
||||
password_secret: DOCKERHUB_TOKEN
|
||||
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=raw,value={{sha}},enable=${{ github.ref_type != 'tag' }}
|
||||
|
||||
# henrygd/beszel-agent-intel
|
||||
- image: henrygd/beszel-agent-intel
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_agent_intel
|
||||
platforms: linux/amd64
|
||||
registry: docker.io
|
||||
username_secret: DOCKERHUB_USERNAME
|
||||
password_secret: DOCKERHUB_TOKEN
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=raw,value={{sha}},enable=${{ github.ref_type != 'tag' }}
|
||||
|
||||
# henrygd/beszel-agent:alpine
|
||||
- image: henrygd/beszel-agent
|
||||
dockerfile: ./internal/dockerfile_agent_alpine
|
||||
registry: docker.io
|
||||
username_secret: DOCKERHUB_USERNAME
|
||||
password_secret: DOCKERHUB_TOKEN
|
||||
tags: |
|
||||
type=raw,value=alpine
|
||||
type=semver,pattern={{version}}-alpine
|
||||
type=semver,pattern={{major}}.{{minor}}-alpine
|
||||
type=semver,pattern={{major}}-alpine
|
||||
|
||||
# ghcr.io/henrygd/beszel
|
||||
- image: ghcr.io/${{ github.repository }}/beszel
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_hub
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password_secret: GITHUB_TOKEN
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=raw,value={{sha}},enable=${{ github.ref_type != 'tag' }}
|
||||
|
||||
# ghcr.io/henrygd/beszel-agent
|
||||
- image: ghcr.io/${{ github.repository }}/beszel-agent
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_agent
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password_secret: GITHUB_TOKEN
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=raw,value=latest
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=raw,value={{sha}},enable=${{ github.ref_type != 'tag' }}
|
||||
|
||||
# ghcr.io/henrygd/beszel-agent-nvidia
|
||||
- image: ghcr.io/${{ github.repository }}/beszel-agent-nvidia
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_agent_nvidia
|
||||
platforms: linux/amd64
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password_secret: GITHUB_TOKEN
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=raw,value={{sha}},enable=${{ github.ref_type != 'tag' }}
|
||||
|
||||
# ghcr.io/henrygd/beszel-agent-intel
|
||||
- image: ghcr.io/${{ github.repository }}/beszel-agent-intel
|
||||
context: ./
|
||||
dockerfile: ./internal/dockerfile_agent_intel
|
||||
platforms: linux/amd64
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password_secret: GITHUB_TOKEN
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=raw,value={{sha}},enable=${{ github.ref_type != 'tag' }}
|
||||
|
||||
# ghcr.io/henrygd/beszel-agent:alpine
|
||||
- image: ghcr.io/${{ github.repository }}/beszel-agent
|
||||
dockerfile: ./internal/dockerfile_agent_alpine
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password_secret: GITHUB_TOKEN
|
||||
tags: |
|
||||
type=raw,value=alpine
|
||||
type=semver,pattern={{version}}-alpine
|
||||
type=semver,pattern={{major}}.{{minor}}-alpine
|
||||
type=semver,pattern={{major}}-alpine
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -100,12 +174,7 @@ jobs:
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ matrix.image }}
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=raw,value={{sha}},enable=${{ github.ref_type != 'tag' }}
|
||||
tags: ${{ matrix.tags }}
|
||||
|
||||
# https://github.com/docker/login-action
|
||||
- name: Login to Docker Hub
|
||||
@@ -123,7 +192,7 @@ jobs:
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: "${{ matrix.context }}"
|
||||
context: ./
|
||||
file: ${{ matrix.dockerfile }}
|
||||
platforms: ${{ matrix.platforms || 'linux/amd64,linux/arm64,linux/arm/v7' }}
|
||||
push: ${{ github.ref_type == 'tag' && secrets[matrix.password_secret] != '' }}
|
||||
|
||||
@@ -5,6 +5,7 @@ project_name: beszel
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
- go generate -run fetchsmartctl ./agent
|
||||
|
||||
builds:
|
||||
- id: beszel
|
||||
|
||||
10
Makefile
10
Makefile
@@ -7,7 +7,7 @@ SKIP_WEB ?= false
|
||||
# Set executable extension based on target OS
|
||||
EXE_EXT := $(if $(filter windows,$(OS)),.exe,)
|
||||
|
||||
.PHONY: tidy build-agent build-hub build-hub-dev build clean lint dev-server dev-agent dev-hub dev generate-locales
|
||||
.PHONY: tidy build-agent build-hub build-hub-dev build clean lint dev-server dev-agent dev-hub dev generate-locales fetch-smartctl-conditional
|
||||
.DEFAULT_GOAL := build
|
||||
|
||||
clean:
|
||||
@@ -46,8 +46,14 @@ build-dotnet-conditional:
|
||||
fi; \
|
||||
fi
|
||||
|
||||
# Download smartctl.exe at build time for Windows (skips if already present)
|
||||
fetch-smartctl-conditional:
|
||||
@if [ "$(OS)" = "windows" ]; then \
|
||||
go generate -run fetchsmartctl ./agent; \
|
||||
fi
|
||||
|
||||
# Update build-agent to include conditional .NET build
|
||||
build-agent: tidy build-dotnet-conditional
|
||||
build-agent: tidy build-dotnet-conditional fetch-smartctl-conditional
|
||||
GOOS=$(OS) GOARCH=$(ARCH) go build -o ./build/beszel-agent_$(OS)_$(ARCH)$(EXE_EXT) -ldflags "-w -s" ./internal/cmd/agent
|
||||
|
||||
build-hub: tidy $(if $(filter false,$(SKIP_WEB)),build-web-ui)
|
||||
|
||||
@@ -43,6 +43,7 @@ type Agent struct {
|
||||
dataDir string // Directory for persisting data
|
||||
keys []gossh.PublicKey // SSH public keys
|
||||
smartManager *SmartManager // Manages SMART data
|
||||
systemdManager *systemdManager // Manages systemd services
|
||||
}
|
||||
|
||||
// NewAgent creates a new agent with the given data directory for persisting data.
|
||||
@@ -101,6 +102,11 @@ func NewAgent(dataDir ...string) (agent *Agent, err error) {
|
||||
// initialize docker manager
|
||||
agent.dockerManager = newDockerManager(agent)
|
||||
|
||||
agent.systemdManager, err = newSystemdManager()
|
||||
if err != nil {
|
||||
slog.Debug("Systemd", "err", err)
|
||||
}
|
||||
|
||||
agent.smartManager, err = NewSmartManager()
|
||||
if err != nil {
|
||||
slog.Debug("SMART", "err", err)
|
||||
@@ -154,7 +160,13 @@ func (a *Agent) gatherStats(cacheTimeMs uint16) *system.CombinedData {
|
||||
}
|
||||
}
|
||||
|
||||
// skip updating systemd services if cache time is not the default 60sec interval
|
||||
if a.systemdManager != nil && cacheTimeMs == 60_000 && a.systemdManager.hasFreshStats {
|
||||
data.SystemdServices = a.systemdManager.getServiceStats(nil, false)
|
||||
}
|
||||
|
||||
data.Stats.ExtraFs = make(map[string]*system.FsStats)
|
||||
data.Info.ExtraFsPct = make(map[string]float64)
|
||||
for name, stats := range a.fsStats {
|
||||
if !stats.Root && stats.DiskTotal > 0 {
|
||||
// Use custom name if available, otherwise use device name
|
||||
@@ -163,6 +175,11 @@ func (a *Agent) gatherStats(cacheTimeMs uint16) *system.CombinedData {
|
||||
key = stats.Name
|
||||
}
|
||||
data.Stats.ExtraFs[key] = stats
|
||||
// Add percentages to Info struct for dashboard
|
||||
if stats.DiskTotal > 0 {
|
||||
pct := twoDecimals((stats.DiskUsed / stats.DiskTotal) * 100)
|
||||
data.Info.ExtraFsPct[key] = pct
|
||||
}
|
||||
}
|
||||
}
|
||||
slog.Debug("Extra FS", "data", data.Stats.ExtraFs)
|
||||
|
||||
@@ -6,12 +6,15 @@ package battery
|
||||
import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
"math"
|
||||
|
||||
"github.com/distatus/battery"
|
||||
)
|
||||
|
||||
var systemHasBattery = false
|
||||
var haveCheckedBattery = false
|
||||
var (
|
||||
systemHasBattery = false
|
||||
haveCheckedBattery = false
|
||||
)
|
||||
|
||||
// HasReadableBattery checks if the system has a battery and returns true if it does.
|
||||
func HasReadableBattery() bool {
|
||||
@@ -19,8 +22,13 @@ func HasReadableBattery() bool {
|
||||
return systemHasBattery
|
||||
}
|
||||
haveCheckedBattery = true
|
||||
bat, err := battery.Get(0)
|
||||
systemHasBattery = err == nil && bat != nil && bat.Design != 0 && bat.Full != 0
|
||||
batteries, err := battery.GetAll()
|
||||
for _, bat := range batteries {
|
||||
if bat != nil && (bat.Full > 0 || bat.Design > 0) {
|
||||
systemHasBattery = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !systemHasBattery {
|
||||
slog.Debug("No battery found", "err", err)
|
||||
}
|
||||
@@ -28,25 +36,49 @@ func HasReadableBattery() bool {
|
||||
}
|
||||
|
||||
// GetBatteryStats returns the current battery percent and charge state
|
||||
// percent = (current charge of all batteries) / (sum of designed/full capacity of all batteries)
|
||||
func GetBatteryStats() (batteryPercent uint8, batteryState uint8, err error) {
|
||||
if !systemHasBattery {
|
||||
if !HasReadableBattery() {
|
||||
return batteryPercent, batteryState, errors.ErrUnsupported
|
||||
}
|
||||
batteries, err := battery.GetAll()
|
||||
if err != nil || len(batteries) == 0 {
|
||||
return batteryPercent, batteryState, err
|
||||
// we'll handle errors later by skipping batteries with errors, rather
|
||||
// than skipping everything because of the presence of some errors.
|
||||
if len(batteries) == 0 {
|
||||
return batteryPercent, batteryState, errors.New("no batteries")
|
||||
}
|
||||
|
||||
totalCapacity := float64(0)
|
||||
totalCharge := float64(0)
|
||||
for _, bat := range batteries {
|
||||
if bat.Design != 0 {
|
||||
totalCapacity += bat.Design
|
||||
} else {
|
||||
totalCapacity += bat.Full
|
||||
errs, partialErrs := err.(battery.Errors)
|
||||
|
||||
batteryState = math.MaxUint8
|
||||
|
||||
for i, bat := range batteries {
|
||||
if partialErrs && errs[i] != nil {
|
||||
// if there were some errors, like missing data, skip it
|
||||
continue
|
||||
}
|
||||
if bat == nil || bat.Full == 0 {
|
||||
// skip batteries with no capacity. Charge is unlikely to ever be zero, but
|
||||
// we can't guarantee that, so don't skip based on charge.
|
||||
continue
|
||||
}
|
||||
totalCapacity += bat.Full
|
||||
totalCharge += bat.Current
|
||||
if bat.State.Raw >= 0 {
|
||||
batteryState = uint8(bat.State.Raw)
|
||||
}
|
||||
}
|
||||
|
||||
if totalCapacity == 0 || batteryState == math.MaxUint8 {
|
||||
// for macs there's sometimes a ghost battery with 0 capacity
|
||||
// https://github.com/distatus/battery/issues/34
|
||||
// Instead of skipping over those batteries, we'll check for total 0 capacity
|
||||
// and return an error. This also prevents a divide by zero.
|
||||
return batteryPercent, batteryState, errors.New("no battery capacity")
|
||||
}
|
||||
|
||||
batteryPercent = uint8(totalCharge / totalCapacity * 100)
|
||||
batteryState = uint8(batteries[0].State.Raw)
|
||||
return batteryPercent, batteryState, nil
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/henrygd/beszel/internal/common"
|
||||
"github.com/henrygd/beszel/internal/entities/smart"
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
"github.com/henrygd/beszel/internal/entities/systemd"
|
||||
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
"github.com/lxzan/gws"
|
||||
@@ -276,6 +277,8 @@ func (client *WebSocketClient) sendResponse(data any, requestID *uint32) error {
|
||||
response.String = &v
|
||||
case map[string]smart.SmartData:
|
||||
response.SmartData = v
|
||||
case systemd.ServiceDetails:
|
||||
response.ServiceInfo = v
|
||||
// case []byte:
|
||||
// response.RawBytes = v
|
||||
// case string:
|
||||
|
||||
92
agent/cpu.go
92
agent/cpu.go
@@ -4,10 +4,12 @@ import (
|
||||
"math"
|
||||
"runtime"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
"github.com/shirou/gopsutil/v4/cpu"
|
||||
)
|
||||
|
||||
var lastCpuTimes = make(map[uint16]cpu.TimesStat)
|
||||
var lastPerCoreCpuTimes = make(map[uint16][]cpu.TimesStat)
|
||||
|
||||
// init initializes the CPU monitoring by storing the initial CPU times
|
||||
// for the default 60-second cache interval.
|
||||
@@ -15,23 +17,92 @@ func init() {
|
||||
if times, err := cpu.Times(false); err == nil {
|
||||
lastCpuTimes[60000] = times[0]
|
||||
}
|
||||
if perCoreTimes, err := cpu.Times(true); err == nil {
|
||||
lastPerCoreCpuTimes[60000] = perCoreTimes
|
||||
}
|
||||
}
|
||||
|
||||
// getCpuPercent calculates the CPU usage percentage using cached previous measurements.
|
||||
// It uses the specified cache time interval to determine the time window for calculation.
|
||||
// Returns the CPU usage percentage (0-100) and any error encountered.
|
||||
func getCpuPercent(cacheTimeMs uint16) (float64, error) {
|
||||
// CpuMetrics contains detailed CPU usage breakdown
|
||||
type CpuMetrics struct {
|
||||
Total float64
|
||||
User float64
|
||||
System float64
|
||||
Iowait float64
|
||||
Steal float64
|
||||
Idle float64
|
||||
}
|
||||
|
||||
// getCpuMetrics calculates detailed CPU usage metrics using cached previous measurements.
|
||||
// It returns percentages for total, user, system, iowait, and steal time.
|
||||
func getCpuMetrics(cacheTimeMs uint16) (CpuMetrics, error) {
|
||||
times, err := cpu.Times(false)
|
||||
if err != nil || len(times) == 0 {
|
||||
return 0, err
|
||||
return CpuMetrics{}, err
|
||||
}
|
||||
// if cacheTimeMs is not in lastCpuTimes, use 60000 as fallback lastCpuTime
|
||||
if _, ok := lastCpuTimes[cacheTimeMs]; !ok {
|
||||
lastCpuTimes[cacheTimeMs] = lastCpuTimes[60000]
|
||||
}
|
||||
delta := calculateBusy(lastCpuTimes[cacheTimeMs], times[0])
|
||||
|
||||
t1 := lastCpuTimes[cacheTimeMs]
|
||||
t2 := times[0]
|
||||
|
||||
t1All, _ := getAllBusy(t1)
|
||||
t2All, _ := getAllBusy(t2)
|
||||
|
||||
totalDelta := t2All - t1All
|
||||
if totalDelta <= 0 {
|
||||
return CpuMetrics{}, nil
|
||||
}
|
||||
|
||||
metrics := CpuMetrics{
|
||||
Total: calculateBusy(t1, t2),
|
||||
User: clampPercent((t2.User - t1.User) / totalDelta * 100),
|
||||
System: clampPercent((t2.System - t1.System) / totalDelta * 100),
|
||||
Iowait: clampPercent((t2.Iowait - t1.Iowait) / totalDelta * 100),
|
||||
Steal: clampPercent((t2.Steal - t1.Steal) / totalDelta * 100),
|
||||
Idle: clampPercent((t2.Idle - t1.Idle) / totalDelta * 100),
|
||||
}
|
||||
|
||||
lastCpuTimes[cacheTimeMs] = times[0]
|
||||
return delta, nil
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
// clampPercent ensures the percentage is between 0 and 100
|
||||
func clampPercent(value float64) float64 {
|
||||
return math.Min(100, math.Max(0, value))
|
||||
}
|
||||
|
||||
// getPerCoreCpuUsage calculates per-core CPU busy usage as integer percentages (0-100).
|
||||
// It uses cached previous measurements for the provided cache interval.
|
||||
func getPerCoreCpuUsage(cacheTimeMs uint16) (system.Uint8Slice, error) {
|
||||
perCoreTimes, err := cpu.Times(true)
|
||||
if err != nil || len(perCoreTimes) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize cache if needed
|
||||
if _, ok := lastPerCoreCpuTimes[cacheTimeMs]; !ok {
|
||||
lastPerCoreCpuTimes[cacheTimeMs] = lastPerCoreCpuTimes[60000]
|
||||
}
|
||||
|
||||
lastTimes := lastPerCoreCpuTimes[cacheTimeMs]
|
||||
|
||||
// Limit to the number of cores available in both samples
|
||||
length := len(perCoreTimes)
|
||||
if len(lastTimes) < length {
|
||||
length = len(lastTimes)
|
||||
}
|
||||
|
||||
usage := make([]uint8, length)
|
||||
for i := 0; i < length; i++ {
|
||||
t1 := lastTimes[i]
|
||||
t2 := perCoreTimes[i]
|
||||
usage[i] = uint8(math.Round(calculateBusy(t1, t2)))
|
||||
}
|
||||
|
||||
lastPerCoreCpuTimes[cacheTimeMs] = perCoreTimes
|
||||
return usage, nil
|
||||
}
|
||||
|
||||
// calculateBusy calculates the CPU busy percentage between two time points.
|
||||
@@ -41,13 +112,10 @@ func calculateBusy(t1, t2 cpu.TimesStat) float64 {
|
||||
t1All, t1Busy := getAllBusy(t1)
|
||||
t2All, t2Busy := getAllBusy(t2)
|
||||
|
||||
if t2Busy <= t1Busy {
|
||||
if t2All <= t1All || t2Busy <= t1Busy {
|
||||
return 0
|
||||
}
|
||||
if t2All <= t1All {
|
||||
return 100
|
||||
}
|
||||
return math.Min(100, math.Max(0, (t2Busy-t1Busy)/(t2All-t1All)*100))
|
||||
return clampPercent((t2Busy - t1Busy) / (t2All - t1All) * 100)
|
||||
}
|
||||
|
||||
// getAllBusy calculates the total CPU time and busy CPU time from CPU times statistics.
|
||||
|
||||
@@ -31,6 +31,7 @@ func (a *Agent) initializeDiskInfo() {
|
||||
filesystem, _ := GetEnv("FILESYSTEM")
|
||||
efPath := "/extra-filesystems"
|
||||
hasRoot := false
|
||||
isWindows := runtime.GOOS == "windows"
|
||||
|
||||
partitions, err := disk.Partitions(false)
|
||||
if err != nil {
|
||||
@@ -38,6 +39,13 @@ func (a *Agent) initializeDiskInfo() {
|
||||
}
|
||||
slog.Debug("Disk", "partitions", partitions)
|
||||
|
||||
// trim trailing backslash for Windows devices (#1361)
|
||||
if isWindows {
|
||||
for i, p := range partitions {
|
||||
partitions[i].Device = strings.TrimSuffix(p.Device, "\\")
|
||||
}
|
||||
}
|
||||
|
||||
// ioContext := context.WithValue(a.sensorsContext,
|
||||
// common.EnvKey, common.EnvMap{common.HostProcEnvKey: "/tmp/testproc"},
|
||||
// )
|
||||
@@ -52,7 +60,7 @@ func (a *Agent) initializeDiskInfo() {
|
||||
// Helper function to add a filesystem to fsStats if it doesn't exist
|
||||
addFsStat := func(device, mountpoint string, root bool, customName ...string) {
|
||||
var key string
|
||||
if runtime.GOOS == "windows" {
|
||||
if isWindows {
|
||||
key = device
|
||||
} else {
|
||||
key = filepath.Base(device)
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -32,6 +33,12 @@ const (
|
||||
maxMemoryUsage uint64 = 100 * 1024 * 1024 * 1024 * 1024
|
||||
// Number of log lines to request when fetching container logs
|
||||
dockerLogsTail = 200
|
||||
// Maximum size of a single log frame (1MB) to prevent memory exhaustion
|
||||
// A single log line larger than 1MB is likely an error or misconfiguration
|
||||
maxLogFrameSize = 1024 * 1024
|
||||
// Maximum total log content size (5MB) to prevent memory exhaustion
|
||||
// This provides a reasonable limit for network transfer and browser rendering
|
||||
maxTotalLogSize = 5 * 1024 * 1024
|
||||
)
|
||||
|
||||
type dockerManager struct {
|
||||
@@ -47,6 +54,7 @@ type dockerManager struct {
|
||||
buf *bytes.Buffer // Buffer to store and read response bodies
|
||||
decoder *json.Decoder // Reusable JSON decoder that reads from buf
|
||||
apiStats *container.ApiStats // Reusable API stats object
|
||||
excludeContainers []string // Patterns to exclude containers by name
|
||||
|
||||
// Cache-time-aware tracking for CPU stats (similar to cpu.go)
|
||||
// Maps cache time intervals to container-specific CPU usage tracking
|
||||
@@ -88,6 +96,19 @@ func (d *dockerManager) dequeue() {
|
||||
}
|
||||
}
|
||||
|
||||
// shouldExcludeContainer checks if a container name matches any exclusion pattern
|
||||
func (dm *dockerManager) shouldExcludeContainer(name string) bool {
|
||||
if len(dm.excludeContainers) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, pattern := range dm.excludeContainers {
|
||||
if match, _ := path.Match(pattern, name); match {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns stats for all running containers with cache-time-aware delta tracking
|
||||
func (dm *dockerManager) getDockerStats(cacheTimeMs uint16) ([]*container.Stats, error) {
|
||||
resp, err := dm.client.Get("http://localhost/containers/json")
|
||||
@@ -115,6 +136,13 @@ func (dm *dockerManager) getDockerStats(cacheTimeMs uint16) ([]*container.Stats,
|
||||
|
||||
for _, ctr := range dm.apiContainerList {
|
||||
ctr.IdShort = ctr.Id[:12]
|
||||
|
||||
// Skip this container if it matches the exclusion pattern
|
||||
if dm.shouldExcludeContainer(ctr.Names[0][1:]) {
|
||||
slog.Debug("Excluding container", "name", ctr.Names[0][1:])
|
||||
continue
|
||||
}
|
||||
|
||||
dm.validIds[ctr.IdShort] = struct{}{}
|
||||
// check if container is less than 1 minute old (possible restart)
|
||||
// note: can't use Created field because it's not updated on restart
|
||||
@@ -497,6 +525,19 @@ func newDockerManager(a *Agent) *dockerManager {
|
||||
userAgent: "Docker-Client/",
|
||||
}
|
||||
|
||||
// Read container exclusion patterns from environment variable
|
||||
var excludeContainers []string
|
||||
if excludeStr, set := GetEnv("EXCLUDE_CONTAINERS"); set && excludeStr != "" {
|
||||
parts := strings.SplitSeq(excludeStr, ",")
|
||||
for part := range parts {
|
||||
trimmed := strings.TrimSpace(part)
|
||||
if trimmed != "" {
|
||||
excludeContainers = append(excludeContainers, trimmed)
|
||||
}
|
||||
}
|
||||
slog.Info("EXCLUDE_CONTAINERS", "patterns", excludeContainers)
|
||||
}
|
||||
|
||||
manager := &dockerManager{
|
||||
client: &http.Client{
|
||||
Timeout: timeout,
|
||||
@@ -506,6 +547,7 @@ func newDockerManager(a *Agent) *dockerManager {
|
||||
sem: make(chan struct{}, 5),
|
||||
apiContainerList: []*container.ApiInfo{},
|
||||
apiStats: &container.ApiStats{},
|
||||
excludeContainers: excludeContainers,
|
||||
|
||||
// Initialize cache-time-aware tracking structures
|
||||
lastCpuContainer: make(map[uint16]map[string]uint64),
|
||||
@@ -596,30 +638,34 @@ func getDockerHost() string {
|
||||
}
|
||||
|
||||
// getContainerInfo fetches the inspection data for a container
|
||||
func (dm *dockerManager) getContainerInfo(ctx context.Context, containerID string) (string, error) {
|
||||
func (dm *dockerManager) getContainerInfo(ctx context.Context, containerID string) ([]byte, error) {
|
||||
endpoint := fmt.Sprintf("http://localhost/containers/%s/json", containerID)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := dm.client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
|
||||
return "", fmt.Errorf("container info request failed: %s: %s", resp.Status, strings.TrimSpace(string(body)))
|
||||
return nil, fmt.Errorf("container info request failed: %s: %s", resp.Status, strings.TrimSpace(string(body)))
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
// Remove sensitive environment variables from Config.Env
|
||||
var containerInfo map[string]any
|
||||
if err := json.NewDecoder(resp.Body).Decode(&containerInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config, ok := containerInfo["Config"].(map[string]any); ok {
|
||||
delete(config, "Env")
|
||||
}
|
||||
|
||||
return string(data), nil
|
||||
return json.Marshal(containerInfo)
|
||||
}
|
||||
|
||||
// getLogs fetches the logs for a container
|
||||
@@ -653,6 +699,7 @@ func decodeDockerLogStream(reader io.Reader, builder *strings.Builder) error {
|
||||
const headerSize = 8
|
||||
var header [headerSize]byte
|
||||
buf := make([]byte, 0, dockerLogsTail*200)
|
||||
totalBytesRead := 0
|
||||
|
||||
for {
|
||||
if _, err := io.ReadFull(reader, header[:]); err != nil {
|
||||
@@ -667,6 +714,19 @@ func decodeDockerLogStream(reader io.Reader, builder *strings.Builder) error {
|
||||
continue
|
||||
}
|
||||
|
||||
// Prevent memory exhaustion from excessively large frames
|
||||
if frameLen > maxLogFrameSize {
|
||||
return fmt.Errorf("log frame size (%d) exceeds maximum (%d)", frameLen, maxLogFrameSize)
|
||||
}
|
||||
|
||||
// Check if reading this frame would exceed total log size limit
|
||||
if totalBytesRead+int(frameLen) > maxTotalLogSize {
|
||||
// Read and discard remaining data to avoid blocking
|
||||
_, _ = io.Copy(io.Discard, io.LimitReader(reader, int64(frameLen)))
|
||||
slog.Debug("Truncating logs: limit reached", "read", totalBytesRead, "limit", maxTotalLogSize)
|
||||
return nil
|
||||
}
|
||||
|
||||
buf = allocateBuffer(buf, int(frameLen))
|
||||
if _, err := io.ReadFull(reader, buf[:frameLen]); err != nil {
|
||||
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
@@ -678,6 +738,7 @@ func decodeDockerLogStream(reader io.Reader, builder *strings.Builder) error {
|
||||
return err
|
||||
}
|
||||
builder.Write(buf[:frameLen])
|
||||
totalBytesRead += int(frameLen)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -911,6 +913,8 @@ func TestConstantsAndUtilityFunctions(t *testing.T) {
|
||||
assert.Equal(t, uint16(60000), defaultCacheTimeMs)
|
||||
assert.Equal(t, uint64(5e9), maxNetworkSpeedBps)
|
||||
assert.Equal(t, 2100, dockerTimeoutMs)
|
||||
assert.Equal(t, uint32(1024*1024), uint32(maxLogFrameSize)) // 1MB
|
||||
assert.Equal(t, 5*1024*1024, maxTotalLogSize) // 5MB
|
||||
|
||||
// Test utility functions
|
||||
assert.Equal(t, 1.5, twoDecimals(1.499))
|
||||
@@ -921,3 +925,281 @@ func TestConstantsAndUtilityFunctions(t *testing.T) {
|
||||
assert.Equal(t, 0.5, bytesToMegabytes(524288)) // 512 KB
|
||||
assert.Equal(t, 0.0, bytesToMegabytes(0))
|
||||
}
|
||||
|
||||
func TestDecodeDockerLogStream(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []byte
|
||||
expected string
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "simple log entry",
|
||||
input: []byte{
|
||||
// Frame 1: stdout, 11 bytes
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B,
|
||||
'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd',
|
||||
},
|
||||
expected: "Hello World",
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "multiple frames",
|
||||
input: []byte{
|
||||
// Frame 1: stdout, 5 bytes
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
|
||||
'H', 'e', 'l', 'l', 'o',
|
||||
// Frame 2: stdout, 5 bytes
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
|
||||
'W', 'o', 'r', 'l', 'd',
|
||||
},
|
||||
expected: "HelloWorld",
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "zero length frame",
|
||||
input: []byte{
|
||||
// Frame 1: stdout, 0 bytes
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Frame 2: stdout, 5 bytes
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
|
||||
'H', 'e', 'l', 'l', 'o',
|
||||
},
|
||||
expected: "Hello",
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "empty input",
|
||||
input: []byte{},
|
||||
expected: "",
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
reader := bytes.NewReader(tt.input)
|
||||
var builder strings.Builder
|
||||
err := decodeDockerLogStream(reader, &builder)
|
||||
|
||||
if tt.expectError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, builder.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeDockerLogStreamMemoryProtection(t *testing.T) {
|
||||
t.Run("excessively large frame should error", func(t *testing.T) {
|
||||
// Create a frame with size exceeding maxLogFrameSize
|
||||
excessiveSize := uint32(maxLogFrameSize + 1)
|
||||
input := []byte{
|
||||
// Frame header with excessive size
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
byte(excessiveSize >> 24), byte(excessiveSize >> 16), byte(excessiveSize >> 8), byte(excessiveSize),
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(input)
|
||||
var builder strings.Builder
|
||||
err := decodeDockerLogStream(reader, &builder)
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "log frame size")
|
||||
assert.Contains(t, err.Error(), "exceeds maximum")
|
||||
})
|
||||
|
||||
t.Run("total size limit should truncate", func(t *testing.T) {
|
||||
// Create frames that exceed maxTotalLogSize (5MB)
|
||||
// Use frames within maxLogFrameSize (1MB) to avoid single-frame rejection
|
||||
frameSize := uint32(800 * 1024) // 800KB per frame
|
||||
var input []byte
|
||||
|
||||
// Frames 1-6: 800KB each (total 4.8MB - within 5MB limit)
|
||||
for i := 0; i < 6; i++ {
|
||||
char := byte('A' + i)
|
||||
frameHeader := []byte{
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
byte(frameSize >> 24), byte(frameSize >> 16), byte(frameSize >> 8), byte(frameSize),
|
||||
}
|
||||
input = append(input, frameHeader...)
|
||||
input = append(input, bytes.Repeat([]byte{char}, int(frameSize))...)
|
||||
}
|
||||
|
||||
// Frame 7: 800KB (would bring total to 5.6MB, exceeding 5MB limit - should be truncated)
|
||||
frame7Header := []byte{
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
byte(frameSize >> 24), byte(frameSize >> 16), byte(frameSize >> 8), byte(frameSize),
|
||||
}
|
||||
input = append(input, frame7Header...)
|
||||
input = append(input, bytes.Repeat([]byte{'Z'}, int(frameSize))...)
|
||||
|
||||
reader := bytes.NewReader(input)
|
||||
var builder strings.Builder
|
||||
err := decodeDockerLogStream(reader, &builder)
|
||||
|
||||
// Should complete without error (graceful truncation)
|
||||
assert.NoError(t, err)
|
||||
// Should have read 6 frames (4.8MB total, stopping before 7th would exceed 5MB limit)
|
||||
expectedSize := int(frameSize) * 6
|
||||
assert.Equal(t, expectedSize, builder.Len())
|
||||
// Should contain A-F but not Z
|
||||
result := builder.String()
|
||||
assert.Contains(t, result, "A")
|
||||
assert.Contains(t, result, "F")
|
||||
assert.NotContains(t, result, "Z")
|
||||
})
|
||||
}
|
||||
|
||||
func TestAllocateBuffer(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
currentCap int
|
||||
needed int
|
||||
expectedCap int
|
||||
shouldRealloc bool
|
||||
}{
|
||||
{
|
||||
name: "buffer has enough capacity",
|
||||
currentCap: 1024,
|
||||
needed: 512,
|
||||
expectedCap: 1024,
|
||||
shouldRealloc: false,
|
||||
},
|
||||
{
|
||||
name: "buffer needs reallocation",
|
||||
currentCap: 512,
|
||||
needed: 1024,
|
||||
expectedCap: 1024,
|
||||
shouldRealloc: true,
|
||||
},
|
||||
{
|
||||
name: "buffer needs exact size",
|
||||
currentCap: 1024,
|
||||
needed: 1024,
|
||||
expectedCap: 1024,
|
||||
shouldRealloc: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
current := make([]byte, 0, tt.currentCap)
|
||||
result := allocateBuffer(current, tt.needed)
|
||||
|
||||
assert.Equal(t, tt.needed, len(result))
|
||||
assert.GreaterOrEqual(t, cap(result), tt.expectedCap)
|
||||
|
||||
if tt.shouldRealloc {
|
||||
// If reallocation was needed, capacity should be at least the needed size
|
||||
assert.GreaterOrEqual(t, cap(result), tt.needed)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldExcludeContainer(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
containerName string
|
||||
patterns []string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "empty patterns excludes nothing",
|
||||
containerName: "any-container",
|
||||
patterns: []string{},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "exact match - excluded",
|
||||
containerName: "test-web",
|
||||
patterns: []string{"test-web", "test-api"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "exact match - not excluded",
|
||||
containerName: "prod-web",
|
||||
patterns: []string{"test-web", "test-api"},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "wildcard prefix match - excluded",
|
||||
containerName: "test-web",
|
||||
patterns: []string{"test-*"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "wildcard prefix match - not excluded",
|
||||
containerName: "prod-web",
|
||||
patterns: []string{"test-*"},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "wildcard suffix match - excluded",
|
||||
containerName: "myapp-staging",
|
||||
patterns: []string{"*-staging"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "wildcard suffix match - not excluded",
|
||||
containerName: "myapp-prod",
|
||||
patterns: []string{"*-staging"},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "wildcard both sides match - excluded",
|
||||
containerName: "test-myapp-staging",
|
||||
patterns: []string{"*-myapp-*"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "wildcard both sides match - not excluded",
|
||||
containerName: "prod-yourapp-live",
|
||||
patterns: []string{"*-myapp-*"},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "multiple patterns - matches first",
|
||||
containerName: "test-container",
|
||||
patterns: []string{"test-*", "*-staging"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "multiple patterns - matches second",
|
||||
containerName: "myapp-staging",
|
||||
patterns: []string{"test-*", "*-staging"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "multiple patterns - no match",
|
||||
containerName: "prod-web",
|
||||
patterns: []string{"test-*", "*-staging"},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "mixed exact and wildcard - exact match",
|
||||
containerName: "temp-container",
|
||||
patterns: []string{"temp-container", "test-*"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "mixed exact and wildcard - wildcard match",
|
||||
containerName: "test-web",
|
||||
patterns: []string{"temp-container", "test-*"},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
dm := &dockerManager{
|
||||
excludeContainers: tt.patterns,
|
||||
}
|
||||
result := dm.shouldExcludeContainer(tt.containerName)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,12 @@ func (gm *GPUManager) updateIntelFromStats(sample *intelGpuStats) bool {
|
||||
|
||||
// collectIntelStats executes intel_gpu_top in text mode (-l) and parses the output
|
||||
func (gm *GPUManager) collectIntelStats() (err error) {
|
||||
cmd := exec.Command(intelGpuStatsCmd, "-s", intelGpuStatsInterval, "-l")
|
||||
// Build command arguments, optionally selecting a device via -d
|
||||
args := []string{"-s", intelGpuStatsInterval, "-l"}
|
||||
if dev, ok := GetEnv("INTEL_GPU_DEVICE"); ok && dev != "" {
|
||||
args = append(args, "-d", dev)
|
||||
}
|
||||
cmd := exec.Command(intelGpuStatsCmd, args...)
|
||||
// Avoid blocking if intel_gpu_top writes to stderr
|
||||
cmd.Stderr = io.Discard
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
@@ -129,7 +134,9 @@ func (gm *GPUManager) parseIntelHeaders(header1 string, header2 string) (engineN
|
||||
powerIndex = -1 // Initialize to -1, will be set to actual index if found
|
||||
// Collect engine names from header1
|
||||
for _, col := range h1 {
|
||||
key := strings.TrimRightFunc(col, func(r rune) bool { return r >= '0' && r <= '9' })
|
||||
key := strings.TrimRightFunc(col, func(r rune) bool {
|
||||
return (r >= '0' && r <= '9') || r == '/'
|
||||
})
|
||||
var friendly string
|
||||
switch key {
|
||||
case "RCS":
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -1437,6 +1439,15 @@ func TestParseIntelHeaders(t *testing.T) {
|
||||
wantPowerIndex: 4, // "gpu" is at index 4
|
||||
wantPreEngineCols: 8, // 17 total cols - 3*3 = 8
|
||||
},
|
||||
{
|
||||
name: "basic headers with RCS BCS VCS using index in name",
|
||||
header1: "Freq MHz IRQ RC6 Power W IMC MiB/s RCS/0 BCS/1 VCS/2",
|
||||
header2: " req act /s % gpu pkg rd wr % se wa % se wa % se wa",
|
||||
wantEngineNames: []string{"RCS", "BCS", "VCS"},
|
||||
wantFriendlyNames: []string{"Render/3D", "Blitter", "Video"},
|
||||
wantPowerIndex: 4, // "gpu" is at index 4
|
||||
wantPreEngineCols: 8, // 17 total cols - 3*3 = 8
|
||||
},
|
||||
{
|
||||
name: "headers with only RCS",
|
||||
header1: "Freq MHz IRQ RC6 Power W IMC MiB/s RCS",
|
||||
@@ -1624,3 +1635,42 @@ func TestParseIntelData(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntelCollectorDeviceEnv(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
t.Setenv("PATH", dir)
|
||||
|
||||
// Prepare a file to capture args
|
||||
argsFile := filepath.Join(dir, "args.txt")
|
||||
|
||||
// Create a fake intel_gpu_top that records its arguments and prints minimal valid output
|
||||
scriptPath := filepath.Join(dir, "intel_gpu_top")
|
||||
script := fmt.Sprintf(`#!/bin/sh
|
||||
echo "$@" > %s
|
||||
echo "Freq MHz IRQ RC6 Power W IMC MiB/s RCS VCS"
|
||||
echo " req act /s %% gpu pkg rd wr %% se wa %% se wa"
|
||||
echo "226 223 338 58 2.00 2.69 1820 965 0.00 0 0 0.00 0 0"
|
||||
echo "189 187 412 67 1.80 2.45 1950 823 8.50 2 1 15.00 1 0"
|
||||
`, argsFile)
|
||||
if err := os.WriteFile(scriptPath, []byte(script), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Set device selector via prefixed env var
|
||||
t.Setenv("BESZEL_AGENT_INTEL_GPU_DEVICE", "sriov")
|
||||
|
||||
gm := &GPUManager{GpuDataMap: make(map[string]*system.GPUData)}
|
||||
if err := gm.collectIntelStats(); err != nil {
|
||||
t.Fatalf("collectIntelStats error: %v", err)
|
||||
}
|
||||
|
||||
// Verify that -d sriov was passed
|
||||
data, err := os.ReadFile(argsFile)
|
||||
if err != nil {
|
||||
t.Fatalf("failed reading args file: %v", err)
|
||||
}
|
||||
argsStr := strings.TrimSpace(string(data))
|
||||
require.Contains(t, argsStr, "-d sriov")
|
||||
require.Contains(t, argsStr, "-s ")
|
||||
require.Contains(t, argsStr, "-l")
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ func NewHandlerRegistry() *HandlerRegistry {
|
||||
registry.Register(common.GetContainerLogs, &GetContainerLogsHandler{})
|
||||
registry.Register(common.GetContainerInfo, &GetContainerInfoHandler{})
|
||||
registry.Register(common.GetSmartData, &GetSmartDataHandler{})
|
||||
registry.Register(common.GetSystemdInfo, &GetSystemdInfoHandler{})
|
||||
|
||||
return registry
|
||||
}
|
||||
@@ -154,7 +155,7 @@ func (h *GetContainerInfoHandler) Handle(hctx *HandlerContext) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return hctx.SendResponse(info, hctx.RequestID)
|
||||
return hctx.SendResponse(string(info), hctx.RequestID)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@@ -168,9 +169,37 @@ func (h *GetSmartDataHandler) Handle(hctx *HandlerContext) error {
|
||||
// return empty map to indicate no data
|
||||
return hctx.SendResponse(map[string]smart.SmartData{}, hctx.RequestID)
|
||||
}
|
||||
if err := hctx.Agent.smartManager.Refresh(); err != nil {
|
||||
if err := hctx.Agent.smartManager.Refresh(false); err != nil {
|
||||
slog.Debug("smart refresh failed", "err", err)
|
||||
}
|
||||
data := hctx.Agent.smartManager.GetCurrentData()
|
||||
return hctx.SendResponse(data, hctx.RequestID)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// GetSystemdInfoHandler handles detailed systemd service info requests
|
||||
type GetSystemdInfoHandler struct{}
|
||||
|
||||
func (h *GetSystemdInfoHandler) Handle(hctx *HandlerContext) error {
|
||||
if hctx.Agent.systemdManager == nil {
|
||||
return errors.ErrUnsupported
|
||||
}
|
||||
|
||||
var req common.SystemdInfoRequest
|
||||
if err := cbor.Unmarshal(hctx.Request.Data, &req); err != nil {
|
||||
return err
|
||||
}
|
||||
if req.ServiceName == "" {
|
||||
return errors.New("service name is required")
|
||||
}
|
||||
|
||||
details, err := hctx.Agent.systemdManager.getServiceDetails(req.ServiceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return hctx.SendResponse(details, hctx.RequestID)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ import (
|
||||
|
||||
"github.com/henrygd/beszel"
|
||||
"github.com/henrygd/beszel/internal/common"
|
||||
"github.com/henrygd/beszel/internal/entities/smart"
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
"github.com/henrygd/beszel/internal/entities/systemd"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
@@ -170,6 +172,10 @@ func (a *Agent) handleSSHRequest(w io.Writer, req *common.HubRequest[cbor.RawMes
|
||||
response.SystemData = v
|
||||
case string:
|
||||
response.String = &v
|
||||
case map[string]smart.SmartData:
|
||||
response.SmartData = v
|
||||
case systemd.ServiceDetails:
|
||||
response.ServiceInfo = v
|
||||
default:
|
||||
response.Error = fmt.Sprintf("unsupported response type: %T", data)
|
||||
}
|
||||
|
||||
698
agent/smart.go
698
agent/smart.go
@@ -1,10 +1,18 @@
|
||||
//go:generate -command fetchsmartctl go run ./tools/fetchsmartctl
|
||||
//go:generate fetchsmartctl -out ./smartmontools/smartctl.exe -url https://static.beszel.dev/bin/smartctl/smartctl-nc.exe -sha 3912249c3b329249aa512ce796fd1b64d7cbd8378b68ad2756b39163d9c30b47
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -16,9 +24,12 @@ import (
|
||||
// SmartManager manages data collection for SMART devices
|
||||
type SmartManager struct {
|
||||
sync.Mutex
|
||||
SmartDataMap map[string]*smart.SmartData
|
||||
SmartDevices []*DeviceInfo
|
||||
refreshMutex sync.Mutex
|
||||
SmartDataMap map[string]*smart.SmartData
|
||||
SmartDevices []*DeviceInfo
|
||||
refreshMutex sync.Mutex
|
||||
lastScanTime time.Time
|
||||
binPath string
|
||||
excludedDevices map[string]struct{}
|
||||
}
|
||||
|
||||
type scanOutput struct {
|
||||
@@ -35,18 +46,23 @@ type DeviceInfo struct {
|
||||
Type string `json:"type"`
|
||||
InfoName string `json:"info_name"`
|
||||
Protocol string `json:"protocol"`
|
||||
// typeVerified reports whether we have already parsed SMART data for this device
|
||||
// with the stored parserType. When true we can skip re-running the detection logic.
|
||||
typeVerified bool
|
||||
// parserType holds the parser type (nvme, sat, scsi) that last succeeded.
|
||||
parserType string
|
||||
}
|
||||
|
||||
var errNoValidSmartData = fmt.Errorf("no valid SMART data found") // Error for missing data
|
||||
|
||||
// Refresh updates SMART data for all known devices on demand.
|
||||
func (sm *SmartManager) Refresh() error {
|
||||
// Refresh updates SMART data for all known devices
|
||||
func (sm *SmartManager) Refresh(forceScan bool) error {
|
||||
sm.refreshMutex.Lock()
|
||||
defer sm.refreshMutex.Unlock()
|
||||
|
||||
scanErr := sm.ScanDevices()
|
||||
scanErr := sm.ScanDevices(false)
|
||||
if scanErr != nil {
|
||||
slog.Warn("smartctl scan failed", "err", scanErr)
|
||||
slog.Debug("smartctl scan failed", "err", scanErr)
|
||||
}
|
||||
|
||||
devices := sm.devicesSnapshot()
|
||||
@@ -56,7 +72,7 @@ func (sm *SmartManager) Refresh() error {
|
||||
continue
|
||||
}
|
||||
if err := sm.CollectSmart(deviceInfo); err != nil {
|
||||
slog.Info("smartctl collect failed for device, skipping", "device", deviceInfo.Name, "err", err)
|
||||
slog.Debug("smartctl collect failed", "device", deviceInfo.Name, "err", err)
|
||||
collectErr = err
|
||||
}
|
||||
}
|
||||
@@ -126,77 +142,356 @@ func (sm *SmartManager) GetCurrentData() map[string]smart.SmartData {
|
||||
// Scan devices using `smartctl --scan -j`
|
||||
// If scan fails, return error
|
||||
// If scan succeeds, parse the output and update the SmartDevices slice
|
||||
func (sm *SmartManager) ScanDevices() error {
|
||||
func (sm *SmartManager) ScanDevices(force bool) error {
|
||||
if !force && time.Since(sm.lastScanTime) < 30*time.Minute {
|
||||
return nil
|
||||
}
|
||||
sm.lastScanTime = time.Now()
|
||||
currentDevices := sm.devicesSnapshot()
|
||||
|
||||
var configuredDevices []*DeviceInfo
|
||||
if configuredRaw, ok := GetEnv("SMART_DEVICES"); ok {
|
||||
slog.Info("SMART_DEVICES", "value", configuredRaw)
|
||||
config := strings.TrimSpace(configuredRaw)
|
||||
if config == "" {
|
||||
return errNoValidSmartData
|
||||
}
|
||||
|
||||
parsedDevices, err := sm.parseConfiguredDevices(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configuredDevices = parsedDevices
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(ctx, "smartctl", "--scan", "-j")
|
||||
cmd := exec.CommandContext(ctx, sm.binPath, "--scan", "-j")
|
||||
output, err := cmd.Output()
|
||||
|
||||
var (
|
||||
scanErr error
|
||||
scannedDevices []*DeviceInfo
|
||||
hasValidScan bool
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
scanErr = err
|
||||
} else {
|
||||
scannedDevices, hasValidScan = sm.parseScan(output)
|
||||
if !hasValidScan {
|
||||
scanErr = errNoValidSmartData
|
||||
}
|
||||
}
|
||||
|
||||
hasValidData := sm.parseScan(output)
|
||||
if !hasValidData {
|
||||
finalDevices := mergeDeviceLists(currentDevices, scannedDevices, configuredDevices)
|
||||
finalDevices = sm.filterExcludedDevices(finalDevices)
|
||||
sm.updateSmartDevices(finalDevices)
|
||||
|
||||
if len(finalDevices) == 0 {
|
||||
if scanErr != nil {
|
||||
slog.Debug("smartctl scan failed", "err", scanErr)
|
||||
return scanErr
|
||||
}
|
||||
return errNoValidSmartData
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sm *SmartManager) parseConfiguredDevices(config string) ([]*DeviceInfo, error) {
|
||||
entries := strings.Split(config, ",")
|
||||
devices := make([]*DeviceInfo, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
entry = strings.TrimSpace(entry)
|
||||
if entry == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.SplitN(entry, ":", 2)
|
||||
|
||||
name := strings.TrimSpace(parts[0])
|
||||
if name == "" {
|
||||
return nil, fmt.Errorf("invalid SMART_DEVICES entry %q", entry)
|
||||
}
|
||||
|
||||
devType := ""
|
||||
if len(parts) == 2 {
|
||||
devType = strings.ToLower(strings.TrimSpace(parts[1]))
|
||||
}
|
||||
|
||||
devices = append(devices, &DeviceInfo{
|
||||
Name: name,
|
||||
Type: devType,
|
||||
})
|
||||
}
|
||||
|
||||
if len(devices) == 0 {
|
||||
return nil, errNoValidSmartData
|
||||
}
|
||||
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
func (sm *SmartManager) refreshExcludedDevices() {
|
||||
rawValue, _ := GetEnv("EXCLUDE_SMART")
|
||||
sm.excludedDevices = make(map[string]struct{})
|
||||
|
||||
for entry := range strings.SplitSeq(rawValue, ",") {
|
||||
device := strings.TrimSpace(entry)
|
||||
if device == "" {
|
||||
continue
|
||||
}
|
||||
sm.excludedDevices[device] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SmartManager) isExcludedDevice(deviceName string) bool {
|
||||
_, exists := sm.excludedDevices[deviceName]
|
||||
return exists
|
||||
}
|
||||
|
||||
func (sm *SmartManager) filterExcludedDevices(devices []*DeviceInfo) []*DeviceInfo {
|
||||
if devices == nil {
|
||||
return []*DeviceInfo{}
|
||||
}
|
||||
|
||||
excluded := sm.excludedDevices
|
||||
if len(excluded) == 0 {
|
||||
return devices
|
||||
}
|
||||
|
||||
filtered := make([]*DeviceInfo, 0, len(devices))
|
||||
for _, device := range devices {
|
||||
if device == nil || device.Name == "" {
|
||||
continue
|
||||
}
|
||||
if _, skip := excluded[device.Name]; skip {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, device)
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
// detectSmartOutputType inspects sections that are unique to each smartctl
|
||||
// JSON schema (NVMe, ATA/SATA, SCSI) to determine which parser should be used
|
||||
// when the reported device type is ambiguous or missing.
|
||||
func detectSmartOutputType(output []byte) string {
|
||||
var hints struct {
|
||||
AtaSmartAttributes json.RawMessage `json:"ata_smart_attributes"`
|
||||
NVMeSmartHealthInformationLog json.RawMessage `json:"nvme_smart_health_information_log"`
|
||||
ScsiErrorCounterLog json.RawMessage `json:"scsi_error_counter_log"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(output, &hints); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
switch {
|
||||
case hasJSONValue(hints.NVMeSmartHealthInformationLog):
|
||||
return "nvme"
|
||||
case hasJSONValue(hints.AtaSmartAttributes):
|
||||
return "sat"
|
||||
case hasJSONValue(hints.ScsiErrorCounterLog):
|
||||
return "scsi"
|
||||
default:
|
||||
return "sat"
|
||||
}
|
||||
}
|
||||
|
||||
// hasJSONValue reports whether a JSON payload contains a concrete value. The
|
||||
// smartctl output often emits "null" for sections that do not apply, so we
|
||||
// only treat non-null content as a hint.
|
||||
func hasJSONValue(raw json.RawMessage) bool {
|
||||
if len(raw) == 0 {
|
||||
return false
|
||||
}
|
||||
trimmed := strings.TrimSpace(string(raw))
|
||||
return trimmed != "" && trimmed != "null"
|
||||
}
|
||||
|
||||
func normalizeParserType(value string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(value)) {
|
||||
case "nvme", "sntasmedia", "sntrealtek":
|
||||
return "nvme"
|
||||
case "sat", "ata":
|
||||
return "sat"
|
||||
case "scsi":
|
||||
return "scsi"
|
||||
default:
|
||||
return strings.ToLower(strings.TrimSpace(value))
|
||||
}
|
||||
}
|
||||
|
||||
// parseSmartOutput attempts each SMART parser, optionally detecting the type when
|
||||
// it is not provided, and updates the device info when a parser succeeds.
|
||||
func (sm *SmartManager) parseSmartOutput(deviceInfo *DeviceInfo, output []byte) bool {
|
||||
parsers := []struct {
|
||||
Type string
|
||||
Parse func([]byte) (bool, int)
|
||||
}{
|
||||
{Type: "nvme", Parse: sm.parseSmartForNvme},
|
||||
{Type: "sat", Parse: sm.parseSmartForSata},
|
||||
{Type: "scsi", Parse: sm.parseSmartForScsi},
|
||||
}
|
||||
|
||||
deviceType := normalizeParserType(deviceInfo.parserType)
|
||||
if deviceType == "" {
|
||||
deviceType = normalizeParserType(deviceInfo.Type)
|
||||
}
|
||||
if deviceInfo.parserType == "" {
|
||||
switch deviceType {
|
||||
case "nvme", "sat", "scsi":
|
||||
deviceInfo.parserType = deviceType
|
||||
}
|
||||
}
|
||||
|
||||
// Only run the type detection when we do not yet know which parser works
|
||||
// or the previous attempt failed.
|
||||
needsDetection := deviceType == "" || !deviceInfo.typeVerified
|
||||
if needsDetection {
|
||||
structureType := detectSmartOutputType(output)
|
||||
if deviceType != structureType {
|
||||
deviceType = structureType
|
||||
deviceInfo.parserType = structureType
|
||||
deviceInfo.typeVerified = false
|
||||
}
|
||||
if deviceInfo.Type == "" || strings.EqualFold(deviceInfo.Type, structureType) {
|
||||
deviceInfo.Type = structureType
|
||||
}
|
||||
}
|
||||
|
||||
// Try the most likely parser first, but keep the remaining parsers in reserve
|
||||
// so an incorrect hint never leaves the device unparsed.
|
||||
selectedParsers := make([]struct {
|
||||
Type string
|
||||
Parse func([]byte) (bool, int)
|
||||
}, 0, len(parsers))
|
||||
if deviceType != "" {
|
||||
for _, parser := range parsers {
|
||||
if parser.Type == deviceType {
|
||||
selectedParsers = append(selectedParsers, parser)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, parser := range parsers {
|
||||
alreadySelected := false
|
||||
for _, selected := range selectedParsers {
|
||||
if selected.Type == parser.Type {
|
||||
alreadySelected = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if alreadySelected {
|
||||
continue
|
||||
}
|
||||
selectedParsers = append(selectedParsers, parser)
|
||||
}
|
||||
|
||||
// Try the selected parsers in order until we find one that succeeds.
|
||||
for _, parser := range selectedParsers {
|
||||
hasData, _ := parser.Parse(output)
|
||||
if hasData {
|
||||
deviceInfo.parserType = parser.Type
|
||||
if deviceInfo.Type == "" || strings.EqualFold(deviceInfo.Type, parser.Type) {
|
||||
deviceInfo.Type = parser.Type
|
||||
}
|
||||
// Remember that this parser is valid so future refreshes can bypass
|
||||
// detection entirely.
|
||||
deviceInfo.typeVerified = true
|
||||
return true
|
||||
}
|
||||
slog.Debug("parser failed", "device", deviceInfo.Name, "parser", parser.Type)
|
||||
}
|
||||
|
||||
// Leave verification false so the next pass will attempt detection again.
|
||||
deviceInfo.typeVerified = false
|
||||
slog.Debug("parsing failed", "device", deviceInfo.Name)
|
||||
return false
|
||||
}
|
||||
|
||||
// CollectSmart collects SMART data for a device
|
||||
// Collect data using `smartctl --all -j /dev/sdX` or `smartctl --all -j /dev/nvmeX`
|
||||
// Collect data using `smartctl -d <type> -aj /dev/<device>` when device type is known
|
||||
// Always attempts to parse output even if command fails, as some data may still be available
|
||||
// If collect fails, return error
|
||||
// If collect succeeds, parse the output and update the SmartDataMap
|
||||
// Uses -n standby to avoid waking up sleeping disks, but bypasses standby mode
|
||||
// for initial data collection when no cached data exists
|
||||
func (sm *SmartManager) CollectSmart(deviceInfo *DeviceInfo) error {
|
||||
if deviceInfo != nil && sm.isExcludedDevice(deviceInfo.Name) {
|
||||
return errNoValidSmartData
|
||||
}
|
||||
|
||||
// slog.Info("collecting SMART data", "device", deviceInfo.Name, "type", deviceInfo.Type, "has_existing_data", sm.hasDataForDevice(deviceInfo.Name))
|
||||
|
||||
// Check if we have any existing data for this device
|
||||
hasExistingData := sm.hasDataForDevice(deviceInfo.Name)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Try with -n standby first if we have existing data
|
||||
cmd := exec.CommandContext(ctx, "smartctl", "-aj", "-n", "standby", deviceInfo.Name)
|
||||
args := sm.smartctlArgs(deviceInfo, true)
|
||||
cmd := exec.CommandContext(ctx, sm.binPath, args...)
|
||||
output, err := cmd.CombinedOutput()
|
||||
|
||||
// Check if device is in standby (exit status 2)
|
||||
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 2 {
|
||||
if hasExistingData {
|
||||
// Device is in standby and we have cached data, keep using cache
|
||||
slog.Debug("device in standby mode, using cached data", "device", deviceInfo.Name)
|
||||
return nil
|
||||
}
|
||||
// No cached data, need to collect initial data by bypassing standby
|
||||
slog.Debug("device in standby but no cached data, collecting initial data", "device", deviceInfo.Name)
|
||||
ctx2, cancel2 := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
ctx2, cancel2 := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel2()
|
||||
cmd = exec.CommandContext(ctx2, "smartctl", "-aj", deviceInfo.Name)
|
||||
args = sm.smartctlArgs(deviceInfo, false)
|
||||
cmd = exec.CommandContext(ctx2, sm.binPath, args...)
|
||||
output, err = cmd.CombinedOutput()
|
||||
}
|
||||
|
||||
hasValidData := false
|
||||
|
||||
switch deviceInfo.Type {
|
||||
case "scsi", "sat", "ata":
|
||||
// parse SATA/SCSI/ATA devices
|
||||
hasValidData, _ = sm.parseSmartForSata(output)
|
||||
case "nvme":
|
||||
// parse nvme devices
|
||||
hasValidData, _ = sm.parseSmartForNvme(output)
|
||||
}
|
||||
hasValidData := sm.parseSmartOutput(deviceInfo, output)
|
||||
|
||||
if !hasValidData {
|
||||
if err != nil {
|
||||
slog.Info("smartctl failed", "device", deviceInfo.Name, "err", err)
|
||||
return err
|
||||
}
|
||||
slog.Info("no valid SMART data found", "device", deviceInfo.Name)
|
||||
return errNoValidSmartData
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// smartctlArgs returns the arguments for the smartctl command
|
||||
// based on the device type and whether to include standby mode
|
||||
func (sm *SmartManager) smartctlArgs(deviceInfo *DeviceInfo, includeStandby bool) []string {
|
||||
args := make([]string, 0, 7)
|
||||
|
||||
if deviceInfo != nil {
|
||||
deviceType := strings.ToLower(deviceInfo.Type)
|
||||
// types sometimes misidentified in scan; see github.com/henrygd/beszel/issues/1345
|
||||
if deviceType != "" && deviceType != "scsi" && deviceType != "ata" {
|
||||
args = append(args, "-d", deviceInfo.Type)
|
||||
}
|
||||
}
|
||||
|
||||
args = append(args, "-a", "--json=c")
|
||||
|
||||
if includeStandby {
|
||||
args = append(args, "-n", "standby")
|
||||
}
|
||||
|
||||
if deviceInfo != nil {
|
||||
args = append(args, deviceInfo.Name)
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
// hasDataForDevice checks if we have cached SMART data for a specific device
|
||||
func (sm *SmartManager) hasDataForDevice(deviceName string) bool {
|
||||
sm.Lock()
|
||||
@@ -211,43 +506,194 @@ func (sm *SmartManager) hasDataForDevice(deviceName string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// parseScan parses the output of smartctl --scan -j and updates the SmartDevices slice
|
||||
func (sm *SmartManager) parseScan(output []byte) bool {
|
||||
sm.Lock()
|
||||
defer sm.Unlock()
|
||||
|
||||
sm.SmartDevices = make([]*DeviceInfo, 0)
|
||||
// parseScan parses the output of smartctl --scan -j and returns the discovered devices.
|
||||
func (sm *SmartManager) parseScan(output []byte) ([]*DeviceInfo, bool) {
|
||||
scan := &scanOutput{}
|
||||
|
||||
if err := json.Unmarshal(output, scan); err != nil {
|
||||
slog.Warn("Failed to parse smartctl scan JSON", "err", err)
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if len(scan.Devices) == 0 {
|
||||
return false
|
||||
slog.Debug("no devices found in smartctl scan")
|
||||
return nil, false
|
||||
}
|
||||
|
||||
scannedDeviceNameMap := make(map[string]bool, len(scan.Devices))
|
||||
|
||||
devices := make([]*DeviceInfo, 0, len(scan.Devices))
|
||||
for _, device := range scan.Devices {
|
||||
deviceInfo := &DeviceInfo{
|
||||
slog.Debug("smartctl scan", "name", device.Name, "type", device.Type, "protocol", device.Protocol)
|
||||
devices = append(devices, &DeviceInfo{
|
||||
Name: device.Name,
|
||||
Type: device.Type,
|
||||
InfoName: device.InfoName,
|
||||
Protocol: device.Protocol,
|
||||
}
|
||||
sm.SmartDevices = append(sm.SmartDevices, deviceInfo)
|
||||
scannedDeviceNameMap[device.Name] = true
|
||||
}
|
||||
// remove devices that are not in the scan
|
||||
for key := range sm.SmartDataMap {
|
||||
if _, ok := scannedDeviceNameMap[key]; !ok {
|
||||
delete(sm.SmartDataMap, key)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return true
|
||||
return devices, true
|
||||
}
|
||||
|
||||
// mergeDeviceLists combines scanned and configured SMART devices, preferring
|
||||
// configured SMART_DEVICES when both sources reference the same device.
|
||||
func mergeDeviceLists(existing, scanned, configured []*DeviceInfo) []*DeviceInfo {
|
||||
if len(scanned) == 0 && len(configured) == 0 {
|
||||
return existing
|
||||
}
|
||||
|
||||
// preserveVerifiedType copies the verified type/parser metadata from an existing
|
||||
// device record so that subsequent scans/config updates never downgrade a
|
||||
// previously verified device.
|
||||
preserveVerifiedType := func(target, prev *DeviceInfo) {
|
||||
if prev == nil || !prev.typeVerified {
|
||||
return
|
||||
}
|
||||
target.Type = prev.Type
|
||||
target.typeVerified = true
|
||||
target.parserType = prev.parserType
|
||||
}
|
||||
|
||||
existingIndex := make(map[string]*DeviceInfo, len(existing))
|
||||
for _, dev := range existing {
|
||||
if dev == nil || dev.Name == "" {
|
||||
continue
|
||||
}
|
||||
existingIndex[dev.Name] = dev
|
||||
}
|
||||
|
||||
finalDevices := make([]*DeviceInfo, 0, len(scanned)+len(configured))
|
||||
deviceIndex := make(map[string]*DeviceInfo, len(scanned)+len(configured))
|
||||
|
||||
// Start with the newly scanned devices so we always surface fresh metadata,
|
||||
// but ensure we retain any previously verified parser assignment.
|
||||
for _, dev := range scanned {
|
||||
if dev == nil || dev.Name == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Work on a copy so we can safely adjust metadata without mutating the
|
||||
// input slices that may be reused elsewhere.
|
||||
copyDev := *dev
|
||||
if prev := existingIndex[copyDev.Name]; prev != nil {
|
||||
preserveVerifiedType(©Dev, prev)
|
||||
}
|
||||
|
||||
finalDevices = append(finalDevices, ©Dev)
|
||||
deviceIndex[copyDev.Name] = finalDevices[len(finalDevices)-1]
|
||||
}
|
||||
|
||||
// Merge configured devices on top so users can override scan results (except
|
||||
// for verified type information).
|
||||
for _, dev := range configured {
|
||||
if dev == nil || dev.Name == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if existingDev, ok := deviceIndex[dev.Name]; ok {
|
||||
// Only update the type if it has not been verified yet; otherwise we
|
||||
// keep the existing verified metadata intact.
|
||||
if dev.Type != "" && !existingDev.typeVerified {
|
||||
newType := strings.TrimSpace(dev.Type)
|
||||
existingDev.Type = newType
|
||||
existingDev.typeVerified = false
|
||||
existingDev.parserType = normalizeParserType(newType)
|
||||
}
|
||||
if dev.InfoName != "" {
|
||||
existingDev.InfoName = dev.InfoName
|
||||
}
|
||||
if dev.Protocol != "" {
|
||||
existingDev.Protocol = dev.Protocol
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
copyDev := *dev
|
||||
if prev := existingIndex[copyDev.Name]; prev != nil {
|
||||
preserveVerifiedType(©Dev, prev)
|
||||
} else if copyDev.Type != "" {
|
||||
copyDev.parserType = normalizeParserType(copyDev.Type)
|
||||
}
|
||||
|
||||
finalDevices = append(finalDevices, ©Dev)
|
||||
deviceIndex[copyDev.Name] = finalDevices[len(finalDevices)-1]
|
||||
}
|
||||
|
||||
return finalDevices
|
||||
}
|
||||
|
||||
// updateSmartDevices replaces the cached device list and prunes SMART data
|
||||
// entries whose backing device no longer exists.
|
||||
func (sm *SmartManager) updateSmartDevices(devices []*DeviceInfo) {
|
||||
sm.Lock()
|
||||
defer sm.Unlock()
|
||||
|
||||
sm.SmartDevices = devices
|
||||
|
||||
if len(sm.SmartDataMap) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
validNames := make(map[string]struct{}, len(devices))
|
||||
for _, device := range devices {
|
||||
if device == nil || device.Name == "" {
|
||||
continue
|
||||
}
|
||||
validNames[device.Name] = struct{}{}
|
||||
}
|
||||
|
||||
for key, data := range sm.SmartDataMap {
|
||||
if data == nil {
|
||||
delete(sm.SmartDataMap, key)
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := validNames[data.DiskName]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
delete(sm.SmartDataMap, key)
|
||||
}
|
||||
}
|
||||
|
||||
// isVirtualDevice checks if a device is a virtual disk that should be filtered out
|
||||
func (sm *SmartManager) isVirtualDevice(data *smart.SmartInfoForSata) bool {
|
||||
vendorUpper := strings.ToUpper(data.ScsiVendor)
|
||||
productUpper := strings.ToUpper(data.ScsiProduct)
|
||||
modelUpper := strings.ToUpper(data.ModelName)
|
||||
|
||||
return sm.isVirtualDeviceFromStrings(vendorUpper, productUpper, modelUpper)
|
||||
}
|
||||
|
||||
// isVirtualDeviceNvme checks if an NVMe device is a virtual disk that should be filtered out
|
||||
func (sm *SmartManager) isVirtualDeviceNvme(data *smart.SmartInfoForNvme) bool {
|
||||
modelUpper := strings.ToUpper(data.ModelName)
|
||||
|
||||
return sm.isVirtualDeviceFromStrings(modelUpper)
|
||||
}
|
||||
|
||||
// isVirtualDeviceScsi checks if a SCSI device is a virtual disk that should be filtered out
|
||||
func (sm *SmartManager) isVirtualDeviceScsi(data *smart.SmartInfoForScsi) bool {
|
||||
vendorUpper := strings.ToUpper(data.ScsiVendor)
|
||||
productUpper := strings.ToUpper(data.ScsiProduct)
|
||||
modelUpper := strings.ToUpper(data.ScsiModelName)
|
||||
|
||||
return sm.isVirtualDeviceFromStrings(vendorUpper, productUpper, modelUpper)
|
||||
}
|
||||
|
||||
// isVirtualDeviceFromStrings checks if any of the provided strings indicate a virtual device
|
||||
func (sm *SmartManager) isVirtualDeviceFromStrings(fields ...string) bool {
|
||||
for _, field := range fields {
|
||||
fieldUpper := strings.ToUpper(field)
|
||||
switch {
|
||||
case strings.Contains(fieldUpper, "IET"), // iSCSI Enterprise Target
|
||||
strings.Contains(fieldUpper, "VIRTUAL"),
|
||||
strings.Contains(fieldUpper, "QEMU"),
|
||||
strings.Contains(fieldUpper, "VBOX"),
|
||||
strings.Contains(fieldUpper, "VMWARE"),
|
||||
strings.Contains(fieldUpper, "MSFT"): // Microsoft Hyper-V
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// parseSmartForSata parses the output of smartctl --all -j for SATA/ATA devices and updates the SmartDataMap
|
||||
@@ -260,14 +706,19 @@ func (sm *SmartManager) parseSmartForSata(output []byte) (bool, int) {
|
||||
}
|
||||
|
||||
if data.SerialNumber == "" {
|
||||
slog.Warn("device has no serial number, skipping", "device", data.Device.Name)
|
||||
slog.Debug("no serial number", "device", data.Device.Name)
|
||||
return false, data.Smartctl.ExitStatus
|
||||
}
|
||||
|
||||
// Skip virtual devices (e.g., Kubernetes PVCs, QEMU, VirtualBox, etc.)
|
||||
if sm.isVirtualDevice(&data) {
|
||||
slog.Debug("skipping smart", "device", data.Device.Name, "model", data.ModelName)
|
||||
return false, data.Smartctl.ExitStatus
|
||||
}
|
||||
|
||||
sm.Lock()
|
||||
defer sm.Unlock()
|
||||
|
||||
// get device name (e.g. /dev/sda)
|
||||
keyName := data.SerialNumber
|
||||
|
||||
// if device does not exist in SmartDataMap, initialize it
|
||||
@@ -290,13 +741,17 @@ func (sm *SmartManager) parseSmartForSata(output []byte) (bool, int) {
|
||||
// update SmartAttributes
|
||||
smartData.Attributes = make([]*smart.SmartAttribute, 0, len(data.AtaSmartAttributes.Table))
|
||||
for _, attr := range data.AtaSmartAttributes.Table {
|
||||
rawValue := uint64(attr.Raw.Value)
|
||||
if parsed, ok := smart.ParseSmartRawValueString(attr.Raw.String); ok {
|
||||
rawValue = parsed
|
||||
}
|
||||
smartAttr := &smart.SmartAttribute{
|
||||
ID: attr.ID,
|
||||
Name: attr.Name,
|
||||
Value: attr.Value,
|
||||
Worst: attr.Worst,
|
||||
Threshold: attr.Thresh,
|
||||
RawValue: attr.Raw.Value,
|
||||
RawValue: rawValue,
|
||||
RawString: attr.Raw.String,
|
||||
WhenFailed: attr.WhenFailed,
|
||||
}
|
||||
@@ -317,6 +772,92 @@ func getSmartStatus(temperature uint8, passed bool) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SmartManager) parseSmartForScsi(output []byte) (bool, int) {
|
||||
var data smart.SmartInfoForScsi
|
||||
|
||||
if err := json.Unmarshal(output, &data); err != nil {
|
||||
return false, 0
|
||||
}
|
||||
|
||||
if data.SerialNumber == "" {
|
||||
slog.Debug("no serial number", "device", data.Device.Name)
|
||||
return false, data.Smartctl.ExitStatus
|
||||
}
|
||||
|
||||
// Skip virtual devices (e.g., Kubernetes PVCs, QEMU, VirtualBox, etc.)
|
||||
if sm.isVirtualDeviceScsi(&data) {
|
||||
slog.Debug("skipping smart", "device", data.Device.Name, "model", data.ScsiModelName)
|
||||
return false, data.Smartctl.ExitStatus
|
||||
}
|
||||
|
||||
sm.Lock()
|
||||
defer sm.Unlock()
|
||||
|
||||
keyName := data.SerialNumber
|
||||
if _, ok := sm.SmartDataMap[keyName]; !ok {
|
||||
sm.SmartDataMap[keyName] = &smart.SmartData{}
|
||||
}
|
||||
|
||||
smartData := sm.SmartDataMap[keyName]
|
||||
smartData.ModelName = data.ScsiModelName
|
||||
smartData.SerialNumber = data.SerialNumber
|
||||
smartData.FirmwareVersion = data.ScsiRevision
|
||||
smartData.Capacity = data.UserCapacity.Bytes
|
||||
smartData.Temperature = data.Temperature.Current
|
||||
smartData.SmartStatus = getSmartStatus(smartData.Temperature, data.SmartStatus.Passed)
|
||||
smartData.DiskName = data.Device.Name
|
||||
smartData.DiskType = data.Device.Type
|
||||
|
||||
attributes := make([]*smart.SmartAttribute, 0, 10)
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "PowerOnHours", RawValue: data.PowerOnTime.Hours})
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "PowerOnMinutes", RawValue: data.PowerOnTime.Minutes})
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "GrownDefectList", RawValue: data.ScsiGrownDefectList})
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "StartStopCycles", RawValue: data.ScsiStartStopCycleCounter.AccumulatedStartStopCycles})
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "LoadUnloadCycles", RawValue: data.ScsiStartStopCycleCounter.AccumulatedLoadUnloadCycles})
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "StartStopSpecified", RawValue: data.ScsiStartStopCycleCounter.SpecifiedCycleCountOverDeviceLifetime})
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "LoadUnloadSpecified", RawValue: data.ScsiStartStopCycleCounter.SpecifiedLoadUnloadCountOverDeviceLifetime})
|
||||
|
||||
readStats := data.ScsiErrorCounterLog.Read
|
||||
writeStats := data.ScsiErrorCounterLog.Write
|
||||
verifyStats := data.ScsiErrorCounterLog.Verify
|
||||
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "ReadTotalErrorsCorrected", RawValue: readStats.TotalErrorsCorrected})
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "ReadTotalUncorrectedErrors", RawValue: readStats.TotalUncorrectedErrors})
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "ReadCorrectionAlgorithmInvocations", RawValue: readStats.CorrectionAlgorithmInvocations})
|
||||
if val := parseScsiGigabytesProcessed(readStats.GigabytesProcessed); val >= 0 {
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "ReadGigabytesProcessed", RawValue: uint64(val)})
|
||||
}
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "WriteTotalErrorsCorrected", RawValue: writeStats.TotalErrorsCorrected})
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "WriteTotalUncorrectedErrors", RawValue: writeStats.TotalUncorrectedErrors})
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "WriteCorrectionAlgorithmInvocations", RawValue: writeStats.CorrectionAlgorithmInvocations})
|
||||
if val := parseScsiGigabytesProcessed(writeStats.GigabytesProcessed); val >= 0 {
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "WriteGigabytesProcessed", RawValue: uint64(val)})
|
||||
}
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "VerifyTotalErrorsCorrected", RawValue: verifyStats.TotalErrorsCorrected})
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "VerifyTotalUncorrectedErrors", RawValue: verifyStats.TotalUncorrectedErrors})
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "VerifyCorrectionAlgorithmInvocations", RawValue: verifyStats.CorrectionAlgorithmInvocations})
|
||||
if val := parseScsiGigabytesProcessed(verifyStats.GigabytesProcessed); val >= 0 {
|
||||
attributes = append(attributes, &smart.SmartAttribute{Name: "VerifyGigabytesProcessed", RawValue: uint64(val)})
|
||||
}
|
||||
|
||||
smartData.Attributes = attributes
|
||||
sm.SmartDataMap[keyName] = smartData
|
||||
|
||||
return true, data.Smartctl.ExitStatus
|
||||
}
|
||||
|
||||
func parseScsiGigabytesProcessed(value string) int64 {
|
||||
if value == "" {
|
||||
return -1
|
||||
}
|
||||
normalized := strings.ReplaceAll(value, ",", "")
|
||||
parsed, err := strconv.ParseInt(normalized, 10, 64)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
// parseSmartForNvme parses the output of smartctl --all -j /dev/nvmeX and updates the SmartDataMap
|
||||
// Returns hasValidData and exitStatus
|
||||
func (sm *SmartManager) parseSmartForNvme(output []byte) (bool, int) {
|
||||
@@ -327,14 +868,19 @@ func (sm *SmartManager) parseSmartForNvme(output []byte) (bool, int) {
|
||||
}
|
||||
|
||||
if data.SerialNumber == "" {
|
||||
slog.Warn("device has no serial number, skipping", "device", data.Device.Name)
|
||||
slog.Debug("no serial number", "device", data.Device.Name)
|
||||
return false, data.Smartctl.ExitStatus
|
||||
}
|
||||
|
||||
// Skip virtual devices (e.g., Kubernetes PVCs, QEMU, VirtualBox, etc.)
|
||||
if sm.isVirtualDeviceNvme(data) {
|
||||
slog.Debug("skipping smart", "device", data.Device.Name, "model", data.ModelName)
|
||||
return false, data.Smartctl.ExitStatus
|
||||
}
|
||||
|
||||
sm.Lock()
|
||||
defer sm.Unlock()
|
||||
|
||||
// get device name (e.g. /dev/nvme0)
|
||||
keyName := data.SerialNumber
|
||||
|
||||
// if device does not exist in SmartDataMap, initialize it
|
||||
@@ -382,11 +928,33 @@ func (sm *SmartManager) parseSmartForNvme(output []byte) (bool, int) {
|
||||
}
|
||||
|
||||
// detectSmartctl checks if smartctl is installed, returns an error if not
|
||||
func (sm *SmartManager) detectSmartctl() error {
|
||||
if _, err := exec.LookPath("smartctl"); err == nil {
|
||||
return nil
|
||||
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
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("no smartctl found - install smartctl")
|
||||
|
||||
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 {
|
||||
if _, err := os.Stat(location); err == nil {
|
||||
return location, nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("smartctl not found")
|
||||
}
|
||||
|
||||
// NewSmartManager creates and initializes a new SmartManager
|
||||
@@ -394,9 +962,13 @@ func NewSmartManager() (*SmartManager, error) {
|
||||
sm := &SmartManager{
|
||||
SmartDataMap: make(map[string]*smart.SmartData),
|
||||
}
|
||||
if err := sm.detectSmartctl(); err != nil {
|
||||
sm.refreshExcludedDevices()
|
||||
path, err := sm.detectSmartctl()
|
||||
if err != nil {
|
||||
slog.Debug(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
slog.Debug("smartctl", "path", path)
|
||||
sm.binPath = path
|
||||
return sm, nil
|
||||
}
|
||||
|
||||
9
agent/smart_nonwindows.go
Normal file
9
agent/smart_nonwindows.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build !windows
|
||||
|
||||
package agent
|
||||
|
||||
import "errors"
|
||||
|
||||
func ensureEmbeddedSmartctl() (string, error) {
|
||||
return "", errors.ErrUnsupported
|
||||
}
|
||||
782
agent/smart_test.go
Normal file
782
agent/smart_test.go
Normal file
@@ -0,0 +1,782 @@
|
||||
//go:build testing
|
||||
// +build testing
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/smart"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseSmartForScsi(t *testing.T) {
|
||||
fixturePath := filepath.Join("test-data", "smart", "scsi.json")
|
||||
data, err := os.ReadFile(fixturePath)
|
||||
if err != nil {
|
||||
t.Fatalf("failed reading fixture: %v", err)
|
||||
}
|
||||
|
||||
sm := &SmartManager{
|
||||
SmartDataMap: make(map[string]*smart.SmartData),
|
||||
}
|
||||
|
||||
hasData, exitStatus := sm.parseSmartForScsi(data)
|
||||
if !hasData {
|
||||
t.Fatalf("expected SCSI data to parse successfully")
|
||||
}
|
||||
if exitStatus != 0 {
|
||||
t.Fatalf("expected exit status 0, got %d", exitStatus)
|
||||
}
|
||||
|
||||
deviceData, ok := sm.SmartDataMap["9YHSDH9B"]
|
||||
if !ok {
|
||||
t.Fatalf("expected smart data entry for serial 9YHSDH9B")
|
||||
}
|
||||
|
||||
assert.Equal(t, deviceData.ModelName, "YADRO WUH721414AL4204")
|
||||
assert.Equal(t, deviceData.SerialNumber, "9YHSDH9B")
|
||||
assert.Equal(t, deviceData.FirmwareVersion, "C240")
|
||||
assert.Equal(t, deviceData.DiskName, "/dev/sde")
|
||||
assert.Equal(t, deviceData.DiskType, "scsi")
|
||||
assert.EqualValues(t, deviceData.Temperature, 34)
|
||||
assert.Equal(t, deviceData.SmartStatus, "PASSED")
|
||||
assert.EqualValues(t, deviceData.Capacity, 14000519643136)
|
||||
|
||||
if len(deviceData.Attributes) == 0 {
|
||||
t.Fatalf("expected attributes to be populated")
|
||||
}
|
||||
|
||||
assertAttrValue(t, deviceData.Attributes, "PowerOnHours", 458)
|
||||
assertAttrValue(t, deviceData.Attributes, "PowerOnMinutes", 25)
|
||||
assertAttrValue(t, deviceData.Attributes, "GrownDefectList", 0)
|
||||
assertAttrValue(t, deviceData.Attributes, "StartStopCycles", 2)
|
||||
assertAttrValue(t, deviceData.Attributes, "LoadUnloadCycles", 418)
|
||||
assertAttrValue(t, deviceData.Attributes, "ReadGigabytesProcessed", 3641)
|
||||
assertAttrValue(t, deviceData.Attributes, "WriteGigabytesProcessed", 2124590)
|
||||
assertAttrValue(t, deviceData.Attributes, "VerifyGigabytesProcessed", 0)
|
||||
}
|
||||
|
||||
func TestParseSmartForSata(t *testing.T) {
|
||||
fixturePath := filepath.Join("test-data", "smart", "sda.json")
|
||||
data, err := os.ReadFile(fixturePath)
|
||||
require.NoError(t, err)
|
||||
|
||||
sm := &SmartManager{
|
||||
SmartDataMap: make(map[string]*smart.SmartData),
|
||||
}
|
||||
|
||||
hasData, exitStatus := sm.parseSmartForSata(data)
|
||||
require.True(t, hasData)
|
||||
assert.Equal(t, 64, exitStatus)
|
||||
|
||||
deviceData, ok := sm.SmartDataMap["9C40918040082"]
|
||||
require.True(t, ok, "expected smart data entry for serial 9C40918040082")
|
||||
|
||||
assert.Equal(t, "P3-2TB", deviceData.ModelName)
|
||||
assert.Equal(t, "X0104A0", deviceData.FirmwareVersion)
|
||||
assert.Equal(t, "/dev/sda", deviceData.DiskName)
|
||||
assert.Equal(t, "sat", deviceData.DiskType)
|
||||
assert.Equal(t, uint8(31), deviceData.Temperature)
|
||||
assert.Equal(t, "PASSED", deviceData.SmartStatus)
|
||||
assert.Equal(t, uint64(2048408248320), deviceData.Capacity)
|
||||
if assert.NotEmpty(t, deviceData.Attributes) {
|
||||
assertAttrValue(t, deviceData.Attributes, "Temperature_Celsius", 31)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSmartForSataParentheticalRawValue(t *testing.T) {
|
||||
jsonPayload := []byte(`{
|
||||
"smartctl": {"exit_status": 0},
|
||||
"device": {"name": "/dev/sdz", "type": "sat"},
|
||||
"model_name": "Example",
|
||||
"serial_number": "PARENTHESES123",
|
||||
"firmware_version": "1.0",
|
||||
"user_capacity": {"bytes": 1024},
|
||||
"smart_status": {"passed": true},
|
||||
"temperature": {"current": 25},
|
||||
"ata_smart_attributes": {
|
||||
"table": [
|
||||
{
|
||||
"id": 9,
|
||||
"name": "Power_On_Hours",
|
||||
"value": 93,
|
||||
"worst": 55,
|
||||
"thresh": 0,
|
||||
"when_failed": "",
|
||||
"raw": {
|
||||
"value": 57891864217128,
|
||||
"string": "39925 (212 206 0)"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`)
|
||||
|
||||
sm := &SmartManager{SmartDataMap: make(map[string]*smart.SmartData)}
|
||||
|
||||
hasData, exitStatus := sm.parseSmartForSata(jsonPayload)
|
||||
require.True(t, hasData)
|
||||
assert.Equal(t, 0, exitStatus)
|
||||
|
||||
data, ok := sm.SmartDataMap["PARENTHESES123"]
|
||||
require.True(t, ok)
|
||||
require.Len(t, data.Attributes, 1)
|
||||
|
||||
attr := data.Attributes[0]
|
||||
assert.Equal(t, uint64(39925), attr.RawValue)
|
||||
assert.Equal(t, "39925 (212 206 0)", attr.RawString)
|
||||
}
|
||||
|
||||
func TestParseSmartForNvme(t *testing.T) {
|
||||
fixturePath := filepath.Join("test-data", "smart", "nvme0.json")
|
||||
data, err := os.ReadFile(fixturePath)
|
||||
require.NoError(t, err)
|
||||
|
||||
sm := &SmartManager{
|
||||
SmartDataMap: make(map[string]*smart.SmartData),
|
||||
}
|
||||
|
||||
hasData, exitStatus := sm.parseSmartForNvme(data)
|
||||
require.True(t, hasData)
|
||||
assert.Equal(t, 0, exitStatus)
|
||||
|
||||
deviceData, ok := sm.SmartDataMap["2024031600129"]
|
||||
require.True(t, ok, "expected smart data entry for serial 2024031600129")
|
||||
|
||||
assert.Equal(t, "PELADN 512GB", deviceData.ModelName)
|
||||
assert.Equal(t, "VC2S038E", deviceData.FirmwareVersion)
|
||||
assert.Equal(t, "/dev/nvme0", deviceData.DiskName)
|
||||
assert.Equal(t, "nvme", deviceData.DiskType)
|
||||
assert.Equal(t, uint8(61), deviceData.Temperature)
|
||||
assert.Equal(t, "PASSED", deviceData.SmartStatus)
|
||||
assert.Equal(t, uint64(512110190592), deviceData.Capacity)
|
||||
if assert.NotEmpty(t, deviceData.Attributes) {
|
||||
assertAttrValue(t, deviceData.Attributes, "PercentageUsed", 0)
|
||||
assertAttrValue(t, deviceData.Attributes, "DataUnitsWritten", 16040567)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasDataForDevice(t *testing.T) {
|
||||
sm := &SmartManager{
|
||||
SmartDataMap: map[string]*smart.SmartData{
|
||||
"serial-1": {DiskName: "/dev/sda"},
|
||||
"serial-2": nil,
|
||||
},
|
||||
}
|
||||
|
||||
assert.True(t, sm.hasDataForDevice("/dev/sda"))
|
||||
assert.False(t, sm.hasDataForDevice("/dev/sdb"))
|
||||
}
|
||||
|
||||
func TestDevicesSnapshotReturnsCopy(t *testing.T) {
|
||||
originalDevice := &DeviceInfo{Name: "/dev/sda"}
|
||||
sm := &SmartManager{
|
||||
SmartDevices: []*DeviceInfo{
|
||||
originalDevice,
|
||||
{Name: "/dev/sdb"},
|
||||
},
|
||||
}
|
||||
|
||||
snapshot := sm.devicesSnapshot()
|
||||
require.Len(t, snapshot, 2)
|
||||
|
||||
sm.SmartDevices[0] = &DeviceInfo{Name: "/dev/sdz"}
|
||||
assert.Equal(t, "/dev/sda", snapshot[0].Name)
|
||||
|
||||
snapshot[1] = &DeviceInfo{Name: "/dev/nvme0"}
|
||||
assert.Equal(t, "/dev/sdb", sm.SmartDevices[1].Name)
|
||||
|
||||
sm.SmartDevices = append(sm.SmartDevices, &DeviceInfo{Name: "/dev/nvme1"})
|
||||
assert.Len(t, snapshot, 2)
|
||||
}
|
||||
|
||||
func TestScanDevicesWithEnvOverride(t *testing.T) {
|
||||
t.Setenv("SMART_DEVICES", "/dev/sda:sat, /dev/nvme0:nvme")
|
||||
|
||||
sm := &SmartManager{
|
||||
SmartDataMap: make(map[string]*smart.SmartData),
|
||||
}
|
||||
|
||||
err := sm.ScanDevices(true)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, sm.SmartDevices, 2)
|
||||
assert.Equal(t, "/dev/sda", sm.SmartDevices[0].Name)
|
||||
assert.Equal(t, "sat", sm.SmartDevices[0].Type)
|
||||
assert.Equal(t, "/dev/nvme0", sm.SmartDevices[1].Name)
|
||||
assert.Equal(t, "nvme", sm.SmartDevices[1].Type)
|
||||
}
|
||||
|
||||
func TestScanDevicesWithEnvOverrideInvalid(t *testing.T) {
|
||||
t.Setenv("SMART_DEVICES", ":sat")
|
||||
|
||||
sm := &SmartManager{
|
||||
SmartDataMap: make(map[string]*smart.SmartData),
|
||||
}
|
||||
|
||||
err := sm.ScanDevices(true)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestScanDevicesWithEnvOverrideEmpty(t *testing.T) {
|
||||
t.Setenv("SMART_DEVICES", " ")
|
||||
|
||||
sm := &SmartManager{
|
||||
SmartDataMap: make(map[string]*smart.SmartData),
|
||||
}
|
||||
|
||||
err := sm.ScanDevices(true)
|
||||
assert.ErrorIs(t, err, errNoValidSmartData)
|
||||
assert.Empty(t, sm.SmartDevices)
|
||||
}
|
||||
|
||||
func TestSmartctlArgsWithoutType(t *testing.T) {
|
||||
device := &DeviceInfo{Name: "/dev/sda"}
|
||||
|
||||
sm := &SmartManager{}
|
||||
|
||||
args := sm.smartctlArgs(device, true)
|
||||
assert.Equal(t, []string{"-a", "--json=c", "-n", "standby", "/dev/sda"}, args)
|
||||
}
|
||||
|
||||
func TestSmartctlArgs(t *testing.T) {
|
||||
sm := &SmartManager{}
|
||||
|
||||
sataDevice := &DeviceInfo{Name: "/dev/sda", Type: "sat"}
|
||||
assert.Equal(t,
|
||||
[]string{"-d", "sat", "-a", "--json=c", "-n", "standby", "/dev/sda"},
|
||||
sm.smartctlArgs(sataDevice, true),
|
||||
)
|
||||
|
||||
assert.Equal(t,
|
||||
[]string{"-d", "sat", "-a", "--json=c", "/dev/sda"},
|
||||
sm.smartctlArgs(sataDevice, false),
|
||||
)
|
||||
|
||||
assert.Equal(t,
|
||||
[]string{"-a", "--json=c", "-n", "standby"},
|
||||
sm.smartctlArgs(nil, true),
|
||||
)
|
||||
}
|
||||
|
||||
func TestResolveRefreshError(t *testing.T) {
|
||||
scanErr := errors.New("scan failed")
|
||||
collectErr := errors.New("collect failed")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
devices []*DeviceInfo
|
||||
data map[string]*smart.SmartData
|
||||
scanErr error
|
||||
collectErr error
|
||||
expectedErr error
|
||||
expectNoErr bool
|
||||
}{
|
||||
{
|
||||
name: "no devices returns scan error",
|
||||
devices: nil,
|
||||
data: make(map[string]*smart.SmartData),
|
||||
scanErr: scanErr,
|
||||
expectedErr: scanErr,
|
||||
},
|
||||
{
|
||||
name: "has data ignores errors",
|
||||
devices: []*DeviceInfo{{Name: "/dev/sda"}},
|
||||
data: map[string]*smart.SmartData{"serial": {}},
|
||||
scanErr: scanErr,
|
||||
collectErr: collectErr,
|
||||
expectNoErr: true,
|
||||
},
|
||||
{
|
||||
name: "collect error preferred",
|
||||
devices: []*DeviceInfo{{Name: "/dev/sda"}},
|
||||
data: make(map[string]*smart.SmartData),
|
||||
collectErr: collectErr,
|
||||
expectedErr: collectErr,
|
||||
},
|
||||
{
|
||||
name: "scan error returned when no data",
|
||||
devices: []*DeviceInfo{{Name: "/dev/sda"}},
|
||||
data: make(map[string]*smart.SmartData),
|
||||
scanErr: scanErr,
|
||||
expectedErr: scanErr,
|
||||
},
|
||||
{
|
||||
name: "no errors returns sentinel",
|
||||
devices: []*DeviceInfo{{Name: "/dev/sda"}},
|
||||
data: make(map[string]*smart.SmartData),
|
||||
expectedErr: errNoValidSmartData,
|
||||
},
|
||||
{
|
||||
name: "no devices collect error",
|
||||
devices: nil,
|
||||
data: make(map[string]*smart.SmartData),
|
||||
collectErr: collectErr,
|
||||
expectedErr: collectErr,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
sm := &SmartManager{
|
||||
SmartDevices: tt.devices,
|
||||
SmartDataMap: tt.data,
|
||||
}
|
||||
|
||||
err := sm.resolveRefreshError(tt.scanErr, tt.collectErr)
|
||||
if tt.expectNoErr {
|
||||
assert.NoError(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
if tt.expectedErr == nil {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Equal(t, tt.expectedErr, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseScan(t *testing.T) {
|
||||
sm := &SmartManager{
|
||||
SmartDataMap: map[string]*smart.SmartData{
|
||||
"serial-active": {DiskName: "/dev/sda"},
|
||||
"serial-stale": {DiskName: "/dev/sdb"},
|
||||
},
|
||||
}
|
||||
|
||||
scanJSON := []byte(`{
|
||||
"devices": [
|
||||
{"name": "/dev/sda", "type": "sat", "info_name": "/dev/sda [SAT]", "protocol": "ATA"},
|
||||
{"name": "/dev/nvme0", "type": "nvme", "info_name": "/dev/nvme0", "protocol": "NVMe"}
|
||||
]
|
||||
}`)
|
||||
|
||||
devices, hasData := sm.parseScan(scanJSON)
|
||||
assert.True(t, hasData)
|
||||
|
||||
sm.updateSmartDevices(devices)
|
||||
|
||||
require.Len(t, sm.SmartDevices, 2)
|
||||
assert.Equal(t, "/dev/sda", sm.SmartDevices[0].Name)
|
||||
assert.Equal(t, "sat", sm.SmartDevices[0].Type)
|
||||
assert.Equal(t, "/dev/nvme0", sm.SmartDevices[1].Name)
|
||||
assert.Equal(t, "nvme", sm.SmartDevices[1].Type)
|
||||
|
||||
_, activeExists := sm.SmartDataMap["serial-active"]
|
||||
assert.True(t, activeExists, "active smart data should be preserved when device path remains")
|
||||
|
||||
_, staleExists := sm.SmartDataMap["serial-stale"]
|
||||
assert.False(t, staleExists, "stale smart data entry should be removed when device path disappears")
|
||||
}
|
||||
|
||||
func TestMergeDeviceListsPrefersConfigured(t *testing.T) {
|
||||
scanned := []*DeviceInfo{
|
||||
{Name: "/dev/sda", Type: "sat", InfoName: "scan-info", Protocol: "ATA"},
|
||||
{Name: "/dev/nvme0", Type: "nvme"},
|
||||
}
|
||||
|
||||
configured := []*DeviceInfo{
|
||||
{Name: "/dev/sda", Type: "sat-override"},
|
||||
{Name: "/dev/sdb", Type: "sat"},
|
||||
}
|
||||
|
||||
merged := mergeDeviceLists(nil, scanned, configured)
|
||||
require.Len(t, merged, 3)
|
||||
|
||||
byName := make(map[string]*DeviceInfo, len(merged))
|
||||
for _, dev := range merged {
|
||||
byName[dev.Name] = dev
|
||||
}
|
||||
|
||||
require.Contains(t, byName, "/dev/sda")
|
||||
assert.Equal(t, "sat-override", byName["/dev/sda"].Type, "configured type should override scanned type")
|
||||
assert.Equal(t, "scan-info", byName["/dev/sda"].InfoName, "scan metadata should be preserved when config does not provide it")
|
||||
|
||||
require.Contains(t, byName, "/dev/nvme0")
|
||||
assert.Equal(t, "nvme", byName["/dev/nvme0"].Type)
|
||||
|
||||
require.Contains(t, byName, "/dev/sdb")
|
||||
assert.Equal(t, "sat", byName["/dev/sdb"].Type)
|
||||
}
|
||||
|
||||
func TestMergeDeviceListsPreservesVerification(t *testing.T) {
|
||||
existing := []*DeviceInfo{
|
||||
{Name: "/dev/sda", Type: "sat+megaraid", parserType: "sat", typeVerified: true},
|
||||
}
|
||||
|
||||
scanned := []*DeviceInfo{
|
||||
{Name: "/dev/sda", Type: "nvme"},
|
||||
}
|
||||
|
||||
merged := mergeDeviceLists(existing, scanned, nil)
|
||||
require.Len(t, merged, 1)
|
||||
|
||||
device := merged[0]
|
||||
assert.True(t, device.typeVerified)
|
||||
assert.Equal(t, "sat", device.parserType)
|
||||
assert.Equal(t, "sat+megaraid", device.Type)
|
||||
}
|
||||
|
||||
func TestMergeDeviceListsUpdatesTypeWhenUnverified(t *testing.T) {
|
||||
existing := []*DeviceInfo{
|
||||
{Name: "/dev/sda", Type: "sat", parserType: "sat", typeVerified: false},
|
||||
}
|
||||
|
||||
scanned := []*DeviceInfo{
|
||||
{Name: "/dev/sda", Type: "nvme"},
|
||||
}
|
||||
|
||||
merged := mergeDeviceLists(existing, scanned, nil)
|
||||
require.Len(t, merged, 1)
|
||||
|
||||
device := merged[0]
|
||||
assert.False(t, device.typeVerified)
|
||||
assert.Equal(t, "nvme", device.Type)
|
||||
assert.Equal(t, "", device.parserType)
|
||||
}
|
||||
|
||||
func TestParseSmartOutputMarksVerified(t *testing.T) {
|
||||
fixturePath := filepath.Join("test-data", "smart", "nvme0.json")
|
||||
data, err := os.ReadFile(fixturePath)
|
||||
require.NoError(t, err)
|
||||
|
||||
sm := &SmartManager{SmartDataMap: make(map[string]*smart.SmartData)}
|
||||
device := &DeviceInfo{Name: "/dev/nvme0"}
|
||||
|
||||
require.True(t, sm.parseSmartOutput(device, data))
|
||||
assert.Equal(t, "nvme", device.Type)
|
||||
assert.Equal(t, "nvme", device.parserType)
|
||||
assert.True(t, device.typeVerified)
|
||||
}
|
||||
|
||||
func TestParseSmartOutputKeepsCustomType(t *testing.T) {
|
||||
fixturePath := filepath.Join("test-data", "smart", "sda.json")
|
||||
data, err := os.ReadFile(fixturePath)
|
||||
require.NoError(t, err)
|
||||
|
||||
sm := &SmartManager{SmartDataMap: make(map[string]*smart.SmartData)}
|
||||
device := &DeviceInfo{Name: "/dev/sda", Type: "sat+megaraid"}
|
||||
|
||||
require.True(t, sm.parseSmartOutput(device, data))
|
||||
assert.Equal(t, "sat+megaraid", device.Type)
|
||||
assert.Equal(t, "sat", device.parserType)
|
||||
assert.True(t, device.typeVerified)
|
||||
}
|
||||
|
||||
func TestParseSmartOutputResetsVerificationOnFailure(t *testing.T) {
|
||||
sm := &SmartManager{SmartDataMap: make(map[string]*smart.SmartData)}
|
||||
device := &DeviceInfo{Name: "/dev/sda", Type: "sat", parserType: "sat", typeVerified: true}
|
||||
|
||||
assert.False(t, sm.parseSmartOutput(device, []byte("not json")))
|
||||
assert.False(t, device.typeVerified)
|
||||
assert.Equal(t, "sat", device.parserType)
|
||||
}
|
||||
|
||||
func assertAttrValue(t *testing.T, attributes []*smart.SmartAttribute, name string, expected uint64) {
|
||||
t.Helper()
|
||||
attr := findAttr(attributes, name)
|
||||
if attr == nil {
|
||||
t.Fatalf("expected attribute %s to be present", name)
|
||||
}
|
||||
if attr.RawValue != expected {
|
||||
t.Fatalf("unexpected attribute %s value: got %d, want %d", name, attr.RawValue, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func findAttr(attributes []*smart.SmartAttribute, name string) *smart.SmartAttribute {
|
||||
for _, attr := range attributes {
|
||||
if attr != nil && attr.Name == name {
|
||||
return attr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestIsVirtualDevice(t *testing.T) {
|
||||
sm := &SmartManager{}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
vendor string
|
||||
product string
|
||||
model string
|
||||
expected bool
|
||||
}{
|
||||
{"regular drive", "SEAGATE", "ST1000DM003", "ST1000DM003-1CH162", false},
|
||||
{"qemu virtual", "QEMU", "QEMU HARDDISK", "QEMU HARDDISK", true},
|
||||
{"virtualbox virtual", "VBOX", "HARDDISK", "VBOX HARDDISK", true},
|
||||
{"vmware virtual", "VMWARE", "Virtual disk", "VMWARE Virtual disk", true},
|
||||
{"virtual in model", "ATA", "VIRTUAL", "VIRTUAL DISK", true},
|
||||
{"iet virtual", "IET", "VIRTUAL-DISK", "VIRTUAL-DISK", true},
|
||||
{"hyper-v virtual", "MSFT", "VIRTUAL HD", "VIRTUAL HD", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := &smart.SmartInfoForSata{
|
||||
ScsiVendor: tt.vendor,
|
||||
ScsiProduct: tt.product,
|
||||
ModelName: tt.model,
|
||||
}
|
||||
result := sm.isVirtualDevice(data)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsVirtualDeviceNvme(t *testing.T) {
|
||||
sm := &SmartManager{}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
model string
|
||||
expected bool
|
||||
}{
|
||||
{"regular nvme", "Samsung SSD 970 EVO Plus 1TB", false},
|
||||
{"qemu virtual", "QEMU NVMe Ctrl", true},
|
||||
{"virtualbox virtual", "VBOX NVMe", true},
|
||||
{"vmware virtual", "VMWARE NVMe", true},
|
||||
{"virtual in model", "Virtual NVMe Device", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := &smart.SmartInfoForNvme{
|
||||
ModelName: tt.model,
|
||||
}
|
||||
result := sm.isVirtualDeviceNvme(data)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsVirtualDeviceScsi(t *testing.T) {
|
||||
sm := &SmartManager{}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
vendor string
|
||||
product string
|
||||
model string
|
||||
expected bool
|
||||
}{
|
||||
{"regular scsi", "SEAGATE", "ST1000DM003", "ST1000DM003-1CH162", false},
|
||||
{"qemu virtual", "QEMU", "QEMU HARDDISK", "QEMU HARDDISK", true},
|
||||
{"virtualbox virtual", "VBOX", "HARDDISK", "VBOX HARDDISK", true},
|
||||
{"vmware virtual", "VMWARE", "Virtual disk", "VMWARE Virtual disk", true},
|
||||
{"virtual in model", "ATA", "VIRTUAL", "VIRTUAL DISK", true},
|
||||
{"iet virtual", "IET", "VIRTUAL-DISK", "VIRTUAL-DISK", true},
|
||||
{"hyper-v virtual", "MSFT", "VIRTUAL HD", "VIRTUAL HD", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := &smart.SmartInfoForScsi{
|
||||
ScsiVendor: tt.vendor,
|
||||
ScsiProduct: tt.product,
|
||||
ScsiModelName: tt.model,
|
||||
}
|
||||
result := sm.isVirtualDeviceScsi(data)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshExcludedDevices(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
envValue string
|
||||
expectedDevs map[string]struct{}
|
||||
}{
|
||||
{
|
||||
name: "empty env",
|
||||
envValue: "",
|
||||
expectedDevs: map[string]struct{}{},
|
||||
},
|
||||
{
|
||||
name: "single device",
|
||||
envValue: "/dev/sda",
|
||||
expectedDevs: map[string]struct{}{
|
||||
"/dev/sda": {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple devices",
|
||||
envValue: "/dev/sda,/dev/sdb,/dev/nvme0",
|
||||
expectedDevs: map[string]struct{}{
|
||||
"/dev/sda": {},
|
||||
"/dev/sdb": {},
|
||||
"/dev/nvme0": {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "devices with whitespace",
|
||||
envValue: " /dev/sda , /dev/sdb , /dev/nvme0 ",
|
||||
expectedDevs: map[string]struct{}{
|
||||
"/dev/sda": {},
|
||||
"/dev/sdb": {},
|
||||
"/dev/nvme0": {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "duplicate devices",
|
||||
envValue: "/dev/sda,/dev/sdb,/dev/sda",
|
||||
expectedDevs: map[string]struct{}{
|
||||
"/dev/sda": {},
|
||||
"/dev/sdb": {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty entries and whitespace",
|
||||
envValue: "/dev/sda,, /dev/sdb , , ",
|
||||
expectedDevs: map[string]struct{}{
|
||||
"/dev/sda": {},
|
||||
"/dev/sdb": {},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.envValue != "" {
|
||||
t.Setenv("EXCLUDE_SMART", tt.envValue)
|
||||
} else {
|
||||
// Ensure env var is not set for empty test
|
||||
os.Unsetenv("EXCLUDE_SMART")
|
||||
}
|
||||
|
||||
sm := &SmartManager{}
|
||||
sm.refreshExcludedDevices()
|
||||
|
||||
assert.Equal(t, tt.expectedDevs, sm.excludedDevices)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsExcludedDevice(t *testing.T) {
|
||||
sm := &SmartManager{
|
||||
excludedDevices: map[string]struct{}{
|
||||
"/dev/sda": {},
|
||||
"/dev/nvme0": {},
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
deviceName string
|
||||
expectedBool bool
|
||||
}{
|
||||
{"excluded device sda", "/dev/sda", true},
|
||||
{"excluded device nvme0", "/dev/nvme0", true},
|
||||
{"non-excluded device sdb", "/dev/sdb", false},
|
||||
{"non-excluded device nvme1", "/dev/nvme1", false},
|
||||
{"empty device name", "", false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := sm.isExcludedDevice(tt.deviceName)
|
||||
assert.Equal(t, tt.expectedBool, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterExcludedDevices(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
excludedDevs map[string]struct{}
|
||||
inputDevices []*DeviceInfo
|
||||
expectedDevs []*DeviceInfo
|
||||
expectedLength int
|
||||
}{
|
||||
{
|
||||
name: "no exclusions",
|
||||
excludedDevs: map[string]struct{}{},
|
||||
inputDevices: []*DeviceInfo{
|
||||
{Name: "/dev/sda"},
|
||||
{Name: "/dev/sdb"},
|
||||
{Name: "/dev/nvme0"},
|
||||
},
|
||||
expectedDevs: []*DeviceInfo{
|
||||
{Name: "/dev/sda"},
|
||||
{Name: "/dev/sdb"},
|
||||
{Name: "/dev/nvme0"},
|
||||
},
|
||||
expectedLength: 3,
|
||||
},
|
||||
{
|
||||
name: "some devices excluded",
|
||||
excludedDevs: map[string]struct{}{
|
||||
"/dev/sda": {},
|
||||
"/dev/nvme0": {},
|
||||
},
|
||||
inputDevices: []*DeviceInfo{
|
||||
{Name: "/dev/sda"},
|
||||
{Name: "/dev/sdb"},
|
||||
{Name: "/dev/nvme0"},
|
||||
{Name: "/dev/nvme1"},
|
||||
},
|
||||
expectedDevs: []*DeviceInfo{
|
||||
{Name: "/dev/sdb"},
|
||||
{Name: "/dev/nvme1"},
|
||||
},
|
||||
expectedLength: 2,
|
||||
},
|
||||
{
|
||||
name: "all devices excluded",
|
||||
excludedDevs: map[string]struct{}{
|
||||
"/dev/sda": {},
|
||||
"/dev/sdb": {},
|
||||
},
|
||||
inputDevices: []*DeviceInfo{
|
||||
{Name: "/dev/sda"},
|
||||
{Name: "/dev/sdb"},
|
||||
},
|
||||
expectedDevs: []*DeviceInfo{},
|
||||
expectedLength: 0,
|
||||
},
|
||||
{
|
||||
name: "nil devices",
|
||||
excludedDevs: map[string]struct{}{},
|
||||
inputDevices: nil,
|
||||
expectedDevs: []*DeviceInfo{},
|
||||
expectedLength: 0,
|
||||
},
|
||||
{
|
||||
name: "filter nil and empty name devices",
|
||||
excludedDevs: map[string]struct{}{
|
||||
"/dev/sda": {},
|
||||
},
|
||||
inputDevices: []*DeviceInfo{
|
||||
{Name: "/dev/sda"},
|
||||
nil,
|
||||
{Name: ""},
|
||||
{Name: "/dev/sdb"},
|
||||
},
|
||||
expectedDevs: []*DeviceInfo{
|
||||
{Name: "/dev/sdb"},
|
||||
},
|
||||
expectedLength: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
sm := &SmartManager{
|
||||
excludedDevices: tt.excludedDevs,
|
||||
}
|
||||
|
||||
result := sm.filterExcludedDevices(tt.inputDevices)
|
||||
|
||||
assert.Len(t, result, tt.expectedLength)
|
||||
assert.Equal(t, tt.expectedDevs, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
40
agent/smart_windows.go
Normal file
40
agent/smart_windows.go
Normal file
@@ -0,0 +1,40 @@
|
||||
//go:build windows
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
)
|
||||
|
||||
//go:embed smartmontools/smartctl.exe
|
||||
var embeddedSmartctl []byte
|
||||
|
||||
var (
|
||||
smartctlOnce sync.Once
|
||||
smartctlPath string
|
||||
smartctlErr error
|
||||
)
|
||||
|
||||
func ensureEmbeddedSmartctl() (string, error) {
|
||||
smartctlOnce.Do(func() {
|
||||
destDir := filepath.Join(os.TempDir(), "beszel", "smartmontools")
|
||||
if err := os.MkdirAll(destDir, 0o755); err != nil {
|
||||
smartctlErr = fmt.Errorf("failed to create smartctl directory: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
destPath := filepath.Join(destDir, "smartctl.exe")
|
||||
if err := os.WriteFile(destPath, embeddedSmartctl, 0o755); err != nil {
|
||||
smartctlErr = fmt.Errorf("failed to write embedded smartctl: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
smartctlPath = destPath
|
||||
})
|
||||
|
||||
return smartctlPath, smartctlErr
|
||||
}
|
||||
@@ -78,16 +78,29 @@ func (a *Agent) getSystemStats(cacheTimeMs uint16) system.Stats {
|
||||
var systemStats system.Stats
|
||||
|
||||
// battery
|
||||
if battery.HasReadableBattery() {
|
||||
systemStats.Battery[0], systemStats.Battery[1], _ = battery.GetBatteryStats()
|
||||
if batteryPercent, batteryState, err := battery.GetBatteryStats(); err == nil {
|
||||
systemStats.Battery[0] = batteryPercent
|
||||
systemStats.Battery[1] = batteryState
|
||||
}
|
||||
|
||||
// cpu percent
|
||||
cpuPercent, err := getCpuPercent(cacheTimeMs)
|
||||
// cpu metrics
|
||||
cpuMetrics, err := getCpuMetrics(cacheTimeMs)
|
||||
if err == nil {
|
||||
systemStats.Cpu = twoDecimals(cpuPercent)
|
||||
systemStats.Cpu = twoDecimals(cpuMetrics.Total)
|
||||
systemStats.CpuBreakdown = []float64{
|
||||
twoDecimals(cpuMetrics.User),
|
||||
twoDecimals(cpuMetrics.System),
|
||||
twoDecimals(cpuMetrics.Iowait),
|
||||
twoDecimals(cpuMetrics.Steal),
|
||||
twoDecimals(cpuMetrics.Idle),
|
||||
}
|
||||
} else {
|
||||
slog.Error("Error getting cpu percent", "err", err)
|
||||
slog.Error("Error getting cpu metrics", "err", err)
|
||||
}
|
||||
|
||||
// per-core cpu usage
|
||||
if perCoreUsage, err := getPerCoreCpuUsage(cacheTimeMs); err == nil {
|
||||
systemStats.CpuCoresUsage = perCoreUsage
|
||||
}
|
||||
|
||||
// load average
|
||||
|
||||
229
agent/systemd.go
Normal file
229
agent/systemd.go
Normal file
@@ -0,0 +1,229 @@
|
||||
//go:build linux
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"maps"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-systemd/v22/dbus"
|
||||
"github.com/henrygd/beszel/internal/entities/systemd"
|
||||
)
|
||||
|
||||
var (
|
||||
errNoActiveTime = errors.New("no active time")
|
||||
)
|
||||
|
||||
// systemdManager manages the collection of systemd service statistics.
|
||||
type systemdManager struct {
|
||||
sync.Mutex
|
||||
serviceStatsMap map[string]*systemd.Service
|
||||
isRunning bool
|
||||
hasFreshStats bool
|
||||
}
|
||||
|
||||
// newSystemdManager creates a new systemdManager.
|
||||
func newSystemdManager() (*systemdManager, error) {
|
||||
conn, err := dbus.NewSystemConnectionContext(context.Background())
|
||||
if err != nil {
|
||||
slog.Warn("Error connecting to systemd", "err", err, "ref", "https://beszel.dev/guide/systemd")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
manager := &systemdManager{
|
||||
serviceStatsMap: make(map[string]*systemd.Service),
|
||||
}
|
||||
|
||||
manager.startWorker(conn)
|
||||
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
func (sm *systemdManager) startWorker(conn *dbus.Conn) {
|
||||
if sm.isRunning {
|
||||
return
|
||||
}
|
||||
sm.isRunning = true
|
||||
// prime the service stats map with the current services
|
||||
_ = sm.getServiceStats(conn, true)
|
||||
// update the services every 10 minutes
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Minute * 10)
|
||||
_ = sm.getServiceStats(nil, true)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// getServiceStats collects statistics for all running systemd services.
|
||||
func (sm *systemdManager) getServiceStats(conn *dbus.Conn, refresh bool) []*systemd.Service {
|
||||
// start := time.Now()
|
||||
// defer func() {
|
||||
// slog.Info("systemdManager.getServiceStats", "duration", time.Since(start))
|
||||
// }()
|
||||
|
||||
var services []*systemd.Service
|
||||
var err error
|
||||
|
||||
if !refresh {
|
||||
// return nil
|
||||
sm.Lock()
|
||||
defer sm.Unlock()
|
||||
for _, service := range sm.serviceStatsMap {
|
||||
services = append(services, service)
|
||||
}
|
||||
sm.hasFreshStats = false
|
||||
return services
|
||||
}
|
||||
|
||||
if conn == nil || !conn.Connected() {
|
||||
conn, err = dbus.NewSystemConnectionContext(context.Background())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer conn.Close()
|
||||
}
|
||||
|
||||
units, err := conn.ListUnitsByPatternsContext(context.Background(), []string{"loaded"}, []string{"*.service"})
|
||||
if err != nil {
|
||||
slog.Error("Error listing systemd service units", "err", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, unit := range units {
|
||||
service, err := sm.updateServiceStats(conn, unit)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
services = append(services, service)
|
||||
}
|
||||
sm.hasFreshStats = true
|
||||
return services
|
||||
}
|
||||
|
||||
// updateServiceStats updates the statistics for a single systemd service.
|
||||
func (sm *systemdManager) updateServiceStats(conn *dbus.Conn, unit dbus.UnitStatus) (*systemd.Service, error) {
|
||||
sm.Lock()
|
||||
defer sm.Unlock()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// if service has never been active (no active since time), skip it
|
||||
if activeEnterTsProp, err := conn.GetUnitTypePropertyContext(ctx, unit.Name, "Unit", "ActiveEnterTimestamp"); err == nil {
|
||||
if ts, ok := activeEnterTsProp.Value.Value().(uint64); !ok || ts == 0 || ts == math.MaxUint64 {
|
||||
return nil, errNoActiveTime
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
service, serviceExists := sm.serviceStatsMap[unit.Name]
|
||||
if !serviceExists {
|
||||
service = &systemd.Service{Name: unescapeServiceName(strings.TrimSuffix(unit.Name, ".service"))}
|
||||
sm.serviceStatsMap[unit.Name] = service
|
||||
}
|
||||
|
||||
memPeak := service.MemPeak
|
||||
if memPeakProp, err := conn.GetUnitTypePropertyContext(ctx, unit.Name, "Service", "MemoryPeak"); err == nil {
|
||||
// If memPeak is MaxUint64 the api is saying it's not available
|
||||
if v, ok := memPeakProp.Value.Value().(uint64); ok && v != math.MaxUint64 {
|
||||
memPeak = v
|
||||
}
|
||||
}
|
||||
|
||||
var memUsage uint64
|
||||
if memProp, err := conn.GetUnitTypePropertyContext(ctx, unit.Name, "Service", "MemoryCurrent"); err == nil {
|
||||
// If memUsage is MaxUint64 the api is saying it's not available
|
||||
if v, ok := memProp.Value.Value().(uint64); ok && v != math.MaxUint64 {
|
||||
memUsage = v
|
||||
}
|
||||
}
|
||||
|
||||
service.State = systemd.ParseServiceStatus(unit.ActiveState)
|
||||
service.Sub = systemd.ParseServiceSubState(unit.SubState)
|
||||
|
||||
// some systems always return 0 for mem peak, so we should update the peak if the current usage is greater
|
||||
if memUsage > memPeak {
|
||||
memPeak = memUsage
|
||||
}
|
||||
|
||||
var cpuUsage uint64
|
||||
if cpuProp, err := conn.GetUnitTypePropertyContext(ctx, unit.Name, "Service", "CPUUsageNSec"); err == nil {
|
||||
if v, ok := cpuProp.Value.Value().(uint64); ok {
|
||||
cpuUsage = v
|
||||
}
|
||||
}
|
||||
|
||||
service.Mem = memUsage
|
||||
if memPeak > service.MemPeak {
|
||||
service.MemPeak = memPeak
|
||||
}
|
||||
service.UpdateCPUPercent(cpuUsage)
|
||||
|
||||
return service, nil
|
||||
}
|
||||
|
||||
// getServiceDetails collects extended information for a specific systemd service.
|
||||
func (sm *systemdManager) getServiceDetails(serviceName string) (systemd.ServiceDetails, error) {
|
||||
conn, err := dbus.NewSystemConnectionContext(context.Background())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
unitName := serviceName
|
||||
if !strings.HasSuffix(unitName, ".service") {
|
||||
unitName += ".service"
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
props, err := conn.GetUnitPropertiesContext(ctx, unitName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Start with all unit properties
|
||||
details := make(systemd.ServiceDetails)
|
||||
maps.Copy(details, props)
|
||||
|
||||
// // Add service-specific properties
|
||||
servicePropNames := []string{
|
||||
"MainPID", "ExecMainPID", "TasksCurrent", "TasksMax",
|
||||
"MemoryCurrent", "MemoryPeak", "MemoryLimit", "CPUUsageNSec",
|
||||
"NRestarts", "ExecMainStartTimestampRealtime", "Result",
|
||||
}
|
||||
|
||||
for _, propName := range servicePropNames {
|
||||
if variant, err := conn.GetUnitTypePropertyContext(ctx, unitName, "Service", propName); err == nil {
|
||||
value := variant.Value.Value()
|
||||
// Check if the value is MaxUint64, which indicates unlimited/infinite
|
||||
if uint64Value, ok := value.(uint64); ok && uint64Value == math.MaxUint64 {
|
||||
// Set to nil to indicate unlimited - frontend will handle this appropriately
|
||||
details[propName] = nil
|
||||
} else {
|
||||
details[propName] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return details, nil
|
||||
}
|
||||
|
||||
// unescapeServiceName unescapes systemd service names that contain C-style escape sequences like \x2d
|
||||
func unescapeServiceName(name string) string {
|
||||
if !strings.Contains(name, "\\x") {
|
||||
return name
|
||||
}
|
||||
unescaped, err := strconv.Unquote("\"" + name + "\"")
|
||||
if err != nil {
|
||||
return name
|
||||
}
|
||||
return unescaped
|
||||
}
|
||||
28
agent/systemd_nonlinux.go
Normal file
28
agent/systemd_nonlinux.go
Normal file
@@ -0,0 +1,28 @@
|
||||
//go:build !linux
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/systemd"
|
||||
)
|
||||
|
||||
// systemdManager manages the collection of systemd service statistics.
|
||||
type systemdManager struct {
|
||||
hasFreshStats bool
|
||||
}
|
||||
|
||||
// newSystemdManager creates a new systemdManager.
|
||||
func newSystemdManager() (*systemdManager, error) {
|
||||
return &systemdManager{}, nil
|
||||
}
|
||||
|
||||
// getServiceStats returns nil for non-linux systems.
|
||||
func (sm *systemdManager) getServiceStats(conn any, refresh bool) []*systemd.Service {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sm *systemdManager) getServiceDetails(string) (systemd.ServiceDetails, error) {
|
||||
return nil, errors.New("systemd manager unavailable")
|
||||
}
|
||||
53
agent/systemd_nonlinux_test.go
Normal file
53
agent/systemd_nonlinux_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
//go:build !linux && testing
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewSystemdManager(t *testing.T) {
|
||||
manager, err := newSystemdManager()
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, manager)
|
||||
}
|
||||
|
||||
func TestSystemdManagerGetServiceStats(t *testing.T) {
|
||||
manager, err := newSystemdManager()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test with refresh = true
|
||||
result := manager.getServiceStats(true)
|
||||
assert.Nil(t, result)
|
||||
|
||||
// Test with refresh = false
|
||||
result = manager.getServiceStats(false)
|
||||
assert.Nil(t, result)
|
||||
}
|
||||
|
||||
func TestSystemdManagerGetServiceDetails(t *testing.T) {
|
||||
manager, err := newSystemdManager()
|
||||
assert.NoError(t, err)
|
||||
|
||||
result, err := manager.getServiceDetails("any-service")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "systemd manager unavailable", err.Error())
|
||||
assert.Nil(t, result)
|
||||
|
||||
// Test with empty service name
|
||||
result, err = manager.getServiceDetails("")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "systemd manager unavailable", err.Error())
|
||||
assert.Nil(t, result)
|
||||
}
|
||||
|
||||
func TestSystemdManagerFields(t *testing.T) {
|
||||
manager, err := newSystemdManager()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// The non-linux manager should be a simple struct with no special fields
|
||||
// We can't test private fields directly, but we can test the methods work
|
||||
assert.NotNil(t, manager)
|
||||
}
|
||||
48
agent/systemd_test.go
Normal file
48
agent/systemd_test.go
Normal file
@@ -0,0 +1,48 @@
|
||||
//go:build linux && testing
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUnescapeServiceName(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"nginx.service", "nginx.service"}, // No escaping needed
|
||||
{"test\\x2dwith\\x2ddashes.service", "test-with-dashes.service"}, // \x2d is dash
|
||||
{"service\\x20with\\x20spaces.service", "service with spaces.service"}, // \x20 is space
|
||||
{"mixed\\x2dand\\x2dnormal", "mixed-and-normal"}, // Mixed escaped and normal
|
||||
{"no-escape-here", "no-escape-here"}, // No escape sequences
|
||||
{"", ""}, // Empty string
|
||||
{"\\x2d\\x2d", "--"}, // Multiple escapes
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.input, func(t *testing.T) {
|
||||
result := unescapeServiceName(test.input)
|
||||
assert.Equal(t, test.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnescapeServiceNameInvalid(t *testing.T) {
|
||||
// Test invalid escape sequences - should return original string
|
||||
invalidInputs := []string{
|
||||
"invalid\\x", // Incomplete escape
|
||||
"invalid\\xZZ", // Invalid hex
|
||||
"invalid\\x2", // Incomplete hex
|
||||
"invalid\\xyz", // Not a valid escape
|
||||
}
|
||||
|
||||
for _, input := range invalidInputs {
|
||||
t.Run(input, func(t *testing.T) {
|
||||
result := unescapeServiceName(input)
|
||||
assert.Equal(t, input, result, "Invalid escape sequences should return original string")
|
||||
})
|
||||
}
|
||||
}
|
||||
272
agent/test-data/smart/nvme0.json
Normal file
272
agent/test-data/smart/nvme0.json
Normal file
@@ -0,0 +1,272 @@
|
||||
{
|
||||
"json_format_version": [
|
||||
1,
|
||||
0
|
||||
],
|
||||
"smartctl": {
|
||||
"version": [
|
||||
7,
|
||||
5
|
||||
],
|
||||
"pre_release": false,
|
||||
"svn_revision": "5714",
|
||||
"platform_info": "x86_64-linux-6.17.1-2-cachyos",
|
||||
"build_info": "(local build)",
|
||||
"argv": [
|
||||
"smartctl",
|
||||
"-aj",
|
||||
"/dev/nvme0"
|
||||
],
|
||||
"exit_status": 0
|
||||
},
|
||||
"local_time": {
|
||||
"time_t": 1761507494,
|
||||
"asctime": "Sun Oct 26 15:38:14 2025 EDT"
|
||||
},
|
||||
"device": {
|
||||
"name": "/dev/nvme0",
|
||||
"info_name": "/dev/nvme0",
|
||||
"type": "nvme",
|
||||
"protocol": "NVMe"
|
||||
},
|
||||
"model_name": "PELADN 512GB",
|
||||
"serial_number": "2024031600129",
|
||||
"firmware_version": "VC2S038E",
|
||||
"nvme_pci_vendor": {
|
||||
"id": 4332,
|
||||
"subsystem_id": 4332
|
||||
},
|
||||
"nvme_ieee_oui_identifier": 57420,
|
||||
"nvme_controller_id": 1,
|
||||
"nvme_version": {
|
||||
"string": "1.4",
|
||||
"value": 66560
|
||||
},
|
||||
"nvme_number_of_namespaces": 1,
|
||||
"nvme_namespaces": [
|
||||
{
|
||||
"id": 1,
|
||||
"size": {
|
||||
"blocks": 1000215216,
|
||||
"bytes": 512110190592
|
||||
},
|
||||
"capacity": {
|
||||
"blocks": 1000215216,
|
||||
"bytes": 512110190592
|
||||
},
|
||||
"utilization": {
|
||||
"blocks": 1000215216,
|
||||
"bytes": 512110190592
|
||||
},
|
||||
"formatted_lba_size": 512,
|
||||
"eui64": {
|
||||
"oui": 57420,
|
||||
"ext_id": 112094110470
|
||||
},
|
||||
"features": {
|
||||
"value": 0,
|
||||
"thin_provisioning": false,
|
||||
"na_fields": false,
|
||||
"dealloc_or_unwritten_block_error": false,
|
||||
"uid_reuse": false,
|
||||
"np_fields": false,
|
||||
"other": 0
|
||||
},
|
||||
"lba_formats": [
|
||||
{
|
||||
"formatted": true,
|
||||
"data_bytes": 512,
|
||||
"metadata_bytes": 0,
|
||||
"relative_performance": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"user_capacity": {
|
||||
"blocks": 1000215216,
|
||||
"bytes": 512110190592
|
||||
},
|
||||
"logical_block_size": 512,
|
||||
"smart_support": {
|
||||
"available": true,
|
||||
"enabled": true
|
||||
},
|
||||
"nvme_firmware_update_capabilities": {
|
||||
"value": 2,
|
||||
"slots": 1,
|
||||
"first_slot_is_read_only": false,
|
||||
"activiation_without_reset": false,
|
||||
"multiple_update_detection": false,
|
||||
"other": 0
|
||||
},
|
||||
"nvme_optional_admin_commands": {
|
||||
"value": 23,
|
||||
"security_send_receive": true,
|
||||
"format_nvm": true,
|
||||
"firmware_download": true,
|
||||
"namespace_management": false,
|
||||
"self_test": true,
|
||||
"directives": false,
|
||||
"mi_send_receive": false,
|
||||
"virtualization_management": false,
|
||||
"doorbell_buffer_config": false,
|
||||
"get_lba_status": false,
|
||||
"command_and_feature_lockdown": false,
|
||||
"other": 0
|
||||
},
|
||||
"nvme_optional_nvm_commands": {
|
||||
"value": 94,
|
||||
"compare": false,
|
||||
"write_uncorrectable": true,
|
||||
"dataset_management": true,
|
||||
"write_zeroes": true,
|
||||
"save_select_feature_nonzero": true,
|
||||
"reservations": false,
|
||||
"timestamp": true,
|
||||
"verify": false,
|
||||
"copy": false,
|
||||
"other": 0
|
||||
},
|
||||
"nvme_log_page_attributes": {
|
||||
"value": 2,
|
||||
"smart_health_per_namespace": false,
|
||||
"commands_effects_log": true,
|
||||
"extended_get_log_page_cmd": false,
|
||||
"telemetry_log": false,
|
||||
"persistent_event_log": false,
|
||||
"supported_log_pages_log": false,
|
||||
"telemetry_data_area_4": false,
|
||||
"other": 0
|
||||
},
|
||||
"nvme_maximum_data_transfer_pages": 32,
|
||||
"nvme_composite_temperature_threshold": {
|
||||
"warning": 100,
|
||||
"critical": 110
|
||||
},
|
||||
"temperature": {
|
||||
"op_limit_max": 100,
|
||||
"critical_limit_max": 110,
|
||||
"current": 61
|
||||
},
|
||||
"nvme_power_states": [
|
||||
{
|
||||
"non_operational_state": false,
|
||||
"relative_read_latency": 0,
|
||||
"relative_read_throughput": 0,
|
||||
"relative_write_latency": 0,
|
||||
"relative_write_throughput": 0,
|
||||
"entry_latency_us": 230000,
|
||||
"exit_latency_us": 50000,
|
||||
"max_power": {
|
||||
"value": 800,
|
||||
"scale": 2,
|
||||
"units_per_watt": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"non_operational_state": false,
|
||||
"relative_read_latency": 1,
|
||||
"relative_read_throughput": 1,
|
||||
"relative_write_latency": 1,
|
||||
"relative_write_throughput": 1,
|
||||
"entry_latency_us": 4000,
|
||||
"exit_latency_us": 50000,
|
||||
"max_power": {
|
||||
"value": 400,
|
||||
"scale": 2,
|
||||
"units_per_watt": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"non_operational_state": false,
|
||||
"relative_read_latency": 2,
|
||||
"relative_read_throughput": 2,
|
||||
"relative_write_latency": 2,
|
||||
"relative_write_throughput": 2,
|
||||
"entry_latency_us": 4000,
|
||||
"exit_latency_us": 250000,
|
||||
"max_power": {
|
||||
"value": 300,
|
||||
"scale": 2,
|
||||
"units_per_watt": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"non_operational_state": true,
|
||||
"relative_read_latency": 3,
|
||||
"relative_read_throughput": 3,
|
||||
"relative_write_latency": 3,
|
||||
"relative_write_throughput": 3,
|
||||
"entry_latency_us": 5000,
|
||||
"exit_latency_us": 10000,
|
||||
"max_power": {
|
||||
"value": 300,
|
||||
"scale": 1,
|
||||
"units_per_watt": 10000
|
||||
}
|
||||
},
|
||||
{
|
||||
"non_operational_state": true,
|
||||
"relative_read_latency": 4,
|
||||
"relative_read_throughput": 4,
|
||||
"relative_write_latency": 4,
|
||||
"relative_write_throughput": 4,
|
||||
"entry_latency_us": 54000,
|
||||
"exit_latency_us": 45000,
|
||||
"max_power": {
|
||||
"value": 50,
|
||||
"scale": 1,
|
||||
"units_per_watt": 10000
|
||||
}
|
||||
}
|
||||
],
|
||||
"smart_status": {
|
||||
"passed": true,
|
||||
"nvme": {
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"nvme_smart_health_information_log": {
|
||||
"nsid": -1,
|
||||
"critical_warning": 0,
|
||||
"temperature": 61,
|
||||
"available_spare": 100,
|
||||
"available_spare_threshold": 32,
|
||||
"percentage_used": 0,
|
||||
"data_units_read": 6573104,
|
||||
"data_units_written": 16040567,
|
||||
"host_reads": 63241130,
|
||||
"host_writes": 253050006,
|
||||
"controller_busy_time": 0,
|
||||
"power_cycles": 430,
|
||||
"power_on_hours": 4399,
|
||||
"unsafe_shutdowns": 44,
|
||||
"media_errors": 0,
|
||||
"num_err_log_entries": 0,
|
||||
"warning_temp_time": 0,
|
||||
"critical_comp_time": 0
|
||||
},
|
||||
"spare_available": {
|
||||
"current_percent": 100,
|
||||
"threshold_percent": 32
|
||||
},
|
||||
"endurance_used": {
|
||||
"current_percent": 0
|
||||
},
|
||||
"power_cycle_count": 430,
|
||||
"power_on_time": {
|
||||
"hours": 4399
|
||||
},
|
||||
"nvme_error_information_log": {
|
||||
"size": 8,
|
||||
"read": 8,
|
||||
"unread": 0
|
||||
},
|
||||
"nvme_self_test_log": {
|
||||
"nsid": -1,
|
||||
"current_self_test_operation": {
|
||||
"value": 0,
|
||||
"string": "No self-test in progress"
|
||||
}
|
||||
}
|
||||
}
|
||||
36
agent/test-data/smart/scan.json
Normal file
36
agent/test-data/smart/scan.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"json_format_version": [
|
||||
1,
|
||||
0
|
||||
],
|
||||
"smartctl": {
|
||||
"version": [
|
||||
7,
|
||||
5
|
||||
],
|
||||
"pre_release": false,
|
||||
"svn_revision": "5714",
|
||||
"platform_info": "x86_64-linux-6.17.1-2-cachyos",
|
||||
"build_info": "(local build)",
|
||||
"argv": [
|
||||
"smartctl",
|
||||
"--scan",
|
||||
"-j"
|
||||
],
|
||||
"exit_status": 0
|
||||
},
|
||||
"devices": [
|
||||
{
|
||||
"name": "/dev/sda",
|
||||
"info_name": "/dev/sda [SAT]",
|
||||
"type": "sat",
|
||||
"protocol": "ATA"
|
||||
},
|
||||
{
|
||||
"name": "/dev/nvme0",
|
||||
"info_name": "/dev/nvme0",
|
||||
"type": "nvme",
|
||||
"protocol": "NVMe"
|
||||
}
|
||||
]
|
||||
}
|
||||
125
agent/test-data/smart/scsi.json
Normal file
125
agent/test-data/smart/scsi.json
Normal file
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"json_format_version": [
|
||||
1,
|
||||
0
|
||||
],
|
||||
"smartctl": {
|
||||
"version": [
|
||||
7,
|
||||
3
|
||||
],
|
||||
"svn_revision": "5338",
|
||||
"platform_info": "x86_64-linux-6.12.43+deb12-amd64",
|
||||
"build_info": "(local build)",
|
||||
"argv": [
|
||||
"smartctl",
|
||||
"-aj",
|
||||
"/dev/sde"
|
||||
],
|
||||
"exit_status": 0
|
||||
},
|
||||
"local_time": {
|
||||
"time_t": 1761502142,
|
||||
"asctime": "Sun Oct 21 21:09:02 2025 MSK"
|
||||
},
|
||||
"device": {
|
||||
"name": "/dev/sde",
|
||||
"info_name": "/dev/sde",
|
||||
"type": "scsi",
|
||||
"protocol": "SCSI"
|
||||
},
|
||||
"scsi_vendor": "YADRO",
|
||||
"scsi_product": "WUH721414AL4204",
|
||||
"scsi_model_name": "YADRO WUH721414AL4204",
|
||||
"scsi_revision": "C240",
|
||||
"scsi_version": "SPC-4",
|
||||
"user_capacity": {
|
||||
"blocks": 3418095616,
|
||||
"bytes": 14000519643136
|
||||
},
|
||||
"logical_block_size": 4096,
|
||||
"scsi_lb_provisioning": {
|
||||
"name": "fully provisioned",
|
||||
"value": 0,
|
||||
"management_enabled": {
|
||||
"name": "LBPME",
|
||||
"value": 0
|
||||
},
|
||||
"read_zeros": {
|
||||
"name": "LBPRZ",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"rotation_rate": 7200,
|
||||
"form_factor": {
|
||||
"scsi_value": 2,
|
||||
"name": "3.5 inches"
|
||||
},
|
||||
"logical_unit_id": "0x5000cca29063dc00",
|
||||
"serial_number": "9YHSDH9B",
|
||||
"device_type": {
|
||||
"scsi_terminology": "Peripheral Device Type [PDT]",
|
||||
"scsi_value": 0,
|
||||
"name": "disk"
|
||||
},
|
||||
"scsi_transport_protocol": {
|
||||
"name": "SAS (SPL-4)",
|
||||
"value": 6
|
||||
},
|
||||
"smart_support": {
|
||||
"available": true,
|
||||
"enabled": true
|
||||
},
|
||||
"temperature_warning": {
|
||||
"enabled": true
|
||||
},
|
||||
"smart_status": {
|
||||
"passed": true
|
||||
},
|
||||
"temperature": {
|
||||
"current": 34,
|
||||
"drive_trip": 85
|
||||
},
|
||||
"power_on_time": {
|
||||
"hours": 458,
|
||||
"minutes": 25
|
||||
},
|
||||
"scsi_start_stop_cycle_counter": {
|
||||
"year_of_manufacture": "2022",
|
||||
"week_of_manufacture": "41",
|
||||
"specified_cycle_count_over_device_lifetime": 50000,
|
||||
"accumulated_start_stop_cycles": 2,
|
||||
"specified_load_unload_count_over_device_lifetime": 600000,
|
||||
"accumulated_load_unload_cycles": 418
|
||||
},
|
||||
"scsi_grown_defect_list": 0,
|
||||
"scsi_error_counter_log": {
|
||||
"read": {
|
||||
"errors_corrected_by_eccfast": 0,
|
||||
"errors_corrected_by_eccdelayed": 0,
|
||||
"errors_corrected_by_rereads_rewrites": 0,
|
||||
"total_errors_corrected": 0,
|
||||
"correction_algorithm_invocations": 346,
|
||||
"gigabytes_processed": "3,641",
|
||||
"total_uncorrected_errors": 0
|
||||
},
|
||||
"write": {
|
||||
"errors_corrected_by_eccfast": 0,
|
||||
"errors_corrected_by_eccdelayed": 0,
|
||||
"errors_corrected_by_rereads_rewrites": 0,
|
||||
"total_errors_corrected": 0,
|
||||
"correction_algorithm_invocations": 4052,
|
||||
"gigabytes_processed": "2124,590",
|
||||
"total_uncorrected_errors": 0
|
||||
},
|
||||
"verify": {
|
||||
"errors_corrected_by_eccfast": 0,
|
||||
"errors_corrected_by_eccdelayed": 0,
|
||||
"errors_corrected_by_rereads_rewrites": 0,
|
||||
"total_errors_corrected": 0,
|
||||
"correction_algorithm_invocations": 223,
|
||||
"gigabytes_processed": "0,000",
|
||||
"total_uncorrected_errors": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
1013
agent/test-data/smart/sda.json
Normal file
1013
agent/test-data/smart/sda.json
Normal file
File diff suppressed because it is too large
Load Diff
130
agent/tools/fetchsmartctl/main.go
Normal file
130
agent/tools/fetchsmartctl/main.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Download smartctl.exe from the given URL and save it to the given destination.
|
||||
// This is used to embed smartctl.exe in the Windows build.
|
||||
|
||||
func main() {
|
||||
url := flag.String("url", "", "URL to download smartctl.exe from (required)")
|
||||
out := flag.String("out", "", "Destination path for smartctl.exe (required)")
|
||||
sha := flag.String("sha", "", "Optional SHA1/SHA256 checksum for integrity validation")
|
||||
force := flag.Bool("force", false, "Force re-download even if destination exists")
|
||||
flag.Parse()
|
||||
|
||||
if *url == "" || *out == "" {
|
||||
fatalf("-url and -out are required")
|
||||
}
|
||||
|
||||
if !*force {
|
||||
if info, err := os.Stat(*out); err == nil && info.Size() > 0 {
|
||||
fmt.Println("smartctl.exe already present, skipping download")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := downloadFile(*url, *out, *sha); err != nil {
|
||||
fatalf("download failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func downloadFile(url, dest, shaHex string) error {
|
||||
// Prepare destination
|
||||
if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil {
|
||||
return fmt.Errorf("create dir: %w", err)
|
||||
}
|
||||
|
||||
// HTTP client
|
||||
client := &http.Client{Timeout: 60 * time.Second}
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("new request: %w", err)
|
||||
}
|
||||
req.Header.Set("User-Agent", "beszel-fetchsmartctl/1.0")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("http get: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("unexpected HTTP status: %s", resp.Status)
|
||||
}
|
||||
|
||||
tmp := dest + ".tmp"
|
||||
f, err := os.OpenFile(tmp, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open tmp: %w", err)
|
||||
}
|
||||
|
||||
// Determine hash algorithm based on length (SHA1=40, SHA256=64)
|
||||
var hasher hash.Hash
|
||||
if shaHex := strings.TrimSpace(shaHex); shaHex != "" {
|
||||
cleanSha := strings.ToLower(strings.ReplaceAll(shaHex, " ", ""))
|
||||
switch len(cleanSha) {
|
||||
case 40:
|
||||
hasher = sha1.New()
|
||||
case 64:
|
||||
hasher = sha256.New()
|
||||
default:
|
||||
f.Close()
|
||||
os.Remove(tmp)
|
||||
return fmt.Errorf("unsupported hash length: %d (expected 40 for SHA1 or 64 for SHA256)", len(cleanSha))
|
||||
}
|
||||
}
|
||||
|
||||
var mw io.Writer = f
|
||||
if hasher != nil {
|
||||
mw = io.MultiWriter(f, hasher)
|
||||
}
|
||||
if _, err := io.Copy(mw, resp.Body); err != nil {
|
||||
f.Close()
|
||||
os.Remove(tmp)
|
||||
return fmt.Errorf("write tmp: %w", err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
os.Remove(tmp)
|
||||
return fmt.Errorf("close tmp: %w", err)
|
||||
}
|
||||
|
||||
if hasher != nil && shaHex != "" {
|
||||
cleanSha := strings.ToLower(strings.ReplaceAll(strings.TrimSpace(shaHex), " ", ""))
|
||||
got := strings.ToLower(hex.EncodeToString(hasher.Sum(nil)))
|
||||
if got != cleanSha {
|
||||
os.Remove(tmp)
|
||||
return fmt.Errorf("hash mismatch: got %s want %s", got, cleanSha)
|
||||
}
|
||||
}
|
||||
|
||||
// Make executable and move into place
|
||||
if err := os.Chmod(tmp, 0o755); err != nil {
|
||||
os.Remove(tmp)
|
||||
return fmt.Errorf("chmod: %w", err)
|
||||
}
|
||||
if err := os.Rename(tmp, dest); err != nil {
|
||||
os.Remove(tmp)
|
||||
return fmt.Errorf("rename: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("smartctl.exe downloaded to", dest)
|
||||
return nil
|
||||
}
|
||||
|
||||
func fatalf(format string, a ...any) {
|
||||
fmt.Fprintf(os.Stderr, format+"\n", a...)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import "github.com/blang/semver"
|
||||
|
||||
const (
|
||||
// Version is the current version of the application.
|
||||
Version = "0.14.1"
|
||||
Version = "0.16.0"
|
||||
// AppName is the name of the application.
|
||||
AppName = "beszel"
|
||||
)
|
||||
|
||||
49
go.mod
49
go.mod
@@ -1,27 +1,25 @@
|
||||
module github.com/henrygd/beszel
|
||||
|
||||
go 1.25.1
|
||||
|
||||
// lock shoutrrr to specific version to allow review before updating
|
||||
replace github.com/nicholas-fedor/shoutrrr => github.com/nicholas-fedor/shoutrrr v0.9.1
|
||||
go 1.25.3
|
||||
|
||||
require (
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/coreos/go-systemd/v22 v22.6.0
|
||||
github.com/distatus/battery v0.11.0
|
||||
github.com/fxamacker/cbor/v2 v2.9.0
|
||||
github.com/gliderlabs/ssh v0.3.8
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/lxzan/gws v1.8.9
|
||||
github.com/nicholas-fedor/shoutrrr v0.10.0
|
||||
github.com/nicholas-fedor/shoutrrr v0.12.0
|
||||
github.com/pocketbase/dbx v1.11.0
|
||||
github.com/pocketbase/pocketbase v0.30.1
|
||||
github.com/shirou/gopsutil/v4 v4.25.9
|
||||
github.com/pocketbase/pocketbase v0.32.0
|
||||
github.com/shirou/gopsutil/v4 v4.25.10
|
||||
github.com/spf13/cast v1.10.0
|
||||
github.com/spf13/cobra v1.10.1
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/stretchr/testify v1.11.1
|
||||
golang.org/x/crypto v0.42.0
|
||||
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9
|
||||
golang.org/x/crypto v0.44.0
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -33,37 +31,38 @@ require (
|
||||
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/ebitengine/purego v0.9.0 // indirect
|
||||
github.com/ebitengine/purego v0.9.1 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.11 // indirect
|
||||
github.com/ganigeorgiev/fexpr v0.5.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.9.1 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect
|
||||
github.com/klauspost/compress v1.18.1 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.16 // indirect
|
||||
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.31.0 // indirect
|
||||
golang.org/x/net v0.44.0 // indirect
|
||||
golang.org/x/oauth2 v0.31.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.36.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
golang.org/x/image v0.33.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.33.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
howett.net/plist v1.0.1 // indirect
|
||||
modernc.org/libc v1.66.3 // indirect
|
||||
modernc.org/libc v1.66.10 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.39.0 // indirect
|
||||
modernc.org/sqlite v1.40.0 // indirect
|
||||
)
|
||||
|
||||
112
go.sum
112
go.sum
@@ -9,6 +9,8 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo=
|
||||
github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
@@ -23,16 +25,16 @@ github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCO
|
||||
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.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k=
|
||||
github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
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/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=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
|
||||
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/ganigeorgiev/fexpr v0.5.0 h1:XA9JxtTE/Xm+g/JFI6RfZEHSiQlk+1glLvRK1Lpv/Tk=
|
||||
github.com/ganigeorgiev/fexpr v0.5.0/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
@@ -49,13 +51,15 @@ github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtS
|
||||
github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/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-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY=
|
||||
github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U=
|
||||
github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d h1:KJIErDwbSHjnp/SGzE5ed8Aol7JsKiI5X7yWKAtzhM0=
|
||||
github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U=
|
||||
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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
@@ -63,26 +67,26 @@ 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.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
|
||||
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
|
||||
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-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg=
|
||||
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k=
|
||||
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
github.com/lxzan/gws v1.8.9 h1:VU3SGUeWlQrEwfUSfokcZep8mdg/BrUF+y73YYshdBM=
|
||||
github.com/lxzan/gws v1.8.9/go.mod h1:d9yHaR1eDTBHagQC6KY7ycUOaz5KWeqQtP3xu7aMK8Y=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/nicholas-fedor/shoutrrr v0.9.1 h1:SEBhM6P1favzILO0f55CY3P9JwvM9RZ7B1ZMCl+Injs=
|
||||
github.com/nicholas-fedor/shoutrrr v0.9.1/go.mod h1:khue5m8LYyMzdPWuJxDTJeT89l9gjwjA+a+r0e8qxxk=
|
||||
github.com/onsi/ginkgo/v2 v2.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw=
|
||||
github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE=
|
||||
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.12.0 h1:8mwJdfU+uBEybSymwQJMGl/grG7lvVUKbVSNxn3XvUI=
|
||||
github.com/nicholas-fedor/shoutrrr v0.12.0/go.mod h1:WYiRalR4C43Qmd2zhPWGIFIxu633NB1hDM6Ap/DQcsA=
|
||||
github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns=
|
||||
github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
|
||||
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
|
||||
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -90,8 +94,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.11.0 h1:LpZezioMfT3K4tLrqA55wWFw1EtH1pM4tzSVa7kgszU=
|
||||
github.com/pocketbase/dbx v1.11.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
|
||||
github.com/pocketbase/pocketbase v0.30.1 h1:8lgfhH+HiSw1PyKVMq2sjtC4ZNvda2f/envTAzWMLOA=
|
||||
github.com/pocketbase/pocketbase v0.30.1/go.mod h1:sUI+uekXZam5Wa0eh+DClc+HieKMCeqsHA7Ydd9vwyE=
|
||||
github.com/pocketbase/pocketbase v0.32.0 h1:2DskUUO06sjDeXzmi9NlU/xIa5OknuHAnDQk+ncsfvc=
|
||||
github.com/pocketbase/pocketbase v0.32.0/go.mod h1:prwdJKQYTums5Nhy5eeqFR5qV2AIZlS8o2JD0k6qn5E=
|
||||
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=
|
||||
@@ -99,8 +103,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.25.9 h1:JImNpf6gCVhKgZhtaAHJ0serfFGtlfIlSC08eaKdTrU=
|
||||
github.com/shirou/gopsutil/v4 v4.25.9/go.mod h1:gxIxoC+7nQRwUl/xNhutXlD8lq+jxTgpIkEf3rADHL8=
|
||||
github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA=
|
||||
github.com/shirou/gopsutil/v4 v4.25.10/go.mod h1:+kSwyC8DRUD9XXEHCAFjK+0nuArFJM0lva+StQAcskM=
|
||||
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.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
|
||||
@@ -112,57 +116,55 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
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=
|
||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
|
||||
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
|
||||
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
|
||||
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
|
||||
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/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
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.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 h1:TQwNpfvNkxAVlItJf6Cr5JTsVZoC/Sj7K3OZv2Pc14A=
|
||||
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
|
||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY=
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.31.0 h1:mLChjE2MV6g1S7oqbXC0/UcKijjm5fnJLUYKIYrLESA=
|
||||
golang.org/x/image v0.31.0/go.mod h1:R9ec5Lcp96v9FTF+ajwaH3uGxPH4fKfHHAVbUILxghA=
|
||||
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
||||
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
||||
golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ=
|
||||
golang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
|
||||
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||
golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo=
|
||||
golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
|
||||
golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
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.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
|
||||
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
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.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
|
||||
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/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-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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=
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
@@ -179,8 +181,6 @@ modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ=
|
||||
modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8=
|
||||
modernc.org/libc v1.66.10 h1:yZkb3YeLx4oynyR+iUsXsybsX4Ubx7MQlSYEw4yj59A=
|
||||
modernc.org/libc v1.66.10/go.mod h1:8vGSEwvoUoltr4dlywvHqjtAqHBaw0j1jI7iFBTAr2I=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
@@ -191,8 +191,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.39.0 h1:6bwu9Ooim0yVYA7IZn9demiQk/Ejp0BtTjBWFLymSeY=
|
||||
modernc.org/sqlite v1.39.0/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E=
|
||||
modernc.org/sqlite v1.40.0 h1:bNWEDlYhNPAUdUdBzjAvn8icAs/2gaKlj4vM+tQ6KdQ=
|
||||
modernc.org/sqlite v1.40.0/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE=
|
||||
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=
|
||||
|
||||
@@ -40,13 +40,18 @@ type UserNotificationSettings struct {
|
||||
}
|
||||
|
||||
type SystemAlertStats struct {
|
||||
Cpu float64 `json:"cpu"`
|
||||
Mem float64 `json:"mp"`
|
||||
Disk float64 `json:"dp"`
|
||||
NetSent float64 `json:"ns"`
|
||||
NetRecv float64 `json:"nr"`
|
||||
Temperatures map[string]float32 `json:"t"`
|
||||
LoadAvg [3]float64 `json:"la"`
|
||||
Cpu float64 `json:"cpu"`
|
||||
Mem float64 `json:"mp"`
|
||||
Disk float64 `json:"dp"`
|
||||
NetSent float64 `json:"ns"`
|
||||
NetRecv float64 `json:"nr"`
|
||||
GPU map[string]SystemAlertGPUData `json:"g"`
|
||||
Temperatures map[string]float32 `json:"t"`
|
||||
LoadAvg [3]float64 `json:"la"`
|
||||
}
|
||||
|
||||
type SystemAlertGPUData struct {
|
||||
Usage float64 `json:"u"`
|
||||
}
|
||||
|
||||
type SystemAlertData struct {
|
||||
|
||||
@@ -161,19 +161,14 @@ func (am *AlertManager) sendStatusAlert(alertStatus string, systemName string, a
|
||||
title := fmt.Sprintf("Connection to %s is %s %v", systemName, alertStatus, emoji)
|
||||
message := strings.TrimSuffix(title, emoji)
|
||||
|
||||
// if errs := am.hub.ExpandRecord(alertRecord, []string{"user"}, nil); len(errs) > 0 {
|
||||
// return errs["user"]
|
||||
// }
|
||||
// user := alertRecord.ExpandedOne("user")
|
||||
// if user == nil {
|
||||
// return nil
|
||||
// }
|
||||
// Get system ID for the link
|
||||
systemID := alertRecord.GetString("system")
|
||||
|
||||
return am.SendAlert(AlertMessageData{
|
||||
UserID: alertRecord.GetString("user"),
|
||||
Title: title,
|
||||
Message: message,
|
||||
Link: am.hub.MakeLink("system", systemName),
|
||||
Link: am.hub.MakeLink("system", systemID),
|
||||
LinkText: "View " + systemName,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -64,6 +64,8 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *syst
|
||||
case "LoadAvg15":
|
||||
val = data.Info.LoadAvg[2]
|
||||
unit = ""
|
||||
case "GPU":
|
||||
val = data.Info.GpuPct
|
||||
}
|
||||
|
||||
triggered := alertRecord.GetBool("triggered")
|
||||
@@ -206,6 +208,17 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *syst
|
||||
alert.val += stats.LoadAvg[1]
|
||||
case "LoadAvg15":
|
||||
alert.val += stats.LoadAvg[2]
|
||||
case "GPU":
|
||||
if len(stats.GPU) == 0 {
|
||||
continue
|
||||
}
|
||||
maxUsage := 0.0
|
||||
for _, gpu := range stats.GPU {
|
||||
if gpu.Usage > maxUsage {
|
||||
maxUsage = gpu.Usage
|
||||
}
|
||||
}
|
||||
alert.val += maxUsage
|
||||
default:
|
||||
continue
|
||||
}
|
||||
@@ -268,9 +281,9 @@ func (am *AlertManager) sendSystemAlert(alert SystemAlertData) {
|
||||
alert.name = after + "m Load"
|
||||
}
|
||||
|
||||
// make title alert name lowercase if not CPU
|
||||
// make title alert name lowercase if not CPU or GPU
|
||||
titleAlertName := alert.name
|
||||
if titleAlertName != "CPU" {
|
||||
if titleAlertName != "CPU" && titleAlertName != "GPU" {
|
||||
titleAlertName = strings.ToLower(titleAlertName)
|
||||
}
|
||||
|
||||
@@ -298,7 +311,7 @@ func (am *AlertManager) sendSystemAlert(alert SystemAlertData) {
|
||||
UserID: alert.alertRecord.GetString("user"),
|
||||
Title: subject,
|
||||
Message: body,
|
||||
Link: am.hub.MakeLink("system", systemName),
|
||||
Link: am.hub.MakeLink("system", alert.systemRecord.Id),
|
||||
LinkText: "View " + systemName,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package common
|
||||
import (
|
||||
"github.com/henrygd/beszel/internal/entities/smart"
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
"github.com/henrygd/beszel/internal/entities/systemd"
|
||||
)
|
||||
|
||||
type WebSocketAction = uint8
|
||||
@@ -18,6 +19,8 @@ const (
|
||||
GetContainerInfo
|
||||
// Request SMART data from agent
|
||||
GetSmartData
|
||||
// Request detailed systemd service info from agent
|
||||
GetSystemdInfo
|
||||
// Add new actions here...
|
||||
)
|
||||
|
||||
@@ -36,6 +39,7 @@ type AgentResponse struct {
|
||||
Error string `cbor:"3,keyasint,omitempty,omitzero"`
|
||||
String *string `cbor:"4,keyasint,omitempty,omitzero"`
|
||||
SmartData map[string]smart.SmartData `cbor:"5,keyasint,omitempty,omitzero"`
|
||||
ServiceInfo systemd.ServiceDetails `cbor:"6,keyasint,omitempty,omitzero"`
|
||||
// Logs *LogsPayload `cbor:"4,keyasint,omitempty,omitzero"`
|
||||
// RawBytes []byte `cbor:"4,keyasint,omitempty,omitzero"`
|
||||
}
|
||||
@@ -65,3 +69,7 @@ type ContainerLogsRequest struct {
|
||||
type ContainerInfoRequest struct {
|
||||
ContainerID string `cbor:"0,keyasint"`
|
||||
}
|
||||
|
||||
type SystemdInfoRequest struct {
|
||||
ServiceName string `cbor:"0,keyasint"`
|
||||
}
|
||||
|
||||
28
internal/dockerfile_agent_alpine
Normal file
28
internal/dockerfile_agent_alpine
Normal file
@@ -0,0 +1,28 @@
|
||||
FROM --platform=$BUILDPLATFORM golang:alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ../go.mod ../go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Copy source files
|
||||
COPY . ./
|
||||
|
||||
# Build
|
||||
ARG TARGETOS TARGETARCH
|
||||
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./internal/cmd/agent
|
||||
|
||||
RUN rm -rf /tmp/*
|
||||
|
||||
# --------------------------
|
||||
# Final image: default scratch-based agent
|
||||
# --------------------------
|
||||
FROM alpine:latest
|
||||
COPY --from=builder /agent /agent
|
||||
|
||||
RUN apk add --no-cache smartmontools
|
||||
|
||||
# Ensure data persistence across container recreations
|
||||
VOLUME ["/var/lib/beszel-agent"]
|
||||
|
||||
ENTRYPOINT ["/agent"]
|
||||
@@ -20,7 +20,7 @@ FROM alpine:edge
|
||||
|
||||
COPY --from=builder /agent /agent
|
||||
|
||||
RUN apk add --no-cache -X https://dl-cdn.alpinelinux.org/alpine/edge/testing igt-gpu-tools
|
||||
RUN apk add --no-cache -X https://dl-cdn.alpinelinux.org/alpine/edge/testing igt-gpu-tools smartmontools
|
||||
|
||||
# Ensure data persistence across container recreations
|
||||
VOLUME ["/var/lib/beszel-agent"]
|
||||
|
||||
@@ -2,7 +2,6 @@ FROM --platform=$BUILDPLATFORM golang:alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
COPY ../go.mod ../go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
@@ -13,7 +12,24 @@ COPY . ./
|
||||
ARG TARGETOS TARGETARCH
|
||||
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./internal/cmd/agent
|
||||
|
||||
RUN rm -rf /tmp/*
|
||||
# --------------------------
|
||||
# Smartmontools builder stage
|
||||
# --------------------------
|
||||
FROM nvidia/cuda:12.2.2-base-ubuntu22.04 AS smartmontools-builder
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
wget \
|
||||
build-essential \
|
||||
&& wget https://downloads.sourceforge.net/project/smartmontools/smartmontools/7.5/smartmontools-7.5.tar.gz \
|
||||
&& tar zxvf smartmontools-7.5.tar.gz \
|
||||
&& cd smartmontools-7.5 \
|
||||
&& ./configure --prefix=/usr --sysconfdir=/etc \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& rm -rf /smartmontools-7.5* \
|
||||
&& apt-get remove -y wget build-essential \
|
||||
&& apt-get autoremove -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# --------------------------
|
||||
# Final image: GPU-enabled agent with nvidia-smi
|
||||
@@ -21,8 +37,8 @@ RUN rm -rf /tmp/*
|
||||
FROM nvidia/cuda:12.2.2-base-ubuntu22.04
|
||||
COPY --from=builder /agent /agent
|
||||
|
||||
# this is so we don't need to create the /tmp directory in the scratch container
|
||||
COPY --from=builder /tmp /tmp
|
||||
# Copy smartmontools binaries and config files
|
||||
COPY --from=smartmontools-builder /usr/sbin/smartctl /usr/sbin/smartctl
|
||||
|
||||
# Ensure data persistence across container recreations
|
||||
VOLUME ["/var/lib/beszel-agent"]
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package smart
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Common types
|
||||
type VersionInfo [2]int
|
||||
|
||||
@@ -129,30 +135,136 @@ type AtaSmartAttributes struct {
|
||||
}
|
||||
|
||||
type AtaSmartAttribute struct {
|
||||
ID uint16 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Value uint16 `json:"value"`
|
||||
Worst uint16 `json:"worst"`
|
||||
Thresh uint16 `json:"thresh"`
|
||||
WhenFailed string `json:"when_failed"`
|
||||
Flags AttributeFlags `json:"flags"`
|
||||
Raw RawValue `json:"raw"`
|
||||
ID uint16 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Value uint16 `json:"value"`
|
||||
Worst uint16 `json:"worst"`
|
||||
Thresh uint16 `json:"thresh"`
|
||||
WhenFailed string `json:"when_failed"`
|
||||
// Flags AttributeFlags `json:"flags"`
|
||||
Raw RawValue `json:"raw"`
|
||||
}
|
||||
|
||||
type AttributeFlags struct {
|
||||
Value int `json:"value"`
|
||||
String string `json:"string"`
|
||||
Prefailure bool `json:"prefailure"`
|
||||
UpdatedOnline bool `json:"updated_online"`
|
||||
Performance bool `json:"performance"`
|
||||
ErrorRate bool `json:"error_rate"`
|
||||
EventCount bool `json:"event_count"`
|
||||
AutoKeep bool `json:"auto_keep"`
|
||||
}
|
||||
// type AttributeFlags struct {
|
||||
// Value int `json:"value"`
|
||||
// String string `json:"string"`
|
||||
// Prefailure bool `json:"prefailure"`
|
||||
// UpdatedOnline bool `json:"updated_online"`
|
||||
// Performance bool `json:"performance"`
|
||||
// ErrorRate bool `json:"error_rate"`
|
||||
// EventCount bool `json:"event_count"`
|
||||
// AutoKeep bool `json:"auto_keep"`
|
||||
// }
|
||||
|
||||
type RawValue struct {
|
||||
Value uint64 `json:"value"`
|
||||
String string `json:"string"`
|
||||
Value SmartRawValue `json:"value"`
|
||||
String string `json:"string"`
|
||||
}
|
||||
|
||||
func (r *RawValue) UnmarshalJSON(data []byte) error {
|
||||
var tmp struct {
|
||||
Value json.RawMessage `json:"value"`
|
||||
String string `json:"string"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(tmp.Value) > 0 {
|
||||
if err := r.Value.UnmarshalJSON(tmp.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
r.Value = 0
|
||||
}
|
||||
|
||||
r.String = tmp.String
|
||||
|
||||
if parsed, ok := ParseSmartRawValueString(tmp.String); ok {
|
||||
r.Value = SmartRawValue(parsed)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type SmartRawValue uint64
|
||||
|
||||
// handles when drives report strings like "0h+0m+0.000s" or "7344 (253d 8h)" for power on hours
|
||||
func (v *SmartRawValue) UnmarshalJSON(data []byte) error {
|
||||
trimmed := strings.TrimSpace(string(data))
|
||||
if len(trimmed) == 0 || trimmed == "null" {
|
||||
*v = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
if trimmed[0] == '"' {
|
||||
valueStr, err := strconv.Unquote(trimmed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parsed, ok := ParseSmartRawValueString(valueStr)
|
||||
if ok {
|
||||
*v = SmartRawValue(parsed)
|
||||
return nil
|
||||
}
|
||||
*v = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
if parsed, err := strconv.ParseUint(trimmed, 0, 64); err == nil {
|
||||
*v = SmartRawValue(parsed)
|
||||
return nil
|
||||
}
|
||||
|
||||
if parsed, ok := ParseSmartRawValueString(trimmed); ok {
|
||||
*v = SmartRawValue(parsed)
|
||||
return nil
|
||||
}
|
||||
|
||||
*v = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseSmartRawValueString attempts to extract a numeric value from the raw value
|
||||
// strings emitted by smartctl, which sometimes include human-friendly annotations
|
||||
// like "7344 (253d 8h)" or "0h+0m+0.000s". It returns the parsed value and a
|
||||
// boolean indicating success.
|
||||
func ParseSmartRawValueString(value string) (uint64, bool) {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
if parsed, err := strconv.ParseUint(value, 0, 64); err == nil {
|
||||
return parsed, true
|
||||
}
|
||||
|
||||
if idx := strings.IndexRune(value, 'h'); idx > 0 {
|
||||
hoursPart := strings.TrimSpace(value[:idx])
|
||||
if hoursPart != "" {
|
||||
if parsed, err := strconv.ParseFloat(hoursPart, 64); err == nil {
|
||||
return uint64(parsed), true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(value); i++ {
|
||||
if value[i] < '0' || value[i] > '9' {
|
||||
continue
|
||||
}
|
||||
end := i + 1
|
||||
for end < len(value) && value[end] >= '0' && value[end] <= '9' {
|
||||
end++
|
||||
}
|
||||
digits := value[i:end]
|
||||
if parsed, err := strconv.ParseUint(digits, 10, 64); err == nil {
|
||||
return parsed, true
|
||||
}
|
||||
i = end
|
||||
}
|
||||
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// type PowerOnTimeInfo struct {
|
||||
@@ -163,6 +275,11 @@ type TemperatureInfo struct {
|
||||
Current uint8 `json:"current"`
|
||||
}
|
||||
|
||||
type TemperatureInfoScsi struct {
|
||||
Current uint8 `json:"current"`
|
||||
DriveTrip uint8 `json:"drive_trip"`
|
||||
}
|
||||
|
||||
// type SelectiveSelfTestTable struct {
|
||||
// LbaMin int `json:"lba_min"`
|
||||
// LbaMax int `json:"lba_max"`
|
||||
@@ -211,6 +328,8 @@ type SmartInfoForSata struct {
|
||||
// Wwn WwnInfo `json:"wwn"`
|
||||
FirmwareVersion string `json:"firmware_version"`
|
||||
UserCapacity UserCapacity `json:"user_capacity"`
|
||||
ScsiVendor string `json:"scsi_vendor"`
|
||||
ScsiProduct string `json:"scsi_product"`
|
||||
// LogicalBlockSize int `json:"logical_block_size"`
|
||||
// PhysicalBlockSize int `json:"physical_block_size"`
|
||||
// RotationRate int `json:"rotation_rate"`
|
||||
@@ -233,6 +352,54 @@ type SmartInfoForSata struct {
|
||||
// AtaSmartSelectiveSelfTestLog AtaSmartSelectiveSelfTestLog `json:"ata_smart_selective_self_test_log"`
|
||||
}
|
||||
|
||||
type ScsiErrorCounter struct {
|
||||
ErrorsCorrectedByECCFast uint64 `json:"errors_corrected_by_eccfast"`
|
||||
ErrorsCorrectedByECCDelayed uint64 `json:"errors_corrected_by_eccdelayed"`
|
||||
ErrorsCorrectedByRereadsRewrites uint64 `json:"errors_corrected_by_rereads_rewrites"`
|
||||
TotalErrorsCorrected uint64 `json:"total_errors_corrected"`
|
||||
CorrectionAlgorithmInvocations uint64 `json:"correction_algorithm_invocations"`
|
||||
GigabytesProcessed string `json:"gigabytes_processed"`
|
||||
TotalUncorrectedErrors uint64 `json:"total_uncorrected_errors"`
|
||||
}
|
||||
|
||||
type ScsiErrorCounterLog struct {
|
||||
Read ScsiErrorCounter `json:"read"`
|
||||
Write ScsiErrorCounter `json:"write"`
|
||||
Verify ScsiErrorCounter `json:"verify"`
|
||||
}
|
||||
|
||||
type ScsiStartStopCycleCounter struct {
|
||||
YearOfManufacture string `json:"year_of_manufacture"`
|
||||
WeekOfManufacture string `json:"week_of_manufacture"`
|
||||
SpecifiedCycleCountOverDeviceLifetime uint64 `json:"specified_cycle_count_over_device_lifetime"`
|
||||
AccumulatedStartStopCycles uint64 `json:"accumulated_start_stop_cycles"`
|
||||
SpecifiedLoadUnloadCountOverDeviceLifetime uint64 `json:"specified_load_unload_count_over_device_lifetime"`
|
||||
AccumulatedLoadUnloadCycles uint64 `json:"accumulated_load_unload_cycles"`
|
||||
}
|
||||
|
||||
type PowerOnTimeScsi struct {
|
||||
Hours uint64 `json:"hours"`
|
||||
Minutes uint64 `json:"minutes"`
|
||||
}
|
||||
|
||||
type SmartInfoForScsi struct {
|
||||
Smartctl SmartctlInfoLegacy `json:"smartctl"`
|
||||
Device DeviceInfo `json:"device"`
|
||||
ScsiVendor string `json:"scsi_vendor"`
|
||||
ScsiProduct string `json:"scsi_product"`
|
||||
ScsiModelName string `json:"scsi_model_name"`
|
||||
ScsiRevision string `json:"scsi_revision"`
|
||||
ScsiVersion string `json:"scsi_version"`
|
||||
SerialNumber string `json:"serial_number"`
|
||||
UserCapacity UserCapacity `json:"user_capacity"`
|
||||
Temperature TemperatureInfoScsi `json:"temperature"`
|
||||
SmartStatus SmartStatusInfo `json:"smart_status"`
|
||||
PowerOnTime PowerOnTimeScsi `json:"power_on_time"`
|
||||
ScsiStartStopCycleCounter ScsiStartStopCycleCounter `json:"scsi_start_stop_cycle_counter"`
|
||||
ScsiGrownDefectList uint64 `json:"scsi_grown_defect_list"`
|
||||
ScsiErrorCounterLog ScsiErrorCounterLog `json:"scsi_error_counter_log"`
|
||||
}
|
||||
|
||||
// type AtaSmartErrorLog struct {
|
||||
// Summary SummaryInfo `json:"summary"`
|
||||
// }
|
||||
|
||||
62
internal/entities/smart/smart_test.go
Normal file
62
internal/entities/smart/smart_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package smart
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSmartRawValueUnmarshalDuration(t *testing.T) {
|
||||
input := []byte(`{"value":"62312h+33m+50.907s","string":"62312h+33m+50.907s"}`)
|
||||
var raw RawValue
|
||||
err := json.Unmarshal(input, &raw)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, 62312, raw.Value)
|
||||
}
|
||||
|
||||
func TestSmartRawValueUnmarshalNumericString(t *testing.T) {
|
||||
input := []byte(`{"value":"7344","string":"7344"}`)
|
||||
var raw RawValue
|
||||
err := json.Unmarshal(input, &raw)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, 7344, raw.Value)
|
||||
}
|
||||
|
||||
func TestSmartRawValueUnmarshalParenthetical(t *testing.T) {
|
||||
input := []byte(`{"value":"39925 (212 206 0)","string":"39925 (212 206 0)"}`)
|
||||
var raw RawValue
|
||||
err := json.Unmarshal(input, &raw)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, 39925, raw.Value)
|
||||
}
|
||||
|
||||
func TestSmartRawValueUnmarshalDurationWithFractions(t *testing.T) {
|
||||
input := []byte(`{"value":"2748h+31m+49.560s","string":"2748h+31m+49.560s"}`)
|
||||
var raw RawValue
|
||||
err := json.Unmarshal(input, &raw)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, 2748, raw.Value)
|
||||
}
|
||||
|
||||
func TestSmartRawValueUnmarshalParentheticalRawValue(t *testing.T) {
|
||||
input := []byte(`{"value":57891864217128,"string":"39925 (212 206 0)"}`)
|
||||
var raw RawValue
|
||||
err := json.Unmarshal(input, &raw)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, 39925, raw.Value)
|
||||
}
|
||||
|
||||
func TestSmartRawValueUnmarshalDurationRawValue(t *testing.T) {
|
||||
input := []byte(`{"value":57891864217128,"string":"2748h+31m+49.560s"}`)
|
||||
var raw RawValue
|
||||
err := json.Unmarshal(input, &raw)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, 2748, raw.Value)
|
||||
}
|
||||
@@ -3,9 +3,11 @@ package system
|
||||
// TODO: this is confusing, make common package with common/types common/helpers etc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/container"
|
||||
"github.com/henrygd/beszel/internal/entities/systemd"
|
||||
)
|
||||
|
||||
type Stats struct {
|
||||
@@ -41,9 +43,28 @@ type Stats struct {
|
||||
LoadAvg [3]float64 `json:"la,omitempty" cbor:"28,keyasint"`
|
||||
Battery [2]uint8 `json:"bat,omitzero" cbor:"29,keyasint,omitzero"` // [percent, charge state, current]
|
||||
MaxMem float64 `json:"mm,omitempty" cbor:"30,keyasint,omitempty"`
|
||||
NetworkInterfaces map[string][4]uint64 `json:"ni,omitempty" cbor:"31,keyasint,omitempty"` // [upload bytes, download bytes, total upload, total download]
|
||||
DiskIO [2]uint64 `json:"dio,omitzero" cbor:"32,keyasint,omitzero"` // [read bytes, write bytes]
|
||||
MaxDiskIO [2]uint64 `json:"diom,omitzero" cbor:"-"` // [max read bytes, max write bytes]
|
||||
NetworkInterfaces map[string][4]uint64 `json:"ni,omitempty" cbor:"31,keyasint,omitempty"` // [upload bytes, download bytes, total upload, total download]
|
||||
DiskIO [2]uint64 `json:"dio,omitzero" cbor:"32,keyasint,omitzero"` // [read bytes, write bytes]
|
||||
MaxDiskIO [2]uint64 `json:"diom,omitzero" cbor:"-"` // [max read bytes, max write bytes]
|
||||
CpuBreakdown []float64 `json:"cpub,omitempty" cbor:"33,keyasint,omitempty"` // [user, system, iowait, steal, idle]
|
||||
CpuCoresUsage Uint8Slice `json:"cpus,omitempty" cbor:"34,keyasint,omitempty"` // per-core busy usage [CPU0..]
|
||||
}
|
||||
|
||||
// Uint8Slice wraps []uint8 to customize JSON encoding while keeping CBOR efficient.
|
||||
// JSON: encodes as array of numbers (avoids base64 string).
|
||||
// CBOR: falls back to default handling for []uint8 (byte string), keeping payload small.
|
||||
type Uint8Slice []uint8
|
||||
|
||||
func (s Uint8Slice) MarshalJSON() ([]byte, error) {
|
||||
if s == nil {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
// Convert to wider ints to force array-of-numbers encoding.
|
||||
arr := make([]uint16, len(s))
|
||||
for i, v := range s {
|
||||
arr[i] = uint16(v)
|
||||
}
|
||||
return json.Marshal(arr)
|
||||
}
|
||||
|
||||
type GPUData struct {
|
||||
@@ -123,13 +144,15 @@ type Info struct {
|
||||
LoadAvg15 float64 `json:"l15,omitempty" cbor:"17,keyasint,omitempty"`
|
||||
BandwidthBytes uint64 `json:"bb" cbor:"18,keyasint"`
|
||||
// TODO: remove load fields in future release in favor of load avg array
|
||||
LoadAvg [3]float64 `json:"la,omitempty" cbor:"19,keyasint"`
|
||||
ConnectionType ConnectionType `json:"ct,omitempty" cbor:"20,keyasint,omitempty,omitzero"`
|
||||
LoadAvg [3]float64 `json:"la,omitempty" cbor:"19,keyasint"`
|
||||
ConnectionType ConnectionType `json:"ct,omitempty" cbor:"20,keyasint,omitempty,omitzero"`
|
||||
ExtraFsPct map[string]float64 `json:"efs,omitempty" cbor:"21,keyasint,omitempty"`
|
||||
}
|
||||
|
||||
// Final data structure to return to the hub
|
||||
type CombinedData struct {
|
||||
Stats Stats `json:"stats" cbor:"0,keyasint"`
|
||||
Info Info `json:"info" cbor:"1,keyasint"`
|
||||
Containers []*container.Stats `json:"container" cbor:"2,keyasint"`
|
||||
Stats Stats `json:"stats" cbor:"0,keyasint"`
|
||||
Info Info `json:"info" cbor:"1,keyasint"`
|
||||
Containers []*container.Stats `json:"container" cbor:"2,keyasint"`
|
||||
SystemdServices []*systemd.Service `json:"systemd,omitempty" cbor:"3,keyasint,omitempty"`
|
||||
}
|
||||
|
||||
127
internal/entities/systemd/systemd.go
Normal file
127
internal/entities/systemd/systemd.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package systemd
|
||||
|
||||
import (
|
||||
"math"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ServiceState represents the status of a systemd service
|
||||
type ServiceState uint8
|
||||
|
||||
const (
|
||||
StatusActive ServiceState = iota
|
||||
StatusInactive
|
||||
StatusFailed
|
||||
StatusActivating
|
||||
StatusDeactivating
|
||||
StatusReloading
|
||||
)
|
||||
|
||||
// ServiceSubState represents the sub status of a systemd service
|
||||
type ServiceSubState uint8
|
||||
|
||||
const (
|
||||
SubStateDead ServiceSubState = iota
|
||||
SubStateRunning
|
||||
SubStateExited
|
||||
SubStateFailed
|
||||
SubStateUnknown
|
||||
)
|
||||
|
||||
// ParseServiceStatus converts a string status to a ServiceStatus enum value
|
||||
func ParseServiceStatus(status string) ServiceState {
|
||||
switch status {
|
||||
case "active":
|
||||
return StatusActive
|
||||
case "inactive":
|
||||
return StatusInactive
|
||||
case "failed":
|
||||
return StatusFailed
|
||||
case "activating":
|
||||
return StatusActivating
|
||||
case "deactivating":
|
||||
return StatusDeactivating
|
||||
case "reloading":
|
||||
return StatusReloading
|
||||
default:
|
||||
return StatusInactive
|
||||
}
|
||||
}
|
||||
|
||||
// ParseServiceSubState converts a string sub status to a ServiceSubState enum value
|
||||
func ParseServiceSubState(subState string) ServiceSubState {
|
||||
switch subState {
|
||||
case "dead":
|
||||
return SubStateDead
|
||||
case "running":
|
||||
return SubStateRunning
|
||||
case "exited":
|
||||
return SubStateExited
|
||||
case "failed":
|
||||
return SubStateFailed
|
||||
default:
|
||||
return SubStateUnknown
|
||||
}
|
||||
}
|
||||
|
||||
// Service represents a single systemd service with its stats.
|
||||
type Service struct {
|
||||
Name string `json:"n" cbor:"0,keyasint"`
|
||||
State ServiceState `json:"s" cbor:"1,keyasint"`
|
||||
Cpu float64 `json:"c" cbor:"2,keyasint"`
|
||||
Mem uint64 `json:"m" cbor:"3,keyasint"`
|
||||
MemPeak uint64 `json:"mp" cbor:"4,keyasint"`
|
||||
Sub ServiceSubState `json:"ss" cbor:"5,keyasint"`
|
||||
CpuPeak float64 `json:"cp" cbor:"6,keyasint"`
|
||||
PrevCpuUsage uint64 `json:"-"`
|
||||
PrevReadTime time.Time `json:"-"`
|
||||
}
|
||||
|
||||
// UpdateCPUPercent calculates the CPU usage percentage for the service.
|
||||
func (s *Service) UpdateCPUPercent(cpuUsage uint64) {
|
||||
now := time.Now()
|
||||
|
||||
if s.PrevReadTime.IsZero() || cpuUsage < s.PrevCpuUsage {
|
||||
s.Cpu = 0
|
||||
s.PrevCpuUsage = cpuUsage
|
||||
s.PrevReadTime = now
|
||||
return
|
||||
}
|
||||
|
||||
duration := now.Sub(s.PrevReadTime).Nanoseconds()
|
||||
if duration <= 0 {
|
||||
s.PrevCpuUsage = cpuUsage
|
||||
s.PrevReadTime = now
|
||||
return
|
||||
}
|
||||
|
||||
coreCount := int64(runtime.NumCPU())
|
||||
duration *= coreCount
|
||||
|
||||
usageDelta := cpuUsage - s.PrevCpuUsage
|
||||
cpuPercent := float64(usageDelta) / float64(duration)
|
||||
s.Cpu = twoDecimals(cpuPercent * 100)
|
||||
|
||||
if s.Cpu > s.CpuPeak {
|
||||
s.CpuPeak = s.Cpu
|
||||
}
|
||||
|
||||
s.PrevCpuUsage = cpuUsage
|
||||
s.PrevReadTime = now
|
||||
}
|
||||
|
||||
func twoDecimals(value float64) float64 {
|
||||
return math.Round(value*100) / 100
|
||||
}
|
||||
|
||||
// ServiceDependency represents a unit that the service depends on.
|
||||
type ServiceDependency struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
ActiveState string `json:"activeState,omitempty"`
|
||||
SubState string `json:"subState,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceDetails contains extended information about a systemd service.
|
||||
type ServiceDetails map[string]any
|
||||
113
internal/entities/systemd/systemd_test.go
Normal file
113
internal/entities/systemd/systemd_test.go
Normal file
@@ -0,0 +1,113 @@
|
||||
//go:build testing
|
||||
|
||||
package systemd_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/systemd"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseServiceStatus(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected systemd.ServiceState
|
||||
}{
|
||||
{"active", systemd.StatusActive},
|
||||
{"inactive", systemd.StatusInactive},
|
||||
{"failed", systemd.StatusFailed},
|
||||
{"activating", systemd.StatusActivating},
|
||||
{"deactivating", systemd.StatusDeactivating},
|
||||
{"reloading", systemd.StatusReloading},
|
||||
{"unknown", systemd.StatusInactive}, // default case
|
||||
{"", systemd.StatusInactive}, // default case
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.input, func(t *testing.T) {
|
||||
result := systemd.ParseServiceStatus(test.input)
|
||||
assert.Equal(t, test.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseServiceSubState(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected systemd.ServiceSubState
|
||||
}{
|
||||
{"dead", systemd.SubStateDead},
|
||||
{"running", systemd.SubStateRunning},
|
||||
{"exited", systemd.SubStateExited},
|
||||
{"failed", systemd.SubStateFailed},
|
||||
{"unknown", systemd.SubStateUnknown},
|
||||
{"other", systemd.SubStateUnknown}, // default case
|
||||
{"", systemd.SubStateUnknown}, // default case
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.input, func(t *testing.T) {
|
||||
result := systemd.ParseServiceSubState(test.input)
|
||||
assert.Equal(t, test.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceUpdateCPUPercent(t *testing.T) {
|
||||
t.Run("initial call sets CPU to 0", func(t *testing.T) {
|
||||
service := &systemd.Service{}
|
||||
service.UpdateCPUPercent(1000)
|
||||
assert.Equal(t, 0.0, service.Cpu)
|
||||
assert.Equal(t, uint64(1000), service.PrevCpuUsage)
|
||||
assert.False(t, service.PrevReadTime.IsZero())
|
||||
})
|
||||
|
||||
t.Run("subsequent call calculates CPU percentage", func(t *testing.T) {
|
||||
service := &systemd.Service{}
|
||||
service.PrevCpuUsage = 1000
|
||||
service.PrevReadTime = time.Now().Add(-time.Second)
|
||||
|
||||
service.UpdateCPUPercent(8000000000) // 8 seconds of CPU time
|
||||
|
||||
// CPU usage should be positive and reasonable
|
||||
assert.Greater(t, service.Cpu, 0.0, "CPU usage should be positive")
|
||||
assert.LessOrEqual(t, service.Cpu, 100.0, "CPU usage should not exceed 100%")
|
||||
assert.Equal(t, uint64(8000000000), service.PrevCpuUsage)
|
||||
assert.Greater(t, service.CpuPeak, 0.0, "CPU peak should be set")
|
||||
})
|
||||
|
||||
t.Run("CPU peak updates only when higher", func(t *testing.T) {
|
||||
service := &systemd.Service{}
|
||||
service.PrevCpuUsage = 1000
|
||||
service.PrevReadTime = time.Now().Add(-time.Second)
|
||||
service.UpdateCPUPercent(8000000000) // Set initial peak to ~50%
|
||||
initialPeak := service.CpuPeak
|
||||
|
||||
// Now try with much lower CPU usage - should not update peak
|
||||
service.PrevReadTime = time.Now().Add(-time.Second)
|
||||
service.UpdateCPUPercent(1000000) // Much lower usage
|
||||
assert.Equal(t, initialPeak, service.CpuPeak, "Peak should not update for lower CPU usage")
|
||||
})
|
||||
|
||||
t.Run("handles zero duration", func(t *testing.T) {
|
||||
service := &systemd.Service{}
|
||||
service.PrevCpuUsage = 1000
|
||||
now := time.Now()
|
||||
service.PrevReadTime = now
|
||||
// Mock time.Now() to return the same time to ensure zero duration
|
||||
// Since we can't mock time in Go easily, we'll check the logic manually
|
||||
// The zero duration case happens when duration <= 0
|
||||
assert.Equal(t, 0.0, service.Cpu, "CPU should start at 0")
|
||||
})
|
||||
|
||||
t.Run("handles CPU usage wraparound", func(t *testing.T) {
|
||||
service := &systemd.Service{}
|
||||
// Simulate wraparound where new usage is less than previous
|
||||
service.PrevCpuUsage = 1000
|
||||
service.PrevReadTime = time.Now().Add(-time.Second)
|
||||
service.UpdateCPUPercent(500) // Less than previous, should reset
|
||||
assert.Equal(t, 0.0, service.Cpu)
|
||||
})
|
||||
}
|
||||
@@ -136,6 +136,7 @@ func setCollectionAuthSettings(app core.App) error {
|
||||
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"
|
||||
@@ -147,6 +148,7 @@ func setCollectionAuthSettings(app core.App) error {
|
||||
} else {
|
||||
usersCollection.CreateRule = nil
|
||||
}
|
||||
|
||||
// enable mfaOtp mfa if MFA_OTP env var is set
|
||||
mfaOtp, _ := GetEnv("MFA_OTP")
|
||||
usersCollection.OTP.Length = 6
|
||||
@@ -161,23 +163,37 @@ func setCollectionAuthSettings(app core.App) error {
|
||||
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
|
||||
}
|
||||
shareAllSystems, _ := GetEnv("SHARE_ALL_SYSTEMS")
|
||||
systemsReadRule := "@request.auth.id != \"\""
|
||||
if shareAllSystems != "true" {
|
||||
// default is to only show systems that the user id is assigned to
|
||||
systemsReadRule += " && users.id ?= @request.auth.id"
|
||||
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
|
||||
return app.Save(systemsCollection)
|
||||
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
|
||||
return app.Save(containersCollection)
|
||||
}
|
||||
|
||||
// registerCronJobs sets up scheduled tasks
|
||||
@@ -252,12 +268,17 @@ func (h *Hub) registerApiRoutes(se *core.ServeEvent) error {
|
||||
// update / delete user alerts
|
||||
apiAuth.POST("/user-alerts", alerts.UpsertUserAlerts)
|
||||
apiAuth.DELETE("/user-alerts", alerts.DeleteUserAlerts)
|
||||
// get container logs
|
||||
apiAuth.GET("/containers/logs", h.getContainerLogs)
|
||||
// get container info
|
||||
apiAuth.GET("/containers/info", h.getContainerInfo)
|
||||
// get SMART data
|
||||
apiAuth.GET("/smart", h.getSmartData)
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -304,7 +325,7 @@ func (h *Hub) containerRequestHandler(e *core.RequestEvent, fetchFunc func(*syst
|
||||
|
||||
data, err := fetchFunc(system, containerID)
|
||||
if err != nil {
|
||||
return e.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return e.JSON(http.StatusNotFound, map[string]string{"error": err.Error()})
|
||||
}
|
||||
|
||||
return e.JSON(http.StatusOK, map[string]string{responseKey: data})
|
||||
@@ -323,6 +344,27 @@ func (h *Hub) getContainerInfo(e *core.RequestEvent) error {
|
||||
}, "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})
|
||||
}
|
||||
|
||||
// getSmartData handles GET /api/beszel/smart requests
|
||||
func (h *Hub) getSmartData(e *core.RequestEvent) error {
|
||||
systemID := e.Request.URL.Query().Get("system")
|
||||
@@ -335,7 +377,7 @@ func (h *Hub) getSmartData(e *core.RequestEvent) error {
|
||||
}
|
||||
data, err := system.FetchSmartDataFromAgent()
|
||||
if err != nil {
|
||||
return e.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
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, data)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strings"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/container"
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
"github.com/henrygd/beszel/internal/entities/systemd"
|
||||
|
||||
"github.com/henrygd/beszel"
|
||||
|
||||
@@ -171,6 +173,14 @@ func (sys *System) createRecords(data *system.CombinedData) (*core.Record, error
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// add new systemd_stats record
|
||||
if len(data.SystemdServices) > 0 {
|
||||
if err := createSystemdStatsRecords(txApp, data.SystemdServices, sys.Id); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// update system record (do this last because it triggers alerts and we need above records to be inserted first)
|
||||
systemRecord.Set("status", up)
|
||||
|
||||
@@ -184,11 +194,50 @@ func (sys *System) createRecords(data *system.CombinedData) (*core.Record, error
|
||||
return systemRecord, err
|
||||
}
|
||||
|
||||
func createSystemdStatsRecords(app core.App, data []*systemd.Service, systemId string) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
// shared params for all records
|
||||
params := dbx.Params{
|
||||
"system": systemId,
|
||||
"updated": time.Now().UTC().UnixMilli(),
|
||||
}
|
||||
|
||||
valueStrings := make([]string, 0, len(data))
|
||||
for i, service := range data {
|
||||
suffix := fmt.Sprintf("%d", i)
|
||||
valueStrings = append(valueStrings, fmt.Sprintf("({:id%[1]s}, {:system}, {:name%[1]s}, {:state%[1]s}, {:sub%[1]s}, {:cpu%[1]s}, {:cpuPeak%[1]s}, {:memory%[1]s}, {:memPeak%[1]s}, {:updated})", suffix))
|
||||
params["id"+suffix] = getSystemdServiceId(systemId, service.Name)
|
||||
params["name"+suffix] = service.Name
|
||||
params["state"+suffix] = service.State
|
||||
params["sub"+suffix] = service.Sub
|
||||
params["cpu"+suffix] = service.Cpu
|
||||
params["cpuPeak"+suffix] = service.CpuPeak
|
||||
params["memory"+suffix] = service.Mem
|
||||
params["memPeak"+suffix] = service.MemPeak
|
||||
}
|
||||
queryString := fmt.Sprintf(
|
||||
"INSERT INTO systemd_services (id, system, name, state, sub, cpu, cpuPeak, memory, memPeak, updated) VALUES %s ON CONFLICT(id) DO UPDATE SET system = excluded.system, name = excluded.name, state = excluded.state, sub = excluded.sub, cpu = excluded.cpu, cpuPeak = excluded.cpuPeak, memory = excluded.memory, memPeak = excluded.memPeak, updated = excluded.updated",
|
||||
strings.Join(valueStrings, ","),
|
||||
)
|
||||
_, err := app.DB().NewQuery(queryString).Bind(params).Execute()
|
||||
return err
|
||||
}
|
||||
|
||||
// getSystemdServiceId generates a deterministic unique id for a systemd service
|
||||
func getSystemdServiceId(systemId string, serviceName string) string {
|
||||
hash := fnv.New32a()
|
||||
hash.Write([]byte(systemId + serviceName))
|
||||
return fmt.Sprintf("%x", hash.Sum32())
|
||||
}
|
||||
|
||||
// createContainerRecords creates container records
|
||||
func createContainerRecords(app core.App, data []*container.Stats, systemId string) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
// shared params for all records
|
||||
params := dbx.Params{
|
||||
"system": systemId,
|
||||
"updated": time.Now().UTC().UnixMilli(),
|
||||
@@ -340,6 +389,52 @@ func (sys *System) FetchContainerLogsFromAgent(containerID string) (string, erro
|
||||
return sys.fetchStringFromAgentViaSSH(common.GetContainerLogs, common.ContainerLogsRequest{ContainerID: containerID}, "no logs in response")
|
||||
}
|
||||
|
||||
// FetchSystemdInfoFromAgent fetches detailed systemd service information from the agent
|
||||
func (sys *System) FetchSystemdInfoFromAgent(serviceName string) (systemd.ServiceDetails, error) {
|
||||
// fetch via websocket
|
||||
if sys.WsConn != nil && sys.WsConn.IsConnected() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
return sys.WsConn.RequestSystemdInfo(ctx, serviceName)
|
||||
}
|
||||
|
||||
var result systemd.ServiceDetails
|
||||
err := sys.runSSHOperation(5*time.Second, 1, func(session *ssh.Session) (bool, error) {
|
||||
stdout, err := session.StdoutPipe()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
stdin, stdinErr := session.StdinPipe()
|
||||
if stdinErr != nil {
|
||||
return false, stdinErr
|
||||
}
|
||||
if err := session.Shell(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req := common.HubRequest[any]{Action: common.GetSystemdInfo, Data: common.SystemdInfoRequest{ServiceName: serviceName}}
|
||||
if err := cbor.NewEncoder(stdin).Encode(req); err != nil {
|
||||
return false, err
|
||||
}
|
||||
_ = stdin.Close()
|
||||
|
||||
var resp common.AgentResponse
|
||||
if err := cbor.NewDecoder(stdout).Decode(&resp); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if resp.ServiceInfo == nil {
|
||||
if resp.Error != "" {
|
||||
return false, errors.New(resp.Error)
|
||||
}
|
||||
return false, errors.New("no systemd info in response")
|
||||
}
|
||||
result = resp.ServiceInfo
|
||||
return false, nil
|
||||
})
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// FetchSmartDataFromAgent fetches SMART data from the agent
|
||||
func (sys *System) FetchSmartDataFromAgent() (map[string]any, error) {
|
||||
// fetch via websocket
|
||||
|
||||
75
internal/hub/systems/system_systemd_test.go
Normal file
75
internal/hub/systems/system_systemd_test.go
Normal file
@@ -0,0 +1,75 @@
|
||||
//go:build testing
|
||||
|
||||
package systems
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetSystemdServiceId(t *testing.T) {
|
||||
t.Run("deterministic output", func(t *testing.T) {
|
||||
systemId := "sys-123"
|
||||
serviceName := "nginx.service"
|
||||
|
||||
// Call multiple times and ensure same result
|
||||
id1 := getSystemdServiceId(systemId, serviceName)
|
||||
id2 := getSystemdServiceId(systemId, serviceName)
|
||||
id3 := getSystemdServiceId(systemId, serviceName)
|
||||
|
||||
assert.Equal(t, id1, id2)
|
||||
assert.Equal(t, id2, id3)
|
||||
assert.NotEmpty(t, id1)
|
||||
})
|
||||
|
||||
t.Run("different inputs produce different ids", func(t *testing.T) {
|
||||
systemId1 := "sys-123"
|
||||
systemId2 := "sys-456"
|
||||
serviceName1 := "nginx.service"
|
||||
serviceName2 := "apache.service"
|
||||
|
||||
id1 := getSystemdServiceId(systemId1, serviceName1)
|
||||
id2 := getSystemdServiceId(systemId2, serviceName1)
|
||||
id3 := getSystemdServiceId(systemId1, serviceName2)
|
||||
id4 := getSystemdServiceId(systemId2, serviceName2)
|
||||
|
||||
// All IDs should be different
|
||||
assert.NotEqual(t, id1, id2)
|
||||
assert.NotEqual(t, id1, id3)
|
||||
assert.NotEqual(t, id1, id4)
|
||||
assert.NotEqual(t, id2, id3)
|
||||
assert.NotEqual(t, id2, id4)
|
||||
assert.NotEqual(t, id3, id4)
|
||||
})
|
||||
|
||||
t.Run("consistent length", func(t *testing.T) {
|
||||
testCases := []struct {
|
||||
systemId string
|
||||
serviceName string
|
||||
}{
|
||||
{"short", "short.service"},
|
||||
{"very-long-system-id-that-might-be-used-in-practice", "very-long-service-name.service"},
|
||||
{"", "empty-system.service"},
|
||||
{"empty-service", ""},
|
||||
{"", ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
id := getSystemdServiceId(tc.systemId, tc.serviceName)
|
||||
// FNV-32 produces 8 hex characters
|
||||
assert.Len(t, id, 8, "ID should be 8 characters for systemId='%s', serviceName='%s'", tc.systemId, tc.serviceName)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("hexadecimal output", func(t *testing.T) {
|
||||
id := getSystemdServiceId("test-system", "test-service")
|
||||
assert.NotEmpty(t, id)
|
||||
|
||||
// Should only contain hexadecimal characters
|
||||
for _, char := range id {
|
||||
assert.True(t, (char >= '0' && char <= '9') || (char >= 'a' && char <= 'f'),
|
||||
"ID should only contain hexadecimal characters, got: %s", id)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
"github.com/henrygd/beszel/internal/common"
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
"github.com/henrygd/beszel/internal/entities/systemd"
|
||||
"github.com/lxzan/gws"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
@@ -115,6 +116,44 @@ func (ws *WsConn) RequestContainerInfo(ctx context.Context, containerID string)
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// RequestSystemdInfo requests detailed information about a systemd service via WebSocket.
|
||||
func (ws *WsConn) RequestSystemdInfo(ctx context.Context, serviceName string) (systemd.ServiceDetails, error) {
|
||||
if !ws.IsConnected() {
|
||||
return nil, gws.ErrConnClosed
|
||||
}
|
||||
|
||||
req, err := ws.requestManager.SendRequest(ctx, common.GetSystemdInfo, common.SystemdInfoRequest{ServiceName: serviceName})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result systemd.ServiceDetails
|
||||
handler := &systemdInfoHandler{result: &result}
|
||||
if err := ws.handleAgentRequest(req, handler); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// systemdInfoHandler parses ServiceDetails from AgentResponse
|
||||
type systemdInfoHandler struct {
|
||||
BaseHandler
|
||||
result *systemd.ServiceDetails
|
||||
}
|
||||
|
||||
func (h *systemdInfoHandler) Handle(agentResponse common.AgentResponse) error {
|
||||
if agentResponse.ServiceInfo == nil {
|
||||
return errors.New("no systemd info in response")
|
||||
}
|
||||
*h.result = agentResponse.ServiceInfo
|
||||
return nil
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// RequestSmartData requests SMART data via WebSocket.
|
||||
func (ws *WsConn) RequestSmartData(ctx context.Context) (map[string]any, error) {
|
||||
if !ws.IsConnected() {
|
||||
|
||||
75
internal/hub/ws/handlers_test.go
Normal file
75
internal/hub/ws/handlers_test.go
Normal file
@@ -0,0 +1,75 @@
|
||||
//go:build testing
|
||||
|
||||
package ws
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/henrygd/beszel/internal/common"
|
||||
"github.com/henrygd/beszel/internal/entities/systemd"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSystemdInfoHandlerSuccess(t *testing.T) {
|
||||
handler := &systemdInfoHandler{
|
||||
result: &systemd.ServiceDetails{},
|
||||
}
|
||||
|
||||
// Test successful handling with valid ServiceInfo
|
||||
testDetails := systemd.ServiceDetails{
|
||||
"Id": "nginx.service",
|
||||
"ActiveState": "active",
|
||||
"SubState": "running",
|
||||
"Description": "A high performance web server",
|
||||
"ExecMainPID": 1234,
|
||||
"MemoryCurrent": 1024000,
|
||||
}
|
||||
|
||||
response := common.AgentResponse{
|
||||
ServiceInfo: testDetails,
|
||||
}
|
||||
|
||||
err := handler.Handle(response)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, testDetails, *handler.result)
|
||||
}
|
||||
|
||||
func TestSystemdInfoHandlerError(t *testing.T) {
|
||||
handler := &systemdInfoHandler{
|
||||
result: &systemd.ServiceDetails{},
|
||||
}
|
||||
|
||||
// Test error handling when ServiceInfo is nil
|
||||
response := common.AgentResponse{
|
||||
ServiceInfo: nil,
|
||||
Error: "service not found",
|
||||
}
|
||||
|
||||
err := handler.Handle(response)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "no systemd info in response", err.Error())
|
||||
}
|
||||
|
||||
func TestSystemdInfoHandlerEmptyResponse(t *testing.T) {
|
||||
handler := &systemdInfoHandler{
|
||||
result: &systemd.ServiceDetails{},
|
||||
}
|
||||
|
||||
// Test with completely empty response
|
||||
response := common.AgentResponse{}
|
||||
|
||||
err := handler.Handle(response)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "no systemd info in response", err.Error())
|
||||
}
|
||||
|
||||
func TestSystemdInfoHandlerLegacyNotSupported(t *testing.T) {
|
||||
handler := &systemdInfoHandler{
|
||||
result: &systemd.ServiceDetails{},
|
||||
}
|
||||
|
||||
// Test that legacy format is not supported
|
||||
err := handler.HandleLegacy([]byte("some data"))
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "legacy format not supported", err.Error())
|
||||
}
|
||||
@@ -75,6 +75,7 @@ func init() {
|
||||
"Disk",
|
||||
"Temperature",
|
||||
"Bandwidth",
|
||||
"GPU",
|
||||
"LoadAvg1",
|
||||
"LoadAvg5",
|
||||
"LoadAvg15"
|
||||
@@ -718,7 +719,9 @@ func init() {
|
||||
"type": "autodate"
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"indexes": [
|
||||
"CREATE INDEX ` + "`" + `idx_systems_status` + "`" + ` ON ` + "`" + `systems` + "`" + ` (` + "`" + `status` + "`" + `)"
|
||||
],
|
||||
"system": false
|
||||
},
|
||||
{
|
||||
@@ -1005,6 +1008,148 @@ func init() {
|
||||
"CREATE INDEX ` + "`" + `idx_r3Ja0rs102` + "`" + ` ON ` + "`" + `containers` + "`" + ` (` + "`" + `system` + "`" + `)"
|
||||
],
|
||||
"system": false
|
||||
},
|
||||
{
|
||||
"createRule": null,
|
||||
"deleteRule": null,
|
||||
"fields": [
|
||||
{
|
||||
"autogeneratePattern": "[a-z0-9]{10}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 10,
|
||||
"min": 6,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"cascadeDelete": true,
|
||||
"collectionId": "2hz5ncl8tizk5nx",
|
||||
"hidden": false,
|
||||
"id": "relation3377271179",
|
||||
"maxSelect": 1,
|
||||
"minSelect": 0,
|
||||
"name": "system",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "relation"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "number2063623452",
|
||||
"max": null,
|
||||
"min": null,
|
||||
"name": "state",
|
||||
"onlyInt": true,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "number1476559580",
|
||||
"max": null,
|
||||
"min": null,
|
||||
"name": "sub",
|
||||
"onlyInt": true,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "number3128971310",
|
||||
"max": null,
|
||||
"min": null,
|
||||
"name": "cpu",
|
||||
"onlyInt": false,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "number1052053287",
|
||||
"max": null,
|
||||
"min": null,
|
||||
"name": "cpuPeak",
|
||||
"onlyInt": false,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "number3933025333",
|
||||
"max": null,
|
||||
"min": null,
|
||||
"name": "memory",
|
||||
"onlyInt": false,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "number1828797201",
|
||||
"max": null,
|
||||
"min": null,
|
||||
"name": "memPeak",
|
||||
"onlyInt": false,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "number3332085495",
|
||||
"max": null,
|
||||
"min": null,
|
||||
"name": "updated",
|
||||
"onlyInt": false,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "number"
|
||||
}
|
||||
],
|
||||
"id": "pbc_3494996990",
|
||||
"indexes": [
|
||||
"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",
|
||||
"name": "systemd_services",
|
||||
"system": false,
|
||||
"type": "base",
|
||||
"updateRule": null,
|
||||
"viewRule": null
|
||||
}
|
||||
]`
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
m "github.com/pocketbase/pocketbase/migrations"
|
||||
)
|
||||
|
||||
// This can be deleted after Nov 2025 or so
|
||||
|
||||
func init() {
|
||||
m.Register(func(app core.App) error {
|
||||
app.RunInTransaction(func(txApp core.App) error {
|
||||
var systemIds []string
|
||||
txApp.DB().NewQuery("SELECT id FROM systems").Column(&systemIds)
|
||||
|
||||
for _, systemId := range systemIds {
|
||||
var statRecordIds []string
|
||||
txApp.DB().NewQuery("SELECT id FROM system_stats WHERE system = {:system} AND created > {:created}").Bind(map[string]any{"system": systemId, "created": "2025-09-21"}).Column(&statRecordIds)
|
||||
|
||||
for _, statRecordId := range statRecordIds {
|
||||
statRecord, err := txApp.FindRecordById("system_stats", statRecordId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var systemStats system.Stats
|
||||
err = statRecord.UnmarshalJSONField("stats", &systemStats)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if mem buff cache is less than total mem, we don't need to fix it
|
||||
if systemStats.MemBuffCache < systemStats.Mem {
|
||||
continue
|
||||
}
|
||||
systemStats.MemBuffCache = 0
|
||||
statRecord.Set("stats", systemStats)
|
||||
err = txApp.SaveNoValidate(statRecord)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}, func(app core.App) error {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -177,6 +177,10 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *
|
||||
stats := &tempStats
|
||||
// necessary because uint8 is not big enough for the sum
|
||||
batterySum := 0
|
||||
// accumulate per-core usage across records
|
||||
var cpuCoresSums []uint64
|
||||
// accumulate cpu breakdown [user, system, iowait, steal, idle]
|
||||
var cpuBreakdownSums []float64
|
||||
|
||||
count := float64(len(records))
|
||||
tempCount := float64(0)
|
||||
@@ -194,6 +198,15 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *
|
||||
}
|
||||
|
||||
sum.Cpu += stats.Cpu
|
||||
// accumulate cpu time breakdowns if present
|
||||
if stats.CpuBreakdown != nil {
|
||||
if len(cpuBreakdownSums) < len(stats.CpuBreakdown) {
|
||||
cpuBreakdownSums = append(cpuBreakdownSums, make([]float64, len(stats.CpuBreakdown)-len(cpuBreakdownSums))...)
|
||||
}
|
||||
for i, v := range stats.CpuBreakdown {
|
||||
cpuBreakdownSums[i] += v
|
||||
}
|
||||
}
|
||||
sum.Mem += stats.Mem
|
||||
sum.MemUsed += stats.MemUsed
|
||||
sum.MemPct += stats.MemPct
|
||||
@@ -217,6 +230,17 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *
|
||||
sum.DiskIO[1] += stats.DiskIO[1]
|
||||
batterySum += int(stats.Battery[0])
|
||||
sum.Battery[1] = stats.Battery[1]
|
||||
|
||||
// accumulate per-core usage if present
|
||||
if stats.CpuCoresUsage != nil {
|
||||
if len(cpuCoresSums) < len(stats.CpuCoresUsage) {
|
||||
// extend slices to accommodate core count
|
||||
cpuCoresSums = append(cpuCoresSums, make([]uint64, len(stats.CpuCoresUsage)-len(cpuCoresSums))...)
|
||||
}
|
||||
for i, v := range stats.CpuCoresUsage {
|
||||
cpuCoresSums[i] += uint64(v)
|
||||
}
|
||||
}
|
||||
// Set peak values
|
||||
sum.MaxCpu = max(sum.MaxCpu, stats.MaxCpu, stats.Cpu)
|
||||
sum.MaxMem = max(sum.MaxMem, stats.MaxMem, stats.MemUsed)
|
||||
@@ -269,6 +293,10 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *
|
||||
fs.DiskReadPs += value.DiskReadPs
|
||||
fs.MaxDiskReadPS = max(fs.MaxDiskReadPS, value.MaxDiskReadPS, value.DiskReadPs)
|
||||
fs.MaxDiskWritePS = max(fs.MaxDiskWritePS, value.MaxDiskWritePS, value.DiskWritePs)
|
||||
fs.DiskReadBytes += value.DiskReadBytes
|
||||
fs.DiskWriteBytes += value.DiskWriteBytes
|
||||
fs.MaxDiskReadBytes = max(fs.MaxDiskReadBytes, value.MaxDiskReadBytes, value.DiskReadBytes)
|
||||
fs.MaxDiskWriteBytes = max(fs.MaxDiskWriteBytes, value.MaxDiskWriteBytes, value.DiskWriteBytes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,6 +384,8 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *
|
||||
fs.DiskUsed = twoDecimals(fs.DiskUsed / count)
|
||||
fs.DiskWritePs = twoDecimals(fs.DiskWritePs / count)
|
||||
fs.DiskReadPs = twoDecimals(fs.DiskReadPs / count)
|
||||
fs.DiskReadBytes = fs.DiskReadBytes / uint64(count)
|
||||
fs.DiskWriteBytes = fs.DiskWriteBytes / uint64(count)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,6 +409,25 @@ func (rm *RecordManager) AverageSystemStats(db dbx.Builder, records RecordIds) *
|
||||
sum.GPUData[id] = gpu
|
||||
}
|
||||
}
|
||||
|
||||
// Average per-core usage
|
||||
if len(cpuCoresSums) > 0 {
|
||||
avg := make(system.Uint8Slice, len(cpuCoresSums))
|
||||
for i := range cpuCoresSums {
|
||||
v := math.Round(float64(cpuCoresSums[i]) / count)
|
||||
avg[i] = uint8(v)
|
||||
}
|
||||
sum.CpuCoresUsage = avg
|
||||
}
|
||||
|
||||
// Average CPU breakdown
|
||||
if len(cpuBreakdownSums) > 0 {
|
||||
avg := make([]float64, len(cpuBreakdownSums))
|
||||
for i := range cpuBreakdownSums {
|
||||
avg[i] = twoDecimals(cpuBreakdownSums[i] / count)
|
||||
}
|
||||
sum.CpuBreakdown = avg
|
||||
}
|
||||
}
|
||||
|
||||
return sum
|
||||
@@ -441,6 +490,10 @@ func (rm *RecordManager) DeleteOldRecords() {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = deleteOldSystemdServiceRecords(txApp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = deleteOldAlertsHistory(txApp, 200, 250)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -510,6 +563,20 @@ func deleteOldSystemStats(app core.App) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deletes systemd service records that haven't been updated in the last 20 minutes
|
||||
func deleteOldSystemdServiceRecords(app core.App) error {
|
||||
now := time.Now().UTC()
|
||||
twentyMinutesAgo := now.Add(-20 * time.Minute)
|
||||
|
||||
// Delete systemd service records where updated < twentyMinutesAgo
|
||||
_, err := app.DB().NewQuery("DELETE FROM systemd_services WHERE updated < {:updated}").Bind(dbx.Params{"updated": twentyMinutesAgo.UnixMilli()}).Execute()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete old systemd service records: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deletes container records that haven't been updated in the last 10 minutes
|
||||
func deleteOldContainerRecords(app core.App) error {
|
||||
now := time.Now().UTC()
|
||||
|
||||
@@ -351,6 +351,83 @@ func TestDeleteOldAlertsHistoryEdgeCases(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestDeleteOldSystemdServiceRecords tests systemd service cleanup via DeleteOldRecords
|
||||
func TestDeleteOldSystemdServiceRecords(t *testing.T) {
|
||||
hub, err := tests.NewTestHub(t.TempDir())
|
||||
require.NoError(t, err)
|
||||
defer hub.Cleanup()
|
||||
|
||||
rm := records.NewRecordManager(hub)
|
||||
|
||||
// Create test user and system
|
||||
user, err := tests.CreateUser(hub, "test@example.com", "testtesttest")
|
||||
require.NoError(t, err)
|
||||
|
||||
system, err := tests.CreateRecord(hub, "systems", map[string]any{
|
||||
"name": "test-system",
|
||||
"host": "localhost",
|
||||
"port": "45876",
|
||||
"status": "up",
|
||||
"users": []string{user.Id},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
// Create old systemd service records that should be deleted (older than 20 minutes)
|
||||
oldRecord, err := tests.CreateRecord(hub, "systemd_services", map[string]any{
|
||||
"system": system.Id,
|
||||
"name": "nginx.service",
|
||||
"state": 0, // Active
|
||||
"sub": 1, // Running
|
||||
"cpu": 5.0,
|
||||
"cpuPeak": 10.0,
|
||||
"memory": 1024000,
|
||||
"memPeak": 2048000,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
// Set updated time to 25 minutes ago (should be deleted)
|
||||
oldRecord.SetRaw("updated", now.Add(-25*time.Minute).UnixMilli())
|
||||
err = hub.SaveNoValidate(oldRecord)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create recent systemd service record that should be kept (within 20 minutes)
|
||||
recentRecord, err := tests.CreateRecord(hub, "systemd_services", map[string]any{
|
||||
"system": system.Id,
|
||||
"name": "apache.service",
|
||||
"state": 1, // Inactive
|
||||
"sub": 0, // Dead
|
||||
"cpu": 2.0,
|
||||
"cpuPeak": 3.0,
|
||||
"memory": 512000,
|
||||
"memPeak": 1024000,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
// Set updated time to 10 minutes ago (should be kept)
|
||||
recentRecord.SetRaw("updated", now.Add(-10*time.Minute).UnixMilli())
|
||||
err = hub.SaveNoValidate(recentRecord)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Count records before deletion
|
||||
countBefore, err := hub.CountRecords("systemd_services")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(2), countBefore, "Should have 2 systemd service records initially")
|
||||
|
||||
// Run deletion via RecordManager
|
||||
rm.DeleteOldRecords()
|
||||
|
||||
// Count records after deletion
|
||||
countAfter, err := hub.CountRecords("systemd_services")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(1), countAfter, "Should have 1 systemd service record after deletion")
|
||||
|
||||
// Verify the correct record was kept
|
||||
remainingRecords, err := hub.FindRecordsByFilter("systemd_services", "", "", 10, 0, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, remainingRecords, 1, "Should have exactly 1 record remaining")
|
||||
assert.Equal(t, "apache.service", remainingRecords[0].Get("name"), "The recent record should be kept")
|
||||
}
|
||||
|
||||
// TestRecordManagerCreation tests RecordManager creation
|
||||
func TestRecordManagerCreation(t *testing.T) {
|
||||
hub, err := tests.NewTestHub(t.TempDir())
|
||||
|
||||
@@ -11,10 +11,10 @@ export default defineConfig({
|
||||
"es",
|
||||
"fa",
|
||||
"fr",
|
||||
"he",
|
||||
"hr",
|
||||
"hu",
|
||||
"it",
|
||||
"is",
|
||||
"ja",
|
||||
"ko",
|
||||
"nl",
|
||||
|
||||
4
internal/site/package-lock.json
generated
4
internal/site/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "beszel",
|
||||
"version": "0.14.1",
|
||||
"version": "0.16.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "beszel",
|
||||
"version": "0.14.1",
|
||||
"version": "0.16.0",
|
||||
"dependencies": {
|
||||
"@henrygd/queue": "^1.0.7",
|
||||
"@henrygd/semaphore": "^0.0.2",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "beszel",
|
||||
"private": true,
|
||||
"version": "0.14.1",
|
||||
"version": "0.16.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
|
||||
@@ -26,7 +26,7 @@ export default memo(function AlertsButton({ system }: { system: SystemRecord })
|
||||
/>
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent className="max-h-full overflow-auto w-145 !max-w-full p-4 sm:p-6">
|
||||
<SheetContent className="max-h-full overflow-auto w-150 !max-w-full p-4 sm:p-6">
|
||||
{opened && <AlertDialogContent system={system} />}
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
|
||||
@@ -17,6 +17,7 @@ export type DataPoint = {
|
||||
dataKey: (data: SystemStatsRecord) => number | undefined
|
||||
color: number | string
|
||||
opacity: number
|
||||
stackId?: string | number
|
||||
}
|
||||
|
||||
export default function AreaChartDefault({
|
||||
@@ -29,19 +30,25 @@ export default function AreaChartDefault({
|
||||
domain,
|
||||
legend,
|
||||
itemSorter,
|
||||
showTotal = false,
|
||||
reverseStackOrder = false,
|
||||
hideYAxis = 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?: [number, number]
|
||||
legend?: boolean
|
||||
itemSorter?: (a: any, b: any) => number
|
||||
// logRender?: boolean
|
||||
}) {
|
||||
{
|
||||
chartData: ChartData
|
||||
max?: number
|
||||
maxToggled?: boolean
|
||||
tickFormatter: (value: number, index: number) => string
|
||||
contentFormatter: ({ value, payload }: { value: number; payload: SystemStatsRecord }) => string
|
||||
dataPoints?: DataPoint[]
|
||||
domain?: [number, number]
|
||||
legend?: boolean
|
||||
showTotal?: boolean
|
||||
itemSorter?: (a: any, b: any) => number
|
||||
reverseStackOrder?: boolean
|
||||
hideYAxis?: boolean
|
||||
// logRender?: boolean
|
||||
}) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: ignore
|
||||
@@ -56,21 +63,29 @@ export default function AreaChartDefault({
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
"opacity-100": yAxisWidth || hideYAxis,
|
||||
"ps-4": hideYAxis,
|
||||
})}
|
||||
>
|
||||
<AreaChart accessibilityLayer data={chartData.systemStats} margin={chartMargin}>
|
||||
<AreaChart
|
||||
reverseStackOrder={reverseStackOrder}
|
||||
accessibilityLayer
|
||||
data={chartData.systemStats}
|
||||
margin={hideYAxis ? { ...chartMargin, left: 5 } : chartMargin}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<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}
|
||||
/>
|
||||
{!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"
|
||||
@@ -81,6 +96,7 @@ export default function AreaChartDefault({
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={contentFormatter}
|
||||
showTotal={showTotal}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
@@ -99,13 +115,14 @@ export default function AreaChartDefault({
|
||||
fillOpacity={dataPoint.opacity}
|
||||
stroke={color}
|
||||
isAnimationActive={false}
|
||||
stackId={dataPoint.stackId}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{legend && <ChartLegend content={<ChartLegendContent />} />}
|
||||
{legend && <ChartLegend content={<ChartLegendContent reverse={reverseStackOrder} />} />}
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)
|
||||
}, [chartData.systemStats.at(-1), yAxisWidth, maxToggled])
|
||||
}, [chartData.systemStats.at(-1), yAxisWidth, maxToggled, showTotal])
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ export default memo(function ContainerChart({
|
||||
// tick formatter
|
||||
if (chartType === ChartType.CPU) {
|
||||
obj.tickFormatter = (value) => {
|
||||
const val = toFixedFloat(value, 2) + unit
|
||||
const val = `${toFixedFloat(value, 2)}%`
|
||||
return updateYAxisWidth(val)
|
||||
}
|
||||
} else {
|
||||
@@ -78,7 +78,7 @@ export default memo(function ContainerChart({
|
||||
return `${decimalString(value)} ${unit}`
|
||||
}
|
||||
} else {
|
||||
obj.toolTipFormatter = (item: any) => `${decimalString(item.value)} ${unit}`
|
||||
obj.toolTipFormatter = (item: any) => `${decimalString(item.value)}${unit}`
|
||||
}
|
||||
// data function
|
||||
if (isNetChart) {
|
||||
@@ -139,7 +139,7 @@ export default memo(function ContainerChart({
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
// @ts-expect-error
|
||||
itemSorter={(a, b) => b.value - a.value}
|
||||
content={<ChartTooltipContent filter={filter} contentFormatter={toolTipFormatter} />}
|
||||
content={<ChartTooltipContent filter={filter} contentFormatter={toolTipFormatter} showTotal={true} />}
|
||||
/>
|
||||
{Object.keys(chartConfig).map((key) => {
|
||||
const filtered = filteredKeys.has(key)
|
||||
|
||||
@@ -69,7 +69,7 @@ export function useContainerChartConfigs(containerData: ChartData["containerData
|
||||
const hue = ((i * 360) / count) % 360
|
||||
chartConfig[containerName] = {
|
||||
label: containerName,
|
||||
color: `hsl(${hue}, 60%, 55%)`,
|
||||
color: `hsl(${hue}, var(--chart-saturation), var(--chart-lightness))`,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ export default memo(function MemChart({ chartData, showMax }: { chartData: Chart
|
||||
const { value: convertedValue, unit } = formatBytes(value * 1024, false, Unit.Bytes, true)
|
||||
return decimalString(convertedValue, convertedValue >= 100 ? 1 : 2) + " " + unit
|
||||
}}
|
||||
showTotal={true}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -40,7 +40,7 @@ export const containerChartCols: ColumnDef<ContainerRecord>[] = [
|
||||
accessorFn: (record) => record.name,
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Name`} Icon={ContainerIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
return <span className="ms-1.5 xl:w-45 block truncate">{getValue() as string}</span>
|
||||
return <span className="ms-1.5 xl:w-48 block truncate">{getValue() as string}</span>
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -55,7 +55,7 @@ export const containerChartCols: ColumnDef<ContainerRecord>[] = [
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`System`} Icon={ServerIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
const allSystems = useStore($allSystemsById)
|
||||
return <span className="ms-1.5 xl:w-32 block truncate">{allSystems[getValue() as string]?.name ?? ""}</span>
|
||||
return <span className="ms-1.5 xl:w-34 block truncate">{allSystems[getValue() as string]?.name ?? ""}</span>
|
||||
},
|
||||
},
|
||||
// {
|
||||
@@ -131,7 +131,7 @@ export const containerChartCols: ColumnDef<ContainerRecord>[] = [
|
||||
accessorFn: (record) => record.image,
|
||||
header: ({ column }) => <HeaderButton column={column} name={t({ message: "Image", context: "Docker image" })} Icon={LayersIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
return <span className="ms-1.5 xl:w-36 block truncate">{getValue() as string}</span>
|
||||
return <span className="ms-1.5 xl:w-40 block truncate">{getValue() as string}</span>
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@ import { getPagePath } from "@nanostores/router"
|
||||
const syntaxTheme = "github-dark-dimmed"
|
||||
|
||||
export default function ContainersTable({ systemId }: { systemId?: string }) {
|
||||
const loadTime = Date.now()
|
||||
const [data, setData] = useState<ContainerRecord[]>([])
|
||||
const [sorting, setSorting] = useBrowserStorage<SortingState>(
|
||||
`sort-c-${systemId ? 1 : 0}`,
|
||||
@@ -47,55 +48,53 @@ export default function ContainersTable({ systemId }: { systemId?: string }) {
|
||||
const [globalFilter, setGlobalFilter] = useState("")
|
||||
|
||||
useEffect(() => {
|
||||
const pbOptions = {
|
||||
fields: "id,name,image,cpu,memory,net,health,status,system,updated",
|
||||
}
|
||||
|
||||
const fetchData = (lastXMs: number) => {
|
||||
const updated = Date.now() - lastXMs
|
||||
let filter: string
|
||||
if (systemId) {
|
||||
filter = pb.filter("system={:system} && updated > {:updated}", { system: systemId, updated })
|
||||
} else {
|
||||
filter = pb.filter("updated > {:updated}", { updated })
|
||||
}
|
||||
function fetchData(systemId?: string) {
|
||||
pb.collection<ContainerRecord>("containers")
|
||||
.getList(0, 2000, {
|
||||
...pbOptions,
|
||||
filter,
|
||||
fields: "id,name,image,cpu,memory,net,health,status,system,updated",
|
||||
filter: systemId ? pb.filter("system={:system}", { system: systemId }) : undefined,
|
||||
})
|
||||
.then(({ items }) => setData((curItems) => {
|
||||
const containerIds = new Set(items.map(item => item.id))
|
||||
const now = Date.now()
|
||||
for (const item of curItems) {
|
||||
if (!containerIds.has(item.id) && now - item.updated < 70_000) {
|
||||
items.push(item)
|
||||
.then(({ items }) => items.length && setData((curItems) => {
|
||||
const lastUpdated = Math.max(items[0].updated, items.at(-1)?.updated ?? 0)
|
||||
const containerIds = new Set()
|
||||
const newItems = []
|
||||
for (const item of items) {
|
||||
if (Math.abs(lastUpdated - item.updated) < 70_000) {
|
||||
containerIds.add(item.id)
|
||||
newItems.push(item)
|
||||
}
|
||||
}
|
||||
return items
|
||||
for (const item of curItems) {
|
||||
if (!containerIds.has(item.id) && lastUpdated - item.updated < 70_000) {
|
||||
newItems.push(item)
|
||||
}
|
||||
}
|
||||
return newItems
|
||||
}))
|
||||
}
|
||||
|
||||
// initial load
|
||||
fetchData(70_000)
|
||||
fetchData(systemId)
|
||||
|
||||
// if no systemId, poll every 10 seconds
|
||||
// if no systemId, pull system containers after every system update
|
||||
if (!systemId) {
|
||||
// poll every 10 seconds
|
||||
const intervalId = setInterval(() => fetchData(10_500), 10_000)
|
||||
// clear interval on unmount
|
||||
return () => clearInterval(intervalId)
|
||||
return $allSystemsById.listen((_value, _oldValue, systemId) => {
|
||||
// exclude initial load of systems
|
||||
if (Date.now() - loadTime > 500) {
|
||||
fetchData(systemId)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// if systemId, fetch containers after the system is updated
|
||||
return listenKeys($allSystemsById, [systemId], (_newSystems) => {
|
||||
setTimeout(() => fetchData(1000), 100)
|
||||
fetchData(systemId)
|
||||
})
|
||||
}, [])
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns: containerChartCols.filter(col => systemId ? col.id !== "system" : true),
|
||||
columns: containerChartCols.filter((col) => (systemId ? col.id !== "system" : true)),
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
@@ -163,78 +162,79 @@ export default function ContainersTable({ systemId }: { systemId?: string }) {
|
||||
)
|
||||
}
|
||||
|
||||
const AllContainersTable = memo(
|
||||
function AllContainersTable({ table, rows, colLength }: { table: TableType<ContainerRecord>; rows: Row<ContainerRecord>[]; colLength: number }) {
|
||||
// The virtualizer will need a reference to the scrollable container element
|
||||
const scrollRef = useRef<HTMLDivElement>(null)
|
||||
const activeContainer = useRef<ContainerRecord | null>(null)
|
||||
const [sheetOpen, setSheetOpen] = useState(false)
|
||||
const openSheet = (container: ContainerRecord) => {
|
||||
activeContainer.current = container
|
||||
setSheetOpen(true)
|
||||
}
|
||||
|
||||
const virtualizer = useVirtualizer<HTMLDivElement, HTMLTableRowElement>({
|
||||
count: rows.length,
|
||||
estimateSize: () => 54,
|
||||
getScrollElement: () => scrollRef.current,
|
||||
overscan: 5,
|
||||
})
|
||||
const virtualRows = virtualizer.getVirtualItems()
|
||||
|
||||
const paddingTop = Math.max(0, virtualRows[0]?.start ?? 0 - virtualizer.options.scrollMargin)
|
||||
const paddingBottom = Math.max(0, virtualizer.getTotalSize() - (virtualRows[virtualRows.length - 1]?.end ?? 0))
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-min max-h-[calc(100dvh-17rem)] max-w-full relative overflow-auto border rounded-md",
|
||||
// don't set min height if there are less than 2 rows, do set if we need to display the empty state
|
||||
(!rows.length || rows.length > 2) && "min-h-50"
|
||||
)}
|
||||
ref={scrollRef}
|
||||
>
|
||||
{/* add header height to table size */}
|
||||
<div style={{ height: `${virtualizer.getTotalSize() + 48}px`, paddingTop, paddingBottom }}>
|
||||
<table className="text-sm w-full h-full text-nowrap">
|
||||
<ContainersTableHead table={table} />
|
||||
<TableBody>
|
||||
{rows.length ? (
|
||||
virtualRows.map((virtualRow) => {
|
||||
const row = rows[virtualRow.index]
|
||||
return (
|
||||
<ContainerTableRow
|
||||
key={row.id}
|
||||
row={row}
|
||||
virtualRow={virtualRow}
|
||||
openSheet={openSheet}
|
||||
/>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={colLength} className="h-37 text-center pointer-events-none">
|
||||
<Trans>No results.</Trans>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</table>
|
||||
</div>
|
||||
<ContainerSheet sheetOpen={sheetOpen} setSheetOpen={setSheetOpen} activeContainer={activeContainer} />
|
||||
</div>
|
||||
)
|
||||
const AllContainersTable = memo(function AllContainersTable({
|
||||
table,
|
||||
rows,
|
||||
colLength,
|
||||
}: {
|
||||
table: TableType<ContainerRecord>
|
||||
rows: Row<ContainerRecord>[]
|
||||
colLength: number
|
||||
}) {
|
||||
// The virtualizer will need a reference to the scrollable container element
|
||||
const scrollRef = useRef<HTMLDivElement>(null)
|
||||
const activeContainer = useRef<ContainerRecord | null>(null)
|
||||
const [sheetOpen, setSheetOpen] = useState(false)
|
||||
const openSheet = (container: ContainerRecord) => {
|
||||
activeContainer.current = container
|
||||
setSheetOpen(true)
|
||||
}
|
||||
)
|
||||
|
||||
const virtualizer = useVirtualizer<HTMLDivElement, HTMLTableRowElement>({
|
||||
count: rows.length,
|
||||
estimateSize: () => 54,
|
||||
getScrollElement: () => scrollRef.current,
|
||||
overscan: 5,
|
||||
})
|
||||
const virtualRows = virtualizer.getVirtualItems()
|
||||
|
||||
const paddingTop = Math.max(0, virtualRows[0]?.start ?? 0 - virtualizer.options.scrollMargin)
|
||||
const paddingBottom = Math.max(0, virtualizer.getTotalSize() - (virtualRows[virtualRows.length - 1]?.end ?? 0))
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-min max-h-[calc(100dvh-17rem)] max-w-full relative overflow-auto border rounded-md",
|
||||
// don't set min height if there are less than 2 rows, do set if we need to display the empty state
|
||||
(!rows.length || rows.length > 2) && "min-h-50"
|
||||
)}
|
||||
ref={scrollRef}
|
||||
>
|
||||
{/* add header height to table size */}
|
||||
<div style={{ height: `${virtualizer.getTotalSize() + 48}px`, paddingTop, paddingBottom }}>
|
||||
<table className="text-sm w-full h-full text-nowrap">
|
||||
<ContainersTableHead table={table} />
|
||||
<TableBody>
|
||||
{rows.length ? (
|
||||
virtualRows.map((virtualRow) => {
|
||||
const row = rows[virtualRow.index]
|
||||
return <ContainerTableRow key={row.id} row={row} virtualRow={virtualRow} openSheet={openSheet} />
|
||||
})
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={colLength} className="h-37 text-center pointer-events-none">
|
||||
<Trans>No results.</Trans>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</table>
|
||||
</div>
|
||||
<ContainerSheet sheetOpen={sheetOpen} setSheetOpen={setSheetOpen} activeContainer={activeContainer} />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
async function getLogsHtml(container: ContainerRecord): Promise<string> {
|
||||
try {
|
||||
const [{ highlighter }, logsHtml] = await Promise.all([import('@/lib/shiki'), pb.send<{ logs: string }>("/api/beszel/containers/logs", {
|
||||
system: container.system,
|
||||
container: container.id,
|
||||
})])
|
||||
return highlighter.codeToHtml(logsHtml.logs, { lang: "log", theme: syntaxTheme })
|
||||
const [{ highlighter }, logsHtml] = await Promise.all([
|
||||
import("@/lib/shiki"),
|
||||
pb.send<{ logs: string }>("/api/beszel/containers/logs", {
|
||||
system: container.system,
|
||||
container: container.id,
|
||||
}),
|
||||
])
|
||||
return logsHtml.logs ? highlighter.codeToHtml(logsHtml.logs, { lang: "log", theme: syntaxTheme }) : t`No results.`
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return ""
|
||||
@@ -243,21 +243,32 @@ async function getLogsHtml(container: ContainerRecord): Promise<string> {
|
||||
|
||||
async function getInfoHtml(container: ContainerRecord): Promise<string> {
|
||||
try {
|
||||
let [{ highlighter }, { info }] = await Promise.all([import('@/lib/shiki'), pb.send<{ info: string }>("/api/beszel/containers/info", {
|
||||
system: container.system,
|
||||
container: container.id,
|
||||
})])
|
||||
let [{ highlighter }, { info }] = await Promise.all([
|
||||
import("@/lib/shiki"),
|
||||
pb.send<{ info: string }>("/api/beszel/containers/info", {
|
||||
system: container.system,
|
||||
container: container.id,
|
||||
}),
|
||||
])
|
||||
try {
|
||||
info = JSON.stringify(JSON.parse(info), null, 2)
|
||||
} catch (_) { }
|
||||
return highlighter.codeToHtml(info, { lang: "json", theme: syntaxTheme })
|
||||
return info ? highlighter.codeToHtml(info, { lang: "json", theme: syntaxTheme }) : t`No results.`
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
function ContainerSheet({ sheetOpen, setSheetOpen, activeContainer }: { sheetOpen: boolean, setSheetOpen: (open: boolean) => void, activeContainer: RefObject<ContainerRecord | null> }) {
|
||||
function ContainerSheet({
|
||||
sheetOpen,
|
||||
setSheetOpen,
|
||||
activeContainer,
|
||||
}: {
|
||||
sheetOpen: boolean
|
||||
setSheetOpen: (open: boolean) => void
|
||||
activeContainer: RefObject<ContainerRecord | null>
|
||||
}) {
|
||||
const container = activeContainer.current
|
||||
if (!container) return null
|
||||
|
||||
@@ -296,14 +307,14 @@ function ContainerSheet({ sheetOpen, setSheetOpen, activeContainer }: { sheetOpe
|
||||
|
||||
useEffect(() => {
|
||||
setLogsDisplay("")
|
||||
setInfoDisplay("");
|
||||
setInfoDisplay("")
|
||||
if (!container) return
|
||||
(async () => {
|
||||
const [logsHtml, infoHtml] = await Promise.all([getLogsHtml(container), getInfoHtml(container)])
|
||||
setLogsDisplay(logsHtml)
|
||||
setInfoDisplay(infoHtml)
|
||||
setTimeout(scrollLogsToBottom, 20)
|
||||
})()
|
||||
; (async () => {
|
||||
const [logsHtml, infoHtml] = await Promise.all([getLogsHtml(container), getInfoHtml(container)])
|
||||
setLogsDisplay(logsHtml)
|
||||
setInfoDisplay(infoHtml)
|
||||
setTimeout(scrollLogsToBottom, 20)
|
||||
})()
|
||||
}, [container])
|
||||
|
||||
return (
|
||||
@@ -327,7 +338,9 @@ function ContainerSheet({ sheetOpen, setSheetOpen, activeContainer }: { sheetOpe
|
||||
<SheetHeader>
|
||||
<SheetTitle>{container.name}</SheetTitle>
|
||||
<SheetDescription className="flex flex-wrap items-center gap-x-2 gap-y-1">
|
||||
<Link className="hover:underline" href={getPagePath($router, "system", { id: container.system })}>{$allSystemsById.get()[container.system]?.name ?? ""}</Link>
|
||||
<Link className="hover:underline" href={getPagePath($router, "system", { id: container.system })}>
|
||||
{$allSystemsById.get()[container.system]?.name ?? ""}
|
||||
</Link>
|
||||
<Separator orientation="vertical" className="h-2.5 bg-muted-foreground opacity-70" />
|
||||
{container.status}
|
||||
<Separator orientation="vertical" className="h-2.5 bg-muted-foreground opacity-70" />
|
||||
@@ -349,19 +362,20 @@ function ContainerSheet({ sheetOpen, setSheetOpen, activeContainer }: { sheetOpe
|
||||
disabled={isRefreshingLogs}
|
||||
>
|
||||
<RefreshCwIcon
|
||||
className={`size-4 transition-transform duration-300 ${isRefreshingLogs ? 'animate-spin' : ''}`}
|
||||
className={`size-4 transition-transform duration-300 ${isRefreshingLogs ? "animate-spin" : ""}`}
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setLogsFullscreenOpen(true)}
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<Button variant="ghost" size="sm" onClick={() => setLogsFullscreenOpen(true)} className="h-8 w-8 p-0">
|
||||
<MaximizeIcon className="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div ref={logsContainerRef} className={cn("max-h-[calc(50dvh-10rem)] w-full overflow-auto p-3 rounded-md bg-gh-dark text-sm", !logsDisplay && ["animate-pulse", "h-full"])}>
|
||||
<div
|
||||
ref={logsContainerRef}
|
||||
className={cn(
|
||||
"max-h-[calc(50dvh-10rem)] w-full overflow-auto p-3 rounded-md bg-gh-dark text-white text-sm",
|
||||
!logsDisplay && ["animate-pulse", "h-full"]
|
||||
)}
|
||||
>
|
||||
<div dangerouslySetInnerHTML={{ __html: logsDisplay }} />
|
||||
</div>
|
||||
<div className="flex items-center w-full">
|
||||
@@ -375,15 +389,18 @@ function ContainerSheet({ sheetOpen, setSheetOpen, activeContainer }: { sheetOpe
|
||||
<MaximizeIcon className="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className={cn("grow h-[calc(50dvh-4rem)] w-full overflow-auto p-3 rounded-md bg-gh-dark text-sm", !infoDisplay && "animate-pulse")}>
|
||||
<div
|
||||
className={cn(
|
||||
"grow h-[calc(50dvh-4rem)] w-full overflow-auto p-3 rounded-md bg-gh-dark text-white text-sm",
|
||||
!infoDisplay && "animate-pulse"
|
||||
)}
|
||||
>
|
||||
<div dangerouslySetInnerHTML={{ __html: infoDisplay }} />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
@@ -405,39 +422,51 @@ function ContainersTableHead({ table }: { table: TableType<ContainerRecord> }) {
|
||||
)
|
||||
}
|
||||
|
||||
const ContainerTableRow = memo(
|
||||
function ContainerTableRow({
|
||||
row,
|
||||
virtualRow,
|
||||
openSheet,
|
||||
}: {
|
||||
row: Row<ContainerRecord>
|
||||
virtualRow: VirtualItem
|
||||
openSheet: (container: ContainerRecord) => void
|
||||
}) {
|
||||
return (
|
||||
<TableRow
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
className="cursor-pointer transition-opacity"
|
||||
onClick={() => openSheet(row.original)}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
className="py-0"
|
||||
style={{
|
||||
height: virtualRow.size,
|
||||
}}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
)
|
||||
}
|
||||
)
|
||||
const ContainerTableRow = memo(function ContainerTableRow({
|
||||
row,
|
||||
virtualRow,
|
||||
openSheet,
|
||||
}: {
|
||||
row: Row<ContainerRecord>
|
||||
virtualRow: VirtualItem
|
||||
openSheet: (container: ContainerRecord) => void
|
||||
}) {
|
||||
return (
|
||||
<TableRow
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
className="cursor-pointer transition-opacity"
|
||||
onClick={() => openSheet(row.original)}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
className="py-0"
|
||||
style={{
|
||||
height: virtualRow.size,
|
||||
}}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
)
|
||||
})
|
||||
|
||||
function LogsFullscreenDialog({ open, onOpenChange, logsDisplay, containerName, onRefresh, isRefreshing }: { open: boolean, onOpenChange: (open: boolean) => void, logsDisplay: string, containerName: string, onRefresh: () => void | Promise<void>, isRefreshing: boolean }) {
|
||||
function LogsFullscreenDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
logsDisplay,
|
||||
containerName,
|
||||
onRefresh,
|
||||
isRefreshing,
|
||||
}: {
|
||||
open: boolean
|
||||
onOpenChange: (open: boolean) => void
|
||||
logsDisplay: string
|
||||
containerName: string
|
||||
onRefresh: () => void | Promise<void>
|
||||
isRefreshing: boolean
|
||||
}) {
|
||||
const outerContainerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -470,16 +499,24 @@ function LogsFullscreenDialog({ open, onOpenChange, logsDisplay, containerName,
|
||||
title={t`Refresh`}
|
||||
aria-label={t`Refresh`}
|
||||
>
|
||||
<RefreshCwIcon
|
||||
className={`size-4 transition-transform duration-300 ${isRefreshing ? 'animate-spin' : ''}`}
|
||||
/>
|
||||
<RefreshCwIcon className={`size-4 transition-transform duration-300 ${isRefreshing ? "animate-spin" : ""}`} />
|
||||
</button>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
function InfoFullscreenDialog({ open, onOpenChange, infoDisplay, containerName }: { open: boolean, onOpenChange: (open: boolean) => void, infoDisplay: string, containerName: string }) {
|
||||
function InfoFullscreenDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
infoDisplay,
|
||||
containerName,
|
||||
}: {
|
||||
open: boolean
|
||||
onOpenChange: (open: boolean) => void
|
||||
infoDisplay: string
|
||||
containerName: string
|
||||
}) {
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="w-[calc(100vw-20px)] h-[calc(100dvh-20px)] max-w-none p-0 bg-gh-dark border-0 text-white">
|
||||
|
||||
@@ -63,7 +63,7 @@ export default function ConfigYaml() {
|
||||
</Trans>
|
||||
</p>
|
||||
<Alert className="my-4 border-destructive text-destructive w-auto table md:pe-6">
|
||||
<AlertCircleIcon className="h-4 w-4 stroke-destructive" />
|
||||
<AlertCircleIcon className="size-4.5 stroke-destructive" />
|
||||
<AlertTitle>
|
||||
<Trans>Caution - potential data loss</Trans>
|
||||
</AlertTitle>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { Plural, Trans, useLingui } from "@lingui/react/macro"
|
||||
import { Trans, useLingui } from "@lingui/react/macro"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { getPagePath } from "@nanostores/router"
|
||||
import { timeTicks } from "d3-time"
|
||||
@@ -42,9 +42,9 @@ import {
|
||||
chartTimeData,
|
||||
cn,
|
||||
compareSemVer,
|
||||
debounce,
|
||||
decimalString,
|
||||
formatBytes,
|
||||
secondsToString,
|
||||
getHostDisplayValue,
|
||||
listen,
|
||||
parseSemVer,
|
||||
@@ -72,10 +72,9 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from ".
|
||||
import { Separator } from "../ui/separator"
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip"
|
||||
import NetworkSheet from "./system/network-sheet"
|
||||
import CpuCoresSheet from "./system/cpu-sheet"
|
||||
import LineChartDefault from "../charts/line-chart"
|
||||
|
||||
|
||||
|
||||
type ChartTimeData = {
|
||||
time: number
|
||||
data: {
|
||||
@@ -96,8 +95,8 @@ function getTimeData(chartTime: ChartTimes, lastCreated: number) {
|
||||
}
|
||||
}
|
||||
|
||||
const buffer = chartTime === "1m" ? 400 : 20_000
|
||||
const now = new Date(Date.now() + buffer)
|
||||
// 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 = {
|
||||
@@ -358,21 +357,13 @@ export default memo(function SystemDetail({ id }: { id: string }) {
|
||||
value: system.info.k,
|
||||
},
|
||||
}
|
||||
let uptime: React.ReactNode
|
||||
let uptime: string
|
||||
if (system.info.u < 3600) {
|
||||
uptime = (
|
||||
<Plural
|
||||
value={Math.trunc(system.info.u / 60)}
|
||||
one="# minute"
|
||||
few="# minutes"
|
||||
many="# minutes"
|
||||
other="# minutes"
|
||||
/>
|
||||
)
|
||||
} else if (system.info.u < 172800) {
|
||||
uptime = <Plural value={Math.trunc(system.info.u / 3600)} one="# hour" other="# hours" />
|
||||
uptime = secondsToString(system.info.u, "minute")
|
||||
} else if (system.info.u < 360000) {
|
||||
uptime = secondsToString(system.info.u, "hour")
|
||||
} else {
|
||||
uptime = <Plural value={Math.trunc(system.info?.u / 86400)} one="# day" other="# days" />
|
||||
uptime = secondsToString(system.info.u, "day")
|
||||
}
|
||||
return [
|
||||
{ value: getHostDisplayValue(system), Icon: GlobeIcon },
|
||||
@@ -592,7 +583,12 @@ export default memo(function SystemDetail({ id }: { id: string }) {
|
||||
grid={grid}
|
||||
title={t`CPU Usage`}
|
||||
description={t`Average system-wide CPU utilization`}
|
||||
cornerEl={maxValSelect}
|
||||
cornerEl={
|
||||
<div className="flex gap-2">
|
||||
{maxValSelect}
|
||||
<CpuCoresSheet chartData={chartData} dataEmpty={dataEmpty} grid={grid} maxValues={maxValues} />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
@@ -700,6 +696,7 @@ export default memo(function SystemDetail({ id }: { id: string }) {
|
||||
const { value: convertedValue, unit } = formatBytes(value, true, userSettings.unitDisk, false)
|
||||
return `${decimalString(convertedValue, convertedValue >= 100 ? 1 : 2)} ${unit}`
|
||||
}}
|
||||
showTotal={true}
|
||||
/>
|
||||
</ChartCard>
|
||||
|
||||
@@ -753,6 +750,7 @@ export default memo(function SystemDetail({ id }: { id: string }) {
|
||||
const { value, unit } = formatBytes(data.value, true, userSettings.unitNet, false)
|
||||
return `${decimalString(value, value >= 100 ? 1 : 2)} ${unit}`
|
||||
}}
|
||||
showTotal={true}
|
||||
/>
|
||||
</ChartCard>
|
||||
|
||||
@@ -965,9 +963,9 @@ export default memo(function SystemDetail({ id }: { id: string }) {
|
||||
label: t`Write`,
|
||||
dataKey: ({ stats }) => {
|
||||
if (showMax) {
|
||||
return stats?.efs?.[extraFsName]?.wb ?? (stats?.efs?.[extraFsName]?.wm ?? 0) * 1024 * 1024
|
||||
return stats?.efs?.[extraFsName]?.wbm || (stats?.efs?.[extraFsName]?.wm ?? 0) * 1024 * 1024
|
||||
}
|
||||
return stats?.efs?.[extraFsName]?.wb ?? (stats?.efs?.[extraFsName]?.w ?? 0) * 1024 * 1024
|
||||
return stats?.efs?.[extraFsName]?.wb || (stats?.efs?.[extraFsName]?.w ?? 0) * 1024 * 1024
|
||||
},
|
||||
color: 3,
|
||||
opacity: 0.3,
|
||||
@@ -1003,15 +1001,20 @@ export default memo(function SystemDetail({ id }: { id: string }) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{containerData.length > 0 && compareSemVer(chartData.agentVersion, parseSemVer("0.14.0")) >= 0 && (
|
||||
<LazyContainersTable systemId={id} />
|
||||
{compareSemVer(chartData.agentVersion, parseSemVer("0.15.0")) >= 0 && (
|
||||
<LazySmartTable systemId={system.id} />
|
||||
)}
|
||||
|
||||
<LazySmartTable systemId={system.id} />
|
||||
{containerData.length > 0 && compareSemVer(chartData.agentVersion, parseSemVer("0.14.0")) >= 0 && (
|
||||
<LazyContainersTable systemId={system.id} />
|
||||
)}
|
||||
|
||||
{system.info?.os === Os.Linux && compareSemVer(chartData.agentVersion, parseSemVer("0.16.0")) >= 0 && (
|
||||
<LazySystemdTable systemId={system.id} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* add space for tooltip if more than 12 containers */}
|
||||
{/* add space for tooltip if lots of sensors */}
|
||||
{bottomSpacing > 0 && <span className="block" style={{ height: bottomSpacing }} />}
|
||||
</>
|
||||
)
|
||||
@@ -1040,32 +1043,51 @@ function GpuEnginesChart({ chartData }: { chartData: ChartData }) {
|
||||
}
|
||||
|
||||
function FilterBar({ store = $containerFilter }: { store?: typeof $containerFilter }) {
|
||||
const containerFilter = useStore(store)
|
||||
const storeValue = useStore(store)
|
||||
const [inputValue, setInputValue] = useState(storeValue)
|
||||
const { t } = useLingui()
|
||||
|
||||
const debouncedStoreSet = useMemo(() => debounce((value: string) => store.set(value), 80), [store])
|
||||
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>) => debouncedStoreSet(e.target.value),
|
||||
[debouncedStoreSet]
|
||||
(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={containerFilter}
|
||||
value={inputValue}
|
||||
/>
|
||||
{containerFilter && (
|
||||
{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={() => store.set("")}
|
||||
onClick={handleClear}
|
||||
>
|
||||
<XIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
@@ -1125,7 +1147,7 @@ export function ChartCard({
|
||||
<CardDescription>{description}</CardDescription>
|
||||
{cornerEl && <div className="py-1 grid sm:justify-end sm:absolute sm:top-3.5 sm:end-3.5">{cornerEl}</div>}
|
||||
</CardHeader>
|
||||
<div className={cn("ps-0 w-[calc(100%-1.5em)] relative group", legend ? "h-54 md:h-56" : "h-48 md:h-52")}>
|
||||
<div className={cn("ps-0 w-[calc(100%-1.3em)] relative group", legend ? "h-54 md:h-56" : "h-48 md:h-52")}>
|
||||
{
|
||||
<Spinner
|
||||
msg={empty ? t`Waiting for enough records to display` : undefined}
|
||||
@@ -1144,7 +1166,7 @@ const ContainersTable = lazy(() => import("../containers-table/containers-table"
|
||||
function LazyContainersTable({ systemId }: { systemId: string }) {
|
||||
const { isIntersecting, ref } = useIntersectionObserver({ rootMargin: "90px" })
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<div ref={ref} className={cn(isIntersecting && "contents")}>
|
||||
{isIntersecting && <ContainersTable systemId={systemId} />}
|
||||
</div>
|
||||
)
|
||||
@@ -1153,10 +1175,21 @@ function LazyContainersTable({ systemId }: { systemId: string }) {
|
||||
const SmartTable = lazy(() => import("./system/smart-table"))
|
||||
|
||||
function LazySmartTable({ systemId }: { systemId: string }) {
|
||||
const { isIntersecting, ref } = useIntersectionObserver()
|
||||
const { isIntersecting, ref } = useIntersectionObserver({ rootMargin: "90px" })
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<div ref={ref} className={cn(isIntersecting && "contents")}>
|
||||
{isIntersecting && <SmartTable systemId={systemId} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const SystemdTable = lazy(() => import("../systemd-table/systemd-table"))
|
||||
|
||||
function LazySystemdTable({ systemId }: { systemId: string }) {
|
||||
const { isIntersecting, ref } = useIntersectionObserver()
|
||||
return (
|
||||
<div ref={ref} className={cn(isIntersecting && "contents")}>
|
||||
{isIntersecting && <SystemdTable systemId={systemId} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
195
internal/site/src/components/routes/system/cpu-sheet.tsx
Normal file
195
internal/site/src/components/routes/system/cpu-sheet.tsx
Normal file
@@ -0,0 +1,195 @@
|
||||
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 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"
|
||||
|
||||
const minAgentVersion = parseSemVer("0.15.3")
|
||||
|
||||
export default memo(function CpuCoresSheet({
|
||||
chartData,
|
||||
dataEmpty,
|
||||
grid,
|
||||
maxValues,
|
||||
}: {
|
||||
chartData: ChartData
|
||||
dataEmpty: boolean
|
||||
grid: boolean
|
||||
maxValues: boolean
|
||||
}) {
|
||||
const [cpuCoresOpen, setCpuCoresOpen] = useState(false)
|
||||
const hasOpened = useRef(false)
|
||||
|
||||
const supportsBreakdown = compareSemVer(chartData.agentVersion, minAgentVersion) >= 0
|
||||
|
||||
if (!supportsBreakdown) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (cpuCoresOpen && !hasOpened.current) {
|
||||
hasOpened.current = true
|
||||
}
|
||||
|
||||
// Latest stats snapshot
|
||||
const latest = chartData.systemStats.at(-1)?.stats
|
||||
const cpus = latest?.cpus ?? []
|
||||
const numCores = cpus.length
|
||||
const hasBreakdown = (latest?.cpub?.length ?? 0) > 0
|
||||
|
||||
const breakdownDataPoints = [
|
||||
{
|
||||
label: "System",
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.cpub?.[1],
|
||||
color: 3,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
},
|
||||
{
|
||||
label: "User",
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.cpub?.[0],
|
||||
color: 1,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
},
|
||||
{
|
||||
label: "IOWait",
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.cpub?.[2],
|
||||
color: 4,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
},
|
||||
{
|
||||
label: "Steal",
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.cpub?.[3],
|
||||
color: 5,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
},
|
||||
{
|
||||
label: "Idle",
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.cpub?.[4],
|
||||
color: 2,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
},
|
||||
{
|
||||
label: t`Other`,
|
||||
dataKey: ({ stats }: SystemStatsRecord) => {
|
||||
const total = stats?.cpub?.reduce((acc, curr) => acc + curr, 0) ?? 0
|
||||
return total > 0 ? 100 - total : null
|
||||
},
|
||||
color: `hsl(80, 65%, 52%)`,
|
||||
opacity: 0.35,
|
||||
stackId: "a"
|
||||
},
|
||||
] as DataPoint[]
|
||||
|
||||
|
||||
return (
|
||||
<Sheet open={cpuCoresOpen} onOpenChange={setCpuCoresOpen}>
|
||||
<DialogTitle className="sr-only">{t`CPU Usage`}</DialogTitle>
|
||||
<SheetTrigger asChild>
|
||||
<Button
|
||||
title={t`View more`}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="shrink-0 max-sm:absolute max-sm:top-3 max-sm:end-3"
|
||||
>
|
||||
<MoreHorizontalIcon />
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
{hasOpened.current && (
|
||||
<SheetContent aria-describedby={undefined} className="overflow-auto w-200 !max-w-full p-4 sm:p-6">
|
||||
<ChartTimeSelect className="w-[calc(100%-2em)] bg-card" agentVersion={chartData.agentVersion} />
|
||||
{hasBreakdown && (
|
||||
<ChartCard
|
||||
key="cpu-breakdown"
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`CPU Time Breakdown`}
|
||||
description={t`Percentage of time spent in each state`}
|
||||
legend={true}
|
||||
className="min-h-auto"
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
maxToggled={maxValues}
|
||||
legend={true}
|
||||
dataPoints={breakdownDataPoints}
|
||||
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
||||
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
||||
reverseStackOrder={true}
|
||||
itemSorter={() => 1}
|
||||
domain={[0, 100]}
|
||||
/>
|
||||
</ChartCard>
|
||||
)}
|
||||
|
||||
{numCores > 0 && (
|
||||
<ChartCard
|
||||
key="cpu-cores-all"
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`CPU Cores`}
|
||||
legend={numCores < 10}
|
||||
description={t`Per-core average utilization`}
|
||||
className="min-h-auto"
|
||||
>
|
||||
<AreaChartDefault
|
||||
hideYAxis={true}
|
||||
chartData={chartData}
|
||||
maxToggled={maxValues}
|
||||
legend={numCores < 10}
|
||||
dataPoints={Array.from({ length: numCores }).map((_, i) => ({
|
||||
label: `CPU ${i}`,
|
||||
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"
|
||||
}))}
|
||||
tickFormatter={(val) => `${val}%`}
|
||||
contentFormatter={({ value }) => `${value}%`}
|
||||
reverseStackOrder={true}
|
||||
itemSorter={() => 1}
|
||||
/>
|
||||
</ChartCard>
|
||||
)}
|
||||
|
||||
{Array.from({ length: numCores }).map((_, i) => (
|
||||
<ChartCard
|
||||
key={`cpu-core-${i}`}
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={`CPU ${i}`}
|
||||
description={t`Per-core average utilization`}
|
||||
legend={false}
|
||||
className="min-h-auto"
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
maxToggled={maxValues}
|
||||
legend={false}
|
||||
dataPoints={[
|
||||
{
|
||||
label: t`Usage`,
|
||||
dataKey: ({ stats }: SystemStatsRecord) => stats?.cpus?.[i],
|
||||
color: `hsl(${226 + (((i * 360) / Math.max(1, numCores)) % 360)}, 65%, 52%)`,
|
||||
opacity: 0.35,
|
||||
},
|
||||
]}
|
||||
tickFormatter={(val) => `${val}%`}
|
||||
contentFormatter={({ value }) => `${value}%`}
|
||||
/>
|
||||
</ChartCard>
|
||||
))}
|
||||
</SheetContent>
|
||||
)}
|
||||
</Sheet>
|
||||
)
|
||||
})
|
||||
@@ -53,7 +53,7 @@ export default memo(function NetworkSheet({
|
||||
</SheetTrigger>
|
||||
{hasOpened.current && (
|
||||
<SheetContent aria-describedby={undefined} className="overflow-auto w-200 !max-w-full p-4 sm:p-6">
|
||||
<ChartTimeSelect className="w-[calc(100%-2em)]" agentVersion={chartData.agentVersion} />
|
||||
<ChartTimeSelect className="w-[calc(100%-2em)] bg-card" agentVersion={chartData.agentVersion} />
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { t } from "@lingui/core/macro"
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
Column,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
@@ -23,9 +24,10 @@ import {
|
||||
TableRow,
|
||||
} from "@/components/ui/table"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { pb } from "@/lib/api"
|
||||
import { SmartData, SmartAttribute } from "@/types"
|
||||
import { formatBytes, toFixedFloat, formatTemperature } from "@/lib/utils"
|
||||
import { formatBytes, toFixedFloat, formatTemperature, cn, secondsToString } from "@/lib/utils"
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import { ThermometerIcon } from "@/components/ui/icons"
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||
@@ -36,10 +38,6 @@ export const smartColumns: ColumnDef<SmartAttribute>[] = [
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: "ID",
|
||||
cell: ({ getValue }) => {
|
||||
const id = getValue() as number | undefined
|
||||
return <div className="font-mono text-sm">{id?.toString() || ""}</div>
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.n,
|
||||
@@ -91,18 +89,25 @@ function formatCapacity(bytes: number): string {
|
||||
|
||||
// Function to convert SmartData to DiskInfo
|
||||
function convertSmartDataToDiskInfo(smartDataRecord: Record<string, SmartData>): DiskInfo[] {
|
||||
const unknown = "Unknown"
|
||||
return Object.entries(smartDataRecord).map(([key, smartData]) => ({
|
||||
device: smartData.dn || key,
|
||||
model: smartData.mn || "Unknown",
|
||||
serialNumber: smartData.sn || "Unknown",
|
||||
firmwareVersion: smartData.fv || "Unknown",
|
||||
capacity: smartData.c ? formatCapacity(smartData.c) : "Unknown",
|
||||
status: smartData.s || "Unknown",
|
||||
model: smartData.mn || unknown,
|
||||
serialNumber: smartData.sn || unknown,
|
||||
firmwareVersion: smartData.fv || unknown,
|
||||
capacity: smartData.c ? formatCapacity(smartData.c) : unknown,
|
||||
status: smartData.s || unknown,
|
||||
temperature: smartData.t || 0,
|
||||
deviceType: smartData.dt || "Unknown",
|
||||
deviceType: smartData.dt || unknown,
|
||||
// These fields need to be extracted from SmartAttribute if available
|
||||
powerOnHours: smartData.a?.find(attr => attr.n.toLowerCase().includes("poweronhours") || attr.n.toLowerCase().includes("power_on_hours"))?.rv,
|
||||
powerCycles: smartData.a?.find(attr => attr.n.toLowerCase().includes("power") && attr.n.toLowerCase().includes("cycle"))?.rv,
|
||||
powerOnHours: smartData.a?.find(attr => {
|
||||
const name = attr.n.toLowerCase();
|
||||
return name.includes("poweronhours") || name.includes("power_on_hours");
|
||||
})?.rv,
|
||||
powerCycles: smartData.a?.find(attr => {
|
||||
const name = attr.n.toLowerCase();
|
||||
return (name.includes("power") && name.includes("cycle")) || name.includes("startstopcycles");
|
||||
})?.rv,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -110,151 +115,136 @@ function convertSmartDataToDiskInfo(smartDataRecord: Record<string, SmartData>):
|
||||
export const columns: ColumnDef<DiskInfo>[] = [
|
||||
{
|
||||
accessorKey: "device",
|
||||
header: () => (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<HardDrive className="size-4" />
|
||||
<Trans>Device</Trans>
|
||||
</div>
|
||||
),
|
||||
sortingFn: (a, b) => a.original.device.localeCompare(b.original.device),
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Device`} Icon={HardDrive} />,
|
||||
cell: ({ row }) => (
|
||||
<div className="font-medium">{row.getValue("device")}</div>
|
||||
<div className="font-medium ms-1.5">{row.getValue("device")}</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "model",
|
||||
header: () => (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Box className="size-4" />
|
||||
<Trans>Model</Trans>
|
||||
</div>
|
||||
),
|
||||
sortingFn: (a, b) => a.original.model.localeCompare(b.original.model),
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Model`} Icon={Box} />,
|
||||
cell: ({ row }) => (
|
||||
<div className="max-w-50 truncate" title={row.getValue("model")}>
|
||||
<div className="max-w-50 truncate ms-1.5" title={row.getValue("model")}>
|
||||
{row.getValue("model")}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "capacity",
|
||||
header: () => (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<BinaryIcon className="size-4" />
|
||||
<Trans>Capacity</Trans>
|
||||
</div>
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Capacity`} Icon={BinaryIcon} />,
|
||||
cell: ({ getValue }) => (
|
||||
<span className="ms-1.5">{getValue() as string}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "temperature",
|
||||
header: () => (
|
||||
<div className="flex items-center gap-2">
|
||||
<ThermometerIcon className="size-4" />
|
||||
<Trans>Temp</Trans>
|
||||
</div>
|
||||
),
|
||||
invertSorting: true,
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Temp`} Icon={ThermometerIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
const { value, unit } = formatTemperature(getValue() as number)
|
||||
return `${value} ${unit}`
|
||||
return <span className="ms-1.5">{`${value} ${unit}`}</span>
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: () => (
|
||||
<div className="flex items-center gap-2">
|
||||
<Activity className="size-4" />
|
||||
<Trans>Status</Trans>
|
||||
</div>
|
||||
),
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Status`} Icon={Activity} />,
|
||||
cell: ({ getValue }) => {
|
||||
const status = getValue() as string
|
||||
return (
|
||||
<Badge
|
||||
variant={status === "PASSED" ? "success" : status === "FAILED" ? "danger" : "warning"}
|
||||
>
|
||||
{status}
|
||||
</Badge>
|
||||
<div className="ms-1.5">
|
||||
<Badge
|
||||
variant={status === "PASSED" ? "success" : status === "FAILED" ? "danger" : "warning"}
|
||||
>
|
||||
{status}
|
||||
</Badge>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "deviceType",
|
||||
header: () => (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<ArrowLeftRightIcon className="size-4" />
|
||||
<Trans>Type</Trans>
|
||||
</div>
|
||||
),
|
||||
sortingFn: (a, b) => a.original.deviceType.localeCompare(b.original.deviceType),
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Type`} Icon={ArrowLeftRightIcon} />,
|
||||
cell: ({ getValue }) => (
|
||||
<Badge variant="outline" className="uppercase">
|
||||
{getValue() as string}
|
||||
</Badge>
|
||||
<div className="ms-1.5">
|
||||
<Badge variant="outline" className="uppercase">
|
||||
{getValue() as string}
|
||||
</Badge>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "powerOnHours",
|
||||
header: () => (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Clock className="size-4" />
|
||||
<Trans comment="Power On Time">Power On</Trans>
|
||||
</div>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const hours = row.getValue("powerOnHours") as number | undefined
|
||||
invertSorting: true,
|
||||
header: ({ column }) => <HeaderButton column={column} name={t({ message: "Power On", comment: "Power On Time" })} Icon={Clock} />,
|
||||
cell: ({ getValue }) => {
|
||||
const hours = (getValue() ?? 0) as number
|
||||
if (!hours && hours !== 0) {
|
||||
return (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
<div className="text-sm text-muted-foreground ms-1.5">
|
||||
N/A
|
||||
</div>
|
||||
)
|
||||
}
|
||||
const days = Math.floor(hours / 24)
|
||||
const seconds = hours * 3600
|
||||
return (
|
||||
<div className="text-sm">
|
||||
<div>{hours.toLocaleString()} hours</div>
|
||||
<div className="text-muted-foreground text-xs">{days} days</div>
|
||||
<div className="text-sm ms-1.5">
|
||||
<div>{secondsToString(seconds, "hour")}</div>
|
||||
<div className="text-muted-foreground text-xs">{secondsToString(seconds, "day")}</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "powerCycles",
|
||||
header: () => (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<RotateCwIcon className="size-4" />
|
||||
<Trans comment="Power Cycles">Cycles</Trans>
|
||||
</div>
|
||||
),
|
||||
invertSorting: true,
|
||||
header: ({ column }) => <HeaderButton column={column} name={t({ message: "Cycles", comment: "Power Cycles" })} Icon={RotateCwIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
const cycles = getValue() as number | undefined
|
||||
if (!cycles && cycles !== 0) {
|
||||
return (
|
||||
<div className="text-muted-foreground">
|
||||
<div className="text-muted-foreground ms-1.5">
|
||||
N/A
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return cycles
|
||||
return <span className="ms-1.5">{cycles}</span>
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "serialNumber",
|
||||
header: () => (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<HashIcon className="size-4" />
|
||||
<Trans>Serial Number</Trans>
|
||||
</div>
|
||||
sortingFn: (a, b) => a.original.serialNumber.localeCompare(b.original.serialNumber),
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Serial Number`} Icon={HashIcon} />,
|
||||
cell: ({ getValue }) => (
|
||||
<span className="ms-1.5">{getValue() as string}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "firmwareVersion",
|
||||
header: () => (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<CpuIcon className="size-4" />
|
||||
<Trans>Firmware</Trans>
|
||||
</div>
|
||||
sortingFn: (a, b) => a.original.firmwareVersion.localeCompare(b.original.firmwareVersion),
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Firmware`} Icon={CpuIcon} />,
|
||||
cell: ({ getValue }) => (
|
||||
<span className="ms-1.5">{getValue() as string}</span>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
function HeaderButton({ column, name, Icon }: { column: Column<DiskInfo>; name: string; Icon: React.ElementType }) {
|
||||
const isSorted = column.getIsSorted()
|
||||
return (
|
||||
<Button
|
||||
className={cn("h-9 px-3 flex items-center gap-2 duration-50", isSorted && "bg-accent/70 light:bg-accent text-accent-foreground/90")}
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||
>
|
||||
{Icon && <Icon className="size-4" />}
|
||||
{name}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
export default function DisksTable({ systemId }: { systemId: string }) {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([{ id: "device", desc: false }])
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
|
||||
@@ -301,6 +291,10 @@ export default function DisksTable({ systemId }: { systemId: string }) {
|
||||
},
|
||||
})
|
||||
|
||||
if (!diskData.length && !columnFilters.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Card className="p-6 @container w-full">
|
||||
@@ -331,7 +325,7 @@ export default function DisksTable({ systemId }: { systemId: string }) {
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
<TableHead key={header.id} className="px-2">
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
@@ -354,7 +348,7 @@ export default function DisksTable({ systemId }: { systemId: string }) {
|
||||
onClick={() => openSheet(row.original)}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
<TableCell key={cell.id} className="md:ps-5">
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
@@ -378,7 +372,7 @@ export default function DisksTable({ systemId }: { systemId: string }) {
|
||||
</Table>
|
||||
</div>
|
||||
</Card>
|
||||
<DiskSheet disk={activeDisk} smartData={activeDisk && smartData ? Object.values(smartData).find(sd => sd.dn === activeDisk.device || sd.mn === activeDisk.model) : undefined} open={sheetOpen} onOpenChange={setSheetOpen} />
|
||||
<DiskSheet disk={activeDisk} smartData={smartData?.[activeDisk?.serialNumber ?? ""]} open={sheetOpen} onOpenChange={setSheetOpen} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -386,8 +380,6 @@ export default function DisksTable({ systemId }: { systemId: string }) {
|
||||
function DiskSheet({ disk, smartData, open, onOpenChange }: { disk: DiskInfo | null; smartData?: SmartData; open: boolean; onOpenChange: (open: boolean) => void }) {
|
||||
if (!disk) return null
|
||||
|
||||
const [sorting, setSorting] = React.useState<SortingState>([{ id: "id", desc: false }])
|
||||
|
||||
const smartAttributes = smartData?.a || []
|
||||
|
||||
// Find all attributes where when failed is not empty
|
||||
@@ -411,11 +403,6 @@ function DiskSheet({ disk, smartData, open, onOpenChange }: { disk: DiskInfo | n
|
||||
data: smartAttributes,
|
||||
columns: visibleColumns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
onSortingChange: setSorting,
|
||||
state: {
|
||||
sorting,
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
import type { Column, ColumnDef } from "@tanstack/react-table"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { cn, decimalString, formatBytes, hourWithSeconds } from "@/lib/utils"
|
||||
import type { SystemdRecord } from "@/types"
|
||||
import { ServiceStatus, ServiceStatusLabels, ServiceSubState, ServiceSubStateLabels } from "@/lib/enums"
|
||||
import {
|
||||
ActivityIcon,
|
||||
ArrowUpDownIcon,
|
||||
ClockIcon,
|
||||
CpuIcon,
|
||||
MemoryStickIcon,
|
||||
TerminalSquareIcon,
|
||||
} from "lucide-react"
|
||||
import { Badge } from "../ui/badge"
|
||||
import { t } from "@lingui/core/macro"
|
||||
// import { $allSystemsById } from "@/lib/stores"
|
||||
// import { useStore } from "@nanostores/react"
|
||||
|
||||
function getSubStateColor(subState: ServiceSubState) {
|
||||
switch (subState) {
|
||||
case ServiceSubState.Running:
|
||||
return "bg-green-500"
|
||||
case ServiceSubState.Failed:
|
||||
return "bg-red-500"
|
||||
case ServiceSubState.Dead:
|
||||
return "bg-yellow-500"
|
||||
default:
|
||||
return "bg-zinc-500"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const systemdTableCols: ColumnDef<SystemdRecord>[] = [
|
||||
{
|
||||
id: "name",
|
||||
sortingFn: (a, b) => a.original.name.localeCompare(b.original.name),
|
||||
accessorFn: (record) => record.name,
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Name`} Icon={TerminalSquareIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
return <span className="ms-1.5 xl:w-50 block truncate">{getValue() as string}</span>
|
||||
},
|
||||
},
|
||||
// {
|
||||
// id: "system",
|
||||
// accessorFn: (record) => record.system,
|
||||
// sortingFn: (a, b) => {
|
||||
// const allSystems = $allSystemsById.get()
|
||||
// const systemNameA = allSystems[a.original.system]?.name ?? ""
|
||||
// const systemNameB = allSystems[b.original.system]?.name ?? ""
|
||||
// return systemNameA.localeCompare(systemNameB)
|
||||
// },
|
||||
// header: ({ column }) => <HeaderButton column={column} name={t`System`} Icon={ServerIcon} />,
|
||||
// cell: ({ getValue }) => {
|
||||
// const allSystems = useStore($allSystemsById)
|
||||
// return <span className="ms-1.5 xl:w-34 block truncate">{allSystems[getValue() as string]?.name ?? ""}</span>
|
||||
// },
|
||||
// },
|
||||
{
|
||||
id: "state",
|
||||
accessorFn: (record) => record.state,
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`State`} Icon={ActivityIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
const statusValue = getValue() as ServiceStatus
|
||||
const statusLabel = ServiceStatusLabels[statusValue] || "Unknown"
|
||||
return (
|
||||
<Badge variant="outline" className="dark:border-white/12">
|
||||
<span className={cn("size-2 me-1.5 rounded-full", getStatusColor(statusValue))} />
|
||||
{statusLabel}
|
||||
</Badge>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "sub",
|
||||
accessorFn: (record) => record.sub,
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Sub State`} Icon={ActivityIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
const subState = getValue() as ServiceSubState
|
||||
const subStateLabel = ServiceSubStateLabels[subState] || "Unknown"
|
||||
return (
|
||||
<Badge variant="outline" className="dark:border-white/12 text-xs capitalize">
|
||||
<span className={cn("size-2 me-1.5 rounded-full", getSubStateColor(subState))} />
|
||||
{subStateLabel}
|
||||
</Badge>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "cpu",
|
||||
accessorFn: (record) => {
|
||||
if (record.sub !== ServiceSubState.Running) {
|
||||
return -1
|
||||
}
|
||||
return record.cpu
|
||||
},
|
||||
invertSorting: true,
|
||||
header: ({ column }) => <HeaderButton column={column} name={`${t`CPU`} (10m)`} Icon={CpuIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
const val = getValue() as number
|
||||
if (val < 0) {
|
||||
return <span className="ms-1.5 text-muted-foreground">N/A</span>
|
||||
}
|
||||
return <span className="ms-1.5 tabular-nums">{`${decimalString(val, val >= 10 ? 1 : 2)}%`}</span>
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "cpuPeak",
|
||||
accessorFn: (record) => {
|
||||
if (record.sub !== ServiceSubState.Running) {
|
||||
return -1
|
||||
}
|
||||
return record.cpuPeak ?? 0
|
||||
},
|
||||
invertSorting: true,
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`CPU Peak`} Icon={CpuIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
const val = getValue() as number
|
||||
if (val < 0) {
|
||||
return <span className="ms-1.5 text-muted-foreground">N/A</span>
|
||||
}
|
||||
return <span className="ms-1.5 tabular-nums">{`${decimalString(val, val >= 10 ? 1 : 2)}%`}</span>
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "memory",
|
||||
accessorFn: (record) => record.memory,
|
||||
invertSorting: true,
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Memory`} Icon={MemoryStickIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
const val = getValue() as number
|
||||
if (!val) {
|
||||
return <span className="ms-1.5 text-muted-foreground">N/A</span>
|
||||
}
|
||||
const formatted = formatBytes(val, false, undefined, false)
|
||||
return (
|
||||
<span className="ms-1.5 tabular-nums">{`${decimalString(formatted.value, formatted.value >= 10 ? 1 : 2)} ${formatted.unit}`}</span>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "memPeak",
|
||||
accessorFn: (record) => record.memPeak,
|
||||
invertSorting: true,
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Memory Peak`} Icon={MemoryStickIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
const val = getValue() as number
|
||||
if (!val) {
|
||||
return <span className="ms-1.5 text-muted-foreground">N/A</span>
|
||||
}
|
||||
const formatted = formatBytes(val, false, undefined, false)
|
||||
return (
|
||||
<span className="ms-1.5 tabular-nums">{`${decimalString(formatted.value, formatted.value >= 10 ? 1 : 2)} ${formatted.unit}`}</span>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "updated",
|
||||
invertSorting: true,
|
||||
accessorFn: (record) => record.updated,
|
||||
header: ({ column }) => <HeaderButton column={column} name={t`Updated`} Icon={ClockIcon} />,
|
||||
cell: ({ getValue }) => {
|
||||
const timestamp = getValue() as number
|
||||
return (
|
||||
<span className="ms-1.5 tabular-nums">
|
||||
{hourWithSeconds(new Date(timestamp).toISOString())}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
function HeaderButton({ column, name, Icon }: { column: Column<SystemdRecord>; name: string; Icon: React.ElementType }) {
|
||||
const isSorted = column.getIsSorted()
|
||||
return (
|
||||
<Button
|
||||
className={cn("h-9 px-3 flex items-center gap-2 duration-50", isSorted && "bg-accent/70 light:bg-accent text-accent-foreground/90")}
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||
>
|
||||
{Icon && <Icon className="size-4" />}
|
||||
{name}
|
||||
<ArrowUpDownIcon className="size-4" />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
export function getStatusColor(status: ServiceStatus) {
|
||||
switch (status) {
|
||||
case ServiceStatus.Active:
|
||||
return "bg-green-500"
|
||||
case ServiceStatus.Failed:
|
||||
return "bg-red-500"
|
||||
case ServiceStatus.Reloading:
|
||||
case ServiceStatus.Activating:
|
||||
case ServiceStatus.Deactivating:
|
||||
return "bg-yellow-500"
|
||||
default:
|
||||
return "bg-zinc-500"
|
||||
}
|
||||
}
|
||||
667
internal/site/src/components/systemd-table/systemd-table.tsx
Normal file
667
internal/site/src/components/systemd-table/systemd-table.tsx
Normal file
@@ -0,0 +1,667 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import {
|
||||
type ColumnFiltersState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getSortedRowModel,
|
||||
type Row,
|
||||
type SortingState,
|
||||
type Table as TableType,
|
||||
useReactTable,
|
||||
type VisibilityState,
|
||||
} from "@tanstack/react-table"
|
||||
import { useVirtualizer, type VirtualItem } from "@tanstack/react-virtual"
|
||||
import { LoaderCircleIcon } from "lucide-react"
|
||||
import { listenKeys } from "nanostores"
|
||||
import { memo, type ReactNode, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { getStatusColor, systemdTableCols } from "@/components/systemd-table/systemd-table-columns"
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||
import { Card, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Sheet, SheetContent, SheetHeader, SheetTitle } from "@/components/ui/sheet"
|
||||
import { TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||
import { pb } from "@/lib/api"
|
||||
import { ServiceStatus, ServiceStatusLabels, type ServiceSubState, ServiceSubStateLabels } from "@/lib/enums"
|
||||
import { $allSystemsById } from "@/lib/stores"
|
||||
import { cn, decimalString, formatBytes, useBrowserStorage } from "@/lib/utils"
|
||||
import type { SystemdRecord, SystemdServiceDetails } from "@/types"
|
||||
import { Separator } from "../ui/separator"
|
||||
|
||||
export default function SystemdTable({ systemId }: { systemId?: string }) {
|
||||
const loadTime = Date.now()
|
||||
const [data, setData] = useState<SystemdRecord[]>([])
|
||||
const [sorting, setSorting] = useBrowserStorage<SortingState>(
|
||||
`sort-sd-${systemId ? 1 : 0}`,
|
||||
[{ id: systemId ? "name" : "system", desc: false }],
|
||||
sessionStorage
|
||||
)
|
||||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
|
||||
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
|
||||
const [globalFilter, setGlobalFilter] = useState("")
|
||||
|
||||
// clear old data when systemId changes
|
||||
useEffect(() => {
|
||||
return setData([])
|
||||
}, [systemId])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const lastUpdated = data[0]?.updated ?? 0
|
||||
|
||||
function fetchData(systemId?: string) {
|
||||
pb.collection<SystemdRecord>("systemd_services")
|
||||
.getList(0, 2000, {
|
||||
fields: "name,state,sub,cpu,cpuPeak,memory,memPeak,updated",
|
||||
filter: systemId ? pb.filter("system={:system}", { system: systemId }) : undefined,
|
||||
})
|
||||
.then(
|
||||
({ items }) =>
|
||||
items.length &&
|
||||
setData((curItems) => {
|
||||
const lastUpdated = Math.max(items[0].updated, items.at(-1)?.updated ?? 0)
|
||||
const systemdNames = new Set()
|
||||
const newItems: SystemdRecord[] = []
|
||||
for (const item of items) {
|
||||
if (Math.abs(lastUpdated - item.updated) < 70_000) {
|
||||
systemdNames.add(item.name)
|
||||
newItems.push(item)
|
||||
}
|
||||
}
|
||||
for (const item of curItems) {
|
||||
if (!systemdNames.has(item.name) && lastUpdated - item.updated < 70_000) {
|
||||
newItems.push(item)
|
||||
}
|
||||
}
|
||||
return newItems
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
// initial load
|
||||
fetchData(systemId)
|
||||
|
||||
// if no systemId, pull system containers after every system update
|
||||
if (!systemId) {
|
||||
return $allSystemsById.listen((_value, _oldValue, systemId) => {
|
||||
// exclude initial load of systems
|
||||
if (Date.now() - loadTime > 500) {
|
||||
fetchData(systemId)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// if systemId, fetch containers after the system is updated
|
||||
return listenKeys($allSystemsById, [systemId], (_newSystems) => {
|
||||
// don't fetch data if the last update is less than 9.5 minutes
|
||||
if (lastUpdated > Date.now() - 9.5 * 60 * 1000) {
|
||||
return
|
||||
}
|
||||
fetchData(systemId)
|
||||
})
|
||||
}, [systemId])
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
// columns: systemdTableCols.filter((col) => (systemId ? col.id !== "system" : true)),
|
||||
columns: systemdTableCols,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
defaultColumn: {
|
||||
sortUndefined: "last",
|
||||
size: 100,
|
||||
minSize: 0,
|
||||
},
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
globalFilter,
|
||||
},
|
||||
onGlobalFilterChange: setGlobalFilter,
|
||||
globalFilterFn: (row, _columnId, filterValue) => {
|
||||
const service = row.original
|
||||
const systemName = $allSystemsById.get()[service.system]?.name ?? ""
|
||||
const name = service.name ?? ""
|
||||
const statusLabel = ServiceStatusLabels[service.state as ServiceStatus] ?? ""
|
||||
const subState = service.sub ?? ""
|
||||
const searchString = `${systemName} ${name} ${statusLabel} ${subState}`.toLowerCase()
|
||||
|
||||
return (filterValue as string)
|
||||
.toLowerCase()
|
||||
.split(" ")
|
||||
.every((term) => searchString.includes(term))
|
||||
},
|
||||
})
|
||||
|
||||
const rows = table.getRowModel().rows
|
||||
const visibleColumns = table.getVisibleLeafColumns()
|
||||
|
||||
const statusTotals = useMemo(() => {
|
||||
const totals = [0, 0, 0, 0, 0, 0]
|
||||
for (const service of data) {
|
||||
totals[service.state]++
|
||||
}
|
||||
return totals
|
||||
}, [data])
|
||||
|
||||
if (!data.length && !globalFilter) {
|
||||
return null
|
||||
}
|
||||
|
||||
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">
|
||||
<div className="px-2 sm:px-1">
|
||||
<CardTitle className="mb-2">
|
||||
<Trans>Systemd Services</Trans>
|
||||
</CardTitle>
|
||||
<CardDescription className="flex items-center">
|
||||
<Trans>Total: {data.length}</Trans>
|
||||
<Separator orientation="vertical" className="h-4 mx-2 bg-primary/40" />
|
||||
<Trans>Failed: {statusTotals[ServiceStatus.Failed]}</Trans>
|
||||
<Separator orientation="vertical" className="h-4 mx-2 bg-primary/40" />
|
||||
<Trans>Updated every 10 minutes.</Trans>
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Input
|
||||
placeholder={t`Filter...`}
|
||||
value={globalFilter}
|
||||
onChange={(e) => setGlobalFilter(e.target.value)}
|
||||
className="ms-auto px-4 w-full max-w-full md:w-64"
|
||||
/>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<div className="rounded-md">
|
||||
<AllSystemdTable table={table} rows={rows} colLength={visibleColumns.length} systemId={systemId} />
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
const AllSystemdTable = memo(function AllSystemdTable({
|
||||
table,
|
||||
rows,
|
||||
colLength,
|
||||
systemId,
|
||||
}: {
|
||||
table: TableType<SystemdRecord>
|
||||
rows: Row<SystemdRecord>[]
|
||||
colLength: number
|
||||
systemId?: string
|
||||
}) {
|
||||
// The virtualizer will need a reference to the scrollable container element
|
||||
const scrollRef = useRef<HTMLDivElement>(null)
|
||||
const activeService = useRef<SystemdRecord | null>(null)
|
||||
const [sheetOpen, setSheetOpen] = useState(false)
|
||||
const openSheet = (service: SystemdRecord) => {
|
||||
activeService.current = service
|
||||
setSheetOpen(true)
|
||||
}
|
||||
|
||||
const virtualizer = useVirtualizer<HTMLDivElement, HTMLTableRowElement>({
|
||||
count: rows.length,
|
||||
estimateSize: () => 54,
|
||||
getScrollElement: () => scrollRef.current,
|
||||
overscan: 5,
|
||||
})
|
||||
const virtualRows = virtualizer.getVirtualItems()
|
||||
|
||||
const paddingTop = Math.max(0, virtualRows[0]?.start ?? 0 - virtualizer.options.scrollMargin)
|
||||
const paddingBottom = Math.max(0, virtualizer.getTotalSize() - (virtualRows[virtualRows.length - 1]?.end ?? 0))
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-min max-h-[calc(100dvh-17rem)] max-w-full relative overflow-auto border rounded-md",
|
||||
// don't set min height if there are less than 2 rows, do set if we need to display the empty state
|
||||
(!rows.length || rows.length > 2) && "min-h-50"
|
||||
)}
|
||||
ref={scrollRef}
|
||||
>
|
||||
{/* add header height to table size */}
|
||||
<div style={{ height: `${virtualizer.getTotalSize() + 48}px`, paddingTop, paddingBottom }}>
|
||||
<table className="text-sm w-full h-full text-nowrap">
|
||||
<SystemdTableHead table={table} />
|
||||
<TableBody>
|
||||
{rows.length ? (
|
||||
virtualRows.map((virtualRow) => {
|
||||
const row = rows[virtualRow.index]
|
||||
return <SystemdTableRow key={row.id} row={row} virtualRow={virtualRow} openSheet={openSheet} />
|
||||
})
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={colLength} className="h-37 text-center pointer-events-none">
|
||||
<Trans>No results.</Trans>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</table>
|
||||
</div>
|
||||
<SystemdSheet
|
||||
sheetOpen={sheetOpen}
|
||||
setSheetOpen={setSheetOpen}
|
||||
activeService={activeService}
|
||||
systemId={systemId}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
function SystemdSheet({
|
||||
sheetOpen,
|
||||
setSheetOpen,
|
||||
activeService,
|
||||
systemId,
|
||||
}: {
|
||||
sheetOpen: boolean
|
||||
setSheetOpen: (open: boolean) => void
|
||||
activeService: React.RefObject<SystemdRecord | null>
|
||||
systemId?: string
|
||||
}) {
|
||||
const service = activeService.current
|
||||
const [details, setDetails] = useState<SystemdServiceDetails | null>(null)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (!sheetOpen || !service) {
|
||||
return
|
||||
}
|
||||
|
||||
setError(null)
|
||||
|
||||
let cancelled = false
|
||||
setDetails(null)
|
||||
setIsLoading(true)
|
||||
|
||||
pb.send<{ details: SystemdServiceDetails }>("/api/beszel/systemd/info", {
|
||||
query: {
|
||||
system: systemId,
|
||||
service: service.name,
|
||||
},
|
||||
})
|
||||
.then(({ details }) => {
|
||||
if (cancelled) return
|
||||
if (details) {
|
||||
setDetails(details)
|
||||
} else {
|
||||
setDetails(null)
|
||||
setError(t`No results found.`)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (cancelled) return
|
||||
setError(err?.message ?? "Failed to load service details")
|
||||
setDetails(null)
|
||||
})
|
||||
.finally(() => {
|
||||
if (!cancelled) {
|
||||
setIsLoading(false)
|
||||
}
|
||||
})
|
||||
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [sheetOpen, service, systemId])
|
||||
|
||||
if (!service) return null
|
||||
|
||||
const statusLabel = ServiceStatusLabels[service.state as ServiceStatus] ?? ""
|
||||
const subStateLabel = ServiceSubStateLabels[service.sub as ServiceSubState] ?? ""
|
||||
|
||||
const notAvailable = <span className="text-muted-foreground">N/A</span>
|
||||
|
||||
const formatMemory = (value?: number | null) => {
|
||||
if (value === undefined || value === null) {
|
||||
return value === null ? t`Unlimited` : undefined
|
||||
}
|
||||
const { value: convertedValue, unit } = formatBytes(value, false, undefined, false)
|
||||
const digits = convertedValue >= 10 ? 1 : 2
|
||||
return `${decimalString(convertedValue, digits)} ${unit}`
|
||||
}
|
||||
|
||||
const formatCpuTime = (ns?: number) => {
|
||||
if (!ns) return undefined
|
||||
const seconds = ns / 1_000_000_000
|
||||
if (seconds >= 3600) {
|
||||
const hours = Math.floor(seconds / 3600)
|
||||
const minutes = Math.floor((seconds % 3600) / 60)
|
||||
const secs = Math.floor(seconds % 60)
|
||||
return [hours ? `${hours}h` : null, minutes ? `${minutes}m` : null, secs ? `${secs}s` : null]
|
||||
.filter(Boolean)
|
||||
.join(" ")
|
||||
}
|
||||
if (seconds >= 60) {
|
||||
const minutes = Math.floor(seconds / 60)
|
||||
const secs = Math.floor(seconds % 60)
|
||||
return `${minutes}m ${secs}s`
|
||||
}
|
||||
if (seconds >= 1) {
|
||||
return `${decimalString(seconds, 2)}s`
|
||||
}
|
||||
return `${decimalString(seconds * 1000, 2)}ms`
|
||||
}
|
||||
|
||||
const formatTasks = (current?: number, max?: number) => {
|
||||
const hasCurrent = typeof current === "number" && current >= 0
|
||||
const hasMax = typeof max === "number" && max > 0 && max !== null
|
||||
if (!hasCurrent && !hasMax) {
|
||||
return undefined
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{hasCurrent ? current : notAvailable}
|
||||
{hasMax && (
|
||||
<span className="text-muted-foreground ms-1.5">
|
||||
{`(${t`limit`}: ${max})`}
|
||||
</span>
|
||||
)}
|
||||
{max === null && (
|
||||
<span className="text-muted-foreground ms-1.5">
|
||||
{`(${t`limit`}: ${t`Unlimited`.toLowerCase()})`}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const formatTimestamp = (timestamp?: number) => {
|
||||
if (!timestamp) return undefined
|
||||
// systemd timestamps are in microseconds, convert to milliseconds for JavaScript Date
|
||||
const date = new Date(timestamp / 1000)
|
||||
if (Number.isNaN(date.getTime())) return undefined
|
||||
return date.toLocaleString()
|
||||
}
|
||||
|
||||
const activeStateValue = (() => {
|
||||
const stateText = details?.ActiveState
|
||||
? details.SubState
|
||||
? `${details.ActiveState} (${details.SubState})`
|
||||
: details.ActiveState
|
||||
: subStateLabel
|
||||
? `${statusLabel} (${subStateLabel})`
|
||||
: statusLabel
|
||||
|
||||
for (const [index, status] of ServiceStatusLabels.entries()) {
|
||||
if (details?.ActiveState?.toLowerCase() === status.toLowerCase()) {
|
||||
service.state = index as ServiceStatus
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={cn("w-2 h-2 rounded-full flex-shrink-0", getStatusColor(service.state))} />
|
||||
{stateText}
|
||||
</div>
|
||||
)
|
||||
})()
|
||||
|
||||
const statusTextValue = details?.Result
|
||||
|
||||
const cpuTime = formatCpuTime(details?.CPUUsageNSec)
|
||||
const tasks = formatTasks(details?.TasksCurrent, details?.TasksMax)
|
||||
const memoryCurrent = formatMemory(details?.MemoryCurrent)
|
||||
const memoryPeak = formatMemory(details?.MemoryPeak)
|
||||
const memoryLimit = formatMemory(details?.MemoryLimit)
|
||||
const restartsValue = typeof details?.NRestarts === "number" ? details.NRestarts : undefined
|
||||
const mainPidValue = typeof details?.MainPID === "number" && details.MainPID > 0 ? details.MainPID : undefined
|
||||
const execMainPidValue =
|
||||
typeof details?.ExecMainPID === "number" && details.ExecMainPID > 0 && details.ExecMainPID !== details?.MainPID
|
||||
? details.ExecMainPID
|
||||
: undefined
|
||||
const activeEnterTimestamp = formatTimestamp(details?.ActiveEnterTimestamp)
|
||||
const activeExitTimestamp = formatTimestamp(details?.ActiveExitTimestamp)
|
||||
const inactiveEnterTimestamp = formatTimestamp(details?.InactiveEnterTimestamp)
|
||||
const execMainStartTimestamp = undefined // Property not available in current systemd interface
|
||||
|
||||
const renderRow = (key: string, label: ReactNode, value?: ReactNode, alwaysShow = false) => {
|
||||
if (!alwaysShow && (value === undefined || value === null || value === "")) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<tr key={key} className="border-b last:border-b-0">
|
||||
<td className="px-3 py-2 font-medium bg-muted dark:bg-muted/40 align-top w-35">{label}</td>
|
||||
<td className="px-3 py-2">{value ?? notAvailable}</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
const capitalize = (str: string) => `${str.charAt(0).toUpperCase()}${str.slice(1).toLowerCase()}`
|
||||
|
||||
return (
|
||||
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
|
||||
<SheetContent className="w-full sm:max-w-220 p-6 overflow-y-auto">
|
||||
<SheetHeader className="p-0">
|
||||
<SheetTitle>
|
||||
<Trans>Service Details</Trans>
|
||||
</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className="grid gap-6">
|
||||
{isLoading && (
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<LoaderCircleIcon className="size-4 animate-spin" />
|
||||
<Trans>Loading...</Trans>
|
||||
</div>
|
||||
)}
|
||||
{error && (
|
||||
<Alert className="border-destructive/50 text-destructive dark:border-destructive/60 dark:text-destructive">
|
||||
<AlertTitle>
|
||||
<Trans>Error</Trans>
|
||||
</AlertTitle>
|
||||
<AlertDescription>{error}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<div className="border rounded-md">
|
||||
<table className="w-full text-sm">
|
||||
<tbody>
|
||||
{renderRow("name", t`Name`, service.name, true)}
|
||||
{renderRow("description", t`Description`, details?.Description, true)}
|
||||
{renderRow("loadState", t`Load state`, details?.LoadState, true)}
|
||||
{renderRow(
|
||||
"bootState",
|
||||
t`Boot state`,
|
||||
<div className="flex items-center">
|
||||
{details?.UnitFileState}
|
||||
{details?.UnitFilePreset && (
|
||||
<span className="text-muted-foreground ms-1.5">(preset: {details?.UnitFilePreset})</span>
|
||||
)}
|
||||
</div>,
|
||||
true
|
||||
)}
|
||||
{renderRow("unitFile", t`Unit file`, details?.FragmentPath, true)}
|
||||
{renderRow("active", t`Active state`, activeStateValue, true)}
|
||||
{renderRow("status", t`Status`, statusTextValue, true)}
|
||||
{renderRow(
|
||||
"documentation",
|
||||
t`Documentation`,
|
||||
Array.isArray(details?.Documentation) && details.Documentation.length > 0
|
||||
? details.Documentation.join(", ")
|
||||
: undefined
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-medium mb-3">
|
||||
<Trans>Runtime Metrics</Trans>
|
||||
</h3>
|
||||
<div className="border rounded-md">
|
||||
<table className="w-full text-sm">
|
||||
<tbody>
|
||||
{renderRow("mainPid", t`Main PID`, mainPidValue, true)}
|
||||
{renderRow("execMainPid", t`Exec main PID`, execMainPidValue)}
|
||||
{renderRow("tasks", t`Tasks`, tasks, true)}
|
||||
{renderRow("cpuTime", t`CPU time`, cpuTime)}
|
||||
{renderRow("memory", t`Memory`, memoryCurrent, true)}
|
||||
{renderRow("memoryPeak", capitalize(t`Memory Peak`), memoryPeak)}
|
||||
{renderRow("memoryLimit", t`Memory limit`, memoryLimit)}
|
||||
{renderRow("restarts", t`Restarts`, restartsValue, true)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="hidden has-[tr]:block">
|
||||
<h3 className="text-sm font-medium mb-3">
|
||||
<Trans>Relationships</Trans>
|
||||
</h3>
|
||||
<div className="border rounded-md">
|
||||
<table className="w-full text-sm">
|
||||
<tbody>
|
||||
{renderRow(
|
||||
"wants",
|
||||
t`Wants`,
|
||||
Array.isArray(details?.Wants) && details.Wants.length > 0 ? details.Wants.join(", ") : undefined
|
||||
)}
|
||||
{renderRow(
|
||||
"requires",
|
||||
t`Requires`,
|
||||
Array.isArray(details?.Requires) && details.Requires.length > 0
|
||||
? details.Requires.join(", ")
|
||||
: undefined
|
||||
)}
|
||||
{renderRow(
|
||||
"requiredBy",
|
||||
t`Required by`,
|
||||
Array.isArray(details?.RequiredBy) && details.RequiredBy.length > 0
|
||||
? details.RequiredBy.join(", ")
|
||||
: undefined
|
||||
)}
|
||||
{renderRow(
|
||||
"conflicts",
|
||||
t`Conflicts`,
|
||||
Array.isArray(details?.Conflicts) && details.Conflicts.length > 0
|
||||
? details.Conflicts.join(", ")
|
||||
: undefined
|
||||
)}
|
||||
{renderRow(
|
||||
"before",
|
||||
t`Before`,
|
||||
Array.isArray(details?.Before) && details.Before.length > 0 ? details.Before.join(", ") : undefined
|
||||
)}
|
||||
{renderRow(
|
||||
"after",
|
||||
t`After`,
|
||||
Array.isArray(details?.After) && details.After.length > 0 ? details.After.join(", ") : undefined
|
||||
)}
|
||||
{renderRow(
|
||||
"triggers",
|
||||
t`Triggers`,
|
||||
Array.isArray(details?.Triggers) && details.Triggers.length > 0
|
||||
? details.Triggers.join(", ")
|
||||
: undefined
|
||||
)}
|
||||
{renderRow(
|
||||
"triggeredBy",
|
||||
t`Triggered by`,
|
||||
Array.isArray(details?.TriggeredBy) && details.TriggeredBy.length > 0
|
||||
? details.TriggeredBy.join(", ")
|
||||
: undefined
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="hidden has-[tr]:block">
|
||||
<h3 className="text-sm font-medium mb-3">
|
||||
<Trans>Lifecycle</Trans>
|
||||
</h3>
|
||||
<div className="border rounded-md">
|
||||
<table className="w-full text-sm">
|
||||
<tbody>
|
||||
{renderRow("activeSince", t`Became active`, activeEnterTimestamp)}
|
||||
{service.state !== ServiceStatus.Active &&
|
||||
renderRow("lastActive", t`Exited active`, activeExitTimestamp)}
|
||||
{renderRow("inactiveSince", t`Became inactive`, inactiveEnterTimestamp)}
|
||||
{renderRow("execMainStart", t`Process started`, execMainStartTimestamp)}
|
||||
{/* {renderRow("invocationId", t`Invocation ID`, details?.InvocationID)} */}
|
||||
{/* {renderRow("freezerState", t`Freezer State`, details?.FreezerState)} */}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="hidden has-[tr]:block">
|
||||
<h3 className="text-sm font-medium mb-3">
|
||||
<Trans>Capabilities</Trans>
|
||||
</h3>
|
||||
<div className="border rounded-md">
|
||||
<table className="w-full text-sm">
|
||||
<tbody>
|
||||
{renderRow("canStart", t`Can start`, details?.CanStart ? t`Yes` : t`No`)}
|
||||
{renderRow("canStop", t`Can stop`, details?.CanStop ? t`Yes` : t`No`)}
|
||||
{renderRow("canReload", t`Can reload`, details?.CanReload ? t`Yes` : t`No`)}
|
||||
{/* {renderRow("refuseManualStart", t`Refuse Manual Start`, details?.RefuseManualStart ? t`Yes` : t`No`)}
|
||||
{renderRow("refuseManualStop", t`Refuse Manual Stop`, details?.RefuseManualStop ? t`Yes` : t`No`)} */}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
)
|
||||
}
|
||||
|
||||
function SystemdTableHead({ table }: { table: TableType<SystemdRecord> }) {
|
||||
return (
|
||||
<TableHeader className="sticky top-0 z-50 w-full border-b-2">
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead className="px-2" key={header.id}>
|
||||
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
|
||||
</TableHead>
|
||||
)
|
||||
})}
|
||||
</tr>
|
||||
))}
|
||||
</TableHeader>
|
||||
)
|
||||
}
|
||||
|
||||
const SystemdTableRow = memo(function SystemdTableRow({
|
||||
row,
|
||||
virtualRow,
|
||||
openSheet,
|
||||
}: {
|
||||
row: Row<SystemdRecord>
|
||||
virtualRow: VirtualItem
|
||||
openSheet: (service: SystemdRecord) => void
|
||||
}) {
|
||||
return (
|
||||
<TableRow
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
className="cursor-pointer transition-opacity"
|
||||
onClick={() => openSheet(row.original)}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
className="py-0"
|
||||
style={{
|
||||
height: virtualRow.size,
|
||||
}}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
)
|
||||
})
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
WifiIcon,
|
||||
} from "lucide-react"
|
||||
import { memo, useMemo, useRef, useState } from "react"
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip"
|
||||
import { isReadOnlyUser, pb } from "@/lib/api"
|
||||
import { ConnectionType, connectionTypeLabels, MeterState, SystemStatus } from "@/lib/enums"
|
||||
import { $longestSystemNameLen, $userSettings } from "@/lib/stores"
|
||||
@@ -153,7 +154,7 @@ export default function SystemsTableColumns(viewMode: "table" | "grid"): ColumnD
|
||||
accessorFn: ({ info }) => info.dp,
|
||||
id: "disk",
|
||||
name: () => t`Disk`,
|
||||
cell: TableCellWithMeter,
|
||||
cell: DiskCellWithMultiple,
|
||||
Icon: HardDriveIcon,
|
||||
header: sortableHeader,
|
||||
},
|
||||
@@ -354,6 +355,79 @@ function TableCellWithMeter(info: CellContext<SystemRecord, unknown>) {
|
||||
)
|
||||
}
|
||||
|
||||
function DiskCellWithMultiple(info: CellContext<SystemRecord, unknown>) {
|
||||
const { info: sysInfo, status, id } = info.row.original
|
||||
const extraFs = Object.entries(sysInfo.efs ?? {})
|
||||
|
||||
// No extra disks - show basic meter
|
||||
if (extraFs.length === 0) {
|
||||
return TableCellWithMeter(info)
|
||||
}
|
||||
|
||||
const rootDiskPct = sysInfo.dp
|
||||
|
||||
// sort extra disks by percentage descending
|
||||
extraFs.sort((a, b) => b[1] - a[1])
|
||||
|
||||
function getMeterClass(pct: number) {
|
||||
const threshold = getMeterState(pct)
|
||||
return cn(
|
||||
"h-full",
|
||||
(status !== SystemStatus.Up && STATUS_COLORS.paused) ||
|
||||
(threshold === MeterState.Good && STATUS_COLORS.up) ||
|
||||
(threshold === MeterState.Warn && STATUS_COLORS.pending) ||
|
||||
STATUS_COLORS.down
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Link href={getPagePath($router, "system", { id })} tabIndex={-1} className="flex flex-col gap-0.5 w-full relative z-10">
|
||||
<div className="flex gap-2 items-center tabular-nums tracking-tight">
|
||||
<span className="min-w-8 shrink-0">{decimalString(rootDiskPct, rootDiskPct >= 10 ? 1 : 2)}%</span>
|
||||
<span className="flex-1 min-w-8 grid bg-muted h-[1em] rounded-sm overflow-hidden">
|
||||
{/* Root disk */}
|
||||
<span className={getMeterClass(rootDiskPct)} style={{ width: `${rootDiskPct}%` }}></span>
|
||||
{/* Extra disks */}
|
||||
{extraFs.map(([_name, pct], index) => (
|
||||
<span key={index} className={getMeterClass(pct)} style={{ width: `${pct}%` }}></span>
|
||||
))}
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right" className="max-w-xs pb-2">
|
||||
<div className="grid gap-1.5">
|
||||
<div className="grid gap-0.5">
|
||||
<div className="text-[0.65rem] text-muted-foreground uppercase tracking-wide tabular-nums"><Trans context="Root disk label">Root</Trans></div>
|
||||
<div className="flex gap-2 items-center tabular-nums text-xs">
|
||||
<span className="min-w-7">{decimalString(rootDiskPct, rootDiskPct >= 10 ? 1 : 2)}%</span>
|
||||
<span className="flex-1 min-w-12 grid bg-muted h-2.5 rounded-sm overflow-hidden">
|
||||
<span className={getMeterClass(rootDiskPct)} style={{ width: `${rootDiskPct}%` }}></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{extraFs.map(([name, pct]) => {
|
||||
return (
|
||||
<div key={name} className="grid gap-0.5">
|
||||
<div className="text-[0.65rem] max-w-40 text-muted-foreground uppercase tracking-wide truncate">{name}</div>
|
||||
<div className="flex gap-2 items-center tabular-nums text-xs">
|
||||
<span className="min-w-7">{decimalString(pct, pct >= 10 ? 1 : 2)}%</span>
|
||||
<span className="flex-1 min-w-12 grid bg-muted h-2.5 rounded-sm overflow-hidden">
|
||||
<span className={getMeterClass(pct)} style={{ width: `${pct}%` }}></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
export function IndicatorDot({ system, className }: { system: SystemRecord; className?: ClassValue }) {
|
||||
className ||= STATUS_COLORS[system.status as keyof typeof STATUS_COLORS] || ""
|
||||
return (
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import type { JSX } from "react"
|
||||
import { useLingui } from "@lingui/react/macro"
|
||||
import * as React from "react"
|
||||
import * as RechartsPrimitive from "recharts"
|
||||
import { chartTimeData, cn } from "@/lib/utils"
|
||||
import type { ChartData } from "@/types"
|
||||
import { Separator } from "./separator"
|
||||
|
||||
// Format: { THEME_NAME: CSS_SELECTOR }
|
||||
const THEMES = { light: "", dark: ".dark" } as const
|
||||
@@ -100,6 +102,8 @@ const ChartTooltipContent = React.forwardRef<
|
||||
filter?: string
|
||||
contentFormatter?: (item: any, key: string) => React.ReactNode | string
|
||||
truncate?: boolean
|
||||
showTotal?: boolean
|
||||
totalLabel?: React.ReactNode
|
||||
}
|
||||
>(
|
||||
(
|
||||
@@ -121,11 +125,16 @@ const ChartTooltipContent = React.forwardRef<
|
||||
itemSorter,
|
||||
contentFormatter: content = undefined,
|
||||
truncate = false,
|
||||
showTotal = false,
|
||||
totalLabel,
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
// const { config } = useChart()
|
||||
const config = {}
|
||||
const { t } = useLingui()
|
||||
const totalLabelNode = totalLabel ?? t`Total`
|
||||
const totalName = typeof totalLabelNode === "string" ? totalLabelNode : t`Total`
|
||||
|
||||
React.useMemo(() => {
|
||||
if (filter) {
|
||||
@@ -141,6 +150,76 @@ const ChartTooltipContent = React.forwardRef<
|
||||
}
|
||||
}, [itemSorter, payload])
|
||||
|
||||
const totalValueDisplay = React.useMemo(() => {
|
||||
if (!showTotal || !payload?.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
let totalValue = 0
|
||||
let hasNumericValue = false
|
||||
const aggregatedNestedValues: Record<string, number> = {}
|
||||
|
||||
for (const item of payload) {
|
||||
const numericValue = typeof item.value === "number" ? item.value : Number(item.value)
|
||||
if (Number.isFinite(numericValue)) {
|
||||
totalValue += numericValue
|
||||
hasNumericValue = true
|
||||
}
|
||||
|
||||
if (content && item?.payload) {
|
||||
const payloadKey = `${nameKey || item.name || item.dataKey || "value"}`
|
||||
const nestedPayload = (item.payload as Record<string, unknown> | undefined)?.[payloadKey]
|
||||
|
||||
if (nestedPayload && typeof nestedPayload === "object") {
|
||||
for (const [nestedKey, nestedValue] of Object.entries(nestedPayload)) {
|
||||
if (typeof nestedValue === "number" && Number.isFinite(nestedValue)) {
|
||||
aggregatedNestedValues[nestedKey] = (aggregatedNestedValues[nestedKey] ?? 0) + nestedValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasNumericValue) {
|
||||
return null
|
||||
}
|
||||
|
||||
const totalKey = "__total__"
|
||||
const totalItem: any = {
|
||||
value: totalValue,
|
||||
name: totalName,
|
||||
dataKey: totalKey,
|
||||
color,
|
||||
}
|
||||
|
||||
if (content) {
|
||||
const basePayload =
|
||||
payload[0]?.payload && typeof payload[0].payload === "object"
|
||||
? { ...(payload[0].payload as Record<string, unknown>) }
|
||||
: {}
|
||||
totalItem.payload = {
|
||||
...basePayload,
|
||||
[totalKey]: aggregatedNestedValues,
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof formatter === "function") {
|
||||
return formatter(
|
||||
totalValue,
|
||||
totalName,
|
||||
totalItem,
|
||||
payload.length,
|
||||
totalItem.payload ?? payload[0]?.payload
|
||||
)
|
||||
}
|
||||
|
||||
if (content) {
|
||||
return content(totalItem, totalKey)
|
||||
}
|
||||
|
||||
return `${totalValue.toLocaleString()}${unit ?? ""}`
|
||||
}, [color, content, formatter, nameKey, payload, showTotal, totalName, unit])
|
||||
|
||||
const tooltipLabel = React.useMemo(() => {
|
||||
if (hideLabel || !payload?.length) {
|
||||
return null
|
||||
@@ -242,6 +321,15 @@ const ChartTooltipContent = React.forwardRef<
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
{totalValueDisplay ? (
|
||||
<>
|
||||
<Separator className="mt-0.5" />
|
||||
<div className="flex items-center justify-between gap-2 -mt-0.75 font-medium">
|
||||
<span className="text-muted-foreground ps-3">{totalLabelNode}</span>
|
||||
<span>{totalValueDisplay}</span>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -257,14 +345,17 @@ const ChartLegendContent = React.forwardRef<
|
||||
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
|
||||
hideIcon?: boolean
|
||||
nameKey?: string
|
||||
reverse?: boolean
|
||||
}
|
||||
>(({ className, payload, verticalAlign = "bottom" }, ref) => {
|
||||
>(({ className, payload, verticalAlign = "bottom", reverse = false }, ref) => {
|
||||
// const { config } = useChart()
|
||||
|
||||
if (!payload?.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
const reversedPayload = reverse ? [...payload].reverse() : payload
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
@@ -274,7 +365,7 @@ const ChartLegendContent = React.forwardRef<
|
||||
className
|
||||
)}
|
||||
>
|
||||
{payload.map((item) => {
|
||||
{reversedPayload.map((item) => {
|
||||
// const key = `${nameKey || item.dataKey || 'value'}`
|
||||
// const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
--chart-4: hsl(280 65% 60%);
|
||||
--chart-5: hsl(340 75% 55%);
|
||||
--table-header: hsl(225, 6%, 97%);
|
||||
--chart-saturation: 65%;
|
||||
--chart-lightness: 50%;
|
||||
}
|
||||
|
||||
.dark {
|
||||
@@ -51,11 +53,13 @@
|
||||
--accent: hsl(220 5% 15.5%);
|
||||
--accent-foreground: hsl(220 2% 98%);
|
||||
--destructive: hsl(0 62% 46%);
|
||||
--border: hsl(220 3% 16%);
|
||||
--border: hsl(220 3% 17%);
|
||||
--input: hsl(220 4% 22%);
|
||||
--ring: hsl(220 4% 80%);
|
||||
--table-header: hsl(220, 6%, 13%);
|
||||
--radius: 0.8rem;
|
||||
--chart-saturation: 60%;
|
||||
--chart-lightness: 55%;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
@@ -145,7 +149,7 @@
|
||||
}
|
||||
|
||||
@utility container {
|
||||
@apply max-w-360 mx-auto px-4;
|
||||
@apply max-w-370 mx-auto px-4;
|
||||
}
|
||||
|
||||
@utility link {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { CpuIcon, HardDriveIcon, HourglassIcon, MemoryStickIcon, ServerIcon, ThermometerIcon } from "lucide-react"
|
||||
import type { RecordSubscription } from "pocketbase"
|
||||
import { EthernetIcon } from "@/components/ui/icons"
|
||||
import { EthernetIcon, GpuIcon } from "@/components/ui/icons"
|
||||
import { $alerts } from "@/lib/stores"
|
||||
import type { AlertInfo, AlertRecord } from "@/types"
|
||||
import { pb } from "./api"
|
||||
@@ -41,6 +41,12 @@ export const alertInfo: Record<string, AlertInfo> = {
|
||||
desc: () => t`Triggers when combined up/down exceeds a threshold`,
|
||||
max: 125,
|
||||
},
|
||||
GPU: {
|
||||
name: () => t`GPU Usage`,
|
||||
unit: "%",
|
||||
icon: GpuIcon,
|
||||
desc: () => t`Triggers when GPU usage exceeds a threshold`,
|
||||
},
|
||||
Temperature: {
|
||||
name: () => t`Temperature`,
|
||||
unit: "°C",
|
||||
|
||||
@@ -71,3 +71,26 @@ export enum ConnectionType {
|
||||
}
|
||||
|
||||
export const connectionTypeLabels = ["", "SSH", "WebSocket"] as const
|
||||
|
||||
/** Systemd service state */
|
||||
export enum ServiceStatus {
|
||||
Active,
|
||||
Inactive,
|
||||
Failed,
|
||||
Activating,
|
||||
Deactivating,
|
||||
Reloading,
|
||||
}
|
||||
|
||||
export const ServiceStatusLabels = ["Active", "Inactive", "Failed", "Activating", "Deactivating", "Reloading"] as const
|
||||
|
||||
/** Systemd service sub state */
|
||||
export enum ServiceSubState {
|
||||
Dead,
|
||||
Running,
|
||||
Exited,
|
||||
Failed,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
export const ServiceSubStateLabels = ["Dead", "Running", "Exited", "Failed", "Unknown"] as const
|
||||
|
||||
@@ -7,13 +7,15 @@ import { messages as enMessages } from "@/locales/en/en"
|
||||
import { BatteryState } from "./enums"
|
||||
import { $direction } from "./stores"
|
||||
|
||||
const rtlLanguages = new Set(["ar", "fa", "he"])
|
||||
|
||||
// activates locale
|
||||
function activateLocale(locale: string, messages: Messages = enMessages) {
|
||||
i18n.load(locale, messages)
|
||||
i18n.activate(locale)
|
||||
document.documentElement.lang = locale
|
||||
localStorage.setItem("lang", locale)
|
||||
$direction.set(locale.startsWith("ar") || locale.startsWith("fa") ? "rtl" : "ltr")
|
||||
$direction.set(rtlLanguages.has(locale) ? "rtl" : "ltr")
|
||||
}
|
||||
|
||||
// dynamically loads translations for the given locale
|
||||
|
||||
@@ -44,6 +44,11 @@ export default [
|
||||
label: "Français",
|
||||
e: "🇫🇷",
|
||||
},
|
||||
{
|
||||
lang: "he",
|
||||
label: "עברית",
|
||||
e: "🕎",
|
||||
},
|
||||
{
|
||||
lang: "hr",
|
||||
label: "Hrvatski",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { plural, t } from "@lingui/core/macro"
|
||||
import { type ClassValue, clsx } from "clsx"
|
||||
import { listenKeys } from "nanostores"
|
||||
import { timeDay, timeHour, timeMinute } from "d3-time"
|
||||
@@ -111,18 +111,17 @@ export const updateFavicon = (() => {
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#gradient)" d="M35 70H0V0h35q4.4 0 8.2 1.7a21.4 21.4 0 0 1 6.6 4.5q2.9 2.8 4.5 6.6Q56 16.7 56 21a15.4 15.4 0 0 1-.3 3.2 17.6 17.6 0 0 1-.2.8 19.4 19.4 0 0 1-1.5 4 17 17 0 0 1-2.4 3.4 13.5 13.5 0 0 1-2.6 2.3 12.5 12.5 0 0 1-.4.3q1.7 1 3 2.5Q53 39.1 54 41a18.3 18.3 0 0 1 1.5 4 17.4 17.4 0 0 1 .5 3 15.3 15.3 0 0 1 0 1q0 4.4-1.7 8.2a21.4 21.4 0 0 1-4.5 6.6q-2.8 2.9-6.6 4.6Q39.4 70 35 70ZM14 14v14h21a7 7 0 0 0 2.3-.3 6.6 6.6 0 0 0 .4-.2Q39 27 40 26a6.9 6.9 0 0 0 1.5-2.2q.5-1.3.5-2.8a7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 17 40 16a7 7 0 0 0-2.3-1.4 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Zm0 28v14h21a7 7 0 0 0 2.3-.4 6.6 6.6 0 0 0 .4-.1Q39 54.9 40 54a7 7 0 0 0 1.5-2.2 6.9 6.9 0 0 0 .5-2.6 7.9 7.9 0 0 0 0-.2 7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 45 40 44a7 7 0 0 0-2.3-1.5 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Z"/>
|
||||
${
|
||||
downCount > 0 &&
|
||||
`
|
||||
${downCount > 0 &&
|
||||
`
|
||||
<circle cx="40" cy="50" r="22" fill="#f00"/>
|
||||
<text x="40" y="60" font-size="34" text-anchor="middle" fill="#fff" font-family="Arial" font-weight="bold">${downCount}</text>
|
||||
`
|
||||
}
|
||||
}
|
||||
</svg>
|
||||
`
|
||||
const blob = new Blob([svg], { type: "image/svg+xml" })
|
||||
const url = URL.createObjectURL(blob)
|
||||
;(document.querySelector("link[rel='icon']") as HTMLLinkElement).href = url
|
||||
; (document.querySelector("link[rel='icon']") as HTMLLinkElement).href = url
|
||||
}
|
||||
})()
|
||||
|
||||
@@ -288,7 +287,7 @@ export function formatBytes(
|
||||
}
|
||||
}
|
||||
|
||||
export const chartMargin = { top: 12 }
|
||||
export const chartMargin = { top: 12, right: 5 }
|
||||
|
||||
/**
|
||||
* Retuns value of system host, truncating full path if socket.
|
||||
@@ -367,6 +366,12 @@ export function formatDuration(
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
/** Parse semver string into major, minor, and patch numbers
|
||||
* @example
|
||||
* const semVer = "1.2.3"
|
||||
* const { major, minor, patch } = parseSemVer(semVer)
|
||||
* console.log(major, minor, patch) // 1, 2, 3
|
||||
*/
|
||||
export const parseSemVer = (semVer = ""): SemVer => {
|
||||
// if (semVer.startsWith("v")) {
|
||||
// semVer = semVer.slice(1)
|
||||
@@ -423,3 +428,17 @@ export function runOnce<T extends (...args: any[]) => any>(fn: T): T {
|
||||
return state.result
|
||||
}) as T
|
||||
}
|
||||
|
||||
/** Format seconds to hours, minutes, or seconds */
|
||||
export function secondsToString(seconds: number, unit: "hour" | "minute" | "day"): string {
|
||||
const count = Math.floor(seconds / (unit === "hour" ? 3600 : unit === "minute" ? 60 : 86400))
|
||||
const countString = count.toLocaleString()
|
||||
switch (unit) {
|
||||
case "minute":
|
||||
return plural(count, { one: `${countString} minute`, few: `${countString} minutes`, many: `${countString} minutes`, other: `${countString} minutes` })
|
||||
case "hour":
|
||||
return plural(count, { one: `${countString} hour`, other: `${countString} hours` })
|
||||
case "day":
|
||||
return plural(count, { one: `${countString} day`, other: `${countString} days` })
|
||||
}
|
||||
}
|
||||
@@ -8,30 +8,15 @@ msgstr ""
|
||||
"Language: ar\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-08-28 23:21\n"
|
||||
"PO-Revision-Date: 2025-10-30 21:52\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Arabic\n"
|
||||
"Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: ar\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# يوم} other {# أيام}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# ساعة} other {# ساعات}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# دقيقة} few {# دقائق} many {# دقيقة} other {# دقيقة}}"
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
@@ -39,6 +24,18 @@ msgstr "{0, plural, one {# دقيقة} few {# دقائق} many {# دقيقة} ot
|
||||
msgid "{0} of {1} row(s) selected."
|
||||
msgstr "تم تحديد {0} من {1} صف"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} يوم} other {{countString} أيام}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} ساعة} other {{countString} ساعات}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} دقيقة} few {{countString} دقائق} many {{countString} دقيقة} other {{countString} دقيقة}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 ساعة"
|
||||
@@ -93,6 +90,10 @@ msgstr "نشط"
|
||||
msgid "Active Alerts"
|
||||
msgstr "التنبيهات النشطة"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "الحالة النشطة"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "إضافة <0>نظام</0>"
|
||||
@@ -118,6 +119,10 @@ msgstr "تعديل خيارات العرض للرسوم البيانية."
|
||||
msgid "Admin"
|
||||
msgstr "مسؤول"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "بعد"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "وكيل"
|
||||
@@ -203,6 +208,18 @@ msgstr "عرض النطاق الترددي"
|
||||
msgid "Battery"
|
||||
msgstr "البطارية"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "أصبح نشطًا"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "أصبح غير نشط"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "قبل"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "يدعم بيزيل بروتوكول OpenID Connect والعديد من مزوّدي المصادقة عبر بروتوكول OAuth2."
|
||||
@@ -220,6 +237,10 @@ msgstr "ثنائي"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "بت (كيلوبت/ثانية، ميجابت/ثانية، جيجابت/ثانية)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "حالة التمهيد"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
@@ -229,11 +250,31 @@ msgstr "بايت (كيلوبايت/ثانية، ميجابايت/ثانية، ج
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "ذاكرة التخزين المؤقت / المخازن المؤقتة"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "يمكن إعادة التحميل"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "يمكن البدء"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "يمكن الإيقاف"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "إلغاء"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "القدرات"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "السعة"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "تحذير - فقدان محتمل للبيانات"
|
||||
@@ -279,6 +320,10 @@ msgstr "تحقق من خدمة الإشعارات الخاصة بك"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "انقر على حاوية لعرض مزيد من المعلومات."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "انقر على جهاز لعرض مزيد من المعلومات."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "انقر على نظام لعرض مزيد من المعلومات."
|
||||
@@ -301,6 +346,10 @@ msgstr "هيئ التنبيهات الواردة"
|
||||
msgid "Confirm password"
|
||||
msgstr "تأكيد كلمة المرور"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "التعارضات"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "الاتصال مقطوع"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "نسخ YAML"
|
||||
|
||||
#: 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 "المعالج"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "نوى المعالج"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "ذروة المعالج"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "وقت المعالج"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "تفصيل وقت المعالج"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "استخدام وحدة المعالجة المركزية"
|
||||
@@ -397,6 +464,11 @@ msgstr "الرفع التراكمي"
|
||||
msgid "Current state"
|
||||
msgstr "الحالة الحالية"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "الدورات"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "لوحة التحكم"
|
||||
@@ -414,10 +486,18 @@ msgstr "حذف"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "حذف البصمة"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "الوصف"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "التفاصيل"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "الجهاز"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "إدخال/إخراج الشبكة للدوكر"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "التوثيق"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "أدخل كلمة المرور لمرة واحدة الخاصة بك."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "خطأ"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "خطأ"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "يتجاوز {0}{1} في آخر {2, plural, one {# دقيقة} other {# دقائق}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "معرف العملية الرئيسي للتنفيذ"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "سيتم حذف الأنظمة الحالية غير المعرفة في <0>config.yml</0>. يرجى عمل نسخ احتياطية بانتظام."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "خرج نشطًا"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "تصدير"
|
||||
@@ -548,6 +638,10 @@ msgstr "تصدير تكوين الأنظمة الحالية الخاصة بك."
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "فهرنهايت (°ف)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "السمات الفاشلة:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "فشل في المصادقة"
|
||||
@@ -565,9 +659,16 @@ msgstr "فشل في إرسال إشعار الاختبار"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "فشل في تحديث التنبيه"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "تصفية..."
|
||||
@@ -576,6 +677,10 @@ msgstr "تصفية..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "البصمة"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "البرمجيات الثابتة"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "لمدة <0>{min}</0> {min, plural, one {دقيقة} other {دقائق}}"
|
||||
@@ -609,6 +714,10 @@ msgstr "محركات GPU"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "استهلاك طاقة وحدة معالجة الرسوميات"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "استخدام وحدة معالجة الرسوميات"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "شبكة"
|
||||
@@ -658,6 +767,15 @@ msgstr "اللغة"
|
||||
msgid "Layout"
|
||||
msgstr "التخطيط"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "دورة الحياة"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "الحد"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "متوسط التحميل"
|
||||
@@ -679,6 +797,14 @@ msgstr "متوسط التحميل 5 دقائق"
|
||||
msgid "Load Avg"
|
||||
msgstr "متوسط التحميل"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "حالة التحميل"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "جاري التحميل..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "تسجيل الخروج"
|
||||
@@ -702,6 +828,10 @@ msgstr "السجلات"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "هل تبحث عن مكان لإنشاء التنبيهات؟ انقر على أيقونات الجرس <0/> في جدول الأنظمة."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "معرف العملية الرئيسي"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "إدارة تفضيلات العرض والإشعارات."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "الحد الأقصى دقيقة"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "الذاكرة"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "حد الذاكرة"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "ذروة الذاكرة"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "استخدام الذاكرة"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "استخدام الذاكرة لحاويات دوكر"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "الموديل"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "الاسم"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "حركة مرور الشبكة للواجهات العامة"
|
||||
msgid "Network unit"
|
||||
msgstr "وحدة الشبكة"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "لا"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "لم يتم العثور على نتائج."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "لا توجد نتائج."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "لا توجد سمات S.M.A.R.T. متاحة لهذا الجهاز."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "فتح القائمة"
|
||||
msgid "Or continue with"
|
||||
msgstr "أو المتابعة باستخدام"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "أخرى"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "الكتابة فوق التنبيهات الحالية"
|
||||
@@ -847,6 +1013,15 @@ msgstr "متوقف مؤقتا"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "متوقف مؤقتا ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "متوسط الاستخدام لكل نواة"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "النسبة المئوية للوقت المقضي في كل حالة"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "يرجى <0>تكوين خادم SMTP</0> لضمان تسليم التنبيهات."
|
||||
@@ -884,6 +1059,11 @@ msgstr "يرجى تسجيل الدخول إلى حسابك"
|
||||
msgid "Port"
|
||||
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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "الاستخدام الدقيق في الوقت المسجل"
|
||||
msgid "Preferred Language"
|
||||
msgstr "اللغة المفضلة"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "تم بدء العملية"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "تم الاستلام"
|
||||
msgid "Refresh"
|
||||
msgstr "تحديث"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "العلاقات"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "طلب كلمة مرور لمرة واحدة"
|
||||
@@ -921,6 +1109,14 @@ msgstr "طلب كلمة مرور لمرة واحدة"
|
||||
msgid "Request OTP"
|
||||
msgstr "طلب OTP"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "مطلوب من قبل"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "يتطلب"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "إعادة تعيين كلمة المرور"
|
||||
@@ -931,10 +1127,19 @@ msgstr "إعادة تعيين كلمة المرور"
|
||||
msgid "Resolved"
|
||||
msgstr "تم حلها"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "إعادة التشغيل"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "استئناف"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "الجذر"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "تدوير الرمز المميز"
|
||||
@@ -943,6 +1148,18 @@ msgstr "تدوير الرمز المميز"
|
||||
msgid "Rows per page"
|
||||
msgstr "صفوف لكل صفحة"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "مقاييس وقت التشغيل"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "تفاصيل S.M.A.R.T."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "اختبار S.M.A.R.T. الذاتي"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "احفظ العنوان باستخدام مفتاح الإدخال أو الفاصلة. اتركه فارغًا لتعطيل إشعارات البريد الإشباكي."
|
||||
@@ -972,6 +1189,14 @@ msgstr "راجع <0>إعدادات الإشعارات</0> لتكوين كيفي
|
||||
msgid "Sent"
|
||||
msgstr "تم الإرسال"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "الرقم التسلسلي"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "تفاصيل الخدمة"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "تعيين عتبات النسبة المئوية لألوان العداد."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "الترتيب حسب"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "الحالة"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "الحالة"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "الحالة الفرعية"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "مساحة التبديل المستخدمة من قبل النظام"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "النظام"
|
||||
msgid "System load averages over time"
|
||||
msgstr "متوسط تحميل النظام مع مرور الوقت"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "خدمات systemd"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "الأنظمة"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "يمكن إدارة الأنظمة في ملف <0>config.yml</0> داخ
|
||||
msgid "Table"
|
||||
msgstr "جدول"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "المهام"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "درجة الحرارة"
|
||||
@@ -1124,6 +1365,11 @@ msgstr "تسمح الرموز المميزة للوكلاء بالاتصال و
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "تُستخدم الرموز المميزة والبصمات للمصادقة على اتصالات WebSocket إلى المحور."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "الإجمالي"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "إجمالي البيانات المستلمة لكل واجهة"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "إجمالي البيانات المستلمة لكل واجهة"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "إجمالي البيانات المرسلة لكل واجهة"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "الإجمالي: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "تم التفعيل بواسطة"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "المحفزات"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز متوسط التحميل لمدة دقيقة واحدة عتبة معينة"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "يتم التفعيل عندما يتجاوز الجمع بين الصع
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز استخدام وحدة المعالجة المركزية عتبة معينة"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز استخدام وحدة معالجة الرسوميات عتبة معينة"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز استخدام الذاكرة عتبة معينة"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "يتم التفعيل عندما يتغير الحالة بين التش
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز استخدام أي قرص عتبة معينة"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "النوع"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "ملف الوحدة"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "رمز مميز عالمي"
|
||||
msgid "Unknown"
|
||||
msgstr "غير معروفة"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "غير محدود"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "قيد التشغيل ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "تم التحديث"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "يتم التحديث كل 10 دقائق."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "رفع"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "مدة التشغيل"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "الاستخدام"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "القيمة"
|
||||
msgid "View"
|
||||
msgstr "عرض"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "عرض المزيد"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "في انتظار وجود سجلات كافية للعرض"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "هل تريد مساعدتنا في تحسين ترجماتنا؟ تحقق من <0>Crowdin</0> لمزيد من التفاصيل."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "يريد"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "تحذير (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "تكوين YAML"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "تكوين YAML"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "نعم"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "تم تحديث إعدادات المستخدم الخاصة بك."
|
||||
|
||||
@@ -8,30 +8,15 @@ msgstr ""
|
||||
"Language: bg\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-08-28 23:21\n"
|
||||
"PO-Revision-Date: 2025-10-20 21:37\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Bulgarian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: bg\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# ден} other {# дни}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# час} other {# часа}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# минута} few {# минути} many {# минути} other {# минути}}"
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
@@ -39,6 +24,18 @@ msgstr "{0, plural, one {# минута} few {# минути} many {# минут
|
||||
msgid "{0} of {1} row(s) selected."
|
||||
msgstr "{0} от {1} селектирани."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} ден} other {{countString} дни}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} час} other {{countString} часа}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} минута} few {{countString} минути} many {{countString} минути} other {{countString} минути}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 час"
|
||||
@@ -93,6 +90,10 @@ msgstr "Активен"
|
||||
msgid "Active Alerts"
|
||||
msgstr "Активни тревоги"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "Активно състояние"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Добави <0>Система</0>"
|
||||
@@ -118,6 +119,10 @@ msgstr "Настрой опциите за показване на диагра
|
||||
msgid "Admin"
|
||||
msgstr "Администратор"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "След"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Агент"
|
||||
@@ -203,6 +208,18 @@ msgstr "Bandwidth на мрежата"
|
||||
msgid "Battery"
|
||||
msgstr "Батерия"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Стана активен"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Стана неактивен"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Преди"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel поддържа OpenID Connect и много други OAuth2 доставчици за удостоверяване."
|
||||
@@ -220,6 +237,10 @@ msgstr "Двоичен код"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Бита (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "Състояние при зареждане"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
@@ -229,11 +250,31 @@ msgstr "Байта (KB/s, MB/s, GB/s)"
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Кеш / Буфери"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Може да се презареди"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Може да се стартира"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Може да се спре"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Откажи"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "Възможности"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Капацитет"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Внимание - възможност за загуба на данни"
|
||||
@@ -279,6 +320,10 @@ msgstr "Провери услугата си за удостоверяване"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Кликнете върху контейнер, за да видите повече информация."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Кликнете върху устройство, за да видите повече информация."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "Кликнете върху система, за да видите повече информация."
|
||||
@@ -301,6 +346,10 @@ msgstr "Настрой как получаваш нотификации за т
|
||||
msgid "Confirm password"
|
||||
msgstr "Потвърди парола"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "Конфликти"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "Връзката е прекъсната"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "Копирай YAML"
|
||||
|
||||
#: 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 "Процесор"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "CPU ядра"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "Пик на CPU"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "Време на CPU"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Разбивка на времето на CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "Употреба на процесор"
|
||||
@@ -397,6 +464,11 @@ msgstr "Кумулативно качване"
|
||||
msgid "Current state"
|
||||
msgstr "Текущо състояние"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Цикли"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Табло"
|
||||
@@ -414,10 +486,18 @@ msgstr "Изтрий"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "Изтрий пръстов отпечатък"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Описание"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Подробности"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Устройство"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "Мрежов I/O използван от docker"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Документация"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "Въведете Вашата еднократна парола."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Грешка"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "Грешка"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Надвишава {0}{1} в последните {2, plural, one {# минута} other {# минути}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Съществуващи системи които не са дефинирани в <0>config.yml</0> ще бъдат изтрити. Моля прави чести архиви."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Излезе активно"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "Експортиране"
|
||||
@@ -548,6 +638,10 @@ msgstr "Експортирай конфигурацията на системи
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Фаренхайт (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Неуспешни атрибути:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Неуспешно удостоверяване"
|
||||
@@ -565,9 +659,16 @@ msgstr "Неуспешно изпрати тестова нотификация"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Неуспешно обнови тревога"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Филтрирай..."
|
||||
@@ -576,6 +677,10 @@ msgstr "Филтрирай..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "Пръстов отпечатък"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Фърмуер"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "За <0>{min}</0> {min, plural, one {минута} other {минути}}"
|
||||
@@ -609,6 +714,10 @@ msgstr "GPU двигатели"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Консумация на ток от графична карта"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "Употреба на GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Мрежово"
|
||||
@@ -658,6 +767,15 @@ msgstr "Език"
|
||||
msgid "Layout"
|
||||
msgstr "Подреждане"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "Жизнен цикъл"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "лимит"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Средно натоварване"
|
||||
@@ -679,6 +797,14 @@ msgstr "Средно натоварване 5 минути"
|
||||
msgid "Load Avg"
|
||||
msgstr "Средно натоварване"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "Състояние на зареждане"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Зареждане..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Изход"
|
||||
@@ -702,6 +828,10 @@ msgstr "Логове"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Търсиш къде да създадеш тревоги? Натисни емотиконата за звънец <0/> в таблицата за системи."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Управление на предпочитанията за показване и уведомяване."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "Максимум 1 минута"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "Памет"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Лимит на памет"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "Пик на памет"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "Употреба на паметта"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Използването на памет от docker контейнерите"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Модел"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Име"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "Мрежов трафик на публични интерфейси"
|
||||
msgid "Network unit"
|
||||
msgstr "Единица за измерване на скорост"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "Не"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "Няма намерени резултати."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "Няма резултати."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "Няма налични S.M.A.R.T. атрибути за това устройство."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "Отвори менюто"
|
||||
msgid "Or continue with"
|
||||
msgstr "Или продължи с"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Други"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Презапиши съществуващи тревоги"
|
||||
@@ -847,6 +1013,15 @@ msgstr "На пауза"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "На пауза ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Средно използване на ядро"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Процент време, прекарано във всяко състояние"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Моля <0>конфигурурай SMTP сървър</0> за да се подсигуриш, че тревогите са доставени."
|
||||
@@ -884,6 +1059,11 @@ msgstr "Моля влез в акаунта ти"
|
||||
msgid "Port"
|
||||
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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "Точно използване в записаното време"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Предпочитан език"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Процесът стартира"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "Получени"
|
||||
msgid "Refresh"
|
||||
msgstr "Опресни"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Връзки"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Заявка за еднократна парола"
|
||||
@@ -921,6 +1109,14 @@ msgstr "Заявка за еднократна парола"
|
||||
msgid "Request OTP"
|
||||
msgstr "Заявка OTP"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Изисква се от"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Изисква"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Нулиране на парола"
|
||||
@@ -931,10 +1127,19 @@ msgstr "Нулиране на парола"
|
||||
msgid "Resolved"
|
||||
msgstr "Решен"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Рестартирания"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Възобнови"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Корен"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "Пресъздаване на идентификатора"
|
||||
@@ -943,6 +1148,18 @@ msgstr "Пресъздаване на идентификатора"
|
||||
msgid "Rows per page"
|
||||
msgstr "Редове на страница"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Метрики на изпълнение"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "S.M.A.R.T. Детайли"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. Самотест"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Запази адреса с enter или запетая. Остави празно за да изключиш нотификациите чрез имейл."
|
||||
@@ -972,6 +1189,14 @@ msgstr "Виж <0>настройките за нотификациите</0> з
|
||||
msgid "Sent"
|
||||
msgstr "Изпратени"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Сериен номер"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Детайли на услугата"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Задайте процентни прагове за цветовете на измервателните уреди."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "Сортиране по"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "Състояние"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Статус"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Подсъстояние"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Изполван swap от системата"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "Система"
|
||||
msgid "System load averages over time"
|
||||
msgstr "Средно натоварване на системата във времето"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Услуги на systemd"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "Системи"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "Системите могат да бъдат управлявани в
|
||||
msgid "Table"
|
||||
msgstr "Таблица"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Задачи"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Температура"
|
||||
@@ -1124,6 +1365,11 @@ msgstr "Токените позволяват на агентите да се с
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "Токените и пръстовите отпечатъци се използват за удостоверяване на WebSocket връзките към концентратора."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Общо"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "Общо получени данни за всеки интерфейс"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "Общо получени данни за всеки интерфейс"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Общо изпратени данни за всеки интерфейс"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Общо: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Активиран от"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Активатори"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "Задейства се, когато употребата на паметта за 1 минута надвиши зададен праг"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "Задейства се, когато комбинираното кач
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Задейства се, когато употребата на процесора надвиши зададен праг"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Задейства се, когато употребата на паметта надвиши зададен праг"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "Задейства се, когато статуса превключв
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Задейства се, когато употребата на някой диск надивши зададен праг"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Тип"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "Файл на единица"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "Универсален тоукън"
|
||||
msgid "Unknown"
|
||||
msgstr "Неизвестна"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "Неограничено"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "Нагоре ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Актуализирано"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "Актуализира се на всеки 10 минути."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Качване"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "Време на работа"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Употреба"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "Стойност"
|
||||
msgid "View"
|
||||
msgstr "Изглед"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "Виж повече"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "Изчаква се за достатъчно записи за пока
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Искаш да помогнеш да направиш преводите още по-добри? Провери нашия <0>Crowdin</0> за повече детайли."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Иска"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Предупреждение (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "YAML конфигурация"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML конфигурация"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Да"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Настройките за потребителя ти са обновени."
|
||||
|
||||
@@ -8,30 +8,15 @@ msgstr ""
|
||||
"Language: cs\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-08-28 23:21\n"
|
||||
"PO-Revision-Date: 2025-10-28 23:00\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Czech\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 3;\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: cs\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# den} few {# dny} other {# dní}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# Hodina} few {# Hodiny} many {# Hodin} other {# Hodin}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# minuta} few {# minuty} many {# minut} other {# minut}}"
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
@@ -39,6 +24,18 @@ msgstr "{0, plural, one {# minuta} few {# minuty} many {# minut} other {# minut}
|
||||
msgid "{0} of {1} row(s) selected."
|
||||
msgstr "{0} z {1} vybraných řádků."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} den} few {{countString} dny} other {{countString} dní}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} Hodina} few {{countString} Hodiny} many {{countString} Hodin} other {{countString} Hodin}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} minuta} few {{countString} minuty} many {{countString} minut} other {{countString} minut}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 hodina"
|
||||
@@ -46,7 +43,7 @@ msgstr "1 hodina"
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr "1 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 minute"
|
||||
@@ -63,7 +60,7 @@ msgstr "12 hodin"
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr "15 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "24 hours"
|
||||
@@ -76,7 +73,7 @@ msgstr "30 dní"
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr "5 min"
|
||||
msgstr ""
|
||||
|
||||
#. Table column
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
@@ -93,6 +90,10 @@ msgstr "Aktivní"
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktivní výstrahy"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "Aktivní stav"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Přidat <0>Systém</0>"
|
||||
@@ -116,7 +117,11 @@ msgstr "Upravit možnosti zobrazení pro grafy."
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
msgstr "Administrátor"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "Po"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
@@ -203,6 +208,18 @@ msgstr "Přenos"
|
||||
msgid "Battery"
|
||||
msgstr "Baterie"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Stal se aktivním"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Stal se neaktivním"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Před"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel podporuje OpenID Connect a mnoho poskytovatelů OAuth2 ověřování."
|
||||
@@ -213,27 +230,51 @@ msgstr "Beszel používá <0>Shoutrrr</0> k integraci s populárními notifikač
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Binary"
|
||||
msgstr "Binary"
|
||||
msgstr "Binární"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bity (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "Stav zavádění"
|
||||
|
||||
#: 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 "Byty (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / vyrovnávací paměť"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Může znovu načíst"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Může spustit"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Může zastavit"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Zrušit"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "Schopnosti"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Kapacita"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Upozornění - možná ztráta dat"
|
||||
@@ -279,6 +320,10 @@ msgstr "Zkontrolujte službu upozornění"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Klikněte na kontejner pro zobrazení dalších informací."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Klikněte na zařízení pro zobrazení dalších informací."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "Klikněte na systém pro zobrazení více informací."
|
||||
@@ -301,6 +346,10 @@ msgstr "Konfigurace způsobu přijímání upozornění."
|
||||
msgid "Confirm password"
|
||||
msgstr "Potvrdit heslo"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "Konflikty"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "Připojení je nedostupné"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "Kopírovat YAML"
|
||||
|
||||
#: 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 "Procesor"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "CPU jádra"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "Špička CPU"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "Čas CPU"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Rozdělení času CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "Využití procesoru"
|
||||
@@ -397,6 +464,11 @@ msgstr "Kumulativní odeslání"
|
||||
msgid "Current state"
|
||||
msgstr "Aktuální stav"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Cykly"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Přehled"
|
||||
@@ -414,10 +486,18 @@ msgstr "Odstranit"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "Smazat identifikátor"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Popis"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Detail"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Zařízení"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "Síťové I/O Dockeru"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentace"
|
||||
|
||||
@@ -490,7 +571,7 @@ msgstr "Upravit"
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
#: src/components/login/otp-forms.tsx
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
msgstr "E-mail"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Email notifications"
|
||||
@@ -518,6 +599,7 @@ msgstr "Zadejte Vaše jednorázové heslo."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Chyba"
|
||||
|
||||
@@ -528,13 +610,21 @@ msgstr "Chyba"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Překračuje {0}{1} za {2, plural, one {poslední # minutu} few {poslední # minuty} other {posledních # minut}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "Hlavní PID spuštění"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Stávající systémy, které nejsou definovány v <0>config.yml</0>, budou odstraněny. Provádějte pravidelné zálohování."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Ukončeno aktivně"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "Export"
|
||||
msgstr "Exportovat"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Export configuration"
|
||||
@@ -548,6 +638,10 @@ msgstr "Exportovat aktuální konfiguraci systémů."
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheita (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Neúspěšné atributy:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Ověření se nezdařilo"
|
||||
@@ -565,9 +659,16 @@ msgstr "Nepodařilo se odeslat testovací oznámení"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Nepodařilo se aktualizovat upozornění"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filtr..."
|
||||
@@ -576,6 +677,10 @@ msgstr "Filtr..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "Otisk"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Za <0>{min}</0> {min, plural, one {minutu} few {minuty} other {minut}}"
|
||||
@@ -609,6 +714,10 @@ msgstr "GPU enginy"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Spotřeba energie GPU"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "Využití GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Mřížka"
|
||||
@@ -648,7 +757,7 @@ msgstr "Neplatná e-mailová adresa."
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
msgstr "Jádro"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Language"
|
||||
@@ -658,6 +767,15 @@ msgstr "Jazyk"
|
||||
msgid "Layout"
|
||||
msgstr "Rozvržení"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "Životní cyklus"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "limit"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Průměrné vytížení"
|
||||
@@ -679,6 +797,14 @@ msgstr "Průměrná zátěž 5m"
|
||||
msgid "Load Avg"
|
||||
msgstr "Prům. zatížení"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "Stav načtení"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Načítání..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Odhlásit"
|
||||
@@ -702,6 +828,10 @@ msgstr "Logy"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Hledáte místo kde vytvářet upozornění? Klikněte na ikonu zvonku <0/> v systémové tabulce."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "Hlavní PID"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Správa nastavení zobrazení a oznámení."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "Max. 1 min"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "Paměť"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Limit paměti"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "Špička paměti"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "Využití paměti"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Využití paměti docker kontejnerů"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Název"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "Síťový provoz veřejných rozhraní"
|
||||
msgid "Network unit"
|
||||
msgstr "Síťová jednotka"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "Ne"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "Nenalezeny žádné výskyty."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "Žádné výsledky."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "Pro toto zařízení nejsou k dispozici žádné atributy S.M.A.R.T."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "Otevřít menu"
|
||||
msgid "Or continue with"
|
||||
msgstr "Nebo pokračujte s"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Jiné"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Přepsat existující upozornění"
|
||||
@@ -847,6 +1013,15 @@ msgstr "Pozastaveno"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "Pozastaveno ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Průměrné využití na jádro"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Procento času strávěného v každém stavu"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "<0>nakonfigurujte SMTP server</0> pro zajištění toho, aby byla upozornění doručena."
|
||||
@@ -884,6 +1059,11 @@ msgstr "Přihlaste se prosím k vašemu účtu"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#. 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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "Přesné využití v zaznamenaném čase"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Upřednostňovaný jazyk"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Proces spuštěn"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "Přijato"
|
||||
msgid "Refresh"
|
||||
msgstr "Aktualizovat"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Vztahy"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Požádat o jednorázové heslo"
|
||||
@@ -921,6 +1109,14 @@ msgstr "Požádat o jednorázové heslo"
|
||||
msgid "Request OTP"
|
||||
msgstr "Požádat OTP"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Vyžadováno službou"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Vyžaduje"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Obnovit heslo"
|
||||
@@ -931,10 +1127,19 @@ msgstr "Obnovit heslo"
|
||||
msgid "Resolved"
|
||||
msgstr "Vyřešeno"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Restarty"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Pokračovat"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Kořenový"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "Změnit token"
|
||||
@@ -943,6 +1148,18 @@ msgstr "Změnit token"
|
||||
msgid "Rows per page"
|
||||
msgstr "Řádků na stránku"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Metriky běhu"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "S.M.A.R.T. Detaily"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. Vlastní test"
|
||||
|
||||
#: 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."
|
||||
@@ -972,6 +1189,14 @@ msgstr "Podívejte se na <0>nastavení upozornění</0> pro nastavení toho, jak
|
||||
msgid "Sent"
|
||||
msgstr "Odeslat"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Sériové číslo"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Detaily služby"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Nastavte procentuální prahové hodnoty pro barvy měřičů."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "Seřadit podle"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "Stav"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Stav"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Podstav"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap prostor využívaný systémem"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "Systém"
|
||||
msgid "System load averages over time"
|
||||
msgstr "Průměry zatížení systému v průběhu času"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Služby systemd"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "Systémy"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "Systémy lze spravovat v souboru <0>config.yml</0> uvnitř datového adr
|
||||
msgid "Table"
|
||||
msgstr "Tabulka"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Úlohy"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Teplota"
|
||||
@@ -1062,7 +1303,7 @@ msgstr "Teploty systémových senzorů"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
msgstr "Testovat <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Test notification sent"
|
||||
@@ -1124,6 +1365,11 @@ msgstr "Tokeny umožňují agentům připojení a registraci. Otisky jsou stabil
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "Tokeny a otisky slouží k ověření připojení WebSocket k uzlu."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Celkem"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "Celkový přijatý objem dat pro každé rozhraní"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "Celkový přijatý objem dat pro každé rozhraní"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Celkový odeslaný objem dat pro každé rozhraní"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Celkem: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Spuštěno službou"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Spouštěče"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "Spustí se, když využití paměti během 1 minuty překročí prahovou hodnotu"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "Spustí se, když kombinace up/down překročí prahovou hodnotu"
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Spustí se, když využití procesoru překročí prahovou hodnotu"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "Spustí se, když využití GPU překročí prahovou hodnotu"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Spustí se, když využití paměti překročí prahovou hodnotu"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "Spouští se, když se změní dostupnost"
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Spustí se, když využití disku překročí prahovou hodnotu"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Typ"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "Soubor jednotky"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "Univerzální token"
|
||||
msgid "Unknown"
|
||||
msgstr "Neznámá"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "Neomezeno"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "Funkční ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Aktualizováno"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "Aktualizováno každých 10 minut."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Odeslání"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "Doba provozu"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Využití"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "Hodnota"
|
||||
msgid "View"
|
||||
msgstr "Zobrazení"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "Zobrazit více"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "Čeká se na dostatek záznamů k zobrazení"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Chcete nám pomoci s našimi překlady ještě lépe? Podívejte se na <0>Crowdin</0> pro více informací."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Chce"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Varování (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "YAML konfigurace"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML konfigurace"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Ano"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Vaše uživatelská nastavení byla aktualizována."
|
||||
|
||||
@@ -8,36 +8,33 @@ msgstr ""
|
||||
"Language: da\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-08-28 23:21\n"
|
||||
"PO-Revision-Date: 2025-10-28 23:00\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Danish\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: da\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# day} other {# days}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# hour} other {# hours}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. 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 ""
|
||||
msgstr "{0} af {1} række(r) valgt."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} dag} other {{countString} dage}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} time} other {{countString} timer}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} minut} other {{countString} minutter}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
@@ -46,7 +43,7 @@ msgstr "1 time"
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr ""
|
||||
msgstr "1 minut"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 minute"
|
||||
@@ -63,7 +60,7 @@ msgstr "12 timer"
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr ""
|
||||
msgstr "15 minutter"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "24 hours"
|
||||
@@ -76,7 +73,7 @@ msgstr "30 dage"
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr ""
|
||||
msgstr "5 minutter"
|
||||
|
||||
#. Table column
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
@@ -87,12 +84,16 @@ msgstr "Handlinger"
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
msgstr "Aktiv"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktive Alarmer"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "Aktiv tilstand"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Tilføj <0>System</0>"
|
||||
@@ -116,7 +117,11 @@ msgstr "Juster visningsindstillinger for diagrammer."
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
msgstr "Administrator"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "Efter"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
@@ -126,7 +131,7 @@ msgstr "Agent"
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Alert History"
|
||||
msgstr ""
|
||||
msgstr "Advarselshistorik"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
@@ -153,7 +158,7 @@ msgstr "Er du sikker på, at du vil slette {name}?"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Are you sure?"
|
||||
msgstr ""
|
||||
msgstr "Er du sikker?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Automatic copy requires a secure context."
|
||||
@@ -187,7 +192,7 @@ msgstr "Gennemsnitlig udnyttelse af {0}"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "Gennemsnitlig udnyttelse af GPU-motorer"
|
||||
msgstr "Gennemsnitlig udnyttelse af GPU-enheder"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
@@ -203,6 +208,18 @@ msgstr "Båndbredde"
|
||||
msgid "Battery"
|
||||
msgstr "Batteri"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Blev aktiv"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Blev inaktiv"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Før"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel understøtter OpenID Connect og mange OAuth2 godkendelsesudbydere."
|
||||
@@ -218,33 +235,57 @@ msgstr "Binær"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr ""
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "Opstartstilstand"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr ""
|
||||
msgstr "Bytes (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffere"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Kan genindlæse"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Kan starte"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Kan stoppe"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Fortryd"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Kapacitet"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Forsigtig - muligt tab af data"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr ""
|
||||
msgstr "Celsius (°C)"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
msgstr ""
|
||||
msgstr "Ændre viste enheder for målinger."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change general application options."
|
||||
@@ -279,9 +320,13 @@ msgstr "Tjek din notifikationstjeneste"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Klik på en container for at se mere information."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Klik på en enhed for at se flere oplysninger."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr ""
|
||||
msgstr "Klik på et system for at se mere information."
|
||||
|
||||
#: src/components/ui/input-copy.tsx
|
||||
msgid "Click to copy"
|
||||
@@ -301,9 +346,13 @@ msgstr "Konfigurer hvordan du modtager advarselsmeddelelser."
|
||||
msgid "Confirm password"
|
||||
msgstr "Bekræft adgangskode"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr ""
|
||||
msgstr "Forbindelsen er nede"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -329,7 +378,7 @@ msgstr "Kopiér docker run"
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgctxt "Environment variables"
|
||||
msgid "Copy env"
|
||||
msgstr ""
|
||||
msgstr "Kopier miljø"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Copy host"
|
||||
@@ -350,23 +399,41 @@ msgstr "Kopier tekst"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
|
||||
msgstr ""
|
||||
msgstr "Kopier installationskommandoen for agenten nedenfor, eller registrer agenter automatisk med en <0>universalnøgle</0>."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
|
||||
msgstr ""
|
||||
msgstr "Kopier <0>docker-compose.yml</0> indholdet for agenten nedenfor, eller registrer agenter automatisk med en <1>universalnøgle</1>."
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Copy YAML"
|
||||
msgstr ""
|
||||
msgstr "Kopier YAML"
|
||||
|
||||
#: 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"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "CPU-kerner"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU-tidsfordeling"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU forbrug"
|
||||
@@ -378,7 +445,7 @@ msgstr "Opret konto"
|
||||
#. Context: date created
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
msgid "Created"
|
||||
msgstr ""
|
||||
msgstr "Oprettet"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Critical (%)"
|
||||
@@ -397,6 +464,11 @@ msgstr "Kumulativ upload"
|
||||
msgid "Current state"
|
||||
msgstr "Nuværende tilstand"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Cykler"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Oversigtspanel"
|
||||
@@ -412,12 +484,20 @@ msgstr "Slet"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Delete fingerprint"
|
||||
msgstr ""
|
||||
msgstr "Slet fingeraftryk"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Beskrivelse"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Detalje"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Enhed"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -433,7 +513,7 @@ msgstr "Disk I/O"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Disk unit"
|
||||
msgstr ""
|
||||
msgstr "Diskenhed"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "Docker Netværk I/O"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentation"
|
||||
|
||||
@@ -471,15 +552,15 @@ msgstr "Nede"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Down ({downSystemsLength})"
|
||||
msgstr ""
|
||||
msgstr "Nede ({downSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Download"
|
||||
msgstr "Download"
|
||||
msgstr "Hent ned"
|
||||
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
msgid "Duration"
|
||||
msgstr ""
|
||||
msgstr "Varighed"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -518,6 +599,7 @@ msgstr "Indtast din engangsadgangskode."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Fejl"
|
||||
|
||||
@@ -528,13 +610,21 @@ msgstr "Fejl"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Overskrider {0}{1} i sidste {2, plural, one {# minut} other {# minutter}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Eksisterende systemer ikke defineret i <0>config.yml</0> vil blive slettet. Opret venligst regelmæssige sikkerhedskopier."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Afsluttet aktiv"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr ""
|
||||
msgstr "Eksporter"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Export configuration"
|
||||
@@ -546,7 +636,11 @@ msgstr "Eksporter din nuværende systemkonfiguration."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
msgstr "Fahrenheit (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Mislykkede attributter:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
@@ -565,16 +659,27 @@ msgstr "Afsendelse af testnotifikation mislykkedes"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Kunne ikke opdatere alarm"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Fingerprint"
|
||||
msgstr ""
|
||||
msgstr "Fingeraftryk"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
@@ -603,12 +708,16 @@ msgstr "Generelt"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU-motorer"
|
||||
msgstr "GPU-enheder"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Gpu Strøm Træk"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU-forbrug"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Gitter"
|
||||
@@ -639,7 +748,7 @@ msgstr "Hvis du har mistet adgangskoden til din administratorkonto, kan du nulst
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgctxt "Docker image"
|
||||
msgid "Image"
|
||||
msgstr "Image"
|
||||
msgstr "Billede"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Invalid email address."
|
||||
@@ -648,7 +757,7 @@ msgstr "Ugyldig email adresse."
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
msgstr "Kerne"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Language"
|
||||
@@ -656,28 +765,45 @@ msgstr "Sprog"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Layout"
|
||||
msgstr "Layout"
|
||||
msgstr "Opstilling"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "Livscyklus"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr ""
|
||||
msgstr "Belastning Gennemsnitlig"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Load Average 15m"
|
||||
msgstr ""
|
||||
msgstr "Belastning Gennemsnitlig 15m"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Load Average 1m"
|
||||
msgstr ""
|
||||
msgstr "Belastning Gennemsnitlig 1m"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Load Average 5m"
|
||||
msgstr ""
|
||||
msgstr "Belastning Gennemsnitlig 5m"
|
||||
|
||||
#. Short label for load average
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Load Avg"
|
||||
msgstr ""
|
||||
msgstr "Belastning gns."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "Indlæsningstilstand"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Indlæser..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
@@ -702,6 +828,10 @@ msgstr "Logs"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Leder du i stedet for efter hvor du kan oprette alarmer? Klik på klokken <0/> ikoner i system tabellen."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Administrer display og notifikationsindstillinger."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "Maks. 1 min"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "Hukommelse"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Hukommelsesgrænse"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,16 +871,22 @@ msgstr "Hukommelsesforbrug"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Hukommelsesforbrug af dockercontainere"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
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
|
||||
msgid "Network traffic of docker containers"
|
||||
@@ -755,16 +902,31 @@ msgstr "Netværkstrafik af offentlige grænseflader"
|
||||
#. Context: Bytes or bits
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Network unit"
|
||||
msgstr ""
|
||||
msgstr "Netværksenhed"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "Nej"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "Ingen resultater fundet."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr ""
|
||||
msgstr "Ingen resultater."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "Ingen S.M.A.R.T.-attributter tilgængelige for denne enhed."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -799,6 +961,10 @@ msgstr "Åbn menu"
|
||||
msgid "Or continue with"
|
||||
msgstr "Eller fortsæt med"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Andre"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Overskriv eksisterende alarmer"
|
||||
@@ -812,7 +978,7 @@ msgstr "Side"
|
||||
#. placeholder {1}: table.getPageCount()
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Page {0} of {1}"
|
||||
msgstr ""
|
||||
msgstr "Side {0} af {1}"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Pages / Settings"
|
||||
@@ -845,7 +1011,16 @@ msgstr "Sat på pause"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr ""
|
||||
msgstr "Sat på pause ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Gennemsnitlig udnyttelse pr. kerne"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Procentdel af tid brugt i hver tilstand"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
@@ -884,6 +1059,11 @@ msgstr "Log venligst ind på din konto"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#. 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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "Præcis udnyttelse på det registrerede tidspunkt"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Foretrukket sprog"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Proces startet"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "Modtaget"
|
||||
msgid "Refresh"
|
||||
msgstr "Opdater"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Relationer"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Anmod om engangsadgangskode"
|
||||
@@ -921,6 +1109,14 @@ msgstr "Anmod om engangsadgangskode"
|
||||
msgid "Request OTP"
|
||||
msgstr "Anmod OTP"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Kræves af"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Kræver"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Nulstil adgangskode"
|
||||
@@ -929,19 +1125,40 @@ msgstr "Nulstil adgangskode"
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Resolved"
|
||||
msgstr ""
|
||||
msgstr "Løst"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Genstarter"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Genoptag"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr ""
|
||||
msgstr "Roter nøgle"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Rows per page"
|
||||
msgstr ""
|
||||
msgstr "Rækker per side"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Køretidsmålinger"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "S.M.A.R.T.-detaljer"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. selvtest"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
@@ -972,6 +1189,14 @@ msgstr "Se <0>meddelelsesindstillinger</0> for at konfigurere, hvordan du modtag
|
||||
msgid "Sent"
|
||||
msgstr "Sendt"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Serienummer"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Tjenestedetaljer"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Indstil procentvise tærskler for målerfarver."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "Sorter efter"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr ""
|
||||
msgstr "Tilstand"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Undertilstand"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap plads brugt af systemet"
|
||||
@@ -1028,6 +1260,10 @@ msgstr "System"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "System load averages over time"
|
||||
msgstr "Gennemsnitlig system belastning over tid"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
@@ -1042,7 +1278,12 @@ msgstr "Systemer kan være administreres i filen <0>config.yml</0> i din datamap
|
||||
msgid "Table"
|
||||
msgstr "Tabel"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Opgaver"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Temperatur"
|
||||
@@ -1054,7 +1295,7 @@ msgstr "Temperatur"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Temperature unit"
|
||||
msgstr ""
|
||||
msgstr "Temperaturenhed"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
@@ -1078,7 +1319,7 @@ msgstr "Denne handling kan ikke fortrydes. Dette vil permanent slette alle aktue
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "This will permanently delete all selected records from the database."
|
||||
msgstr ""
|
||||
msgstr "Dette vil permanent slette alle poster fra databasen."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Throughput of {extraFsName}"
|
||||
@@ -1108,21 +1349,26 @@ msgstr "Skift tema"
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Token"
|
||||
msgstr ""
|
||||
msgstr "Nøgle"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Tokens & Fingerprints"
|
||||
msgstr ""
|
||||
msgstr "Nøgler & fingeraftryk"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
|
||||
msgstr ""
|
||||
msgstr "Nøgler tillader agenter at oprette forbindelse og registrere. Fingeraftryk er stabile identifikatorer unikke for hvert system, indstillet ved første forbindelse."
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr ""
|
||||
msgstr "Nøgler og fingeraftryk bruges til at godkende WebSocket-forbindelser til hubben."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Samlet"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
@@ -1132,17 +1378,30 @@ msgstr "Samlet modtaget data for hver interface"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Samlet sendt data for hver interface"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "I alt: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Udløst af"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Udløsere"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr ""
|
||||
msgstr "Udløser når 1 minut belastning gennemsnit overstiger en tærskel"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 15 minute load average exceeds a threshold"
|
||||
msgstr ""
|
||||
msgstr "Udløser når 15 minut belastning gennemsnit overstiger en tærskel"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 5 minute load average exceeds a threshold"
|
||||
msgstr ""
|
||||
msgstr "Udløser når 5 minut belastning gennemsnit overstiger en tærskel"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "Udløses når de kombinerede op/ned overstiger en tærskel"
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Udløser når CPU-forbrug overstiger en tærskel"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Udløser når hukommelsesforbruget overstiger en tærskel"
|
||||
@@ -1168,21 +1431,34 @@ msgstr "Udløser når status skifter mellem op og ned"
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Udløser når brugen af en disk overstiger en tærskel"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr ""
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
msgstr ""
|
||||
msgstr "Enhedspræferencer"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Universal token"
|
||||
msgstr ""
|
||||
msgstr "Universalnøgle"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Unknown"
|
||||
msgstr "Ukendt"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr ""
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1191,15 +1467,20 @@ msgstr "Oppe"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Up ({upSystemsLength})"
|
||||
msgstr ""
|
||||
msgstr "Oppe ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Opdateret"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "Opdateret hver 10. minut."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Upload"
|
||||
msgstr "Overfør"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Uptime"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "Oppetid"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Forbrug"
|
||||
|
||||
@@ -1228,19 +1510,20 @@ msgstr "Brugere"
|
||||
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
msgid "Value"
|
||||
msgstr ""
|
||||
msgstr "Værdi"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "View"
|
||||
msgstr "Vis"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "Se mere"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "View your 200 most recent alerts."
|
||||
msgstr ""
|
||||
msgstr "Se dine 200 nyeste alarmer."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Visible Fields"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "Venter på nok posteringer til at vise"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Vil du hjælpe os med at gøre vores oversættelser endnu bedre? Tjek <0>Crowdin</0> for flere detaljer."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Ønsker"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Advarsel (%)"
|
||||
@@ -1268,7 +1555,7 @@ msgstr "Webhook / Push notifikationer"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
|
||||
msgstr ""
|
||||
msgstr "Når aktiveret tillader denne nøgle agenter at selvregistrere uden forudgående systemoprettelse. Udløber efter en time eller ved hub-genstart."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
@@ -1290,6 +1577,12 @@ msgstr "YAML Konfiguration"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML Konfiguration"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Ja"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Dine brugerindstillinger er opdateret."
|
||||
|
||||
@@ -8,30 +8,15 @@ msgstr ""
|
||||
"Language: de\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-10-05 16:13\n"
|
||||
"PO-Revision-Date: 2025-10-28 22:59\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: German\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: de\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# Tag} other {# Tage}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# Stunde} other {# Stunden}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# Minute} other {# Minuten}}"
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
@@ -39,6 +24,18 @@ msgstr "{0, plural, one {# Minute} other {# Minuten}}"
|
||||
msgid "{0} of {1} row(s) selected."
|
||||
msgstr "{0} von {1} Zeile(n) ausgewählt."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} Tag} other {{countString} Tage}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} Stunde} other {{countString} Stunden}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} Minute} other {{countString} Minuten}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 Stunde"
|
||||
@@ -93,6 +90,10 @@ msgstr "Aktiv"
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktive Warnungen"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "Aktiver Zustand"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>System</0> hinzufügen"
|
||||
@@ -118,6 +119,10 @@ msgstr "Anzeigeoptionen für Diagramme anpassen."
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "Nach"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
@@ -126,7 +131,7 @@ msgstr "Agent"
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Alert History"
|
||||
msgstr "Alarm-Verlauf"
|
||||
msgstr "Warnungsverlauf"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
@@ -203,6 +208,18 @@ msgstr "Bandbreite"
|
||||
msgid "Battery"
|
||||
msgstr "Batterie"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Wurde aktiv"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Wurde inaktiv"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Vor"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel unterstützt OpenID Connect und viele OAuth2-Authentifizierungsanbieter."
|
||||
@@ -220,6 +237,10 @@ msgstr "Binär"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "Boot-Zustand"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
@@ -229,11 +250,31 @@ msgstr "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Puffer"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Kann neu laden"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Kann starten"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Kann stoppen"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Abbrechen"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "Fähigkeiten"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Kapazität"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Vorsicht - potenzieller Datenverlust"
|
||||
@@ -277,7 +318,11 @@ msgstr "Überprüfe deinen Benachrichtigungsdienst"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Klicken Sie auf einen Container, um weitere Informationen zu sehen."
|
||||
msgstr "Klicke auf einen Container, um weitere Informationen zu sehen."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Klicke auf ein Gerät, um weitere Informationen zu sehen."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
@@ -301,6 +346,10 @@ msgstr "Konfiguriere, wie du Warnbenachrichtigungen erhältst."
|
||||
msgid "Confirm password"
|
||||
msgstr "Passwort bestätigen"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "Konflikte"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "Verbindung unterbrochen"
|
||||
@@ -350,23 +399,41 @@ msgstr "Text kopieren"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
|
||||
msgstr "Kopieren Sie den Installationsbefehl für den Agent unten oder registrieren Sie Agents automatisch mit einem <0>universellen Token</0>."
|
||||
msgstr "Kopiere den Installationsbefehl für den Agent unten oder registriere Agents automatisch mit einem <0>universellen Token</0>."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
|
||||
msgstr "Kopieren Sie den<0>docker-compose.yml</0> Inhalt für den Agent unten oder registrieren Sie Agents automatisch mit einem <1>universellen Token</1>."
|
||||
msgstr "Kopiere den<0>docker-compose.yml</0> Inhalt für den Agent unten oder registriere Agents automatisch mit einem <1>universellen Token</1>."
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Copy YAML"
|
||||
msgstr "YAML kopieren"
|
||||
|
||||
#: 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"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "CPU-Kerne"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "CPU-Spitze"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "CPU-Zeit"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU-Zeit-Aufschlüsselung"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU-Auslastung"
|
||||
@@ -397,6 +464,11 @@ msgstr "Kumulativer Upload"
|
||||
msgid "Current state"
|
||||
msgstr "Aktueller Zustand"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Zyklen"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Dashboard"
|
||||
@@ -414,9 +486,17 @@ msgstr "Löschen"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "Fingerabdruck löschen"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Beschreibung"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Detail"
|
||||
msgstr "Details"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Gerät"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "Docker-Netzwerk-I/O"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentation"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "Geben Sie Ihr Einmalpasswort ein."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Fehler"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "Fehler"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Überschreitet {0}{1} in den letzten {2, plural, one {# Minute} other {# Minuten}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "Ausführungs-Haupt-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."
|
||||
msgstr "Bestehende Systeme, die nicht in der <0>config.yml</0> definiert sind, werden gelöscht. Bitte mache regelmäßige Backups."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Beendet aktiv"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "Exportieren"
|
||||
@@ -548,6 +638,10 @@ msgstr "Exportiere die aktuelle Systemkonfiguration."
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Fehlgeschlagene Attribute:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Authentifizierung fehlgeschlagen"
|
||||
@@ -565,9 +659,16 @@ msgstr "Testbenachrichtigung konnte nicht gesendet werden"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Warnung konnte nicht aktualisiert werden"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
@@ -576,6 +677,10 @@ msgstr "Filter..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "Fingerabdruck"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Für <0>{min}</0> {min, plural, one {Minute} other {Minuten}}"
|
||||
@@ -609,6 +714,10 @@ msgstr "GPU-Engines"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU-Leistungsaufnahme"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU-Auslastung"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Raster"
|
||||
@@ -658,6 +767,15 @@ msgstr "Sprache"
|
||||
msgid "Layout"
|
||||
msgstr "Anordnung"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "Lebenszyklus"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "Limit"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Durchschnittliche Systemlast"
|
||||
@@ -679,6 +797,14 @@ msgstr "Durchschnittliche Systemlast 5 Min"
|
||||
msgid "Load Avg"
|
||||
msgstr "Systemlast"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "Ladezustand"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Lädt..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Abmelden"
|
||||
@@ -702,6 +828,10 @@ msgstr "Protokolle"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Du möchtest neue Warnungen erstellen? Klicke dafür auf die Glocken-<0/>-Symbole in der Systemtabelle."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "Haupt-PID"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Anzeige- und Benachrichtigungseinstellungen verwalten."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "Max 1 Min"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "Arbeitsspeicher"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Arbeitsspeicherlimit"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "Arbeitsspeicher-Spitze"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "Arbeitsspeichernutzung"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Arbeitsspeichernutzung der Docker-Container"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modell"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "Netzwerkverkehr der öffentlichen Schnittstellen"
|
||||
msgid "Network unit"
|
||||
msgstr "Netzwerkeinheit"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "Nein"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "Keine Ergebnisse gefunden."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "Keine Ergebnisse."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "Für dieses Gerät sind keine S.M.A.R.T.-Attribute verfügbar."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "Menü öffnen"
|
||||
msgid "Or continue with"
|
||||
msgstr "Oder fortfahren mit"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Andere"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Bestehende Warnungen überschreiben"
|
||||
@@ -847,6 +1013,15 @@ msgstr "Pausiert"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "Pausiert ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Durchschnittliche Auslastung pro Kern"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Prozentsatz der Zeit in jedem Zustand"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Bitte <0>konfiguriere einen SMTP-Server</0>, um sicherzustellen, dass Warnungen zugestellt werden."
|
||||
@@ -884,6 +1059,11 @@ msgstr "Bitte melde dich bei deinem Konto an"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#. 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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,10 +1073,14 @@ msgstr "Genaue Nutzung zum aufgezeichneten Zeitpunkt"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Bevorzugte Sprache"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Prozess gestartet"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
msgstr "Schlüssel"
|
||||
msgstr "Öffentlicher Schlüssel"
|
||||
|
||||
#. Disk read
|
||||
#: src/components/routes/system.tsx
|
||||
@@ -913,6 +1097,10 @@ msgstr "Empfangen"
|
||||
msgid "Refresh"
|
||||
msgstr "Aktualisieren"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Beziehungen"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Einmalpasswort anfordern"
|
||||
@@ -921,6 +1109,14 @@ msgstr "Einmalpasswort anfordern"
|
||||
msgid "Request OTP"
|
||||
msgstr "OTP anfordern"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Benötigt von"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Benötigt"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Passwort zurücksetzen"
|
||||
@@ -931,10 +1127,19 @@ msgstr "Passwort zurücksetzen"
|
||||
msgid "Resolved"
|
||||
msgstr "Gelöst"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Neustarts"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Fortsetzen"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Root"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "Token rotieren"
|
||||
@@ -943,6 +1148,18 @@ msgstr "Token rotieren"
|
||||
msgid "Rows per page"
|
||||
msgstr "Zeilen pro Seite"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Laufzeitmetriken"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "S.M.A.R.T.-Details"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T.-Selbsttest"
|
||||
|
||||
#: 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."
|
||||
@@ -954,7 +1171,7 @@ msgstr "Einstellungen speichern"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Save system"
|
||||
msgstr "System sichern"
|
||||
msgstr "System speichern"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Search"
|
||||
@@ -972,6 +1189,14 @@ msgstr "Siehe <0>Benachrichtigungseinstellungen</0>, um zu konfigurieren, wie du
|
||||
msgid "Sent"
|
||||
msgstr "Gesendet"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Seriennummer"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Servicedetails"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Prozentuale Schwellenwerte für Zählerfarben festlegen."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "Sortieren nach"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Unterzustand"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Vom System genutzter Swap-Speicher"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "System"
|
||||
msgid "System load averages over time"
|
||||
msgstr "Systemlastdurchschnitt im Zeitverlauf"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Systemd-Dienste"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "Systeme"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "Systeme können in einer <0>config.yml</0>-Datei im Datenverzeichnis ver
|
||||
msgid "Table"
|
||||
msgstr "Tabelle"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Aufgaben"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Temperatur"
|
||||
@@ -1124,13 +1365,31 @@ msgstr "Tokens ermöglichen es Agents, sich zu verbinden und zu registrieren. Fi
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "Tokens und Fingerabdrücke werden verwendet, um WebSocket-Verbindungen zum Hub zu authentifizieren."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Gesamt"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "Gesamtdatenmenge für jede Schnittstelle empfangen"
|
||||
msgstr "Empfangene Gesamtdatenmenge je Schnittstelle "
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Gesamtdatenmenge für jede Schnittstelle gesendet"
|
||||
msgstr "Gesendete Gesamtdatenmenge je Schnittstelle"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Gesamt: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Ausgelöst von"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Trigger"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
@@ -1150,12 +1409,16 @@ msgstr "Löst aus, wenn ein Sensor einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die kombinierte Auf-/Abwärtsbewegung einen Schwellenwert überschreitet"
|
||||
msgstr "Löst aus, wenn die kombinierte Up- und Downloadrate einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die CPU-Auslastung einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die GPU-Auslastung einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die Arbeitsspeichernutzung einen Schwellenwert überschreitet"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "Löst aus, wenn der Status zwischen online und offline wechselt"
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die Nutzung einer Festplatte einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Typ"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "Unit-Datei"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "Universeller Token"
|
||||
msgid "Unknown"
|
||||
msgstr "Unbekannt"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "Unbegrenzt"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "aktiv ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Aktualisiert"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "Alle 10 Minuten aktualisiert."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Hochladen"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "Betriebszeit"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Nutzung"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "Wert"
|
||||
msgid "View"
|
||||
msgstr "Ansicht"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "Mehr anzeigen"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "Warten auf genügend Datensätze zur Anzeige"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Möchtest du uns helfen, unsere Übersetzungen noch besser zu machen? Schau dir <0>Crowdin</0> für weitere Details an."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Möchte"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Warnung (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "YAML-Konfiguration"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML-Konfiguration"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Ja"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Deine Benutzereinstellungen wurden aktualisiert."
|
||||
|
||||
1296
internal/site/src/locales/el/el.po
Normal file
1296
internal/site/src/locales/el/el.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -13,27 +13,24 @@ msgstr ""
|
||||
"Language-Team: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# day} other {# days}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# hour} other {# hours}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
|
||||
#. 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} of {1} row(s) selected."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 hour"
|
||||
@@ -88,6 +85,10 @@ msgstr "Active"
|
||||
msgid "Active Alerts"
|
||||
msgstr "Active Alerts"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "Active state"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Add <0>System</0>"
|
||||
@@ -113,6 +114,10 @@ msgstr "Adjust display options for charts."
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "After"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
@@ -198,6 +203,18 @@ msgstr "Bandwidth"
|
||||
msgid "Battery"
|
||||
msgstr "Battery"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Became active"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Became inactive"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Before"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
@@ -215,6 +232,10 @@ msgstr "Binary"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "Boot state"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
@@ -224,11 +245,31 @@ msgstr "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffers"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Can reload"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Can start"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Can stop"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Cancel"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "Capabilities"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Capacity"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Caution - potential data loss"
|
||||
@@ -274,6 +315,10 @@ msgstr "Check your notification service"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Click on a container to view more information."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Click on a device to view more information."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "Click on a system to view more information."
|
||||
@@ -296,6 +341,10 @@ msgstr "Configure how you receive alert notifications."
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirm password"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "Conflicts"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "Connection is down"
|
||||
@@ -356,12 +405,30 @@ msgid "Copy YAML"
|
||||
msgstr "Copy YAML"
|
||||
|
||||
#: 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"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "CPU Cores"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "CPU Peak"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "CPU time"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU Time Breakdown"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU Usage"
|
||||
@@ -392,6 +459,11 @@ msgstr "Cumulative Upload"
|
||||
msgid "Current state"
|
||||
msgstr "Current state"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Cycles"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Dashboard"
|
||||
@@ -409,10 +481,18 @@ msgstr "Delete"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "Delete fingerprint"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Detail"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Device"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -453,6 +533,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "Docker Network I/O"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Documentation"
|
||||
|
||||
@@ -513,6 +594,7 @@ msgstr "Enter your one-time password."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Error"
|
||||
|
||||
@@ -523,10 +605,18 @@ msgstr "Error"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "Exec main 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."
|
||||
msgstr "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Exited active"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "Export"
|
||||
@@ -543,6 +633,10 @@ msgstr "Export your current systems configuration."
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Failed Attributes:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Failed to authenticate"
|
||||
@@ -560,9 +654,16 @@ msgstr "Failed to send test notification"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Failed to update alert"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
@@ -571,6 +672,10 @@ msgstr "Filter..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "Fingerprint"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
@@ -604,6 +709,10 @@ msgstr "GPU Engines"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU Power Draw"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU Usage"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Grid"
|
||||
@@ -653,6 +762,15 @@ msgstr "Language"
|
||||
msgid "Layout"
|
||||
msgstr "Layout"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "Lifecycle"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "limit"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Load Average"
|
||||
@@ -674,6 +792,14 @@ msgstr "Load Average 5m"
|
||||
msgid "Load Avg"
|
||||
msgstr "Load Avg"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "Load state"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Loading..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Log Out"
|
||||
@@ -697,6 +823,10 @@ msgstr "Logs"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "Main PID"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Manage display and notification preferences."
|
||||
@@ -712,10 +842,21 @@ msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "Memory"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Memory limit"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "Memory Peak"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -725,9 +866,15 @@ msgstr "Memory Usage"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Memory usage of docker containers"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
@@ -752,15 +899,30 @@ msgstr "Network traffic of public interfaces"
|
||||
msgid "Network unit"
|
||||
msgstr "Network unit"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "No"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "No results found."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "No results."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "No S.M.A.R.T. attributes available for this device."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -794,6 +956,10 @@ msgstr "Open menu"
|
||||
msgid "Or continue with"
|
||||
msgstr "Or continue with"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Other"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Overwrite existing alerts"
|
||||
@@ -842,6 +1008,15 @@ msgstr "Paused"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "Paused ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Per-core average utilization"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Percentage of time spent in each state"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
@@ -879,6 +1054,11 @@ msgstr "Please sign in to your account"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#. 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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -888,6 +1068,10 @@ msgstr "Precise utilization at the recorded time"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Preferred Language"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Process started"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -908,6 +1092,10 @@ msgstr "Received"
|
||||
msgid "Refresh"
|
||||
msgstr "Refresh"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Relationships"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Request a one-time password"
|
||||
@@ -916,6 +1104,14 @@ msgstr "Request a one-time password"
|
||||
msgid "Request OTP"
|
||||
msgstr "Request OTP"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Required by"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Requires"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Reset Password"
|
||||
@@ -926,10 +1122,19 @@ msgstr "Reset Password"
|
||||
msgid "Resolved"
|
||||
msgstr "Resolved"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Restarts"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Resume"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Root"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "Rotate token"
|
||||
@@ -938,6 +1143,18 @@ msgstr "Rotate token"
|
||||
msgid "Rows per page"
|
||||
msgstr "Rows per page"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Runtime Metrics"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "S.M.A.R.T. Details"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. Self-Test"
|
||||
|
||||
#: 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."
|
||||
@@ -967,6 +1184,14 @@ msgstr "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgid "Sent"
|
||||
msgstr "Sent"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Serial Number"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Service Details"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Set percentage thresholds for meter colors."
|
||||
@@ -996,15 +1221,22 @@ msgstr "Sort By"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "State"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Sub State"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap space used by the system"
|
||||
@@ -1025,6 +1257,10 @@ msgstr "System"
|
||||
msgid "System load averages over time"
|
||||
msgstr "System load averages over time"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Systemd Services"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "Systems"
|
||||
@@ -1037,7 +1273,12 @@ msgstr "Systems may be managed in a <0>config.yml</0> file inside your data dire
|
||||
msgid "Table"
|
||||
msgstr "Table"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Tasks"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Temp"
|
||||
@@ -1119,6 +1360,11 @@ msgstr "Tokens allow agents to connect and register. Fingerprints are stable ide
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "Total data received for each interface"
|
||||
@@ -1127,6 +1373,19 @@ msgstr "Total data received for each interface"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Total data sent for each interface"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Total: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Triggered by"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Triggers"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "Triggers when 1 minute load average exceeds a threshold"
|
||||
@@ -1151,6 +1410,10 @@ msgstr "Triggers when combined up/down exceeds a threshold"
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Triggers when CPU usage exceeds a threshold"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "Triggers when GPU usage exceeds a threshold"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Triggers when memory usage exceeds a threshold"
|
||||
@@ -1163,6 +1426,14 @@ msgstr "Triggers when status switches between up and down"
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Triggers when usage of any disk exceeds a threshold"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "Unit file"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1178,6 +1449,11 @@ msgstr "Universal token"
|
||||
msgid "Unknown"
|
||||
msgstr "Unknown"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "Unlimited"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1189,9 +1465,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "Up ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Updated"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "Updated every 10 minutes."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Upload"
|
||||
@@ -1204,6 +1485,7 @@ msgstr "Uptime"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Usage"
|
||||
|
||||
@@ -1229,6 +1511,7 @@ msgstr "Value"
|
||||
msgid "View"
|
||||
msgstr "View"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "View more"
|
||||
@@ -1249,6 +1532,10 @@ msgstr "Waiting for enough records to display"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Wants"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Warning (%)"
|
||||
@@ -1285,6 +1572,12 @@ msgstr "YAML Config"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML Configuration"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Yes"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Your user settings have been updated."
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,30 +8,15 @@ msgstr ""
|
||||
"Language: fa\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-08-28 23:21\n"
|
||||
"PO-Revision-Date: 2025-10-28 23:00\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Persian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: fa\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# روز} other {# روز}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# ساعت} other {# ساعت}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# دقیقه} few {# دقیقه} many {# دقیقه} other {# دقیقه}}"
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
@@ -39,6 +24,18 @@ msgstr "{0, plural, one {# دقیقه} few {# دقیقه} many {# دقیقه} ot
|
||||
msgid "{0} of {1} row(s) selected."
|
||||
msgstr "{0} از {1} ردیف انتخاب شده است."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} روز} other {{countString} روز}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} ساعت} other {{countString} ساعت}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} دقیقه} few {{countString} دقیقه} many {{countString} دقیقه} other {{countString} دقیقه}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "۱ ساعت"
|
||||
@@ -93,6 +90,10 @@ msgstr "فعال"
|
||||
msgid "Active Alerts"
|
||||
msgstr " هشدارهای فعال"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "وضعیت فعال"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "افزودن <0>سیستم</0>"
|
||||
@@ -118,6 +119,10 @@ msgstr "تنظیم گزینههای نمایش برای نمودارها."
|
||||
msgid "Admin"
|
||||
msgstr "مدیر"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "بعد از"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "عامل"
|
||||
@@ -203,6 +208,18 @@ msgstr "پهنای باند"
|
||||
msgid "Battery"
|
||||
msgstr "باتری"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "فعال شد"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "غیرفعال شد"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "قبل از"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "بِزل از OpenID Connect و بسیاری از ارائهدهندگان احراز هویت OAuth2 پشتیبانی میکند."
|
||||
@@ -220,6 +237,10 @@ msgstr "دودویی"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "بیت (کیلوبیت بر ثانیه، مگابیت بر ثانیه، گیگابیت بر ثانیه)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "وضعیت بوت"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
@@ -229,11 +250,31 @@ msgstr "بایت (کیلوبایت بر ثانیه، مگابایت بر ثان
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "حافظه پنهان / بافرها"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "میتواند بارگذاری مجدد شود"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "میتواند شروع شود"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "میتواند متوقف شود"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "لغو"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "قابلیتها"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "ظرفیت"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "احتیاط - احتمال از دست رفتن دادهها"
|
||||
@@ -279,6 +320,10 @@ msgstr "سرویس اطلاعرسانی خود را بررسی کنید"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "برای مشاهده اطلاعات بیشتر روی کانتینر کلیک کنید."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "برای مشاهده اطلاعات بیشتر روی دستگاه کلیک کنید."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "برای مشاهده اطلاعات بیشتر روی یک سیستم کلیک کنید."
|
||||
@@ -301,6 +346,10 @@ msgstr "نحوه دریافت هشدارهای اطلاعرسانی را پی
|
||||
msgid "Confirm password"
|
||||
msgstr "تأیید رمز عبور"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "تعارضها"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "اتصال قطع است"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "کپی YAML"
|
||||
|
||||
#: 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 "پردازنده"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "هستههای CPU"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "حداکثر CPU"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "زمان CPU"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "تجزیه زمان CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "میزان استفاده از پردازنده"
|
||||
@@ -397,6 +464,11 @@ msgstr "آپلود تجمعی"
|
||||
msgid "Current state"
|
||||
msgstr "وضعیت فعلی"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "چرخهها"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "داشبورد"
|
||||
@@ -414,10 +486,18 @@ msgstr "حذف"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "حذف اثر انگشت"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "توضیحات"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "جزئیات"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "دستگاه"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "ورودی/خروجی شبکه داکر"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "مستندات"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "رمز عبور یکبار مصرف خود را وارد کنید."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "خطا"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "خطا"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "در {2, plural, one {# دقیقه} other {# دقیقه}} گذشته از {0}{1} بیشتر است"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "سیستمهای موجود که در <0>config.yml</0> تعریف نشدهاند حذف خواهند شد. لطفاً به طور منظم پشتیبانگیری کنید."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "خروج فعال"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "خروجی گرفتن"
|
||||
@@ -548,6 +638,10 @@ msgstr "پیکربندی سیستمهای فعلی خود را خارج کن
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "فارنهایت (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "ویژگیهای ناموفق:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "احراز هویت ناموفق بود"
|
||||
@@ -565,9 +659,16 @@ msgstr "ارسال اعلان آزمایشی ناموفق بود"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "بهروزرسانی هشدار ناموفق بود"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "فیلتر..."
|
||||
@@ -576,6 +677,10 @@ msgstr "فیلتر..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "اثر انگشت"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "فرمویر"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "برای <0>{min}</0> {min, plural, one {دقیقه} other {دقیقه}}"
|
||||
@@ -609,6 +714,10 @@ msgstr "موتورهای GPU"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "مصرف برق پردازنده گرافیکی"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "میزان استفاده از GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "جدول"
|
||||
@@ -658,6 +767,15 @@ msgstr "زبان"
|
||||
msgid "Layout"
|
||||
msgstr "طرحبندی"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "چرخه حیات"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "میانگین بار"
|
||||
@@ -679,6 +797,14 @@ msgstr "میانگین بار ۵ دقیقه"
|
||||
msgid "Load Avg"
|
||||
msgstr "میانگین بار"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "وضعیت بارگذاری"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "در حال بارگذاری..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "خروج"
|
||||
@@ -702,6 +828,10 @@ msgstr "لاگها"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "به دنبال جایی برای ایجاد هشدار هستید؟ روی آیکونهای زنگ <0/> در جدول سیستمها کلیک کنید."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "مدیریت تنظیمات نمایش و اعلانها."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "حداکثر ۱ دقیقه"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "حافظه"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "محدودیت حافظه"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "حداکثر حافظه"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "میزان استفاده از حافظه"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "میزان استفاده از حافظه کانتینرهای داکر"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "مدل"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "نام"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "ترافیک شبکه رابطهای عمومی"
|
||||
msgid "Network unit"
|
||||
msgstr "واحد شبکه"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "خیر"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "هیچ نتیجهای یافت نشد."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "نتیجهای یافت نشد."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "هیچ ویژگی S.M.A.R.T برای این دستگاه موجود نیست."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "باز کردن منو"
|
||||
msgid "Or continue with"
|
||||
msgstr "یا ادامه با"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "سایر"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "بازنویسی هشدارهای موجود"
|
||||
@@ -847,6 +1013,15 @@ msgstr "مکث شده"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "مکث شده ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "میانگین استفاده در هر هسته"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "درصد زمان صرف شده در هر حالت"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "لطفاً برای اطمینان از تحویل هشدارها، یک <0>سرور SMTP پیکربندی کنید</0>."
|
||||
@@ -884,6 +1059,11 @@ msgstr "لطفاً به حساب کاربری خود وارد شوید"
|
||||
msgid "Port"
|
||||
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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "میزان دقیق استفاده در زمان ثبت شده"
|
||||
msgid "Preferred Language"
|
||||
msgstr "زبان ترجیحی"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "فرآیند شروع شد"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "دریافت شد"
|
||||
msgid "Refresh"
|
||||
msgstr "تازهسازی"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "روابط"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "درخواست رمز عبور یکبار مصرف"
|
||||
@@ -921,6 +1109,14 @@ msgstr "درخواست رمز عبور یکبار مصرف"
|
||||
msgid "Request OTP"
|
||||
msgstr "درخواست OTP"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "مورد نیاز توسط"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "نیازمند"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "بازنشانی رمز عبور"
|
||||
@@ -931,10 +1127,19 @@ msgstr "بازنشانی رمز عبور"
|
||||
msgid "Resolved"
|
||||
msgstr "حل شده"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "راهاندازی مجدد"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "ادامه"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "چرخش توکن"
|
||||
@@ -943,6 +1148,18 @@ msgstr "چرخش توکن"
|
||||
msgid "Rows per page"
|
||||
msgstr "ردیف در هر صفحه"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "معیارهای زمان اجرا"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "جزئیات S.M.A.R.T"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "تست خود S.M.A.R.T"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "آدرس را با استفاده از کلید Enter یا کاما ذخیره کنید. برای غیرفعال کردن اعلانهای ایمیلی، خالی بگذارید."
|
||||
@@ -972,6 +1189,14 @@ msgstr "برای پیکربندی نحوه دریافت هشدارها، به <0
|
||||
msgid "Sent"
|
||||
msgstr "ارسال شد"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "شماره سریال"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "جزئیات سرویس"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "آستانه های درصدی را برای رنگ های متر تنظیم کنید."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "مرتبسازی بر اساس"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "وضعیت"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "وضعیت"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "وضعیت فرعی"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "فضای Swap استفاده شده توسط سیستم"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "سیستم"
|
||||
msgid "System load averages over time"
|
||||
msgstr "میانگین بار سیستم در طول زمان"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "سیستمها"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "سیستمها ممکن است در یک فایل <0>config.yml</0>
|
||||
msgid "Table"
|
||||
msgstr "جدول"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "وظایف"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "دما"
|
||||
@@ -1124,6 +1365,11 @@ msgstr "توکنها به عاملها اجازه اتصال و ثبت
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "توکنها و اثرات انگشت برای احراز هویت اتصالات WebSocket به هاب استفاده میشوند."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "کل"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "دادههای کل دریافت شده برای هر رابط"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "دادههای کل دریافت شده برای هر رابط"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "دادههای کل ارسال شده برای هر رابط"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "کل: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "فعال شده توسط"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "محرکها"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "هنگامی که میانگین بار ۱ دقیقهای از یک آستانه فراتر رود، فعال میشود"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "هنگامی که مجموع بالا/پایین از یک آستانه
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "هنگامی که میزان استفاده از CPU از یک آستانه فراتر رود، فعال میشود"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "هنگامی که میزان استفاده از GPU از یک آستانه فراتر رود، فعال میشود"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "هنگامی که میزان استفاده از حافظه از یک آستانه فراتر رود، فعال میشود"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "هنگامی که وضعیت بین بالا و پایین تغییر م
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "هنگامی که استفاده از هر دیسکی از یک آستانه فراتر رود، فعال میشود"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "نوع"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr ""
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "توکن جهانی"
|
||||
msgid "Unknown"
|
||||
msgstr "ناشناخته"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "نامحدود"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "فعال ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "بهروزرسانی شد"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "هر ۱۰ دقیقه بهروزرسانی میشود."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "آپلود"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "آپتایم"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "میزان استفاده"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "مقدار"
|
||||
msgid "View"
|
||||
msgstr "مشاهده"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "مشاهده بیشتر"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "در انتظار رکوردهای کافی برای نمایش"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "میخواهید به ما کمک کنید تا ترجمههای خود را بهتر کنیم؟ برای جزئیات بیشتر به <0>Crowdin</0> مراجعه کنید."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "میخواهد"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "هشدار (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "پیکربندی YAML"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "پیکربندی YAML"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "بله"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "تنظیمات کاربری شما بهروزرسانی شد."
|
||||
|
||||
@@ -8,30 +8,15 @@ msgstr ""
|
||||
"Language: fr\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-10-20 16:38\n"
|
||||
"PO-Revision-Date: 2025-11-11 19:25\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: French\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: fr\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# jour} other {# jours}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# heure} other {# heures}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
@@ -39,6 +24,18 @@ msgstr "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# min
|
||||
msgid "{0} of {1} row(s) selected."
|
||||
msgstr "{0} sur {1} ligne(s) sélectionnée(s)."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} jour} other {{countString} jours}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} heure} other {{countString} heures}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 heure"
|
||||
@@ -93,6 +90,10 @@ msgstr "Active"
|
||||
msgid "Active Alerts"
|
||||
msgstr "Alertes actives"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "État actif"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Ajouter <0>un Système</0>"
|
||||
@@ -118,6 +119,10 @@ msgstr "Ajuster les options d'affichage pour les graphiques."
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "Après"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
@@ -203,6 +208,18 @@ msgstr "Bande passante"
|
||||
msgid "Battery"
|
||||
msgstr "Batterie"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Devenu actif"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Devenu inactif"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Avant"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel prend en charge OpenID Connect et de nombreux fournisseurs d'authentification OAuth2."
|
||||
@@ -220,6 +237,10 @@ msgstr "Binaire"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
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)"
|
||||
@@ -229,11 +250,31 @@ msgstr "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Tampons"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Peut recharger"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Peut démarrer"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Peut arrêter"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "Capacités"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Capacité"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Attention - perte de données potentielle"
|
||||
@@ -279,6 +320,10 @@ msgstr "Vérifiez votre service de notification"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Cliquez sur un conteneur pour voir plus d'informations."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Cliquez sur un appareil pour voir plus d'informations."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "Cliquez sur un système pour voir plus d'informations."
|
||||
@@ -301,6 +346,10 @@ msgstr "Configurez comment vous recevez les notifications d'alerte."
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmer le mot de passe"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "Conflits"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "Connexion interrompue"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "Copier YAML"
|
||||
|
||||
#: 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"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "Cœurs CPU"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "Pic CPU"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "Temps CPU"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Répartition du temps CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "Utilisation du CPU"
|
||||
@@ -397,6 +464,11 @@ msgstr "Téléversement cumulatif"
|
||||
msgid "Current state"
|
||||
msgstr "État actuel"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Cycles"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Tableau de bord"
|
||||
@@ -414,10 +486,18 @@ msgstr "Supprimer"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "Supprimer l'empreinte"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Détail"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Appareil"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ 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"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "Entrez votre mot de passe à usage unique."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Erreur"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "Erreur"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Dépasse {0}{1} dans {2, plural, one {la dernière # minute} other {les dernières # minutes}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "PID principal d'exécution"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Les systèmes existants non définis dans <0>config.yml</0> seront supprimés. Veuillez faire des sauvegardes régulières."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Sorti actif"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "Exporter"
|
||||
@@ -548,6 +638,10 @@ msgstr "Exportez la configuration actuelle de vos systèmes."
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Attributs défaillants :"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Échec de l'authentification"
|
||||
@@ -565,9 +659,16 @@ msgstr "Échec de l'envoi de la notification de test"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Échec de la mise à jour de l'alerte"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filtrer..."
|
||||
@@ -576,6 +677,10 @@ msgstr "Filtrer..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "Empreinte"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Micrologiciel"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Pour <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
@@ -609,6 +714,10 @@ msgstr "Moteurs GPU"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Consommation du GPU"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "Utilisation GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Grille"
|
||||
@@ -658,6 +767,15 @@ msgstr "Langue"
|
||||
msgid "Layout"
|
||||
msgstr "Disposition"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "Cycle de vie"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "limite"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Charge moyenne"
|
||||
@@ -679,6 +797,14 @@ msgstr "Charge moyenne 5m"
|
||||
msgid "Load Avg"
|
||||
msgstr "Charge moy."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "État de charge"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Chargement..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Déconnexion"
|
||||
@@ -702,6 +828,10 @@ msgstr "Journaux"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Vous cherchez plutôt où créer des alertes ? Cliquez sur les icônes de cloche <0/> dans le tableau des systèmes."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "PID principal"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Gérer les préférences d'affichage et de notification."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "Mémoire"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Limite mémoire"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "Pic mémoire"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "Utilisation de la mémoire"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Utilisation de la mémoire des conteneurs Docker"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modèle"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "Trafic réseau des interfaces publiques"
|
||||
msgid "Network unit"
|
||||
msgstr "Unité réseau"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "Non"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "Aucun résultat trouvé."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "Aucun résultat."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "Aucun attribut S.M.A.R.T. disponible pour cet appareil."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "Ouvrir le menu"
|
||||
msgid "Or continue with"
|
||||
msgstr "Ou continuer avec"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Autre"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Écraser les alertes existantes"
|
||||
@@ -847,6 +1013,15 @@ msgstr "En pause"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "Mis en pause ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Utilisation moyenne par cœur"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Pourcentage de temps passé dans chaque état"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Veuillez <0>configurer un serveur SMTP</0> pour garantir la livraison des alertes."
|
||||
@@ -884,6 +1059,11 @@ msgstr "Veuillez vous connecter à votre compte"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#. 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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "Utilisation précise au moment enregistré"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Langue préférée"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Processus démarré"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "Reçu"
|
||||
msgid "Refresh"
|
||||
msgstr "Actualiser"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Relations"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Demander un mot de passe à usage unique"
|
||||
@@ -921,6 +1109,14 @@ msgstr "Demander un mot de passe à usage unique"
|
||||
msgid "Request OTP"
|
||||
msgstr "Demander OTP"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Requis par"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Requiert"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Réinitialiser le mot de passe"
|
||||
@@ -929,12 +1125,21 @@ msgstr "Réinitialiser le mot de passe"
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Resolved"
|
||||
msgstr "Résolue"
|
||||
msgstr "Résolu"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Redémarrages"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Reprendre"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Racine"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "Faire tourner le token"
|
||||
@@ -943,6 +1148,18 @@ msgstr "Faire tourner le token"
|
||||
msgid "Rows per page"
|
||||
msgstr "Lignes par page"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Métriques d'exécution"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "Détails S.M.A.R.T."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "Auto-test S.M.A.R.T."
|
||||
|
||||
#: 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."
|
||||
@@ -972,6 +1189,14 @@ msgstr "Voir les <0>paramètres de notification</0> pour configurer comment vous
|
||||
msgid "Sent"
|
||||
msgstr "Envoyé"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Numéro de série"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Détails du service"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Définir des seuils de pourcentage pour les couleurs des compteurs."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "Trier par"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "État"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Statut"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Sous-état"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Espace Swap utilisé par le système"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "Système"
|
||||
msgid "System load averages over time"
|
||||
msgstr "Charges moyennes du système dans le temps"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Services systemd"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "Systèmes"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "Les systèmes peuvent être gérés dans un fichier <0>config.yml</0> à
|
||||
msgid "Table"
|
||||
msgstr "Tableau"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Tâches"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Temp."
|
||||
@@ -1054,7 +1295,7 @@ msgstr "Température"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Temperature unit"
|
||||
msgstr ""
|
||||
msgstr "Unité de température"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Temperatures of system sensors"
|
||||
@@ -1124,6 +1365,11 @@ msgstr "Les tokens permettent aux agents de se connecter et de s'enregistrer. Le
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "Les tokens et les empreintes sont utilisés pour authentifier les connexions WebSocket vers le hub."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "Données totales reçues pour chaque interface"
|
||||
@@ -1132,9 +1378,22 @@ msgstr "Données totales reçues pour chaque interface"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Données totales envoyées pour chaque interface"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Total : {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Déclenché par"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Déclencheurs"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr ""
|
||||
msgstr "Se déclenche lorsque la charge moyenne sur 1 minute dépasse un seuil"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 15 minute load average exceeds a threshold"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "Déclenchement lorsque le montant/descendant combinée dépasse un seuil
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque l'utilisation du CPU dépasse un seuil"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque l'utilisation du GPU dépasse un seuil"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque l'utilisation de la mémoire dépasse un seuil"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "Se déclenche lorsque le statut passe de \"Joignable\" à \"Injoignable\
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque l'utilisation de tout disque dépasse un seuil"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "Fichier unité"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "Token universel"
|
||||
msgid "Unknown"
|
||||
msgstr "Inconnue"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "Illimité"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "Joignable ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Mis à jour"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "Mis à jour toutes les 10 minutes."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Téléverser"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "Temps de fonctionnement"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Utilisation"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "Valeur"
|
||||
msgid "View"
|
||||
msgstr "Vue"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "Voir plus"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "En attente de suffisamment d'enregistrements à afficher"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Vous voulez nous aider à améliorer nos traductions ? Consultez <0>Crowdin</0> pour plus de détails."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Souhaite"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Avertissement (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "Configuration YAML"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Configuration YAML"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Oui"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Vos paramètres utilisateur ont été mis à jour."
|
||||
|
||||
1588
internal/site/src/locales/he/he.po
Normal file
1588
internal/site/src/locales/he/he.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: hr\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-10-18 23:59\n"
|
||||
"PO-Revision-Date: 2025-10-28 23:00\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,27 +18,24 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dan} other {# dani}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# sat} other {# sati}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# minuta} few {# minuta} many {# minuta} other {# minute}}"
|
||||
|
||||
#. 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} od {1} redaka izabrano."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} dan} other {{countString} dani}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} sat} other {{countString} sati}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} minuta} few {{countString} minuta} many {{countString} minuta} other {{countString} minute}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 sat"
|
||||
@@ -93,6 +90,10 @@ msgstr "Aktivan"
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktivna upozorenja"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "Aktivno stanje"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Dodaj <0>Sistem</0>"
|
||||
@@ -118,6 +119,10 @@ msgstr "Podesite opcije prikaza za grafikone."
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "Nakon"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
@@ -203,6 +208,18 @@ msgstr "Propusnost"
|
||||
msgid "Battery"
|
||||
msgstr "Baterija"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Postalo aktivno"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Postalo neaktivno"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Prije"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel podržava OpenID Connect i mnoge druge OAuth2 davatalje autentifikacije."
|
||||
@@ -220,6 +237,10 @@ msgstr "Binarni"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bitovi (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "Stanje pokretanja"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
@@ -229,11 +250,31 @@ msgstr "Bajtovi (KB/s, MB/s, GB/s)"
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Predmemorija / Međuspremnici"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Može se ponovno učitati"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Može se pokrenuti"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Može se zaustaviti"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Otkaži"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Kapacitet"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Oprez - mogući gubitak podataka"
|
||||
@@ -279,6 +320,10 @@ msgstr "Provjerite Vaš servis notifikacija"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Kliknite na spremnik za prikaz više informacija."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Kliknite na uređaj da biste vidjeli više informacija."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "Odaberite sustav za prikaz više informacija."
|
||||
@@ -301,6 +346,10 @@ msgstr "Konfigurirajte način primanja obavijesti upozorenja."
|
||||
msgid "Confirm password"
|
||||
msgstr "Potvrdite lozinku"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "Sukobi"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "Veza je pala"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "Kopiraj YAML"
|
||||
|
||||
#: 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 "Procesor"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "CPU jezgre"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "CPU vrhunac"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "CPU vrijeme"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Raspodjela CPU vremena"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "Iskorištenost procesora"
|
||||
@@ -397,6 +464,11 @@ msgstr "Kumulativno otpremanje"
|
||||
msgid "Current state"
|
||||
msgstr "Trenutno stanje"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Ciklusi"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Nadzorna ploča"
|
||||
@@ -414,10 +486,18 @@ msgstr "Izbriši"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "Izbriši otisak"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Opis"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Detalj"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Uređaj"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "Docker Mrežni I/O"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentacija"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "Unesite Vašu jednokratnu lozinku."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Greška"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "Greška"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Premašuje {0}{1} u posljednjih {2, plural, one {# minuta} other {# minute}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "Glavni PID izvršavanja"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Postojeći sistemi koji nisu definirani u <0>config.yml</0> će biti izbrisani. Molimo Vas napravite redovite sigurnosne kopije."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Izašlo aktivno"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "Izvezi"
|
||||
@@ -548,6 +638,10 @@ msgstr "Izvoz trenutne sistemske konfiguracije."
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Farenhajt (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Neuspjeli atributi:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Provjera autentičnosti nije uspjela"
|
||||
@@ -565,9 +659,16 @@ msgstr "Neuspješno slanje testne notifikacije"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Ažuriranje upozorenja nije uspjelo"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filtriraj..."
|
||||
@@ -576,6 +677,10 @@ msgstr "Filtriraj..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "Otisak prsta"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Za <0>{min}</0> {min, plural, one {minutu} other {minute}}"
|
||||
@@ -609,6 +714,10 @@ msgstr "GPU motori"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Energetska potrošnja grafičkog procesora"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "Iskorištenost GPU-a"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Mreža"
|
||||
@@ -658,6 +767,15 @@ msgstr "Jezik"
|
||||
msgid "Layout"
|
||||
msgstr "Izgled"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "Životni ciklus"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "ograničenje"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Prosječno Opterećenje"
|
||||
@@ -679,6 +797,14 @@ msgstr "Prosječno Opterećenje 5m"
|
||||
msgid "Load Avg"
|
||||
msgstr "Prosječno opterećenje"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "Stanje učitavanja"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Učitavanje..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Odjava"
|
||||
@@ -702,6 +828,10 @@ msgstr "Logovi"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Tražite gdje stvoriti upozorenja? Kliknite ikonu zvona <0/> u tablici sustava."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "Glavni PID"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Upravljajte postavkama prikaza i obavijesti."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "Maksimalno 1 minuta"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "Memorija"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Ograničenje memorije"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "Vrhunac memorije"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "Upotreba memorije"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Upotreba memorije Docker spremnika"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Ime"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "Mrežni promet javnih sučelja"
|
||||
msgid "Network unit"
|
||||
msgstr "Mjerna jedinica za mrežu"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "Ne"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "Nema rezultata."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "Nema rezultata."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "Nema dostupnih S.M.A.R.T. atributa za ovaj uređaj."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "Otvori menu"
|
||||
msgid "Or continue with"
|
||||
msgstr "Ili nastavi sa"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Ostalo"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Prebrišite postojeća upozorenja"
|
||||
@@ -847,6 +1013,15 @@ msgstr "Pauzirano"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "Pauzirano ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Prosječna iskorištenost po jezgri"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Postotak vremena provedenog u svakom stanju"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Molimo <0>konfigurirajte SMTP server</0> kako biste osigurali isporuku upozorenja."
|
||||
@@ -884,6 +1059,11 @@ msgstr "Molimo prijavite se u svoj račun"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#. 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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "Precizno iskorištenje u zabilježenom vremenu"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Preferirani jezik"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Proces pokrenut"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "Primljeno"
|
||||
msgid "Refresh"
|
||||
msgstr "Osvježi"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Odnosi"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Zatraži jednokratnu lozinku"
|
||||
@@ -921,6 +1109,14 @@ msgstr "Zatraži jednokratnu lozinku"
|
||||
msgid "Request OTP"
|
||||
msgstr "Zatraži OTP"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Zahtijeva"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Zahtijeva"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Resetiraj Lozinku"
|
||||
@@ -931,10 +1127,19 @@ msgstr "Resetiraj Lozinku"
|
||||
msgid "Resolved"
|
||||
msgstr "Razrješeno"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Ponovna pokretanja"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Nastavi"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "Promijeni token"
|
||||
@@ -943,6 +1148,18 @@ msgstr "Promijeni token"
|
||||
msgid "Rows per page"
|
||||
msgstr "Redovi po stranici"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Metrike izvršavanja"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "S.M.A.R.T. Detalji"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. Samotestiranje"
|
||||
|
||||
#: 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."
|
||||
@@ -972,6 +1189,14 @@ msgstr "Pogledajte <0>postavke obavijesti</0> da biste konfigurirali način prim
|
||||
msgid "Sent"
|
||||
msgstr "Poslano"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Serijski broj"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Detalji usluge"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Postavite pragove postotka za boje mjerača."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "Sortiraj po"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "Stanje"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Podstanje"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap prostor uzet od strane sistema"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "Sistem"
|
||||
msgid "System load averages over time"
|
||||
msgstr "Prosječno opterećenje sustava kroz vrijeme"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "Sistemi"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "Sistemima se može upravljati u <0>config.yml</0> datoteci unutar data d
|
||||
msgid "Table"
|
||||
msgstr "Tablica"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Zadaci"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Temp"
|
||||
@@ -1124,6 +1365,11 @@ msgstr "Tokeni dopuštaju agentima prijavu i registraciju. Otisci su stabilni id
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "Tokeni se uz otiske koriste za autentifikaciju WebSocket veza prema središnjoj kontroli."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Ukupno"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "Ukupni podaci primljeni za svako sučelje"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "Ukupni podaci primljeni za svako sučelje"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Ukupni podaci poslani za svako sučelje"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Ukupno: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Pokrenuto od"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Okidači"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "Pokreće se kada prosječna opterećenost sustava unutar 1 minute prijeđe prag"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "Pokreće se kada kombinacija gore/dolje premaši prag"
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Pokreće se kada iskorištenost procesora premaši prag"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "Pokreće se kada iskorištenost GPU-a premaši prag"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Pokreće se kada iskorištenost memorije premaši prag"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "Pokreće se kada se status sistema promijeni"
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Pokreće se kada iskorištenost bilo kojeg diska premaši prag"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Vrsta"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "Datoteka jedinice"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "Sveopći token"
|
||||
msgid "Unknown"
|
||||
msgstr "Nepoznata"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "Neograničeno"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "Sustav je podignut ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Ažurirano"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "Ažurirano svakih 10 minuta."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Otpremi"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "Vrijeme rada"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Iskorištenost"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "Vrijednost"
|
||||
msgid "View"
|
||||
msgstr "Prikaz"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "Prikaži više"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "Čeka se na više podataka prije prikaza"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Želite li nam pomoći da naše prijevode učinimo još boljim? Posjetite <0>Crowdin</0> za više detalja."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Želi"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Upozorenje (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "YAML konfiguracija"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML Konfiguracija"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Da"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Vaše korisničke postavke su ažurirane."
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: hu\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-10-14 23:40\n"
|
||||
"PO-Revision-Date: 2025-10-28 22:59\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Hungarian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -18,27 +18,24 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# nap} other {# nap}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# óra} other {# óra}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# perc} few {# perc} many {# perc} other {# perc}}"
|
||||
|
||||
#. 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} a(z) {1} sorból kiválasztva."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} nap} other {{countString} nap}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} óra} other {{countString} óra}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} perc} few {{countString} perc} many {{countString} perc} other {{countString} perc}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 óra"
|
||||
@@ -93,6 +90,10 @@ msgstr "Aktív"
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktív riasztások"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "Aktív állapot"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Hozzáadás <0>System</0>"
|
||||
@@ -118,6 +119,10 @@ msgstr "Állítsa be a diagram megjelenítését."
|
||||
msgid "Admin"
|
||||
msgstr "Adminisztráció"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "Utána"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Ügynök"
|
||||
@@ -187,7 +192,7 @@ msgstr "{0} átlagos kihasználtsága"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Average utilization of GPU engines"
|
||||
msgstr "GPU motorok átlagos kihasználtsága"
|
||||
msgstr "GPU-k átlagos kihasználtsága"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/navbar.tsx
|
||||
@@ -203,6 +208,18 @@ msgstr "Sávszélesség"
|
||||
msgid "Battery"
|
||||
msgstr "Akkumulátor"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Aktívvá vált"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Inaktívvá vált"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Előtte"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "A Beszel támogatja az OpenID Connect-et és számos OAuth2 hitelesítési szolgáltatót."
|
||||
@@ -220,6 +237,10 @@ msgstr "Bináris"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bitek (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "Indítási állapot"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
@@ -229,11 +250,31 @@ msgstr "Byte-ok (KB/s, MB/s, GB/s)"
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Gyorsítótár / Pufferelések"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Újratölthető"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Indítható"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Leállítható"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Mégsem"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "Képességek"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Kapacitás"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Figyelem - potenciális adatvesztés"
|
||||
@@ -279,6 +320,10 @@ msgstr "Ellenőrizd az értesítési szolgáltatásodat"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Kattintson egy konténerre a további információk megtekintéséhez."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Kattintson egy eszközre további információk megtekintéséhez."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "További információkért kattints egy rendszerre."
|
||||
@@ -301,6 +346,10 @@ msgstr "Konfiguráld, hogyan kapod az értesítéseket."
|
||||
msgid "Confirm password"
|
||||
msgstr "Jelszó megerősítése"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "Konfliktusok"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "Kapcsolat megszakadt"
|
||||
@@ -350,23 +399,41 @@ msgstr "Szöveg másolása"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
|
||||
msgstr ""
|
||||
msgstr "Másold az alábbi ügynök telepítési parancsát, vagy regisztráld az ügynököket automatikusan egy <0>univerzális tokennel</0>."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
|
||||
msgstr ""
|
||||
msgstr "Másold az alábbi ügynök <0>docker-compose.yml</0> tartalmát, vagy regisztráld az ügynököket automatikusan egy <1>univerzális tokennel</1>."
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Copy YAML"
|
||||
msgstr "YAML másolása"
|
||||
|
||||
#: 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"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "CPU magok"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "CPU csúcs"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "CPU idő"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU idő felbontása"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU használat"
|
||||
@@ -397,6 +464,11 @@ msgstr "Kumulatív feltöltés"
|
||||
msgid "Current state"
|
||||
msgstr "Jelenlegi állapot"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Ciklusok"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Áttekintés"
|
||||
@@ -414,10 +486,18 @@ msgstr "Törlés"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "Ujjlenyomat törlése"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Leírás"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Részlet"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Eszköz"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "Docker hálózat I/O"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentáció"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "Adja meg az egyszeri jelszavát."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Hiba"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "Hiba"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Túllépi a {0}{1} értéket az elmúlt {2, plural, one {# percben} other {# percben}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "A <0>config.yml</0> fájlban nem definiált meglévő rendszerek törlésre kerülnek. Kérjük, készítsen rendszeres biztonsági mentéseket."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Aktívként kilépett"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "Exportálás"
|
||||
@@ -548,6 +638,10 @@ msgstr "Exportálja a jelenlegi rendszerkonfigurációt."
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Sikertelen attribútumok:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Hitelesítés sikertelen"
|
||||
@@ -565,9 +659,16 @@ msgstr "Teszt értesítés elküldése sikertelen"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Nem sikerült frissíteni a riasztást"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Szűrő..."
|
||||
@@ -576,6 +677,10 @@ msgstr "Szűrő..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "Ujjlenyomat"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "A <0>{min}</0> {min, plural, one {perc} other {percek}}"
|
||||
@@ -603,12 +708,16 @@ msgstr "Általános"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU Engines"
|
||||
msgstr "GPU motorok"
|
||||
msgstr "GPU-k"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU áramfelvétele"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU használat"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Rács"
|
||||
@@ -658,6 +767,15 @@ msgstr "Nyelv"
|
||||
msgid "Layout"
|
||||
msgstr "Elrendezés"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "Életciklus"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "korlát"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Terhelési átlag"
|
||||
@@ -679,6 +797,14 @@ msgstr "Terhelési átlag 5p"
|
||||
msgid "Load Avg"
|
||||
msgstr "Terhelési átlag"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "Betöltési állapot"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Betöltés..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Kijelentkezés"
|
||||
@@ -702,6 +828,10 @@ msgstr "Naplók"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Inkább azt keresi, hogy hol hozhat létre riasztásokat? Kattintson a csengő <0/> ikonokra a rendszerek táblázatában."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "A megjelenítési és értesítési beállítások kezelése."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "Maximum 1 perc"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "RAM"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Memória korlát"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "Memória csúcs"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "Memóriahasználat"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Docker konténerek memória használata"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modell"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Név"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "Nyilvános interfészek hálózati forgalma"
|
||||
msgid "Network unit"
|
||||
msgstr "Sávszélesség mértékegysége"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "Nem"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "Nincs találat."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "Nincs találat."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "Ehhez az eszközhöz nem állnak rendelkezésre S.M.A.R.T. attribútumok."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "Menü megnyitása"
|
||||
msgid "Or continue with"
|
||||
msgstr "Vagy folytasd ezzel"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Egyéb"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Felülírja a meglévő riasztásokat"
|
||||
@@ -847,6 +1013,15 @@ msgstr "Szüneteltetve"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "Szüneteltetve ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Átlagos kihasználtság magonként"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Az idő százalékos aránya minden állapotban"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Kérjük, <0>konfigurálj egy SMTP szervert</0> az értesítések kézbesítésének biztosítása érdekében."
|
||||
@@ -884,6 +1059,11 @@ msgstr "Kérjük, jelentkezzen be a fiókjába"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#. 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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "Pontos kihasználás a rögzített időpontban"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Preferált nyelv"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Folyamat elindítva"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "Fogadott"
|
||||
msgid "Refresh"
|
||||
msgstr "Frissítés"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Kapcsolatok"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Egyszeri jelszó kérése"
|
||||
@@ -921,6 +1109,14 @@ msgstr "Egyszeri jelszó kérése"
|
||||
msgid "Request OTP"
|
||||
msgstr "OTP kérése"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Szükséges"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Igényel"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Jelszó visszaállítása"
|
||||
@@ -931,10 +1127,19 @@ msgstr "Jelszó visszaállítása"
|
||||
msgid "Resolved"
|
||||
msgstr "Megoldva"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Újraindítások"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Folytatás"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Gyökér"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "Tokenváltás"
|
||||
@@ -943,6 +1148,18 @@ msgstr "Tokenváltás"
|
||||
msgid "Rows per page"
|
||||
msgstr "Sorok száma oldalanként"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Futásidejű metrikák"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "S.M.A.R.T. Részletek"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. Önteszt"
|
||||
|
||||
#: 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."
|
||||
@@ -972,6 +1189,14 @@ msgstr "Lásd <0>az értesítési beállításokat</0>, hogy konfigurálja, hogy
|
||||
msgid "Sent"
|
||||
msgstr "Elküldve"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Sorozatszám"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Szolgáltatás részletei"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Százalékos küszöbértékek beállítása a mérőszínekhez."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "Rendezés"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "Állapot"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Állapot"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Részállapot"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Rendszer által használt swap terület"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "Rendszer"
|
||||
msgid "System load averages over time"
|
||||
msgstr "Rendszer terhelési átlaga"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Systemd szolgáltatások"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "Rendszer"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "A rendszereket egy <0>config.yml</0> fájlban lehet kezelni az adatköny
|
||||
msgid "Table"
|
||||
msgstr "Tábla"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Feladatok"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Hőmérséklet"
|
||||
@@ -1118,11 +1359,16 @@ msgstr "Tokenek & Ujjlenyomatok"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
|
||||
msgstr ""
|
||||
msgstr "A tokenek lehetővé teszik az ügynökök csatlakozását és regisztrációját. A fingeravtrykkok stabil azonosítók, amelyek minden rendszerre egyediek, és az első kapcsolódáskor kerülnek beállításra."
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr ""
|
||||
msgstr "A tokeneket és fingeravtrykkokat a hubhoz való WebSocket kapcsolatok hitelesítésére használják."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Összesen"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "Összes fogadott adat minden interfészenként"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Összes elküldött adat minden interfészenként"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Összesen: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Kiváltva"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Kiváltók"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "Riaszt, ha az 1 perces terhelési átlag túllép egy küszöbértéket"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "Bekapcsol, ha bármelyik érzékelő túllép egy küszöbértéket"
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Bekapcsol, ha a CPU érzékelő túllép egy küszöbértéket"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "Riaszt, ha a GPU használat túllép egy küszöbértéket"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Bekapcsol, ha a Ram érzékelő túllép egy küszöbértéket"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "Bekapcsol, amikor az állapot fel és le között változik"
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Bekapcsol, ha a lemez érzékelő túllép egy küszöbértéket"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Típus"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "Egység fájl"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "Univerzális token"
|
||||
msgid "Unknown"
|
||||
msgstr "Ismeretlen"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "Korlátlan"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "Online ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Frissítve"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "10 percenként frissítve."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Feltöltés"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "Üzemidő"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Használat"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "Érték"
|
||||
msgid "View"
|
||||
msgstr "Nézet"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "Továbbiak megjelenítése"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "Elegendő rekordra várva a megjelenítéshez"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Szeretne segíteni nekünk abban, hogy fordításaink még jobbak legyenek? További részletekért nézze meg a <0>Crowdin</0> honlapot."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Igényel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Figyelmeztetés (%)"
|
||||
@@ -1268,7 +1555,7 @@ msgstr "Webhook / Push értesítések"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
|
||||
msgstr ""
|
||||
msgstr "Ha engedélyezve van, ez a token lehetővé teszi az ügynökök önregisztrációját előzetes rendszerlétrehozás nélkül. Egy óra után vagy a hub újraindításakor lejár."
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
@@ -1290,6 +1577,12 @@ msgstr "YAML konfiguráció"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML konfiguráció"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Igen"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "A felhasználói beállítások frissítésre kerültek."
|
||||
|
||||
1353
internal/site/src/locales/id/id.po
Normal file
1353
internal/site/src/locales/id/id.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,15 +8,15 @@ msgstr ""
|
||||
"Language: is\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-08-28 23:21\n"
|
||||
"PO-Revision-Date: 2025-09-22 23:10\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Icelandic\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: is\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
@@ -116,7 +116,7 @@ msgstr ""
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
@@ -213,7 +213,7 @@ msgstr "Beszel notar <0>Shoutrrr</0> til að tengjast vinsælum tilkynningaþjó
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Binary"
|
||||
msgstr "Binary"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
@@ -234,6 +234,10 @@ msgstr "Skyndiminni / Biðminni"
|
||||
msgid "Cancel"
|
||||
msgstr "Hætta við"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Aðvörun - möguleiki á gagnatapi"
|
||||
@@ -279,6 +283,10 @@ msgstr "Athugaðu tilkynningaþjónustuna þína"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Smelltu á gám til að sjá frekari upplýsingar."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr ""
|
||||
@@ -397,6 +405,11 @@ msgstr ""
|
||||
msgid "Current state"
|
||||
msgstr "Núverandi ástand"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Yfirlitssíða"
|
||||
@@ -418,6 +431,10 @@ msgstr ""
|
||||
msgid "Detail"
|
||||
msgstr "Nánar"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr ""
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -548,6 +565,10 @@ msgstr ""
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Villa í auðkenningu"
|
||||
@@ -568,6 +589,7 @@ msgstr "Mistókst að uppfæra tilkynningu"
|
||||
#: 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/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Sía..."
|
||||
@@ -576,6 +598,10 @@ msgstr "Sía..."
|
||||
msgid "Fingerprint"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr ""
|
||||
@@ -593,7 +619,7 @@ msgstr ""
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Full"
|
||||
msgstr "Full"
|
||||
msgstr ""
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx
|
||||
@@ -625,7 +651,7 @@ msgstr "Homebrew skipun"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
msgstr ""
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
@@ -730,6 +756,10 @@ msgstr "Minnisnotkun"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Minnisnotkun docker kerfa"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
@@ -739,7 +769,7 @@ msgstr "Nafn"
|
||||
#: 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
|
||||
msgid "Network traffic of docker containers"
|
||||
@@ -748,7 +778,6 @@ msgstr "Net traffík docker kerfa"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr ""
|
||||
|
||||
@@ -761,11 +790,18 @@ msgstr ""
|
||||
msgid "No results found."
|
||||
msgstr "Engar niðurstöður fundust."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No results."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -882,7 +918,7 @@ msgstr "Vinsamlegast skráðu þig inn á aðganginn þinn"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
@@ -908,11 +944,6 @@ msgstr "Lesa"
|
||||
msgid "Received"
|
||||
msgstr "Móttekið"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Refresh"
|
||||
msgstr "Endurhlaða"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr ""
|
||||
@@ -943,6 +974,14 @@ msgstr ""
|
||||
msgid "Rows per page"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr ""
|
||||
@@ -970,7 +1009,7 @@ msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Sent"
|
||||
msgstr "Sent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
@@ -1005,6 +1044,7 @@ msgid "State"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
@@ -1043,6 +1083,7 @@ msgid "Table"
|
||||
msgstr "Tafla"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr ""
|
||||
@@ -1168,6 +1209,10 @@ msgstr "Virkjast þegar staða breytist milli virkur og óvirkur"
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Virkjast þegar diska notkun fer yfir þröskuld"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1193,10 +1238,6 @@ msgstr ""
|
||||
msgid "Up ({upSystemsLength})"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Uppfært"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr ""
|
||||
@@ -1293,3 +1334,4 @@ msgstr ""
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Notenda stillingar vistaðar."
|
||||
|
||||
|
||||
@@ -8,30 +8,15 @@ msgstr ""
|
||||
"Language: it\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-08-28 23:21\n"
|
||||
"PO-Revision-Date: 2025-10-30 21:53\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Italian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: it\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# giorno} other {# giorni}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# ora} other {# ore}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# minuto} other {# minuti}}"
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
@@ -39,6 +24,18 @@ msgstr "{0, plural, one {# minuto} other {# minuti}}"
|
||||
msgid "{0} of {1} row(s) selected."
|
||||
msgstr "{0} di {1} righe selezionate."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} giorno} other {{countString} giorni}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} ora} other {{countString} ore}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} minuto} other {{countString} minuti}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 ora"
|
||||
@@ -93,6 +90,10 @@ msgstr "Attivo"
|
||||
msgid "Active Alerts"
|
||||
msgstr "Avvisi Attivi"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "Stato attivo"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Aggiungi <0>Sistema</0>"
|
||||
@@ -118,6 +119,10 @@ msgstr "Regola le opzioni di visualizzazione per i grafici."
|
||||
msgid "Admin"
|
||||
msgstr "Amministratore"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "Dopo"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agente"
|
||||
@@ -203,6 +208,18 @@ msgstr "Larghezza di banda"
|
||||
msgid "Battery"
|
||||
msgstr "Batteria"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Diventato attivo"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Diventato inattivo"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Prima"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel supporta OpenID Connect e molti provider di autenticazione OAuth2."
|
||||
@@ -220,6 +237,10 @@ msgstr "Binario"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bit (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "Stato di avvio"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
@@ -229,11 +250,31 @@ msgstr "Byte (KB/s, MB/s, GB/s)"
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffer"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Può ricaricare"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Può avviare"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Può fermare"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Annulla"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "Funzionalità"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Capacità"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Attenzione - possibile perdita di dati"
|
||||
@@ -279,6 +320,10 @@ msgstr "Controlla il tuo servizio di notifica"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Fare clic su un contenitore per visualizzare ulteriori informazioni."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Fare clic su un dispositivo per visualizzare più informazioni."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "Clicca su un sistema per visualizzare più informazioni."
|
||||
@@ -301,6 +346,10 @@ msgstr "Configura come ricevere le notifiche di avviso."
|
||||
msgid "Confirm password"
|
||||
msgstr "Conferma password"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "Conflitti"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "La connessione è interrotta"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "Copia YAML"
|
||||
|
||||
#: 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"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "Core CPU"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "Picco CPU"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "Tempo CPU"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Suddivisione tempo CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "Utilizzo CPU"
|
||||
@@ -397,6 +464,11 @@ msgstr "Upload cumulativo"
|
||||
msgid "Current state"
|
||||
msgstr "Stato attuale"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Cicli"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Cruscotto"
|
||||
@@ -414,10 +486,18 @@ msgstr "Elimina"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "Elimina impronta digitale"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Descrizione"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Dettagli"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Dispositivo"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "I/O di Rete Docker"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Documentazione"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "Inserisci la tua password monouso."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Errore"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "Errore"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Supera {0}{1} negli ultimi {2, plural, one {# minuto} other {# minuti}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "PID principale exec"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "I sistemi esistenti non definiti in <0>config.yml</0> verranno eliminati. Si prega di effettuare backup regolari."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Uscito attivo"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "Esporta"
|
||||
@@ -548,6 +638,10 @@ msgstr "Esporta la configurazione attuale dei tuoi sistemi."
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Attributi falliti:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Autenticazione fallita"
|
||||
@@ -565,9 +659,16 @@ msgstr "Invio della notifica di test fallito"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Aggiornamento dell'avviso fallito"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filtra..."
|
||||
@@ -576,6 +677,10 @@ msgstr "Filtra..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "Impronta digitale"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Per <0>{min}</0> {min, plural, one {minuto} other {minuti}}"
|
||||
@@ -609,6 +714,10 @@ msgstr "Motori GPU"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Consumo della GPU"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "Utilizzo GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Griglia"
|
||||
@@ -658,6 +767,15 @@ msgstr "Lingua"
|
||||
msgid "Layout"
|
||||
msgstr "Aspetto"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "Ciclo di vita"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "limite"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Carico medio"
|
||||
@@ -679,6 +797,14 @@ msgstr "Caricamento medio 5m"
|
||||
msgid "Load Avg"
|
||||
msgstr "Carico Medio"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "Stato di caricamento"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Caricamento..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Disconnetti"
|
||||
@@ -702,6 +828,10 @@ msgstr "Log"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Cerchi invece dove creare avvisi? Clicca sulle icone della campana <0/> nella tabella dei sistemi."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "PID principale"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Gestisci le preferenze di visualizzazione e notifica."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "Memoria"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Limite memoria"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "Picco memoria"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "Utilizzo Memoria"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Utilizzo della memoria dei container Docker"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modello"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Nome"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "Traffico di rete delle interfacce pubbliche"
|
||||
msgid "Network unit"
|
||||
msgstr "Unità rete"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "No"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "Nessun risultato trovato."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "Nessun risultato."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "Nessun attributo S.M.A.R.T. disponibile per questo dispositivo."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "Apri menu"
|
||||
msgid "Or continue with"
|
||||
msgstr "Oppure continua con"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Altro"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Sovrascrivi avvisi esistenti"
|
||||
@@ -847,6 +1013,15 @@ msgstr "In pausa"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "In pausa ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Utilizzo medio per core"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Percentuale di tempo trascorso in ogni stato"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Si prega di <0>configurare un server SMTP</0> per garantire la consegna degli avvisi."
|
||||
@@ -884,6 +1059,11 @@ msgstr "Si prega di accedere al proprio account"
|
||||
msgid "Port"
|
||||
msgstr "Porta"
|
||||
|
||||
#. 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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "Utilizzo preciso al momento registrato"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Lingua Preferita"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Processo avviato"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "Ricevuto"
|
||||
msgid "Refresh"
|
||||
msgstr "Aggiorna"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Relazioni"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Richiedi una password monouso"
|
||||
@@ -921,6 +1109,14 @@ msgstr "Richiedi una password monouso"
|
||||
msgid "Request OTP"
|
||||
msgstr "Richiedi OTP"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Richiesto da"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Richiede"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Reimposta Password"
|
||||
@@ -931,10 +1127,19 @@ msgstr "Reimposta Password"
|
||||
msgid "Resolved"
|
||||
msgstr "Risolto"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Riavvii"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Riprendi"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Root"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "Ruota token"
|
||||
@@ -943,6 +1148,18 @@ msgstr "Ruota token"
|
||||
msgid "Rows per page"
|
||||
msgstr "Righe per pagina"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Metriche di runtime"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "Dettagli S.M.A.R.T."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "Autotest S.M.A.R.T."
|
||||
|
||||
#: 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."
|
||||
@@ -972,6 +1189,14 @@ msgstr "Vedi <0>impostazioni di notifica</0> per configurare come ricevere gli a
|
||||
msgid "Sent"
|
||||
msgstr "Inviato"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Numero di serie"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Dettagli servizio"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Imposta le soglie percentuali per i colori dei contatori."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "Ordina per"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "Stato"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Stato"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Sotto-stato"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Spazio di swap utilizzato dal sistema"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "Sistema"
|
||||
msgid "System load averages over time"
|
||||
msgstr "Medie di carico del sistema nel tempo"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Servizi Systemd"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "Sistemi"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "I sistemi possono essere gestiti in un file <0>config.yml</0> all'intern
|
||||
msgid "Table"
|
||||
msgstr "Tabella"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Attività"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Temperatura"
|
||||
@@ -1124,6 +1365,11 @@ msgstr "I token consentono agli agenti di connettersi e registrarsi. Le impronte
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "I token e le impronte digitali vengono utilizzati per autenticare le connessioni WebSocket all'hub."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Totale"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "Dati totali ricevuti per ogni interfaccia"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "Dati totali ricevuti per ogni interfaccia"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Dati totali inviati per ogni interfaccia"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Totale: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Attivato da"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Trigger"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "Si attiva quando la media di carico di 1 minuto supera una soglia"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "Attiva quando il combinato up/down supera una soglia"
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Attiva quando l'utilizzo della CPU supera una soglia"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "Si attiva quando l'utilizzo della GPU supera una soglia"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Attiva quando l'utilizzo della memoria supera una soglia"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "Attiva quando lo stato passa tra up e down"
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Attiva quando l'utilizzo di un disco supera una soglia"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Tipo"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "File unit"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "Token universale"
|
||||
msgid "Unknown"
|
||||
msgstr "Sconosciuta"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "Illimitato"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "Attivo ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Aggiornato"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "Aggiornato ogni 10 minuti."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Carica"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "Tempo di attività"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Utilizzo"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "Valore"
|
||||
msgid "View"
|
||||
msgstr "Vista"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "Visualizza altro"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "In attesa di abbastanza record da visualizzare"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Vuoi aiutarci a migliorare ulteriormente le nostre traduzioni? Dai un'occhiata a <0>Crowdin</0> per maggiori dettagli."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Desidera"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Avviso (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "Configurazione YAML"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Configurazione YAML"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Sì"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Le impostazioni utente sono state aggiornate."
|
||||
|
||||
@@ -8,30 +8,15 @@ msgstr ""
|
||||
"Language: ja\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-08-28 23:21\n"
|
||||
"PO-Revision-Date: 2025-10-28 23:00\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Japanese\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: ja\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# 日} other {# 日}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# 時間} other {# 時間}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# 分} few {# 分} many {# 分} other {# 分}}"
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
@@ -39,6 +24,18 @@ msgstr "{0, plural, one {# 分} few {# 分} many {# 分} other {# 分}}"
|
||||
msgid "{0} of {1} row(s) selected."
|
||||
msgstr "{1}行のうち{0}行が選択されました。"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} 日} other {{countString} 日}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} 時間} other {{countString} 時間}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} 分} few {{countString} 分} many {{countString} 分} other {{countString} 分}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1時間"
|
||||
@@ -93,6 +90,10 @@ msgstr "アクティブ"
|
||||
msgid "Active Alerts"
|
||||
msgstr "アクティブなアラート"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "アクティブ状態"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>システム</0>を追加"
|
||||
@@ -118,6 +119,10 @@ msgstr "チャートの表示オプションを調整します。"
|
||||
msgid "Admin"
|
||||
msgstr "管理者"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "後"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "エージェント"
|
||||
@@ -203,6 +208,18 @@ msgstr "帯域幅"
|
||||
msgid "Battery"
|
||||
msgstr "バッテリー"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "アクティブになった"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "非アクティブになった"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "前"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "BeszelはOpenID Connectと多くのOAuth2認証プロバイダーをサポートしています。"
|
||||
@@ -220,6 +237,10 @@ msgstr "バイナリ"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "ビット (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "ブート状態"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
@@ -229,11 +250,31 @@ msgstr "バイト (KB/s, MB/s, GB/s)"
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "キャッシュ / バッファ"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "リロード可能"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "開始可能"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "停止可能"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "キャンセル"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "機能"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "容量"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "注意 - データ損失の可能性"
|
||||
@@ -279,6 +320,10 @@ msgstr "通知サービスを確認してください"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "詳細情報を表示するにはコンテナをクリックしてください。"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "詳細情報を表示するにはデバイスをクリックしてください。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "システムをクリックして詳細を表示します。"
|
||||
@@ -301,6 +346,10 @@ msgstr "アラート通知の受信方法を設定します。"
|
||||
msgid "Confirm password"
|
||||
msgstr "パスワードを確認"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "競合"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "接続が切断されました"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "YAMLをコピー"
|
||||
|
||||
#: 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"
|
||||
msgstr "CPU コア"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "CPUピーク"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "CPU時間"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU 時間の内訳"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU使用率"
|
||||
@@ -397,6 +464,11 @@ msgstr "累積アップロード"
|
||||
msgid "Current state"
|
||||
msgstr "現在の状態"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "サイクル"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "ダッシュボード"
|
||||
@@ -414,10 +486,18 @@ msgstr "削除"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "フィンガープリントを削除"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "説明"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "詳細"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "デバイス"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "DockerネットワークI/O"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "ドキュメント"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "ワンタイムパスワードを入力してください。"
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "エラー"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "エラー"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "過去{2, plural, one {# 分} other {# 分}}で{0}{1}を超えています"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "実行メイン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."
|
||||
msgstr "<0>config.yml</0>に定義されていない既存のシステムは削除されます。定期的にバックアップを作成してください。"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "アクティブ状態で終了"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "エクスポート"
|
||||
@@ -548,6 +638,10 @@ msgstr "現在のシステム設定をエクスポートします。"
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "華氏 (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "失敗した属性:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "認証に失敗しました"
|
||||
@@ -565,9 +659,16 @@ msgstr "テスト通知の送信に失敗しました"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "アラートの更新に失敗しました"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "フィルター..."
|
||||
@@ -576,6 +677,10 @@ msgstr "フィルター..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "フィンガープリント"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "ファームウェア"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "<0>{min}</0> {min, plural, one {分} other {分}}の間"
|
||||
@@ -609,6 +714,10 @@ msgstr "GPUエンジン"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPUの消費電力"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU使用率"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "グリッド"
|
||||
@@ -658,6 +767,15 @@ msgstr "言語"
|
||||
msgid "Layout"
|
||||
msgstr "レイアウト"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "ライフサイクル"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "制限"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "負荷平均"
|
||||
@@ -679,6 +797,14 @@ msgstr "負荷平均 (5分)"
|
||||
msgid "Load Avg"
|
||||
msgstr "負荷平均"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "ロード状態"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "読み込み中..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "ログアウト"
|
||||
@@ -702,6 +828,10 @@ msgstr "ログ"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "アラートを作成する場所を探していますか?システムテーブルのベル<0/>アイコンをクリックしてください。"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "メインPID"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "表示と通知の設定を管理します。"
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "最大1分"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "メモリ"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "メモリ制限"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "メモリピーク"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "メモリ使用率"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Dockerコンテナのメモリ使用率"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "モデル"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "名前"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "パブリックインターフェースのネットワークトラフィ
|
||||
msgid "Network unit"
|
||||
msgstr "ネットワーク単位"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "いいえ"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "結果が見つかりませんでした。"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "結果がありません。"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "このデバイスのS.M.A.R.T.属性は利用できません。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "メニューを開く"
|
||||
msgid "Or continue with"
|
||||
msgstr "または、以下の方法でログイン"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "その他"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "既存のアラートを上書き"
|
||||
@@ -847,6 +1013,15 @@ msgstr "一時停止中"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "一時停止 ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "コアごとの平均使用率"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "各状態で費やした時間の割合"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "アラートが配信されるように<0>SMTPサーバーを設定</0>してください。"
|
||||
@@ -884,6 +1059,11 @@ msgstr "アカウントにサインインしてください"
|
||||
msgid "Port"
|
||||
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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "記録された時点での正確な利用"
|
||||
msgid "Preferred Language"
|
||||
msgstr "優先言語"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "プロセス開始"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "受信"
|
||||
msgid "Refresh"
|
||||
msgstr "更新"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "関係"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "ワンタイムパスワードをリクエスト"
|
||||
@@ -921,6 +1109,14 @@ msgstr "ワンタイムパスワードをリクエスト"
|
||||
msgid "Request OTP"
|
||||
msgstr "OTP をリクエスト"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "必要とされる"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "必要とする"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "パスワードをリセット"
|
||||
@@ -931,10 +1127,19 @@ msgstr "パスワードをリセット"
|
||||
msgid "Resolved"
|
||||
msgstr "解決済み"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "再起動"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "再開"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "トークンをローテート"
|
||||
@@ -943,6 +1148,18 @@ msgstr "トークンをローテート"
|
||||
msgid "Rows per page"
|
||||
msgstr "ページあたりの行数"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "ランタイムメトリクス"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "S.M.A.R.T.詳細"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T.セルフテスト"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Enterキーまたはカンマを使用してアドレスを保存します。空白のままにするとメール通知が無効になります。"
|
||||
@@ -972,6 +1189,14 @@ msgstr "アラートの受信方法を設定するには<0>通知設定</0>を
|
||||
msgid "Sent"
|
||||
msgstr "送信"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "シリアル番号"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "サービス詳細"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "メーターの色を変更するしきい値(パーセンテージ)を設定します。"
|
||||
@@ -1001,15 +1226,22 @@ msgstr "並び替え基準"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "状態"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "ステータス"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "サブ状態"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "システムが使用するスワップ領域"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "システム"
|
||||
msgid "System load averages over time"
|
||||
msgstr "システムの負荷平均の推移"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Systemdサービス"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "システム"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "システムはデータディレクトリ内の<0>config.yml</0>ファ
|
||||
msgid "Table"
|
||||
msgstr "テーブル"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "タスク"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "温度"
|
||||
@@ -1124,6 +1365,11 @@ msgstr "トークンはエージェントの接続と登録を可能にします
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "トークンとフィンガープリントは、ハブへのWebSocket接続の認証に使用されます。"
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "総数"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "各インターフェースの総受信データ量"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "各インターフェースの総受信データ量"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "各インターフェースの総送信データ量"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "合計: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "トリガー元"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "トリガー"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "1分間の負荷平均がしきい値を超えたときにトリガーされます"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "上り/下りの合計がしきい値を超えたときにトリガー
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "CPU使用率がしきい値を超えたときにトリガーされます"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "GPU使用率がしきい値を超えたときにトリガーされます"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "メモリ使用率がしきい値を超えたときにトリガーされます"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "ステータスが上から下に切り替わるときにトリガーさ
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "ディスクの使用量がしきい値を超えたときにトリガーされます"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "タイプ"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "ユニットファイル"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "ユニバーサルトークン"
|
||||
msgid "Unknown"
|
||||
msgstr "不明"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "無制限"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "正常 ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "更新済み"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "10分ごとに更新されます。"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "アップロード"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "稼働時間"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "使用量"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "値"
|
||||
msgid "View"
|
||||
msgstr "表示"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "もっと見る"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "表示するのに十分なレコードを待っています"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "翻訳をさらに良くするためにご協力をお願いします。詳細については<0>Crowdin</0>をご覧ください。"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "要求"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "警告 (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "YAML設定"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML設定"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "はい"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "ユーザー設定が更新されました。"
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: ko\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-09-23 02:45\n"
|
||||
"PO-Revision-Date: 2025-10-28 23:00\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Korean\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
@@ -18,27 +18,24 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# 일} other {# 일}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# 시간} other {# 시간}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# 분} few {# 분} many {# 분} other {# 분}}"
|
||||
|
||||
#. 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 "{1}개의 행 중 {0}개가 선택되었습니다."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} 일} other {{countString} 일}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} 시간} other {{countString} 시간}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} 분} few {{countString} 분} many {{countString} 분} other {{countString} 분}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1시간"
|
||||
@@ -93,6 +90,10 @@ msgstr "활성"
|
||||
msgid "Active Alerts"
|
||||
msgstr "활성화된 알림들"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "활성 상태"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>시스템</0> 추가"
|
||||
@@ -118,6 +119,10 @@ msgstr "차트 표시 옵션 변경."
|
||||
msgid "Admin"
|
||||
msgstr "관리자"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "이후"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "에이전트"
|
||||
@@ -203,6 +208,18 @@ msgstr "대역폭"
|
||||
msgid "Battery"
|
||||
msgstr "배터리"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "활성화됨"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "비활성화됨"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "이전"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel은 OpenID Connect 및 많은 OAuth2 인증 제공자를 지원합니다."
|
||||
@@ -220,6 +237,10 @@ msgstr "실행 파일"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "비트 (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "부팅 상태"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
@@ -229,11 +250,31 @@ msgstr "바이트 (KB/s, MB/s, GB/s)"
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "캐시 / 버퍼"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "재로드 가능"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "시작 가능"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "중지 가능"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "취소"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "권한"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "용량"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "주의 - 데이터 손실 가능성"
|
||||
@@ -279,6 +320,10 @@ msgstr "알림 서비스를 확인하세요."
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "더 많은 정보를 보려면 컨테이너를 클릭하세요."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "더 많은 정보를 보려면 장치를 클릭하세요."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "더 많은 정보를 보려면 시스템을 클릭하세요."
|
||||
@@ -301,6 +346,10 @@ msgstr "알림을 수신할 방법을 설정하세요."
|
||||
msgid "Confirm password"
|
||||
msgstr "비밀번호 확인"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "충돌"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "연결이 끊겼습니다"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "YAML 복사"
|
||||
|
||||
#: 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"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "CPU 코어"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "CPU 최대값"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "CPU 시간"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU 시간 분배"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU 사용량"
|
||||
@@ -397,6 +464,11 @@ msgstr "누적 업로드"
|
||||
msgid "Current state"
|
||||
msgstr "현재 상태"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "사이클"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "대시보드"
|
||||
@@ -414,10 +486,18 @@ msgstr "삭제"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "지문 삭제"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "설명"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "세부사항"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "장치"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "Docker 네트워크 I/O"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "문서"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "OTP를 입력하세요."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "오류"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "오류"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "마지막 {2, plural, one {# 분} other {# 분}} 동안 {0}{1} 초과"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "<0>config.yml</0>에 정의되지 않은 기존 시스템은 삭제됩니다. 정기적으로 백업을 하세요."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "활성 종료됨"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "내보내기"
|
||||
@@ -548,6 +638,10 @@ msgstr "현재 시스템 구성 내보내기"
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "화씨 (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "실패한 속성:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "인증 실패"
|
||||
@@ -565,9 +659,16 @@ msgstr "테스트 알림 전송 실패"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "알림 수정 실패"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "필터..."
|
||||
@@ -576,6 +677,10 @@ msgstr "필터..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "지문"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "펌웨어"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "<0>{min}</0> {min, plural, one {분} other {분}} 동안"
|
||||
@@ -609,6 +714,10 @@ msgstr "GPU 엔진들"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU 전원 사용량"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU 사용량"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "그리드"
|
||||
@@ -658,6 +767,15 @@ msgstr "언어"
|
||||
msgid "Layout"
|
||||
msgstr "레이아웃"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "생명주기"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "부하 평균"
|
||||
@@ -679,6 +797,14 @@ msgstr "부하 평균 5분"
|
||||
msgid "Load Avg"
|
||||
msgstr "부하 평균"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "로드 상태"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "로딩 중..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "로그아웃"
|
||||
@@ -702,6 +828,10 @@ msgstr "로그"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "알림을 생성하려 하시나요? 시스템 테이블의 종 <0/> 아이콘을 클릭하세요."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "디스플레이 및 알림 설정"
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "1분간 최댓값"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "메모리"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "메모리 제한"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "메모리 최대값"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "메모리 사용량"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Docker 컨테이너의 메모리 사용량"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "모델"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "이름"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "공용 인터페이스의 네트워크 트래픽"
|
||||
msgid "Network unit"
|
||||
msgstr "네트워크 단위"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "아니오"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "결과가 없습니다."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "결과 없음."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "이 장치에 사용할 수 있는 S.M.A.R.T. 속성이 없습니다."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "메뉴 열기"
|
||||
msgid "Or continue with"
|
||||
msgstr "또는 아래 항목으로 진행하기"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "기타"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "기존 알림 덮어쓰기"
|
||||
@@ -847,6 +1013,15 @@ msgstr "일시 정지됨"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "일시 정지됨 ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "코어별 평균 사용률"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "각 상태에서 보낸 시간의 백분율"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "알림이 전달되도록 <0>SMTP 서버를 구성</0>하세요."
|
||||
@@ -884,6 +1059,11 @@ msgstr "계정에 로그인하세요."
|
||||
msgid "Port"
|
||||
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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "기록된 시간의 정확한 사용량"
|
||||
msgid "Preferred Language"
|
||||
msgstr "선호 언어"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "프로세스 시작됨"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "수신됨"
|
||||
msgid "Refresh"
|
||||
msgstr "새로고침"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "관계"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "OTP 요청"
|
||||
@@ -921,6 +1109,14 @@ msgstr "OTP 요청"
|
||||
msgid "Request OTP"
|
||||
msgstr "OTP 요청"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "필요한 대상"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "필요 항목"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "비밀번호 재설정"
|
||||
@@ -931,10 +1127,19 @@ msgstr "비밀번호 재설정"
|
||||
msgid "Resolved"
|
||||
msgstr "해결됨"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "재시작 횟수"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "재개"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "토큰 회전"
|
||||
@@ -943,6 +1148,18 @@ msgstr "토큰 회전"
|
||||
msgid "Rows per page"
|
||||
msgstr "페이지당 행 수"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "런타임 메트릭"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "S.M.A.R.T. 세부 정보"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. 자체 테스트"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Enter 키 또는 쉼표를 사용하여 주소를 저장하세요. 이메일 알림을 비활성화하려면 비워 두세요."
|
||||
@@ -972,6 +1189,14 @@ msgstr "알림을 받는 방법을 구성하려면 <0>알림 설정</0>을 참
|
||||
msgid "Sent"
|
||||
msgstr "보냄"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "시리얼 번호"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "서비스 세부 정보"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "그래프 미터 색상의 백분율 임계값을 설정합니다."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "정렬 기준"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "상태"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "상태"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "하위 상태"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "시스템에서 사용된 스왑 공간"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "시스템"
|
||||
msgid "System load averages over time"
|
||||
msgstr "시간에 따른 시스템 부하 평균"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "시스템"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "시스템은 데이터 디렉토리 내의 <0>config.yml</0> 파일에
|
||||
msgid "Table"
|
||||
msgstr "표"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "작업"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "온도"
|
||||
@@ -1124,6 +1365,11 @@ msgstr "토큰은 에이전트가 연결하고 등록할 수 있도록 합니다
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "토큰과 지문은 허브에 대한 WebSocket 연결을 인증하는 데 사용됩니다."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "총"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "각 인터페이스별 총합 다운로드 데이터량"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "각 인터페이스별 총합 다운로드 데이터량"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "각 인터페이스별 총합 업로드 데이터량"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "총: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "트리거 대상"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "트리거"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "1분 부하 평균이 임계값을 초과하면 트리거됩니다."
|
||||
@@ -1156,6 +1415,10 @@ msgstr "업로드와 다운로드 대역폭의 합이 임계값을 초과할 때
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "CPU 사용량이 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "GPU 사용량이 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "메모리 사용량이 임계값을 초과할 때 트리거됩니다."
|
||||
@@ -1168,6 +1431,14 @@ msgstr "시스템의 전원이 켜지거나 꺼질때 트리거됩니다."
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "디스크 사용량이 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "유형"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr ""
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "범용 토큰"
|
||||
msgid "Unknown"
|
||||
msgstr "알 수 없음"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "무제한"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "온라인 ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "업데이트됨"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "10분마다 업데이트됩니다."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "업로드"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "가동 시간"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "사용량"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "값"
|
||||
msgid "View"
|
||||
msgstr "보기"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "더 보기"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "표시할 충분한 기록을 기다리는 중"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "번역을 개선하는데 도움을 주시겠습니까? 자세한 내용은 <0>Crowdin</0>을 확인해 주세요."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "요구 항목"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "경고 (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "YAML 구성"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML 구성"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "예"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "사용자 설정이 업데이트되었습니다."
|
||||
|
||||
@@ -8,30 +8,15 @@ msgstr ""
|
||||
"Language: nl\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-08-28 23:21\n"
|
||||
"PO-Revision-Date: 2025-10-28 22:59\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Dutch\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: nl\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dag} other {# dagen}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# uur} other {# uren}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# minuut} other {# minuten}}"
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
@@ -39,6 +24,18 @@ msgstr "{0, plural, one {# minuut} other {# minuten}}"
|
||||
msgid "{0} of {1} row(s) selected."
|
||||
msgstr "{0} van de {1} rij(en) geselecteerd."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} dag} other {{countString} dagen}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} uur} other {{countString} uren}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} minuut} other {{countString} minuten}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 uur"
|
||||
@@ -93,6 +90,10 @@ msgstr "Actief"
|
||||
msgid "Active Alerts"
|
||||
msgstr "Actieve waarschuwingen"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "Actieve status"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Voeg <0>Systeem</0> toe"
|
||||
@@ -116,11 +117,15 @@ msgstr "Weergaveopties voor grafieken aanpassen."
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "Na"
|
||||
|
||||
#: 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
|
||||
@@ -203,6 +208,18 @@ msgstr "Bandbreedte"
|
||||
msgid "Battery"
|
||||
msgstr "Batterij"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Actief geworden"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Inactief geworden"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Voor"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel ondersteunt OpenID Connect en vele OAuth2 authenticatieaanbieders."
|
||||
@@ -218,29 +235,53 @@ 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"
|
||||
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
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffers"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Kan herladen"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Kan starten"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Kan stoppen"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Annuleren"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "Mogelijkheden"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Capaciteit"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
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."
|
||||
@@ -279,6 +320,10 @@ msgstr "Controleer je meldingsservice"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Klik op een container om meer informatie te zien."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Klik op een apparaat om meer informatie te bekijken."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "Klik op een systeem om meer informatie te bekijken."
|
||||
@@ -301,6 +346,10 @@ msgstr "Configureer hoe je waarschuwingsmeldingen ontvangt."
|
||||
msgid "Confirm password"
|
||||
msgstr "Bevestig wachtwoord"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "Conflicten"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "Verbinding is niet actief"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "YAML kopiëren"
|
||||
|
||||
#: 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"
|
||||
msgstr "CPU-kernen"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "CPU-piek"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "CPU-tijd"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU-tijdverdeling"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "Processorgebruik"
|
||||
@@ -397,9 +464,14 @@ msgstr "Cumulatieve upload"
|
||||
msgid "Current state"
|
||||
msgstr "Huidige status"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Cycli"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Dashboard"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Default time period"
|
||||
@@ -414,10 +486,18 @@ msgstr "Verwijderen"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "Vingerafdruk verwijderen"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Beschrijving"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Detail"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Apparaat"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "Docker netwerk I/O"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Documentatie"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "Voer uw eenmalig wachtwoord in."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Fout"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "Fout"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Overschrijdt {0}{1} in de laatste {2, plural, one {# minuut} other {# minuten}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "Uitvoer hoofd-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."
|
||||
msgstr "Bestaande systemen die niet gedefinieerd zijn in <0>config.yml</0> zullen worden verwijderd. Maak regelmatige backups."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Beëindigd actief"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "Exporteren"
|
||||
@@ -546,7 +636,11 @@ msgstr "Exporteer je huidige systeemconfiguratie."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Mislukte kenmerken:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
@@ -565,17 +659,28 @@ msgstr "Versturen test notificatie mislukt"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Bijwerken waarschuwing mislukt"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
msgstr "Filteren..."
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Fingerprint"
|
||||
msgstr "Vingerafdruk"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Voor <0>{min}</0> {min, plural, one {minuut} other {minuten}}"
|
||||
@@ -609,6 +714,10 @@ msgstr "GPU-engines"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU stroomverbruik"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU-gebruik"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Raster"
|
||||
@@ -639,7 +748,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 "Image"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Invalid email address."
|
||||
@@ -648,7 +757,7 @@ msgstr "Ongeldig e-mailadres."
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Language"
|
||||
@@ -658,6 +767,15 @@ msgstr "Taal"
|
||||
msgid "Layout"
|
||||
msgstr "Indeling"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Gemiddelde Belasting"
|
||||
@@ -679,6 +797,14 @@ msgstr "Gemiddelde Belasting 5m"
|
||||
msgid "Load Avg"
|
||||
msgstr "Gem. Belasting"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "Laadstatus"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Laden..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Afmelden"
|
||||
@@ -696,12 +822,16 @@ msgstr "Aanmelding mislukt"
|
||||
#: 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."
|
||||
msgstr "Zoek je waar je meldingen kunt aanmaken? Klik op de bel <0/> in de systeemtabel."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "Hoofd-PID"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Weergave- en notificatievoorkeuren beheren."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "Geheugen"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Geheugenlimiet"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "Geheugenpiek"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,16 +871,22 @@ msgstr "Geheugengebruik"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Geheugengebruik van docker containers"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Naam"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Net"
|
||||
msgstr "Net"
|
||||
msgstr "Netwerk"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Network traffic of docker containers"
|
||||
@@ -757,15 +904,30 @@ msgstr "Netwerkverkeer van publieke interfaces"
|
||||
msgid "Network unit"
|
||||
msgstr "Netwerk eenheid"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "Nee"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "Geen resultaten gevonden."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "Geen resultaten."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "Geen S.M.A.R.T. kenmerken beschikbaar voor dit apparaat."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -793,12 +955,16 @@ msgstr "Eenmalig wachtwoord"
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Open menu"
|
||||
msgstr "Open menu"
|
||||
msgstr "Menu openen"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Or continue with"
|
||||
msgstr "Of ga verder met"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Overig"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Overschrijf bestaande waarschuwingen"
|
||||
@@ -847,6 +1013,15 @@ msgstr "Gepauzeerd"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "Gepauzeerd ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Gemiddeld gebruik per kern"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Percentage tijd besteed in elke status"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "<0>Configureer een SMTP-server </0> om ervoor te zorgen dat waarschuwingen worden afgeleverd."
|
||||
@@ -884,6 +1059,11 @@ msgstr "Meld je aan bij je account"
|
||||
msgid "Port"
|
||||
msgstr "Poort"
|
||||
|
||||
#. 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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "Nauwkeurig gebruik op de opgenomen tijd"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Voorkeurstaal"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Proces gestart"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "Ontvangen"
|
||||
msgid "Refresh"
|
||||
msgstr "Vernieuwen"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Relaties"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Eenmalig wachtwoord aanvragen"
|
||||
@@ -921,6 +1109,14 @@ msgstr "Eenmalig wachtwoord aanvragen"
|
||||
msgid "Request OTP"
|
||||
msgstr "OTP aanvragen"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Vereist door"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Vereist"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Wachtwoord resetten"
|
||||
@@ -931,10 +1127,19 @@ msgstr "Wachtwoord resetten"
|
||||
msgid "Resolved"
|
||||
msgstr "Opgelost"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Herstarten"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Hervatten"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "Roteer Token"
|
||||
@@ -943,6 +1148,18 @@ msgstr "Roteer Token"
|
||||
msgid "Rows per page"
|
||||
msgstr "Rijen per pagina"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Runtime-metrieken"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "S.M.A.R.T.-details"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. Zelf-test"
|
||||
|
||||
#: 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."
|
||||
@@ -972,6 +1189,14 @@ msgstr "Zie <0>notificatie-instellingen</0> om te configureren hoe je meldingen
|
||||
msgid "Sent"
|
||||
msgstr "Verzonden"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Serienummer"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Servicedetails"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Stel percentagedrempels in voor meterkleuren."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "Sorteren op"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Substatus"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap ruimte gebruikt door het systeem"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "Systeem"
|
||||
msgid "System load averages over time"
|
||||
msgstr "Gemiddelde systeembelasting na verloop van tijd"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Systemd-services"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "Systemen"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "Systemen kunnen worden beheerd in een <0>config.yml</0> bestand in je da
|
||||
msgid "Table"
|
||||
msgstr "Tabel"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Taken"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Temperatuur"
|
||||
@@ -1124,6 +1365,11 @@ msgstr "Tokens staan agenten toe om verbinding te maken met en te registreren. V
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "Tokens en vingerafdrukken worden gebruikt om WebSocket verbindingen te verifiëren naar de hub."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Totaal"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "Totaal ontvangen gegevens per interface"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "Totaal ontvangen gegevens per interface"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Totaal verzonden gegevens per interface"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Totaal: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Geactiveerd door"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Triggers"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "Triggert wanneer de gemiddelde belasting een drempelwaarde overschrijdt"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "Triggert wanneer de gecombineerde up/down een drempelwaarde overschrijdt
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Triggert wanneer het CPU-gebruik een drempelwaarde overschrijdt"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "Triggert wanneer het GPU-gebruik een drempelwaarde overschrijdt"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Triggert wanneer het geheugengebruik een drempelwaarde overschrijdt"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "Triggert wanneer de status schakelt tussen up en down"
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Triggert wanneer het gebruik van een schijf een drempelwaarde overschrijdt"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "Unit-bestand"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "Universele token"
|
||||
msgid "Unknown"
|
||||
msgstr "Onbekend"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "Onbeperkt"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "Online ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Bijgewerkt"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "Elke 10 minuten bijgewerkt."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Uploaden"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "Actief"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Gebruik"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "Waarde"
|
||||
msgid "View"
|
||||
msgstr "Weergave"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "Meer weergeven"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "Wachtend op genoeg records om weer te geven"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Wil je ons helpen onze vertalingen nog beter te maken? Bekijk <0>Crowdin</0> voor meer informatie."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Wil"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Waarschuwing (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "YAML Configuratie"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML Configuratie"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Ja"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Je gebruikersinstellingen zijn bijgewerkt."
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: no\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-10-13 17:31\n"
|
||||
"PO-Revision-Date: 2025-10-28 23:00\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Norwegian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -18,27 +18,24 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dag} other {# dager}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# time} other {# timer}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# minutt} other {# minutter}}"
|
||||
|
||||
#. 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} av {1} rad(er) valgt."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} dag} other {{countString} dager}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} time} other {{countString} timer}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} minutt} other {{countString} minutter}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 time"
|
||||
@@ -93,6 +90,10 @@ msgstr "Aktiv"
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktive Alarmer"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "Aktiv tilstand"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Legg til <0>System</0>"
|
||||
@@ -118,6 +119,10 @@ msgstr "Juster visningsalternativer for diagrammer."
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "Etter"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
@@ -203,6 +208,18 @@ msgstr "Båndbredde"
|
||||
msgid "Battery"
|
||||
msgstr "Batteri"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Ble aktiv"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Ble inaktiv"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Før"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel støtter OpenID Connect og mange OAuth2 autentiserings-tilbydere."
|
||||
@@ -220,6 +237,10 @@ msgstr "Binær"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "Oppstartstilstand"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
@@ -229,11 +250,31 @@ msgstr "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffere"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Kan laste inn på nytt"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Kan starte"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Kan stoppe"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Avbryt"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "Kapabiliteter"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Kapasitet"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Advarsel - potensielt tap av data"
|
||||
@@ -279,6 +320,10 @@ msgstr "Sjekk din meldingstjeneste"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Klikk på en container for å se mer informasjon."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Klikk på en enhet for å se mer informasjon."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "Klikk på et system for å se mer informasjon."
|
||||
@@ -301,6 +346,10 @@ msgstr "Konfigurer hvordan du vil motta alarmvarsler."
|
||||
msgid "Confirm password"
|
||||
msgstr "Bekreft passord"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "Konflikter"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "Tilkoblingen er nede"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "Kopier YAML"
|
||||
|
||||
#: 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"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "CPU-kjerner"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "CPU-topp"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "CPU-tid"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "CPU-tidsoppdeling"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU-bruk"
|
||||
@@ -397,6 +464,11 @@ msgstr "Kumulativ opplasting"
|
||||
msgid "Current state"
|
||||
msgstr "Nåværende tilstand"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Sykluser"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Dashbord"
|
||||
@@ -414,9 +486,17 @@ msgstr "Slett"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "Slett fingeravtrykk"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Beskrivelse"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Detalj"
|
||||
msgstr "Detaljer"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Enhet"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "Docker Nettverks-I/O"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentasjon"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "Skriv inn ditt engangspassord."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Feil"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "Feil"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Overstiger {0}{1} {2, plural, one {det siste minuttet} other {de siste # minuttene}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "Hovedprosess-ID"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Eksisterende systemer som ikke er er definert i <0>config.yml</0> vil bli slettet. Vennligst ta jevnlige sikkerhetskopier."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Avsluttet aktiv"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "Eksporter"
|
||||
@@ -548,6 +638,10 @@ msgstr "Eksporter din nåværende systemkonfigurasjon"
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Mislykkede attributter:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Autentisering mislyktes"
|
||||
@@ -565,9 +659,16 @@ msgstr "Kunne ikke sende test-varsling"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Kunne ikke oppdatere alarm"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
@@ -576,6 +677,10 @@ msgstr "Filter..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "Fingeravtrykk"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Fastvare"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "I <0>{min}</0> {min, plural, one {minutt} other {minutter}}"
|
||||
@@ -609,6 +714,10 @@ msgstr "GPU-motorer"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "GPU Effektforbruk"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "GPU-bruk"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Rutenett"
|
||||
@@ -658,6 +767,15 @@ msgstr "Språk"
|
||||
msgid "Layout"
|
||||
msgstr "Oppsett"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "Livssyklus"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "grense"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Snittbelastning Last"
|
||||
@@ -679,6 +797,14 @@ msgstr "Snittbelastning 5m"
|
||||
msgid "Load Avg"
|
||||
msgstr "Snittbelastning"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "Lastetilstand"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Laster..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Logg Ut"
|
||||
@@ -702,6 +828,10 @@ msgstr "Logger"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Ser du etter hvor du kan opprette alarmer? Klikk på bjelle-ikonene <0/> i systemtabellen."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "Hovedprosess-ID"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Endre visnings- og varslingsinnstillinger."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "Maks 1 min"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "Minne"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Minnegrense"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "Minne-topp"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "Minnebruk"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Minnebruk av docker-konteinere"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modell"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Navn"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "Nettverkstrafikk av eksterne nettverksgrensesnitt"
|
||||
msgid "Network unit"
|
||||
msgstr "Nettverksenhet"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "Nei"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "Ingen resultater funnet."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "Ingen resultater."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "Ingen S.M.A.R.T.-attributter tilgjengelig for denne enheten."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "Åpne meny"
|
||||
msgid "Or continue with"
|
||||
msgstr "Eller fortsett med"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Andre"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Overskriv eksisterende alarmer"
|
||||
@@ -847,6 +1013,15 @@ msgstr "Satt på Pause"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "Pauset ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Gjennomsnittlig utnyttelse per kjerne"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Prosentandel av tid brukt i hver tilstand"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Vennligst <0>konfigurer en SMTP-server</0> for å forsikre deg om at varsler blir levert."
|
||||
@@ -884,6 +1059,11 @@ msgstr "Vennligst logg inn på kontoen din"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#. 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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "Nøyaktig utnyttelse på registrert tidspunkt"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Foretrukket Språk"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Prosess startet"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "Mottatt"
|
||||
msgid "Refresh"
|
||||
msgstr "Oppdater"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Relasjoner"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Be om engangspassord"
|
||||
@@ -921,6 +1109,14 @@ msgstr "Be om engangspassord"
|
||||
msgid "Request OTP"
|
||||
msgstr "Be om OTP"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Påkrevd av"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Påkrevd"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Nullstill Passord"
|
||||
@@ -931,10 +1127,19 @@ msgstr "Nullstill Passord"
|
||||
msgid "Resolved"
|
||||
msgstr "Løst"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Omstarter"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Gjenoppta"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr "Rot"
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "Forny token"
|
||||
@@ -943,6 +1148,18 @@ msgstr "Forny token"
|
||||
msgid "Rows per page"
|
||||
msgstr "Rader per side"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Kjøretidsmålinger"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "S.M.A.R.T.-detaljer"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "S.M.A.R.T. selvtest"
|
||||
|
||||
#: 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."
|
||||
@@ -972,6 +1189,14 @@ msgstr "Se <0>varslingsinnstillingene</0> for å konfigurere hvordan du vil mott
|
||||
msgid "Sent"
|
||||
msgstr "Sendt"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Serienummer"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Tjenestedetaljer"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Angi prosentvise terskler for målerfarger."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "Sorter Etter"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "Tilstand"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Undertilstand"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap-plass i bruk av systemet"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "System"
|
||||
msgid "System load averages over time"
|
||||
msgstr "Systembelastning gjennomsnitt over tid"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Systemd-tjenester"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "Systemer"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "Systemer kan håndteres i en <0>config.yml</0>-fil i din data-katalog."
|
||||
msgid "Table"
|
||||
msgstr "Tabell"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Oppgaver"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Temp"
|
||||
@@ -1124,6 +1365,11 @@ msgstr "Tokens lar agenter koble til og registrere seg selv. Fingeravtrykk er st
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "Tokens og fingeravtrykk blir brukt for å autentisere WebSocket-tilkoblinger til huben."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "Totalt mottatt data for hvert grensesnitt"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "Totalt mottatt data for hvert grensesnitt"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Totalt sendt data for hvert grensesnitt"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Totalt: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Utløst av"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Utløsere"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "Slår inn når gjennomsnittsbelastningen over 1 minutt overstiger en grenseverdi"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "Slår inn når kombinert opp/ned overskrider en grenseverdi"
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Slår inn når CPU-bruken overstiger en grenseverdi"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "Slår inn når GPU-bruken overstiger en grenseverdi"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Slår inn når minnebruken overstiger en grenseverdi"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "Slår inn når statusen veksler mellom oppe og nede"
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Slår inn når forbruk av hvilken som helst disk overstiger en grenseverdi"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "Enhetsfil"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "Universal token"
|
||||
msgid "Unknown"
|
||||
msgstr "Ukjent"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "Ubegrenset"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "Oppe ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Oppdatert"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "Oppdatert hvert 10. minutt."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Last opp"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "Oppetid"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Forbruk"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "Verdi"
|
||||
msgid "View"
|
||||
msgstr "Visning"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "Se mer"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "Venter på nok registreringer til å vise"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Vil du hjelpe oss med å gjøre oversettelsene enda bedre? Ta en titt på <0>Crowdin</0> for mer informasjon."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Ønsker"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Advarsel (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "YAML Oppsett"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML Konfigurasjon"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Ja"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Dine brukerinnstillinger har blitt oppdatert."
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: pl\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-09-18 15:36\n"
|
||||
"PO-Revision-Date: 2025-10-28 23:00\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,27 +18,24 @@ msgstr ""
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dzień} few {# dni} many {# dni} other {# dni}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {godzinę} few {# godziny} many {# godzin} other {# godziny}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# minuta} few {# minuty} many {# minut} other {# minut}}"
|
||||
|
||||
#. 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} z {1} wybranych wierszy."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} dzień} few {{countString} dni} many {{countString} dni} other {{countString} dni}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {godzinę} few {{countString} godziny} many {{countString} godzin} other {{countString} godziny}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} minuta} few {{countString} minuty} many {{countString} minut} other {{countString} minut}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 godzina"
|
||||
@@ -93,6 +90,10 @@ msgstr "Aktywny"
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktywne alerty"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "Stan aktywny"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Dodaj <0>system</0>"
|
||||
@@ -118,6 +119,10 @@ msgstr "Dostosuj opcje wyświetlania wykresów."
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "Po"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
@@ -203,6 +208,18 @@ msgstr "Przepustowość"
|
||||
msgid "Battery"
|
||||
msgstr "Bateria"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Stało się aktywnym"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Stało się nieaktywnym"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Przed"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel obsługuje OpenID Connect i wielu dostawców uwierzytelniania OAuth2."
|
||||
@@ -220,6 +237,10 @@ msgstr "Plik binarny"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bity (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
msgstr "Stan rozruchu"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
@@ -229,11 +250,31 @@ msgstr "Bajty (KB/s, MB/s, GB/s)"
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Pamięć podręczna / Bufory"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Może przeładować"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Może uruchomić"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Może zatrzymać"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Anuluj"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "Możliwości"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Pojemność"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Uwaga- potencjalna utrata danych."
|
||||
@@ -279,6 +320,10 @@ msgstr "Sprawdź swój serwis powiadomień"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Kliknij na kontener, aby wyświetlić więcej informacji."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Kliknij na urządzenie, aby wyświetlić więcej informacji."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "Kliknij na system, aby zobaczyć więcej informacji."
|
||||
@@ -301,6 +346,10 @@ msgstr "Skonfiguruj sposób otrzymywania powiadomień."
|
||||
msgid "Confirm password"
|
||||
msgstr "Potwierdź hasło"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "Konflikty"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "Brak połączenia"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "Kopiuj YAML"
|
||||
|
||||
#: 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 "Procesor"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "Rdzenie CPU"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "Szczyt CPU"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "Czas CPU"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Time Breakdown"
|
||||
msgstr "Podział czasu CPU"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "Użycie procesora"
|
||||
@@ -397,6 +464,11 @@ msgstr "Wysyłanie skumulowane"
|
||||
msgid "Current state"
|
||||
msgstr "Aktualny stan"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Cykle"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Panel kontrolny"
|
||||
@@ -414,10 +486,18 @@ msgstr "Usuń"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "Usuń odcisk palca"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Opis"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Szczegół"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Urządzenie"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "Sieć Docker I/O"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentacja"
|
||||
|
||||
@@ -518,6 +599,7 @@ msgstr "Wprowadź swoje jednorazowe hasło."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Błąd"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "Błąd"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Przekracza {0}{1} w ciągu ostatnich {2, plural, one {# minuty} other {# minut}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "Główny PID wykonania"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Istniejące systemy, które nie są zdefiniowane w <0>config.yml</0>, zostaną usunięte. Proszę regularnie tworzyć kopie zapasowe."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Zakończono aktywnie"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "Eksport"
|
||||
@@ -548,6 +638,10 @@ msgstr "Eksportuj aktualną konfigurację systemów."
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Nieudane atrybuty:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Błąd autoryzacji"
|
||||
@@ -565,9 +659,16 @@ msgstr "Nie udało się wysłać testowego powiadomienia"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Nie udało się zaktualizować powiadomienia"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filtruj..."
|
||||
@@ -576,6 +677,10 @@ msgstr "Filtruj..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "Odcisk palca"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Oprogramowanie sprzętowe"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Na <0>{min}</0> {min, plural, one {minutę} other {minut}}"
|
||||
@@ -609,6 +714,10 @@ msgstr "Silniki GPU"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Moc GPU"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "Użycie GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Siatka"
|
||||
@@ -658,6 +767,15 @@ msgstr "Język"
|
||||
msgid "Layout"
|
||||
msgstr "Układ"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "Cykl życia"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Średnie obciążenie"
|
||||
@@ -679,6 +797,14 @@ msgstr "Średnie obciążenie 5 m"
|
||||
msgid "Load Avg"
|
||||
msgstr "Śr. obciążenie"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "Stan obciążenia"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Ładowanie..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Wyloguj"
|
||||
@@ -702,6 +828,10 @@ msgstr "Logi"
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Szukasz, gdzie utworzyć powiadomienia? Kliknij ikonę dzwonka <0/> w tabeli systemów."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "Główny PID"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Zarządzaj preferencjami wyświetlania i powiadomień."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "Maks. 1 min"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "Pamięć"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Limit pamięci"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "Szczyt pamięci"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "Wykorzystanie pamięci"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Użycie pamięci przez kontenery Docker."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Nazwa"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "Ruch sieciowy interfejsów publicznych"
|
||||
msgid "Network unit"
|
||||
msgstr "Jednostka sieciowa"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "Nie"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "Brak wyników."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "Brak wyników."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "Brak dostępnych atrybutów S.M.A.R.T. dla tego urządzenia."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "Otwórz menu"
|
||||
msgid "Or continue with"
|
||||
msgstr "Lub kontynuuj z"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Inne"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Nadpisz istniejące alerty"
|
||||
@@ -847,6 +1013,15 @@ msgstr "Wstrzymane"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "Wstrzymane ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Średnie wykorzystanie na rdzeń"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Procent czasu spędzonego w każdym stanie"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Proszę <0>skonfigurować serwer SMTP</0>, aby zapewnić dostarczanie powiadomień."
|
||||
@@ -884,6 +1059,11 @@ msgstr "Zaloguj się na swoje konto"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#. 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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "Dokładne wykorzystanie w zarejestrowanym czasie"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Preferowany język"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Proces uruchomiony"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "Otrzymane"
|
||||
msgid "Refresh"
|
||||
msgstr "Odśwież"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Relacje"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Zażądaj jednorazowego hasła"
|
||||
@@ -921,6 +1109,14 @@ msgstr "Zażądaj jednorazowego hasła"
|
||||
msgid "Request OTP"
|
||||
msgstr "Zażądaj OTP"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Wymagane przez"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Wymaga"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Resetuj hasło"
|
||||
@@ -931,10 +1127,19 @@ msgstr "Resetuj hasło"
|
||||
msgid "Resolved"
|
||||
msgstr "Rozwiązany"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Ponowne uruchomienia"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Wznów"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "Zmień token"
|
||||
@@ -943,6 +1148,18 @@ msgstr "Zmień token"
|
||||
msgid "Rows per page"
|
||||
msgstr "Wiersze na stronę"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Metryki czasu wykonania"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "Szczegóły S.M.A.R.T."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "Samodiagnostyka S.M.A.R.T."
|
||||
|
||||
#: 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."
|
||||
@@ -972,6 +1189,14 @@ msgstr "Zobacz <0>ustawienia powiadomień</0>, aby skonfigurować sposób, w jak
|
||||
msgid "Sent"
|
||||
msgstr "Wysłane"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Numer seryjny"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Szczegóły usługi"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Ustaw progi procentowe dla kolorów mierników."
|
||||
@@ -1001,15 +1226,22 @@ msgstr "Sortuj według"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "Stan"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Stan podrzędny"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Pamięć wymiany używana przez system"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "System"
|
||||
msgid "System load averages over time"
|
||||
msgstr "Średnie obciążenie systemu w czasie"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Usługi systemd"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "Systemy"
|
||||
@@ -1042,7 +1278,12 @@ msgstr "Systemy mogą być zarządzane w pliku <0>config.yml</0> znajdującym si
|
||||
msgid "Table"
|
||||
msgstr "Tabela"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Zadania"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Temp"
|
||||
msgstr "Temperatura"
|
||||
@@ -1124,6 +1365,11 @@ msgstr "Tokeny umożliwiają agentom łączenie się i rejestrację. Odciski pal
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "Tokeny i odciski palców (fingerprinty) służą do uwierzytelniania połączeń WebSocket z hubem."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Łącznie"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "Całkowita ilość danych odebranych dla każdego interfejsu"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "Całkowita ilość danych odebranych dla każdego interfejsu"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Całkowita ilość danych wysłanych dla każdego interfejsu"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Łącznie: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Wyzwalane przez"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Wyzwalacze"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "Uruchamia się, gdy 1-minutowe średnie obciążenie systemu przekroczy ustawiony próg"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "Wyzwalane, gdy łączna wartość w górę/w dół przekroczy próg"
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Wyzwalane, gdy użycie procesora przekracza próg"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "Wyzwalane, gdy użycie GPU przekroczy próg"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Wyzwalane, wykorzystanie pamięci przekroczy ustalony próg."
|
||||
@@ -1168,6 +1431,14 @@ msgstr "Wyzwalane, gdy status przełącza się między stanem aktywnym a nieakty
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Wyzwalane, gdy wykorzystanie któregokolwiek dysku przekroczy ustalony próg"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Typ"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "Plik jednostki"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,6 +1454,11 @@ msgstr "Uniwersalny token"
|
||||
msgid "Unknown"
|
||||
msgstr "Nieznana"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "Bez limitu"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
@@ -1194,9 +1470,14 @@ msgid "Up ({upSystemsLength})"
|
||||
msgstr "Działa ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Zaktualizowano"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "Aktualizowane co 10 minut."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Wysyłanie"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "Czas pracy"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Wykorzystanie"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "Wartość"
|
||||
msgid "View"
|
||||
msgstr "Widok"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "Zobacz więcej"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "Oczekiwanie na wystarczającą liczbę rekordów do wyświetlenia"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Chcesz pomóc nam uczynić nasze tłumaczenia jeszcze lepszymi? Sprawdź <0>Crowdin</0> po więcej szczegółów."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Wymaga"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Ostrzeżenie (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "Konf. YAML"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Konfiguracja YAML"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Tak"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Twoje ustawienia użytkownika zostały zaktualizowane."
|
||||
|
||||
@@ -8,30 +8,15 @@ msgstr ""
|
||||
"Language: pt\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-10-09 12:03\n"
|
||||
"PO-Revision-Date: 2025-11-04 22:13\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Portuguese\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: pt-PT\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info?.u / 86400)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dia} other {# dias}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 3600)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{0, plural, one {# hora} other {# horas}}"
|
||||
|
||||
#. placeholder {0}: Math.trunc(system.info.u / 60)
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{0, plural, one {# minute} few {# minutes} many {# minutes} other {# minutes}}"
|
||||
msgstr "{0, plural, one {# minuto} other {# minutos}}"
|
||||
"X-Crowdin-File: /main/internal/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 32\n"
|
||||
|
||||
#. placeholder {0}: table.getFilteredSelectedRowModel().rows.length
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
@@ -39,6 +24,18 @@ msgstr "{0, plural, one {# minuto} other {# minutos}}"
|
||||
msgid "{0} of {1} row(s) selected."
|
||||
msgstr "{0} de {1} linha(s) selecionada(s)."
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} day} other {{countString} days}}"
|
||||
msgstr "{count, plural, one {{countString} dia} other {{countString} dias}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} hour} other {{countString} hours}}"
|
||||
msgstr "{count, plural, one {{countString} hora} other {{countString} horas}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "{count, plural, one {{countString} minute} few {{countString} minutes} many {{countString} minutes} other {{countString} minutes}}"
|
||||
msgstr "{count, plural, one {{countString} minuto} other {{countString} minutos}}"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 hour"
|
||||
msgstr "1 hora"
|
||||
@@ -93,6 +90,10 @@ msgstr "Ativo"
|
||||
msgid "Active Alerts"
|
||||
msgstr "Alertas Ativos"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Active state"
|
||||
msgstr "Estado ativo"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Adicionar <0>Sistema</0>"
|
||||
@@ -118,6 +119,10 @@ msgstr "Ajustar opções de exibição para gráficos."
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "After"
|
||||
msgstr "Depois"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Agent"
|
||||
msgstr "Agente"
|
||||
@@ -137,7 +142,7 @@ msgstr "Alertas"
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/containers.tsx
|
||||
msgid "All Containers"
|
||||
msgstr "Todos os contentores"
|
||||
msgstr "Todos os Contêineres"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
#: src/components/command-palette.tsx
|
||||
@@ -203,6 +208,18 @@ msgstr "Largura de Banda"
|
||||
msgid "Battery"
|
||||
msgstr "Bateria"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became active"
|
||||
msgstr "Tornou-se ativo"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Became inactive"
|
||||
msgstr "Tornou-se inativo"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Before"
|
||||
msgstr "Antes"
|
||||
|
||||
#: src/components/login/auth-form.tsx
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel suporta OpenID Connect e muitos provedores de autenticação OAuth2."
|
||||
@@ -220,6 +237,10 @@ msgstr "Binário"
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Boot state"
|
||||
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)"
|
||||
@@ -227,13 +248,33 @@ msgstr "Bytes (KB/s, MB/s, GB/s)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffers"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can reload"
|
||||
msgstr "Pode recarregar"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can start"
|
||||
msgstr "Pode iniciar"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Can stop"
|
||||
msgstr "Pode parar"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Capabilities"
|
||||
msgstr "Capacidades"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Capacity"
|
||||
msgstr "Capacidade"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Cuidado - possível perda de dados"
|
||||
@@ -279,6 +320,10 @@ msgstr "Verifique seu serviço de notificação"
|
||||
msgid "Click on a container to view more information."
|
||||
msgstr "Clique num contentor para ver mais informações."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Click on a device to view more information."
|
||||
msgstr "Clique em um dispositivo para ver mais informações."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Click on a system to view more information."
|
||||
msgstr "Clique em um sistema para ver mais informações."
|
||||
@@ -301,6 +346,10 @@ msgstr "Configure como você recebe notificações de alerta."
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmar senha"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Conflicts"
|
||||
msgstr "Conflitos"
|
||||
|
||||
#: src/components/active-alerts.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr "A conexão está inativa"
|
||||
@@ -361,12 +410,30 @@ msgid "Copy YAML"
|
||||
msgstr "Copiar YAML"
|
||||
|
||||
#: 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"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "CPU Cores"
|
||||
msgstr "Núcleos de CPU"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "CPU Peak"
|
||||
msgstr "Pico de CPU"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "CPU time"
|
||||
msgstr "Tempo de CPU"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
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/cpu-sheet.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "CPU Usage"
|
||||
msgstr "Uso de CPU"
|
||||
@@ -397,6 +464,11 @@ msgstr "Upload cumulativo"
|
||||
msgid "Current state"
|
||||
msgstr "Estado atual"
|
||||
|
||||
#. Power Cycles
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Cycles"
|
||||
msgstr "Ciclos"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
msgid "Dashboard"
|
||||
msgstr "Painel"
|
||||
@@ -414,10 +486,18 @@ msgstr "Excluir"
|
||||
msgid "Delete fingerprint"
|
||||
msgstr "Excluir impressão digital"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Description"
|
||||
msgstr "Descrição"
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
msgid "Detail"
|
||||
msgstr "Detalhe"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Device"
|
||||
msgstr "Dispositivo"
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
msgid "Discharging"
|
||||
@@ -458,6 +538,7 @@ msgid "Docker Network I/O"
|
||||
msgstr "E/S de Rede do Docker"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Documentation"
|
||||
msgstr "Documentação"
|
||||
|
||||
@@ -467,7 +548,7 @@ msgstr "Documentação"
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Down"
|
||||
msgstr "“Desligado”"
|
||||
msgstr "Desligado"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Down ({downSystemsLength})"
|
||||
@@ -518,6 +599,7 @@ msgstr "Insira a sua senha de uso único."
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Error"
|
||||
msgstr "Erro"
|
||||
|
||||
@@ -528,10 +610,18 @@ msgstr "Erro"
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Excede {0}{1} no último {2, plural, one {# minuto} other {# minutos}}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exec main PID"
|
||||
msgstr "PID principal de execução"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Sistemas existentes não definidos em <0>config.yml</0> serão excluídos. Faça backups regulares."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Exited active"
|
||||
msgstr "Saiu ativo"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Export"
|
||||
msgstr "Exportar"
|
||||
@@ -548,6 +638,10 @@ msgstr "Exporte a configuração atual dos seus sistemas."
|
||||
msgid "Fahrenheit (°F)"
|
||||
msgstr "Fahrenheit (°F)"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Failed Attributes:"
|
||||
msgstr "Atributos com Falha:"
|
||||
|
||||
#: src/lib/api.ts
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Falha na autenticação"
|
||||
@@ -565,9 +659,16 @@ msgstr "Falha ao enviar notificação de teste"
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Falha ao atualizar alerta"
|
||||
|
||||
#. placeholder {0}: statusTotals[ServiceStatus.Failed]
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Failed: {0}"
|
||||
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/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Filter..."
|
||||
msgstr "Filtrar..."
|
||||
@@ -576,6 +677,10 @@ msgstr "Filtrar..."
|
||||
msgid "Fingerprint"
|
||||
msgstr "Impressão digital"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Firmware"
|
||||
msgstr "Firmware"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Por <0>{min}</0> {min, plural, one {minuto} other {minutos}}"
|
||||
@@ -609,6 +714,10 @@ msgstr "Motores GPU"
|
||||
msgid "GPU Power Draw"
|
||||
msgstr "Consumo de Energia da GPU"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "GPU Usage"
|
||||
msgstr "Uso de GPU"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Grid"
|
||||
msgstr "Grade"
|
||||
@@ -625,7 +734,7 @@ msgstr "Comando Homebrew"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
msgstr ""
|
||||
|
||||
#. Context: Battery state
|
||||
#: src/lib/i18n.ts
|
||||
@@ -648,7 +757,7 @@ msgstr "Endereço de email inválido."
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Language"
|
||||
@@ -658,6 +767,15 @@ msgstr "Idioma"
|
||||
msgid "Layout"
|
||||
msgstr "Aspeto"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Lifecycle"
|
||||
msgstr "Ciclo de vida"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "limit"
|
||||
msgstr "limite"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Load Average"
|
||||
msgstr "Carga Média"
|
||||
@@ -679,6 +797,14 @@ msgstr "Carga média 5m"
|
||||
msgid "Load Avg"
|
||||
msgstr "Carga Média"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Load state"
|
||||
msgstr "Estado de carga"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Loading..."
|
||||
msgstr "Carregando..."
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Log Out"
|
||||
msgstr "Sair"
|
||||
@@ -696,12 +822,16 @@ 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."
|
||||
msgstr "Procurando onde criar alertas? Clique nos ícones de sino <0/> na tabela de sistemas."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Main PID"
|
||||
msgstr "PID principal"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Gerenciar preferências de exibição e notificação."
|
||||
@@ -717,10 +847,21 @@ msgid "Max 1 min"
|
||||
msgstr "Máx 1 min"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Memory"
|
||||
msgstr "Memória"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory limit"
|
||||
msgstr "Limite de memória"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Memory Peak"
|
||||
msgstr "Pico de memória"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Memory Usage"
|
||||
@@ -730,9 +871,15 @@ msgstr "Uso de Memória"
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Uso de memória dos contêineres Docker"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Model"
|
||||
msgstr "Modelo"
|
||||
|
||||
#: src/components/add-system.tsx
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Name"
|
||||
msgstr "Nome"
|
||||
|
||||
@@ -757,15 +904,30 @@ msgstr "Tráfego de rede das interfaces públicas"
|
||||
msgid "Network unit"
|
||||
msgstr "Unidade de rede"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No"
|
||||
msgstr "Não"
|
||||
|
||||
#: src/components/command-palette.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results found."
|
||||
msgstr "Nenhum resultado encontrado."
|
||||
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/containers-table/containers-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "No results."
|
||||
msgstr "Sem resultados."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "No S.M.A.R.T. attributes available for this device."
|
||||
msgstr "Nenhum atributo S.M.A.R.T. disponível para este dispositivo."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "No systems found."
|
||||
@@ -799,6 +961,10 @@ msgstr "Abrir menu"
|
||||
msgid "Or continue with"
|
||||
msgstr "Ou continue com"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Other"
|
||||
msgstr "Outro"
|
||||
|
||||
#: src/components/alerts/alerts-sheet.tsx
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Sobrescrever alertas existentes"
|
||||
@@ -847,6 +1013,15 @@ msgstr "Pausado"
|
||||
msgid "Paused ({pausedSystemsLength})"
|
||||
msgstr "Pausado ({pausedSystemsLength})"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Per-core average utilization"
|
||||
msgstr "Utilização média por núcleo"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Percentage of time spent in each state"
|
||||
msgstr "Percentagem de tempo gasto em cada estado"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Por favor, <0>configure um servidor SMTP</0> para garantir que os alertas sejam entregues."
|
||||
@@ -884,6 +1059,11 @@ msgstr "Por favor, entre na sua conta"
|
||||
msgid "Port"
|
||||
msgstr "Porta"
|
||||
|
||||
#. 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
|
||||
msgid "Precise utilization at the recorded time"
|
||||
@@ -893,6 +1073,10 @@ msgstr "Utilização precisa no momento registrado"
|
||||
msgid "Preferred Language"
|
||||
msgstr "Idioma Preferido"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Process started"
|
||||
msgstr "Processo iniciado"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx
|
||||
msgid "Public Key"
|
||||
@@ -913,6 +1097,10 @@ msgstr "Recebido"
|
||||
msgid "Refresh"
|
||||
msgstr "Atualizar"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Relationships"
|
||||
msgstr "Relacionamentos"
|
||||
|
||||
#: src/components/login/login.tsx
|
||||
msgid "Request a one-time password"
|
||||
msgstr "Solicitar senha de uso único"
|
||||
@@ -921,6 +1109,14 @@ msgstr "Solicitar senha de uso único"
|
||||
msgid "Request OTP"
|
||||
msgstr "Solicitar OTP"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Required by"
|
||||
msgstr "Requerido por"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Requires"
|
||||
msgstr "Requer"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Redefinir Senha"
|
||||
@@ -931,10 +1127,19 @@ msgstr "Redefinir Senha"
|
||||
msgid "Resolved"
|
||||
msgstr "Resolvido"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Restarts"
|
||||
msgstr "Reinícios"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Resume"
|
||||
msgstr "Retomar"
|
||||
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgctxt "Root disk label"
|
||||
msgid "Root"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Rotate token"
|
||||
msgstr "Rotacionar token"
|
||||
@@ -943,6 +1148,18 @@ msgstr "Rotacionar token"
|
||||
msgid "Rows per page"
|
||||
msgstr "Linhas por página"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Runtime Metrics"
|
||||
msgstr "Métricas de tempo de execução"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Details"
|
||||
msgstr "Detalhes S.M.A.R.T."
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "S.M.A.R.T. Self-Test"
|
||||
msgstr "Auto-teste S.M.A.R.T."
|
||||
|
||||
#: 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."
|
||||
@@ -972,6 +1189,14 @@ msgstr "Veja <0>configurações de notificação</0> para configurar como você
|
||||
msgid "Sent"
|
||||
msgstr "Enviado"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Serial Number"
|
||||
msgstr "Número de Série"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Service Details"
|
||||
msgstr "Detalhes do serviço"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Set percentage thresholds for meter colors."
|
||||
msgstr "Defina os limiares de porcentagem para as cores do medidor."
|
||||
@@ -1001,14 +1226,21 @@ msgstr "Ordenar Por"
|
||||
|
||||
#. Context: alert state (active or resolved)
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "State"
|
||||
msgstr "Estado"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
msgstr "Estado"
|
||||
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Sub State"
|
||||
msgstr "Subestado"
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "Swap space used by the system"
|
||||
@@ -1030,6 +1262,10 @@ msgstr "Sistema"
|
||||
msgid "System load averages over time"
|
||||
msgstr "Médias de carga do sistema ao longo do tempo"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Systemd Services"
|
||||
msgstr "Serviços Systemd"
|
||||
|
||||
#: src/components/navbar.tsx
|
||||
msgid "Systems"
|
||||
msgstr "Sistemas"
|
||||
@@ -1042,10 +1278,15 @@ msgstr "Os sistemas podem ser gerenciados em um arquivo <0>config.yml</0> dentro
|
||||
msgid "Table"
|
||||
msgstr "Tabela"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Tasks"
|
||||
msgstr "Tarefas"
|
||||
|
||||
#. Temperature label in systems table
|
||||
#: 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/lib/alerts.ts
|
||||
@@ -1108,7 +1349,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
|
||||
@@ -1124,6 +1365,11 @@ msgstr "Os tokens permitem que os agentes se conectem e registrem. As impressõe
|
||||
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
|
||||
msgstr "Tokens e impressões digitais são usados para autenticar conexões WebSocket ao hub."
|
||||
|
||||
#: src/components/ui/chart.tsx
|
||||
#: src/components/ui/chart.tsx
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Total data received for each interface"
|
||||
msgstr "Dados totais recebidos para cada interface"
|
||||
@@ -1132,6 +1378,19 @@ msgstr "Dados totais recebidos para cada interface"
|
||||
msgid "Total data sent for each interface"
|
||||
msgstr "Dados totais enviados para cada interface"
|
||||
|
||||
#. placeholder {0}: data.length
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Total: {0}"
|
||||
msgstr "Total: {0}"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggered by"
|
||||
msgstr "Acionado por"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Triggers"
|
||||
msgstr "Acionadores"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when 1 minute load average exceeds a threshold"
|
||||
msgstr "Dispara quando a média de carga de 1 minuto excede um limite"
|
||||
@@ -1156,6 +1415,10 @@ msgstr "Dispara quando a soma de subida/descida excede um limite"
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Dispara quando o uso de CPU excede um limite"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when GPU usage exceeds a threshold"
|
||||
msgstr "Dispara quando o uso de GPU excede um limite"
|
||||
|
||||
#: src/lib/alerts.ts
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Dispara quando o uso de memória excede um limite"
|
||||
@@ -1168,6 +1431,14 @@ msgstr "Dispara quando o status alterna entre ativo e inativo"
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Dispara quando o uso de qualquer disco excede um limite"
|
||||
|
||||
#: src/components/routes/system/smart-table.tsx
|
||||
msgid "Type"
|
||||
msgstr "Tipo"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unit file"
|
||||
msgstr "Arquivo de unidade"
|
||||
|
||||
#. Temperature / network units
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Unit preferences"
|
||||
@@ -1183,20 +1454,30 @@ msgstr "Token universal"
|
||||
msgid "Unknown"
|
||||
msgstr "Desconhecida"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Unlimited"
|
||||
msgstr "Ilimitado"
|
||||
|
||||
#. Context: System is up
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/systems-table/systems-table-columns.tsx
|
||||
msgid "Up"
|
||||
msgstr "“Ligado”"
|
||||
msgstr "Ligado"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Up ({upSystemsLength})"
|
||||
msgstr "Ativo ({upSystemsLength})"
|
||||
|
||||
#: src/components/containers-table/containers-table-columns.tsx
|
||||
#: src/components/systemd-table/systemd-table-columns.tsx
|
||||
msgid "Updated"
|
||||
msgstr "Atualizado"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Updated every 10 minutes."
|
||||
msgstr "Atualizado a cada 10 minutos."
|
||||
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "Upload"
|
||||
msgstr "Carregar"
|
||||
@@ -1209,6 +1490,7 @@ msgstr "Tempo de Atividade"
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system.tsx
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
msgid "Usage"
|
||||
msgstr "Uso"
|
||||
|
||||
@@ -1234,6 +1516,7 @@ msgstr "Valor"
|
||||
msgid "View"
|
||||
msgstr "Visual"
|
||||
|
||||
#: src/components/routes/system/cpu-sheet.tsx
|
||||
#: src/components/routes/system/network-sheet.tsx
|
||||
msgid "View more"
|
||||
msgstr "Ver mais"
|
||||
@@ -1254,6 +1537,10 @@ msgstr "Aguardando registros suficientes para exibir"
|
||||
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
|
||||
msgstr "Quer nos ajudar a melhorar ainda mais nossas traduções? Confira <0>Crowdin</0> para mais detalhes."
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Wants"
|
||||
msgstr "Deseja"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Warning (%)"
|
||||
msgstr "Aviso (%)"
|
||||
@@ -1290,6 +1577,12 @@ msgstr "Configuração YAML"
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Configuração YAML"
|
||||
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
#: src/components/systemd-table/systemd-table.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Sim"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "As configurações do seu usuário foram atualizadas."
|
||||
|
||||
1341
internal/site/src/locales/ro/ro.po
Normal file
1341
internal/site/src/locales/ro/ro.po
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user