Compare commits

..

94 Commits

Author SHA1 Message Date
henrygd
ab6ea71695 Release v0.11.0 2025-04-27 19:20:17 -04:00
henrygd
6280323cb1 Always display two decimals in container memory tooltip
- Also removes --china-mirrors when copying brew install script
2025-04-27 19:18:44 -04:00
henrygd
17c8e7e1bd Update bark notification to use url param for link 2025-04-27 14:07:33 -04:00
henrygd
f60fb6f8a9 Handle title and link for Lark notifications 2025-04-26 21:25:18 -04:00
henrygd
3eebbce2d4 Update Go dependencies
Also replaces containrrr/shoutrrr with pinned version of
nicholas-fedor/shoutrrr
2025-04-26 17:47:34 -04:00
henrygd
e92a94a24d update translations 2025-04-26 17:45:12 -04:00
Andypsl8
7c7c073ae4 New zh-CN translations 2025-04-26 14:58:06 -04:00
zoixc
c009a40749 New Russian translations 2025-04-26 14:56:23 -04:00
Alex van Steenhoven
5e85b803e0 New Dutch translations 2025-04-26 14:55:05 -04:00
henrygd
256d3c5ba1 Italian translations from @saamdotexe 2025-04-26 14:51:29 -04:00
henrygd
bd048a8989 French translations from leo.info54 on crowdin 2025-04-26 14:46:24 -04:00
henrygd
f6b4231500 new Arabic translations from rihla on crowdin 2025-04-26 14:41:31 -04:00
henrygd
bda06f30b3 Add temperature chart filtering (#430)
- Refactored ContainerFilterBar to accept a dynamic store prop.
- Updated filtering logic in ContainerChart to be case-insensitive.
2025-04-25 19:19:19 -04:00
henrygd
38f2ba3984 Small refactoring of docker manager
- Add isWindows flag to dockerManager
- `CalculateCpuPercentWindows` and `CalculateCpuPercentLinux` methods added to container.ApiStats
- Remove prevNetStats.Time in favor of Stats.PrevRead
- Replace regex Windows check with strings.Contains, and check the `/containers/json` response
2025-04-25 18:39:24 -04:00
ViryBe
1a7d897bdc compute cpu and memory stats for docker on windows (#653)
The Docker daemon's API returns different values on Windows and non-Windows systems. This impacts
the calculation of `cpuPct` and `usedMemory` for each container. The systems are disciminate on the
`Server` header send by the server. Uses the unix stats calculation in case the header is not set.

`docker stats` implementation for reference:
https://github.com/docker/cli/blob/master/cli/command/container/stats_helpers.go#L100

Co-authored-by: Benoit VIRY <benoit.viry@cgx-group.com>
2025-04-25 18:27:36 -04:00
henrygd
c74e7430ef Disable h/l/left/right changing system if shift, ctrl, or meta keys are pressed (#703) 2025-04-23 16:40:58 -04:00
henrygd
2467bbc0f0 Add support for copying Windows and Homebrew installation commands 2025-04-23 14:17:14 -04:00
henrygd
ea665e02da Improve system information retrieval for macOS and Windows
- Introduce `Os` enum to represent supported operating systems.
- Update `SystemInfo` interface to include OS type.
- Refactor `ContainerChart` component to use `ChartType` enum for better clarity.
- Switched to dynamic units in container memory chart.
2025-04-22 20:29:17 -04:00
henrygd
358e05d544 truncate tooltip container name if very long 2025-04-22 20:16:11 -04:00
henrygd
aab5725d82 Use gpu temp as primary sensor if no other sensors 2025-04-18 18:00:39 -04:00
henrygd
e94a1cd421 brew install - change env var from PORT to LISTEN 2025-04-18 17:59:59 -04:00
henrygd
73c1a1b208 Refactor sensor configuration handling in tests and implementation
- Add skipCollection propery
- Ensure that sensors are initialized as an empty map
2025-04-18 17:59:25 -04:00
henrygd
0526c88ce0 support blacklisting and wildcard matching in SENSORS env var (#650)
- Moved sensor related code to sensors.go
- Added SensorConfig struct
- Added newSensorConfig
- Added tests
2025-04-17 21:08:05 -04:00
henrygd
a2e9056a00 update macos agent install script
- adds option to install homebrew if not installed
2025-04-15 17:54:53 -04:00
henrygd
fd4ac60908 Remove -Program parameter from windows firewall rule (#739) 2025-04-14 17:19:24 -04:00
henrygd
330e4c67f3 Update release workflow and goreleaser configuration
- Change tag pattern in release workflow to 'v*'
- Update description
2025-04-14 17:16:02 -04:00
henrygd
5d840bd473 Windows agent install script improvements
- Remove unneeded set-executionpolicy (in parent command)
- Wait before checking status
- Use direct binary path instead of shim
- Log to one file

Co-authored-by: vmhomelab <info@vmhomelab.de>
2025-04-13 19:56:23 -04:00
henrygd
54e3f3eba1 add goreleaser homebrew config and brew helper script 2025-04-09 19:58:46 -04:00
henrygd
d79111fce4 remove nvidia-smi dependency for jetson / tegrastats (#286) 2025-04-07 20:02:14 -04:00
henrygd
93c3c7b9d8 add windows agent install script 2025-04-06 22:09:43 -04:00
henrygd
410d236f89 fix EXTRA_FILESYSTEMS for windows (#422)
Co-authored-by: coosir <git@coosir.com>
2025-04-05 17:57:34 -04:00
henrygd
9a8071c314 prepend base path for command palette links 2025-04-05 17:34:33 -04:00
henrygd
80df0efccd add correct icon / label for windows build number 2025-04-05 17:33:41 -04:00
henrygd
3f1f4c7596 goreleaser: fix archive ids and add scoop for beszel-agent 2025-04-03 19:15:46 -04:00
Val V
04ac688be4 Agent OpenBSD release (#726) 2025-04-03 18:28:23 -04:00
henrygd
ace83172ff agent install script: improvements to --china-mirrors and --auto-update flags
- Allow using = to define flags
- Allow passing --auto-update=false to skip prompt
2025-03-18 15:58:41 -04:00
Daniel Hiller
e8b864b515 agent installer script: option to skip auto update question 2025-03-16 05:22:42 +01:00
henrygd
7057f2e917 release 0.10.2 2025-03-15 03:01:57 -04:00
henrygd
47b2689f24 updates for lingui 5 2025-03-15 03:01:49 -04:00
henrygd
9b65110aef fix dumb error i pushed five min ago :) 2025-03-15 01:16:18 -04:00
henrygd
3935a9bf00 i18n: update language files 2025-03-15 01:03:20 -04:00
henrygd
fb2adf08dc remove "GPU" from translations 2025-03-15 01:03:11 -04:00
stanol
61441b115b i18n: new Ukrainian translations 2025-03-15 00:58:38 -04:00
aroxu
3ad78a2588 i18n: new Korean translations 2025-03-15 00:57:51 -04:00
harupong
81514d4deb i18n: new Japanese translations 2025-03-15 00:55:14 -04:00
NickAss512
faeb801512 i18n: new cs translations 2025-03-15 00:54:08 -04:00
henrygd
968ca70670 agent temperature fixes (#648, #663)
- Fixes a bad sensor returning an error instead of other good sensors
- Adds ability to set GPU as PRIMARY_SENSOR
2025-03-15 00:29:41 -04:00
henrygd
5837b4f25c Refactor hub initialization and error handling 2025-03-15 00:25:42 -04:00
henrygd
c38d04b34b Add health command for hub and align agent health command 2025-03-15 00:23:12 -04:00
henrygd
cadc09b493 delete duplicate alerts as part of 0.10.2 migrations 2025-03-14 23:03:07 -04:00
henrygd
edefc6f53e add health check for agent
- Updated command-line flag parsing.
- Moved GetAddress and GetNetwork to server.go
2025-03-14 03:33:25 -04:00
henrygd
400ea89587 correct version in upcoming migration name 2025-03-13 22:05:29 -04:00
henrygd
3058c24e82 Allow dynamic size value in default area chart
- Fixes system pause / unpause rendering
- Some formatting
2025-03-13 22:04:29 -04:00
henrygd
521be05bc1 gpu.go refactoring and jetson fixes
- Fixed usage and power values
- Added new test cases
- Moved some variables to constants
2025-03-13 21:32:53 -04:00
henrygd
6b766b2653 add unique multicolumn index to prevent duplicate alerts (#662) 2025-03-13 02:20:27 -04:00
henrygd
d36b8369cc react refactoring for better performance with lots of systems 2025-03-13 02:16:54 -04:00
henrygd
ae22334645 pass hub version through html and update dependencies
- Changed Vite configuration to replace version during development.
2025-03-13 02:15:03 -04:00
henrygd
1d7c0ebc27 fix: error adding alerts to 50+ systems (#664)
- Fixed PB SDK autocancelling requests.
- Refactored SystemAlert and SystemAlertGlobal components.
- Introduced a batchWrapper function for handling batch operations on alerts.
2025-03-13 02:07:58 -04:00
henrygd
3b9910351d release 0.10.1 2025-03-06 05:40:38 -05:00
henrygd
f397ab0797 fix: improve error logging for temperature sensor retrieval 2025-03-06 05:38:49 -05:00
henrygd
b1fc715ec9 fix: prevent 404 on initial startup by moving h.initialize after hooks
- I don't know why this works. Need to look further into it tomorrow :)
2025-03-06 05:38:33 -05:00
henrygd
d25c7c58c1 fix: SYS_SENSORS context error (#643) 2025-03-06 05:36:20 -05:00
henrygd
a6daa70010 chore: bump version to 0.10.0 🎉 2025-03-06 03:11:22 -05:00
henrygd
d722e4712c i18n: update language files 2025-03-06 03:10:34 -05:00
henrygd
1d61ad5d7c deps: update pocketbase 2025-03-06 03:10:01 -05:00
henrygd
28589455bf feat: keep chart time when navigating with arrow keys 2025-03-06 02:23:30 -05:00
henrygd
dd21c18939 feat: add SHARE_ALL_SYSTEMS env var 2025-03-06 01:28:36 -05:00
henrygd
fd79bc3341 i18n: update language files and fix strings for new lingui version 2025-03-06 00:58:29 -05:00
henrygd
7edcf8db85 i18n: new Spanish translations (by Elkin Torres on crowdin) 2025-03-06 00:21:32 -05:00
Roy W. Andersen
245a047062 i18n: new Norwegian translations 2025-03-06 00:19:58 -05:00
stanol
520b52e532 i18n: new Ukrainian translations 2025-03-06 00:19:26 -05:00
Stepan
c421ffac70 i18n: new Russian translations 2025-03-06 00:18:49 -05:00
henrygd
6767392ea8 refactor: update some types in docker.go 2025-03-05 23:40:23 -05:00
henrygd
25b73bfb85 fix: make sure system alerts are checked after records are committed 2025-03-05 23:39:01 -05:00
henrygd
5fbc0de07f refactor: rename address flag and environment variable to 'listen' 2025-03-05 23:37:51 -05:00
henrygd
c8130a10d4 fix: allow logout if auto login if enabled 2025-03-05 23:36:57 -05:00
henrygd
0619eabec2 feat: add keyboard navigation for systems 2025-03-05 23:35:46 -05:00
henrygd
5b4d5c648e chore: update migrations 2025-03-05 23:34:15 -05:00
henrygd
0443a85015 fix: correct typo in Docker stats collection variable name 2025-03-04 17:39:49 -05:00
henrygd
c4d8deb986 feat: agent data cache to support connections to multiple hubs (#341) 2025-03-04 16:25:45 -05:00
henrygd
681286eb4f fix: add User-Agent to resolve Docker Desktop bug (#513, #603)
- also added body closure I forgot earlier whoops
2025-03-04 01:56:22 -05:00
henrygd
99cdb196ca feat: persist selected tab in system dialog (#602) 2025-03-04 01:09:48 -05:00
henrygd
31431fd211 refactor: improve GPU data parsing
- Use byte-based regex matching instead of string-based matching
- Increase buffer size for GPU data
- Switch to `bufio.Scanner`
2025-03-04 00:15:10 -05:00
henrygd
9e56f4611f refactor: restructure hub initialization and startup process
- Separated hub initialization logic into distinct methods
- Move command specific things to cmd/hub
- Add compatibility with new systems package
2025-03-03 23:54:25 -05:00
henrygd
a1f6eeb9eb refactor: alerts package compatiblity with new systems package 2025-03-03 23:52:27 -05:00
henrygd
f8a1d9fc5d refactor: optimize system updates and create systems package
- Created SystemManager to handle system lifecycle and events
- Created tests for system management operations
- Added test helpers for creating and managing test systems
- Introduced optional port configuration in system config
2025-03-03 23:50:19 -05:00
henrygd
d81db6e319 refactor: optimize record management and deletion logic 2025-03-03 23:44:50 -05:00
henrygd
17a163de26 feat: allow searching by status in systems table 2025-03-03 23:39:50 -05:00
henrygd
85db31a8cd chore: add Makefile test target for running Go tests 2025-03-03 23:38:41 -05:00
henrygd
327db38953 chore: update go dependencies 2025-03-03 23:38:01 -05:00
henrygd
0413368762 chore: update js dependencies 2025-03-03 23:37:43 -05:00
henrygd
db73928604 chore: update gitignore 2025-03-03 23:36:26 -05:00
henrygd
add1b27346 remove unreleased migration 2025-03-03 23:35:18 -05:00
henrygd
2ef1fe6b2a systemd: remove ProtectKernelTunables=yes (#176)
https://github.com/henrygd/beszel/issues/176#issuecomment-2691192334
2025-02-28 14:28:00 -05:00
113 changed files with 7660 additions and 13109 deletions

View File

@@ -3,7 +3,7 @@ name: Make release and binaries
on:
push:
tags:
- '*'
- 'v*'
permissions:
contents: write

3
.gitignore vendored
View File

@@ -15,4 +15,5 @@ beszel/build
*timestamp*
.swc
beszel/site/src/locales/**/*.ts
*.bak
*.bak
__debug_*

View File

@@ -29,6 +29,7 @@ builds:
- linux
- darwin
- freebsd
- openbsd
- windows
goarch:
- amd64
@@ -39,6 +40,8 @@ builds:
ignore:
- goos: freebsd
goarch: arm
- goos: openbsd
goarch: arm
- goos: windows
goarch: arm
- goos: darwin
@@ -47,7 +50,7 @@ builds:
goarch: riscv64
archives:
- id: beszel
- id: beszel-agent
format: tar.gz
builds:
- beszel-agent
@@ -59,7 +62,7 @@ archives:
- goos: windows
format: zip
- id: beszel-agent
- id: beszel
format: tar.gz
builds:
- beszel
@@ -111,6 +114,65 @@ nfpms:
# https://github.com/goreleaser/goreleaser/issues/5487
#config: ../supplemental/debian/config.sh
scoops:
- ids: [beszel-agent]
name: beszel-agent
repository:
owner: henrygd
name: beszel-scoops
homepage: 'https://beszel.dev'
description: 'Agent for Beszel, a lightweight server monitoring platform.'
license: MIT
# # Needs choco installed, so doesn't build on linux / default gh workflow :(
# chocolateys:
# - title: Beszel Agent
# ids: [beszel-agent]
# package_source_url: https://github.com/henrygd/beszel-chocolatey
# owners: henrygd
# authors: henrygd
# summary: 'Agent for Beszel, a lightweight server monitoring platform.'
# description: |
# Beszel is a lightweight server monitoring platform that includes Docker statistics, historical data, and alert functions.
# It has a friendly web interface, simple configuration, and is ready to use out of the box. It supports automatic backup, multi-user, OAuth authentication, and API access.
# license_url: https://github.com/henrygd/beszel/blob/main/LICENSE
# project_url: https://beszel.dev
# project_source_url: https://github.com/henrygd/beszel
# docs_url: https://beszel.dev/guide/getting-started
# icon_url: https://cdn.jsdelivr.net/gh/selfhst/icons/png/beszel.png
# bug_tracker_url: https://github.com/henrygd/beszel/issues
# copyright: 2025 henrygd
# tags: foss cross-platform admin monitoring
# require_license_acceptance: false
# release_notes: 'https://github.com/henrygd/beszel/releases/tag/v{{ .Version }}'
brews:
- ids: [beszel-agent]
name: beszel-agent
repository:
owner: henrygd
name: homebrew-beszel
homepage: 'https://beszel.dev'
description: 'Agent for Beszel, a lightweight server monitoring platform.'
license: MIT
extra_install: |
(bin/"beszel-agent-launcher").write <<~EOS
#!/bin/bash
set -a
if [ -f "$HOME/.config/beszel/beszel-agent.env" ]; then
source "$HOME/.config/beszel/beszel-agent.env"
fi
set +a
exec #{bin}/beszel-agent "$@"
EOS
(bin/"beszel-agent-launcher").chmod 0755
service: |
run ["#{bin}/beszel-agent-launcher"]
log_path "#{Dir.home}/.cache/beszel/beszel-agent.log"
error_log_path "#{Dir.home}/.cache/beszel/beszel-agent.log"
keep_alive true
release:
draft: true

View File

@@ -14,6 +14,10 @@ clean:
lint:
golangci-lint run
test: export GOEXPERIMENT=synctest
test:
go test -tags=testing ./...
tidy:
go mod tidy

View File

@@ -7,50 +7,63 @@ import (
"fmt"
"log"
"os"
"strings"
"golang.org/x/crypto/ssh"
)
// cli options
type cmdOptions struct {
key string // key is the public key(s) for SSH authentication.
addr string // addr is the address or port to listen on.
key string // key is the public key(s) for SSH authentication.
listen string // listen is the address or port to listen on.
}
// parseFlags parses the command line flags and populates the config struct.
func (opts *cmdOptions) parseFlags() {
// parse parses the command line flags and populates the config struct.
// It returns true if a subcommand was handled and the program should exit.
func (opts *cmdOptions) parse() bool {
flag.StringVar(&opts.key, "key", "", "Public key(s) for SSH authentication")
flag.StringVar(&opts.addr, "addr", "", "Address or port to listen on")
flag.StringVar(&opts.listen, "listen", "", "Address or port to listen on")
flag.Usage = func() {
fmt.Printf("Usage: %s [options] [subcommand]\n", os.Args[0])
fmt.Println("\nOptions:")
fmt.Printf("Usage: %s [command] [flags]\n", os.Args[0])
fmt.Println("\nCommands:")
fmt.Println(" health Check if the agent is running")
fmt.Println(" help Display this help message")
fmt.Println(" update Update to the latest version")
fmt.Println(" version Display the version")
fmt.Println("\nFlags:")
flag.PrintDefaults()
fmt.Println("\nSubcommands:")
fmt.Println(" version Display the version")
fmt.Println(" help Display this help message")
fmt.Println(" update Update the agent to the latest version")
}
}
// handleSubcommand handles subcommands such as version, help, and update.
// It returns true if a subcommand was handled, false otherwise.
func handleSubcommand() bool {
if len(os.Args) <= 1 {
return false
subcommand := ""
if len(os.Args) > 1 {
subcommand = os.Args[1]
}
switch os.Args[1] {
case "version", "-v":
switch subcommand {
case "-v", "version":
fmt.Println(beszel.AppName+"-agent", beszel.Version)
os.Exit(0)
return true
case "help":
flag.Usage()
os.Exit(0)
return true
case "update":
agent.Update()
os.Exit(0)
return true
case "health":
// for health, we need to parse flags first to get the listen address
args := append(os.Args[2:], subcommand)
flag.CommandLine.Parse(args)
addr := opts.getAddress()
network := agent.GetNetwork(addr)
err := agent.Health(addr, network)
if err != nil {
log.Fatal(err)
}
fmt.Print("ok")
return true
}
flag.Parse()
return false
}
@@ -79,46 +92,18 @@ func (opts *cmdOptions) loadPublicKeys() ([]ssh.PublicKey, error) {
return agent.ParseKeys(string(pubKey))
}
// getAddress gets the address to listen on from the command line flag, environment variable, or default value.
func (opts *cmdOptions) getAddress() string {
// Try command line flag first
if opts.addr != "" {
return opts.addr
}
// Try environment variables
if addr, ok := agent.GetEnv("ADDR"); ok && addr != "" {
return addr
}
// Legacy PORT environment variable support
if port, ok := agent.GetEnv("PORT"); ok && port != "" {
return port
}
return ":45876"
}
// getNetwork returns the network type to use for the server.
func (opts *cmdOptions) getNetwork() string {
if network, _ := agent.GetEnv("NETWORK"); network != "" {
return network
}
if strings.HasPrefix(opts.addr, "/") {
return "unix"
}
return "tcp"
return agent.GetAddress(opts.listen)
}
func main() {
var opts cmdOptions
opts.parseFlags()
subcommandHandled := opts.parse()
if handleSubcommand() {
if subcommandHandled {
return
}
flag.Parse()
opts.addr = opts.getAddress()
var serverConfig agent.ServerOptions
var err error
serverConfig.Keys, err = opts.loadPublicKeys()
@@ -126,8 +111,9 @@ func main() {
log.Fatal("Failed to load public keys:", err)
}
serverConfig.Addr = opts.addr
serverConfig.Network = opts.getNetwork()
addr := opts.getAddress()
serverConfig.Addr = addr
serverConfig.Network = agent.GetNetwork(addr)
agent := agent.NewAgent()
if err := agent.StartServer(serverConfig); err != nil {

View File

@@ -1,6 +1,7 @@
package main
import (
"beszel/internal/agent"
"crypto/ed25519"
"flag"
"os"
@@ -27,22 +28,22 @@ func TestGetAddress(t *testing.T) {
{
name: "use address from flag",
opts: cmdOptions{
addr: "8080",
listen: "8080",
},
expected: "8080",
expected: ":8080",
},
{
name: "use unix socket from flag",
opts: cmdOptions{
addr: "/tmp/beszel.sock",
listen: "/tmp/beszel.sock",
},
expected: "/tmp/beszel.sock",
},
{
name: "use ADDR env var",
name: "use LISTEN env var",
opts: cmdOptions{},
envVars: map[string]string{
"ADDR": "1.2.3.4:9090",
"LISTEN": "1.2.3.4:9090",
},
expected: "1.2.3.4:9090",
},
@@ -52,26 +53,26 @@ func TestGetAddress(t *testing.T) {
envVars: map[string]string{
"PORT": "7070",
},
expected: "7070",
expected: ":7070",
},
{
name: "use unix socket from env var",
opts: cmdOptions{
addr: "",
listen: "",
},
envVars: map[string]string{
"ADDR": "/tmp/beszel.sock",
"LISTEN": "/tmp/beszel.sock",
},
expected: "/tmp/beszel.sock",
},
{
name: "flag takes precedence over env vars",
opts: cmdOptions{
addr: ":8080",
listen: ":8080",
},
envVars: map[string]string{
"ADDR": ":9090",
"PORT": "7070",
"LISTEN": ":9090",
"PORT": "7070",
},
expected: ":8080",
},
@@ -201,27 +202,27 @@ func TestGetNetwork(t *testing.T) {
},
{
name: "only port",
opts: cmdOptions{addr: "8080"},
opts: cmdOptions{listen: "8080"},
expected: "tcp",
},
{
name: "ipv4 address",
opts: cmdOptions{addr: "1.2.3.4:8080"},
opts: cmdOptions{listen: "1.2.3.4:8080"},
expected: "tcp",
},
{
name: "ipv6 address",
opts: cmdOptions{addr: "[2001:db8::1]:8080"},
opts: cmdOptions{listen: "[2001:db8::1]:8080"},
expected: "tcp",
},
{
name: "unix network",
opts: cmdOptions{addr: "/tmp/beszel.sock"},
opts: cmdOptions{listen: "/tmp/beszel.sock"},
expected: "unix",
},
{
name: "env var network",
opts: cmdOptions{addr: ":8080"},
opts: cmdOptions{listen: ":8080"},
envVars: map[string]string{"NETWORK": "tcp4"},
expected: "tcp4",
},
@@ -233,7 +234,7 @@ func TestGetNetwork(t *testing.T) {
for k, v := range tt.envVars {
t.Setenv(k, v)
}
network := tt.opts.getNetwork()
network := agent.GetNetwork(tt.opts.listen)
assert.Equal(t, tt.expected, network)
})
}
@@ -256,32 +257,32 @@ func TestParseFlags(t *testing.T) {
name: "no flags",
args: []string{"cmd"},
expected: cmdOptions{
key: "",
addr: "",
key: "",
listen: "",
},
},
{
name: "key flag only",
args: []string{"cmd", "-key", "testkey"},
expected: cmdOptions{
key: "testkey",
addr: "",
key: "testkey",
listen: "",
},
},
{
name: "addr flag only",
args: []string{"cmd", "-addr", ":8080"},
args: []string{"cmd", "-listen", ":8080"},
expected: cmdOptions{
key: "",
addr: ":8080",
key: "",
listen: ":8080",
},
},
{
name: "both flags",
args: []string{"cmd", "-key", "testkey", "-addr", ":8080"},
args: []string{"cmd", "-key", "testkey", "-listen", ":8080"},
expected: cmdOptions{
key: "testkey",
addr: ":8080",
key: "testkey",
listen: ":8080",
},
},
}
@@ -293,7 +294,7 @@ func TestParseFlags(t *testing.T) {
os.Args = tt.args
var opts cmdOptions
opts.parseFlags()
opts.parse()
flag.Parse()
assert.Equal(t, tt.expected, opts)

View File

@@ -1,10 +1,99 @@
package main
import (
"beszel"
"beszel/internal/hub"
_ "beszel/migrations"
"fmt"
"log"
"net/http"
"os"
"time"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/plugins/migratecmd"
"github.com/spf13/cobra"
)
func main() {
hub.NewHub().Run()
// handle health check first to prevent unneeded execution
if len(os.Args) > 3 && os.Args[1] == "health" {
url := os.Args[3]
if err := checkHealth(url); err != nil {
log.Fatal(err)
}
fmt.Print("ok")
return
}
baseApp := getBaseApp()
h := hub.NewHub(baseApp)
if err := h.StartHub(); err != nil {
log.Fatal(err)
}
}
// getBaseApp creates a new PocketBase app with the default config
func getBaseApp() *pocketbase.PocketBase {
isDev := os.Getenv("ENV") == "dev"
baseApp := pocketbase.NewWithConfig(pocketbase.Config{
DefaultDataDir: beszel.AppName + "_data",
DefaultDev: isDev,
})
baseApp.RootCmd.Version = beszel.Version
baseApp.RootCmd.Use = beszel.AppName
baseApp.RootCmd.Short = ""
// add update command
baseApp.RootCmd.AddCommand(&cobra.Command{
Use: "update",
Short: "Update " + beszel.AppName + " to the latest version",
Run: hub.Update,
})
// add health command
baseApp.RootCmd.AddCommand(newHealthCmd())
// enable auto creation of migration files when making collection changes in the Admin UI
migratecmd.MustRegister(baseApp, baseApp.RootCmd, migratecmd.Config{
Automigrate: isDev,
Dir: "../../migrations",
})
return baseApp
}
func newHealthCmd() *cobra.Command {
var baseURL string
healthCmd := &cobra.Command{
Use: "health",
Short: "Check health of running hub",
Run: func(cmd *cobra.Command, args []string) {
if err := checkHealth(baseURL); err != nil {
log.Fatal(err)
}
os.Exit(0)
},
}
healthCmd.Flags().StringVar(&baseURL, "url", "", "base URL")
healthCmd.MarkFlagRequired("url")
return healthCmd
}
// checkHealth checks the health of the hub.
func checkHealth(baseURL string) error {
client := &http.Client{
Timeout: time.Second * 3,
}
healthURL := baseURL + "/api/health"
resp, err := client.Get(healthURL)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return fmt.Errorf("%s returned status %d", healthURL, resp.StatusCode)
}
return nil
}

View File

@@ -1,65 +1,48 @@
module beszel
go 1.24.0
go 1.24.2
// lock shoutrrr to specific version to allow review before updating
replace github.com/nicholas-fedor/shoutrrr => github.com/nicholas-fedor/shoutrrr v0.8.8
require (
github.com/blang/semver v3.5.1+incompatible
github.com/containrrr/shoutrrr v0.8.0
github.com/gliderlabs/ssh v0.3.8
github.com/goccy/go-json v0.10.5
github.com/nicholas-fedor/shoutrrr v0.8.8
github.com/pocketbase/dbx v1.11.0
github.com/pocketbase/pocketbase v0.25.0
github.com/pocketbase/pocketbase v0.27.1
github.com/rhysd/go-github-selfupdate v1.2.3
github.com/shirou/gopsutil/v4 v4.25.1
github.com/shirou/gopsutil/v4 v4.25.3
github.com/spf13/cast v1.7.1
github.com/spf13/cobra v1.8.1
github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.32.0
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c
golang.org/x/crypto v0.37.0
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go-v2 v1.36.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.8 // indirect
github.com/aws/aws-sdk-go-v2/config v1.29.6 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.59 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.59 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.32 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.5.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.13 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.75.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.14 // indirect
github.com/aws/smithy-go v1.22.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/disintegration/imaging v1.6.2 // indirect
github.com/domodwyer/mailyak/v3 v3.6.2 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/ebitengine/purego v0.8.2 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/ganigeorgiev/fexpr v0.4.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.9 // 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/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/go-sql-driver/mysql v1.9.1 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/google/go-github/v30 v30.1.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // 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
@@ -68,26 +51,18 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/tcnksm/go-gitconfig v0.1.2 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.9.0 // indirect
github.com/tklauser/go-sysconf v0.3.15 // indirect
github.com/tklauser/numcpus v0.10.0 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opencensus.io v0.24.0 // indirect
gocloud.dev v0.40.0 // indirect
golang.org/x/image v0.24.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/oauth2 v0.26.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/term v0.29.0 // indirect
golang.org/x/text v0.22.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/api v0.220.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 // indirect
google.golang.org/grpc v1.70.0 // indirect
google.golang.org/protobuf v1.36.4 // indirect
modernc.org/libc v1.55.3 // indirect
golang.org/x/image v0.26.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/oauth2 v0.29.0 // indirect
golang.org/x/sync v0.13.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
modernc.org/libc v1.64.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.8.2 // indirect
modernc.org/sqlite v1.34.5 // indirect
modernc.org/memory v1.10.0 // indirect
modernc.org/sqlite v1.37.0 // indirect
)

View File

@@ -1,75 +1,14 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0=
cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM=
cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M=
cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc=
cloud.google.com/go/compute v1.14.0 h1:hfm2+FfxVmnRlh6LpB7cg1ZNU+5edAHmW679JePztk0=
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
cloud.google.com/go/iam v1.1.13 h1:7zWBXG9ERbMLrzQBRhFliAV+kjcRToDTgQT3CTwYyv4=
cloud.google.com/go/iam v1.1.13/go.mod h1:K8mY0uSXwEXS30KrnVb+j54LB/ntfZu1dr+4zFMNbus=
cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs=
cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/aws/aws-sdk-go-v2 v1.36.1 h1:iTDl5U6oAhkNPba0e1t1hrwAo02ZMqbrGq4k5JBWM5E=
github.com/aws/aws-sdk-go-v2 v1.36.1/go.mod h1:5PMILGVKiW32oDzjj6RU52yrNrDPUHcbZQYr1sM7qmM=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.8 h1:zAxi9p3wsZMIaVCdoiQp2uZ9k1LsZvmAnoTBeZPXom0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.8/go.mod h1:3XkePX5dSaxveLAYY7nsbsZZrKxCyEuE5pM4ziFxyGg=
github.com/aws/aws-sdk-go-v2/config v1.29.6 h1:fqgqEKK5HaZVWLQoLiC9Q+xDlSp+1LYidp6ybGE2OGg=
github.com/aws/aws-sdk-go-v2/config v1.29.6/go.mod h1:Ft+WLODzDQmCTHDvqAH1JfC2xxbZ0MxpZAcJqmE1LTQ=
github.com/aws/aws-sdk-go-v2/credentials v1.17.59 h1:9btwmrt//Q6JcSdgJOLI98sdr5p7tssS9yAsGe8aKP4=
github.com/aws/aws-sdk-go-v2/credentials v1.17.59/go.mod h1:NM8fM6ovI3zak23UISdWidyZuI1ghNe2xjzUZAyT+08=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 h1:KwsodFKVQTlI5EyhRSugALzsV6mG/SGrdjlMXSZSdso=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28/go.mod h1:EY3APf9MzygVhKuPXAc5H+MkGb8k/DOSQjWS0LgkKqI=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.59 h1:5Vsrfdlf9KQP3leGX1dD7VwZq/3HAerEFoXAII4t6zo=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.59/go.mod h1:7XTNs3NYApJjkx6A2Fk9qq23qBuBnIU58k3fKC2Fr1I=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32 h1:BjUcr3X3K0wZPGFg2bxOWW3VPN8rkE3/61zhP+IHviA=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32/go.mod h1:80+OGC/bgzzFFTUmcuwD0lb4YutwQeKLFpmt6hoWapU=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32 h1:m1GeXHVMJsRsUAqG6HjZWx9dj7F5TR+cF1bjyfYyBd4=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32/go.mod h1:IitoQxGfaKdVLNg0hD8/DXmAqNy0H4K2H2Sf91ti8sI=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.32 h1:OIHj/nAhVzIXGzbAE+4XmZ8FPvro3THr6NlqErJc3wY=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.32/go.mod h1:LiBEsDo34OJXqdDlRGsilhlIiXR7DL+6Cx2f4p1EgzI=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.5.6 h1:cCBJaT7EeEojpJ4s7wTDbhZlHVJOgNHN7iw6qVurGaw=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.5.6/go.mod h1:WYH1ABybY7JK9TITPnk6ZlP7gQB8psI4c9qDmMsnLSA=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13 h1:SYVGSFQHlchIcy6e7x12bsrxClCXSP5et8cqVhL8cuw=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13/go.mod h1:kizuDaLX37bG5WZaoxGPQR/LNFXpxp0vsUnqfkWXfNE=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.13 h1:OBsrtam3rk8NfBEq7OLOMm5HtQ9Yyw32X4UQMya/wjw=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.13/go.mod h1:3U4gFA5pmoCOja7aq4nSaIAGbaOHv2Yl2ug018cmC+Q=
github.com/aws/aws-sdk-go-v2/service/s3 v1.75.4 h1:DJYjOvNgC30JAcDCRmtQHoYK4trc7XetDXRTEAReGKA=
github.com/aws/aws-sdk-go-v2/service/s3 v1.75.4/go.mod h1:KuLNrwYJFaC2AVZ+CVVc12k9NyqwgWsoNNHjwqF6QNk=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 h1:/eE3DogBjYlvlbhd2ssWyeuovWunHLxfgw3s/OJa4GQ=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.15/go.mod h1:2PCJYpi7EKeA5SkStAmZlF6fi0uUABuhtF8ILHjGc3Y=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 h1:M/zwXiL2iXUrHputuXgmO94TVNmcenPHxgLXLutodKE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14/go.mod h1:RVwIw3y/IqxC2YEXSIkAzRDdEU1iRabDPaYjpGCbCGQ=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.14 h1:TzeR06UCMUq+KA3bDkujxK1GVGy+G8qQN/QVYzGLkQE=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.14/go.mod h1:dspXf/oYWGWo6DEvj98wpaTeqt5+DMidZD0A9BYTizc=
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec=
github.com/containrrr/shoutrrr v0.8.0/go.mod h1:ioyQAyu1LJY6sILuNyKaQaw+9Ttik5QePU8atnAdO2o=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
@@ -80,94 +19,55 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
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/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k=
github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
github.com/ganigeorgiev/fexpr v0.5.0 h1:XA9JxtTE/Xm+g/JFI6RfZEHSiQlk+1glLvRK1Lpv/Tk=
github.com/ganigeorgiev/fexpr v0.5.0/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI=
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/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo=
github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8=
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jarcoal/httpmock v1.4.0 h1:BvhqnH0JAYbNudL2GMJKgOHe2CtKlzJ/5rWKyp+hc2k=
github.com/jarcoal/httpmock v1.4.0/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -175,31 +75,32 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0=
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/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.8.8 h1:F/oyoatWK5cbHPPgkjRZrA0262TP7KWuUQz9KskRtR8=
github.com/nicholas-fedor/shoutrrr v0.8.8/go.mod h1:T30Y+eoZFEjDk4HtOItcHQioZSOe3Z6a6aNfSz6jc5c=
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
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.25.0 h1:/4YQq1hd0muvhzbERyUTVNh88N0BCj5diqK0jtLN6k8=
github.com/pocketbase/pocketbase v0.25.0/go.mod h1:tOtOv7f3vJhAiyUluIwV9JPuKeknZRQ9F6uJE3W/ntI=
github.com/pocketbase/pocketbase v0.27.1 h1:KGCsS8idUVTC5QHxTj91qHDhIXOb5Yb50wwHhNvJRTQ=
github.com/pocketbase/pocketbase v0.27.1/go.mod h1:aTpwwloVJzeJ7MlwTRrbI/x62QNR2/kkCrovmyrXpqs=
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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rhysd/go-github-selfupdate v1.2.3 h1:iaa+J202f+Nc+A8zi75uccC8Wg3omaM7HDeimXA22Ag=
@@ -207,156 +108,82 @@ github.com/rhysd/go-github-selfupdate v1.2.3/go.mod h1:mp/N8zj6jFfBQy/XMYoWsmfzx
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.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0ZqmLjXs=
github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI=
github.com/shirou/gopsutil/v4 v4.25.3 h1:SeA68lsu8gLggyMbmCn8cmp97V1TI9ld9sVzAUcKcKE=
github.com/shirou/gopsutil/v4 v4.25.3/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw=
github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE=
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI=
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 h1:PS8wXpbyaDJQ2VDHHncMe9Vct0Zn1fEjpsjrLxGJoSc=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
gocloud.dev v0.40.0 h1:f8LgP+4WDqOG/RXoUcyLpeIAGOcAbZrZbDQCUee10ng=
gocloud.dev v0.40.0/go.mod h1:drz+VyYNBvrMTW0KZiBAYEdl8lbNZx+OQ7oQvdrFmSQ=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE=
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/api v0.220.0 h1:3oMI4gdBgB72WFVwE1nerDD8W3HUOS4kypK6rRLbGns=
google.golang.org/api v0.220.0/go.mod h1:26ZAlY6aN/8WgpCzjPNy18QpYaz7Zgg1h0qe1GkZEmY=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 h1:CT2Thj5AuPV9phrYMtzX11k+XkzMGfRAet42PmoTATM=
google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc=
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 h1:5bKytslY8ViY0Cj/ewmRtrWHW64bNF03cAatUUFCdFI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -364,32 +191,29 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
modernc.org/cc/v4 v4.26.0 h1:QMYvbVduUGH0rrO+5mqF/PSPPRZNpRtg2CLELy7vUpA=
modernc.org/cc/v4 v4.26.0/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.26.0 h1:gVzXaDzGeBYJ2uXTOpR8FR7OlksDOe9jxnjhIKCsiTc=
modernc.org/ccgo/v4 v4.26.0/go.mod h1:Sem8f7TFUtVXkG2fiaChQtyyfkqhJBg/zjEJBkmuAVY=
modernc.org/fileutil v1.3.1 h1:8vq5fe7jdtEvoCf3Zf9Nm0Q05sH6kGx0Op2CPx1wTC8=
modernc.org/fileutil v1.3.1/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/libc v1.64.0 h1:U0k8BD2d3cD3e9I8RLcZgJBHAcsJzbXx5mKGSb5pyJA=
modernc.org/libc v1.64.0/go.mod h1:7m9VzGq7APssBTydds2zBcxGREwvIGpuUBaKTXdm2Qs=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI=
modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.34.5 h1:Bb6SR13/fjp15jt70CL4f18JIN7p7dnMExd+UFnF15g=
modernc.org/sqlite v1.34.5/go.mod h1:YLuNmX9NKs8wRNK2ko1LW1NGYcc9FkBO69JOt1AR9JE=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/memory v1.10.0 h1:fzumd51yQ1DxcOxSO+S6X7+QTuVU+n8/Aj7swYjFfC4=
modernc.org/memory v1.10.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
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.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI=
modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM=
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=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=

View File

@@ -4,37 +4,36 @@ package agent
import (
"beszel"
"beszel/internal/entities/system"
"context"
"log/slog"
"os"
"strings"
"sync"
"github.com/shirou/gopsutil/v4/common"
"time"
)
type Agent struct {
sync.Mutex // Used to lock agent while collecting data
debug bool // true if LOG_LEVEL is set to debug
zfs bool // true if system has arcstats
memCalc string // Memory calculation formula
fsNames []string // List of filesystem device names being monitored
fsStats map[string]*system.FsStats // Keeps track of disk stats for each filesystem
netInterfaces map[string]struct{} // Stores all valid network interfaces
netIoStats system.NetIoStats // Keeps track of bandwidth usage
dockerManager *dockerManager // Manages Docker API requests
sensorsContext context.Context // Sensors context to override sys location
sensorsWhitelist map[string]struct{} // List of sensors to monitor
systemInfo system.Info // Host system info
gpuManager *GPUManager // Manages GPU data
sync.Mutex // Used to lock agent while collecting data
debug bool // true if LOG_LEVEL is set to debug
zfs bool // true if system has arcstats
memCalc string // Memory calculation formula
fsNames []string // List of filesystem device names being monitored
fsStats map[string]*system.FsStats // Keeps track of disk stats for each filesystem
netInterfaces map[string]struct{} // Stores all valid network interfaces
netIoStats system.NetIoStats // Keeps track of bandwidth usage
dockerManager *dockerManager // Manages Docker API requests
sensorConfig *SensorConfig // Sensors config
systemInfo system.Info // Host system info
gpuManager *GPUManager // Manages GPU data
cache *SessionCache // Cache for system stats based on primary session ID
}
func NewAgent() *Agent {
agent := &Agent{
fsStats: make(map[string]*system.FsStats),
cache: NewSessionCache(69 * time.Second),
}
agent.memCalc, _ = GetEnv("MEM_CALC")
agent.sensorConfig = agent.newSensorConfig()
// Set up slog with a log level determined by the LOG_LEVEL env var
if logLevelStr, exists := GetEnv("LOG_LEVEL"); exists {
switch strings.ToLower(logLevelStr) {
@@ -50,26 +49,6 @@ func NewAgent() *Agent {
slog.Debug(beszel.Version)
// Set sensors context (allows overriding sys location for sensors)
if sysSensors, exists := GetEnv("SYS_SENSORS"); exists {
slog.Info("SYS_SENSORS", "path", sysSensors)
agent.sensorsContext = context.WithValue(agent.sensorsContext,
common.EnvKey, common.EnvMap{common.HostSysEnvKey: sysSensors},
)
} else {
agent.sensorsContext = context.Background()
}
// Set sensors whitelist
if sensors, exists := GetEnv("SENSORS"); exists {
agent.sensorsWhitelist = make(map[string]struct{})
for _, sensor := range strings.Split(sensors, ",") {
if sensor != "" {
agent.sensorsWhitelist[sensor] = struct{}{}
}
}
}
// initialize system info / docker manager
agent.initializeSystemInfo()
agent.initializeDiskInfo()
@@ -85,7 +64,7 @@ func NewAgent() *Agent {
// if debugging, print stats
if agent.debug {
slog.Debug("Stats", "data", agent.gatherStats())
slog.Debug("Stats", "data", agent.gatherStats(""))
}
return agent
@@ -100,29 +79,37 @@ func GetEnv(key string) (value string, exists bool) {
return os.LookupEnv(key)
}
func (a *Agent) gatherStats() system.CombinedData {
func (a *Agent) gatherStats(sessionID string) *system.CombinedData {
a.Lock()
defer a.Unlock()
slog.Debug("Getting stats")
systemData := system.CombinedData{
cachedData, ok := a.cache.Get(sessionID)
if ok {
slog.Debug("Cached stats", "session", sessionID)
return cachedData
}
*cachedData = system.CombinedData{
Stats: a.getSystemStats(),
Info: a.systemInfo,
}
slog.Debug("System stats", "data", systemData)
// add docker stats
slog.Debug("System stats", "data", cachedData)
if containerStats, err := a.dockerManager.getDockerStats(); err == nil {
systemData.Containers = containerStats
slog.Debug("Docker stats", "data", systemData.Containers)
cachedData.Containers = containerStats
slog.Debug("Docker stats", "data", cachedData.Containers)
} else {
slog.Debug("Error getting docker stats", "err", err)
slog.Debug("Docker stats", "err", err)
}
// add extra filesystems
systemData.Stats.ExtraFs = make(map[string]*system.FsStats)
cachedData.Stats.ExtraFs = make(map[string]*system.FsStats)
for name, stats := range a.fsStats {
if !stats.Root && stats.DiskTotal > 0 {
systemData.Stats.ExtraFs[name] = stats
cachedData.Stats.ExtraFs[name] = stats
}
}
slog.Debug("Extra filesystems", "data", systemData.Stats.ExtraFs)
return systemData
slog.Debug("Extra filesystems", "data", cachedData.Stats.ExtraFs)
a.cache.Set(sessionID, cachedData)
return cachedData
}

View File

@@ -0,0 +1,36 @@
package agent
import (
"beszel/internal/entities/system"
"time"
)
// Not thread safe since we only access from gatherStats which is already locked
type SessionCache struct {
data *system.CombinedData
lastUpdate time.Time
primarySession string
leaseTime time.Duration
}
func NewSessionCache(leaseTime time.Duration) *SessionCache {
return &SessionCache{
leaseTime: leaseTime,
data: &system.CombinedData{},
}
}
func (c *SessionCache) Get(sessionID string) (stats *system.CombinedData, isCached bool) {
if sessionID != c.primarySession && time.Since(c.lastUpdate) < c.leaseTime {
return c.data, true
}
return c.data, false
}
func (c *SessionCache) Set(sessionID string, data *system.CombinedData) {
if data != nil {
*c.data = *data
}
c.primarySession = sessionID
c.lastUpdate = time.Now()
}

View File

@@ -0,0 +1,85 @@
package agent
import (
"beszel/internal/entities/system"
"testing"
"testing/synctest"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSessionCache_GetSet(t *testing.T) {
synctest.Run(func() {
cache := NewSessionCache(69 * time.Second)
testData := &system.CombinedData{
Info: system.Info{
Hostname: "test-host",
Cores: 4,
},
Stats: system.Stats{
Cpu: 50.0,
MemPct: 30.0,
DiskPct: 40.0,
},
}
// Test initial state - should not be cached
data, isCached := cache.Get("session1")
assert.False(t, isCached, "Expected no cached data initially")
assert.NotNil(t, data, "Expected data to be initialized")
// Set data for session1
cache.Set("session1", testData)
time.Sleep(15 * time.Second)
// Get data for a different session - should be cached
data, isCached = cache.Get("session2")
assert.True(t, isCached, "Expected data to be cached for non-primary session")
require.NotNil(t, data, "Expected cached data to be returned")
assert.Equal(t, "test-host", data.Info.Hostname, "Hostname should match test data")
assert.Equal(t, 4, data.Info.Cores, "Cores should match test data")
assert.Equal(t, 50.0, data.Stats.Cpu, "CPU should match test data")
assert.Equal(t, 30.0, data.Stats.MemPct, "Memory percentage should match test data")
assert.Equal(t, 40.0, data.Stats.DiskPct, "Disk percentage should match test data")
time.Sleep(10 * time.Second)
// Get data for the primary session - should not be cached
data, isCached = cache.Get("session1")
assert.False(t, isCached, "Expected data not to be cached for primary session")
require.NotNil(t, data, "Expected data to be returned even if not cached")
assert.Equal(t, "test-host", data.Info.Hostname, "Hostname should match test data")
// if not cached, agent will update the data
cache.Set("session1", testData)
time.Sleep(45 * time.Second)
// Get data for a different session - should still be cached
_, isCached = cache.Get("session2")
assert.True(t, isCached, "Expected data to be cached for non-primary session")
// Wait for the lease to expire
time.Sleep(30 * time.Second)
// Get data for session2 - should not be cached
_, isCached = cache.Get("session2")
assert.False(t, isCached, "Expected data not to be cached after lease expiration")
})
}
func TestSessionCache_NilData(t *testing.T) {
// Create a new SessionCache
cache := NewSessionCache(30 * time.Second)
// Test setting nil data (should not panic)
assert.NotPanics(t, func() {
cache.Set("session1", nil)
}, "Setting nil data should not panic")
// Get data - should not be nil even though we set nil
data, _ := cache.Get("session2")
assert.NotNil(t, data, "Expected data to not be nil after setting nil data")
}

View File

@@ -5,6 +5,7 @@ import (
"log/slog"
"os"
"path/filepath"
"runtime"
"strings"
"time"
@@ -36,7 +37,12 @@ func (a *Agent) initializeDiskInfo() {
// Helper function to add a filesystem to fsStats if it doesn't exist
addFsStat := func(device, mountpoint string, root bool) {
key := filepath.Base(device)
var key string
if runtime.GOOS == "windows" {
key = device
} else {
key = filepath.Base(device)
}
var ioMatch bool
if _, exists := a.fsStats[key]; !exists {
if root {

View File

@@ -22,10 +22,23 @@ type dockerManager struct {
wg sync.WaitGroup // WaitGroup to wait for all goroutines to finish
sem chan struct{} // Semaphore to limit concurrent container requests
containerStatsMutex sync.RWMutex // Mutex to prevent concurrent access to containerStatsMap
apiContainerList *[]container.ApiInfo // List of containers from Docker API
apiContainerList []*container.ApiInfo // List of containers from Docker API (no pointer)
containerStatsMap map[string]*container.Stats // Keeps track of container stats
validIds map[string]struct{} // Map of valid container ids, used to prune invalid containers from containerStatsMap
goodDockerVersion bool // Whether docker version is at least 25.0.0 (one-shot works correctly)
isWindows bool // Whether the Docker Engine API is running on Windows
}
// userAgentRoundTripper is a custom http.RoundTripper that adds a User-Agent header to all requests
type userAgentRoundTripper struct {
rt http.RoundTripper
userAgent string
}
// RoundTrip implements the http.RoundTripper interface
func (u *userAgentRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
req.Header.Set("User-Agent", u.userAgent)
return u.rt.RoundTrip(req)
}
// Add goroutine to the queue
@@ -52,11 +65,14 @@ func (dm *dockerManager) getDockerStats() ([]*container.Stats, error) {
}
defer resp.Body.Close()
dm.apiContainerList = dm.apiContainerList[:0]
if err := json.NewDecoder(resp.Body).Decode(&dm.apiContainerList); err != nil {
return nil, err
}
containersLength := len(*dm.apiContainerList)
dm.isWindows = strings.Contains(resp.Header.Get("Server"), "windows")
containersLength := len(dm.apiContainerList)
// store valid ids to clean up old container ids from map
if dm.validIds == nil {
@@ -65,9 +81,9 @@ func (dm *dockerManager) getDockerStats() ([]*container.Stats, error) {
clear(dm.validIds)
}
var failedContainters []container.ApiInfo
var failedContainers []*container.ApiInfo
for _, ctr := range *dm.apiContainerList {
for _, ctr := range dm.apiContainerList {
ctr.IdShort = ctr.Id[:12]
dm.validIds[ctr.IdShort] = struct{}{}
// check if container is less than 1 minute old (possible restart)
@@ -84,7 +100,7 @@ func (dm *dockerManager) getDockerStats() ([]*container.Stats, error) {
if err != nil {
dm.containerStatsMutex.Lock()
delete(dm.containerStatsMap, ctr.IdShort)
failedContainters = append(failedContainters, ctr)
failedContainers = append(failedContainers, ctr)
dm.containerStatsMutex.Unlock()
}
}()
@@ -93,9 +109,9 @@ func (dm *dockerManager) getDockerStats() ([]*container.Stats, error) {
dm.wg.Wait()
// retry failed containers separately so we can run them in parallel (docker 24 bug)
if len(failedContainters) > 0 {
slog.Debug("Retrying failed containers", "count", len(failedContainters))
for _, ctr := range failedContainters {
if len(failedContainers) > 0 {
slog.Debug("Retrying failed containers", "count", len(failedContainers))
for _, ctr := range failedContainers {
dm.queue()
go func() {
defer dm.dequeue()
@@ -122,7 +138,7 @@ func (dm *dockerManager) getDockerStats() ([]*container.Stats, error) {
}
// Updates stats for individual container
func (dm *dockerManager) updateContainerStats(ctr container.ApiInfo) error {
func (dm *dockerManager) updateContainerStats(ctr *container.ApiInfo) error {
name := ctr.Names[0][1:]
resp, err := dm.client.Get("http://localhost/containers/" + ctr.IdShort + "/stats?stream=0&one-shot=1")
@@ -153,22 +169,27 @@ func (dm *dockerManager) updateContainerStats(ctr container.ApiInfo) error {
return err
}
// check if container has valid data, otherwise may be in restart loop (#103)
if res.MemoryStats.Usage == 0 {
return fmt.Errorf("%s - no memory stats - see https://github.com/henrygd/beszel/issues/144", name)
// calculate cpu and memory stats
var usedMemory uint64
var cpuPct float64
if dm.isWindows {
usedMemory = res.MemoryStats.PrivateWorkingSet
cpuPct = res.CalculateCpuPercentWindows(stats.PrevCpu[0], stats.PrevRead)
} else {
// check if container has valid data, otherwise may be in restart loop (#103)
if res.MemoryStats.Usage == 0 {
return fmt.Errorf("%s - no memory stats - see https://github.com/henrygd/beszel/issues/144", name)
}
memCache := res.MemoryStats.Stats.InactiveFile
if memCache == 0 {
memCache = res.MemoryStats.Stats.Cache
}
usedMemory = res.MemoryStats.Usage - memCache
cpuPct = res.CalculateCpuPercentLinux(stats.PrevCpu)
}
// memory (https://docs.docker.com/reference/cli/docker/container/stats/)
memCache := res.MemoryStats.Stats.InactiveFile
if memCache == 0 {
memCache = res.MemoryStats.Stats.Cache
}
usedMemory := res.MemoryStats.Usage - memCache
// cpu
cpuDelta := res.CPUStats.CPUUsage.TotalUsage - stats.PrevCpu[0]
systemDelta := res.CPUStats.SystemUsage - stats.PrevCpu[1]
cpuPct := float64(cpuDelta) / float64(systemDelta) * 100
if cpuPct > 100 {
return fmt.Errorf("%s cpu pct greater than 100: %+v", name, cpuPct)
}
@@ -183,18 +204,18 @@ func (dm *dockerManager) updateContainerStats(ctr container.ApiInfo) error {
var sent_delta, recv_delta float64
// prevent first run from sending all prev sent/recv bytes
if initialized {
secondsElapsed := time.Since(stats.PrevNet.Time).Seconds()
secondsElapsed := time.Since(stats.PrevRead).Seconds()
sent_delta = float64(total_sent-stats.PrevNet.Sent) / secondsElapsed
recv_delta = float64(total_recv-stats.PrevNet.Recv) / secondsElapsed
}
stats.PrevNet.Sent = total_sent
stats.PrevNet.Recv = total_recv
stats.PrevNet.Time = time.Now()
stats.Cpu = twoDecimals(cpuPct)
stats.Mem = bytesToMegabytes(float64(usedMemory))
stats.NetworkSent = bytesToMegabytes(sent_delta)
stats.NetworkRecv = bytesToMegabytes(recv_delta)
stats.PrevRead = res.Read
return nil
}
@@ -251,20 +272,27 @@ func newDockerManager(a *Agent) *dockerManager {
slog.Info("DOCKER_TIMEOUT", "timeout", timeout)
}
dockerClient := &dockerManager{
// Custom user-agent to avoid docker bug: https://github.com/docker/for-mac/issues/7575
userAgentTransport := &userAgentRoundTripper{
rt: transport,
userAgent: "Docker-Client/",
}
manager := &dockerManager{
client: &http.Client{
Timeout: timeout,
Transport: transport,
Transport: userAgentTransport,
},
containerStatsMap: make(map[string]*container.Stats),
sem: make(chan struct{}, 5),
apiContainerList: []*container.ApiInfo{},
}
// If using podman, return client
if strings.Contains(dockerHost, "podman") {
a.systemInfo.Podman = true
dockerClient.goodDockerVersion = true
return dockerClient
manager.goodDockerVersion = true
return manager
}
// Check docker version
@@ -272,23 +300,24 @@ func newDockerManager(a *Agent) *dockerManager {
var versionInfo struct {
Version string `json:"Version"`
}
resp, err := dockerClient.client.Get("http://localhost/version")
resp, err := manager.client.Get("http://localhost/version")
if err != nil {
return dockerClient
return manager
}
defer resp.Body.Close()
if err := json.NewDecoder(resp.Body).Decode(&versionInfo); err != nil {
return dockerClient
return manager
}
// if version > 24, one-shot works correctly and we can limit concurrent operations
if dockerVersion, err := semver.Parse(versionInfo.Version); err == nil && dockerVersion.Major > 24 {
dockerClient.goodDockerVersion = true
manager.goodDockerVersion = true
} else {
slog.Info(fmt.Sprintf("Docker %s is outdated. Upgrade if possible. See https://github.com/henrygd/beszel/issues/58", versionInfo.Version))
}
return dockerClient
return manager
}
// Test docker / podman sockets and return if one exists

View File

@@ -3,6 +3,7 @@ package agent
import (
"beszel/internal/entities/system"
"bufio"
"bytes"
"encoding/json"
"fmt"
"os/exec"
@@ -15,6 +16,28 @@ import (
"golang.org/x/exp/slog"
)
const (
// Commands
nvidiaSmiCmd = "nvidia-smi"
rocmSmiCmd = "rocm-smi"
tegraStatsCmd = "tegrastats"
// Polling intervals
nvidiaSmiInterval = "4" // in seconds
tegraStatsInterval = "3700" // in milliseconds
rocmSmiInterval = 4300 * time.Millisecond
// Command retry and timeout constants
retryWaitTime = 5 * time.Second
maxFailureRetries = 5
cmdBufferSize = 10 * 1024
// Unit Conversions
mebibytesInAMegabyte = 1.024 // nvidia-smi reports memory in MiB
milliwattsInAWatt = 1000.0 // tegrastats reports power in mW
)
// GPUManager manages data collection for GPUs (either Nvidia or AMD)
type GPUManager struct {
sync.Mutex
@@ -56,7 +79,7 @@ func (c *gpuCollector) start() {
break
}
slog.Warn(c.name+" failed, restarting", "err", err)
time.Sleep(time.Second * 5)
time.Sleep(retryWaitTime)
continue
}
}
@@ -75,7 +98,7 @@ func (c *gpuCollector) collect() error {
scanner := bufio.NewScanner(stdout)
if c.buf == nil {
c.buf = make([]byte, 0, 4*1024)
c.buf = make([]byte, 0, cmdBufferSize)
}
scanner.Buffer(c.buf, bufio.MaxScanTokenSize)
@@ -102,36 +125,35 @@ func (gm *GPUManager) getJetsonParser() func(output []byte) bool {
// TODO: Maybe use VDD_IN for Nano / NX and add a total system power chart
powerPattern := regexp.MustCompile(`(GPU_SOC|CPU_GPU_CV) (\d+)mW`)
// jetson devices have only one gpu so we'll just initialize here
gpuData := &system.GPUData{Name: "GPU"}
gm.GpuDataMap["0"] = gpuData
return func(output []byte) bool {
gm.Lock()
defer gm.Unlock()
// we get gpu name from the intitial run of nvidia-smi, so return if it hasn't been initialized
gpuData, ok := gm.GpuDataMap["0"]
if !ok {
return true
}
data := string(output)
// Parse RAM usage
ramMatches := ramPattern.FindStringSubmatch(data)
ramMatches := ramPattern.FindSubmatch(output)
if ramMatches != nil {
gpuData.MemoryUsed, _ = strconv.ParseFloat(ramMatches[1], 64)
gpuData.MemoryTotal, _ = strconv.ParseFloat(ramMatches[2], 64)
gpuData.MemoryUsed, _ = strconv.ParseFloat(string(ramMatches[1]), 64)
gpuData.MemoryTotal, _ = strconv.ParseFloat(string(ramMatches[2]), 64)
}
// Parse GR3D (GPU) usage
gr3dMatches := gr3dPattern.FindStringSubmatch(data)
gr3dMatches := gr3dPattern.FindSubmatch(output)
if gr3dMatches != nil {
gpuData.Usage, _ = strconv.ParseFloat(gr3dMatches[1], 64)
gr3dUsage, _ := strconv.ParseFloat(string(gr3dMatches[1]), 64)
gpuData.Usage += gr3dUsage
}
// Parse temperature
tempMatches := tempPattern.FindStringSubmatch(data)
tempMatches := tempPattern.FindSubmatch(output)
if tempMatches != nil {
gpuData.Temperature, _ = strconv.ParseFloat(tempMatches[1], 64)
gpuData.Temperature, _ = strconv.ParseFloat(string(tempMatches[1]), 64)
}
// Parse power usage
powerMatches := powerPattern.FindStringSubmatch(data)
powerMatches := powerPattern.FindSubmatch(output)
if powerMatches != nil {
power, _ := strconv.ParseFloat(powerMatches[2], 64)
gpuData.Power = power / 1000
power, _ := strconv.ParseFloat(string(powerMatches[2]), 64)
gpuData.Power += power / milliwattsInAWatt
}
gpuData.Count++
return true
@@ -142,8 +164,10 @@ func (gm *GPUManager) getJetsonParser() func(output []byte) bool {
func (gm *GPUManager) parseNvidiaData(output []byte) bool {
gm.Lock()
defer gm.Unlock()
scanner := bufio.NewScanner(bytes.NewReader(output))
var valid bool
for line := range strings.Lines(string(output)) {
for scanner.Scan() {
line := scanner.Text() // Or use scanner.Bytes() for []byte
fields := strings.Split(strings.TrimSpace(line), ", ")
if len(fields) < 7 {
continue
@@ -159,18 +183,12 @@ func (gm *GPUManager) parseNvidiaData(output []byte) bool {
if _, ok := gm.GpuDataMap[id]; !ok {
name := strings.TrimPrefix(fields[1], "NVIDIA ")
gm.GpuDataMap[id] = &system.GPUData{Name: strings.TrimSuffix(name, " Laptop GPU")}
// check if tegrastats is active - if so we will only use nvidia-smi to get gpu name
// - nvidia-smi does not provide metrics for tegra / jetson devices
// this will end the nvidia-smi collector
if gm.tegrastats {
return false
}
}
// update gpu data
gpu := gm.GpuDataMap[id]
gpu.Temperature = temp
gpu.MemoryUsed = memoryUsage / 1.024
gpu.MemoryTotal = totalMemory / 1.024
gpu.MemoryUsed = memoryUsage / mebibytesInAMegabyte
gpu.MemoryTotal = totalMemory / mebibytesInAMegabyte
gpu.Usage += usage
gpu.Power += power
gpu.Count++
@@ -241,6 +259,7 @@ func (gm *GPUManager) GetCurrentData() map[string]system.GPUData {
}
gpuData[id] = gpuCopy
}
slog.Debug("GPU", "data", gpuData)
return gpuData
}
@@ -249,14 +268,15 @@ func (gm *GPUManager) GetCurrentData() map[string]system.GPUData {
// tools are found. If none of the tools are found, it returns an error indicating that no GPU
// management tools are available.
func (gm *GPUManager) detectGPUs() error {
if _, err := exec.LookPath("nvidia-smi"); err == nil {
if _, err := exec.LookPath(nvidiaSmiCmd); err == nil {
gm.nvidiaSmi = true
}
if _, err := exec.LookPath("rocm-smi"); err == nil {
if _, err := exec.LookPath(rocmSmiCmd); err == nil {
gm.rocmSmi = true
}
if _, err := exec.LookPath("tegrastats"); err == nil {
if _, err := exec.LookPath(tegraStatsCmd); err == nil {
gm.tegrastats = true
gm.nvidiaSmi = false
}
if gm.nvidiaSmi || gm.rocmSmi || gm.tegrastats {
return nil
@@ -270,17 +290,19 @@ func (gm *GPUManager) startCollector(command string) {
name: command,
}
switch command {
case "nvidia-smi":
collector.cmdArgs = []string{"-l", "4",
case nvidiaSmiCmd:
collector.cmdArgs = []string{
"-l", nvidiaSmiInterval,
"--query-gpu=index,name,temperature.gpu,memory.used,memory.total,utilization.gpu,power.draw",
"--format=csv,noheader,nounits"}
"--format=csv,noheader,nounits",
}
collector.parse = gm.parseNvidiaData
go collector.start()
case "tegrastats":
collector.cmdArgs = []string{"--interval", "3000"}
case tegraStatsCmd:
collector.cmdArgs = []string{"--interval", tegraStatsInterval}
collector.parse = gm.getJetsonParser()
go collector.start()
case "rocm-smi":
case rocmSmiCmd:
collector.cmdArgs = []string{"--showid", "--showtemp", "--showuse", "--showpower", "--showproductname", "--showmeminfo", "vram", "--json"}
collector.parse = gm.parseAmdData
go func() {
@@ -288,12 +310,12 @@ func (gm *GPUManager) startCollector(command string) {
for {
if err := collector.collect(); err != nil {
failures++
if failures > 5 {
if failures > maxFailureRetries {
break
}
slog.Warn("Error collecting AMD GPU data", "err", err)
}
time.Sleep(4300 * time.Millisecond)
time.Sleep(rocmSmiInterval)
}
}()
}
@@ -308,13 +330,13 @@ func NewGPUManager() (*GPUManager, error) {
gm.GpuDataMap = make(map[string]*system.GPUData)
if gm.nvidiaSmi {
gm.startCollector("nvidia-smi")
gm.startCollector(nvidiaSmiCmd)
}
if gm.rocmSmi {
gm.startCollector("rocm-smi")
gm.startCollector(rocmSmiCmd)
}
if gm.tegrastats {
gm.startCollector("tegrastats")
gm.startCollector(tegraStatsCmd)
}
return &gm, nil

View File

@@ -1,3 +1,6 @@
//go:build testing
// +build testing
package agent
import (
@@ -43,6 +46,52 @@ func TestParseNvidiaData(t *testing.T) {
},
wantValid: true,
},
{
name: "more valid multi-gpu data",
input: `0, NVIDIA A10, 45, 19676, 23028, 0, 58.98
1, NVIDIA A10, 45, 19638, 23028, 0, 62.35
2, NVIDIA A10, 44, 21700, 23028, 0, 59.57
3, NVIDIA A10, 45, 18222, 23028, 0, 61.76`,
wantData: map[string]system.GPUData{
"0": {
Name: "A10",
Temperature: 45.0,
MemoryUsed: 19676.0 / 1.024,
MemoryTotal: 23028.0 / 1.024,
Usage: 0.0,
Power: 58.98,
Count: 1,
},
"1": {
Name: "A10",
Temperature: 45.0,
MemoryUsed: 19638.0 / 1.024,
MemoryTotal: 23028.0 / 1.024,
Usage: 0.0,
Power: 62.35,
Count: 1,
},
"2": {
Name: "A10",
Temperature: 44.0,
MemoryUsed: 21700.0 / 1.024,
MemoryTotal: 23028.0 / 1.024,
Usage: 0.0,
Power: 59.57,
Count: 1,
},
"3": {
Name: "A10",
Temperature: 45.0,
MemoryUsed: 18222.0 / 1.024,
MemoryTotal: 23028.0 / 1.024,
Usage: 0.0,
Power: 61.76,
Count: 1,
},
},
wantValid: true,
},
{
name: "empty input",
input: "",
@@ -202,14 +251,13 @@ func TestParseJetsonData(t *testing.T) {
tests := []struct {
name string
input string
gm *GPUManager
wantMetrics *system.GPUData
}{
{
name: "valid data",
input: "RAM 4300/30698MB GR3D_FREQ 45% tj@52.468C VDD_GPU_SOC 2171mW",
input: "11-14-2024 22:54:33 RAM 4300/30698MB GR3D_FREQ 45% tj@52.468C VDD_GPU_SOC 2171mW",
wantMetrics: &system.GPUData{
Name: "Jetson",
Name: "GPU",
MemoryUsed: 4300.0,
MemoryTotal: 30698.0,
Usage: 45.0,
@@ -219,10 +267,23 @@ func TestParseJetsonData(t *testing.T) {
},
},
{
name: "missing temperature",
input: "RAM 4300/30698MB GR3D_FREQ 45% VDD_GPU_SOC 2171mW",
name: "more valid data",
input: "11-15-2024 08:38:09 RAM 6185/7620MB (lfb 8x2MB) SWAP 851/3810MB (cached 1MB) CPU [15%@729,11%@729,14%@729,13%@729,11%@729,8%@729] EMC_FREQ 43%@2133 GR3D_FREQ 63%@[621] NVDEC off NVJPG off NVJPG1 off VIC off OFA off APE 200 cpu@53.968C soc2@52.437C soc0@50.75C gpu@53.343C tj@53.968C soc1@51.656C VDD_IN 12479mW/12479mW VDD_CPU_GPU_CV 4667mW/4667mW VDD_SOC 2817mW/2817mW",
wantMetrics: &system.GPUData{
Name: "Jetson",
Name: "GPU",
MemoryUsed: 6185.0,
MemoryTotal: 7620.0,
Usage: 63.0,
Temperature: 53.968,
Power: 4.667,
Count: 1,
},
},
{
name: "missing temperature",
input: "11-14-2024 22:54:33 RAM 4300/30698MB GR3D_FREQ 45% VDD_GPU_SOC 2171mW",
wantMetrics: &system.GPUData{
Name: "GPU",
MemoryUsed: 4300.0,
MemoryTotal: 30698.0,
Usage: 45.0,
@@ -230,32 +291,18 @@ func TestParseJetsonData(t *testing.T) {
Count: 1,
},
},
{
name: "no gpu defined by nvidia-smi",
input: "RAM 4300/30698MB GR3D_FREQ 45% VDD_GPU_SOC 2171mW",
gm: &GPUManager{
GpuDataMap: map[string]*system.GPUData{},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.gm != nil {
// should return if no gpu set by nvidia-smi
assert.Empty(t, tt.gm.GpuDataMap)
return
gm := &GPUManager{
GpuDataMap: make(map[string]*system.GPUData),
}
tt.gm = &GPUManager{
GpuDataMap: map[string]*system.GPUData{
"0": {Name: "Jetson"},
},
}
parser := tt.gm.getJetsonParser()
parser := gm.getJetsonParser()
valid := parser([]byte(tt.input))
assert.Equal(t, true, valid)
got := tt.gm.GpuDataMap["0"]
got := gm.GpuDataMap["0"]
require.NotNil(t, got)
assert.Equal(t, tt.wantMetrics.Name, got.Name)
assert.InDelta(t, tt.wantMetrics.MemoryUsed, got.MemoryUsed, 0.01)
@@ -381,7 +428,7 @@ echo "test"`
}
return nil
},
wantNvidiaSmi: true,
wantNvidiaSmi: false,
wantRocmSmi: true,
wantTegrastats: true,
wantErr: false,
@@ -486,7 +533,7 @@ echo '{"card0": {"Temperature (Sensor edge) (C)": "49.0", "Current Socket Graphi
setup: func(t *testing.T) error {
path := filepath.Join(dir, "tegrastats")
script := `#!/bin/sh
echo "RAM 1024/4096MB GR3D_FREQ 80% tj@70C VDD_GPU_SOC 1000mW"`
echo "11-14-2024 22:54:33 RAM 1024/4096MB GR3D_FREQ 80% tj@70C VDD_GPU_SOC 1000mW"`
if err := os.WriteFile(path, []byte(script), 0755); err != nil {
return err
}
@@ -523,3 +570,158 @@ echo "RAM 1024/4096MB GR3D_FREQ 80% tj@70C VDD_GPU_SOC 1000mW"`
})
}
}
// TestAccumulationTableDriven tests the accumulation behavior for all three GPU types
func TestAccumulation(t *testing.T) {
type expectedGPUValues struct {
temperature float64
memoryUsed float64
memoryTotal float64
usage float64
power float64
count float64
avgUsage float64
avgPower float64
}
tests := []struct {
name string
initialGPUData map[string]*system.GPUData
dataSamples [][]byte
parser func(*GPUManager) func([]byte) bool
expectedValues map[string]expectedGPUValues
}{
{
name: "Jetson GPU accumulation",
initialGPUData: map[string]*system.GPUData{
"0": {
Name: "Jetson",
Temperature: 0,
Usage: 0,
Power: 0,
Count: 0,
},
},
dataSamples: [][]byte{
[]byte("11-14-2024 22:54:33 RAM 1024/4096MB GR3D_FREQ 30% tj@50.5C VDD_GPU_SOC 1000mW"),
[]byte("11-14-2024 22:54:33 RAM 1024/4096MB GR3D_FREQ 40% tj@60.5C VDD_GPU_SOC 1200mW"),
[]byte("11-14-2024 22:54:33 RAM 1024/4096MB GR3D_FREQ 50% tj@70.5C VDD_GPU_SOC 1400mW"),
},
parser: func(gm *GPUManager) func([]byte) bool {
return gm.getJetsonParser()
},
expectedValues: map[string]expectedGPUValues{
"0": {
temperature: 70.5, // Last value
memoryUsed: 1024, // Last value
memoryTotal: 4096, // Last value
usage: 120.0, // Accumulated: 30 + 40 + 50
power: 3.6, // Accumulated: 1.0 + 1.2 + 1.4
count: 3,
avgUsage: 40.0, // 120 / 3
avgPower: 1.2, // 3.6 / 3
},
},
},
{
name: "NVIDIA GPU accumulation",
initialGPUData: map[string]*system.GPUData{
// NVIDIA parser will create the GPU data entries
},
dataSamples: [][]byte{
[]byte("0, NVIDIA GeForce RTX 3080, 50, 5000, 10000, 30, 200"),
[]byte("0, NVIDIA GeForce RTX 3080, 60, 6000, 10000, 40, 250"),
[]byte("0, NVIDIA GeForce RTX 3080, 70, 7000, 10000, 50, 300"),
},
parser: func(gm *GPUManager) func([]byte) bool {
return gm.parseNvidiaData
},
expectedValues: map[string]expectedGPUValues{
"0": {
temperature: 70.0, // Last value
memoryUsed: 7000.0 / 1.024, // Last value
memoryTotal: 10000.0 / 1.024, // Last value
usage: 120.0, // Accumulated: 30 + 40 + 50
power: 750.0, // Accumulated: 200 + 250 + 300
count: 3,
avgUsage: 40.0, // 120 / 3
avgPower: 250.0, // 750 / 3
},
},
},
{
name: "AMD GPU accumulation",
initialGPUData: map[string]*system.GPUData{
// AMD parser will create the GPU data entries
},
dataSamples: [][]byte{
[]byte(`{"card0": {"GUID": "34756", "Temperature (Sensor edge) (C)": "50.0", "Current Socket Graphics Package Power (W)": "100.0", "GPU use (%)": "30", "VRAM Total Memory (B)": "10737418240", "VRAM Total Used Memory (B)": "1073741824", "Card Series": "Radeon RX 6800"}}`),
[]byte(`{"card0": {"GUID": "34756", "Temperature (Sensor edge) (C)": "60.0", "Current Socket Graphics Package Power (W)": "150.0", "GPU use (%)": "40", "VRAM Total Memory (B)": "10737418240", "VRAM Total Used Memory (B)": "2147483648", "Card Series": "Radeon RX 6800"}}`),
[]byte(`{"card0": {"GUID": "34756", "Temperature (Sensor edge) (C)": "70.0", "Current Socket Graphics Package Power (W)": "200.0", "GPU use (%)": "50", "VRAM Total Memory (B)": "10737418240", "VRAM Total Used Memory (B)": "3221225472", "Card Series": "Radeon RX 6800"}}`),
},
parser: func(gm *GPUManager) func([]byte) bool {
return gm.parseAmdData
},
expectedValues: map[string]expectedGPUValues{
"34756": {
temperature: 70.0, // Last value
memoryUsed: 3221225472.0 / (1024 * 1024), // Last value
memoryTotal: 10737418240.0 / (1024 * 1024), // Last value
usage: 120.0, // Accumulated: 30 + 40 + 50
power: 450.0, // Accumulated: 100 + 150 + 200
count: 3,
avgUsage: 40.0, // 120 / 3
avgPower: 150.0, // 450 / 3
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a new GPUManager for each test
gm := &GPUManager{
GpuDataMap: tt.initialGPUData,
}
// Get the parser function
parser := tt.parser(gm)
// Process each data sample
for i, sample := range tt.dataSamples {
valid := parser(sample)
assert.True(t, valid, "Sample %d should be valid", i)
}
// Check accumulated values
for id, expected := range tt.expectedValues {
gpu, exists := gm.GpuDataMap[id]
assert.True(t, exists, "GPU with ID %s should exist", id)
if !exists {
continue
}
assert.InDelta(t, expected.temperature, gpu.Temperature, 0.01, "Temperature should match")
assert.InDelta(t, expected.memoryUsed, gpu.MemoryUsed, 0.01, "Memory used should match")
assert.InDelta(t, expected.memoryTotal, gpu.MemoryTotal, 0.01, "Memory total should match")
assert.InDelta(t, expected.usage, gpu.Usage, 0.01, "Usage should match")
assert.InDelta(t, expected.power, gpu.Power, 0.01, "Power should match")
assert.Equal(t, expected.count, gpu.Count, "Count should match")
}
// Verify average calculation in GetCurrentData
result := gm.GetCurrentData()
for id, expected := range tt.expectedValues {
gpu, exists := result[id]
assert.True(t, exists, "GPU with ID %s should exist in GetCurrentData result", id)
if !exists {
continue
}
assert.InDelta(t, expected.temperature, gpu.Temperature, 0.01, "Temperature in GetCurrentData should match")
assert.InDelta(t, expected.avgUsage, gpu.Usage, 0.01, "Average usage in GetCurrentData should match")
assert.InDelta(t, expected.avgPower, gpu.Power, 0.01, "Average power in GetCurrentData should match")
}
})
}
}

View File

@@ -0,0 +1,18 @@
package agent
import (
"net"
"time"
)
// Health checks if the agent's server is running by attempting to connect to it.
//
// If an error occurs when attempting to connect to the server, it returns the error.
func Health(addr string, network string) error {
conn, err := net.DialTimeout(network, addr, 4*time.Second)
if err != nil {
return err
}
conn.Close()
return nil
}

View File

@@ -0,0 +1,118 @@
//go:build testing
// +build testing
package agent_test
import (
"fmt"
"net"
"os"
"testing"
"github.com/stretchr/testify/require"
"beszel/internal/agent"
)
// setupTestServer creates a temporary server for testing
func setupTestServer(t *testing.T) (string, func()) {
// Create a temporary socket file for Unix socket testing
tempSockFile := os.TempDir() + "/beszel_health_test.sock"
// Clean up any existing socket file
os.Remove(tempSockFile)
// Create a listener
listener, err := net.Listen("unix", tempSockFile)
require.NoError(t, err, "Failed to create test listener")
// Start a simple server in a goroutine
go func() {
conn, err := listener.Accept()
if err != nil {
return // Listener closed
}
defer conn.Close()
// Just accept the connection and do nothing
}()
// Return the socket file path and a cleanup function
return tempSockFile, func() {
listener.Close()
os.Remove(tempSockFile)
}
}
// setupTCPTestServer creates a temporary TCP server for testing
func setupTCPTestServer(t *testing.T) (string, func()) {
// Listen on a random available port
listener, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err, "Failed to create test listener")
// Get the port that was assigned
addr := listener.Addr().(*net.TCPAddr)
port := addr.Port
// Start a simple server in a goroutine
go func() {
conn, err := listener.Accept()
if err != nil {
return // Listener closed
}
defer conn.Close()
// Just accept the connection and do nothing
}()
// Return the address and a cleanup function
return fmt.Sprintf("127.0.0.1:%d", port), func() {
listener.Close()
}
}
func TestHealth(t *testing.T) {
t.Run("server is running (unix socket)", func(t *testing.T) {
// Setup a test server
sockFile, cleanup := setupTestServer(t)
defer cleanup()
// Run the health check with explicit parameters
err := agent.Health(sockFile, "unix")
require.NoError(t, err, "Failed to check health")
})
t.Run("server is running (tcp address)", func(t *testing.T) {
// Setup a test server
addr, cleanup := setupTCPTestServer(t)
defer cleanup()
// Run the health check with explicit parameters
err := agent.Health(addr, "tcp")
require.NoError(t, err, "Failed to check health")
})
t.Run("server is not running", func(t *testing.T) {
// Use an address that's likely not in use
addr := "127.0.0.1:65535"
// Run the health check with explicit parameters
err := agent.Health(addr, "tcp")
require.Error(t, err, "Health check should return an error when server is not running")
})
t.Run("invalid network", func(t *testing.T) {
// Use an invalid network type
err := agent.Health("127.0.0.1:8080", "invalid_network")
require.Error(t, err, "Health check should return an error with invalid network")
})
t.Run("unix socket not found", func(t *testing.T) {
// Use a non-existent unix socket
nonExistentSocket := os.TempDir() + "/non_existent_socket.sock"
// Make sure it really doesn't exist
os.Remove(nonExistentSocket)
err := agent.Health(nonExistentSocket, "unix")
require.Error(t, err, "Health check should return an error when socket doesn't exist")
})
}

View File

@@ -17,7 +17,7 @@ func (a *Agent) initializeNetIoStats() {
nics, nicsEnvExists := GetEnv("NICS")
if nicsEnvExists {
nicsMap = make(map[string]struct{}, 0)
for _, nic := range strings.Split(nics, ",") {
for nic := range strings.SplitSeq(nics, ",") {
nicsMap[nic] = struct{}{}
}
}

View File

@@ -0,0 +1,143 @@
package agent
import (
"beszel/internal/entities/system"
"context"
"log/slog"
"path"
"strconv"
"strings"
"github.com/shirou/gopsutil/v4/common"
"github.com/shirou/gopsutil/v4/sensors"
)
type SensorConfig struct {
context context.Context
sensors map[string]struct{}
primarySensor string
isBlacklist bool
hasWildcards bool
skipCollection bool
}
func (a *Agent) newSensorConfig() *SensorConfig {
primarySensor, _ := GetEnv("PRIMARY_SENSOR")
sysSensors, _ := GetEnv("SYS_SENSORS")
sensorsEnvVal, sensorsSet := GetEnv("SENSORS")
skipCollection := sensorsSet && sensorsEnvVal == ""
return a.newSensorConfigWithEnv(primarySensor, sysSensors, sensorsEnvVal, skipCollection)
}
// newSensorConfigWithEnv creates a SensorConfig with the provided environment variables
// sensorsSet indicates if the SENSORS environment variable was explicitly set (even to empty string)
func (a *Agent) newSensorConfigWithEnv(primarySensor, sysSensors, sensorsEnvVal string, skipCollection bool) *SensorConfig {
config := &SensorConfig{
context: context.Background(),
primarySensor: primarySensor,
skipCollection: skipCollection,
sensors: make(map[string]struct{}),
}
// Set sensors context (allows overriding sys location for sensors)
if sysSensors != "" {
slog.Info("SYS_SENSORS", "path", sysSensors)
config.context = context.WithValue(config.context,
common.EnvKey, common.EnvMap{common.HostSysEnvKey: sysSensors},
)
}
// handle blacklist
if strings.HasPrefix(sensorsEnvVal, "-") {
config.isBlacklist = true
sensorsEnvVal = sensorsEnvVal[1:]
}
for sensor := range strings.SplitSeq(sensorsEnvVal, ",") {
sensor = strings.TrimSpace(sensor)
if sensor != "" {
config.sensors[sensor] = struct{}{}
if strings.Contains(sensor, "*") {
config.hasWildcards = true
}
}
}
return config
}
// updateTemperatures updates the agent with the latest sensor temperatures
func (a *Agent) updateTemperatures(systemStats *system.Stats) {
// skip if sensors whitelist is set to empty string
if a.sensorConfig.skipCollection {
slog.Debug("Skipping temperature collection")
return
}
// reset high temp
a.systemInfo.DashboardTemp = 0
// get sensor data
temps, _ := sensors.TemperaturesWithContext(a.sensorConfig.context)
slog.Debug("Temperature", "sensors", temps)
// return if no sensors
if len(temps) == 0 {
return
}
systemStats.Temperatures = make(map[string]float64, len(temps))
for i, sensor := range temps {
// skip if temperature is unreasonable
if sensor.Temperature <= 0 || sensor.Temperature >= 200 {
continue
}
sensorName := sensor.SensorKey
if _, ok := systemStats.Temperatures[sensorName]; ok {
// if key already exists, append int to key
sensorName = sensorName + "_" + strconv.Itoa(i)
}
// skip if not in whitelist or blacklist
if !isValidSensor(sensorName, a.sensorConfig) {
continue
}
// set dashboard temperature
if a.sensorConfig.primarySensor == "" {
a.systemInfo.DashboardTemp = max(a.systemInfo.DashboardTemp, sensor.Temperature)
} else if a.sensorConfig.primarySensor == sensorName {
a.systemInfo.DashboardTemp = sensor.Temperature
}
systemStats.Temperatures[sensorName] = twoDecimals(sensor.Temperature)
}
}
// isValidSensor checks if a sensor is valid based on the sensor name and the sensor config
func isValidSensor(sensorName string, config *SensorConfig) bool {
// if no sensors configured, everything is valid
if len(config.sensors) == 0 {
return true
}
// Exact match - return true if whitelist, false if blacklist
if _, exactMatch := config.sensors[sensorName]; exactMatch {
return !config.isBlacklist
}
// If no wildcards, return true if blacklist, false if whitelist
if !config.hasWildcards {
return config.isBlacklist
}
// Check for wildcard patterns
for pattern := range config.sensors {
if !strings.Contains(pattern, "*") {
continue
}
if match, _ := path.Match(pattern, sensorName); match {
return !config.isBlacklist
}
}
return config.isBlacklist
}

View File

@@ -0,0 +1,374 @@
//go:build testing
// +build testing
package agent
import (
"context"
"os"
"testing"
"github.com/shirou/gopsutil/v4/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestIsValidSensor(t *testing.T) {
tests := []struct {
name string
sensorName string
config *SensorConfig
expectedValid bool
}{
{
name: "Whitelist - sensor in list",
sensorName: "cpu_temp",
config: &SensorConfig{
sensors: map[string]struct{}{"cpu_temp": {}},
isBlacklist: false,
},
expectedValid: true,
},
{
name: "Whitelist - sensor not in list",
sensorName: "gpu_temp",
config: &SensorConfig{
sensors: map[string]struct{}{"cpu_temp": {}},
isBlacklist: false,
},
expectedValid: false,
},
{
name: "Blacklist - sensor in list",
sensorName: "cpu_temp",
config: &SensorConfig{
sensors: map[string]struct{}{"cpu_temp": {}},
isBlacklist: true,
},
expectedValid: false,
},
{
name: "Blacklist - sensor not in list",
sensorName: "gpu_temp",
config: &SensorConfig{
sensors: map[string]struct{}{"cpu_temp": {}},
isBlacklist: true,
},
expectedValid: true,
},
{
name: "Whitelist with wildcard - matching pattern",
sensorName: "core_0_temp",
config: &SensorConfig{
sensors: map[string]struct{}{"core_*_temp": {}},
isBlacklist: false,
hasWildcards: true,
},
expectedValid: true,
},
{
name: "Whitelist with wildcard - non-matching pattern",
sensorName: "gpu_temp",
config: &SensorConfig{
sensors: map[string]struct{}{"core_*_temp": {}},
isBlacklist: false,
hasWildcards: true,
},
expectedValid: false,
},
{
name: "Blacklist with wildcard - matching pattern",
sensorName: "core_0_temp",
config: &SensorConfig{
sensors: map[string]struct{}{"core_*_temp": {}},
isBlacklist: true,
hasWildcards: true,
},
expectedValid: false,
},
{
name: "Blacklist with wildcard - non-matching pattern",
sensorName: "gpu_temp",
config: &SensorConfig{
sensors: map[string]struct{}{"core_*_temp": {}},
isBlacklist: true,
hasWildcards: true,
},
expectedValid: true,
},
{
name: "No sensors configured",
sensorName: "any_temp",
config: &SensorConfig{
sensors: map[string]struct{}{},
isBlacklist: false,
hasWildcards: false,
skipCollection: false,
},
expectedValid: true,
},
{
name: "Mixed patterns in whitelist - exact match",
sensorName: "cpu_temp",
config: &SensorConfig{
sensors: map[string]struct{}{"cpu_temp": {}, "core_*_temp": {}},
isBlacklist: false,
hasWildcards: true,
},
expectedValid: true,
},
{
name: "Mixed patterns in whitelist - wildcard match",
sensorName: "core_1_temp",
config: &SensorConfig{
sensors: map[string]struct{}{"cpu_temp": {}, "core_*_temp": {}},
isBlacklist: false,
hasWildcards: true,
},
expectedValid: true,
},
{
name: "Mixed patterns in blacklist - exact match",
sensorName: "cpu_temp",
config: &SensorConfig{
sensors: map[string]struct{}{"cpu_temp": {}, "core_*_temp": {}},
isBlacklist: true,
hasWildcards: true,
},
expectedValid: false,
},
{
name: "Mixed patterns in blacklist - wildcard match",
sensorName: "core_1_temp",
config: &SensorConfig{
sensors: map[string]struct{}{"cpu_temp": {}, "core_*_temp": {}},
isBlacklist: true,
hasWildcards: true,
},
expectedValid: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := isValidSensor(tt.sensorName, tt.config)
assert.Equal(t, tt.expectedValid, result, "isValidSensor(%q, config) returned unexpected result", tt.sensorName)
})
}
}
func TestNewSensorConfigWithEnv(t *testing.T) {
agent := &Agent{}
tests := []struct {
name string
primarySensor string
sysSensors string
sensors string
skipCollection bool
expectedConfig *SensorConfig
}{
{
name: "Empty configuration",
primarySensor: "",
sysSensors: "",
sensors: "",
expectedConfig: &SensorConfig{
context: context.Background(),
primarySensor: "",
sensors: map[string]struct{}{},
isBlacklist: false,
hasWildcards: false,
skipCollection: false,
},
},
{
name: "Explicitly set to empty string",
primarySensor: "",
sysSensors: "",
sensors: "",
skipCollection: true,
expectedConfig: &SensorConfig{
context: context.Background(),
primarySensor: "",
sensors: map[string]struct{}{},
isBlacklist: false,
hasWildcards: false,
skipCollection: true,
},
},
{
name: "Primary sensor only - should create sensor map",
primarySensor: "cpu_temp",
sysSensors: "",
sensors: "",
expectedConfig: &SensorConfig{
context: context.Background(),
primarySensor: "cpu_temp",
sensors: map[string]struct{}{},
isBlacklist: false,
hasWildcards: false,
},
},
{
name: "Whitelist sensors",
primarySensor: "cpu_temp",
sysSensors: "",
sensors: "cpu_temp,gpu_temp",
expectedConfig: &SensorConfig{
context: context.Background(),
primarySensor: "cpu_temp",
sensors: map[string]struct{}{
"cpu_temp": {},
"gpu_temp": {},
},
isBlacklist: false,
hasWildcards: false,
},
},
{
name: "Blacklist sensors",
primarySensor: "cpu_temp",
sysSensors: "",
sensors: "-cpu_temp,gpu_temp",
expectedConfig: &SensorConfig{
context: context.Background(),
primarySensor: "cpu_temp",
sensors: map[string]struct{}{
"cpu_temp": {},
"gpu_temp": {},
},
isBlacklist: true,
hasWildcards: false,
},
},
{
name: "Sensors with wildcard",
primarySensor: "cpu_temp",
sysSensors: "",
sensors: "cpu_*,gpu_temp",
expectedConfig: &SensorConfig{
context: context.Background(),
primarySensor: "cpu_temp",
sensors: map[string]struct{}{
"cpu_*": {},
"gpu_temp": {},
},
isBlacklist: false,
hasWildcards: true,
},
},
{
name: "Sensors with whitespace",
primarySensor: "cpu_temp",
sysSensors: "",
sensors: "cpu_*, gpu_temp",
expectedConfig: &SensorConfig{
context: context.Background(),
primarySensor: "cpu_temp",
sensors: map[string]struct{}{
"cpu_*": {},
"gpu_temp": {},
},
isBlacklist: false,
hasWildcards: true,
},
},
{
name: "With SYS_SENSORS path",
primarySensor: "cpu_temp",
sysSensors: "/custom/path",
sensors: "cpu_temp",
expectedConfig: &SensorConfig{
primarySensor: "cpu_temp",
sensors: map[string]struct{}{
"cpu_temp": {},
},
isBlacklist: false,
hasWildcards: false,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := agent.newSensorConfigWithEnv(tt.primarySensor, tt.sysSensors, tt.sensors, tt.skipCollection)
// Check primary sensor
assert.Equal(t, tt.expectedConfig.primarySensor, result.primarySensor)
// Check sensor map
if tt.expectedConfig.sensors == nil {
assert.Nil(t, result.sensors)
} else {
assert.Equal(t, len(tt.expectedConfig.sensors), len(result.sensors))
for sensor := range tt.expectedConfig.sensors {
_, exists := result.sensors[sensor]
assert.True(t, exists, "Sensor %s should exist in the result", sensor)
}
}
// Check flags
assert.Equal(t, tt.expectedConfig.isBlacklist, result.isBlacklist)
assert.Equal(t, tt.expectedConfig.hasWildcards, result.hasWildcards)
// Check context
if tt.sysSensors != "" {
// Verify context contains correct values
envMap, ok := result.context.Value(common.EnvKey).(common.EnvMap)
require.True(t, ok, "Context should contain EnvMap")
sysPath, ok := envMap[common.HostSysEnvKey]
require.True(t, ok, "EnvMap should contain HostSysEnvKey")
assert.Equal(t, tt.sysSensors, sysPath)
}
})
}
}
func TestNewSensorConfig(t *testing.T) {
// Save original environment variables
originalPrimary, hasPrimary := os.LookupEnv("BESZEL_AGENT_PRIMARY_SENSOR")
originalSys, hasSys := os.LookupEnv("BESZEL_AGENT_SYS_SENSORS")
originalSensors, hasSensors := os.LookupEnv("BESZEL_AGENT_SENSORS")
// Restore environment variables after the test
defer func() {
// Clean up test environment variables
os.Unsetenv("BESZEL_AGENT_PRIMARY_SENSOR")
os.Unsetenv("BESZEL_AGENT_SYS_SENSORS")
os.Unsetenv("BESZEL_AGENT_SENSORS")
// Restore original values if they existed
if hasPrimary {
os.Setenv("BESZEL_AGENT_PRIMARY_SENSOR", originalPrimary)
}
if hasSys {
os.Setenv("BESZEL_AGENT_SYS_SENSORS", originalSys)
}
if hasSensors {
os.Setenv("BESZEL_AGENT_SENSORS", originalSensors)
}
}()
// Set test environment variables
os.Setenv("BESZEL_AGENT_PRIMARY_SENSOR", "test_primary")
os.Setenv("BESZEL_AGENT_SYS_SENSORS", "/test/path")
os.Setenv("BESZEL_AGENT_SENSORS", "test_sensor1,test_*,test_sensor3")
agent := &Agent{}
result := agent.newSensorConfig()
// Verify results
assert.Equal(t, "test_primary", result.primarySensor)
assert.NotNil(t, result.sensors)
assert.Equal(t, 3, len(result.sensors))
assert.True(t, result.hasWildcards)
assert.False(t, result.isBlacklist)
// Check that sys sensors path is in context
envMap, ok := result.context.Value(common.EnvKey).(common.EnvMap)
require.True(t, ok, "Context should contain EnvMap")
sysPath, ok := envMap[common.HostSysEnvKey]
require.True(t, ok, "EnvMap should contain HostSysEnvKey")
assert.Equal(t, "/test/path", sysPath)
}

View File

@@ -23,20 +23,14 @@ func (a *Agent) StartServer(opts ServerOptions) error {
slog.Info("Starting SSH server", "addr", opts.Addr, "network", opts.Network)
switch opts.Network {
case "unix":
if opts.Network == "unix" {
// remove existing socket file if it exists
if err := os.Remove(opts.Addr); err != nil && !os.IsNotExist(err) {
return err
}
default:
// prefix with : if only port was provided
if !strings.Contains(opts.Addr, ":") {
opts.Addr = ":" + opts.Addr
}
}
// Listen on the address
// start listening on the address
ln, err := net.Listen(opts.Network, opts.Addr)
if err != nil {
return err
@@ -44,7 +38,7 @@ func (a *Agent) StartServer(opts ServerOptions) error {
defer ln.Close()
// Start SSH server on the listener
err = sshServer.Serve(ln, nil, sshServer.NoPty(),
return sshServer.Serve(ln, nil, sshServer.NoPty(),
sshServer.PublicKeyAuth(func(ctx sshServer.Context, key sshServer.PublicKey) bool {
for _, pubKey := range opts.Keys {
if sshServer.KeysEqual(key, pubKey) {
@@ -54,15 +48,11 @@ func (a *Agent) StartServer(opts ServerOptions) error {
return false
}),
)
if err != nil {
return err
}
return nil
}
func (a *Agent) handleSession(s sshServer.Session) {
// slog.Debug("connection", "remoteaddr", s.RemoteAddr(), "user", s.User())
stats := a.gatherStats()
slog.Debug("New session", "client", s.RemoteAddr())
stats := a.gatherStats(s.Context().SessionID())
if err := json.NewEncoder(s).Encode(stats); err != nil {
slog.Error("Error encoding stats", "err", err, "stats", stats)
s.Exit(1)
@@ -74,24 +64,48 @@ func (a *Agent) handleSession(s sshServer.Session) {
// It returns a slice of ssh.PublicKey and an error if any key fails to parse.
func ParseKeys(input string) ([]ssh.PublicKey, error) {
var parsedKeys []ssh.PublicKey
for line := range strings.Lines(input) {
line = strings.TrimSpace(line)
// Skip empty lines or comments
if len(line) == 0 || strings.HasPrefix(line, "#") {
continue
}
// Parse the key
parsedKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(line))
if err != nil {
return nil, fmt.Errorf("failed to parse key: %s, error: %w", line, err)
}
// Append the parsed key to the list
parsedKeys = append(parsedKeys, parsedKey)
}
return parsedKeys, nil
}
// GetAddress gets the address to listen on or connect to from environment variables or default value.
func GetAddress(addr string) string {
if addr == "" {
addr, _ = GetEnv("LISTEN")
}
if addr == "" {
// Legacy PORT environment variable support
addr, _ = GetEnv("PORT")
}
if addr == "" {
return ":45876"
}
// prefix with : if only port was provided
if GetNetwork(addr) != "unix" && !strings.Contains(addr, ":") {
addr = ":" + addr
}
return addr
}
// GetNetwork returns the network type to use based on the address
func GetNetwork(addr string) string {
if network, ok := GetEnv("NETWORK"); ok && network != "" {
return network
}
if strings.HasPrefix(addr, "/") {
return "unix"
}
return "tcp"
}

View File

@@ -45,7 +45,7 @@ func TestStartServer(t *testing.T) {
name: "tcp port only",
config: ServerOptions{
Network: "tcp",
Addr: "45987",
Addr: ":45987",
Keys: []ssh.PublicKey{sshPubKey},
},
},
@@ -88,7 +88,7 @@ func TestStartServer(t *testing.T) {
name: "bad key should fail",
config: ServerOptions{
Network: "tcp",
Addr: "45987",
Addr: ":45987",
Keys: []ssh.PublicKey{sshBadPubKey},
},
wantErr: true,
@@ -98,7 +98,7 @@ func TestStartServer(t *testing.T) {
name: "good key still good",
config: ServerOptions{
Network: "tcp",
Addr: "45987",
Addr: ":45987",
Keys: []ssh.PublicKey{sshPubKey},
},
},

View File

@@ -16,14 +16,28 @@ import (
"github.com/shirou/gopsutil/v4/host"
"github.com/shirou/gopsutil/v4/mem"
psutilNet "github.com/shirou/gopsutil/v4/net"
"github.com/shirou/gopsutil/v4/sensors"
)
// Sets initial / non-changing values about the host system
func (a *Agent) initializeSystemInfo() {
a.systemInfo.AgentVersion = beszel.Version
a.systemInfo.Hostname, _ = os.Hostname()
a.systemInfo.KernelVersion, _ = host.KernelVersion()
platform, _, version, _ := host.PlatformInformation()
if platform == "darwin" {
a.systemInfo.KernelVersion = version
a.systemInfo.Os = system.Darwin
} else if strings.Contains(platform, "indows") {
a.systemInfo.KernelVersion = strings.Replace(platform, "Microsoft ", "", 1) + " " + version
a.systemInfo.Os = system.Windows
} else {
a.systemInfo.Os = system.Linux
}
if a.systemInfo.KernelVersion == "" {
a.systemInfo.KernelVersion, _ = host.KernelVersion()
}
// cpu model
if info, err := cpu.Info(); err == nil && len(info) > 0 {
@@ -184,11 +198,9 @@ func (a *Agent) getSystemStats() system.Stats {
}
}
// temperatures (skip if sensors whitelist is set to empty string)
err = a.updateTemperatures(&systemStats)
if err != nil {
slog.Error("Error getting temperatures", "err", err)
}
// temperatures
// TODO: maybe refactor to methods on systemStats
a.updateTemperatures(&systemStats)
// GPU data
if a.gpuManager != nil {
@@ -202,13 +214,24 @@ func (a *Agent) getSystemStats() system.Stats {
if systemStats.Temperatures == nil {
systemStats.Temperatures = make(map[string]float64, len(gpuData))
}
highestTemp := 0.0
for _, gpu := range gpuData {
if gpu.Temperature > 0 {
systemStats.Temperatures[gpu.Name] = gpu.Temperature
if a.sensorConfig.primarySensor == gpu.Name {
a.systemInfo.DashboardTemp = gpu.Temperature
}
if gpu.Temperature > highestTemp {
highestTemp = gpu.Temperature
}
}
// update high gpu percent for dashboard
a.systemInfo.GpuPct = max(a.systemInfo.GpuPct, gpu.Usage)
}
// use highest temp for dashboard temp if dashboard temp is unset
if a.systemInfo.DashboardTemp == 0 {
a.systemInfo.DashboardTemp = highestTemp
}
}
}
@@ -223,60 +246,6 @@ func (a *Agent) getSystemStats() system.Stats {
return systemStats
}
func (a *Agent) updateTemperatures(systemStats *system.Stats) error {
// skip if sensors whitelist is set to empty string
if a.sensorsWhitelist != nil && len(a.sensorsWhitelist) == 0 {
slog.Debug("Skipping temperature collection")
return nil
}
primarySensor, primarySensorIsDefined := GetEnv("PRIMARY_SENSOR")
// reset high temp
a.systemInfo.DashboardTemp = 0
// get sensor data
temps, err := sensors.TemperaturesWithContext(a.sensorsContext)
if err != nil {
return err
}
slog.Debug("Temperature", "sensors", temps)
// return if no sensors
if len(temps) == 0 {
return nil
}
systemStats.Temperatures = make(map[string]float64, len(temps))
for i, sensor := range temps {
// skip if temperature is unreasonable
if sensor.Temperature <= 0 || sensor.Temperature >= 200 {
continue
}
sensorName := sensor.SensorKey
if _, ok := systemStats.Temperatures[sensorName]; ok {
// if key already exists, append int to key
sensorName = sensorName + "_" + strconv.Itoa(i)
}
// skip if not in whitelist
if a.sensorsWhitelist != nil {
if _, nameInWhitelist := a.sensorsWhitelist[sensorName]; !nameInWhitelist {
continue
}
}
// set dashboard temperature
if primarySensorIsDefined {
if sensorName == primarySensor {
a.systemInfo.DashboardTemp = sensor.Temperature
}
} else {
a.systemInfo.DashboardTemp = max(a.systemInfo.DashboardTemp, sensor.Temperature)
}
systemStats.Temperatures[sensorName] = twoDecimals(sensor.Temperature)
}
return nil
}
// Returns the size of the ZFS ARC memory cache in bytes
func getARCSize() (uint64, error) {
file, err := os.Open("/proc/spl/kstat/zfs/arcstats")

View File

@@ -8,7 +8,7 @@ import (
"sync"
"time"
"github.com/containrrr/shoutrrr"
"github.com/nicholas-fedor/shoutrrr"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
@@ -66,6 +66,7 @@ var supportsTitle = map[string]struct{}{
"gotify": {},
"ifttt": {},
"join": {},
"lark": {},
"matrix": {},
"ntfy": {},
"opsgenie": {},
@@ -166,10 +167,12 @@ func (am *AlertManager) SendShoutrrrAlert(notificationUrl, title, message, link,
// Add link
if scheme == "ntfy" {
// if ntfy, add link to actions
queryParams.Add("Actions", fmt.Sprintf("view, %s, %s", linkText, link))
} else if scheme == "lark" {
queryParams.Add("link", link)
} else if scheme == "bark" {
queryParams.Add("url", link)
} else {
// else add link directly to the message
message += "\n\n" + link
}

View File

@@ -26,8 +26,7 @@ type alertInfo struct {
// startWorker is a long-running goroutine that processes alert tasks
// every x seconds. It must be running to process status alerts.
func (am *AlertManager) startWorker() {
// no special reason for 13 seconds
tick := time.Tick(13 * time.Second)
tick := time.Tick(15 * time.Second)
for {
select {
case <-am.stopChan:
@@ -64,21 +63,12 @@ func (am *AlertManager) StopWorker() {
}
// HandleStatusAlerts manages the logic when system status changes.
func (am *AlertManager) HandleStatusAlerts(newStatus string, oldSystemRecord *core.Record) error {
switch newStatus {
case "up":
if oldSystemRecord.GetString("status") != "down" {
return nil
}
case "down":
if oldSystemRecord.GetString("status") != "up" {
return nil
}
default:
func (am *AlertManager) HandleStatusAlerts(newStatus string, systemRecord *core.Record) error {
if newStatus != "up" && newStatus != "down" {
return nil
}
alertRecords, err := am.getSystemStatusAlerts(oldSystemRecord.Id)
alertRecords, err := am.getSystemStatusAlerts(systemRecord.Id)
if err != nil {
return err
}
@@ -86,7 +76,7 @@ func (am *AlertManager) HandleStatusAlerts(newStatus string, oldSystemRecord *co
return nil
}
systemName := oldSystemRecord.GetString("name")
systemName := systemRecord.GetString("name")
if newStatus == "down" {
am.handleSystemDown(systemName, alertRecords)
} else {

View File

@@ -4,7 +4,6 @@ import (
"beszel/internal/entities/system"
"fmt"
"net/url"
"slices"
"strings"
"time"
@@ -15,7 +14,7 @@ import (
"github.com/spf13/cast"
)
func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, systemInfo system.Info, temperatures map[string]float64, extraFs map[string]*system.FsStats) error {
func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, data *system.CombinedData) error {
alertRecords, err := am.app.FindAllRecords("alerts",
dbx.NewExp("system={:system}", dbx.Params{"system": systemRecord.Id}),
)
@@ -35,15 +34,15 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, systemInfo
switch name {
case "CPU":
val = systemInfo.Cpu
val = data.Info.Cpu
case "Memory":
val = systemInfo.MemPct
val = data.Info.MemPct
case "Bandwidth":
val = systemInfo.Bandwidth
val = data.Info.Bandwidth
unit = " MB/s"
case "Disk":
maxUsedPct := systemInfo.DiskPct
for _, fs := range extraFs {
maxUsedPct := data.Info.DiskPct
for _, fs := range data.Stats.ExtraFs {
usedPct := fs.DiskUsed / fs.DiskTotal * 100
if usedPct > maxUsedPct {
maxUsedPct = usedPct
@@ -51,14 +50,10 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, systemInfo
}
val = maxUsedPct
case "Temperature":
if temperatures == nil {
if data.Info.DashboardTemp < 1 {
continue
}
for _, temp := range temperatures {
if temp > val {
val = temp
}
}
val = data.Info.DashboardTemp
unit = "°C"
}
@@ -74,13 +69,8 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, systemInfo
}
min := max(1, cast.ToUint8(alertRecord.Get("min")))
// add time to alert time to make sure it's slighty after record creation
time := now.Add(-time.Duration(min) * time.Minute)
if time.Before(oldestTime) {
oldestTime = time
}
validAlerts = append(validAlerts, SystemAlertData{
alert := SystemAlertData{
systemRecord: systemRecord,
alertRecord: alertRecord,
name: name,
@@ -88,9 +78,22 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, systemInfo
val: val,
threshold: threshold,
triggered: triggered,
time: time,
min: min,
})
}
// send alert immediately if min is 1 - no need to sum up values.
if min == 1 {
alert.triggered = val > threshold
go am.sendSystemAlert(alert)
continue
}
alert.time = now.Add(-time.Duration(min) * time.Minute)
if alert.time.Before(oldestTime) {
oldestTime = alert.time
}
validAlerts = append(validAlerts, alert)
}
systemStats := []struct {
@@ -111,7 +114,7 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, systemInfo
)).
OrderBy("created").
All(&systemStats)
if err != nil {
if err != nil || len(systemStats) == 0 {
return err
}
@@ -119,13 +122,14 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, systemInfo
oldestRecordTime := systemStats[0].Created.Time()
// log.Println("oldestRecordTime", oldestRecordTime.String())
// delete from validAlerts if time is older than oldestRecord
for i := range validAlerts {
if validAlerts[i].time.Before(oldestRecordTime) {
// log.Println("deleting alert - time is older than oldestRecord", validAlerts[i].name, oldestRecordTime, validAlerts[i].time)
validAlerts = slices.Delete(validAlerts, i, i+1)
// Filter validAlerts to keep only those with time newer than oldestRecord
filteredAlerts := make([]SystemAlertData, 0, len(validAlerts))
for _, alert := range validAlerts {
if alert.time.After(oldestRecordTime) {
filteredAlerts = append(filteredAlerts, alert)
}
}
validAlerts = filteredAlerts
if len(validAlerts) == 0 {
// log.Println("no valid alerts found")
@@ -163,7 +167,7 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, systemInfo
alert.val += stats.NetSent + stats.NetRecv
case "Disk":
if alert.mapSums == nil {
alert.mapSums = make(map[string]float32, len(extraFs)+1)
alert.mapSums = make(map[string]float32, len(data.Stats.ExtraFs)+1)
}
// add root disk
if _, ok := alert.mapSums["root"]; !ok {
@@ -171,7 +175,7 @@ func (am *AlertManager) HandleSystemAlerts(systemRecord *core.Record, systemInfo
}
alert.mapSums["root"] += float32(stats.Disk)
// add extra disks
for key, fs := range extraFs {
for key, fs := range data.Stats.ExtraFs {
if _, ok := alert.mapSums[key]; !ok {
alert.mapSums[key] = 0.0
}

View File

@@ -27,38 +27,41 @@ type ApiInfo struct {
// Docker container resources from /containers/{id}/stats
type ApiStats struct {
// Common stats
// Read time.Time `json:"read"`
// PreRead time.Time `json:"preread"`
Read time.Time `json:"read"` // Time of stats generation
NumProcs uint32 `json:"num_procs,omitzero"` // Windows specific, not populated on Linux.
Networks map[string]NetworkStats
CPUStats CPUStats `json:"cpu_stats"`
MemoryStats MemoryStats `json:"memory_stats"`
}
// Linux specific stats, not populated on Windows.
// PidsStats PidsStats `json:"pids_stats,omitempty"`
// BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
func (s *ApiStats) CalculateCpuPercentLinux(prevCpuUsage [2]uint64) float64 {
cpuDelta := s.CPUStats.CPUUsage.TotalUsage - prevCpuUsage[0]
systemDelta := s.CPUStats.SystemUsage - prevCpuUsage[1]
return float64(cpuDelta) / float64(systemDelta) * 100
}
// Windows specific stats, not populated on Linux.
// NumProcs uint32 `json:"num_procs"`
// StorageStats StorageStats `json:"storage_stats,omitempty"`
// Networks request version >=1.21
Networks map[string]NetworkStats
// from: https://github.com/docker/cli/blob/master/cli/command/container/stats_helpers.go#L185
func (s *ApiStats) CalculateCpuPercentWindows(prevCpuUsage uint64, prevRead time.Time) float64 {
// Max number of 100ns intervals between the previous time read and now
possIntervals := uint64(s.Read.Sub(prevRead).Nanoseconds())
possIntervals /= 100 // Convert to number of 100ns intervals
possIntervals *= uint64(s.NumProcs) // Multiple by the number of processors
// Shared stats
CPUStats CPUStats `json:"cpu_stats,omitempty"`
// PreCPUStats CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous"
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
// Intervals used
intervalsUsed := s.CPUStats.CPUUsage.TotalUsage - prevCpuUsage
// Percentage avoiding divide-by-zero
if possIntervals > 0 {
return float64(intervalsUsed) / float64(possIntervals) * 100.0
}
return 0.00
}
type CPUStats struct {
// CPU Usage. Linux and Windows.
CPUUsage CPUUsage `json:"cpu_usage"`
// System Usage. Linux only.
SystemUsage uint64 `json:"system_cpu_usage,omitempty"`
// Online CPUs. Linux only.
// OnlineCPUs uint32 `json:"online_cpus,omitempty"`
// Throttling Data. Linux only.
// ThrottlingData ThrottlingData `json:"throttling_data,omitempty"`
}
type CPUUsage struct {
@@ -66,42 +69,15 @@ type CPUUsage struct {
// Units: nanoseconds (Linux)
// Units: 100's of nanoseconds (Windows)
TotalUsage uint64 `json:"total_usage"`
// Total CPU time consumed per core (Linux). Not used on Windows.
// Units: nanoseconds.
// PercpuUsage []uint64 `json:"percpu_usage,omitempty"`
// Time spent by tasks of the cgroup in kernel mode (Linux).
// Time spent by all container processes in kernel mode (Windows).
// Units: nanoseconds (Linux).
// Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers.
// UsageInKernelmode uint64 `json:"usage_in_kernelmode"`
// Time spent by tasks of the cgroup in user mode (Linux).
// Time spent by all container processes in user mode (Windows).
// Units: nanoseconds (Linux).
// Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers
// UsageInUsermode uint64 `json:"usage_in_usermode"`
}
type MemoryStats struct {
// current res_counter usage for memory
Usage uint64 `json:"usage,omitempty"`
// all the stats exported via memory.stat.
Stats MemoryStatsStats `json:"stats,omitempty"`
// maximum usage ever recorded.
// MaxUsage uint64 `json:"max_usage,omitempty"`
// TODO(vishh): Export these as stronger types.
// number of times memory usage hits limits.
// Failcnt uint64 `json:"failcnt,omitempty"`
// Limit uint64 `json:"limit,omitempty"`
// // committed bytes
// Commit uint64 `json:"commitbytes,omitempty"`
// // peak committed bytes
// CommitPeak uint64 `json:"commitpeakbytes,omitempty"`
// // private working set
// PrivateWorkingSet uint64 `json:"privateworkingset,omitempty"`
Stats MemoryStatsStats `json:"stats"`
// private working set (Windows only)
PrivateWorkingSet uint64 `json:"privateworkingset,omitempty"`
}
type MemoryStatsStats struct {
@@ -119,7 +95,6 @@ type NetworkStats struct {
type prevNetStats struct {
Sent uint64
Recv uint64
Time time.Time
}
// Docker container stats
@@ -131,4 +106,5 @@ type Stats struct {
NetworkRecv float64 `json:"nr"`
PrevCpu [2]uint64 `json:"-"`
PrevNet prevNetStats `json:"-"`
PrevRead time.Time `json:"-"`
}

View File

@@ -1,5 +1,7 @@
package system
// TODO: this is confusing, make common package with common/types common/helpers etc
import (
"beszel/internal/entities/container"
"time"
@@ -62,6 +64,14 @@ type NetIoStats struct {
Name string
}
type Os uint8
const (
Linux Os = iota
Darwin
Windows
)
type Info struct {
Hostname string `json:"h"`
KernelVersion string `json:"k,omitempty"`
@@ -77,6 +87,7 @@ type Info struct {
Podman bool `json:"p,omitempty"`
GpuPct float64 `json:"g,omitempty"`
DashboardTemp float64 `json:"dt,omitempty"`
Os Os `json:"os"`
}
// Final data structure to return to the hub

View File

@@ -6,7 +6,6 @@ import (
"log"
"os"
"path/filepath"
"strconv"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/apis"
@@ -22,12 +21,13 @@ type Config struct {
type SystemConfig struct {
Name string `yaml:"name"`
Host string `yaml:"host"`
Port uint16 `yaml:"port"`
Port uint16 `yaml:"port,omitempty"`
Users []string `yaml:"users"`
}
// Syncs systems with the config.yml file
func (h *Hub) syncSystemsWithConfig() error {
func syncSystemsWithConfig(e *core.ServeEvent) error {
h := e.App
configPath := filepath.Join(h.DataDir(), "config.yml")
configData, err := os.ReadFile(configPath)
if err != nil {
@@ -89,16 +89,16 @@ func (h *Hub) syncSystemsWithConfig() error {
return err
}
// Create a map of existing systems for easy lookup
// Create a map of existing systems
existingSystemsMap := make(map[string]*core.Record)
for _, system := range existingSystems {
key := system.GetString("host") + ":" + system.GetString("port")
key := system.GetString("name") + system.GetString("host") + system.GetString("port")
existingSystemsMap[key] = system
}
// Process systems from config
for _, sysConfig := range config.Systems {
key := sysConfig.Host + ":" + strconv.Itoa(int(sysConfig.Port))
key := sysConfig.Name + sysConfig.Host + cast.ToString(sysConfig.Port)
if existingSystem, ok := existingSystemsMap[key]; ok {
// Update existing system
existingSystem.Set("name", sysConfig.Name)

View File

@@ -4,67 +4,46 @@ package hub
import (
"beszel"
"beszel/internal/alerts"
"beszel/internal/entities/system"
"beszel/internal/hub/systems"
"beszel/internal/records"
"beszel/internal/users"
"beszel/site"
"context"
"crypto/ed25519"
"encoding/pem"
"fmt"
"io/fs"
"log"
"net"
"net/http"
"net/http/httputil"
"net/url"
"os"
"strings"
"time"
"github.com/goccy/go-json"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/plugins/migratecmd"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh"
)
type Hub struct {
*pocketbase.PocketBase
sshClientConfig *ssh.ClientConfig
pubKey string
am *alerts.AlertManager
um *users.UserManager
rm *records.RecordManager
systemStats *core.Collection
containerStats *core.Collection
appURL string
core.App
*alerts.AlertManager
um *users.UserManager
rm *records.RecordManager
sm *systems.SystemManager
pubKey string
appURL string
}
// NewHub creates a new Hub instance with default configuration
func NewHub() *Hub {
var hub Hub
hub.PocketBase = pocketbase.NewWithConfig(pocketbase.Config{
DefaultDataDir: beszel.AppName + "_data",
})
func NewHub(app core.App) *Hub {
hub := &Hub{}
hub.App = app
hub.RootCmd.Version = beszel.Version
hub.RootCmd.Use = beszel.AppName
hub.RootCmd.Short = ""
// add update command
hub.RootCmd.AddCommand(&cobra.Command{
Use: "update",
Short: "Update " + beszel.AppName + " to the latest version",
Run: Update,
})
hub.am = alerts.NewAlertManager(hub)
hub.AlertManager = alerts.NewAlertManager(hub)
hub.um = users.NewUserManager(hub)
hub.rm = records.NewRecordManager(hub)
hub.sm = systems.NewSystemManager(hub)
hub.appURL, _ = GetEnv("APP_URL")
return &hub
return hub
}
// GetEnv retrieves an environment variable with a "BESZEL_HUB_" prefix, or falls back to the unprefixed key.
@@ -76,444 +55,192 @@ func GetEnv(key string) (value string, exists bool) {
return os.LookupEnv(key)
}
func (h *Hub) Run() {
isDev := os.Getenv("ENV") == "dev"
func (h *Hub) StartHub() error {
// enable auto creation of migration files when making collection changes in the Admin UI
migratecmd.MustRegister(h, h.RootCmd, migratecmd.Config{
// (the isDev check is to enable it only during development)
Automigrate: isDev,
Dir: "../../migrations",
})
// initial setup
h.OnServe().BindFunc(func(se *core.ServeEvent) error {
// create ssh client config
err := h.createSSHClientConfig()
if err != nil {
log.Fatal(err)
}
// set general settings
settings := h.Settings()
// batch requests (for global alerts)
settings.Batch.Enabled = true
// set URL if BASE_URL env is set
if h.appURL != "" {
settings.Meta.AppURL = h.appURL
}
// set auth settings
usersCollection, err := h.FindCollectionByNameOrId("users")
if err != nil {
return err
}
// disable email auth if DISABLE_PASSWORD_AUTH env var is set
disablePasswordAuth, _ := GetEnv("DISABLE_PASSWORD_AUTH")
usersCollection.PasswordAuth.Enabled = disablePasswordAuth != "true"
usersCollection.PasswordAuth.IdentityFields = []string{"email"}
// disable oauth if no providers are configured (todo: remove this in post 0.9.0 release)
if usersCollection.OAuth2.Enabled {
usersCollection.OAuth2.Enabled = len(usersCollection.OAuth2.Providers) > 0
}
// allow oauth user creation if USER_CREATION is set
if userCreation, _ := GetEnv("USER_CREATION"); userCreation == "true" {
cr := "@request.context = 'oauth2'"
usersCollection.CreateRule = &cr
} else {
usersCollection.CreateRule = nil
}
if err := h.Save(usersCollection); err != nil {
h.App.OnServe().BindFunc(func(e *core.ServeEvent) error {
// initialize settings / collections
if err := h.initialize(e); err != nil {
return err
}
// sync systems with config
h.syncSystemsWithConfig()
return se.Next()
})
// serve web ui
h.OnServe().BindFunc(func(se *core.ServeEvent) error {
switch isDev {
case true:
proxy := httputil.NewSingleHostReverseProxy(&url.URL{
Scheme: "http",
Host: "localhost:5173",
})
se.Router.GET("/{path...}", func(e *core.RequestEvent) error {
proxy.ServeHTTP(e.Response, e.Request)
return nil
})
default:
// parse app url
parsedURL, err := url.Parse(h.appURL)
if err != nil {
return err
}
// fix base paths in html if using subpath
basePath := strings.TrimSuffix(parsedURL.Path, "/") + "/"
indexFile, _ := fs.ReadFile(site.DistDirFS, "index.html")
indexContent := strings.ReplaceAll(string(indexFile), "./", basePath)
// set up static asset serving
staticPaths := [2]string{"/static/", "/assets/"}
serveStatic := apis.Static(site.DistDirFS, false)
// get CSP configuration
csp, cspExists := GetEnv("CSP")
// add route
se.Router.GET("/{path...}", func(e *core.RequestEvent) error {
// serve static assets if path is in staticPaths
for i := range staticPaths {
if strings.Contains(e.Request.URL.Path, staticPaths[i]) {
e.Response.Header().Set("Cache-Control", "public, max-age=2592000")
return serveStatic(e)
}
}
if cspExists {
e.Response.Header().Del("X-Frame-Options")
e.Response.Header().Set("Content-Security-Policy", csp)
}
return e.HTML(http.StatusOK, indexContent)
})
if err := syncSystemsWithConfig(e); err != nil {
return err
}
return se.Next()
})
// set up scheduled jobs / ticker for system updates
h.OnServe().BindFunc(func(se *core.ServeEvent) error {
// 15 second ticker for system updates
go h.startSystemUpdateTicker()
// set up cron jobs
// delete old records once every hour
h.Cron().MustAdd("delete old records", "8 * * * *", h.rm.DeleteOldRecords)
// create longer records every 10 minutes
h.Cron().MustAdd("create longer records", "*/10 * * * *", func() {
if systemStats, containerStats, err := h.getCollections(); err == nil {
h.rm.CreateLongerRecords([]*core.Collection{systemStats, containerStats})
}
})
return se.Next()
})
// custom api routes
h.OnServe().BindFunc(func(se *core.ServeEvent) error {
// returns public key
se.Router.GET("/api/beszel/getkey", func(e *core.RequestEvent) error {
info, _ := e.RequestInfo()
if info.Auth == nil {
return apis.NewForbiddenError("Forbidden", nil)
}
return e.JSON(http.StatusOK, map[string]string{"key": h.pubKey, "v": beszel.Version})
})
// check if first time setup on login page
se.Router.GET("/api/beszel/first-run", func(e *core.RequestEvent) error {
total, err := h.CountRecords("users")
return e.JSON(http.StatusOK, map[string]bool{"firstRun": err == nil && total == 0})
})
// send test notification
se.Router.GET("/api/beszel/send-test-notification", h.am.SendTestNotification)
// API endpoint to get config.yml content
se.Router.GET("/api/beszel/config-yaml", h.getYamlConfig)
// create first user endpoint only needed if no users exist
if totalUsers, _ := h.CountRecords("users"); totalUsers == 0 {
se.Router.POST("/api/beszel/create-user", h.um.CreateFirstUser)
// register api routes
if err := h.registerApiRoutes(e); err != nil {
return err
}
// register cron jobs
if err := h.registerCronJobs(e); err != nil {
return err
}
// start server
if err := h.startServer(e); err != nil {
return err
}
// start system updates
if err := h.sm.Initialize(); err != nil {
return err
}
return se.Next()
})
// system creation defaults
h.OnRecordCreate("systems").BindFunc(func(e *core.RecordEvent) error {
e.Record.Set("info", system.Info{})
e.Record.Set("status", "pending")
return e.Next()
})
// immediately create connection for new systems
h.OnRecordAfterCreateSuccess("systems").BindFunc(func(e *core.RecordEvent) error {
go h.updateSystem(e.Record)
return e.Next()
})
// TODO: move to users package
// handle default values for user / user_settings creation
h.OnRecordCreate("users").BindFunc(h.um.InitializeUserRole)
h.OnRecordCreate("user_settings").BindFunc(h.um.InitializeUserSettings)
h.App.OnRecordCreate("users").BindFunc(h.um.InitializeUserRole)
h.App.OnRecordCreate("user_settings").BindFunc(h.um.InitializeUserSettings)
// empty info for systems that are paused
h.OnRecordUpdate("systems").BindFunc(func(e *core.RecordEvent) error {
if e.Record.GetString("status") == "paused" {
e.Record.Set("info", system.Info{})
}
return e.Next()
})
// do things after a systems record is updated
h.OnRecordAfterUpdateSuccess("systems").BindFunc(func(e *core.RecordEvent) error {
newRecord := e.Record.Fresh()
oldRecord := newRecord.Original()
newStatus := newRecord.GetString("status")
// if system is not up and connection exists, remove it
if newStatus != "up" {
h.deleteSystemConnection(newRecord)
}
// if system is set to pending (unpause), try to connect immediately
if newStatus == "pending" {
go h.updateSystem(newRecord)
} else {
h.am.HandleStatusAlerts(newStatus, oldRecord)
}
return e.Next()
})
// if system is deleted, close connection
h.OnRecordAfterDeleteSuccess("systems").BindFunc(func(e *core.RecordEvent) error {
h.deleteSystemConnection(e.Record)
return e.Next()
})
if err := h.Start(); err != nil {
log.Fatal(err)
}
}
func (h *Hub) startSystemUpdateTicker() {
c := time.Tick(15 * time.Second)
for range c {
h.updateSystems()
}
}
func (h *Hub) updateSystems() {
records, err := h.FindRecordsByFilter(
"2hz5ncl8tizk5nx", // systems collection
"status != 'paused'", // filter
"updated", // sort
-1, // limit
0, // offset
)
// log.Println("records", len(records))
if err != nil || len(records) == 0 {
// h.Logger().Error("Failed to query systems")
return
}
fiftySecondsAgo := time.Now().UTC().Add(-50 * time.Second)
batchSize := len(records)/4 + 1
done := 0
for _, record := range records {
// break if batch size reached or if the system was updated less than 50 seconds ago
if done >= batchSize || record.GetDateTime("updated").Time().After(fiftySecondsAgo) {
break
}
// don't increment for down systems to avoid them jamming the queue
// because they're always first when sorted by least recently updated
if record.GetString("status") != "down" {
done++
}
go h.updateSystem(record)
}
}
func (h *Hub) updateSystem(record *core.Record) {
var client *ssh.Client
var err error
// check if system connection exists
if existingClient, ok := h.Store().GetOk(record.Id); ok {
client = existingClient.(*ssh.Client)
} else {
// create system connection
client, err = h.createSystemConnection(record)
if pb, ok := h.App.(*pocketbase.PocketBase); ok {
// log.Println("Starting pocketbase")
err := pb.Start()
if err != nil {
if record.GetString("status") != "down" {
h.Logger().Error("Failed to connect:", "err", err.Error(), "system", record.GetString("host"), "port", record.GetString("port"))
h.updateSystemStatus(record, "down")
}
return
return err
}
h.Store().Set(record.Id, client)
}
// get system stats from agent
var systemData system.CombinedData
if err := h.requestJsonFromAgent(client, &systemData); err != nil {
if err.Error() == "bad client" {
// if previous connection was closed, try again
h.Logger().Error("Existing SSH connection closed. Retrying...", "host", record.GetString("host"), "port", record.GetString("port"))
h.deleteSystemConnection(record)
time.Sleep(time.Millisecond * 100)
h.updateSystem(record)
return
}
h.Logger().Error("Failed to get system stats: ", "err", err.Error())
h.updateSystemStatus(record, "down")
return
}
// update system record
record.Set("status", "up")
record.Set("info", systemData.Info)
if err := h.SaveNoValidate(record); err != nil {
h.Logger().Error("Failed to update record: ", "err", err.Error())
}
// add system_stats and container_stats records
if systemStats, containerStats, err := h.getCollections(); err != nil {
h.Logger().Error("Failed to get collections: ", "err", err.Error())
} else {
// add new system_stats record
systemStatsRecord := core.NewRecord(systemStats)
systemStatsRecord.Set("system", record.Id)
systemStatsRecord.Set("stats", systemData.Stats)
systemStatsRecord.Set("type", "1m")
if err := h.SaveNoValidate(systemStatsRecord); err != nil {
h.Logger().Error("Failed to save record: ", "err", err.Error())
}
// add new container_stats record
if len(systemData.Containers) > 0 {
containerStatsRecord := core.NewRecord(containerStats)
containerStatsRecord.Set("system", record.Id)
containerStatsRecord.Set("stats", systemData.Containers)
containerStatsRecord.Set("type", "1m")
if err := h.SaveNoValidate(containerStatsRecord); err != nil {
h.Logger().Error("Failed to save record: ", "err", err.Error())
}
}
}
// system info alerts
if err := h.am.HandleSystemAlerts(record, systemData.Info, systemData.Stats.Temperatures, systemData.Stats.ExtraFs); err != nil {
h.Logger().Error("System alerts error", "err", err.Error())
}
}
// return system_stats and container_stats collections
func (h *Hub) getCollections() (*core.Collection, *core.Collection, error) {
if h.systemStats == nil {
systemStats, err := h.FindCollectionByNameOrId("system_stats")
if err != nil {
return nil, nil, err
}
h.systemStats = systemStats
}
if h.containerStats == nil {
containerStats, err := h.FindCollectionByNameOrId("container_stats")
if err != nil {
return nil, nil, err
}
h.containerStats = containerStats
}
return h.systemStats, h.containerStats, nil
}
// set system to specified status and save record
func (h *Hub) updateSystemStatus(record *core.Record, status string) {
if record.Fresh().GetString("status") != status {
record.Set("status", status)
if err := h.SaveNoValidate(record); err != nil {
h.Logger().Error("Failed to update record: ", "err", err.Error())
}
}
}
// delete system connection from map and close connection
func (h *Hub) deleteSystemConnection(record *core.Record) {
if client, ok := h.Store().GetOk(record.Id); ok {
if sshClient := client.(*ssh.Client); sshClient != nil {
sshClient.Close()
}
h.Store().Remove(record.Id)
}
}
func (h *Hub) createSystemConnection(record *core.Record) (*ssh.Client, error) {
network := "tcp"
host := record.GetString("host")
if strings.HasPrefix(host, "/") {
network = "unix"
} else {
host = net.JoinHostPort(host, record.GetString("port"))
}
client, err := ssh.Dial(network, host, h.sshClientConfig)
if err != nil {
return nil, err
}
return client, nil
}
func (h *Hub) createSSHClientConfig() error {
key, err := h.getSSHKey()
if err != nil {
h.Logger().Error("Failed to get SSH key: ", "err", err.Error())
return err
}
// Create the Signer for this private key.
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
return err
}
h.sshClientConfig = &ssh.ClientConfig{
User: "u",
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: 4 * time.Second,
}
return nil
}
// Fetches system stats from the agent and decodes the json data into the provided struct
func (h *Hub) requestJsonFromAgent(client *ssh.Client, systemData *system.CombinedData) error {
session, err := newSessionWithTimeout(client, 4*time.Second)
if err != nil {
return fmt.Errorf("bad client")
}
defer session.Close()
stdout, err := session.StdoutPipe()
if err != nil {
return err
}
if err := session.Shell(); err != nil {
return err
}
if err := json.NewDecoder(stdout).Decode(systemData); err != nil {
return err
}
// wait for the session to complete
if err := session.Wait(); err != nil {
return err
}
return nil
}
// Adds timeout to SSH session creation to avoid hanging in case of network issues
func newSessionWithTimeout(client *ssh.Client, timeout time.Duration) (*ssh.Session, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
// use goroutine to create the session
sessionChan := make(chan *ssh.Session, 1)
errChan := make(chan error, 1)
go func() {
if session, err := client.NewSession(); err != nil {
errChan <- err
} else {
sessionChan <- session
}
}()
select {
case session := <-sessionChan:
return session, nil
case err := <-errChan:
return nil, err
case <-ctx.Done():
return nil, fmt.Errorf("session creation timed out")
// initialize sets up initial configuration (collections, settings, etc.)
func (h *Hub) initialize(e *core.ServeEvent) error {
// set general settings
settings := e.App.Settings()
// batch requests (for global alerts)
settings.Batch.Enabled = true
// set URL if BASE_URL env is set
if h.appURL != "" {
settings.Meta.AppURL = h.appURL
}
// set auth settings
usersCollection, err := e.App.FindCollectionByNameOrId("users")
if err != nil {
return err
}
// disable email auth if DISABLE_PASSWORD_AUTH env var is set
disablePasswordAuth, _ := GetEnv("DISABLE_PASSWORD_AUTH")
usersCollection.PasswordAuth.Enabled = disablePasswordAuth != "true"
usersCollection.PasswordAuth.IdentityFields = []string{"email"}
// disable oauth if no providers are configured (todo: remove this in post 0.9.0 release)
if usersCollection.OAuth2.Enabled {
usersCollection.OAuth2.Enabled = len(usersCollection.OAuth2.Providers) > 0
}
// allow oauth user creation if USER_CREATION is set
if userCreation, _ := GetEnv("USER_CREATION"); userCreation == "true" {
cr := "@request.context = 'oauth2'"
usersCollection.CreateRule = &cr
} else {
usersCollection.CreateRule = nil
}
if err := e.App.Save(usersCollection); err != nil {
return err
}
// allow all users to access systems if SHARE_ALL_SYSTEMS is set
systemsCollection, err := e.App.FindCachedCollectionByNameOrId("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"
}
updateDeleteRule := systemsReadRule + " && @request.auth.role != \"readonly\""
systemsCollection.ListRule = &systemsReadRule
systemsCollection.ViewRule = &systemsReadRule
systemsCollection.UpdateRule = &updateDeleteRule
systemsCollection.DeleteRule = &updateDeleteRule
if err := e.App.Save(systemsCollection); err != nil {
return err
}
return nil
}
func (h *Hub) getSSHKey() ([]byte, error) {
// startServer starts the server for the Beszel (not PocketBase)
func (h *Hub) startServer(se *core.ServeEvent) error {
// TODO: exclude dev server from production binary
switch h.IsDev() {
case true:
proxy := httputil.NewSingleHostReverseProxy(&url.URL{
Scheme: "http",
Host: "localhost:5173",
})
se.Router.GET("/{path...}", func(e *core.RequestEvent) error {
proxy.ServeHTTP(e.Response, e.Request)
return nil
})
default:
// parse app url
parsedURL, err := url.Parse(h.appURL)
if err != nil {
return err
}
// fix base paths in html if using subpath
basePath := strings.TrimSuffix(parsedURL.Path, "/") + "/"
indexFile, _ := fs.ReadFile(site.DistDirFS, "index.html")
indexContent := strings.ReplaceAll(string(indexFile), "./", basePath)
indexContent = strings.Replace(indexContent, "{{V}}", beszel.Version, 1)
// set up static asset serving
staticPaths := [2]string{"/static/", "/assets/"}
serveStatic := apis.Static(site.DistDirFS, false)
// get CSP configuration
csp, cspExists := GetEnv("CSP")
// add route
se.Router.GET("/{path...}", func(e *core.RequestEvent) error {
// serve static assets if path is in staticPaths
for i := range staticPaths {
if strings.Contains(e.Request.URL.Path, staticPaths[i]) {
e.Response.Header().Set("Cache-Control", "public, max-age=2592000")
return serveStatic(e)
}
}
if cspExists {
e.Response.Header().Del("X-Frame-Options")
e.Response.Header().Set("Content-Security-Policy", csp)
}
return e.HTML(http.StatusOK, indexContent)
})
}
return nil
}
// registerCronJobs sets up scheduled tasks
func (h *Hub) registerCronJobs(_ *core.ServeEvent) error {
// delete old records once every hour
h.Cron().MustAdd("delete old records", "8 * * * *", h.rm.DeleteOldRecords)
// create longer records every 10 minutes
h.Cron().MustAdd("create longer records", "*/10 * * * *", h.rm.CreateLongerRecords)
return nil
}
// custom api routes
func (h *Hub) registerApiRoutes(se *core.ServeEvent) error {
// returns public key and version
se.Router.GET("/api/beszel/getkey", func(e *core.RequestEvent) error {
info, _ := e.RequestInfo()
if info.Auth == nil {
return apis.NewForbiddenError("Forbidden", nil)
}
return e.JSON(http.StatusOK, map[string]string{"key": h.pubKey, "v": beszel.Version})
})
// check if first time setup on login page
se.Router.GET("/api/beszel/first-run", func(e *core.RequestEvent) error {
total, err := h.CountRecords("users")
return e.JSON(http.StatusOK, map[string]bool{"firstRun": err == nil && total == 0})
})
// send test notification
se.Router.GET("/api/beszel/send-test-notification", h.SendTestNotification)
// API endpoint to get config.yml content
se.Router.GET("/api/beszel/config-yaml", h.getYamlConfig)
// create first user endpoint only needed if no users exist
if totalUsers, _ := h.CountRecords("users"); totalUsers == 0 {
se.Router.POST("/api/beszel/create-user", h.um.CreateFirstUser)
}
return nil
}
// generates key pair if it doesn't exist and returns private key bytes
func (h *Hub) GetSSHKey() ([]byte, error) {
dataDir := h.DataDir()
// check if the key pair already exists
existingKey, err := os.ReadFile(dataDir + "/id_ed25519")

View File

@@ -0,0 +1,435 @@
package systems
import (
"beszel/internal/entities/system"
"context"
"fmt"
"net"
"strings"
"time"
"github.com/goccy/go-json"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/store"
"golang.org/x/crypto/ssh"
)
const (
up string = "up"
down string = "down"
paused string = "paused"
pending string = "pending"
interval int = 60_000
sessionTimeout = 4 * time.Second
)
type SystemManager struct {
hub hubLike
systems *store.Store[string, *System]
sshConfig *ssh.ClientConfig
}
type System struct {
Id string `db:"id"`
Host string `db:"host"`
Port string `db:"port"`
Status string `db:"status"`
manager *SystemManager
client *ssh.Client
data *system.CombinedData
ctx context.Context
cancel context.CancelFunc
}
type hubLike interface {
core.App
GetSSHKey() ([]byte, error)
HandleSystemAlerts(systemRecord *core.Record, data *system.CombinedData) error
HandleStatusAlerts(status string, systemRecord *core.Record) error
}
func NewSystemManager(hub hubLike) *SystemManager {
return &SystemManager{
systems: store.New(map[string]*System{}),
hub: hub,
}
}
// Initialize initializes the system manager.
// It binds the event hooks and starts updating existing systems.
func (sm *SystemManager) Initialize() error {
sm.bindEventHooks()
// ssh setup
key, err := sm.hub.GetSSHKey()
if err != nil {
return err
}
if err := sm.createSSHClientConfig(key); err != nil {
return err
}
// start updating existing systems
var systems []*System
err = sm.hub.DB().NewQuery("SELECT id, host, port, status FROM systems WHERE status != 'paused'").All(&systems)
if err != nil || len(systems) == 0 {
return err
}
go func() {
// time between initial system updates
delta := interval / max(1, len(systems))
delta = min(delta, 2_000)
sleepTime := time.Duration(delta) * time.Millisecond
for _, system := range systems {
time.Sleep(sleepTime)
_ = sm.AddSystem(system)
}
}()
return nil
}
func (sm *SystemManager) bindEventHooks() {
sm.hub.OnRecordCreate("systems").BindFunc(sm.onRecordCreate)
sm.hub.OnRecordAfterCreateSuccess("systems").BindFunc(sm.onRecordAfterCreateSuccess)
sm.hub.OnRecordUpdate("systems").BindFunc(sm.onRecordUpdate)
sm.hub.OnRecordAfterUpdateSuccess("systems").BindFunc(sm.onRecordAfterUpdateSuccess)
sm.hub.OnRecordAfterDeleteSuccess("systems").BindFunc(sm.onRecordAfterDeleteSuccess)
}
// Runs before the record is committed to the database
func (sm *SystemManager) onRecordCreate(e *core.RecordEvent) error {
e.Record.Set("info", system.Info{})
e.Record.Set("status", pending)
return e.Next()
}
// Runs after the record is committed to the database
func (sm *SystemManager) onRecordAfterCreateSuccess(e *core.RecordEvent) error {
if err := sm.AddRecord(e.Record); err != nil {
e.App.Logger().Error("Error adding record", "err", err)
}
return e.Next()
}
// Runs before the record is updated
func (sm *SystemManager) onRecordUpdate(e *core.RecordEvent) error {
if e.Record.GetString("status") == paused {
e.Record.Set("info", system.Info{})
}
return e.Next()
}
// Runs after the record is updated
func (sm *SystemManager) onRecordAfterUpdateSuccess(e *core.RecordEvent) error {
newStatus := e.Record.GetString("status")
switch newStatus {
case paused:
sm.RemoveSystem(e.Record.Id)
return e.Next()
case pending:
if err := sm.AddRecord(e.Record); err != nil {
e.App.Logger().Error("Error adding record", "err", err)
}
return e.Next()
}
system, ok := sm.systems.GetOk(e.Record.Id)
if !ok {
return sm.AddRecord(e.Record)
}
prevStatus := system.Status
system.Status = newStatus
// system alerts if system is up
if system.Status == up {
if err := sm.hub.HandleSystemAlerts(e.Record, system.data); err != nil {
e.App.Logger().Error("Error handling system alerts", "err", err)
}
}
if (system.Status == down && prevStatus == up) || (system.Status == up && prevStatus == down) {
if err := sm.hub.HandleStatusAlerts(system.Status, e.Record); err != nil {
e.App.Logger().Error("Error handling status alerts", "err", err)
}
}
return e.Next()
}
// Runs after the record is deleted
func (sm *SystemManager) onRecordAfterDeleteSuccess(e *core.RecordEvent) error {
sm.RemoveSystem(e.Record.Id)
return e.Next()
}
// AddSystem adds a system to the manager
func (sm *SystemManager) AddSystem(sys *System) error {
if sm.systems.Has(sys.Id) {
return fmt.Errorf("system exists")
}
if sys.Id == "" || sys.Host == "" {
return fmt.Errorf("system is missing required fields")
}
sys.manager = sm
sys.ctx, sys.cancel = context.WithCancel(context.Background())
sys.data = &system.CombinedData{}
sm.systems.Set(sys.Id, sys)
go sys.StartUpdater()
return nil
}
// RemoveSystem removes a system from the manager
func (sm *SystemManager) RemoveSystem(systemID string) error {
system, ok := sm.systems.GetOk(systemID)
if !ok {
return fmt.Errorf("system not found")
}
// cancel the context to signal stop
if system.cancel != nil {
system.cancel()
}
system.resetSSHClient()
sm.systems.Remove(systemID)
return nil
}
// AddRecord adds a record to the system manager.
// It first removes any existing system with the same ID, then creates a new System
// instance from the record data and adds it to the manager.
// This function is typically called when a new system is created or when an existing
// system's status changes to pending.
func (sm *SystemManager) AddRecord(record *core.Record) (err error) {
_ = sm.RemoveSystem(record.Id)
system := &System{
Id: record.Id,
Status: record.GetString("status"),
Host: record.GetString("host"),
Port: record.GetString("port"),
}
return sm.AddSystem(system)
}
// StartUpdater starts the system updater.
// It first fetches the data from the agent then updates the records.
// If the data is not found or the system is down, it sets the system down.
func (sys *System) StartUpdater() {
if sys.data == nil {
sys.data = &system.CombinedData{}
}
if err := sys.update(); err != nil {
_ = sys.setDown(err)
}
c := time.Tick(time.Duration(interval) * time.Millisecond)
for {
select {
case <-sys.ctx.Done():
return
case <-c:
err := sys.update()
if err != nil {
_ = sys.setDown(err)
}
}
}
}
// update updates the system data and records.
// It first fetches the data from the agent then updates the records.
func (sys *System) update() error {
_, err := sys.fetchDataFromAgent()
if err == nil {
_, err = sys.createRecords()
}
return err
}
// createRecords updates the system record and adds system_stats and container_stats records
func (sys *System) createRecords() (*core.Record, error) {
systemRecord, err := sys.getRecord()
if err != nil {
return nil, err
}
hub := sys.manager.hub
// add system_stats and container_stats records
systemStats, err := hub.FindCachedCollectionByNameOrId("system_stats")
if err != nil {
return nil, err
}
systemStatsRecord := core.NewRecord(systemStats)
systemStatsRecord.Set("system", systemRecord.Id)
systemStatsRecord.Set("stats", sys.data.Stats)
systemStatsRecord.Set("type", "1m")
if err := hub.SaveNoValidate(systemStatsRecord); err != nil {
return nil, err
}
// add new container_stats record
if len(sys.data.Containers) > 0 {
containerStats, err := hub.FindCachedCollectionByNameOrId("container_stats")
if err != nil {
return nil, err
}
containerStatsRecord := core.NewRecord(containerStats)
containerStatsRecord.Set("system", systemRecord.Id)
containerStatsRecord.Set("stats", sys.data.Containers)
containerStatsRecord.Set("type", "1m")
if err := hub.SaveNoValidate(containerStatsRecord); err != nil {
return nil, err
}
}
// update system record (do this last because it triggers alerts and we need above records to be inserted first)
systemRecord.Set("status", up)
systemRecord.Set("info", sys.data.Info)
if err := hub.SaveNoValidate(systemRecord); err != nil {
return nil, err
}
return systemRecord, nil
}
// getRecord retrieves the system record from the database.
// If the record is not found or the system is paused, it removes the system from the manager.
func (sys *System) getRecord() (*core.Record, error) {
record, err := sys.manager.hub.FindRecordById("systems", sys.Id)
if err != nil || record == nil {
_ = sys.manager.RemoveSystem(sys.Id)
return nil, err
}
return record, nil
}
// setDown marks a system as down in the database.
// It takes the original error that caused the system to go down and returns any error
// encountered during the process of updating the system status.
func (sys *System) setDown(OriginalError error) error {
if sys.Status == down {
return nil
}
record, err := sys.getRecord()
if err != nil {
return err
}
sys.manager.hub.Logger().Error("System down", "system", record.GetString("name"), "err", OriginalError)
record.Set("status", down)
err = sys.manager.hub.SaveNoValidate(record)
if err != nil {
return err
}
return nil
}
// fetchDataFromAgent fetches the data from the agent.
// It first creates a new SSH client if it doesn't exist or the system is down.
// Then it creates a new SSH session and fetches the data from the agent.
// If the data is not found or the system is down, it sets the system down.
func (sys *System) fetchDataFromAgent() (*system.CombinedData, error) {
maxRetries := 1
for attempt := 0; attempt <= maxRetries; attempt++ {
if sys.client == nil || sys.Status == down {
if err := sys.createSSHClient(); err != nil {
return nil, err
}
}
session, err := sys.createSessionWithTimeout(4 * time.Second)
if err != nil {
if attempt >= maxRetries {
return nil, err
}
sys.manager.hub.Logger().Warn("Session closed. Retrying...", "host", sys.Host, "port", sys.Port, "err", err)
sys.resetSSHClient()
continue
}
defer session.Close()
stdout, err := session.StdoutPipe()
if err != nil {
return nil, err
}
if err := session.Shell(); err != nil {
return nil, err
}
// this is initialized in startUpdater, should never be nil
*sys.data = system.CombinedData{}
if err := json.NewDecoder(stdout).Decode(sys.data); err != nil {
return nil, err
}
// wait for the session to complete
if err := session.Wait(); err != nil {
return nil, err
}
return sys.data, nil
}
// this should never be reached due to the return in the loop
return nil, fmt.Errorf("failed to fetch data")
}
func (sm *SystemManager) createSSHClientConfig(key []byte) error {
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
return err
}
sm.sshConfig = &ssh.ClientConfig{
User: "u",
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: sessionTimeout,
}
return nil
}
// createSSHClient creates a new SSH client for the system
func (s *System) createSSHClient() error {
network := "tcp"
host := s.Host
if strings.HasPrefix(host, "/") {
network = "unix"
} else {
host = net.JoinHostPort(host, s.Port)
}
var err error
s.client, err = ssh.Dial(network, host, s.manager.sshConfig)
if err != nil {
return err
}
return nil
}
// createSessionWithTimeout creates a new SSH session with a timeout to avoid hanging
// in case of network issues
func (sys *System) createSessionWithTimeout(timeout time.Duration) (*ssh.Session, error) {
if sys.client == nil {
return nil, fmt.Errorf("client not initialized")
}
ctx, cancel := context.WithTimeout(sys.ctx, timeout)
defer cancel()
sessionChan := make(chan *ssh.Session, 1)
errChan := make(chan error, 1)
go func() {
if session, err := sys.client.NewSession(); err != nil {
errChan <- err
} else {
sessionChan <- session
}
}()
select {
case session := <-sessionChan:
return session, nil
case err := <-errChan:
return nil, err
case <-ctx.Done():
return nil, fmt.Errorf("timeout")
}
}
// resetSSHClient closes the SSH connection and resets the client to nil
func (sys *System) resetSSHClient() {
if sys.client != nil {
sys.client.Close()
}
sys.client = nil
}

View File

@@ -0,0 +1,440 @@
//go:build testing
// +build testing
package systems_test
import (
"beszel/internal/entities/container"
"beszel/internal/entities/system"
"beszel/internal/hub/systems"
"beszel/internal/tests"
"fmt"
"sync"
"testing"
"time"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// createTestSystem creates a test system record with a unique host name
// and returns the created record and any error
func createTestSystem(t *testing.T, hub *tests.TestHub, options map[string]any) (*core.Record, error) {
collection, err := hub.FindCachedCollectionByNameOrId("systems")
if err != nil {
return nil, err
}
// get user record
var firstUser *core.Record
users, err := hub.FindAllRecords("users", dbx.NewExp("id != ''"))
if err != nil {
t.Fatal(err)
}
if len(users) > 0 {
firstUser = users[0]
}
// Generate a unique host name to ensure we're adding a new system
uniqueHost := fmt.Sprintf("test-host-%d.example.com", time.Now().UnixNano())
// Create the record
record := core.NewRecord(collection)
record.Set("name", uniqueHost)
record.Set("host", uniqueHost)
record.Set("port", "45876")
record.Set("status", "pending")
record.Set("users", []string{firstUser.Id})
// Apply any custom options
for key, value := range options {
record.Set(key, value)
}
// Save the record to the database
err = hub.Save(record)
if err != nil {
return nil, err
}
return record, nil
}
func TestSystemManagerIntegration(t *testing.T) {
// Create a test hub
hub, err := tests.NewTestHub()
if err != nil {
t.Fatal(err)
}
defer hub.Cleanup()
// Create independent system manager
sm := systems.NewSystemManager(hub)
assert.NotNil(t, sm)
// Test initialization
sm.Initialize()
// Test collection existence. todo: move to hub package tests
t.Run("CollectionExistence", func(t *testing.T) {
// Verify that required collections exist
systems, err := hub.FindCachedCollectionByNameOrId("systems")
require.NoError(t, err)
assert.NotNil(t, systems)
systemStats, err := hub.FindCachedCollectionByNameOrId("system_stats")
require.NoError(t, err)
assert.NotNil(t, systemStats)
containerStats, err := hub.FindCachedCollectionByNameOrId("container_stats")
require.NoError(t, err)
assert.NotNil(t, containerStats)
})
// Test adding a system record
t.Run("AddRecord", func(t *testing.T) {
var wg sync.WaitGroup
wg.Add(2)
// Get the count before adding the system
countBefore := sm.GetSystemCount()
// record should be pending on create
hub.OnRecordCreate("systems").BindFunc(func(e *core.RecordEvent) error {
record := e.Record
if record.GetString("name") == "welcometoarcoampm" {
assert.Equal(t, "pending", e.Record.GetString("status"), "System status should be 'pending'")
wg.Done()
}
return e.Next()
})
// record should be down on update
hub.OnRecordAfterUpdateSuccess("systems").BindFunc(func(e *core.RecordEvent) error {
record := e.Record
if record.GetString("name") == "welcometoarcoampm" {
assert.Equal(t, "down", e.Record.GetString("status"), "System status should be 'pending'")
wg.Done()
}
return e.Next()
})
// Create a test system with the first user assigned
record, err := createTestSystem(t, hub, map[string]any{
"name": "welcometoarcoampm",
"host": "localhost",
"port": "33914",
})
require.NoError(t, err)
wg.Wait()
// system should be down if grabbed from the store
assert.Equal(t, "down", sm.GetSystemStatusFromStore(record.Id), "System status should be 'down'")
// Check that the system count increased
countAfter := sm.GetSystemCount()
assert.Equal(t, countBefore+1, countAfter, "System count should increase after adding a system via event hook")
// Verify the system was added by checking if it exists
assert.True(t, sm.HasSystem(record.Id), "System should exist in the store")
// Verify the system host and port
host, port := sm.GetSystemHostPort(record.Id)
assert.Equal(t, record.Get("host"), host, "System host should match")
assert.Equal(t, record.Get("port"), port, "System port should match")
// Verify the system is in the list of all system IDs
ids := sm.GetAllSystemIDs()
assert.Contains(t, ids, record.Id, "System ID should be in the list of all system IDs")
// Verify the system was added by checking if removing it works
err = sm.RemoveSystem(record.Id)
assert.NoError(t, err, "System should exist and be removable")
// Verify the system no longer exists
assert.False(t, sm.HasSystem(record.Id), "System should not exist in the store after removal")
// Verify the system is not in the list of all system IDs
newIds := sm.GetAllSystemIDs()
assert.NotContains(t, newIds, record.Id, "System ID should not be in the list of all system IDs after removal")
})
t.Run("RemoveSystem", func(t *testing.T) {
// Get the count before adding the system
countBefore := sm.GetSystemCount()
// Create a test system record
record, err := createTestSystem(t, hub, map[string]any{})
require.NoError(t, err)
// Verify the system count increased
countAfterAdd := sm.GetSystemCount()
assert.Equal(t, countBefore+1, countAfterAdd, "System count should increase after adding a system via event hook")
// Verify the system exists
assert.True(t, sm.HasSystem(record.Id), "System should exist in the store")
// Remove the system
err = sm.RemoveSystem(record.Id)
assert.NoError(t, err)
// Check that the system count decreased
countAfterRemove := sm.GetSystemCount()
assert.Equal(t, countAfterAdd-1, countAfterRemove, "System count should decrease after removing a system")
// Verify the system no longer exists
assert.False(t, sm.HasSystem(record.Id), "System should not exist in the store after removal")
// Verify the system is not in the list of all system IDs
ids := sm.GetAllSystemIDs()
assert.NotContains(t, ids, record.Id, "System ID should not be in the list of all system IDs after removal")
// Verify the system status is empty
status := sm.GetSystemStatusFromStore(record.Id)
assert.Equal(t, "", status, "System status should be empty after removal")
// Try to remove it again - should return an error since it's already removed
err = sm.RemoveSystem(record.Id)
assert.Error(t, err)
})
t.Run("NewRecordPending", func(t *testing.T) {
// Create a test system
record, err := createTestSystem(t, hub, map[string]any{})
require.NoError(t, err)
// Add the record to the system manager
err = sm.AddRecord(record)
require.NoError(t, err)
// Test filtering records by status - should be "pending" now
filter := "status = 'pending'"
pendingSystems, err := hub.FindRecordsByFilter("systems", filter, "-created", 0, 0, nil)
require.NoError(t, err)
assert.GreaterOrEqual(t, len(pendingSystems), 1)
})
t.Run("SystemStatusUpdate", func(t *testing.T) {
// Create a test system record
record, err := createTestSystem(t, hub, map[string]any{})
require.NoError(t, err)
// Add the record to the system manager
err = sm.AddRecord(record)
require.NoError(t, err)
// Test status changes
initialStatus := sm.GetSystemStatusFromStore(record.Id)
// Set a new status
sm.SetSystemStatusInDB(record.Id, "up")
// Verify status was updated
newStatus := sm.GetSystemStatusFromStore(record.Id)
assert.Equal(t, "up", newStatus, "System status should be updated to 'up'")
assert.NotEqual(t, initialStatus, newStatus, "Status should have changed")
// Verify the database was updated
updatedRecord, err := hub.FindRecordById("systems", record.Id)
require.NoError(t, err)
assert.Equal(t, "up", updatedRecord.Get("status"), "Database status should match")
})
t.Run("HandleSystemData", func(t *testing.T) {
// Create a test system record
record, err := createTestSystem(t, hub, map[string]any{})
require.NoError(t, err)
// Create test system data
testData := &system.CombinedData{
Info: system.Info{
Hostname: "data-test.example.com",
KernelVersion: "5.15.0-generic",
Cores: 4,
Threads: 8,
CpuModel: "Test CPU",
Uptime: 3600,
Cpu: 25.5,
MemPct: 40.2,
DiskPct: 60.0,
Bandwidth: 100.0,
AgentVersion: "1.0.0",
},
Stats: system.Stats{
Cpu: 25.5,
Mem: 16384.0,
MemUsed: 6553.6,
MemPct: 40.0,
DiskTotal: 1024000.0,
DiskUsed: 614400.0,
DiskPct: 60.0,
NetworkSent: 1024.0,
NetworkRecv: 2048.0,
},
Containers: []*container.Stats{},
}
// Test handling system data. todo: move to hub/alerts package tests
err = hub.HandleSystemAlerts(record, testData)
assert.NoError(t, err)
})
t.Run("ErrorHandling", func(t *testing.T) {
// Try to add a non-existent record
nonExistentId := "non_existent_id"
err := sm.RemoveSystem(nonExistentId)
assert.Error(t, err)
// Try to add a system with invalid host
system := &systems.System{
Host: "",
}
err = sm.AddSystem(system)
assert.Error(t, err)
})
t.Run("DeleteRecord", func(t *testing.T) {
var wg sync.WaitGroup
wg.Add(2)
runs := 0
hub.OnRecordUpdate("systems").BindFunc(func(e *core.RecordEvent) error {
runs++
record := e.Record
if record.GetString("name") == "deadflagblues" {
if runs == 1 {
assert.Equal(t, "up", e.Record.GetString("status"), "System status should be 'up'")
wg.Done()
} else if runs == 2 {
assert.Equal(t, "paused", e.Record.GetString("status"), "System status should be 'paused'")
wg.Done()
}
}
return e.Next()
})
// Create a test system record
record, err := createTestSystem(t, hub, map[string]any{
"name": "deadflagblues",
})
require.NoError(t, err)
// Verify the system exists
assert.True(t, sm.HasSystem(record.Id), "System should exist in the store")
// set the status manually to up
sm.SetSystemStatusInDB(record.Id, "up")
// verify the status is up
assert.Equal(t, "up", sm.GetSystemStatusFromStore(record.Id), "System status should be 'up'")
// Set the status to "paused" which should cause it to be deleted from the store
sm.SetSystemStatusInDB(record.Id, "paused")
wg.Wait()
// Verify the system no longer exists
assert.False(t, sm.HasSystem(record.Id), "System should not exist in the store after deletion")
})
t.Run("ConcurrentOperations", func(t *testing.T) {
// Create a test system
record, err := createTestSystem(t, hub, map[string]any{})
require.NoError(t, err)
// Run concurrent operations
const goroutines = 5
var wg sync.WaitGroup
wg.Add(goroutines)
for i := range goroutines {
go func(i int) {
defer wg.Done()
// Alternate between different operations
switch i % 3 {
case 0:
status := fmt.Sprintf("status-%d", i)
sm.SetSystemStatusInDB(record.Id, status)
case 1:
_ = sm.GetSystemStatusFromStore(record.Id)
case 2:
_, _ = sm.GetSystemHostPort(record.Id)
}
}(i)
}
wg.Wait()
// Verify system still exists and is in a valid state
assert.True(t, sm.HasSystem(record.Id), "System should still exist after concurrent operations")
status := sm.GetSystemStatusFromStore(record.Id)
assert.NotEmpty(t, status, "System should have a status after concurrent operations")
})
t.Run("ContextCancellation", func(t *testing.T) {
// Create a test system record
record, err := createTestSystem(t, hub, map[string]any{})
require.NoError(t, err)
// Verify the system exists in the store
assert.True(t, sm.HasSystem(record.Id), "System should exist in the store")
// Store the original context and cancel function
originalCtx, originalCancel, err := sm.GetSystemContextFromStore(record.Id)
assert.NoError(t, err)
// Ensure the context is not nil
assert.NotNil(t, originalCtx, "System context should not be nil")
assert.NotNil(t, originalCancel, "System cancel function should not be nil")
// Cancel the context
originalCancel()
// Wait a short time for cancellation to propagate
time.Sleep(10 * time.Millisecond)
// Verify the context is done
select {
case <-originalCtx.Done():
// Context was properly cancelled
default:
t.Fatal("Context was not cancelled")
}
// Verify the system is still in the store (cancellation shouldn't remove it)
assert.True(t, sm.HasSystem(record.Id), "System should still exist after context cancellation")
// Explicitly remove the system
err = sm.RemoveSystem(record.Id)
assert.NoError(t, err, "RemoveSystem should succeed")
// Verify the system is removed
assert.False(t, sm.HasSystem(record.Id), "System should be removed after RemoveSystem")
// Try to remove it again - should return an error
err = sm.RemoveSystem(record.Id)
assert.Error(t, err, "RemoveSystem should fail for non-existent system")
// Add the system back
err = sm.AddRecord(record)
require.NoError(t, err, "AddRecord should succeed")
// Verify the system is back in the store
assert.True(t, sm.HasSystem(record.Id), "System should exist after re-adding")
// Verify a new context was created
newCtx, newCancel, err := sm.GetSystemContextFromStore(record.Id)
assert.NoError(t, err)
assert.NotNil(t, newCtx, "New system context should not be nil")
assert.NotNil(t, newCancel, "New system cancel function should not be nil")
assert.NotEqual(t, originalCtx, newCtx, "New context should be different from original")
// Clean up
err = sm.RemoveSystem(record.Id)
assert.NoError(t, err)
})
}

View File

@@ -0,0 +1,117 @@
//go:build testing
// +build testing
package systems
import (
entities "beszel/internal/entities/system"
"context"
"fmt"
)
// GetSystemCount returns the number of systems in the store
func (sm *SystemManager) GetSystemCount() int {
return sm.systems.Length()
}
// HasSystem checks if a system with the given ID exists in the store
func (sm *SystemManager) HasSystem(systemID string) bool {
return sm.systems.Has(systemID)
}
// GetSystemStatusFromStore returns the status of a system with the given ID
// Returns an empty string if the system doesn't exist
func (sm *SystemManager) GetSystemStatusFromStore(systemID string) string {
sys, ok := sm.systems.GetOk(systemID)
if !ok {
return ""
}
return sys.Status
}
// GetSystemContextFromStore returns the context and cancel function for a system
func (sm *SystemManager) GetSystemContextFromStore(systemID string) (context.Context, context.CancelFunc, error) {
sys, ok := sm.systems.GetOk(systemID)
if !ok {
return nil, nil, fmt.Errorf("no system")
}
return sys.ctx, sys.cancel, nil
}
// GetSystemFromStore returns a store from the system
func (sm *SystemManager) GetSystemFromStore(systemID string) (*System, error) {
sys, ok := sm.systems.GetOk(systemID)
if !ok {
return nil, fmt.Errorf("no system")
}
return sys, nil
}
// GetAllSystemIDs returns a slice of all system IDs in the store
func (sm *SystemManager) GetAllSystemIDs() []string {
data := sm.systems.GetAll()
ids := make([]string, 0, len(data))
for id := range data {
ids = append(ids, id)
}
return ids
}
// GetSystemData returns the combined data for a system with the given ID
// Returns nil if the system doesn't exist
// This method is intended for testing
func (sm *SystemManager) GetSystemData(systemID string) *entities.CombinedData {
sys, ok := sm.systems.GetOk(systemID)
if !ok {
return nil
}
return sys.data
}
// GetSystemHostPort returns the host and port for a system with the given ID
// Returns empty strings if the system doesn't exist
func (sm *SystemManager) GetSystemHostPort(systemID string) (string, string) {
sys, ok := sm.systems.GetOk(systemID)
if !ok {
return "", ""
}
return sys.Host, sys.Port
}
// DisableAutoUpdater disables the automatic updater for a system
// This is intended for testing
// Returns false if the system doesn't exist
// func (sm *SystemManager) DisableAutoUpdater(systemID string) bool {
// sys, ok := sm.systems.GetOk(systemID)
// if !ok {
// return false
// }
// if sys.cancel != nil {
// sys.cancel()
// sys.cancel = nil
// }
// return true
// }
// SetSystemStatusInDB sets the status of a system directly and updates the database record
// This is intended for testing
// Returns false if the system doesn't exist
func (sm *SystemManager) SetSystemStatusInDB(systemID string, status string) bool {
if !sm.HasSystem(systemID) {
return false
}
// Update the database record
record, err := sm.hub.FindRecordById("systems", systemID)
if err != nil {
return false
}
record.Set("status", status)
err = sm.hub.Save(record)
if err != nil {
return false
}
return true
}

View File

@@ -4,14 +4,15 @@ package records
import (
"beszel/internal/entities/container"
"beszel/internal/entities/system"
"fmt"
"log"
"math"
"strings"
"time"
"github.com/goccy/go-json"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/types"
)
type RecordManager struct {
@@ -25,11 +26,6 @@ type LongerRecordData struct {
minShorterRecords int
}
type RecordDeletionData struct {
recordType string
retention time.Duration
}
type RecordStats []struct {
Stats []byte `db:"stats"`
}
@@ -39,7 +35,7 @@ func NewRecordManager(app core.App) *RecordManager {
}
// Create longer records by averaging shorter records
func (rm *RecordManager) CreateLongerRecords(collections []*core.Collection) {
func (rm *RecordManager) CreateLongerRecords() {
// start := time.Now()
longerRecordData := []LongerRecordData{
{
@@ -70,14 +66,24 @@ func (rm *RecordManager) CreateLongerRecords(collections []*core.Collection) {
}
// wrap the operations in a transaction
rm.app.RunInTransaction(func(txApp core.App) error {
activeSystems, err := txApp.FindAllRecords("systems", dbx.NewExp("status = 'up'"))
var err error
collections := [2]*core.Collection{}
collections[0], err = txApp.FindCachedCollectionByNameOrId("system_stats")
if err != nil {
log.Println("failed to get active systems", "err", err.Error())
return err
}
collections[1], err = txApp.FindCachedCollectionByNameOrId("container_stats")
if err != nil {
return err
}
var systems []struct {
Id string `db:"id"`
}
txApp.DB().NewQuery("SELECT id FROM systems WHERE status='up'").All(&systems)
// loop through all active systems, time periods, and collections
for _, system := range activeSystems {
for _, system := range systems {
// log.Println("processing system", system.GetString("name"))
for i := range longerRecordData {
recordData := longerRecordData[i]
@@ -92,7 +98,7 @@ func (rm *RecordManager) CreateLongerRecords(collections []*core.Collection) {
if recordData.longerType != "10m" {
lastLongerRecord, err := txApp.FindFirstRecordByFilter(
collection.Id,
"type = {:type} && system = {:system} && created > {:created}",
"system = {:system} && type = {:type} && created > {:created}",
dbx.Params{"type": recordData.longerType, "system": system.Id, "created": longerRecordPeriod},
)
// continue if longer record exists
@@ -108,7 +114,7 @@ func (rm *RecordManager) CreateLongerRecords(collections []*core.Collection) {
Select("stats").
From(collection.Name).
AndWhere(dbx.NewExp(
"type={:type} AND system={:system} AND created > {:created}",
"system={:system} AND type={:type} AND created > {:created}",
dbx.Params{
"type": recordData.shorterType,
"system": system.Id,
@@ -119,7 +125,6 @@ func (rm *RecordManager) CreateLongerRecords(collections []*core.Collection) {
// continue if not enough shorter records
if err != nil || len(stats) < recordData.minShorterRecords {
// log.Println("not enough shorter records. continue.", len(allShorterRecords), recordData.expectedShorterRecords)
continue
}
// average the shorter records and create longer record
@@ -133,7 +138,7 @@ func (rm *RecordManager) CreateLongerRecords(collections []*core.Collection) {
longerRecord.Set("stats", rm.AverageContainerStats(stats))
}
if err := txApp.SaveNoValidate(longerRecord); err != nil {
log.Println("failed to save longer record", "err", err.Error())
log.Println("failed to save longer record", "err", err)
}
}
}
@@ -146,16 +151,20 @@ func (rm *RecordManager) CreateLongerRecords(collections []*core.Collection) {
}
// Calculate the average stats of a list of system_stats records without reflect
func (rm *RecordManager) AverageSystemStats(records RecordStats) system.Stats {
sum := system.Stats{}
func (rm *RecordManager) AverageSystemStats(records RecordStats) *system.Stats {
sum := &system.Stats{}
count := float64(len(records))
// use different counter for temps in case some records don't have them
tempCount := float64(0)
var stats system.Stats
// Temporary struct for unmarshaling
stats := &system.Stats{}
// Accumulate totals
for i := range records {
stats = system.Stats{} // Zero the struct before unmarshalling
json.Unmarshal(records[i].Stats, &stats)
*stats = system.Stats{} // Reset tempStats for unmarshaling
if err := json.Unmarshal(records[i].Stats, stats); err != nil {
continue
}
sum.Cpu += stats.Cpu
sum.Mem += stats.Mem
sum.MemUsed += stats.MemUsed
@@ -171,26 +180,25 @@ func (rm *RecordManager) AverageSystemStats(records RecordStats) system.Stats {
sum.DiskWritePs += stats.DiskWritePs
sum.NetworkSent += stats.NetworkSent
sum.NetworkRecv += stats.NetworkRecv
// set peak values
// Set peak values
sum.MaxCpu = max(sum.MaxCpu, stats.MaxCpu, stats.Cpu)
sum.MaxNetworkSent = max(sum.MaxNetworkSent, stats.MaxNetworkSent, stats.NetworkSent)
sum.MaxNetworkRecv = max(sum.MaxNetworkRecv, stats.MaxNetworkRecv, stats.NetworkRecv)
sum.MaxDiskReadPs = max(sum.MaxDiskReadPs, stats.MaxDiskReadPs, stats.DiskReadPs)
sum.MaxDiskWritePs = max(sum.MaxDiskWritePs, stats.MaxDiskWritePs, stats.DiskWritePs)
// add temps to sum
// Accumulate temperatures
if stats.Temperatures != nil {
if sum.Temperatures == nil {
sum.Temperatures = make(map[string]float64, len(stats.Temperatures))
}
tempCount++
for key, value := range stats.Temperatures {
if _, ok := sum.Temperatures[key]; !ok {
sum.Temperatures[key] = 0
}
sum.Temperatures[key] += value
}
}
// add extra fs to sum
// Accumulate extra filesystem stats
if stats.ExtraFs != nil {
if sum.ExtraFs == nil {
sum.ExtraFs = make(map[string]*system.FsStats, len(stats.ExtraFs))
@@ -199,25 +207,26 @@ func (rm *RecordManager) AverageSystemStats(records RecordStats) system.Stats {
if _, ok := sum.ExtraFs[key]; !ok {
sum.ExtraFs[key] = &system.FsStats{}
}
sum.ExtraFs[key].DiskTotal += value.DiskTotal
sum.ExtraFs[key].DiskUsed += value.DiskUsed
sum.ExtraFs[key].DiskWritePs += value.DiskWritePs
sum.ExtraFs[key].DiskReadPs += value.DiskReadPs
// peak values
sum.ExtraFs[key].MaxDiskReadPS = max(sum.ExtraFs[key].MaxDiskReadPS, value.MaxDiskReadPS, value.DiskReadPs)
sum.ExtraFs[key].MaxDiskWritePS = max(sum.ExtraFs[key].MaxDiskWritePS, value.MaxDiskWritePS, value.DiskWritePs)
fs := sum.ExtraFs[key]
fs.DiskTotal += value.DiskTotal
fs.DiskUsed += value.DiskUsed
fs.DiskWritePs += value.DiskWritePs
fs.DiskReadPs += value.DiskReadPs
fs.MaxDiskReadPS = max(fs.MaxDiskReadPS, value.MaxDiskReadPS, value.DiskReadPs)
fs.MaxDiskWritePS = max(fs.MaxDiskWritePS, value.MaxDiskWritePS, value.DiskWritePs)
}
}
// add GPU data
// Accumulate GPU data
if stats.GPUData != nil {
if sum.GPUData == nil {
sum.GPUData = make(map[string]system.GPUData, len(stats.GPUData))
}
for id, value := range stats.GPUData {
if _, ok := sum.GPUData[id]; !ok {
sum.GPUData[id] = system.GPUData{Name: value.Name}
gpu, ok := sum.GPUData[id]
if !ok {
gpu = system.GPUData{Name: value.Name}
}
gpu := sum.GPUData[id]
gpu.Temperature += value.Temperature
gpu.MemoryUsed += value.MemoryUsed
gpu.MemoryTotal += value.MemoryTotal
@@ -229,76 +238,67 @@ func (rm *RecordManager) AverageSystemStats(records RecordStats) system.Stats {
}
}
stats = system.Stats{
Cpu: twoDecimals(sum.Cpu / count),
Mem: twoDecimals(sum.Mem / count),
MemUsed: twoDecimals(sum.MemUsed / count),
MemPct: twoDecimals(sum.MemPct / count),
MemBuffCache: twoDecimals(sum.MemBuffCache / count),
MemZfsArc: twoDecimals(sum.MemZfsArc / count),
Swap: twoDecimals(sum.Swap / count),
SwapUsed: twoDecimals(sum.SwapUsed / count),
DiskTotal: twoDecimals(sum.DiskTotal / count),
DiskUsed: twoDecimals(sum.DiskUsed / count),
DiskPct: twoDecimals(sum.DiskPct / count),
DiskReadPs: twoDecimals(sum.DiskReadPs / count),
DiskWritePs: twoDecimals(sum.DiskWritePs / count),
NetworkSent: twoDecimals(sum.NetworkSent / count),
NetworkRecv: twoDecimals(sum.NetworkRecv / count),
MaxCpu: sum.MaxCpu,
MaxDiskReadPs: sum.MaxDiskReadPs,
MaxDiskWritePs: sum.MaxDiskWritePs,
MaxNetworkSent: sum.MaxNetworkSent,
MaxNetworkRecv: sum.MaxNetworkRecv,
}
// Compute averages in place
if count > 0 {
sum.Cpu = twoDecimals(sum.Cpu / count)
sum.Mem = twoDecimals(sum.Mem / count)
sum.MemUsed = twoDecimals(sum.MemUsed / count)
sum.MemPct = twoDecimals(sum.MemPct / count)
sum.MemBuffCache = twoDecimals(sum.MemBuffCache / count)
sum.MemZfsArc = twoDecimals(sum.MemZfsArc / count)
sum.Swap = twoDecimals(sum.Swap / count)
sum.SwapUsed = twoDecimals(sum.SwapUsed / count)
sum.DiskTotal = twoDecimals(sum.DiskTotal / count)
sum.DiskUsed = twoDecimals(sum.DiskUsed / count)
sum.DiskPct = twoDecimals(sum.DiskPct / count)
sum.DiskReadPs = twoDecimals(sum.DiskReadPs / count)
sum.DiskWritePs = twoDecimals(sum.DiskWritePs / count)
sum.NetworkSent = twoDecimals(sum.NetworkSent / count)
sum.NetworkRecv = twoDecimals(sum.NetworkRecv / count)
if sum.Temperatures != nil {
stats.Temperatures = make(map[string]float64, len(sum.Temperatures))
for key, value := range sum.Temperatures {
stats.Temperatures[key] = twoDecimals(value / tempCount)
// Average temperatures
if sum.Temperatures != nil && tempCount > 0 {
for key := range sum.Temperatures {
sum.Temperatures[key] = twoDecimals(sum.Temperatures[key] / tempCount)
}
}
}
if sum.ExtraFs != nil {
stats.ExtraFs = make(map[string]*system.FsStats, len(sum.ExtraFs))
for key, value := range sum.ExtraFs {
stats.ExtraFs[key] = &system.FsStats{
DiskTotal: twoDecimals(value.DiskTotal / count),
DiskUsed: twoDecimals(value.DiskUsed / count),
DiskWritePs: twoDecimals(value.DiskWritePs / count),
DiskReadPs: twoDecimals(value.DiskReadPs / count),
MaxDiskReadPS: value.MaxDiskReadPS,
MaxDiskWritePS: value.MaxDiskWritePS,
// Average extra filesystem stats
if sum.ExtraFs != nil {
for key := range sum.ExtraFs {
fs := sum.ExtraFs[key]
fs.DiskTotal = twoDecimals(fs.DiskTotal / count)
fs.DiskUsed = twoDecimals(fs.DiskUsed / count)
fs.DiskWritePs = twoDecimals(fs.DiskWritePs / count)
fs.DiskReadPs = twoDecimals(fs.DiskReadPs / count)
}
}
// Average GPU data
if sum.GPUData != nil {
for id := range sum.GPUData {
gpu := sum.GPUData[id]
gpu.Temperature = twoDecimals(gpu.Temperature / count)
gpu.MemoryUsed = twoDecimals(gpu.MemoryUsed / count)
gpu.MemoryTotal = twoDecimals(gpu.MemoryTotal / count)
gpu.Usage = twoDecimals(gpu.Usage / count)
gpu.Power = twoDecimals(gpu.Power / count)
gpu.Count = twoDecimals(gpu.Count / count)
sum.GPUData[id] = gpu
}
}
}
if sum.GPUData != nil {
stats.GPUData = make(map[string]system.GPUData, len(sum.GPUData))
for id, value := range sum.GPUData {
stats.GPUData[id] = system.GPUData{
Name: value.Name,
Temperature: twoDecimals(value.Temperature / count),
MemoryUsed: twoDecimals(value.MemoryUsed / count),
MemoryTotal: twoDecimals(value.MemoryTotal / count),
Usage: twoDecimals(value.Usage / count),
Power: twoDecimals(value.Power / count),
Count: twoDecimals(value.Count / count),
}
}
}
return stats
return sum
}
// Calculate the average stats of a list of container_stats records
func (rm *RecordManager) AverageContainerStats(records RecordStats) []container.Stats {
sums := make(map[string]*container.Stats)
count := float64(len(records))
var containerStats []container.Stats
containerStats := make([]container.Stats, 0, 50)
for i := range records {
// Reset the slice length to 0, but keep the capacity
// reset slice
containerStats = containerStats[:0]
if err := json.Unmarshal(records[i].Stats, &containerStats); err != nil {
return []container.Stats{}
@@ -330,38 +330,45 @@ func (rm *RecordManager) AverageContainerStats(records RecordStats) []container.
// Deletes records older than what is displayed in the UI
func (rm *RecordManager) DeleteOldRecords() {
// Define the collections to process
collections := []string{"system_stats", "container_stats"}
recordData := []RecordDeletionData{
{
recordType: "1m",
retention: time.Hour,
},
{
recordType: "10m",
retention: 12 * time.Hour,
},
{
recordType: "20m",
retention: 24 * time.Hour,
},
{
recordType: "120m",
retention: 7 * 24 * time.Hour,
},
{
recordType: "480m",
retention: 30 * 24 * time.Hour,
},
// Define record types and their retention periods
type RecordDeletionData struct {
recordType string
retention time.Duration
}
db := rm.app.NonconcurrentDB()
for _, recordData := range recordData {
for _, collectionSlug := range collections {
formattedDate := time.Now().UTC().Add(-recordData.retention).Format(types.DefaultDateLayout)
expr := dbx.NewExp("[[created]] < {:date} AND [[type]] = {:type}", dbx.Params{"date": formattedDate, "type": recordData.recordType})
_, err := db.Delete(collectionSlug, expr).Execute()
if err != nil {
rm.app.Logger().Error("Failed to delete records", "err", err.Error())
}
recordData := []RecordDeletionData{
{recordType: "1m", retention: time.Hour}, // 1 hour
{recordType: "10m", retention: 12 * time.Hour}, // 12 hours
{recordType: "20m", retention: 24 * time.Hour}, // 1 day
{recordType: "120m", retention: 7 * 24 * time.Hour}, // 7 days
{recordType: "480m", retention: 30 * 24 * time.Hour}, // 30 days
}
// Process each collection
for _, collection := range collections {
// Build the WHERE clause dynamically
var conditionParts []string
var params dbx.Params = make(map[string]any)
for i, rd := range recordData {
// Create parameterized condition for this record type
dateParam := fmt.Sprintf("date%d", i)
conditionParts = append(conditionParts, fmt.Sprintf("(type = '%s' AND created < {:%s})", rd.recordType, dateParam))
params[dateParam] = time.Now().UTC().Add(-rd.retention)
}
// Combine conditions with OR
conditionStr := strings.Join(conditionParts, " OR ")
// Construct the full raw query
rawQuery := fmt.Sprintf("DELETE FROM %s WHERE %s", collection, conditionStr)
// Execute the query with parameters
if _, err := rm.app.DB().NewQuery(rawQuery).Bind(params).Execute(); err != nil {
// return fmt.Errorf("failed to delete from %s: %v", collection, err)
rm.app.Logger().Error("failed to delete", "collection", collection, "error", err)
}
}
}

View File

@@ -0,0 +1,58 @@
// Package tests provides helpers for testing the application.
package tests
import (
"beszel/internal/hub"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tests"
_ "github.com/pocketbase/pocketbase/migrations"
)
// TestHub is a wrapper hub instance used for testing.
type TestHub struct {
core.App
*tests.TestApp
*hub.Hub
}
// NewTestHub creates and initializes a test application instance.
//
// It is the caller's responsibility to call app.Cleanup() when the app is no longer needed.
func NewTestHub(optTestDataDir ...string) (*TestHub, error) {
var testDataDir string
if len(optTestDataDir) > 0 {
testDataDir = optTestDataDir[0]
}
return NewTestHubWithConfig(core.BaseAppConfig{
DataDir: testDataDir,
EncryptionEnv: "pb_test_env",
})
}
// NewTestHubWithConfig creates and initializes a test application instance
// from the provided config.
//
// If config.DataDir is not set it fallbacks to the default internal test data directory.
//
// config.DataDir is cloned for each new test application instance.
//
// It is the caller's responsibility to call app.Cleanup() when the app is no longer needed.
func NewTestHubWithConfig(config core.BaseAppConfig) (*TestHub, error) {
testApp, err := tests.NewTestAppWithConfig(config)
if err != nil {
return nil, err
}
hub := hub.NewHub(testApp)
t := &TestHub{
App: testApp,
TestApp: testApp,
Hub: hub,
}
return t, nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,98 +0,0 @@
package migrations
import (
"encoding/json"
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
)
func init() {
m.Register(func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("_pb_users_auth_")
if err != nil {
return err
}
// update collection data
if err := json.Unmarshal([]byte(`{
"indexes": [
"CREATE UNIQUE INDEX ` + "`" + `__pb_users_auth__email_idx` + "`" + ` ON ` + "`" + `users` + "`" + ` (` + "`" + `email` + "`" + `) WHERE ` + "`" + `email` + "`" + ` != ''",
"CREATE UNIQUE INDEX ` + "`" + `__pb_users_auth__tokenKey_idx` + "`" + ` ON ` + "`" + `users` + "`" + ` (` + "`" + `tokenKey` + "`" + `)"
]
}`), &collection); err != nil {
return err
}
// remove field
collection.Fields.RemoveById("text4166911607")
// update field
if err := collection.Fields.AddMarshaledJSONAt(3, []byte(`{
"exceptDomains": null,
"hidden": false,
"id": "email3885137012",
"name": "email",
"onlyDomains": null,
"presentable": false,
"required": true,
"system": true,
"type": "email"
}`)); err != nil {
return err
}
return app.Save(collection)
}, func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("_pb_users_auth_")
if err != nil {
return err
}
// update collection data
if err := json.Unmarshal([]byte(`{
"indexes": [
"CREATE UNIQUE INDEX ` + "`" + `__pb_users_auth__username_idx` + "`" + ` ON ` + "`" + `users` + "`" + ` (username COLLATE NOCASE)",
"CREATE UNIQUE INDEX ` + "`" + `__pb_users_auth__email_idx` + "`" + ` ON ` + "`" + `users` + "`" + ` (` + "`" + `email` + "`" + `) WHERE ` + "`" + `email` + "`" + ` != ''",
"CREATE UNIQUE INDEX ` + "`" + `__pb_users_auth__tokenKey_idx` + "`" + ` ON ` + "`" + `users` + "`" + ` (` + "`" + `tokenKey` + "`" + `)"
]
}`), &collection); err != nil {
return err
}
// add field
if err := collection.Fields.AddMarshaledJSONAt(6, []byte(`{
"autogeneratePattern": "users[0-9]{6}",
"hidden": false,
"id": "text4166911607",
"max": 150,
"min": 3,
"name": "username",
"pattern": "^[\\w][\\w\\.\\-]*$",
"presentable": false,
"primaryKey": false,
"required": true,
"system": false,
"type": "text"
}`)); err != nil {
return err
}
// update field
if err := collection.Fields.AddMarshaledJSONAt(3, []byte(`{
"exceptDomains": null,
"hidden": false,
"id": "email3885137012",
"name": "email",
"onlyDomains": null,
"presentable": false,
"required": false,
"system": true,
"type": "email"
}`)); err != nil {
return err
}
return app.Save(collection)
})
}

View File

@@ -0,0 +1,676 @@
package migrations
import (
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
)
func init() {
m.Register(func(app core.App) error {
// delete duplicate alerts
app.DB().NewQuery(`
DELETE FROM alerts
WHERE rowid NOT IN (
SELECT MAX(rowid)
FROM alerts
GROUP BY user, system, name
);
`).Execute()
// import collections
jsonData := `[
{
"id": "elngm8x1l60zi2v",
"listRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
"viewRule": "",
"createRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
"updateRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
"deleteRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
"name": "alerts",
"type": "base",
"fields": [
{
"autogeneratePattern": "[a-z0-9]{15}",
"hidden": false,
"id": "text3208210256",
"max": 15,
"min": 15,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"cascadeDelete": true,
"collectionId": "_pb_users_auth_",
"hidden": false,
"id": "hn5ly3vi",
"maxSelect": 1,
"minSelect": 0,
"name": "user",
"presentable": false,
"required": true,
"system": false,
"type": "relation"
},
{
"cascadeDelete": true,
"collectionId": "2hz5ncl8tizk5nx",
"hidden": false,
"id": "g5sl3jdg",
"maxSelect": 1,
"minSelect": 0,
"name": "system",
"presentable": false,
"required": true,
"system": false,
"type": "relation"
},
{
"hidden": false,
"id": "zj3ingrv",
"maxSelect": 1,
"name": "name",
"presentable": false,
"required": true,
"system": false,
"type": "select",
"values": [
"Status",
"CPU",
"Memory",
"Disk",
"Temperature",
"Bandwidth"
]
},
{
"hidden": false,
"id": "o2ablxvn",
"max": null,
"min": null,
"name": "value",
"onlyInt": false,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{
"hidden": false,
"id": "fstdehcq",
"max": 60,
"min": null,
"name": "min",
"onlyInt": true,
"presentable": false,
"required": false,
"system": false,
"type": "number"
},
{
"hidden": false,
"id": "6hgdf6hs",
"name": "triggered",
"presentable": false,
"required": false,
"system": false,
"type": "bool"
},
{
"hidden": false,
"id": "autodate2990389176",
"name": "created",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
},
{
"hidden": false,
"id": "autodate3332085495",
"name": "updated",
"onCreate": true,
"onUpdate": true,
"presentable": false,
"system": false,
"type": "autodate"
}
],
"indexes": [
"CREATE UNIQUE INDEX ` + "`" + `idx_MnhEt21L5r` + "`" + ` ON ` + "`" + `alerts` + "`" + ` (\n ` + "`" + `user` + "`" + `,\n ` + "`" + `system` + "`" + `,\n ` + "`" + `name` + "`" + `\n)"
],
"system": false
},
{
"id": "juohu4jipgc13v7",
"listRule": "@request.auth.id != \"\"",
"viewRule": null,
"createRule": null,
"updateRule": null,
"deleteRule": null,
"name": "container_stats",
"type": "base",
"fields": [
{
"autogeneratePattern": "[a-z0-9]{15}",
"hidden": false,
"id": "text3208210256",
"max": 15,
"min": 15,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"cascadeDelete": true,
"collectionId": "2hz5ncl8tizk5nx",
"hidden": false,
"id": "hutcu6ps",
"maxSelect": 1,
"minSelect": 0,
"name": "system",
"presentable": false,
"required": true,
"system": false,
"type": "relation"
},
{
"hidden": false,
"id": "r39hhnil",
"maxSize": 2000000,
"name": "stats",
"presentable": false,
"required": true,
"system": false,
"type": "json"
},
{
"hidden": false,
"id": "vo7iuj96",
"maxSelect": 1,
"name": "type",
"presentable": false,
"required": true,
"system": false,
"type": "select",
"values": [
"1m",
"10m",
"20m",
"120m",
"480m"
]
},
{
"hidden": false,
"id": "autodate2990389176",
"name": "created",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
},
{
"hidden": false,
"id": "autodate3332085495",
"name": "updated",
"onCreate": true,
"onUpdate": true,
"presentable": false,
"system": false,
"type": "autodate"
}
],
"indexes": [
"CREATE INDEX ` + "`" + `idx_d87OiXGZD8` + "`" + ` ON ` + "`" + `container_stats` + "`" + ` (\n ` + "`" + `system` + "`" + `,\n ` + "`" + `type` + "`" + `,\n ` + "`" + `created` + "`" + `\n)"
],
"system": false
},
{
"id": "ej9oowivz8b2mht",
"listRule": "@request.auth.id != \"\"",
"viewRule": null,
"createRule": null,
"updateRule": null,
"deleteRule": null,
"name": "system_stats",
"type": "base",
"fields": [
{
"autogeneratePattern": "[a-z0-9]{15}",
"hidden": false,
"id": "text3208210256",
"max": 15,
"min": 15,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"cascadeDelete": true,
"collectionId": "2hz5ncl8tizk5nx",
"hidden": false,
"id": "h9sg148r",
"maxSelect": 1,
"minSelect": 0,
"name": "system",
"presentable": false,
"required": true,
"system": false,
"type": "relation"
},
{
"hidden": false,
"id": "azftn0be",
"maxSize": 2000000,
"name": "stats",
"presentable": false,
"required": true,
"system": false,
"type": "json"
},
{
"hidden": false,
"id": "m1ekhli3",
"maxSelect": 1,
"name": "type",
"presentable": false,
"required": true,
"system": false,
"type": "select",
"values": [
"1m",
"10m",
"20m",
"120m",
"480m"
]
},
{
"hidden": false,
"id": "autodate2990389176",
"name": "created",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
},
{
"hidden": false,
"id": "autodate3332085495",
"name": "updated",
"onCreate": true,
"onUpdate": true,
"presentable": false,
"system": false,
"type": "autodate"
}
],
"indexes": [
"CREATE INDEX ` + "`" + `idx_GxIee0j` + "`" + ` ON ` + "`" + `system_stats` + "`" + ` (\n ` + "`" + `system` + "`" + `,\n ` + "`" + `type` + "`" + `,\n ` + "`" + `created` + "`" + `\n)"
],
"system": false
},
{
"id": "4afacsdnlu8q8r2",
"listRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
"viewRule": null,
"createRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
"updateRule": "@request.auth.id != \"\" && user.id = @request.auth.id",
"deleteRule": null,
"name": "user_settings",
"type": "base",
"fields": [
{
"autogeneratePattern": "[a-z0-9]{15}",
"hidden": false,
"id": "text3208210256",
"max": 15,
"min": 15,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"cascadeDelete": true,
"collectionId": "_pb_users_auth_",
"hidden": false,
"id": "d5vztyxa",
"maxSelect": 1,
"minSelect": 0,
"name": "user",
"presentable": false,
"required": true,
"system": false,
"type": "relation"
},
{
"hidden": false,
"id": "xcx4qgqq",
"maxSize": 2000000,
"name": "settings",
"presentable": false,
"required": false,
"system": false,
"type": "json"
},
{
"hidden": false,
"id": "autodate2990389176",
"name": "created",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
},
{
"hidden": false,
"id": "autodate3332085495",
"name": "updated",
"onCreate": true,
"onUpdate": true,
"presentable": false,
"system": false,
"type": "autodate"
}
],
"indexes": [
"CREATE UNIQUE INDEX ` + "`" + `idx_30Lwgf2` + "`" + ` ON ` + "`" + `user_settings` + "`" + ` (` + "`" + `user` + "`" + `)"
],
"system": false
},
{
"id": "2hz5ncl8tizk5nx",
"listRule": "@request.auth.id != \"\" && users.id ?= @request.auth.id",
"viewRule": "@request.auth.id != \"\" && users.id ?= @request.auth.id",
"createRule": "@request.auth.id != \"\" && users.id ?= @request.auth.id && @request.auth.role != \"readonly\"",
"updateRule": "@request.auth.id != \"\" && users.id ?= @request.auth.id && @request.auth.role != \"readonly\"",
"deleteRule": "@request.auth.id != \"\" && users.id ?= @request.auth.id && @request.auth.role != \"readonly\"",
"name": "systems",
"type": "base",
"fields": [
{
"autogeneratePattern": "[a-z0-9]{15}",
"hidden": false,
"id": "text3208210256",
"max": 15,
"min": 15,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "7xloxkwk",
"max": 0,
"min": 0,
"name": "name",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": true,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "waj7seaf",
"maxSelect": 1,
"name": "status",
"presentable": false,
"required": false,
"system": false,
"type": "select",
"values": [
"up",
"down",
"paused",
"pending"
]
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "ve781smf",
"max": 0,
"min": 0,
"name": "host",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": true,
"system": false,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "pij0k2jk",
"max": 0,
"min": 0,
"name": "port",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "qoq64ntl",
"maxSize": 2000000,
"name": "info",
"presentable": false,
"required": false,
"system": false,
"type": "json"
},
{
"cascadeDelete": true,
"collectionId": "_pb_users_auth_",
"hidden": false,
"id": "jcarjnjj",
"maxSelect": 2147483647,
"minSelect": 0,
"name": "users",
"presentable": false,
"required": true,
"system": false,
"type": "relation"
},
{
"hidden": false,
"id": "autodate2990389176",
"name": "created",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
},
{
"hidden": false,
"id": "autodate3332085495",
"name": "updated",
"onCreate": true,
"onUpdate": true,
"presentable": false,
"system": false,
"type": "autodate"
}
],
"indexes": [],
"system": false
},
{
"id": "_pb_users_auth_",
"listRule": "id = @request.auth.id",
"viewRule": "id = @request.auth.id",
"createRule": null,
"updateRule": null,
"deleteRule": null,
"name": "users",
"type": "auth",
"fields": [
{
"autogeneratePattern": "[a-z0-9]{15}",
"hidden": false,
"id": "text3208210256",
"max": 15,
"min": 15,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"cost": 10,
"hidden": true,
"id": "password901924565",
"max": 0,
"min": 8,
"name": "password",
"pattern": "",
"presentable": false,
"required": true,
"system": true,
"type": "password"
},
{
"autogeneratePattern": "[a-zA-Z0-9_]{50}",
"hidden": true,
"id": "text2504183744",
"max": 60,
"min": 30,
"name": "tokenKey",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": true,
"system": true,
"type": "text"
},
{
"exceptDomains": null,
"hidden": false,
"id": "email3885137012",
"name": "email",
"onlyDomains": null,
"presentable": false,
"required": true,
"system": true,
"type": "email"
},
{
"hidden": false,
"id": "bool1547992806",
"name": "emailVisibility",
"presentable": false,
"required": false,
"system": true,
"type": "bool"
},
{
"hidden": false,
"id": "bool256245529",
"name": "verified",
"presentable": false,
"required": false,
"system": true,
"type": "bool"
},
{
"autogeneratePattern": "users[0-9]{6}",
"hidden": false,
"id": "text4166911607",
"max": 150,
"min": 3,
"name": "username",
"pattern": "^[\\w][\\w\\.\\-]*$",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "qkbp58ae",
"maxSelect": 1,
"name": "role",
"presentable": false,
"required": false,
"system": false,
"type": "select",
"values": [
"user",
"admin",
"readonly"
]
},
{
"hidden": false,
"id": "autodate2990389176",
"name": "created",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
},
{
"hidden": false,
"id": "autodate3332085495",
"name": "updated",
"onCreate": true,
"onUpdate": true,
"presentable": false,
"system": false,
"type": "autodate"
}
],
"indexes": [
"CREATE UNIQUE INDEX ` + "`" + `__pb_users_auth__username_idx` + "`" + ` ON ` + "`" + `users` + "`" + ` (username COLLATE NOCASE)",
"CREATE UNIQUE INDEX ` + "`" + `__pb_users_auth__email_idx` + "`" + ` ON ` + "`" + `users` + "`" + ` (` + "`" + `email` + "`" + `) WHERE ` + "`" + `email` + "`" + ` != ''",
"CREATE UNIQUE INDEX ` + "`" + `__pb_users_auth__tokenKey_idx` + "`" + ` ON ` + "`" + `users` + "`" + ` (` + "`" + `tokenKey` + "`" + `)"
],
"system": false,
"authRule": "verified=true",
"manageRule": null
}
]`
return app.ImportCollectionsByMarshaledJSON([]byte(jsonData), false)
}, func(app core.App) error {
return nil
})
}

Binary file not shown.

View File

@@ -6,7 +6,12 @@
<link rel="icon" type="image/svg+xml" href="./static/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Beszel</title>
<script>window.BASE_PATH = "%BASE_URL%"</script>
<script>
globalThis.BESZEL = {
BASE_PATH: "%BASE_URL%",
HUB_VERSION: "{{V}}"
}
</script>
</head>
<body>
<div id="app"></div>

View File

@@ -1,6 +1,6 @@
import type { LinguiConfig } from "@lingui/conf"
import { defineConfig } from "@lingui/cli"
const config: LinguiConfig = {
export default defineConfig({
locales: [
"en",
"ar",
@@ -33,12 +33,13 @@ const config: LinguiConfig = {
],
sourceLocale: "en",
compileNamespace: "ts",
formatOptions: {
lineNumbers: false,
},
catalogs: [
{
path: "<rootDir>/src/locales/{locale}/{locale}",
include: ["src"],
},
],
}
export default config
})

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "beszel",
"private": true,
"version": "0.0.0",
"version": "0.11.0",
"type": "module",
"scripts": {
"dev": "vite",
@@ -12,9 +12,10 @@
},
"dependencies": {
"@henrygd/queue": "^1.0.7",
"@lingui/detect-locale": "^4.14.1",
"@lingui/macro": "^4.14.1",
"@lingui/react": "^4.14.1",
"@henrygd/semaphore": "^0.0.2",
"@lingui/detect-locale": "^5.2.0",
"@lingui/macro": "^5.2.0",
"@lingui/react": "^5.2.0",
"@nanostores/react": "^0.7.3",
"@nanostores/router": "^0.11.0",
"@radix-ui/react-alert-dialog": "^1.1.6",
@@ -31,35 +32,35 @@
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-toast": "^1.2.6",
"@radix-ui/react-tooltip": "^1.1.8",
"@tanstack/react-table": "^8.20.6",
"@tanstack/react-table": "^8.21.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.0.4",
"d3-time": "^3.1.0",
"lucide-react": "^0.452.0",
"nanostores": "^0.11.3",
"pocketbase": "^0.25.1",
"nanostores": "^0.11.4",
"pocketbase": "^0.25.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"recharts": "^2.15.1",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
"valibot": "^0.36.0"
"valibot": "^0.42.0"
},
"devDependencies": {
"@lingui/cli": "^4.14.1",
"@lingui/swc-plugin": "^4.1.0",
"@lingui/vite-plugin": "^4.14.1",
"@types/bun": "^1.2.2",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"@vitejs/plugin-react-swc": "^3.7.2",
"@lingui/cli": "^5.2.0",
"@lingui/swc-plugin": "^5.5.0",
"@lingui/vite-plugin": "^5.2.0",
"@types/bun": "^1.2.4",
"@types/react": "^18.3.1",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react-swc": "^3.8.0",
"autoprefixer": "^10.4.20",
"postcss": "^8.5.1",
"postcss": "^8.5.3",
"tailwindcss": "^3.4.17",
"tailwindcss-rtl": "^0.9.0",
"typescript": "^5.7.3",
"vite": "^5.4.14"
"typescript": "^5.8.2",
"vite": "^6.2.0"
},
"overrides": {
"@nanostores/router": {
@@ -69,4 +70,4 @@
"optionalDependencies": {
"@esbuild/linux-arm64": "^0.21.5"
}
}
}

View File

@@ -1,3 +1,5 @@
import { Trans } from "@lingui/react/macro"
import { t } from "@lingui/core/macro"
import { Button } from "@/components/ui/button"
import {
Dialog,
@@ -14,15 +16,15 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/comp
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { $publicKey, pb } from "@/lib/stores"
import { cn, copyToClipboard, isReadOnlyUser } from "@/lib/utils"
import { cn, copyToClipboard, isReadOnlyUser, useLocalStorage } from "@/lib/utils"
import { i18n } from "@lingui/core"
import { t, Trans } from "@lingui/macro"
import { useStore } from "@nanostores/react"
import { ChevronDownIcon, Copy, PlusIcon } from "lucide-react"
import { ChevronDownIcon, Copy, ExternalLinkIcon, PlusIcon } from "lucide-react"
import { memo, useRef, useState } from "react"
import { basePath, navigate } from "./router"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "./ui/dropdown-menu"
import { SystemRecord } from "@/types"
import { AppleIcon, DockerIcon, TuxIcon, WindowsIcon } from "./ui/icons"
export function AddSystemButton({ className }: { className?: string }) {
const [open, setOpen] = useState(false)
@@ -61,25 +63,33 @@ function copyDockerCompose(port = "45876", publicKey: string) {
# monitor other disks / partitions by mounting a folder in /extra-filesystems
# - /mnt/disk/.beszel:/extra-filesystems/sda1:ro
environment:
PORT: ${port}
LISTEN: ${port}
KEY: "${publicKey}"`)
}
function copyDockerRun(port = "45876", publicKey: string) {
copyToClipboard(
`docker run -d --name beszel-agent --network host --restart unless-stopped -v /var/run/docker.sock:/var/run/docker.sock:ro -e KEY="${publicKey}" -e PORT=${port} henrygd/beszel-agent:latest`
`docker run -d --name beszel-agent --network host --restart unless-stopped -v /var/run/docker.sock:/var/run/docker.sock:ro -e KEY="${publicKey}" -e LISTEN=${port} henrygd/beszel-agent:latest`
)
}
function copyInstallCommand(port = "45876", publicKey: string) {
let cmd = `curl -sL https://raw.githubusercontent.com/henrygd/beszel/main/supplemental/scripts/install-agent.sh -o install-agent.sh && chmod +x install-agent.sh && ./install-agent.sh -p ${port} -k "${publicKey}"`
// add china mirrors flag if zh-CN
if ((i18n.locale + navigator.language).includes("zh-CN")) {
function copyLinuxCommand(port = "45876", publicKey: string, brew = false) {
let cmd = `curl -sL https://get.beszel.dev${
brew ? "/brew" : ""
} -o /tmp/install-agent.sh && chmod +x /tmp/install-agent.sh && /tmp/install-agent.sh -p ${port} -k "${publicKey}"`
// brew script does not support --china-mirrors
if (!brew && (i18n.locale + navigator.language).includes("zh-CN")) {
cmd += ` --china-mirrors`
}
copyToClipboard(cmd)
}
function copyWindowsCommand(port = "45876", publicKey: string) {
copyToClipboard(
`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser; & iwr -useb https://get.beszel.dev -OutFile "$env:TEMP\install-agent.ps1"; & "$env:TEMP\install-agent.ps1" -Key "${publicKey}" -Port ${port}`
)
}
/**
* SystemDialog component for adding or editing a system.
* @param {Object} props - The component props.
@@ -91,6 +101,7 @@ export const SystemDialog = memo(({ setOpen, system }: { setOpen: (open: boolean
const port = useRef<HTMLInputElement>(null)
const [hostValue, setHostValue] = useState(system?.host ?? "")
const isUnixSocket = hostValue.startsWith("/")
const [tab, setTab] = useLocalStorage("as-tab", "docker")
async function handleSubmit(e: SubmitEvent) {
e.preventDefault()
@@ -118,7 +129,7 @@ export const SystemDialog = memo(({ setOpen, system }: { setOpen: (open: boolean
setHostValue(system?.host ?? "")
}}
>
<Tabs defaultValue="docker">
<Tabs defaultValue={tab} onValueChange={setTab}>
<DialogHeader>
<DialogTitle className="mb-2">
{system ? `${t`Edit`} ${system?.name}` : <Trans>Add New System</Trans>}
@@ -140,7 +151,7 @@ export const SystemDialog = memo(({ setOpen, system }: { setOpen: (open: boolean
</DialogDescription>
</TabsContent>
{/* Binary */}
<TabsContent value="binary">
<TabsContent value="binary" tabIndex={-1}>
<DialogDescription className="mb-4 leading-normal w-0 min-w-full">
<Trans>
The agent must be running on the system to connect. Copy the installation command for the agent below.
@@ -195,7 +206,7 @@ export const SystemDialog = memo(({ setOpen, system }: { setOpen: (open: boolean
className="absolute end-0 top-0"
onClick={() => copyToClipboard(publicKey)}
>
<Copy className="h-4 w-4 " />
<Copy className="size-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
@@ -211,19 +222,41 @@ export const SystemDialog = memo(({ setOpen, system }: { setOpen: (open: boolean
{/* Docker */}
<TabsContent value="docker" className="contents">
<CopyButton
text={t`Copy` + " docker compose"}
text={t({ message: "Copy docker compose", context: "Button to copy docker compose file content" })}
onClick={() => copyDockerCompose(isUnixSocket ? hostValue : port.current?.value, publicKey)}
dropdownText={t`Copy` + " docker run"}
dropdownOnClick={() => copyDockerRun(isUnixSocket ? hostValue : port.current?.value, publicKey)}
icon={<DockerIcon className="size-4 -me-0.5" />}
dropdownItems={[
{
text: t({ message: "Copy docker run", context: "Button to copy docker run command" }),
onClick: () => copyDockerRun(isUnixSocket ? hostValue : port.current?.value, publicKey),
icons: [<DockerIcon className="size-4" />],
},
]}
/>
</TabsContent>
{/* Binary */}
<TabsContent value="binary" className="contents">
<CopyButton
text={t`Copy Linux command`}
onClick={() => copyInstallCommand(isUnixSocket ? hostValue : port.current?.value, publicKey)}
dropdownText={t`Manual setup instructions`}
dropdownUrl="https://beszel.dev/guide/agent-installation#binary"
icon={<TuxIcon className="size-4" />}
onClick={() => copyLinuxCommand(isUnixSocket ? hostValue : port.current?.value, publicKey)}
dropdownItems={[
{
text: t({ message: "Homebrew command", context: "Button to copy install command" }),
onClick: () => copyLinuxCommand(isUnixSocket ? hostValue : port.current?.value, publicKey, true),
icons: [<AppleIcon className="size-4" />, <TuxIcon className="w-4 h-4" />],
},
{
text: t({ message: "Windows command", context: "Button to copy install command" }),
onClick: () => copyWindowsCommand(isUnixSocket ? hostValue : port.current?.value, publicKey),
icons: [<WindowsIcon className="size-4" />],
},
{
text: t`Manual setup instructions`,
url: "https://beszel.dev/guide/agent-installation#binary",
icons: [<ExternalLinkIcon className="size-4" />],
},
]}
/>
</TabsContent>
{/* Save */}
@@ -235,19 +268,30 @@ export const SystemDialog = memo(({ setOpen, system }: { setOpen: (open: boolean
)
})
interface DropdownItem {
text: string
onClick?: () => void
url?: string
icons?: React.ReactNode[]
}
interface CopyButtonProps {
text: string
onClick: () => void
dropdownText: string
dropdownOnClick?: () => void
dropdownUrl?: string
dropdownItems: DropdownItem[]
icon?: React.ReactNode
}
const CopyButton = memo((props: CopyButtonProps) => {
return (
<div className="flex gap-0 rounded-lg">
<Button type="button" variant="outline" onClick={props.onClick} className="rounded-e-none dark:border-e-0 grow">
{props.text}
<Button
type="button"
variant="outline"
onClick={props.onClick}
className="rounded-e-none dark:border-e-0 grow flex items-center gap-2"
>
{props.text} {props.icon}
</Button>
<div className="w-px h-full bg-muted"></div>
<DropdownMenu>
@@ -257,15 +301,24 @@ const CopyButton = memo((props: CopyButtonProps) => {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{props.dropdownUrl ? (
<DropdownMenuItem asChild>
<a href={props.dropdownUrl} target="_blank" rel="noopener noreferrer">
{props.dropdownText}
</a>
{props.dropdownItems.map((item, index) => (
<DropdownMenuItem key={index} asChild={!!item.url}>
{item.url ? (
<a
href={item.url}
className="cursor-pointer flex items-center gap-1.5"
target="_blank"
rel="noopener noreferrer"
>
{item.text} {item.icons?.map((icon) => icon)}
</a>
) : (
<div onClick={item.onClick} className="cursor-pointer flex items-center gap-1.5">
{item.text} {item.icons?.map((icon) => icon)}
</div>
)}
</DropdownMenuItem>
) : (
<DropdownMenuItem onClick={props.dropdownOnClick}>{props.dropdownText}</DropdownMenuItem>
)}
))}
</DropdownMenuContent>
</DropdownMenu>
</div>

View File

@@ -1,6 +1,8 @@
import { memo, useState } from "react"
import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro";
import { memo, useMemo, useState } from "react"
import { useStore } from "@nanostores/react"
import { $alerts, $systems } from "@/lib/stores"
import { $alerts } from "@/lib/stores"
import {
Dialog,
DialogTrigger,
@@ -17,104 +19,114 @@ import { Link } from "../router"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Checkbox } from "../ui/checkbox"
import { SystemAlert, SystemAlertGlobal } from "./alerts-system"
import { Trans, t } from "@lingui/macro"
export default memo(function AlertsButton({ system }: { system: SystemRecord }) {
const alerts = useStore($alerts)
const [opened, setOpened] = useState(false)
const systemAlerts = alerts.filter((alert) => alert.system === system.id) as AlertRecord[]
const active = systemAlerts.length > 0
const hasAlert = alerts.some((alert) => alert.system === system.id)
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="ghost" size="icon" aria-label={t`Alerts`} data-nolink onClick={() => setOpened(true)}>
<BellIcon
className={cn("h-[1.2em] w-[1.2em] pointer-events-none", {
"fill-primary": active,
})}
/>
</Button>
</DialogTrigger>
<DialogContent className="max-h-full overflow-auto max-w-[35rem]">
{opened && <TheContent data={{ system, alerts, systemAlerts }} />}
</DialogContent>
</Dialog>
return useMemo(
() => (
<Dialog>
<DialogTrigger asChild>
<Button variant="ghost" size="icon" aria-label={t`Alerts`} data-nolink onClick={() => setOpened(true)}>
<BellIcon
className={cn("h-[1.2em] w-[1.2em] pointer-events-none", {
"fill-primary": hasAlert,
})}
/>
</Button>
</DialogTrigger>
<DialogContent className="max-h-full overflow-auto max-w-[35rem]">
{opened && <AlertDialogContent system={system} />}
</DialogContent>
</Dialog>
),
[opened, hasAlert]
)
})
function TheContent({
data: { system, alerts, systemAlerts },
}: {
data: { system: SystemRecord; alerts: AlertRecord[]; systemAlerts: AlertRecord[] }
}) {
function AlertDialogContent({ system }: { system: SystemRecord }) {
const alerts = useStore($alerts)
const [overwriteExisting, setOverwriteExisting] = useState<boolean | "indeterminate">(false)
const systems = $systems.get()
const data = Object.keys(alertInfo).map((key) => {
const alert = alertInfo[key as keyof typeof alertInfo]
return {
key: key as keyof typeof alertInfo,
alert,
system,
// alertsSignature changes only when alerts for this system change
let alertsSignature = ""
const systemAlerts = alerts.filter((alert) => {
if (alert.system === system.id) {
alertsSignature += alert.name + alert.min + alert.value
return true
}
})
return false
}) as AlertRecord[]
return (
<>
<DialogHeader>
<DialogTitle className="text-xl">
<Trans>Alerts</Trans>
</DialogTitle>
<DialogDescription>
<Trans>
See{" "}
<Link href="/settings/notifications" className="link">
notification settings
</Link>{" "}
to configure how you receive alerts.
</Trans>
</DialogDescription>
</DialogHeader>
<Tabs defaultValue="system">
<TabsList className="mb-1 -mt-0.5">
<TabsTrigger value="system">
<ServerIcon className="me-2 h-3.5 w-3.5" />
{system.name}
</TabsTrigger>
<TabsTrigger value="global">
<GlobeIcon className="me-1.5 h-3.5 w-3.5" />
<Trans>All Systems</Trans>
</TabsTrigger>
</TabsList>
<TabsContent value="system">
<div className="grid gap-3">
{data.map((d) => (
<SystemAlert key={d.key} system={system} data={d} systemAlerts={systemAlerts} />
))}
</div>
</TabsContent>
<TabsContent value="global">
<label
htmlFor="ovw"
className="mb-3 flex gap-2 items-center justify-center cursor-pointer border rounded-sm py-3 px-4 border-destructive text-destructive font-semibold text-sm"
>
<Checkbox
id="ovw"
className="text-destructive border-destructive data-[state=checked]:bg-destructive"
checked={overwriteExisting}
onCheckedChange={setOverwriteExisting}
/>
<Trans>Overwrite existing alerts</Trans>
</label>
<div className="grid gap-3">
{data.map((d) => (
<SystemAlertGlobal key={d.key} data={d} overwrite={overwriteExisting} alerts={alerts} systems={systems} />
))}
</div>
</TabsContent>
</Tabs>
</>
)
return useMemo(() => {
// console.log("render modal", system.name, alertsSignature)
const data = Object.keys(alertInfo).map((name) => {
const alert = alertInfo[name as keyof typeof alertInfo]
return {
name: name as keyof typeof alertInfo,
alert,
system,
}
})
return (
<>
<DialogHeader>
<DialogTitle className="text-xl">
<Trans>Alerts</Trans>
</DialogTitle>
<DialogDescription>
<Trans>
See{" "}
<Link href="/settings/notifications" className="link">
notification settings
</Link>{" "}
to configure how you receive alerts.
</Trans>
</DialogDescription>
</DialogHeader>
<Tabs defaultValue="system">
<TabsList className="mb-1 -mt-0.5">
<TabsTrigger value="system">
<ServerIcon className="me-2 h-3.5 w-3.5" />
{system.name}
</TabsTrigger>
<TabsTrigger value="global">
<GlobeIcon className="me-1.5 h-3.5 w-3.5" />
<Trans>All Systems</Trans>
</TabsTrigger>
</TabsList>
<TabsContent value="system">
<div className="grid gap-3">
{data.map((d) => (
<SystemAlert key={d.name} system={system} data={d} systemAlerts={systemAlerts} />
))}
</div>
</TabsContent>
<TabsContent value="global">
<label
htmlFor="ovw"
className="mb-3 flex gap-2 items-center justify-center cursor-pointer border rounded-sm py-3 px-4 border-destructive text-destructive font-semibold text-sm"
>
<Checkbox
id="ovw"
className="text-destructive border-destructive data-[state=checked]:bg-destructive"
checked={overwriteExisting}
onCheckedChange={setOverwriteExisting}
/>
<Trans>Overwrite existing alerts</Trans>
</label>
<div className="grid gap-3">
{data.map((d) => (
<SystemAlertGlobal key={d.name} data={d} overwrite={overwriteExisting} />
))}
</div>
</TabsContent>
</Tabs>
</>
)
}, [alertsSignature, overwriteExisting])
}

View File

@@ -1,18 +1,20 @@
import { pb } from "@/lib/stores"
import { t } from "@lingui/core/macro"
import { Trans, Plural } from "@lingui/react/macro"
import { $alerts, $systems, pb } from "@/lib/stores"
import { alertInfo, cn } from "@/lib/utils"
import { Switch } from "@/components/ui/switch"
import { AlertInfo, AlertRecord, SystemRecord } from "@/types"
import { lazy, Suspense, useRef, useState } from "react"
import { lazy, Suspense, useMemo, useState } from "react"
import { toast } from "../ui/use-toast"
import { RecordOptions } from "pocketbase"
import { Trans, t, Plural } from "@lingui/macro"
import { BatchService } from "pocketbase"
import { getSemaphore } from "@henrygd/semaphore"
interface AlertData {
checked?: boolean
val?: number
min?: number
updateAlert?: (checked: boolean, value: number, min: number) => void
key: keyof typeof alertInfo
name: keyof typeof alertInfo
alert: AlertInfo
system: SystemRecord
}
@@ -35,7 +37,7 @@ export function SystemAlert({
systemAlerts: AlertRecord[]
data: AlertData
}) {
const alert = systemAlerts.find((alert) => alert.name === data.key)
const alert = systemAlerts.find((alert) => alert.name === data.name)
data.updateAlert = async (checked: boolean, value: number, min: number) => {
try {
@@ -47,7 +49,7 @@ export function SystemAlert({
pb.collection("alerts").create({
system: system.id,
user: pb.authStore.record!.id,
name: data.key,
name: data.name,
value: value,
min: min,
})
@@ -66,99 +68,150 @@ export function SystemAlert({
return <AlertContent data={data} />
}
export function SystemAlertGlobal({
data,
overwrite,
alerts,
systems,
}: {
data: AlertData
overwrite: boolean | "indeterminate"
alerts: AlertRecord[]
systems: SystemRecord[]
}) {
const systemsWithExistingAlerts = useRef<{ set: Set<string>; populatedSet: boolean }>({
set: new Set(),
populatedSet: false,
})
export const SystemAlertGlobal = ({ data, overwrite }: { data: AlertData; overwrite: boolean | "indeterminate" }) => {
data.checked = false
data.val = data.min = 0
// set of system ids that have an alert for this name when the component is mounted
const existingAlertsSystems = useMemo(() => {
const map = new Set<string>()
const alerts = $alerts.get()
for (const alert of alerts) {
if (alert.name === data.name) {
map.add(alert.system)
}
}
return map
}, [])
data.updateAlert = async (checked: boolean, value: number, min: number) => {
const { set, populatedSet } = systemsWithExistingAlerts.current
const sem = getSemaphore("alerts")
await sem.acquire()
try {
// if another update is waiting behind, don't start this one
if (sem.size() > 1) {
return
}
// if overwrite checked, make sure all alerts will be overwritten
if (overwrite) {
set.clear()
}
const recordData: Partial<AlertRecord> = {
value,
min,
triggered: false,
}
const recordData: Partial<AlertRecord> = {
value,
min,
triggered: false,
}
const batch = batchWrapper("alerts", 25)
const systems = $systems.get()
const currentAlerts = $alerts.get()
// we can only send 50 in one batch
let done = 0
while (done < systems.length) {
const batch = pb.createBatch()
let batchSize = 0
for (let i = done; i < Math.min(done + 50, systems.length); i++) {
const system = systems[i]
// if overwrite is false and system is in set (alert existed), skip
if (!overwrite && set.has(system.id)) {
continue
// map of current alerts with this name right now by system id
const currentAlertsSystems = new Map<string, AlertRecord>()
for (const alert of currentAlerts) {
if (alert.name === data.name) {
currentAlertsSystems.set(alert.system, alert)
}
// find matching existing alert
const existingAlert = alerts.find((alert) => alert.system === system.id && data.key === alert.name)
// if first run, add system to set (alert already existed when global panel was opened)
if (existingAlert && !populatedSet && !overwrite) {
set.add(system.id)
continue
}
batchSize++
const requestOptions: RecordOptions = {
requestKey: system.id,
}
if (overwrite) {
existingAlertsSystems.clear()
}
const processSystem = async (system: SystemRecord): Promise<void> => {
const existingAlert = existingAlertsSystems.has(system.id)
if (!overwrite && existingAlert) {
return
}
// checked - make sure alert is created or updated
const currentAlert = currentAlertsSystems.get(system.id)
// delete existing alert if unchecked
if (!checked && currentAlert) {
return batch.remove(currentAlert.id)
}
if (checked && currentAlert) {
// update existing alert if checked
return batch.update(currentAlert.id, recordData)
}
if (checked) {
if (existingAlert) {
batch.collection("alerts").update(existingAlert.id, recordData, requestOptions)
} else {
batch.collection("alerts").create(
{
system: system.id,
user: pb.authStore.record!.id,
name: data.key,
...recordData,
},
requestOptions
)
}
} else if (existingAlert) {
batch.collection("alerts").delete(existingAlert.id)
// create new alert if checked and not existing
return batch.create({
system: system.id,
user: pb.authStore.record!.id,
name: data.name,
...recordData,
})
}
}
try {
batchSize && batch.send()
} catch (e) {
failedUpdateToast()
} finally {
done += 50
// make sure current system is updated in the first batch
await processSystem(data.system)
for (const system of systems) {
if (system.id === data.system.id) {
continue
}
if (sem.size() > 1) {
return
}
await processSystem(system)
}
await batch.send()
} finally {
sem.release()
}
systemsWithExistingAlerts.current.populatedSet = true
}
return <AlertContent data={data} />
}
/**
* Creates a wrapper for performing batch operations on a specified collection.
*/
function batchWrapper(collection: string, batchSize: number) {
let batch: BatchService | undefined
let count = 0
const create = async <T extends Record<string, any>>(options: T) => {
batch ||= pb.createBatch()
batch.collection(collection).create(options)
if (++count >= batchSize) {
await send()
}
}
const update = async <T extends Record<string, any>>(id: string, data: T) => {
batch ||= pb.createBatch()
batch.collection(collection).update(id, data)
if (++count >= batchSize) {
await send()
}
}
const remove = async (id: string) => {
batch ||= pb.createBatch()
batch.collection(collection).delete(id)
if (++count >= batchSize) {
await send()
}
}
const send = async () => {
if (count) {
await batch?.send({ requestKey: null })
batch = undefined
count = 0
}
}
return {
update,
remove,
send,
create,
}
}
function AlertContent({ data }: { data: AlertData }) {
const { key } = data
const { name } = data
const singleDescription = data.alert.singleDesc?.()
@@ -166,17 +219,12 @@ function AlertContent({ data }: { data: AlertData }) {
const [min, setMin] = useState(data.min || 10)
const [value, setValue] = useState(data.val || (singleDescription ? 0 : 80))
const newMin = useRef(min)
const newValue = useRef(value)
const Icon = alertInfo[key].icon
const updateAlert = (c?: boolean) => data.updateAlert?.(c ?? checked, newValue.current, newMin.current)
const Icon = alertInfo[name].icon
return (
<div className="rounded-lg border border-muted-foreground/15 hover:border-muted-foreground/20 transition-colors duration-100 group">
<label
htmlFor={`s${key}`}
htmlFor={`s${name}`}
className={cn("flex flex-row items-center justify-between gap-4 cursor-pointer p-4", {
"pb-0": checked,
})}
@@ -188,56 +236,67 @@ function AlertContent({ data }: { data: AlertData }) {
{!checked && <span className="block text-sm text-muted-foreground">{data.alert.desc()}</span>}
</div>
<Switch
id={`s${key}`}
id={`s${name}`}
checked={checked}
onCheckedChange={(checked) => {
setChecked(checked)
updateAlert(checked)
onCheckedChange={(newChecked) => {
setChecked(newChecked)
data.updateAlert?.(newChecked, value, min)
}}
/>
</label>
{checked && (
<div className="grid sm:grid-cols-2 mt-1.5 gap-5 px-4 pb-5 tabular-nums text-muted-foreground">
<Suspense fallback={<div className="h-10" />}>
{!singleDescription && (
<div>
<p id={`v${key}`} className="text-sm block h-8">
<Trans>
Average exceeds{" "}
<strong className="text-foreground">
{value}
{data.alert.unit}
</strong>
</Trans>
</p>
<div className="flex gap-3">
<Slider
aria-labelledby={`v${key}`}
defaultValue={[value]}
onValueCommit={(val) => (newValue.current = val[0]) && updateAlert()}
onValueChange={(val) => setValue(val[0])}
min={1}
max={alertInfo[key].max ?? 99}
/>
{!singleDescription && (
<div>
<p id={`v${name}`} className="text-sm block h-8">
<Trans>
Average exceeds{" "}
<strong className="text-foreground">
{value}
{data.alert.unit}
</strong>
</Trans>
</p>
<div className="flex gap-3">
<Slider
aria-labelledby={`v${name}`}
defaultValue={[value]}
onValueCommit={(val) => {
data.updateAlert?.(true, val[0], min)
}}
onValueChange={(val) => {
setValue(val[0])
}}
min={1}
max={alertInfo[name].max ?? 99}
/>
</div>
</div>
</div>
)}
)}
<div className={cn(singleDescription && "col-span-full lowercase")}>
<p id={`t${key}`} className="text-sm block h-8 first-letter:uppercase">
<p id={`t${name}`} className="text-sm block h-8 first-letter:uppercase">
{singleDescription && (
<>{singleDescription}{` `}</>
<>
{singleDescription}
{` `}
</>
)}
<Trans>
For <strong className="text-foreground">{min}</strong>{" "}
<Plural value={min} one=" minute" other=" minutes" />
<Plural value={min} one="minute" other="minutes" />
</Trans>
</p>
<div className="flex gap-3">
<Slider
aria-labelledby={`v${key}`}
aria-labelledby={`v${name}`}
defaultValue={[min]}
onValueCommit={(val) => (newMin.current = val[0]) && updateAlert()}
onValueChange={(val) => setMin(val[0])}
onValueCommit={(min) => {
data.updateAlert?.(true, value, min[0])
}}
onValueChange={(val) => {
setMin(val[0])
}}
min={1}
max={60}
/>

View File

@@ -1,5 +1,6 @@
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
import { t } from "@lingui/core/macro"
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from "@/components/ui/chart"
import {
useYAxisWidth,
@@ -12,8 +13,7 @@ import {
// import Spinner from '../spinner'
import { ChartData } from "@/types"
import { memo, useMemo } from "react"
import { t } from "@lingui/macro"
import { useLingui } from "@lingui/react"
import { useLingui } from "@lingui/react/macro"
/** [label, key, color, opacity] */
type DataKeys = [string, string, number, number]
@@ -35,6 +35,7 @@ export default memo(function AreaChartDefault({
chartData,
max,
tickFormatter,
contentFormatter,
}: {
maxToggled?: boolean
unit?: string
@@ -42,6 +43,7 @@ export default memo(function AreaChartDefault({
chartData: ChartData
max?: number
tickFormatter?: (value: number) => string
contentFormatter?: (value: number) => string
}) {
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const { i18n } = useLingui()
@@ -115,7 +117,12 @@ export default memo(function AreaChartDefault({
content={
<ChartTooltipContent
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
contentFormatter={(item) => decimalString(item.value) + unit}
contentFormatter={({ value }) => {
if (contentFormatter) {
return contentFormatter(value)
}
return decimalString(value) + unit
}}
// indicator="line"
/>
}

View File

@@ -16,16 +16,17 @@ import { useStore } from "@nanostores/react"
import { $containerFilter } from "@/lib/stores"
import { ChartData } from "@/types"
import { Separator } from "../ui/separator"
import { ChartType } from "@/lib/enums"
export default memo(function ContainerChart({
dataKey,
chartData,
chartName,
chartType,
unit = "%",
}: {
dataKey: string
chartData: ChartData
chartName: string
chartType: ChartType
unit?: string
}) {
const filter = useStore($containerFilter)
@@ -33,7 +34,7 @@ export default memo(function ContainerChart({
const { containerData } = chartData
const isNetChart = chartName === "net"
const isNetChart = chartType === ChartType.Network
const chartConfig = useMemo(() => {
let config = {} as Record<
@@ -81,7 +82,7 @@ export default memo(function ContainerChart({
tickFormatter: (value: any) => string
}
// tick formatter
if (chartName === "cpu") {
if (chartType === ChartType.CPU) {
obj.tickFormatter = (value) => {
const val = toFixedWithoutTrailingZeros(value, 2) + unit
return updateYAxisWidth(val)
@@ -111,6 +112,11 @@ export default memo(function ContainerChart({
return null
}
}
} else if (chartType === ChartType.Memory) {
obj.toolTipFormatter = (item: any) => {
const { v, u } = getSizeAndUnit(item.value, false)
return decimalString(v, 2) + u
}
} else {
obj.toolTipFormatter = (item: any) => decimalString(item.value) + unit
}
@@ -157,13 +163,14 @@ export default memo(function ContainerChart({
<ChartTooltip
animationEasing="ease-out"
animationDuration={150}
truncate={true}
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
// @ts-ignore
itemSorter={(a, b) => b.value - a.value}
content={<ChartTooltipContent filter={filter} contentFormatter={toolTipFormatter} />}
/>
{Object.keys(chartConfig).map((key) => {
const filtered = filter && !key.includes(filter)
const filtered = filter && !key.toLowerCase().includes(filter.toLowerCase())
let fillOpacity = filtered ? 0.05 : 0.4
let strokeOpacity = filtered ? 0.1 : 1
return (

View File

@@ -1,5 +1,4 @@
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from "@/components/ui/chart"
import {
useYAxisWidth,
@@ -12,8 +11,7 @@ import {
} from "@/lib/utils"
import { ChartData } from "@/types"
import { memo } from "react"
import { t } from "@lingui/macro"
import { useLingui } from "@lingui/react"
import { useLingui } from "@lingui/react/macro"
export default memo(function DiskChart({
dataKey,
@@ -25,7 +23,7 @@ export default memo(function DiskChart({
chartData: ChartData
}) {
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const { _ } = useLingui()
const { t } = useLingui()
// round to nearest GB
if (diskSize >= 100) {
@@ -76,7 +74,7 @@ export default memo(function DiskChart({
/>
<Area
dataKey={dataKey}
name={_(t`Disk Usage`)}
name={t`Disk Usage`}
type="monotoneX"
fill="hsl(var(--chart-4))"
fillOpacity={0.4}

View File

@@ -1,15 +1,13 @@
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from "@/components/ui/chart"
import { useYAxisWidth, cn, toFixedFloat, decimalString, formatShortDate, chartMargin } from "@/lib/utils"
import { memo } from "react"
import { ChartData } from "@/types"
import { t } from "@lingui/macro"
import { useLingui } from "@lingui/react"
import { useLingui } from "@lingui/react/macro"
export default memo(function MemChart({ chartData }: { chartData: ChartData }) {
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const { _ } = useLingui()
const { t } = useLingui()
const totalMem = toFixedFloat(chartData.systemStats.at(-1)?.stats.m ?? 0, 1)
@@ -62,7 +60,7 @@ export default memo(function MemChart({ chartData }: { chartData: ChartData }) {
}
/>
<Area
name={_(t`Used`)}
name={t`Used`}
order={3}
dataKey="stats.mu"
type="monotoneX"
@@ -86,7 +84,7 @@ export default memo(function MemChart({ chartData }: { chartData: ChartData }) {
/>
)}
<Area
name={_(t`Cache / Buffers`)}
name={t`Cache / Buffers`}
order={1}
dataKey="stats.mb"
type="monotoneX"

View File

@@ -1,5 +1,6 @@
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
import { t } from "@lingui/core/macro";
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from "@/components/ui/chart"
import {
useYAxisWidth,
@@ -11,7 +12,6 @@ import {
} from "@/lib/utils"
import { ChartData } from "@/types"
import { memo } from "react"
import { t } from "@lingui/macro"
export default memo(function SwapChart({ chartData }: { chartData: ChartData }) {
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()

View File

@@ -18,8 +18,11 @@ import {
} from "@/lib/utils"
import { ChartData } from "@/types"
import { memo, useMemo } from "react"
import { $temperatureFilter } from "@/lib/stores"
import { useStore } from "@nanostores/react"
export default memo(function TemperatureChart({ chartData }: { chartData: ChartData }) {
const filter = useStore($temperatureFilter)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
if (chartData.systemStats.length === 0) {
@@ -86,22 +89,28 @@ export default memo(function TemperatureChart({ chartData }: { chartData: ChartD
<ChartTooltipContent
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
contentFormatter={(item) => decimalString(item.value) + " °C"}
// indicator="line"
filter={filter}
/>
}
/>
{colors.map((key) => (
<Line
key={key}
dataKey={key}
name={key}
type="monotoneX"
dot={false}
strokeWidth={1.5}
stroke={newChartData.colors[key]}
isAnimationActive={false}
/>
))}
{colors.map((key) => {
const filtered = filter && !key.toLowerCase().includes(filter.toLowerCase())
let strokeOpacity = filtered ? 0.1 : 1
return (
<Line
key={key}
dataKey={key}
name={key}
type="monotoneX"
dot={false}
strokeWidth={1.5}
stroke={newChartData.colors[key]}
strokeOpacity={strokeOpacity}
activeDot={{ opacity: filtered ? 0 : 1 }}
isAnimationActive={false}
/>
)
})}
{colors.length < 12 && <ChartLegend content={<ChartLegendContent />} />}
</LineChart>
</ChartContainer>

View File

@@ -19,17 +19,15 @@ import {
CommandSeparator,
CommandShortcut,
} from "@/components/ui/command"
import { useEffect } from "react"
import { useStore } from "@nanostores/react"
import { memo, useEffect, useMemo } from "react"
import { $systems } from "@/lib/stores"
import { getHostDisplayValue, isAdmin } from "@/lib/utils"
import { $router, basePath, navigate } from "./router"
import { Trans, t } from "@lingui/macro"
import { getHostDisplayValue, isAdmin, listen } from "@/lib/utils"
import { $router, basePath, navigate, prependBasePath } from "./router"
import { Trans } from "@lingui/react/macro"
import { t } from "@lingui/core/macro"
import { getPagePath } from "@nanostores/router"
export default function CommandPalette({ open, setOpen }: { open: boolean; setOpen: (open: boolean) => void }) {
const systems = useStore($systems)
export default memo(function CommandPalette({ open, setOpen }: { open: boolean; setOpen: (open: boolean) => void }) {
useEffect(() => {
const down = (e: KeyboardEvent) => {
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
@@ -37,162 +35,163 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
setOpen(!open)
}
}
document.addEventListener("keydown", down)
return () => document.removeEventListener("keydown", down)
return listen(document, "keydown", down)
}, [open, setOpen])
return (
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput placeholder={t`Search for systems or settings...`} />
<CommandList>
<CommandEmpty>
<Trans>No results found.</Trans>
</CommandEmpty>
{systems.length > 0 && (
<>
<CommandGroup>
{systems.map((system) => (
return useMemo(() => {
const systems = $systems.get()
return (
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput placeholder={t`Search for systems or settings...`} />
<CommandList>
<CommandEmpty>
<Trans>No results found.</Trans>
</CommandEmpty>
{systems.length > 0 && (
<>
<CommandGroup>
{systems.map((system) => (
<CommandItem
key={system.id}
onSelect={() => {
navigate(getPagePath($router, "system", { name: system.name }))
setOpen(false)
}}
>
<Server className="me-2 h-4 w-4" />
<span>{system.name}</span>
<CommandShortcut>{getHostDisplayValue(system)}</CommandShortcut>
</CommandItem>
))}
</CommandGroup>
<CommandSeparator className="mb-1.5" />
</>
)}
<CommandGroup heading={t`Pages / Settings`}>
<CommandItem
keywords={["home"]}
onSelect={() => {
navigate(basePath)
setOpen(false)
}}
>
<LayoutDashboard className="me-2 h-4 w-4" />
<span>
<Trans>Dashboard</Trans>
</span>
<CommandShortcut>
<Trans>Page</Trans>
</CommandShortcut>
</CommandItem>
<CommandItem
onSelect={() => {
navigate(getPagePath($router, "settings", { name: "general" }))
setOpen(false)
}}
>
<SettingsIcon className="me-2 h-4 w-4" />
<span>
<Trans>Settings</Trans>
</span>
<CommandShortcut>
<Trans>Settings</Trans>
</CommandShortcut>
</CommandItem>
<CommandItem
keywords={["alerts"]}
onSelect={() => {
navigate(getPagePath($router, "settings", { name: "notifications" }))
setOpen(false)
}}
>
<MailIcon className="me-2 h-4 w-4" />
<span>
<Trans>Notifications</Trans>
</span>
<CommandShortcut>
<Trans>Settings</Trans>
</CommandShortcut>
</CommandItem>
<CommandItem
keywords={["help", "oauth", "oidc"]}
onSelect={() => {
window.location.href = "https://beszel.dev/guide/what-is-beszel"
}}
>
<BookIcon className="me-2 h-4 w-4" />
<span>
<Trans>Documentation</Trans>
</span>
<CommandShortcut>beszel.dev</CommandShortcut>
</CommandItem>
</CommandGroup>
{isAdmin() && (
<>
<CommandSeparator className="mb-1.5" />
<CommandGroup heading={t`Admin`}>
<CommandItem
key={system.id}
keywords={["pocketbase"]}
onSelect={() => {
navigate(getPagePath($router, "system", { name: system.name }))
setOpen(false)
window.open(prependBasePath("/_/"), "_blank")
}}
>
<Server className="me-2 h-4 w-4" />
<span>{system.name}</span>
<CommandShortcut>{getHostDisplayValue(system)}</CommandShortcut>
<UsersIcon className="me-2 h-4 w-4" />
<span>
<Trans>Users</Trans>
</span>
<CommandShortcut>
<Trans>Admin</Trans>
</CommandShortcut>
</CommandItem>
))}
</CommandGroup>
<CommandSeparator className="mb-1.5" />
</>
)}
<CommandGroup heading={t`Pages / Settings`}>
<CommandItem
keywords={["home"]}
onSelect={() => {
navigate(basePath)
setOpen(false)
}}
>
<LayoutDashboard className="me-2 h-4 w-4" />
<span>
<Trans>Dashboard</Trans>
</span>
<CommandShortcut>
<Trans>Page</Trans>
</CommandShortcut>
</CommandItem>
<CommandItem
onSelect={() => {
navigate(getPagePath($router, "settings", { name: "general" }))
setOpen(false)
}}
>
<SettingsIcon className="me-2 h-4 w-4" />
<span>
<Trans>Settings</Trans>
</span>
<CommandShortcut>
<Trans>Settings</Trans>
</CommandShortcut>
</CommandItem>
<CommandItem
keywords={["alerts"]}
onSelect={() => {
navigate(getPagePath($router, "settings", { name: "notifications" }))
setOpen(false)
}}
>
<MailIcon className="me-2 h-4 w-4" />
<span>
<Trans>Notifications</Trans>
</span>
<CommandShortcut>
<Trans>Settings</Trans>
</CommandShortcut>
</CommandItem>
<CommandItem
keywords={["help", "oauth", "oidc"]}
onSelect={() => {
window.location.href = "https://beszel.dev/guide/what-is-beszel"
}}
>
<BookIcon className="me-2 h-4 w-4" />
<span>
<Trans>Documentation</Trans>
</span>
<CommandShortcut>beszel.dev</CommandShortcut>
</CommandItem>
</CommandGroup>
{isAdmin() && (
<>
<CommandSeparator className="mb-1.5" />
<CommandGroup heading={t`Admin`}>
<CommandItem
keywords={["pocketbase"]}
onSelect={() => {
setOpen(false)
window.open("/_/", "_blank")
}}
>
<UsersIcon className="me-2 h-4 w-4" />
<span>
<Trans>Users</Trans>
</span>
<CommandShortcut>
<Trans>Admin</Trans>
</CommandShortcut>
</CommandItem>
<CommandItem
onSelect={() => {
setOpen(false)
window.open("/_/#/logs", "_blank")
}}
>
<LogsIcon className="me-2 h-4 w-4" />
<span>
<Trans>Logs</Trans>
</span>
<CommandShortcut>
<Trans>Admin</Trans>
</CommandShortcut>
</CommandItem>
<CommandItem
onSelect={() => {
setOpen(false)
window.open("/_/#/settings/backups", "_blank")
}}
>
<DatabaseBackupIcon className="me-2 h-4 w-4" />
<span>
<Trans>Backups</Trans>
</span>
<CommandShortcut>
<Trans>Admin</Trans>
</CommandShortcut>
</CommandItem>
<CommandItem
keywords={["email"]}
onSelect={() => {
setOpen(false)
window.open("/_/#/settings/mail", "_blank")
}}
>
<MailIcon className="me-2 h-4 w-4" />
<span>
<Trans>SMTP settings</Trans>
</span>
<CommandShortcut>
<Trans>Admin</Trans>
</CommandShortcut>
</CommandItem>
</CommandGroup>
</>
)}
</CommandList>
</CommandDialog>
)
}
<CommandItem
onSelect={() => {
setOpen(false)
window.open(prependBasePath("/_/#/logs"), "_blank")
}}
>
<LogsIcon className="me-2 h-4 w-4" />
<span>
<Trans>Logs</Trans>
</span>
<CommandShortcut>
<Trans>Admin</Trans>
</CommandShortcut>
</CommandItem>
<CommandItem
onSelect={() => {
setOpen(false)
window.open(prependBasePath("/_/#/settings/backups"), "_blank")
}}
>
<DatabaseBackupIcon className="me-2 h-4 w-4" />
<span>
<Trans>Backups</Trans>
</span>
<CommandShortcut>
<Trans>Admin</Trans>
</CommandShortcut>
</CommandItem>
<CommandItem
keywords={["email"]}
onSelect={() => {
setOpen(false)
window.open(prependBasePath("/_/#/settings/mail"), "_blank")
}}
>
<MailIcon className="me-2 h-4 w-4" />
<span>
<Trans>SMTP settings</Trans>
</span>
<CommandShortcut>
<Trans>Admin</Trans>
</CommandShortcut>
</CommandItem>
</CommandGroup>
</>
)}
</CommandList>
</CommandDialog>
)
}, [open])
})

View File

@@ -1,8 +1,8 @@
import { Trans } from "@lingui/react/macro";
import { useEffect, useMemo, useRef } from "react"
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "./ui/dialog"
import { Textarea } from "./ui/textarea"
import { $copyContent } from "@/lib/stores"
import { Trans } from "@lingui/macro"
export default function CopyToClipboard({ content }: { content: string }) {
return (

View File

@@ -4,7 +4,7 @@ import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import languages from "@/lib/languages"
import { cn } from "@/lib/utils"
import { useLingui } from "@lingui/react"
import { useLingui } from "@lingui/react/macro"
import { dynamicActivate } from "@/lib/i18n"
export function LangToggle() {

View File

@@ -1,3 +1,5 @@
import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro";
import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
@@ -10,7 +12,6 @@ import { Dialog, DialogContent, DialogTrigger, DialogHeader, DialogTitle } from
import { useCallback, useEffect, useState } from "react"
import { AuthMethodsList, AuthProviderInfo, OAuth2AuthConfig } from "pocketbase"
import { $router, Link, prependBasePath } from "../router"
import { Trans, t } from "@lingui/macro"
import { getPagePath } from "@nanostores/router"
const honeypot = v.literal("")
@@ -135,7 +136,6 @@ export function UserAuthForm({
toast({
title: t`Error`,
description: t`Please enable pop-ups for this site`,
variant: "destructive",
})
return
}
@@ -156,14 +156,17 @@ export function UserAuthForm({
useEffect(() => {
// auto login if password disabled and only one auth provider
if (!passwordEnabled && authProviders.length === 1) {
loginWithOauth(authProviders[0], true)
if (!passwordEnabled && authProviders.length === 1 && !sessionStorage.getItem("lo")) {
// Add a small timeout to ensure browser is ready to handle popups
setTimeout(() => {
loginWithOauth(authProviders[0], true)
}, 300)
}
}, [])
return (
<div className={cn("grid gap-6", className)} {...props}>
{passwordEnabled && (
<div className={cn("grid gap-6", className)} {...props}>
{passwordEnabled && (
<>
<form onSubmit={handleSubmit} onChange={() => setErrors({})}>
<div className="grid gap-2.5">
@@ -239,21 +242,20 @@ export function UserAuthForm({
</form>
{(isFirstRun || oauthEnabled) && (
// only show 'continue with' during onboarding or if we have auth providers
<div className="relative">
<div className="absolute inset-0 flex items-center">
(<div className="relative">
<div className="absolute inset-0 flex items-center">
<span className="w-full border-t" />
</div>
<div className="relative flex justify-center text-xs uppercase">
<div className="relative flex justify-center text-xs uppercase">
<span className="bg-background px-2 text-muted-foreground">
<Trans>Or continue with</Trans>
</span>
</div>
</div>
</div>)
)}
</>
)}
{oauthEnabled && (
{oauthEnabled && (
<div className="grid gap-2 -mt-1">
{authMethods.oauth2.providers.map((provider) => (
<button
@@ -283,17 +285,16 @@ export function UserAuthForm({
))}
</div>
)}
{!oauthEnabled && isFirstRun && (
{!oauthEnabled && isFirstRun && (
// only show GitHub button / dialog during onboarding
<Dialog>
<DialogTrigger asChild>
(<Dialog>
<DialogTrigger asChild>
<button type="button" className={cn(buttonVariants({ variant: "outline" }))}>
<img className="me-2 h-4 w-4 dark:invert" src={prependBasePath("/_/images/oauth2/github.svg")} alt="" />
<span className="translate-y-[1px]">GitHub</span>
</button>
</DialogTrigger>
<DialogContent style={{ maxWidth: 440, width: "90%" }}>
<DialogContent style={{ maxWidth: 440, width: "90%" }}>
<DialogHeader>
<DialogTitle>
<Trans>OAuth 2 / OIDC support</Trans>
@@ -317,10 +318,9 @@ export function UserAuthForm({
</p>
</div>
</DialogContent>
</Dialog>
</Dialog>)
)}
{passwordEnabled && !isFirstRun && (
{passwordEnabled && !isFirstRun && (
<Link
href={getPagePath($router, "forgot_password")}
className="text-sm mx-auto hover:text-brand underline underline-offset-4 opacity-70 hover:opacity-100 transition-opacity"
@@ -328,6 +328,6 @@ export function UserAuthForm({
<Trans>Forgot password?</Trans>
</Link>
)}
</div>
)
</div>
);
}

View File

@@ -1,3 +1,5 @@
import { Trans } from "@lingui/react/macro";
import { t } from "@lingui/core/macro";
import { LoaderCircle, MailIcon, SendHorizonalIcon } from "lucide-react"
import { Input } from "../ui/input"
import { Label } from "../ui/label"
@@ -8,7 +10,6 @@ import { cn } from "@/lib/utils"
import { pb } from "@/lib/stores"
import { Dialog, DialogHeader } from "../ui/dialog"
import { DialogContent, DialogTrigger, DialogTitle } from "../ui/dialog"
import { t, Trans } from "@lingui/macro"
const showLoginFaliedToast = () => {
toast({

View File

@@ -1,3 +1,4 @@
import { t } from "@lingui/core/macro";
import { UserAuthForm } from "@/components/login/auth-form"
import { Logo } from "../logo"
import { useEffect, useMemo, useState } from "react"
@@ -6,7 +7,6 @@ import { useStore } from "@nanostores/react"
import ForgotPassword from "./forgot-pass-form"
import { $router } from "../router"
import { AuthMethodsList } from "pocketbase"
import { t } from "@lingui/macro"
import { useTheme } from "../theme-provider"
export default function () {

View File

@@ -1,10 +1,11 @@
import { Trans } from "@lingui/react/macro";
import { t } from "@lingui/core/macro";
import { LaptopIcon, MoonStarIcon, SunIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import { useTheme } from "@/components/theme-provider"
import { cn } from "@/lib/utils"
import { t, Trans } from "@lingui/macro"
export function ModeToggle() {
const { theme, setTheme } = useTheme()

View File

@@ -1,3 +1,4 @@
import { Trans } from "@lingui/react/macro";
import { useState, lazy, Suspense } from "react"
import { Button, buttonVariants } from "@/components/ui/button"
import {
@@ -26,7 +27,6 @@ import {
DropdownMenuItem,
} from "@/components/ui/dropdown-menu"
import { AddSystemButton } from "./add-system"
import { Trans } from "@lingui/macro"
import { getPagePath } from "@nanostores/router"
const CommandPalette = lazy(() => import("./command-palette"))

View File

@@ -11,7 +11,7 @@ const routes = {
* The base path of the application.
* This is used to prepend the base path to all routes.
*/
export const basePath = window.BASE_PATH || ""
export const basePath = globalThis.BESZEL.BASE_PATH || ""
/**
* Prepends the base path to the given path.

View File

@@ -1,6 +1,6 @@
import { Suspense, lazy, useEffect, useMemo } from "react"
import { Suspense, lazy, memo, useEffect, useMemo } from "react"
import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"
import { $alerts, $hubVersion, $systems, pb } from "@/lib/stores"
import { $alerts, $systems, pb } from "@/lib/stores"
import { useStore } from "@nanostores/react"
import { GithubIcon } from "lucide-react"
import { Separator } from "../ui/separator"
@@ -8,17 +8,17 @@ import { alertInfo, updateRecordList, updateSystemList } from "@/lib/utils"
import { AlertRecord, SystemRecord } from "@/types"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { $router, Link } from "../router"
import { Plural, t, Trans } from "@lingui/macro"
import { Plural, Trans, useLingui } from "@lingui/react/macro"
import { getPagePath } from "@nanostores/router"
const SystemsTable = lazy(() => import("../systems-table/systems-table"))
export default function Home() {
const hubVersion = useStore($hubVersion)
export const Home = memo(() => {
const alerts = useStore($alerts)
const systems = useStore($systems)
const { t } = useLingui()
let alertsKey = ""
const activeAlerts = useMemo(() => {
const activeAlerts = alerts.filter((alert) => {
const active = alert.triggered && alert.name in alertInfo
@@ -26,14 +26,17 @@ export default function Home() {
return false
}
alert.sysname = systems.find((system) => system.id === alert.system)?.name
alertsKey += alert.id
return true
})
return activeAlerts
}, [alerts])
}, [systems, alerts])
useEffect(() => {
document.title = t`Dashboard` + " / Beszel"
}, [t])
useEffect(() => {
// make sure we have the latest list of systems
updateSystemList()
@@ -41,7 +44,6 @@ export default function Home() {
pb.collection<SystemRecord>("systems").subscribe("*", (e) => {
updateRecordList(e, $systems)
})
// todo: add toast if new triggered alert comes in
pb.collection<AlertRecord>("alerts").subscribe("*", (e) => {
updateRecordList(e, $alerts)
})
@@ -51,56 +53,15 @@ export default function Home() {
}
}, [])
return (
<>
{/* show active alerts */}
{activeAlerts.length > 0 && (
<Card className="mb-4">
<CardHeader className="pb-4 px-2 sm:px-6 max-sm:pt-5 max-sm:pb-1">
<div className="px-2 sm:px-1">
<CardTitle>
<Trans>Active Alerts</Trans>
</CardTitle>
</div>
</CardHeader>
<CardContent className="max-sm:p-2">
{activeAlerts.length > 0 && (
<div className="grid sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-3">
{activeAlerts.map((alert) => {
const info = alertInfo[alert.name as keyof typeof alertInfo]
return (
<Alert
key={alert.id}
className="hover:-translate-y-[1px] duration-200 bg-transparent border-foreground/10 hover:shadow-md shadow-black"
>
<info.icon className="h-4 w-4" />
<AlertTitle>
{alert.sysname} {info.name().toLowerCase().replace("cpu", "CPU")}
</AlertTitle>
<AlertDescription>
<Trans>
Exceeds {alert.value}
{info.unit} in last <Plural value={alert.min} one="# minute" other="# minutes" />
</Trans>
</AlertDescription>
<Link
href={getPagePath($router, "system", { name: alert.sysname! })}
className="absolute inset-0 w-full h-full"
aria-label="View system"
></Link>
</Alert>
)
})}
</div>
)}
</CardContent>
</Card>
)}
<Suspense>
<SystemsTable />
</Suspense>
return useMemo(
() => (
<>
{/* show active alerts */}
{activeAlerts.length > 0 && <ActiveAlerts key={activeAlerts.length} activeAlerts={activeAlerts} />}
<Suspense>
<SystemsTable />
</Suspense>
{hubVersion && (
<div className="flex gap-1.5 justify-end items-center pe-3 sm:pe-6 mt-3.5 text-xs opacity-80">
<a
href="https://github.com/henrygd/beszel"
@@ -115,10 +76,56 @@ export default function Home() {
target="_blank"
className="text-muted-foreground hover:text-foreground duration-75"
>
Beszel {hubVersion}
Beszel {globalThis.BESZEL.HUB_VERSION}
</a>
</div>
)}
</>
</>
),
[alertsKey]
)
}
})
const ActiveAlerts = memo(({ activeAlerts }: { activeAlerts: AlertRecord[] }) => {
return (
<Card className="mb-4">
<CardHeader className="pb-4 px-2 sm:px-6 max-sm:pt-5 max-sm:pb-1">
<div className="px-2 sm:px-1">
<CardTitle>
<Trans>Active Alerts</Trans>
</CardTitle>
</div>
</CardHeader>
<CardContent className="max-sm:p-2">
{activeAlerts.length > 0 && (
<div className="grid sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-3">
{activeAlerts.map((alert) => {
const info = alertInfo[alert.name as keyof typeof alertInfo]
return (
<Alert
key={alert.id}
className="hover:-translate-y-[1px] duration-200 bg-transparent border-foreground/10 hover:shadow-md shadow-black"
>
<info.icon className="h-4 w-4" />
<AlertTitle>
{alert.sysname} {info.name().toLowerCase().replace("cpu", "CPU")}
</AlertTitle>
<AlertDescription>
<Trans>
Exceeds {alert.value}
{info.unit} in last <Plural value={alert.min} one="# minute" other="# minutes" />
</Trans>
</AlertDescription>
<Link
href={getPagePath($router, "system", { name: alert.sysname! })}
className="absolute inset-0 w-full h-full"
aria-label="View system"
></Link>
</Alert>
)
})}
</div>
)}
</CardContent>
</Card>
)
})

View File

@@ -1,3 +1,5 @@
import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro";
import { isAdmin } from "@/lib/utils"
import { Separator } from "@/components/ui/separator"
import { Button } from "@/components/ui/button"
@@ -10,7 +12,6 @@ import { useState } from "react"
import { Textarea } from "@/components/ui/textarea"
import { toast } from "@/components/ui/use-toast"
import clsx from "clsx"
import { Trans, t } from "@lingui/macro"
export default function ConfigYaml() {
const [configContent, setConfigContent] = useState<string>("")

View File

@@ -1,3 +1,4 @@
import { Trans } from "@lingui/react/macro"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
@@ -7,10 +8,9 @@ import { LanguagesIcon, LoaderCircleIcon, SaveIcon } from "lucide-react"
import { UserSettings } from "@/types"
import { saveSettings } from "./layout"
import { useState } from "react"
import { Trans } from "@lingui/macro"
import languages from "@/lib/languages"
import { dynamicActivate } from "@/lib/i18n"
import { useLingui } from "@lingui/react"
import { useLingui } from "@lingui/react/macro"
// import { setLang } from "@/lib/i18n"
export default function SettingsProfilePage({ userSettings }: { userSettings: UserSettings }) {
@@ -46,11 +46,11 @@ export default function SettingsProfilePage({ userSettings }: { userSettings: Us
</h3>
<p className="text-sm text-muted-foreground leading-relaxed">
<Trans>
Want to help us make our translations even better? Check out{" "}
Want to help improve our translations? Check{" "}
<a href="https://crowdin.com/project/beszel" className="link" target="_blank" rel="noopener noreferrer">
Crowdin
</a>{" "}
for more details.
for details.
</Trans>
</p>
</div>

View File

@@ -1,3 +1,5 @@
import { t } from "@lingui/core/macro"
import { Trans } from "@lingui/react/macro"
import { useEffect } from "react"
import { Separator } from "../../ui/separator"
import { SidebarNav } from "./sidebar-nav.tsx"
@@ -12,8 +14,7 @@ import { UserSettings } from "@/types.js"
import General from "./general.tsx"
import Notifications from "./notifications.tsx"
import ConfigYaml from "./config-yaml.tsx"
import { Trans, t } from "@lingui/macro"
import { useLingui } from "@lingui/react"
import { useLingui } from "@lingui/react/macro"
export async function saveSettings(newSettings: Partial<UserSettings>) {
try {
@@ -44,11 +45,11 @@ export async function saveSettings(newSettings: Partial<UserSettings>) {
}
export default function SettingsLayout() {
const { _ } = useLingui()
const { t } = useLingui()
const sidebarNavItems = [
{
title: _(t({ message: `General`, comment: "Context: General settings" })),
title: t({ message: `General`, comment: "Context: General settings" }),
href: getPagePath($router, "settings", { name: "general" }),
icon: SettingsIcon,
},

View File

@@ -1,3 +1,5 @@
import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro";
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
@@ -12,7 +14,6 @@ import { UserSettings } from "@/types"
import { saveSettings } from "./layout"
import * as v from "valibot"
import { isAdmin } from "@/lib/utils"
import { Trans, t } from "@lingui/macro"
import { prependBasePath } from "@/components/router"
interface ShoutrrrUrlCardProps {

View File

@@ -1,5 +1,17 @@
import { $systems, pb, $chartTime, $containerFilter, $userSettings, $direction, $maxValues } from "@/lib/stores"
import { t } from "@lingui/core/macro"
import { Plural, Trans } from "@lingui/react/macro"
import {
$systems,
pb,
$chartTime,
$containerFilter,
$userSettings,
$direction,
$maxValues,
$temperatureFilter,
} from "@/lib/stores"
import { ChartData, ChartTimes, ContainerStatsRecord, GPUData, SystemRecord, SystemStatsRecord } from "@/types"
import { ChartType, Os } from "@/lib/enums"
import React, { lazy, memo, useCallback, useEffect, useMemo, useRef, useState } from "react"
import { Card, CardHeader, CardTitle, CardDescription } from "../ui/card"
import { useStore } from "@nanostores/react"
@@ -12,6 +24,7 @@ import {
getHostDisplayValue,
getPbTimestamp,
getSizeAndUnit,
listen,
toFixedFloat,
useLocalStorage,
} from "@/lib/utils"
@@ -19,12 +32,13 @@ import { Separator } from "../ui/separator"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip"
import { Button } from "../ui/button"
import { Input } from "../ui/input"
import { ChartAverage, ChartMax, Rows, TuxIcon } from "../ui/icons"
import { ChartAverage, ChartMax, Rows, TuxIcon, WindowsIcon, AppleIcon } from "../ui/icons"
import { useIntersectionObserver } from "@/lib/use-intersection-observer"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select"
import { timeTicks } from "d3-time"
import { Plural, Trans, t } from "@lingui/macro"
import { useLingui } from "@lingui/react"
import { useLingui } from "@lingui/react/macro"
import { $router, navigate } from "../router"
import { getPagePath } from "@nanostores/router"
const AreaChartDefault = lazy(() => import("../charts/area-chart"))
const ContainerChart = lazy(() => import("../charts/container-chart"))
@@ -103,7 +117,7 @@ function dockerOrPodman(str: string, system: SystemRecord) {
export default function SystemDetail({ name }: { name: string }) {
const direction = useStore($direction)
const { _ } = useLingui()
const { t } = useLingui()
const systems = useStore($systems)
const chartTime = useStore($chartTime)
const maxValues = useStore($maxValues)
@@ -112,6 +126,7 @@ export default function SystemDetail({ name }: { name: string }) {
const [systemStats, setSystemStats] = useState([] as SystemStatsRecord[])
const [containerData, setContainerData] = useState([] as ChartData["containerData"])
const netCardRef = useRef<HTMLDivElement>(null)
const persistChartTime = useRef(false)
const [containerFilterBar, setContainerFilterBar] = useState(null as null | JSX.Element)
const [bottomSpacing, setBottomSpacing] = useState(0)
const [chartLoading, setChartLoading] = useState(true)
@@ -120,8 +135,10 @@ export default function SystemDetail({ name }: { name: string }) {
useEffect(() => {
document.title = `${name} / Beszel`
return () => {
$chartTime.set($userSettings.get().chartTime)
// resetCharts()
if (!persistChartTime.current) {
$chartTime.set($userSettings.get().chartTime)
}
persistChartTime.current = false
setSystemStats([])
setContainerData([])
setContainerFilterBar(null)
@@ -211,7 +228,7 @@ export default function SystemDetail({ name }: { name: string }) {
cache.set(cs_cache_key, containerData)
}
if (containerData.length) {
!containerFilterBar && setContainerFilterBar(<ContainerFilterBar />)
!containerFilterBar && setContainerFilterBar(<FilterBar />)
} else if (containerFilterBar) {
setContainerFilterBar(null)
}
@@ -244,6 +261,23 @@ export default function SystemDetail({ name }: { name: string }) {
if (!system.info) {
return []
}
const osInfo = {
[Os.Linux]: {
Icon: TuxIcon,
value: system.info.k,
label: t({ comment: "Linux kernel", message: "Kernel" }),
},
[Os.Darwin]: {
Icon: AppleIcon,
value: `macOS ${system.info.k}`,
},
[Os.Windows]: {
Icon: WindowsIcon,
value: system.info.k,
},
}
let uptime: React.ReactNode
if (system.info.u < 172800) {
const hours = Math.trunc(system.info.u / 3600)
@@ -260,8 +294,8 @@ export default function SystemDetail({ name }: { name: string }) {
// hide if hostname is same as host or name
hide: system.info.h === system.host || system.info.h === system.name,
},
{ value: uptime, Icon: ClockArrowUp, label: t`Uptime` },
{ value: system.info.k, Icon: TuxIcon, label: t({ comment: "Linux kernel", message: "Kernel" }) },
{ value: uptime, Icon: ClockArrowUp, label: t`Uptime`, hide: !system.info.u },
osInfo[system.info.os ?? Os.Linux],
{
value: `${system.info.m} (${system.info.c}c${system.info.t ? `/${system.info.t}t` : ""})`,
Icon: CpuIcon,
@@ -289,6 +323,41 @@ export default function SystemDetail({ name }: { name: string }) {
setBottomSpacing(tooltipHeight - distanceToBottom)
}, [netCardRef, containerData])
// keyboard navigation between systems
useEffect(() => {
if (!systems.length) {
return
}
const handleKeyUp = (e: KeyboardEvent) => {
if (
e.target instanceof HTMLInputElement ||
e.target instanceof HTMLTextAreaElement ||
e.shiftKey ||
e.ctrlKey ||
e.metaKey
) {
return
}
const currentIndex = systems.findIndex((s) => s.name === name)
if (currentIndex === -1 || systems.length <= 1) {
return
}
switch (e.key) {
case "ArrowLeft":
case "h":
const prevIndex = (currentIndex - 1 + systems.length) % systems.length
persistChartTime.current = true
return navigate(getPagePath($router, "system", { name: systems[prevIndex].name }))
case "ArrowRight":
case "l":
const nextIndex = (currentIndex + 1) % systems.length
persistChartTime.current = true
return navigate(getPagePath($router, "system", { name: systems[nextIndex].name }))
}
}
return listen(document, "keyup", handleKeyUp)
}, [name, systems])
if (!system.id) {
return null
}
@@ -395,7 +464,7 @@ export default function SystemDetail({ name }: { name: string }) {
<ChartCard
empty={dataEmpty}
grid={grid}
title={_(t`CPU Usage`)}
title={t`CPU Usage`}
description={t`Average system-wide CPU utilization`}
cornerEl={maxValSelect}
>
@@ -410,7 +479,7 @@ export default function SystemDetail({ name }: { name: string }) {
description={t`Average CPU utilization of containers`}
cornerEl={containerFilterBar}
>
<ContainerChart chartData={chartData} dataKey="c" chartName="cpu" />
<ContainerChart chartData={chartData} dataKey="c" chartType={ChartType.CPU} />
</ChartCard>
)}
@@ -431,7 +500,7 @@ export default function SystemDetail({ name }: { name: string }) {
description={dockerOrPodman(t`Memory usage of docker containers`, system)}
cornerEl={containerFilterBar}
>
<ContainerChart chartData={chartData} chartName="mem" dataKey="m" unit=" MB" />
<ContainerChart chartData={chartData} dataKey="m" chartType={ChartType.Memory} />
</ChartCard>
)}
@@ -473,7 +542,7 @@ export default function SystemDetail({ name }: { name: string }) {
cornerEl={containerFilterBar}
>
{/* @ts-ignore */}
<ContainerChart chartData={chartData} chartName="net" dataKey="n" />
<ContainerChart chartData={chartData} chartType={ChartType.Network} dataKey="n" />
</ChartCard>
</div>
)}
@@ -497,6 +566,7 @@ export default function SystemDetail({ name }: { name: string }) {
grid={grid}
title={t`Temperature`}
description={t`Temperatures of system sensors`}
cornerEl={<FilterBar store={$temperatureFilter} />}
>
<TemperatureChart chartData={chartData} />
</ChartCard>
@@ -520,6 +590,10 @@ export default function SystemDetail({ name }: { name: string }) {
<div className="grid xl:grid-cols-2 gap-4">
{Object.keys(systemStats.at(-1)?.stats.g ?? {}).map((id) => {
const gpu = systemStats.at(-1)?.stats.g?.[id] as GPUData
const sizeFormatter = (value: number, decimals?: number) => {
const { v, u } = getSizeAndUnit(value, false)
return toFixedFloat(v, decimals || 1) + u
}
return (
<div key={id} className="contents">
<ChartCard
@@ -539,12 +613,9 @@ export default function SystemDetail({ name }: { name: string }) {
<AreaChartDefault
chartData={chartData}
chartName={`g.${id}.mu`}
unit=" MB"
max={gpu.mt}
tickFormatter={(value) => {
const { v, u } = getSizeAndUnit(value, false)
return toFixedFloat(v, 1) + u
}}
tickFormatter={sizeFormatter}
contentFormatter={(value) => sizeFormatter(value, 2)}
/>
</ChartCard>
</div>
@@ -593,17 +664,17 @@ export default function SystemDetail({ name }: { name: string }) {
)
}
function ContainerFilterBar() {
const containerFilter = useStore($containerFilter)
const { _ } = useLingui()
function FilterBar({ store = $containerFilter }: { store?: typeof $containerFilter }) {
const containerFilter = useStore(store)
const { t } = useLingui()
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
$containerFilter.set(e.target.value)
store.set(e.target.value)
}, [])
return (
<>
<Input placeholder={_(t`Filter...`)} className="ps-4 pe-8" value={containerFilter} onChange={handleChange} />
<Input placeholder={t`Filter...`} className="ps-4 pe-8" value={containerFilter} onChange={handleChange} />
{containerFilter && (
<Button
type="button"
@@ -611,7 +682,7 @@ function ContainerFilterBar() {
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={() => $containerFilter.set("")}
onClick={() => store.set("")}
>
<XIcon className="h-4 w-4" />
</Button>

View File

@@ -10,6 +10,8 @@ import {
getCoreRowModel,
useReactTable,
HeaderContext,
Row,
Table as TableType,
} from "@tanstack/react-table"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
@@ -61,14 +63,13 @@ import {
PenBoxIcon,
} from "lucide-react"
import { memo, useEffect, useMemo, useRef, useState } from "react"
import { $hubVersion, $systems, pb } from "@/lib/stores"
import { $systems, pb } from "@/lib/stores"
import { useStore } from "@nanostores/react"
import { cn, copyToClipboard, decimalString, isReadOnlyUser, useLocalStorage } from "@/lib/utils"
import AlertsButton from "../alerts/alert-button"
import { $router, Link, navigate } from "../router"
import { EthernetIcon, GpuIcon, ThermometerIcon } from "../ui/icons"
import { Trans, t } from "@lingui/macro"
import { useLingui } from "@lingui/react"
import { useLingui, Trans } from "@lingui/react/macro"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"
import { Input } from "../ui/input"
import { ClassValue } from "clsx"
@@ -103,47 +104,66 @@ function CellFormatter(info: CellContext<SystemRecord, unknown>) {
function sortableHeader(context: HeaderContext<SystemRecord, unknown>) {
const { column } = context
// @ts-ignore
const { Icon, hideSort, name }: { Icon: React.ElementType; name: () => string; hideSort: boolean } = column.columnDef
return (
<Button
variant="ghost"
className="h-9 px-3 flex"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
{/* @ts-ignore */}
{column.columnDef.icon && <column.columnDef.icon className="me-2 size-4" />}
{column.id}
{/* @ts-ignore */}
{column.columnDef.hideSort || <ArrowUpDownIcon className="ms-2 size-4" />}
{Icon && <Icon className="me-2 size-4" />}
{name()}
{hideSort || <ArrowUpDownIcon className="ms-2 size-4" />}
</Button>
)
}
export default function SystemsTable() {
const data = useStore($systems)
const hubVersion = useStore($hubVersion)
const { i18n, t } = useLingui()
const [filter, setFilter] = useState<string>()
const [sorting, setSorting] = useState<SortingState>([{ id: t`System`, desc: false }])
const [sorting, setSorting] = useState<SortingState>([{ id: "system", desc: false }])
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
const [columnVisibility, setColumnVisibility] = useLocalStorage<VisibilityState>("cols", {})
const [viewMode, setViewMode] = useLocalStorage<ViewMode>("viewMode", window.innerWidth > 1024 ? "table" : "grid")
const { i18n } = useLingui()
const locale = i18n.locale
useEffect(() => {
if (filter !== undefined) {
table.getColumn(t`System`)?.setFilterValue(filter)
table.getColumn("system")?.setFilterValue(filter)
}
}, [filter])
const columns = useMemo(() => {
const columnDefs = useMemo(() => {
const statusTranslations = {
up: () => t`Up`.toLowerCase(),
down: () => t`Down`.toLowerCase(),
paused: () => t`Paused`.toLowerCase(),
}
return [
{
// size: 200,
size: 200,
minSize: 0,
accessorKey: "name",
id: t`System`,
id: "system",
name: () => t`System`,
filterFn: (row, _, filterVal) => {
const filterLower = filterVal.toLowerCase()
const { name, status } = row.original
// Check if the filter matches the name or status for this row
if (
name.toLowerCase().includes(filterLower) ||
statusTranslations[status as keyof typeof statusTranslations]?.().includes(filterLower)
) {
return true
}
return false
},
enableHiding: false,
icon: ServerIcon,
Icon: ServerIcon,
cell: (info) => (
<span className="flex gap-0.5 items-center text-base md:pe-5">
<IndicatorDot system={info.row.original} />
@@ -162,43 +182,48 @@ export default function SystemsTable() {
},
{
accessorKey: "info.cpu",
id: t`CPU`,
id: "cpu",
name: () => t`CPU`,
invertSorting: true,
cell: CellFormatter,
icon: CpuIcon,
Icon: CpuIcon,
header: sortableHeader,
},
{
accessorKey: "info.mp",
id: t`Memory`,
id: "memory",
name: () => t`Memory`,
invertSorting: true,
cell: CellFormatter,
icon: MemoryStickIcon,
Icon: MemoryStickIcon,
header: sortableHeader,
},
{
accessorKey: "info.dp",
id: t`Disk`,
id: "disk",
name: () => t`Disk`,
invertSorting: true,
cell: CellFormatter,
icon: HardDriveIcon,
Icon: HardDriveIcon,
header: sortableHeader,
},
{
accessorFn: (originalRow) => originalRow.info.g,
id: "GPU",
id: "gpu",
name: () => "GPU",
invertSorting: true,
sortUndefined: -1,
cell: CellFormatter,
icon: GpuIcon,
Icon: GpuIcon,
header: sortableHeader,
},
{
accessorFn: (originalRow) => originalRow.info.b || 0,
id: t`Net`,
id: "net",
name: () => t`Net`,
invertSorting: true,
size: 50,
icon: EthernetIcon,
Icon: EthernetIcon,
header: sortableHeader,
cell(info) {
const val = info.getValue() as number
@@ -215,15 +240,13 @@ export default function SystemsTable() {
},
{
accessorFn: (originalRow) => originalRow.info.dt,
id: t({
message: "Temp",
comment: "Temperature label in systems table",
}),
id: "temp",
name: () => t({ message: "Temp", comment: "Temperature label in systems table" }),
invertSorting: true,
sortUndefined: -1,
size: 50,
hideSort: true,
icon: ThermometerIcon,
Icon: ThermometerIcon,
header: sortableHeader,
cell(info) {
const val = info.getValue() as number
@@ -243,15 +266,16 @@ export default function SystemsTable() {
},
{
accessorKey: "info.v",
id: t`Agent`,
id: "agent",
name: () => t`Agent`,
invertSorting: true,
size: 50,
icon: WifiIcon,
Icon: WifiIcon,
hideSort: true,
header: sortableHeader,
cell(info) {
const version = info.getValue() as string
if (!version || !hubVersion) {
if (!version) {
return null
}
const system = info.row.original
@@ -265,7 +289,7 @@ export default function SystemsTable() {
system={system}
className={
(system.status !== "up" && "bg-primary/30") ||
(version === hubVersion && "bg-green-500") ||
(version === globalThis.BESZEL.HUB_VERSION && "bg-green-500") ||
"bg-yellow-500"
}
/>
@@ -275,7 +299,9 @@ export default function SystemsTable() {
},
},
{
id: t({ message: "Actions", comment: "Table column" }),
id: "actions",
// @ts-ignore
name: () => t({ message: "Actions", comment: "Table column" }),
size: 50,
cell: ({ row }) => (
<div className="flex justify-end items-center gap-1">
@@ -285,11 +311,11 @@ export default function SystemsTable() {
),
},
] as ColumnDef<SystemRecord>[]
}, [hubVersion, i18n.locale])
}, [])
const table = useReactTable({
data,
columns,
columns: columnDefs,
getCoreRowModel: getCoreRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
@@ -303,15 +329,17 @@ export default function SystemsTable() {
},
defaultColumn: {
minSize: 0,
size: Number.MAX_SAFE_INTEGER,
maxSize: Number.MAX_SAFE_INTEGER,
size: 900,
maxSize: 900,
},
})
const rows = table.getRowModel().rows
return (
<Card>
const columns = table.getAllColumns()
const visibleColumns = table.getVisibleLeafColumns()
// TODO: hiding temp then gpu messes up table headers
const CardHead = useMemo(() => {
return (
<CardHeader className="pb-5 px-2 sm:px-6 max-sm:pt-5 max-sm:pb-1">
<div className="grid md:flex gap-5 w-full items-end">
<div className="px-2 sm:px-1">
@@ -362,8 +390,8 @@ export default function SystemsTable() {
</DropdownMenuLabel>
<DropdownMenuSeparator />
<div className="px-1 pb-1">
{table.getAllColumns().map((column) => {
if (column.id === t`Actions` || !column.getCanSort()) return null
{columns.map((column) => {
if (!column.getCanSort()) return null
let Icon = <span className="w-6"></span>
// if current sort column, show sort direction
if (sorting[0]?.id === column.id) {
@@ -382,7 +410,8 @@ export default function SystemsTable() {
key={column.id}
>
{Icon}
{column.id}
{/* @ts-ignore */}
{column.columnDef.name()}
</DropdownMenuItem>
)
})}
@@ -396,8 +425,7 @@ export default function SystemsTable() {
</DropdownMenuLabel>
<DropdownMenuSeparator />
<div className="px-1.5 pb-1">
{table
.getAllColumns()
{columns
.filter((column) => column.getCanHide())
.map((column) => {
return (
@@ -407,7 +435,8 @@ export default function SystemsTable() {
checked={column.getIsVisible()}
onCheckedChange={(value) => column.toggleVisibility(!!value)}
>
{column.id}
{/* @ts-ignore */}
{column.columnDef.name()}
</DropdownMenuCheckboxItem>
)
})}
@@ -419,128 +448,24 @@ export default function SystemsTable() {
</div>
</div>
</CardHeader>
)
}, [visibleColumns.length, sorting, viewMode, locale])
return (
<Card>
{CardHead}
<div className="p-6 pt-0 max-sm:py-3 max-sm:px-2">
{viewMode === "table" ? (
// table layout
<div className="rounded-md border overflow-hidden">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow 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>
)
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{rows.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.original.id}
data-state={row.getIsSelected() && "selected"}
className={cn("cursor-pointer transition-opacity", {
"opacity-50": row.original.status === "paused",
})}
onClick={(e) => {
const target = e.target as HTMLElement
if (!target.closest("[data-nolink]") && e.currentTarget.contains(target)) {
navigate(getPagePath($router, "system", { name: row.original.name }))
}
}}
>
{row.getVisibleCells().map((cell) => (
<TableCell
key={cell.id}
style={{
width: cell.column.getSize() === Number.MAX_SAFE_INTEGER ? "auto" : cell.column.getSize(),
}}
className={cn("overflow-hidden relative", data.length > 10 ? "py-2" : "py-2.5")}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
<Trans>No systems found.</Trans>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<AllSystemsTable table={table} rows={rows} colLength={visibleColumns.length} />
</div>
) : (
// grid layout
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => {
const system = row.original
const { status } = system
return (
<Card
key={system.id}
className={cn(
"cursor-pointer hover:shadow-md transition-all bg-transparent w-full dark:border-border duration-200 relative",
{
"opacity-50": status === "paused",
}
)}
>
<CardHeader className="py-1 ps-5 pe-3 bg-muted/30 border-b border-border/60">
<div className="flex items-center justify-between gap-2">
<CardTitle className="text-base tracking-normal shrink-1 text-primary/90 flex items-center min-h-10 gap-2.5 min-w-0">
<div className="flex items-center gap-2.5 min-w-0">
<IndicatorDot system={system} />
<CardTitle className="text-[.95em]/normal tracking-normal truncate text-primary/90">
{system.name}
</CardTitle>
</div>
</CardTitle>
{table.getColumn(t`Actions`)?.getIsVisible() && (
<div className="flex gap-1 flex-shrink-0 relative z-10">
<AlertsButton system={system} />
<ActionsButton system={system} />
</div>
)}
</div>
</CardHeader>
<CardContent className="space-y-2.5 text-sm px-5 pt-3.5 pb-4">
{table.getAllColumns().map((column) => {
if (!column.getIsVisible() || column.id === t`System` || column.id === t`Actions`) return null
const cell = row.getAllCells().find((cell) => cell.column.id === column.id)
if (!cell) return null
return (
<div key={column.id} className="flex items-center gap-3">
{/* @ts-ignore */}
{column.columnDef?.icon && (
// @ts-ignore
<column.columnDef.icon className="size-4 text-muted-foreground" />
)}
<div className="flex items-center gap-3 flex-1">
<span className="text-muted-foreground min-w-16">{column.id}:</span>
<div className="flex-1">{flexRender(cell.column.columnDef.cell, cell.getContext())}</div>
</div>
</div>
)
})}
</CardContent>
<Link
href={getPagePath($router, "system", { name: row.original.name })}
className="inset-0 absolute w-full h-full"
>
<span className="sr-only">{row.original.name}</span>
</Link>
</Card>
)
{rows?.length ? (
rows.map((row) => {
return <SystemCard key={row.original.id} row={row} table={table} colLength={visibleColumns.length} />
})
) : (
<div className="col-span-full text-center py-8">
@@ -554,6 +479,247 @@ export default function SystemsTable() {
)
}
const AllSystemsTable = memo(
({ table, rows, colLength }: { table: TableType<SystemRecord>; rows: Row<SystemRecord>[]; colLength: number }) => {
return (
<Table>
<SystemsTableHead table={table} colLength={colLength} />
<TableBody>
{rows.length ? (
rows.map((row) => (
<SystemTableRow key={row.original.id} row={row} length={rows.length} colLength={colLength} />
))
) : (
<TableRow>
<TableCell colSpan={colLength} className="h-24 text-center">
<Trans>No systems found.</Trans>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
)
}
)
function SystemsTableHead({ table, colLength }: { table: TableType<SystemRecord>; colLength: number }) {
const { i18n } = useLingui()
return useMemo(() => {
return (
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead className="px-2" key={header.id}>
{flexRender(header.column.columnDef.header, header.getContext())}
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
)
}, [i18n.locale, colLength])
}
const SystemTableRow = memo(
({ row, length, colLength }: { row: Row<SystemRecord>; length: number; colLength: number }) => {
const system = row.original
const { t } = useLingui()
return useMemo(() => {
return (
<TableRow
// data-state={row.getIsSelected() && "selected"}
className={cn("cursor-pointer transition-opacity", {
"opacity-50": system.status === "paused",
})}
onClick={(e) => {
const target = e.target as HTMLElement
if (!target.closest("[data-nolink]") && e.currentTarget.contains(target)) {
navigate(getPagePath($router, "system", { name: system.name }))
}
}}
>
{row.getVisibleCells().map((cell) => (
<TableCell
key={cell.id}
style={{
width: cell.column.getSize(),
}}
className={cn("overflow-hidden relative", length > 10 ? "py-2" : "py-2.5")}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
)
}, [system, system.status, colLength, t])
}
)
const SystemCard = memo(
({ row, table, colLength }: { row: Row<SystemRecord>; table: TableType<SystemRecord>; colLength: number }) => {
const system = row.original
const { t } = useLingui()
return useMemo(() => {
return (
<Card
key={system.id}
className={cn(
"cursor-pointer hover:shadow-md transition-all bg-transparent w-full dark:border-border duration-200 relative",
{
"opacity-50": system.status === "paused",
}
)}
>
<CardHeader className="py-1 ps-5 pe-3 bg-muted/30 border-b border-border/60">
<div className="flex items-center justify-between gap-2">
<CardTitle className="text-base tracking-normal shrink-1 text-primary/90 flex items-center min-h-10 gap-2.5 min-w-0">
<div className="flex items-center gap-2.5 min-w-0">
<IndicatorDot system={system} />
<CardTitle className="text-[.95em]/normal tracking-normal truncate text-primary/90">
{system.name}
</CardTitle>
</div>
</CardTitle>
{table.getColumn("actions")?.getIsVisible() && (
<div className="flex gap-1 flex-shrink-0 relative z-10">
<AlertsButton system={system} />
<ActionsButton system={system} />
</div>
)}
</div>
</CardHeader>
<CardContent className="space-y-2.5 text-sm px-5 pt-3.5 pb-4">
{table.getAllColumns().map((column) => {
if (!column.getIsVisible() || column.id === "system" || column.id === "actions") return null
const cell = row.getAllCells().find((cell) => cell.column.id === column.id)
if (!cell) return null
// @ts-ignore
const { Icon, name } = column.columnDef as ColumnDef<SystemRecord, unknown>
return (
<div key={column.id} className="flex items-center gap-3">
{Icon && <Icon className="size-4 text-muted-foreground" />}
<div className="flex items-center gap-3 flex-1">
<span className="text-muted-foreground min-w-16">{name()}:</span>
<div className="flex-1">{flexRender(cell.column.columnDef.cell, cell.getContext())}</div>
</div>
</div>
)
})}
</CardContent>
<Link
href={getPagePath($router, "system", { name: row.original.name })}
className="inset-0 absolute w-full h-full"
>
<span className="sr-only">{row.original.name}</span>
</Link>
</Card>
)
}, [system, colLength, t])
}
)
const ActionsButton = memo(({ system }: { system: SystemRecord }) => {
const [deleteOpen, setDeleteOpen] = useState(false)
const [editOpen, setEditOpen] = useState(false)
let editOpened = useRef(false)
const { t } = useLingui()
const { id, status, host, name } = system
return useMemo(() => {
return (
<>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size={"icon"} data-nolink>
<span className="sr-only">
<Trans>Open menu</Trans>
</span>
<MoreHorizontalIcon className="w-5" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{!isReadOnlyUser() && (
<DropdownMenuItem
onSelect={() => {
editOpened.current = true
setEditOpen(true)
}}
>
<PenBoxIcon className="me-2.5 size-4" />
<Trans>Edit</Trans>
</DropdownMenuItem>
)}
<DropdownMenuItem
className={cn(isReadOnlyUser() && "hidden")}
onClick={() => {
pb.collection("systems").update(id, {
status: status === "paused" ? "pending" : "paused",
})
}}
>
{status === "paused" ? (
<>
<PlayCircleIcon className="me-2.5 size-4" />
<Trans>Resume</Trans>
</>
) : (
<>
<PauseCircleIcon className="me-2.5 size-4" />
<Trans>Pause</Trans>
</>
)}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => copyToClipboard(host)}>
<CopyIcon className="me-2.5 size-4" />
<Trans>Copy host</Trans>
</DropdownMenuItem>
<DropdownMenuSeparator className={cn(isReadOnlyUser() && "hidden")} />
<DropdownMenuItem className={cn(isReadOnlyUser() && "hidden")} onSelect={() => setDeleteOpen(true)}>
<Trash2Icon className="me-2.5 size-4" />
<Trans>Delete</Trans>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
{/* edit dialog */}
<Dialog open={editOpen} onOpenChange={setEditOpen}>
{editOpened.current && <SystemDialog system={system} setOpen={setEditOpen} />}
</Dialog>
{/* deletion dialog */}
<AlertDialog open={deleteOpen} onOpenChange={(open) => setDeleteOpen(open)}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
<Trans>Are you sure you want to delete {name}?</Trans>
</AlertDialogTitle>
<AlertDialogDescription>
<Trans>
This action cannot be undone. This will permanently delete all current records for {name} from the
database.
</Trans>
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>
<Trans>Cancel</Trans>
</AlertDialogCancel>
<AlertDialogAction
className={cn(buttonVariants({ variant: "destructive" }))}
onClick={() => pb.collection("systems").delete(id)}
>
<Trans>Continue</Trans>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
)
}, [id, status, host, name, t, deleteOpen, editOpen])
})
function IndicatorDot({ system, className }: { system: SystemRecord; className?: ClassValue }) {
className ||= {
"bg-green-500": system.status === "up",
@@ -568,99 +734,3 @@ function IndicatorDot({ system, className }: { system: SystemRecord; className?:
/>
)
}
const ActionsButton = memo(({ system }: { system: SystemRecord }) => {
const [deleteOpen, setDeleteOpen] = useState(false)
const [editOpen, setEditOpen] = useState(false)
let editOpened = useRef(false)
const { id, status, host, name } = system
return (
<>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size={"icon"} data-nolink>
<span className="sr-only">
<Trans>Open menu</Trans>
</span>
<MoreHorizontalIcon className="w-5" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{!isReadOnlyUser() && (
<DropdownMenuItem
onSelect={() => {
editOpened.current = true
setEditOpen(true)
}}
>
<PenBoxIcon className="me-2.5 size-4" />
<Trans>Edit</Trans>
</DropdownMenuItem>
)}
<DropdownMenuItem
className={cn(isReadOnlyUser() && "hidden")}
onClick={() => {
pb.collection("systems").update(id, {
status: status === "paused" ? "pending" : "paused",
})
}}
>
{status === "paused" ? (
<>
<PlayCircleIcon className="me-2.5 size-4" />
<Trans>Resume</Trans>
</>
) : (
<>
<PauseCircleIcon className="me-2.5 size-4" />
<Trans>Pause</Trans>
</>
)}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => copyToClipboard(host)}>
<CopyIcon className="me-2.5 size-4" />
<Trans>Copy host</Trans>
</DropdownMenuItem>
<DropdownMenuSeparator className={cn(isReadOnlyUser() && "hidden")} />
<DropdownMenuItem className={cn(isReadOnlyUser() && "hidden")} onSelect={() => setDeleteOpen(true)}>
<Trash2Icon className="me-2.5 size-4" />
<Trans>Delete</Trans>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
{/* edit dialog */}
<Dialog open={editOpen} onOpenChange={setEditOpen}>
{editOpened.current && <SystemDialog system={system} setOpen={setEditOpen} />}
</Dialog>
{/* deletion dialog */}
<AlertDialog open={deleteOpen} onOpenChange={(open) => setDeleteOpen(open)}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
<Trans>Are you sure you want to delete {name}?</Trans>
</AlertDialogTitle>
<AlertDialogDescription>
<Trans>
This action cannot be undone. This will permanently delete all current records for {name} from the
database.
</Trans>
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>
<Trans>Cancel</Trans>
</AlertDialogCancel>
<AlertDialogAction
className={cn(buttonVariants({ variant: "destructive" }))}
onClick={() => pb.collection("systems").delete(id)}
>
<Trans>Continue</Trans>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
)
})

View File

@@ -99,6 +99,7 @@ const ChartTooltipContent = React.forwardRef<
unit?: string
filter?: string
contentFormatter?: (item: any, key: string) => React.ReactNode | string
truncate?: boolean
}
>(
(
@@ -119,6 +120,7 @@ const ChartTooltipContent = React.forwardRef<
filter,
itemSorter,
contentFormatter: content = undefined,
truncate = false,
},
ref
) => {
@@ -127,7 +129,7 @@ const ChartTooltipContent = React.forwardRef<
React.useMemo(() => {
if (filter) {
payload = payload?.filter((item) => (item.name as string)?.includes(filter))
payload = payload?.filter((item) => (item.name as string)?.toLowerCase().includes(filter.toLowerCase()))
}
if (itemSorter) {
// @ts-ignore
@@ -214,10 +216,15 @@ const ChartTooltipContent = React.forwardRef<
nestLabel ? "items-end" : "items-center"
)}
>
<div className="grid gap-1.5">
{nestLabel ? tooltipLabel : null}
<span className="text-muted-foreground">{itemConfig?.label || item.name}</span>
</div>
{nestLabel ? tooltipLabel : null}
<span
className={cn(
"text-muted-foreground",
truncate ? "max-w-40 truncate leading-normal -my-1" : ""
)}
>
{itemConfig?.label || item.name}
</span>
{item.value !== undefined && (
<span className="font-medium tabular-nums text-foreground">
{content && typeof content === "function"

View File

@@ -12,6 +12,42 @@ export function TuxIcon(props: SVGProps<SVGSVGElement>) {
)
}
// icon park (Apache 2.0) https://github.com/bytedance/IconPark/blob/master/LICENSE
export function WindowsIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox="0 0 48 48">
<path
fill="none"
stroke="currentColor"
strokeWidth="3.8"
d="m6.8 11 12.9-1.7v12.1h-13zm18-2.2 16.4-2v14.6H25zm0 18.6 16.4.4v13.4L25 38.6zm-18-.8 12.9.3v10.9l-13-2.2z"
/>
</svg>
)
}
// teenyicons (MIT) https://github.com/teenyicons/teenyicons/blob/master/LICENSE
export function AppleIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg viewBox="0 0 20 20" {...props}>
<path
fill="currentColor"
d="M14.1 4.7a5 5 0 0 1 3.8 2c-3.3 1.9-2.8 6.7.6 8L17.2 17c-.8 1.3-2 2.9-3.5 2.9-1.2 0-1.6-.9-3.3-.8s-2.2.8-3.5.8c-1.4 0-2.5-1.5-3.4-2.7-2.3-3.6-2.5-7.9-1.1-10 1-1.7 2.6-2.6 4.1-2.6 1.6 0 2.6.8 3.8.8 1.3 0 2-.8 3.8-.8M13.7 0c.2 1.2-.3 2.4-1 3.2a4 4 0 0 1-3 1.6c-.2-1.2.3-2.3 1-3.2.7-.8 2-1.5 3-1.6"
/>
</svg>
)
}
// ion icons (MIT) https://github.com/ionic-team/ionicons/blob/main/LICENSE
export function DockerIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox="0 0 512 512" fill="currentColor">
<path d="M507 211c-1-1-14-11-42-11a133 133 0 0 0-21 2c-6-36-36-54-37-55l-7-4-5 7a102 102 0 0 0-13 30c-5 21-2 40 8 57-12 7-33 9-37 9H16a16 16 0 0 0-16 16 241 241 0 0 0 15 87c11 30 29 53 51 67 25 15 66 24 113 24a344 344 0 0 0 62-6 257 257 0 0 0 82-29 224 224 0 0 0 55-46c27-30 43-64 55-94h4c30 0 48-12 58-22a63 63 0 0 0 15-22l2-6Z" />
<path d="M47 236h45a4 4 0 0 0 4-4v-40a4 4 0 0 0-4-4H47a4 4 0 0 0-4 4v40a4 4 0 0 0 4 4m63 0h45a4 4 0 0 0 4-4v-40a4 4 0 0 0-4-4h-45a4 4 0 0 0-4 4v40a4 4 0 0 0 4 4m63 0h45a4 4 0 0 0 4-4v-40a4 4 0 0 0-4-4h-45a4 4 0 0 0-4 4v40a4 4 0 0 0 4 4m62 0h45a4 4 0 0 0 4-4v-40a4 4 0 0 0-4-4h-45a4 4 0 0 0-4 4v40a4 4 0 0 0 4 4m-125-57h45a4 4 0 0 0 4-4v-41a4 4 0 0 0-4-4h-45a4 4 0 0 0-4 4v41a4 4 0 0 0 4 4m63 0h45a4 4 0 0 0 4-4v-41a4 4 0 0 0-4-4h-45a4 4 0 0 0-4 4v41a4 4 0 0 0 4 4m62 0h45a4 4 0 0 0 4-4v-41a4 4 0 0 0-4-4h-45a4 4 0 0 0-4 4v41a4 4 0 0 0 4 4m0-58h45a4 4 0 0 0 4-4V76a4 4 0 0 0-4-4h-45a4 4 0 0 0-4 4v40a4 4 0 0 0 4 4m63 116h45a4 4 0 0 0 4-4v-40a4 4 0 0 0-4-4h-45a4 4 0 0 0-4 4v40a4 4 0 0 0 4 4" />
</svg>
)
}
// MingCute Apache License 2.0 https://github.com/Richard9394/MingCute
export function Rows(props: SVGProps<SVGSVGElement>) {
return (

View File

@@ -74,6 +74,7 @@
@layer base {
* {
@apply border-border;
overflow-anchor: none;
}
body {
@apply bg-background text-foreground;

View File

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

View File

@@ -3,15 +3,7 @@ import { i18n } from "@lingui/core"
import type { Messages } from "@lingui/core"
import languages from "@/lib/languages"
import { detect, fromStorage, fromNavigator } from "@lingui/detect-locale"
import { messages as enMessages } from "@/locales/en/en.ts"
// let locale = detect(fromUrl("lang"), fromStorage("lang"), fromNavigator(), "en")
let locale = detect(fromStorage("lang"), fromNavigator(), "en")
// log if dev
if (import.meta.env.DEV) {
console.log("detected locale", locale)
}
import { messages as enMessages } from "@/locales/en/en"
// activates locale
function activateLocale(locale: string, messages: Messages = enMessages) {
@@ -37,21 +29,28 @@ export async function dynamicActivate(locale: string) {
}
}
// handle zh variants
if (locale?.startsWith("zh-")) {
// map zh variants to zh-CN
const zhVariantMap: Record<string, string> = {
"zh-HK": "zh-HK",
"zh-TW": "zh",
"zh-MO": "zh",
"zh-Hant": "zh",
export function getLocale() {
// let locale = detect(fromUrl("lang"), fromStorage("lang"), fromNavigator(), "en")
let locale = detect(fromStorage("lang"), fromNavigator(), "en")
// log if dev
if (import.meta.env.DEV) {
console.log("detected locale", locale)
}
// handle zh variants
if (locale?.startsWith("zh-")) {
// map zh variants to zh-CN
const zhVariantMap: Record<string, string> = {
"zh-HK": "zh-HK",
"zh-TW": "zh",
"zh-MO": "zh",
"zh-Hant": "zh",
}
return zhVariantMap[locale] || "zh-CN"
}
dynamicActivate(zhVariantMap[locale] || "zh-CN")
} else {
locale = (locale || "en").split("-")[0]
// use en if locale is not in languages
if (!languages.some((l) => l.lang === locale)) {
locale = "en"
}
dynamicActivate(locale)
return locale
}

View File

@@ -18,9 +18,6 @@ export const $alerts = atom([] as AlertRecord[])
/** SSH public key */
export const $publicKey = atom("")
/** Beszel hub version */
export const $hubVersion = atom("")
/** Chart time period */
export const $chartTime = atom("1h") as PreinitializedWritableAtom<ChartTimes>
@@ -41,6 +38,9 @@ $userSettings.subscribe((value) => {
/** Container chart filter */
export const $containerFilter = atom("")
/** Temperature chart filter */
export const $temperatureFilter = atom("")
/** Fallback copy to clipboard dialog content */
export const $copyContent = atom("")

View File

@@ -1,3 +1,4 @@
import { t } from "@lingui/core/macro";
import { toast } from "@/components/ui/use-toast"
import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"
@@ -9,13 +10,21 @@ import { timeDay, timeHour } from "d3-time"
import { useEffect, useState } from "react"
import { CpuIcon, HardDriveIcon, MemoryStickIcon, ServerIcon } from "lucide-react"
import { EthernetIcon, ThermometerIcon } from "@/components/ui/icons"
import { t } from "@lingui/macro"
import { prependBasePath } from "@/components/router"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
// export const cn = clsx
/** Adds event listener to node and returns function that removes the listener */
export function listen<T extends Event = Event>(
node: Node,
event: string,
handler: (event: T) => void
) {
node.addEventListener(event, handler as EventListener)
return () => node.removeEventListener(event, handler as EventListener)
}
export async function copyToClipboard(content: string) {
const duration = 1500
@@ -68,6 +77,7 @@ export const updateSystemList = (() => {
/** Logs the user out by clearing the auth store and unsubscribing from realtime updates. */
export async function logOut() {
sessionStorage.setItem("lo", "t")
pb.authStore.clear()
pb.realtime.unsubscribe()
}

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ar\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:53\n"
"PO-Revision-Date: 2025-03-06 07:27\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"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# يوم} 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 "تم تحديد {0} من {1} صف"
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# ساعة} other {# ساعات}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# ساعة} other {# ساعات}}"
msgid "1 hour"
msgstr "1 ساعة"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr "دقيقة واحدة"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 أسبوع"
@@ -50,11 +39,6 @@ msgstr "1 أسبوع"
msgid "12 hours"
msgstr "12 ساعة"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr "15 دقيقة"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 ساعة"
@@ -63,22 +47,11 @@ msgstr "24 ساعة"
msgid "30 days"
msgstr "30 يومًا"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr "5 دقائق"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "إجراءات"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr "نشط"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "التنبيهات النشطة"
@@ -97,12 +70,15 @@ msgstr "إضافة نظام"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "إضافة رابط"
msgstr "إضافة عنوان URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "تعديل خيارات العرض للرسوم البيانية."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "مسؤول"
msgid "Agent"
msgstr "وكيل"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr "سجل التنبيهات"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "جميع الأنظمة"
msgid "Are you sure you want to delete {name}?"
msgstr "هل أنت متأكد أنك تريد حذف {name}؟"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr "هل أنت متأكد؟"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "النسخ التلقائي يتطلب سياقًا آمنًا."
@@ -155,7 +121,7 @@ msgstr "المتوسط يتجاوز <0>{value}{0}</0>"
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
msgstr "متوسط ​​استهلاك طاقة وحدة معالجة الرسوميات"
msgstr "متوسط ​​استهلاك طاقة GPUs"
#: src/components/routes/system.tsx
msgid "Average system-wide CPU utilization"
@@ -178,7 +144,7 @@ msgstr "عرض النطاق الترددي"
#: src/components/login/auth-form.tsx
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
msgstr "يدعم بيزيل بروتوكول OpenID Connect والعديد من مزوّدي المصادقة عبر بروتوكول OAuth2."
msgstr "يدعم Beszel OpenID Connect والعديد من مزودي المصادقة OAuth2."
#: src/components/routes/settings/notifications.tsx
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
@@ -188,22 +154,11 @@ msgstr "يستخدم بيزيل <0>Shoutrrr</0> للتكامل مع خدمات
msgid "Binary"
msgstr "ثنائي"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr "بت (كيلوبت/ثانية، ميجابت/ثانية، جيجابت/ثانية)"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr "بايت (كيلوبايت/ثانية، ميجابايت/ثانية، جيجابايت/ثانية)"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "ذاكرة التخزين المؤقت / المخازن المؤقتة"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "إلغاء"
@@ -211,14 +166,6 @@ msgstr "إلغاء"
msgid "Caution - potential data loss"
msgstr "تحذير - فقدان محتمل للبيانات"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr "درجة مئوية (°م)"
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr "تغيير وحدات عرض المقاييس."
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "تغيير خيارات التطبيق العامة."
@@ -239,7 +186,7 @@ msgstr "تحقق من السجلات لمزيد من التفاصيل."
msgid "Check your notification service"
msgstr "تحقق من خدمة الإشعارات الخاصة بك"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "انقر للنسخ"
@@ -257,12 +204,7 @@ msgstr "قم بتكوين كيفية تلقي إشعارات التنبيه."
msgid "Confirm password"
msgstr "تأكيد كلمة المرور"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr "الاتصال مقطوع"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "متابعة"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "تم النسخ إلى الحافظة"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "نسخ أمر تركيب الدوكر"
msgstr "نسخ docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "نسخ أمر تشغيل الدوكر"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "نسخ متغيرات البيئة"
msgstr "نسخ docker run"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "نسخ المضيف"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "نسخ أمر لينكس"
@@ -300,25 +234,13 @@ msgstr "نسخ أمر لينكس"
msgid "Copy text"
msgstr "نسخ النص"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "انسخ أمر التثبيت للوكيل أدناه، أو سجل الوكلاء تلقائياً باستخدام <0>رمز مميز عالمي</0>."
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr "انسخ محتوى <0>docker-compose.yml</0> للوكيل أدناه، أو سجل الوكلاء تلقائياً باستخدام <1>رمز مميز عالمي</1>."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "نسخ YAML"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "المعالج"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "استخدام وحدة المعالجة المركزية"
@@ -326,11 +248,6 @@ msgstr "استخدام وحدة المعالجة المركزية"
msgid "Create account"
msgstr "إنشاء حساب"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr "أنشئت"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "الفترة الزمنية الافتراضية"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "حذف"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "حذف البصمة"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "القرص"
@@ -362,10 +274,6 @@ msgstr "القرص"
msgid "Disk I/O"
msgstr "إدخال/إخراج القرص"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr "وحدة القرص"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -378,15 +286,15 @@ msgstr "استخدام القرص لـ {extraFsName}"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "استخدام المعالج للدوكر"
msgstr "استخدام المعالج لـ Docker"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "استخدام الذاكرة للدوكر"
msgstr "استخدام الذاكرة لـ Docker"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "إدخال/إخراج الشبكة للدوكر"
msgstr "إدخال/إخراج الشبكة لـ Docker"
#: src/components/command-palette.tsx
msgid "Documentation"
@@ -394,16 +302,11 @@ msgstr "التوثيق"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "معطل"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr "المدة"
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "أدخل عنوان البريد الإشباكي لإعادة تعيي
msgid "Enter email address..."
msgstr "أدخل عنوان البريد الإشباكي..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "خطأ"
@@ -445,10 +346,6 @@ msgstr "يتجاوز {0}{1} في آخر {2, plural, one {# دقيقة} other {#
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "سيتم حذف الأنظمة الحالية غير المعرفة في <0>config.yml</0>. يرجى عمل نسخ احتياطية بانتظام."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr "تصدير"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "تصدير التكوين"
@@ -457,10 +354,6 @@ msgstr "تصدير التكوين"
msgid "Export your current systems configuration."
msgstr "تصدير تكوين الأنظمة الحالية الخاصة بك."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr "فهرنهايت (°ف)"
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "فشل في المصادقة"
@@ -480,14 +373,9 @@ msgstr "فشل في تحديث التنبيه"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "تصفية..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr "البصمة"
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "لمدة <0>{min}</0> {min, plural, one {دقيقة} other {دقائق}}"
@@ -504,14 +392,13 @@ msgstr "عام"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
msgstr "استهلاك طاقة وحدة معالجة الرسوميات"
msgstr "استهلاك طاقة GPU"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "شبكة"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "أمر Homebrew"
@@ -546,27 +433,6 @@ msgstr "التخطيط"
msgid "Light"
msgstr "فاتح"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr "متوسط التحميل"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr "متوسط التحميل 15 دقيقة"
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr "متوسط التحميل 1 دقيقة"
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr "متوسط التحميل 5 دقائق"
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr "متوسط التحميل"
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "تسجيل الخروج"
@@ -600,7 +466,7 @@ msgstr "تعليمات الإعداد اليدوي"
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
msgid "Max 1 min"
msgstr "الحد الأقصى دقيقة"
msgstr "1 دقيقة كحد"
#: src/components/systems-table/systems-table.tsx
msgid "Memory"
@@ -613,9 +479,8 @@ msgstr "استخدام الذاكرة"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "استخدام الذاكرة لحاويات دوكر"
msgstr "استخدام الذاكرة لحاويات Docker"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "الاسم"
@@ -626,25 +491,16 @@ msgstr "الشبكة"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
msgstr "حركة مرور الشبكة لحاويات الدوكر"
msgstr "حركة مرور الشبكة لحاويات Docker"
#: src/components/routes/system.tsx
msgid "Network traffic of public interfaces"
msgstr "حركة مرور الشبكة للواجهات العامة"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr "وحدة الشبكة"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "لم يتم العثور على نتائج."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr "لا توجد نتائج."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "في كل إعادة تشغيل، سيتم تحديث الأنظمة في قاعدة البيانات لتتطابق مع الأنظمة المعرفة في الملف."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "فتح القائمة"
@@ -682,12 +536,6 @@ msgstr "الكتابة فوق التنبيهات الحالية"
msgid "Page"
msgstr "صفحة"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr "صفحة {0} من {1}"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "الصفحات / الإعدادات"
@@ -715,7 +563,7 @@ msgstr "إيقاف مؤقت"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "متوقف مؤقتا"
msgstr "متوقف مؤقتًا"
#: src/components/routes/settings/notifications.tsx
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "المفتاح العام"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "قراءة"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "تم الاستلام"
@@ -782,24 +631,10 @@ msgstr "تم الاستلام"
msgid "Reset Password"
msgstr "إعادة تعيين كلمة المرور"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr "تم حلها"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "استئناف"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "تدوير الرمز المميز"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr "صفوف لكل صفحة"
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "احفظ العنوان باستخدام مفتاح الإدخال أو الفاصلة. اتركه فارغًا لتعطيل إشعارات البريد الإشباكي."
@@ -825,7 +660,8 @@ msgstr "البحث عن الأنظمة أو الإعدادات..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "راجع <0>إعدادات الإشعارات</0> لتكوين كيفية تلقي التنبيهات."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "تم الإرسال"
@@ -833,6 +669,7 @@ msgstr "تم الإرسال"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "يحدد النطاق الزمني الافتراضي للرسوم البيانية عند عرض النظام."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "إعدادات SMTP"
msgid "Sort By"
msgstr "الترتيب حسب"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr "الحالة"
#: src/lib/utils.ts
msgid "Status"
msgstr "الحالة"
@@ -876,16 +708,10 @@ msgstr "استخدام التبديل"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "النظام"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr "متوسط تحميل النظام مع مرور الوقت"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "الأنظمة"
@@ -908,10 +734,6 @@ msgstr "درجة الحرارة"
msgid "Temperature"
msgstr "درجة الحرارة"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr "وحدة درجة الحرارة"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "درجات حرارة مستشعرات النظام"
@@ -924,6 +746,14 @@ msgstr "اختبار <0>URL</0>"
msgid "Test notification sent"
msgstr "تم إرسال إشعار الاختبار"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "يجب أن يكون الوكيل قيد التشغيل على النظام للاتصال. انسخ أمر التثبيت للوكيل أدناه."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "يجب أن يكون الوكيل قيد التشغيل على النظام للاتصال. انسخ <0>docker-compose.yml</0> للوكيل أدناه."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "ثم قم بتسجيل الدخول إلى الواجهة الخلفية وأعد تعيين كلمة مرور حساب المستخدم الخاص بك في جدول المستخدمين."
@@ -932,10 +762,6 @@ msgstr "ثم قم بتسجيل الدخول إلى الواجهة الخلفية
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "لا يمكن التراجع عن هذا الإجراء. سيؤدي ذلك إلى حذف جميع السجلات الحالية لـ {name} من قاعدة البيانات بشكل دائم."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr "سيؤدي هذا إلى حذف جميع السجلات المحددة من قاعدة البيانات بشكل دائم."
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "معدل نقل {extraFsName}"
@@ -957,40 +783,9 @@ msgstr "تبديل الشبكة"
msgid "Toggle theme"
msgstr "تبديل السمة"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "رمز مميز"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "الرموز المميزة والبصمات"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr "تسمح الرموز المميزة للوكلاء بالاتصال والتسجيل. البصمات هي معرفات مستقرة فريدة لكل نظام، يتم تعيينها عند الاتصال الأول."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "تُستخدم الرموز المميزة والبصمات للمصادقة على اتصالات WebSocket إلى المحور."
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr "يتم التفعيل عندما يتجاوز متوسط التحميل لمدة دقيقة واحدة عتبة معينة"
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr "يتم التفعيل عندما يتجاوز متوسط التحميل لمدة 15 دقيقة عتبة معينة"
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr "يتم التفعيل عندما يتجاوز متوسط التحميل لمدة 5 دقائق عتبة معينة"
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "يتم التفعيل عندما <EFBFBD><EFBFBD>تجاوز أي مستشعر عتبة معينة"
msgstr "يتم التفعيل عندما يتجاوز أي مستشعر عتبة معينة"
#: src/lib/utils.ts
msgid "Triggers when combined up/down exceeds a threshold"
@@ -1012,15 +807,6 @@ msgstr "يتم التفعيل عندما يتغير الحالة بين التش
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "يتم التفعيل عندما يتجاوز استخدام أي قرص عتبة معينة"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr "تفضيلات الوحدة"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "رمز مميز عالمي"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "مدة التشغيل"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "الاستخدام"
@@ -1048,6 +833,7 @@ msgstr "استخدام القسم الجذر"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "مستخدم"
@@ -1056,18 +842,10 @@ msgstr "مستخدم"
msgid "Users"
msgstr "المستخدمون"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "القيمة"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "عرض"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr "عرض أحدث 200 تنبيه."
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "الأعمدة الظاهرة"
@@ -1084,19 +862,14 @@ msgstr "هل تريد مساعدتنا في تحسين ترجماتنا؟ تحق
msgid "Webhook / Push notifications"
msgstr "إشعارات Webhook / Push"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "عند التفعيل، يسمح هذا الرمز المميز للوكلاء بالتسجيل الذاتي دون إنشاء نظام مسبق. ينتهي بعد ساعة واحدة أو عند إعادة تشغيل المحور."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "أمر ويندوز"
msgstr "أمر Windows"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "كتابة"
@@ -1111,4 +884,3 @@ msgstr "تكوين YAML"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "تم تحديث إعدادات المستخدم الخاصة بك."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: bg\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:53\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Bulgarian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# ден} 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# час} other {# часа}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# час} other {# часа}}"
msgid "1 hour"
msgstr "1 час"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 седмица"
@@ -50,11 +39,6 @@ msgstr "1 седмица"
msgid "12 hours"
msgstr "12 часа"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 часа"
@@ -63,22 +47,11 @@ msgstr "24 часа"
msgid "30 days"
msgstr "30 дни"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Действия"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Активни тревоги"
@@ -103,6 +76,9 @@ msgstr "Добави URL"
msgid "Adjust display options for charts."
msgstr "Настрой опциите за показване на диаграмите."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Администратор"
msgid "Agent"
msgstr "Агент"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Всички системи"
msgid "Are you sure you want to delete {name}?"
msgstr "Сигурен ли си, че искаш да изтриеш {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Автоматичното копиране изисква защитен контескт."
@@ -188,22 +154,11 @@ msgstr "Beszel ползва <0>Shoutrrr</0> за да се интегрира с
msgid "Binary"
msgstr "Двоичен код"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Кеш / Буфери"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Откажи"
@@ -211,14 +166,6 @@ msgstr "Откажи"
msgid "Caution - potential data loss"
msgstr "Внимание - възможност за загуба на данни"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Смени общите опции на приложението."
@@ -239,7 +186,7 @@ msgstr "Провери log-овете за повече информация."
msgid "Check your notification service"
msgstr "Провери услугата си за удостоверяване"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Настисни за да копираш"
@@ -257,12 +204,7 @@ msgstr "Настрой как получаваш нотификации за т
msgid "Confirm password"
msgstr "Потвърди парола"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Продължи"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Записано в клипборда"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Копирай docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Копирай docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Копирай хоста"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Копирай linux командата"
@@ -300,25 +234,13 @@ msgstr "Копирай linux командата"
msgid "Copy text"
msgstr "Копирай текста"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "Процесор"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Употреба на процесор"
@@ -326,11 +248,6 @@ msgstr "Употреба на процесор"
msgid "Create account"
msgstr "Създай акаунт"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Времеви диапазон по подразбиране"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Изтрий"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Диск"
@@ -362,10 +274,6 @@ msgstr "Диск"
msgid "Disk I/O"
msgstr "Диск I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Документация"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "Въведи имейл адрес за да нулираш парола
msgid "Enter email address..."
msgstr "Въведи имейл адрес..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Грешка"
@@ -445,10 +346,6 @@ msgstr "Надвишава {0}{1} в последните {2, plural, one {# м
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "Съществуващи системи които не са дефинирани в <0>config.yml</0> ще бъдат изтрити. Моля прави чести архиви."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Експортирай конфигурация"
@@ -457,10 +354,6 @@ msgstr "Експортирай конфигурация"
msgid "Export your current systems configuration."
msgstr "Експортирай конфигурацията на системите."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Неуспешно удостоверяване"
@@ -480,14 +373,9 @@ msgstr "Неуспешно обнови тревога"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Филтрирай..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "За <0>{min}</0> {min, plural, one {минута} other {минути}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Мрежово"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Команда Homebrew"
@@ -546,27 +433,6 @@ msgstr "Подреждане"
msgid "Light"
msgstr "Светъл"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Изход"
@@ -615,7 +481,6 @@ msgstr "Употреба на паметта"
msgid "Memory usage of docker containers"
msgstr "Използването на памет от docker контейнерите"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Име"
@@ -632,19 +497,10 @@ msgstr "Мрежов трафик на docker контейнери"
msgid "Network traffic of public interfaces"
msgstr "Мрежов трафик на публични интерфейси"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Няма намерени резултати."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "На всеки рестарт, системите в датабазата ще бъдат обновени да съвпадат със системите зададени във файла."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Отвори менюто"
@@ -682,12 +536,6 @@ msgstr "Презапиши съществуващи тревоги"
msgid "Page"
msgstr "Страница"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Страници / Настройки"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Публичен ключ"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Прочети"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Получени"
@@ -782,24 +631,10 @@ msgstr "Получени"
msgid "Reset Password"
msgstr "Нулиране на парола"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Възобнови"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Запази адреса с enter или запетая. Остави празно за да изключиш нотификациите чрез имейл."
@@ -825,7 +660,8 @@ msgstr "Търси за системи или настройки..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Виж <0>настройките за нотификациите</0> за да конфигурираш как получаваш тревоги."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Изпратени"
@@ -833,6 +669,7 @@ msgstr "Изпратени"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Задава диапазона за време за диаграмите, когато се разглежда система."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "Настройки за SMTP"
msgid "Sort By"
msgstr "Сортиране по"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Статус"
@@ -876,16 +708,10 @@ msgstr "Използване на swap"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Система"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Системи"
@@ -908,10 +734,6 @@ msgstr ""
msgid "Temperature"
msgstr "Температура"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Температири на системни сензори"
@@ -924,6 +746,14 @@ msgstr "Тествай <0>URL</0>"
msgid "Test notification sent"
msgstr "Тестова нотификация изпратена"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "Агента трябва да работи на системата за да се свърже. Копирай инсталационната команда за агента долу."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "Агемта трябва да работи на системата за да се свърже. Копирай <0>docker-compose.yml</0> файла за агента долу."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "След това влез в backend-а и нулирай паролата за потребителския акаунт в таблицата за потребители."
@@ -932,10 +762,6 @@ msgstr "След това влез в backend-а и нулирай парола
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Това действие не може да бъде отменено. Това ще изтрие всички записи за {name} от датабазата."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Пропускателна способност на {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Превключване на мрежа"
msgid "Toggle theme"
msgstr "Включи тема"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Задейства се, когато някой даден сензор надвиши зададен праг"
@@ -1012,15 +807,6 @@ msgstr "Задейства се, когато статуса превключв
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Задейства се, когато употребата на някой диск надивши зададен праг"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "Време на работа"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Употреба"
@@ -1048,6 +833,7 @@ msgstr "Употреба на root partition-а"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Използвани"
@@ -1056,18 +842,10 @@ msgstr "Използвани"
msgid "Users"
msgstr "Потребители"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Изглед"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Видими полета"
@@ -1084,19 +862,14 @@ msgstr "Искаш да помогнеш да направиш преводит
msgid "Webhook / Push notifications"
msgstr "Webhook / Пуш нотификации"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Команда Windows"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Запиши"
@@ -1111,4 +884,3 @@ msgstr "YAML конфигурация"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Настройките за потребителя ти са обновени."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: cs\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:53\n"
"PO-Revision-Date: 2025-03-14 00:50\n"
"Last-Translator: \n"
"Language-Team: Czech\n"
"Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 3;\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# den} few {# dny} other {# dní}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# Hodina} few {# Hodiny} many {# Hodin} other {# Hodin}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# Hodina} few {# Hodiny} many {# Hodin} other {# Ho
msgid "1 hour"
msgstr "1 hodina"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 týden"
@@ -50,11 +39,6 @@ msgstr "1 týden"
msgid "12 hours"
msgstr "12 hodin"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 hodin"
@@ -63,22 +47,11 @@ msgstr "24 hodin"
msgid "30 days"
msgstr "30 dní"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Akce"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktivní výstrahy"
@@ -103,6 +76,9 @@ msgstr "Přidat URL"
msgid "Adjust display options for charts."
msgstr "Upravit možnosti zobrazení pro grafy."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Admin"
msgid "Agent"
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Všechny systémy"
msgid "Are you sure you want to delete {name}?"
msgstr "Opravdu chcete odstranit {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Automatická kopie vyžaduje zabezpečený kontext."
@@ -188,22 +154,11 @@ msgstr "Beszel používá <0>Shoutrrr</0> k integraci s populárními notifikač
msgid "Binary"
msgstr "Binary"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / vyrovnávací paměť"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Zrušit"
@@ -211,14 +166,6 @@ msgstr "Zrušit"
msgid "Caution - potential data loss"
msgstr "Upozornění - možná ztráta dat"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Změnit obecné nastavení aplikace."
@@ -239,7 +186,7 @@ msgstr "Pro více informací zkontrolujte logy."
msgid "Check your notification service"
msgstr "Zkontrolujte službu upozornění"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Klikněte pro zkopírování"
@@ -257,12 +204,7 @@ msgstr "Konfigurace způsobu přijímání upozornění."
msgid "Confirm password"
msgstr "Potvrdit heslo"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Pokračovat"
@@ -271,20 +213,13 @@ msgid "Copied to clipboard"
msgstr "Zkopírováno do schránky"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Kopírovat docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Zkopírovat příkaz na spuštění dockeru"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
@@ -292,7 +227,6 @@ msgid "Copy host"
msgstr "Kopírovat hostitele"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopírovat příkaz Linux"
@@ -300,25 +234,13 @@ msgstr "Kopírovat příkaz Linux"
msgid "Copy text"
msgstr "Kopírovat text"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "Procesor"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Využití procesoru"
@@ -326,11 +248,6 @@ msgstr "Využití procesoru"
msgid "Create account"
msgstr "Vytvořit účet"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Výchozí doba"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Odstranit"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
@@ -362,10 +274,6 @@ msgstr "Disk"
msgid "Disk I/O"
msgstr "Disk I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Dokumentace"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Nefunkční"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "Zadejte e-mailovou adresu pro obnovu hesla"
msgid "Enter email address..."
msgstr "Zadejte e-mailovou adresu..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Chyba"
@@ -445,10 +346,6 @@ msgstr "Překračuje {0}{1} za {2, plural, one {poslední # minutu} few {posledn
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "Stávající systémy, které nejsou definovány v <0>config.yml</0>, budou odstraněny. Provádějte pravidelné zálohování."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Exportovat konfiguraci"
@@ -457,10 +354,6 @@ msgstr "Exportovat konfiguraci"
msgid "Export your current systems configuration."
msgstr "Exportovat aktuální konfiguraci systémů."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Ověření se nezdařilo"
@@ -480,14 +373,9 @@ msgstr "Nepodařilo se aktualizovat upozornění"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filtr..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "Za <0>{min}</0> {min, plural, one {minutu} few {minuty} other {minut}}"
@@ -511,10 +399,9 @@ msgid "Grid"
msgstr "Mřížka"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew příkaz"
msgstr ""
#: src/components/add-system.tsx
msgid "Host / IP"
@@ -546,27 +433,6 @@ msgstr "Rozvržení"
msgid "Light"
msgstr "Světlý"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Odhlásit"
@@ -615,7 +481,6 @@ msgstr "Využití paměti"
msgid "Memory usage of docker containers"
msgstr "Využití paměti docker kontejnerů"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Název"
@@ -632,19 +497,10 @@ msgstr "Síťový provoz kontejnerů docker"
msgid "Network traffic of public interfaces"
msgstr "Síťový provoz veřejných rozhraní"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Nenalezeny žádné výskyty."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "Při každém restartu budou systémy v databázi aktualizovány tak, aby odpovídaly systémům definovaným v souboru."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Otevřít menu"
@@ -682,12 +536,6 @@ msgstr "Přepsat existující upozornění"
msgid "Page"
msgstr "Stránka"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Stránky / Nastavení"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Veřejný klíč"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Číst"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Přijato"
@@ -782,24 +631,10 @@ msgstr "Přijato"
msgid "Reset Password"
msgstr "Obnovit heslo"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Pokračovat"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Adresu uložte pomocí klávesy enter nebo čárky. Pro deaktivaci e-mailových oznámení ponechte prázdné pole."
@@ -825,7 +660,8 @@ msgstr "Hledat systémy nebo nastavení..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Podívejte se na <0>nastavení upozornění</0> pro nastavení toho, jak přijímáte upozornění."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Odeslat"
@@ -833,6 +669,7 @@ msgstr "Odeslat"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Nastaví výchozí časový rozsah grafů, když je systém zobrazen."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "Nastavení SMTP"
msgid "Sort By"
msgstr "Seřadit podle"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Stav"
@@ -876,16 +708,10 @@ msgstr "Swap využití"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Systém"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Systémy"
@@ -908,10 +734,6 @@ msgstr "Teplota"
msgid "Temperature"
msgstr "Teplota"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Teploty systémových senzorů"
@@ -924,6 +746,14 @@ msgstr "Test <0>URL</0>"
msgid "Test notification sent"
msgstr "Testovací oznámení odesláno"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "Agent musí být v systému spuštěn, aby se mohl připojit. Zkopírujte níže uvedený instalační příkaz pro agenta."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "Agent musí být v systému spuštěn, aby se mohl připojit. Zkopírujte níže uvedený soubor<0>docker-compose.yml</0> pro agenta."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Poté se přihlaste do backendu a obnovte heslo k uživatelskému účtu v tabulce uživatelů."
@@ -932,10 +762,6 @@ msgstr "Poté se přihlaste do backendu a obnovte heslo k uživatelskému účtu
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Tuto akci nelze vzít zpět. Tím se z databáze trvale odstraní všechny aktuální záznamy pro {name}."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Propustnost {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Přepnout mřížku"
msgid "Toggle theme"
msgstr "Přepnout motiv"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Spustí se, když některý senzor překročí prahovou hodnotu"
@@ -1012,15 +807,6 @@ 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"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "Doba provozu"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Využití"
@@ -1048,6 +833,7 @@ msgstr "Využití kořenového oddílu"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Využito"
@@ -1056,18 +842,10 @@ msgstr "Využito"
msgid "Users"
msgstr "Uživatelé"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Zobrazení"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Viditelné sloupce"
@@ -1084,19 +862,14 @@ msgstr "Chcete nám pomoci s našimi překlady ještě lépe? Podívejte se na <
msgid "Webhook / Push notifications"
msgstr "Webhook / Push oznámení"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows příkaz"
msgstr ""
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Psát"
@@ -1111,4 +884,3 @@ msgstr "YAML konfigurace"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Vaše uživatelská nastavení byla aktualizována."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: da\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Danish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# day} other {# days}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# hour} other {# hours}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# hour} other {# hours}}"
msgid "1 hour"
msgstr "1 time"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 uge"
@@ -50,11 +39,6 @@ msgstr "1 uge"
msgid "12 hours"
msgstr "12 timer"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 timer"
@@ -63,22 +47,11 @@ msgstr "24 timer"
msgid "30 days"
msgstr "30 dage"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Handlinger"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktive Alarmer"
@@ -103,6 +76,9 @@ msgstr "Tilføj URL"
msgid "Adjust display options for charts."
msgstr "Juster visningsindstillinger for diagrammer."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Admin"
msgid "Agent"
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Alle systemer"
msgid "Are you sure you want to delete {name}?"
msgstr "Er du sikker på, at du vil slette {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Automatisk kopiering kræver en sikker kontekst."
@@ -188,22 +154,11 @@ msgstr "Beszel bruger <0>Shoutrrr</0> til at integrere med populære notifikatio
msgid "Binary"
msgstr "Binær"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / Buffere"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Fortryd"
@@ -211,14 +166,6 @@ msgstr "Fortryd"
msgid "Caution - potential data loss"
msgstr "Forsigtig - muligt tab af data"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Skift generelle applikationsindstillinger."
@@ -239,7 +186,7 @@ msgstr "Tjek logfiler for flere detaljer."
msgid "Check your notification service"
msgstr "Tjek din notifikationstjeneste"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Klik for at kopiere"
@@ -257,12 +204,7 @@ msgstr "Konfigurer hvordan du modtager advarselsmeddelelser."
msgid "Confirm password"
msgstr "Bekræft adgangskode"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Forsæt"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Kopieret til udklipsholder"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Kopiér docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Kopiér docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopier host"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopier Linux kommando"
@@ -300,25 +234,13 @@ msgstr "Kopier Linux kommando"
msgid "Copy text"
msgstr "Kopier tekst"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU forbrug"
@@ -326,11 +248,6 @@ msgstr "CPU forbrug"
msgid "Create account"
msgstr "Opret konto"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Standard tidsperiode"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Slet"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
@@ -362,10 +274,6 @@ msgstr "Disk"
msgid "Disk I/O"
msgstr "Disk I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,20 +302,15 @@ msgstr "Dokumentation"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Nede"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr "Rediger"
msgstr ""
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
@@ -426,10 +329,8 @@ msgstr "Indtast e-mailadresse for at nulstille adgangskoden"
msgid "Enter email address..."
msgstr "Indtast e-mailadresse..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Fejl"
@@ -445,10 +346,6 @@ msgstr "Overskrider {0}{1} i sidste {2, plural, one {# minut} other {# minutter}
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "Eksisterende systemer ikke defineret i <0>config.yml</0> vil blive slettet. Opret venligst regelmæssige sikkerhedskopier."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Eksporter konfiguration"
@@ -457,10 +354,6 @@ msgstr "Eksporter konfiguration"
msgid "Export your current systems configuration."
msgstr "Eksporter din nuværende systemkonfiguration."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Kunne ikke godkende"
@@ -480,14 +373,9 @@ msgstr "Kunne ikke opdatere alarm"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "For <0>{min}</0> {min, plural, one {minut} other {minutter}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Gitter"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew-kommando"
@@ -546,27 +433,6 @@ msgstr "Layout"
msgid "Light"
msgstr "Lys"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Log ud"
@@ -595,7 +461,7 @@ msgstr "Administrer display og notifikationsindstillinger."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "Manuel opsætningsvejledning"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
@@ -615,7 +481,6 @@ msgstr "Hukommelsesforbrug"
msgid "Memory usage of docker containers"
msgstr "Hukommelsesforbrug af dockercontainere"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Navn"
@@ -632,19 +497,10 @@ msgstr "Netværkstrafik af dockercontainere"
msgid "Network traffic of public interfaces"
msgstr "Netværkstrafik af offentlige grænseflader"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Ingen resultater fundet."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "Ved hver genstart vil systemer i databasen blive opdateret til at matche de systemer, der er defineret i filen."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Åbn menu"
@@ -682,12 +536,6 @@ msgstr "Overskriv eksisterende alarmer"
msgid "Page"
msgstr "Side"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Sider / Indstillinger"
@@ -703,7 +551,7 @@ msgstr "Adgangskoden skal være på mindst 8 tegn."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr "Adgangskoden skal være mindre end 72 bytes."
msgstr ""
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Offentlig nøgle"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Læs"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Modtaget"
@@ -782,24 +631,10 @@ msgstr "Modtaget"
msgid "Reset Password"
msgstr "Nulstil adgangskode"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Genoptag"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Gem adresse ved hjælp af enter eller komma. Lad feltet stå tomt for at deaktivere e-mail-meddelelser."
@@ -811,7 +646,7 @@ msgstr "Gem indstillinger"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "Gem system"
msgstr ""
#: src/components/navbar.tsx
msgid "Search"
@@ -825,7 +660,8 @@ msgstr "Søg efter systemer eller indstillinger..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Se <0>meddelelsesindstillinger</0> for at konfigurere, hvordan du modtager alarmer."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Sendt"
@@ -833,6 +669,7 @@ msgstr "Sendt"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Sætter standardtidsintervallet for diagrammer når et system vises."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "SMTP-indstillinger"
msgid "Sort By"
msgstr "Sorter efter"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
@@ -876,16 +708,10 @@ msgstr "Swap forbrug"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "System"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Systemer"
@@ -901,17 +727,13 @@ msgstr "Tabel"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "Temperatur"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Temperatur"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperaturer i systemsensorer"
@@ -924,6 +746,14 @@ msgstr "Test <0>URL</0>"
msgid "Test notification sent"
msgstr "Test notifikation sendt"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "Agenten skal køre på systemet for at forbinde. Kopier installationskommandoen for agenten nedenfor."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "Agenten skal køre på systemet for at forbinde. Kopier <0>docker-compose.yml</0> for agenten nedenfor."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Log derefter ind på backend og nulstil adgangskoden til din brugerkonto i tabellen brugere."
@@ -932,10 +762,6 @@ msgstr "Log derefter ind på backend og nulstil adgangskoden til din brugerkonto
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Denne handling kan ikke fortrydes. Dette vil permanent slette alle aktuelle elementer for {name} fra databasen."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Gennemløb af {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Slå gitter til/fra"
msgid "Toggle theme"
msgstr "Skift tema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Udløser når en sensor overstiger en tærskel"
@@ -1012,20 +807,11 @@ 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"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr "Oppe"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Updated in real time. Click on a system to view information."
@@ -1037,8 +823,7 @@ msgstr "Oppetid"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Forbrug"
@@ -1048,6 +833,7 @@ msgstr "Brug af rodpartition"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Brugt"
@@ -1056,18 +842,10 @@ msgstr "Brugt"
msgid "Users"
msgstr "Brugere"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Vis"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Synlige felter"
@@ -1084,19 +862,14 @@ msgstr "Vil du hjælpe os med at gøre vores oversættelser endnu bedre? Tjek <0
msgid "Webhook / Push notifications"
msgstr "Webhook / Push notifikationer"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows-kommando"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Skriv"
@@ -1111,4 +884,3 @@ msgstr "YAML Konfiguration"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Dine brugerindstillinger er opdateret."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: de\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-25 09:15\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: German\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# Tag} other {# Tage}}"
#. 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} von {1} Zeile(n) ausgewählt."
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# Stunde} other {# Stunden}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# Stunde} other {# Stunden}}"
msgid "1 hour"
msgstr "1 Stunde"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr "1 Min"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 Woche"
@@ -50,11 +39,6 @@ msgstr "1 Woche"
msgid "12 hours"
msgstr "12 Stunden"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr "15 Min"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 Stunden"
@@ -63,22 +47,11 @@ msgstr "24 Stunden"
msgid "30 days"
msgstr "30 Tage"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr "5 Min"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Aktionen"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr "Aktiv"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktive Warnungen"
@@ -103,6 +76,9 @@ msgstr "URL hinzufügen"
msgid "Adjust display options for charts."
msgstr "Anzeigeoptionen für Diagramme anpassen."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Admin"
msgid "Agent"
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr "Alarm-Verlauf"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Alle Systeme"
msgid "Are you sure you want to delete {name}?"
msgstr "Möchtest du {name} wirklich löschen?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr "Bist du sicher?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Automatisches Kopieren erfordert einen sicheren Kontext."
@@ -188,22 +154,11 @@ msgstr "Beszel verwendet <0>Shoutrrr</0>, um sich mit beliebten Benachrichtigung
msgid "Binary"
msgstr "Binär"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr "Bits (Kbps, Mbps, Gbps)"
#: 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)"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / Puffer"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Abbrechen"
@@ -211,14 +166,6 @@ msgstr "Abbrechen"
msgid "Caution - potential data loss"
msgstr "Vorsicht - potenzieller Datenverlust"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr "Celsius (°C)"
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr "Anzeigeeinheiten der Werte ändern."
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Allgemeine Anwendungsoptionen ändern."
@@ -239,7 +186,7 @@ msgstr "Überprüfe die Protokolle für weitere Details."
msgid "Check your notification service"
msgstr "Überprüfe deinen Benachrichtigungsdienst"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Zum Kopieren klicken"
@@ -257,12 +204,7 @@ msgstr "Konfiguriere, wie du Warnbenachrichtigungen erhältst."
msgid "Confirm password"
msgstr "Passwort bestätigen"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr "Verbindung unterbrochen"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Fortfahren"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "In die Zwischenablage kopiert"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Docker compose kopieren"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Docker run kopieren"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "Umgebungsvariablen kopieren"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Host kopieren"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Linux-Befehl kopieren"
@@ -300,25 +234,13 @@ msgstr "Linux-Befehl kopieren"
msgid "Copy text"
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>."
#: 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>."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "YAML kopieren"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU-Auslastung"
@@ -326,11 +248,6 @@ msgstr "CPU-Auslastung"
msgid "Create account"
msgstr "Konto erstellen"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr "Erstellt"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Standardzeitraum"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Löschen"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "Fingerabdruck löschen"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Festplatte"
@@ -362,10 +274,6 @@ msgstr "Festplatte"
msgid "Disk I/O"
msgstr "Festplatten-I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr "Festplatteneinheit"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,15 +302,10 @@ msgstr "Dokumentation"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Offline"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr "Dauer"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
@@ -426,10 +329,8 @@ msgstr "E-Mail-Adresse eingeben, um das Passwort zurückzusetzen"
msgid "Enter email address..."
msgstr "E-Mail-Adresse eingeben..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Fehler"
@@ -445,10 +346,6 @@ msgstr "Überschreitet {0}{1} in den letzten {2, plural, one {# Minute} other {#
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/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr "Exportieren"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Konfiguration exportieren"
@@ -457,10 +354,6 @@ msgstr "Konfiguration exportieren"
msgid "Export your current systems configuration."
msgstr "Exportiere die aktuelle Systemkonfiguration."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr "Fahrenheit (°F)"
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Authentifizierung fehlgeschlagen"
@@ -480,14 +373,9 @@ msgstr "Warnung konnte nicht aktualisiert werden"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr "Fingerabdruck"
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "Für <0>{min}</0> {min, plural, one {Minute} other {Minuten}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Raster"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew-Befehl"
@@ -546,27 +433,6 @@ msgstr "Anordnung"
msgid "Light"
msgstr "Hell"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr "Durchschnittliche Systemlast"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr "Durchschnittliche Systemlast 15 Min"
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr "Durchschnittliche Systemlast 1 Min"
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr "Durchschnittliche Systemlast 5 Min"
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr "Durchschnittliche Last"
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Abmelden"
@@ -595,7 +461,7 @@ msgstr "Anzeige- und Benachrichtigungseinstellungen verwalten."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "Anleitung zur manuellen Einrichtung"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
@@ -615,7 +481,6 @@ msgstr "Arbeitsspeichernutzung"
msgid "Memory usage of docker containers"
msgstr "Arbeitsspeichernutzung der Docker-Container"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Name"
@@ -632,19 +497,10 @@ msgstr "Netzwerkverkehr der Docker-Container"
msgid "Network traffic of public interfaces"
msgstr "Netzwerkverkehr der öffentlichen Schnittstellen"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr "Netzwerkeinheit"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Keine Ergebnisse gefunden."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr "Keine Ergebnisse."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "Bei jedem Neustart werden die Systeme in der Datenbank aktualisiert, um den in der Datei definierten Systemen zu entsprechen."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Menü öffnen"
@@ -682,12 +536,6 @@ msgstr "Bestehende Warnungen überschreiben"
msgid "Page"
msgstr "Seite"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr "Seite {0} von {1}"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Seiten / Einstellungen"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Schlüssel"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Lesen"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Empfangen"
@@ -782,24 +631,10 @@ msgstr "Empfangen"
msgid "Reset Password"
msgstr "Passwort zurücksetzen"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr "Gelöst"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Fortsetzen"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "Token rotieren"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr "Zeilen pro Seite"
#: 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."
@@ -811,7 +646,7 @@ msgstr "Einstellungen speichern"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "System sichern"
msgstr ""
#: src/components/navbar.tsx
msgid "Search"
@@ -825,7 +660,8 @@ msgstr "Nach Systemen oder Einstellungen suchen..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Siehe <0>Benachrichtigungseinstellungen</0>, um zu konfigurieren, wie du Warnungen erhältst."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Gesendet"
@@ -833,6 +669,7 @@ msgstr "Gesendet"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Legt den Standardzeitraum für Diagramme fest, wenn ein System angezeigt wird."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "SMTP-Einstellungen"
msgid "Sort By"
msgstr "Sortieren nach"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr "Status"
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
@@ -876,16 +708,10 @@ msgstr "Swap-Nutzung"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "System"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr "Systemlastdurchschnitt im Zeitverlauf"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Systeme"
@@ -901,17 +727,13 @@ msgstr "Tabelle"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "Temperatur"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Temperatur"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr "Temperatureinheit"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperaturen der Systemsensoren"
@@ -924,6 +746,14 @@ msgstr "Test <0>URL</0>"
msgid "Test notification sent"
msgstr "Testbenachrichtigung gesendet"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "Der Agent muss auf dem System laufen, um eine Verbindung herzustellen. Kopiere den Installationsbefehl für den Agent unten."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "Der Agent muss auf dem System laufen, um eine Verbindung herzustellen. Kopiere die <0>docker-compose.yml</0> für den Agent unten."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Melde dich dann im Backend an und setze dein Benutzerkontopasswort in der Benutzertabelle zurück."
@@ -932,10 +762,6 @@ msgstr "Melde dich dann im Backend an und setze dein Benutzerkontopasswort in de
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Diese Aktion kann nicht rückgängig gemacht werden. Dadurch werden alle aktuellen Datensätze für {name} dauerhaft aus der Datenbank gelöscht."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr "Dadurch werden alle ausgewählten Datensätze dauerhaft aus der Datenbank gelöscht."
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Durchsatz von {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Raster umschalten"
msgid "Toggle theme"
msgstr "Darstellung umschalten"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "Token"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "Tokens & Fingerabdrücke"
#: 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 "Tokens ermöglichen es Agents, sich zu verbinden und zu registrieren. Fingerabdrücke sind stabile, eindeutige Identifikatoren für jedes System, die bei der ersten Verbindung gesetzt werden."
#: src/components/routes/settings/tokens-fingerprints.tsx
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/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr "Löst aus, wenn der Lastdurchschnitt der letzten Minute einen Schwellenwert überschreitet"
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr "Löst aus, wenn der Lastdurchschnitt der letzten 15 Minuten einen Schwellenwert überschreitet"
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr "Löst aus, wenn der Lastdurchschnitt der letzten 5 Minuten einen Schwellenwert überschreitet"
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Löst aus, wenn ein Sensor einen Schwellenwert überschreitet"
@@ -1012,20 +807,11 @@ 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"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr "Einheiten"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "Universeller Token"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr "aktiv"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Updated in real time. Click on a system to view information."
@@ -1037,8 +823,7 @@ msgstr "Betriebszeit"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Nutzung"
@@ -1048,6 +833,7 @@ msgstr "Nutzung der Root-Partition"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Verwendet"
@@ -1056,18 +842,10 @@ msgstr "Verwendet"
msgid "Users"
msgstr "Benutzer"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Wert"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Ansicht"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr "Sieh dir die neusten 200 Alarme an."
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Sichtbare Spalten"
@@ -1084,19 +862,14 @@ msgstr "Möchtest du uns helfen, unsere Übersetzungen noch besser zu machen? Sc
msgid "Webhook / Push notifications"
msgstr "Webhook / Push-Benachrichtigungen"
#: 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 "Wenn aktiviert, ermöglicht dieser Token Agents, sich selbst zu registrieren, ohne vorherige Systemerstellung. Läuft nach einer Stunde oder beim Hub-Neustart ab."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows-Befehl"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Schreiben"
@@ -1111,4 +884,3 @@ msgstr "YAML-Konfiguration"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Deine Benutzereinstellungen wurden aktualisiert."

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: es\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:53\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Spanish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# día} other {# días}}"
#. 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} de {1} fila(s) seleccionada(s)."
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# hora} other {# horas}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# hora} other {# horas}}"
msgid "1 hour"
msgstr "1 hora"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 semana"
@@ -50,11 +39,6 @@ msgstr "1 semana"
msgid "12 hours"
msgstr "12 horas"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 horas"
@@ -63,22 +47,11 @@ msgstr "24 horas"
msgid "30 days"
msgstr "30 días"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Acciones"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr "Activo"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Alertas Activas"
@@ -103,6 +76,9 @@ msgstr "Agregar URL"
msgid "Adjust display options for charts."
msgstr "Ajustar las opciones de visualización para los gráficos."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Administrador"
msgid "Agent"
msgstr "Agente"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr "Historial de Alertas"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Todos los Sistemas"
msgid "Are you sure you want to delete {name}?"
msgstr "¿Está seguro de que desea eliminar {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr "¿Estás seguro?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "La copia automática requiere un contexto seguro."
@@ -188,22 +154,11 @@ msgstr "Beszel utiliza <0>Shoutrrr</0> para integrarse con servicios populares d
msgid "Binary"
msgstr "Binario"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Caché / Buffers"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Cancelar"
@@ -211,14 +166,6 @@ msgstr "Cancelar"
msgid "Caution - potential data loss"
msgstr "Precaución - posible pérdida de datos"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr "Cambiar las unidades de visualización de las métricas."
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Cambiar las opciones generales de la aplicación."
@@ -239,7 +186,7 @@ msgstr "Revise los registros para más detalles."
msgid "Check your notification service"
msgstr "Verifique su servicio de notificaciones"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Haga clic para copiar"
@@ -257,12 +204,7 @@ msgstr "Configure cómo recibe las notificaciones de alertas."
msgid "Confirm password"
msgstr "Confirmar contraseña"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr "La conexión está caída"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Continuar"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Copiado al portapapeles"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Copiar docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Copiar docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "Copiar env"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Copiar host"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Copiar comando de Linux"
@@ -300,25 +234,13 @@ msgstr "Copiar comando de Linux"
msgid "Copy text"
msgstr "Copiar texto"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "Copia el comando de instalación del agente a continuación, o registra agentes automáticamente con un <0>token universal</0>."
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr "Copia el contenido del<0>docker-compose.yml</0> para el agente a continuación, o registra agentes automáticamente con un <1>token universal</1>."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "Copiar YAML"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Uso de CPU"
@@ -326,11 +248,6 @@ msgstr "Uso de CPU"
msgid "Create account"
msgstr "Crear cuenta"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr "Creado"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Período de tiempo predeterminado"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Eliminar"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "Eliminar huella digital"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disco"
@@ -362,10 +274,6 @@ msgstr "Disco"
msgid "Disk I/O"
msgstr "E/S de Disco"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr "Unidad de disco"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Documentación"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Abajo"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr "Duración"
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "Ingrese la dirección de correo electrónico para restablecer la contras
msgid "Enter email address..."
msgstr "Ingrese dirección de correo..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Error"
@@ -445,10 +346,6 @@ msgstr "Excede {0}{1} en el último {2, plural, one {# minuto} other {# minutos}
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "Los sistemas existentes no definidos en <0>config.yml</0> serán eliminados. Por favor, haga copias de seguridad regularmente."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr "Exportar"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Exportar configuración"
@@ -457,10 +354,6 @@ msgstr "Exportar configuración"
msgid "Export your current systems configuration."
msgstr "Exporte la configuración actual de sus sistemas."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Error al autenticar"
@@ -480,14 +373,9 @@ msgstr "Error al actualizar la alerta"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filtrar..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr "Huella dactilar"
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "Por <0>{min}</0> {min, plural, one {minuto} other {minutos}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Cuadrícula"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Comando Homebrew"
@@ -546,27 +433,6 @@ msgstr "Diseño"
msgid "Light"
msgstr "Claro"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr "Carga Media"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr "Carga media 15m"
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr "Carga media 1m"
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr "Carga media 5m"
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr "Carga media"
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Cerrar Sesión"
@@ -615,7 +481,6 @@ msgstr "Uso de Memoria"
msgid "Memory usage of docker containers"
msgstr "Uso de memoria de los contenedores de Docker"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Nombre"
@@ -632,19 +497,10 @@ msgstr "Tráfico de red de los contenedores de Docker"
msgid "Network traffic of public interfaces"
msgstr "Tráfico de red de interfaces públicas"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr "Unidad de red"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "No se encontraron resultados."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr "Sin resultados."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "En cada reinicio, los sistemas en la base de datos se actualizarán para coincidir con los sistemas definidos en el archivo."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Abrir menú"
@@ -682,12 +536,6 @@ msgstr "Sobrescribir alertas existentes"
msgid "Page"
msgstr "Página"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr "Página {0} de {1}"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Páginas / Configuraciones"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Clave Pública"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Lectura"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Recibido"
@@ -782,24 +631,10 @@ msgstr "Recibido"
msgid "Reset Password"
msgstr "Restablecer Contraseña"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr "Resuelto"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Reanudar"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "Rotar token"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr "Filas por página"
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Guarde la dirección usando la tecla enter o coma. Deje en blanco para desactivar las notificaciones por correo."
@@ -825,7 +660,8 @@ msgstr "Buscar sistemas o configuraciones..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Consulte <0>configuración de notificaciones</0> para configurar cómo recibe alertas."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Enviado"
@@ -833,6 +669,7 @@ msgstr "Enviado"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Establece el rango de tiempo predeterminado para los gráficos cuando se visualiza un sistema."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "Configuración SMTP"
msgid "Sort By"
msgstr "Ordenar por"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr "Estado"
#: src/lib/utils.ts
msgid "Status"
msgstr "Estado"
@@ -876,16 +708,10 @@ msgstr "Uso de Swap"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Sistema"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr "Promedios de carga del sistema a lo largo del tiempo"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Sistemas"
@@ -908,10 +734,6 @@ msgstr "Temperatura"
msgid "Temperature"
msgstr "Temperatura"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr "Unidad de temperatura"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperaturas de los sensores del sistema"
@@ -924,6 +746,14 @@ msgstr "Probar <0>URL</0>"
msgid "Test notification sent"
msgstr "Notificación de prueba enviada"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "El agente debe estar ejecutándose en el sistema para conectarse. Copie el comando de instalación para el agente a continuación."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "El agente debe estar ejecutándose en el sistema para conectarse. Copie el <0>docker-compose.yml</0> para el agente a continuación."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Luego inicie sesión en el backend y restablezca la contraseña de su cuenta de usuario en la tabla de usuarios."
@@ -932,10 +762,6 @@ msgstr "Luego inicie sesión en el backend y restablezca la contraseña de su cu
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Esta acción no se puede deshacer. Esto eliminará permanentemente todos los registros actuales de {name} de la base de datos."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr "Esto eliminará permanentemente todos los registros seleccionados de la base de datos."
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Rendimiento de {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Alternar cuadrícula"
msgid "Toggle theme"
msgstr "Alternar tema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "Tokens y Huellas Digitales"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr "Los tokens permiten que los agentes se conecten y registren. Las huellas digitales son identificadores estables únicos para cada sistema, establecidos en la primera conexión."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "Los tokens y las huellas digitales se utilizan para autenticar las conexiones WebSocket al hub."
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr "Se activa cuando la carga media de 1 minuto supera un umbral"
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr "Se activa cuando la carga media de 15 minutos supera un umbral"
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr "Se activa cuando la carga media de 5 minutos supera un umbral"
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Se activa cuando cualquier sensor supera un umbral"
@@ -1012,15 +807,6 @@ msgstr "Se activa cuando el estado cambia entre activo e inactivo"
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Se activa cuando el uso de cualquier disco supera un umbral"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr "Preferencias de unidad"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "Token universal"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "Tiempo de actividad"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Uso"
@@ -1048,6 +833,7 @@ msgstr "Uso de la partición raíz"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Usado"
@@ -1056,18 +842,10 @@ msgstr "Usado"
msgid "Users"
msgstr "Usuarios"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Valor"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Vista"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr "Ver sus 200 alertas más recientes."
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Columnas visibles"
@@ -1084,19 +862,14 @@ msgstr "¿Quieres ayudarnos a mejorar nuestras traducciones? Consulta <0>Crowdin
msgid "Webhook / Push notifications"
msgstr "Notificaciones Webhook / Push"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "Cuando está habilitado, este token permite que los agentes se auto-registren sin crear previamente el sistema. Expira después de una hora o al reiniciar el hub."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Comando Windows"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Escritura"
@@ -1111,4 +884,3 @@ msgstr "Configuración YAML"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Su configuración de usuario ha sido actualizada."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: fa\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Persian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# روز} 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 "{0} از {1} ردیف انتخاب شده است."
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# ساعت} other {# ساعت}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# ساعت} other {# ساعت}}"
msgid "1 hour"
msgstr "۱ ساعت"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr "۱ دقیقه"
#: src/lib/utils.ts
msgid "1 week"
msgstr "۱ هفته"
@@ -50,11 +39,6 @@ msgstr "۱ هفته"
msgid "12 hours"
msgstr "۱۲ ساعت"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr "۱۵ دقیقه"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "۲۴ ساعت"
@@ -63,22 +47,11 @@ msgstr "۲۴ ساعت"
msgid "30 days"
msgstr "۳۰ روز"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr "۵ دقیقه"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "عملیات"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr "فعال"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr " هشدارهای فعال"
@@ -103,6 +76,9 @@ msgstr "افزودن آدرس اینترنتی"
msgid "Adjust display options for charts."
msgstr "تنظیم گزینه‌های نمایش برای نمودارها."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "مدیر"
msgid "Agent"
msgstr "عامل"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr "تاریخچه هشدارها"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "همه سیستم‌ها"
msgid "Are you sure you want to delete {name}?"
msgstr "آیا مطمئن هستید که می‌خواهید {name} را حذف کنید؟"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr "آیا مطمئن هستید؟"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "کپی خودکار نیاز به یک زمینه امن دارد."
@@ -151,7 +117,7 @@ msgstr "میانگین استفاده از CPU کانتینرها"
#. placeholder {0}: data.alert.unit
#: src/components/alerts/alerts-system.tsx
msgid "Average exceeds <0>{value}{0}</0>"
msgstr "میانگین از <0>{value}{0}</0> فراتر رفته است"
msgstr ""
#: src/components/routes/system.tsx
msgid "Average power consumption of GPUs"
@@ -188,22 +154,11 @@ msgstr "بِزل از <0>Shoutrrr</0> برای ادغام با سرویس‌ها
msgid "Binary"
msgstr "دودویی"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr "بیت (کیلوبیت بر ثانیه، مگابیت بر ثانیه، گیگابیت بر ثانیه)"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr "بایت (کیلوبایت بر ثانیه، مگابایت بر ثانیه، گیگابایت بر ثانیه)"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "حافظه پنهان / بافرها"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "لغو"
@@ -211,14 +166,6 @@ msgstr "لغو"
msgid "Caution - potential data loss"
msgstr "احتیاط - احتمال از دست رفتن داده‌ها"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr "سلسیوس (°C)"
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr "تغییر واحدهای نمایش برای معیارها."
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "تغییر گزینه‌های کلی برنامه."
@@ -239,7 +186,7 @@ msgstr "برای جزئیات بیشتر، لاگ‌ها را بررسی کنی
msgid "Check your notification service"
msgstr "سرویس اطلاع‌رسانی خود را بررسی کنید"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "برای کپی کردن کلیک کنید"
@@ -257,12 +204,7 @@ msgstr "نحوه دریافت هشدارهای اطلاع‌رسانی را پی
msgid "Confirm password"
msgstr "تأیید رمز عبور"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr "اتصال قطع است"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "ادامه"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "در کلیپ‌بورد کپی شد"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "کپی docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "کپی docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "کپی متغیرهای محیط"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "کپی میزبان"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "کپی دستور لینوکس"
@@ -300,25 +234,13 @@ msgstr "کپی دستور لینوکس"
msgid "Copy text"
msgstr "کپی متن"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "دستور نصب عامل زیر را کپی کنید، یا عامل‌ها را به طور خودکار با <0>توکن جهانی</0> ثبت کنید."
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr "محتوای <0>docker-compose.yml</0> عامل زیر را کپی کنید، یا عامل‌ها را به طور خودکار با <1>توکن جهانی</1> ثبت کنید."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "کپی YAML"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "پردازنده"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "میزان استفاده از پردازنده"
@@ -326,11 +248,6 @@ msgstr "میزان استفاده از پردازنده"
msgid "Create account"
msgstr "ایجاد حساب کاربری"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr "ایجاد شده"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "بازه زمانی پیش‌فرض"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "حذف"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "حذف اثر انگشت"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "دیسک"
@@ -362,10 +274,6 @@ msgstr "دیسک"
msgid "Disk I/O"
msgstr "ورودی/خروجی دیسک"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr "واحد دیسک"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,20 +302,15 @@ msgstr "مستندات"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "قطع"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr "مدت زمان"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr "ویرایش"
msgstr ""
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
@@ -426,10 +329,8 @@ msgstr "آدرس ایمیل را برای بازنشانی رمز عبور وا
msgid "Enter email address..."
msgstr "آدرس ایمیل را وارد کنید..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "خطا"
@@ -445,10 +346,6 @@ msgstr "در {2, plural, one {# دقیقه} other {# دقیقه}} گذشته ا
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "سیستم‌های موجود که در <0>config.yml</0> تعریف نشده‌اند حذف خواهند شد. لطفاً به طور منظم پشتیبان‌گیری کنید."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr "خروجی گرفتن"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "خارج کردن پیکربندی"
@@ -457,10 +354,6 @@ msgstr "خارج کردن پیکربندی"
msgid "Export your current systems configuration."
msgstr "پیکربندی سیستم‌های فعلی خود را خارج کنید."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr "فارنهایت (°F)"
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "احراز هویت ناموفق بود"
@@ -480,14 +373,9 @@ msgstr "به‌روزرسانی هشدار ناموفق بود"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "فیلتر..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr "اثر انگشت"
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "برای <0>{min}</0> {min, plural, one {دقیقه} other {دقیقه}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "جدول"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "دستور Homebrew"
@@ -546,27 +433,6 @@ msgstr "طرح‌بندی"
msgid "Light"
msgstr "روشن"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr "میانگین بار"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr "میانگین بار ۱۵ دقیقه"
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr "میانگین بار ۱ دقیقه"
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr "میانگین بار ۵ دقیقه"
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr "میانگین بار"
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "خروج"
@@ -595,7 +461,7 @@ msgstr "مدیریت تنظیمات نمایش و اعلان‌ها."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "دستورالعمل‌های راه‌اندازی دستی"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
@@ -615,7 +481,6 @@ msgstr "میزان استفاده از حافظه"
msgid "Memory usage of docker containers"
msgstr "میزان استفاده از حافظه کانتینرهای داکر"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "نام"
@@ -632,19 +497,10 @@ msgstr "ترافیک شبکه کانتینرهای داکر"
msgid "Network traffic of public interfaces"
msgstr "ترافیک شبکه رابط‌های عمومی"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr "واحد شبکه"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "هیچ نتیجه‌ای یافت نشد."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr "نتیجه‌ای یافت نشد."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "در هر بار راه‌اندازی مجدد، سیستم‌های موجود در پایگاه داده با سیستم‌های تعریف شده در فایل مطابقت داده می‌شوند."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "باز کردن منو"
@@ -682,12 +536,6 @@ msgstr "بازنویسی هشدارهای موجود"
msgid "Page"
msgstr "صفحه"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr "صفحه {0} از {1}"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "صفحات / تنظیمات"
@@ -703,7 +551,7 @@ msgstr "رمز عبور باید حداقل ۸ کاراکتر باشد."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr "رمز عبور باید کمتر از ۷۲ بایت باشد."
msgstr ""
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "کلید عمومی"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "خواندن"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "دریافت شد"
@@ -782,24 +631,10 @@ msgstr "دریافت شد"
msgid "Reset Password"
msgstr "بازنشانی رمز عبور"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr "حل شده"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "ادامه"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "چرخش توکن"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr "ردیف در هر صفحه"
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "آدرس را با استفاده از کلید Enter یا کاما ذخیره کنید. برای غیرفعال کردن اعلان‌های ایمیلی، خالی بگذارید."
@@ -811,7 +646,7 @@ msgstr "ذخیره تنظیمات"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "ذخیره سیستم"
msgstr ""
#: src/components/navbar.tsx
msgid "Search"
@@ -825,7 +660,8 @@ msgstr "جستجو برای سیستم‌ها یا تنظیمات..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "برای پیکربندی نحوه دریافت هشدارها، به <0>تنظیمات اعلان</0> مراجعه کنید."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "ارسال شد"
@@ -833,6 +669,7 @@ msgstr "ارسال شد"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "بازه زمانی پیش‌فرض برای نمودارها هنگام مشاهده یک سیستم را تعیین می‌کند."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "تنظیمات SMTP"
msgid "Sort By"
msgstr "مرتب‌سازی بر اساس"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr "وضعیت"
#: src/lib/utils.ts
msgid "Status"
msgstr "وضعیت"
@@ -876,16 +708,10 @@ msgstr "میزان استفاده از Swap"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "سیستم"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr "میانگین بار سیستم در طول زمان"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "سیستم‌ها"
@@ -901,17 +727,13 @@ msgstr "جدول"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "دما"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "دما"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr "واحد دما"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "دمای حسگرهای سیستم"
@@ -924,6 +746,14 @@ msgstr "تست <0>آدرس اینترنتی</0>"
msgid "Test notification sent"
msgstr "اعلان آزمایشی ارسال شد"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "برای اتصال، عامل باید روی سیستم در حال اجرا باشد. دستور نصب عامل را از زیر کپی کنید."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "برای اتصال، عامل باید روی سیستم در حال اجرا باشد. <0>docker-compose.yml</0> مربوط به عامل را از زیر کپی کنید."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "سپس وارد بخش پشتیبان شوید و رمز عبور حساب کاربری خود را در جدول کاربران بازنشانی کنید."
@@ -932,10 +762,6 @@ msgstr "سپس وارد بخش پشتیبان شوید و رمز عبور حسا
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "این عمل قابل برگشت نیست. این کار تمام رکوردهای فعلی {name} را برای همیشه از پایگاه داده حذف خواهد کرد."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr "این کار تمام رکوردهای انتخاب شده را برای همیشه از پایگاه داده حذف خواهد کرد."
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "توان عملیاتی {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "تغییر نمایش جدول"
msgid "Toggle theme"
msgstr "تغییر تم"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "توکن"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "توکن‌ها و اثرات انگشت"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr "توکن‌ها به عامل‌ها اجازه اتصال و ثبت‌نام می‌دهند. اثرات انگشت شناسه‌های پایدار منحصر به فرد هر سیستم هستند که در اولین اتصال تنظیم می‌شوند."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "توکن‌ها و اثرات انگشت برای احراز هویت اتصالات WebSocket به هاب استفاده می‌شوند."
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr "هنگامی که میانگین بار ۱ دقیقه‌ای از یک آستانه فراتر رود، فعال می‌شود"
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr "هنگامی که میانگین بار ۱۵ دقیقه‌ای از یک آستانه فراتر رود، فعال می‌شود"
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr "هنگامی که میانگین بار ۵ دقیقه‌ای از یک آستانه فراتر رود، فعال می‌شود"
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "هنگامی که هر حسگری از یک آستانه فراتر رود، فعال می‌شود"
@@ -1012,20 +807,11 @@ msgstr "هنگامی که وضعیت بین بالا و پایین تغییر م
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "هنگامی که استفاده از هر دیسکی از یک آستانه فراتر رود، فعال می‌شود"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr "تنظیمات واحدها"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "توکن جهانی"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr "فعال"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Updated in real time. Click on a system to view information."
@@ -1037,8 +823,7 @@ msgstr "آپتایم"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "میزان استفاده"
@@ -1048,6 +833,7 @@ msgstr "میزان استفاده از پارتیشن ریشه"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "استفاده شده"
@@ -1056,18 +842,10 @@ msgstr "استفاده شده"
msgid "Users"
msgstr "کاربران"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "مقدار"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "مشاهده"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr "۲۰۰ هشدار اخیر خود را مشاهده کنید."
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "فیلدهای قابل مشاهده"
@@ -1084,19 +862,14 @@ msgstr "می‌خواهید به ما کمک کنید تا ترجمه‌های
msgid "Webhook / Push notifications"
msgstr "اعلان‌های Webhook / Push"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "هنگامی که فعال است، این توکن به عامل‌ها اجازه خودثبت‌نامی بدون ایجاد سیستم قبلی می‌دهد. پس از یک ساعت یا در راه‌اندازی مجدد هاب منقضی می‌شود."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "دستور Windows"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "نوشتن"
@@ -1111,4 +884,3 @@ msgstr "پیکربندی YAML"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "تنظیمات کاربری شما به‌روزرسانی شد."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: fr\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:53\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: French\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# jour} other {# jours}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# heure} other {# heures}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# heure} other {# heures}}"
msgid "1 hour"
msgstr "1 heure"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 semaine"
@@ -50,11 +39,6 @@ msgstr "1 semaine"
msgid "12 hours"
msgstr "12 heures"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 heures"
@@ -63,22 +47,11 @@ msgstr "24 heures"
msgid "30 days"
msgstr "30 jours"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Actions"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Alertes actives"
@@ -103,6 +76,9 @@ msgstr "Ajouter URL"
msgid "Adjust display options for charts."
msgstr "Ajuster les options d'affichage pour les graphiques."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Admin"
msgid "Agent"
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Tous les systèmes"
msgid "Are you sure you want to delete {name}?"
msgstr "Êtes-vous sûr de vouloir supprimer {name} ?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "La copie automatique nécessite un contexte sécurisé."
@@ -188,22 +154,11 @@ msgstr "Beszel utilise <0>Shoutrrr</0> pour s'intégrer aux services de notifica
msgid "Binary"
msgstr "Binaire"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / Tampons"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Annuler"
@@ -211,14 +166,6 @@ msgstr "Annuler"
msgid "Caution - potential data loss"
msgstr "Attention - perte de données potentielle"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Modifier les options générales de l'application."
@@ -239,7 +186,7 @@ msgstr "Vérifiez les journaux pour plus de détails."
msgid "Check your notification service"
msgstr "Vérifiez votre service de notification"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Cliquez pour copier"
@@ -257,12 +204,7 @@ msgstr "Configurez comment vous recevez les notifications d'alerte."
msgid "Confirm password"
msgstr "Confirmer le mot de passe"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Continuer"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Copié dans le presse-papiers"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Copier docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Copier docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "Copier env"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Copier l'hôte"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Copier la commande Linux"
@@ -300,25 +234,13 @@ msgstr "Copier la commande Linux"
msgid "Copy text"
msgstr "Copier le texte"
#: 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 "Copiez la commande d'installation de l'agent ci-dessous, ou enregistrez les agents automatiquement avec un <0>token universel</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 "Copiez le contenu du<0>docker-compose.yml</0> pour l'agent ci-dessous, ou enregistrez les agents automatiquement avec un <1>token universel</1>."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "Copier YAML"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Utilisation du CPU"
@@ -326,11 +248,6 @@ msgstr "Utilisation du CPU"
msgid "Create account"
msgstr "Créer un compte"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Période par défaut"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Supprimer"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "Supprimer l'empreinte"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disque"
@@ -362,10 +274,6 @@ msgstr "Disque"
msgid "Disk I/O"
msgstr "Entrée/Sortie disque"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Documentation"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Injoignable"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "Entrez l'adresse email pour réinitialiser le mot de passe"
msgid "Enter email address..."
msgstr "Entrez l'adresse email..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Erreur"
@@ -445,10 +346,6 @@ msgstr "Dépasse {0}{1} dans {2, plural, one {la dernière # minute} other {les
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/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Exporter la configuration"
@@ -457,10 +354,6 @@ msgstr "Exporter la configuration"
msgid "Export your current systems configuration."
msgstr "Exportez la configuration actuelle de vos systèmes."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Échec de l'authentification"
@@ -480,14 +373,9 @@ msgstr "Échec de la mise à jour de l'alerte"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filtrer..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "Pour <0>{min}</0> {min, plural, one {minute} other {minutes}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Grille"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Commande Homebrew"
@@ -546,27 +433,6 @@ msgstr "Disposition"
msgid "Light"
msgstr "Clair"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Déconnexion"
@@ -615,7 +481,6 @@ msgstr "Utilisation de la mémoire"
msgid "Memory usage of docker containers"
msgstr "Utilisation de la mémoire des conteneurs Docker"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Nom"
@@ -632,19 +497,10 @@ msgstr "Trafic réseau des conteneurs Docker"
msgid "Network traffic of public interfaces"
msgstr "Trafic réseau des interfaces publiques"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Aucun résultat trouvé."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "À chaque redémarrage, les systèmes dans la base de données seront mis à jour pour correspondre aux systèmes définis dans le fichier."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Ouvrir le menu"
@@ -682,12 +536,6 @@ msgstr "Écraser les alertes existantes"
msgid "Page"
msgstr "Page"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Pages / Paramètres"
@@ -711,7 +559,7 @@ msgstr "Demande de réinitialisation du mot de passe reçue"
#: src/components/systems-table/systems-table.tsx
msgid "Pause"
msgstr "Pause"
msgstr "En pause"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Clé publique"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Lecture"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Reçu"
@@ -782,24 +631,10 @@ msgstr "Reçu"
msgid "Reset Password"
msgstr "Réinitialiser le mot de passe"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Reprendre"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "Faire tourner le token"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: 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."
@@ -825,7 +660,8 @@ msgstr "Rechercher des systèmes ou des paramètres..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Voir les <0>paramètres de notification</0> pour configurer comment vous recevez les alertes."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Envoyé"
@@ -833,6 +669,7 @@ msgstr "Envoyé"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Définit la plage de temps par défaut pour les graphiques lorsqu'un système est consulté."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "Paramètres SMTP"
msgid "Sort By"
msgstr "Trier par"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Statut"
@@ -876,16 +708,10 @@ msgstr "Utilisation du swap"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Système"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Systèmes"
@@ -908,10 +734,6 @@ msgstr "Temp."
msgid "Temperature"
msgstr "Température"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Températures des capteurs du système"
@@ -924,6 +746,14 @@ msgstr "Tester <0>URL</0>"
msgid "Test notification sent"
msgstr "Notification de test envoyée"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "L'agent doit être en cours d'exécution sur le système pour se connecter. Copiez la commande d'installation pour l'agent ci-dessous."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "L'agent doit être en cours d'exécution sur le système pour se connecter. Copiez le <0>docker-compose.yml</0> pour l'agent ci-dessous."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Ensuite, connectez-vous au backend et réinitialisez le mot de passe de votre compte utilisateur dans la table des utilisateurs."
@@ -932,10 +762,6 @@ msgstr "Ensuite, connectez-vous au backend et réinitialisez le mot de passe de
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Cette action ne peut pas être annulée. Cela supprimera définitivement tous les enregistrements actuels pour {name} de la base de données."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Débit de {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Basculer la grille"
msgid "Toggle theme"
msgstr "Changer le thème"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "Tokens et Empreintes"
#: 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 "Les tokens permettent aux agents de se connecter et de s'enregistrer. Les empreintes sont des identifiants stables uniques à chaque système, définis lors de la première connexion."
#: src/components/routes/settings/tokens-fingerprints.tsx
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/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Déclenchement lorsque tout capteur dépasse un seuil"
@@ -1012,15 +807,6 @@ 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"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "Token universel"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "Temps de fonctionnement"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Utilisation"
@@ -1048,6 +833,7 @@ msgstr "Utilisation de la partition racine"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Utilisé"
@@ -1056,18 +842,10 @@ msgstr "Utilisé"
msgid "Users"
msgstr "Utilisateurs"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Vue"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Colonnes visibles"
@@ -1084,19 +862,14 @@ msgstr "Vous voulez nous aider à améliorer nos traductions ? Consultez <0>Crow
msgid "Webhook / Push notifications"
msgstr "Notifications Webhook / Push"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "Lorsqu'il est activé, ce token permet aux agents de s'auto-enregistrer sans création préalable du système. Expire après une heure ou au redémarrage du hub."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Commande Windows"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Écriture"
@@ -1111,4 +884,3 @@ msgstr "Configuration YAML"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Vos paramètres utilisateur ont été mis à jour."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: hr\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Croatian\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dan} other {# dani}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# sat} other {# sati}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# sat} other {# sati}}"
msgid "1 hour"
msgstr "1 sat"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 tjedan"
@@ -50,11 +39,6 @@ msgstr "1 tjedan"
msgid "12 hours"
msgstr "12 sati"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 sati"
@@ -63,22 +47,11 @@ msgstr "24 sati"
msgid "30 days"
msgstr "30 dana"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Akcije"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktivna upozorenja"
@@ -103,6 +76,9 @@ msgstr "Dodaj URL"
msgid "Adjust display options for charts."
msgstr "Podesite opcije prikaza za grafikone."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Admin"
msgid "Agent"
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Svi Sistemi"
msgid "Are you sure you want to delete {name}?"
msgstr "Jeste li sigurni da želite izbrisati {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Automatsko kopiranje zahtijeva siguran kontekst."
@@ -188,22 +154,11 @@ msgstr "Beszel koristi <0>Shoutrrr</0> za integraciju sa popularnim servisima za
msgid "Binary"
msgstr "Binarni"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Predmemorija / Međuspremnici"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Otkaži"
@@ -211,14 +166,6 @@ msgstr "Otkaži"
msgid "Caution - potential data loss"
msgstr "Oprez - mogući gubitak podataka"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Promijenite opće opcije aplikacije."
@@ -239,7 +186,7 @@ msgstr "Provjerite logove za više detalja."
msgid "Check your notification service"
msgstr "Provjerite Vaš servis notifikacija"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Pritisnite za kopiranje"
@@ -257,12 +204,7 @@ msgstr "Konfigurirajte način primanja obavijesti upozorenja."
msgid "Confirm password"
msgstr "Potvrdite lozinku"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Nastavite"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Kopirano u međuspremnik"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Kopiraj docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Kopiraj docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopiraj hosta"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopiraj Linux komandu"
@@ -300,25 +234,13 @@ msgstr "Kopiraj Linux komandu"
msgid "Copy text"
msgstr "Kopiraj tekst"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "Procesor"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Iskorištenost procesora"
@@ -326,11 +248,6 @@ msgstr "Iskorištenost procesora"
msgid "Create account"
msgstr "Napravite račun"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Zadano vremensko razdoblje"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Izbriši"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
@@ -362,10 +274,6 @@ msgstr "Disk"
msgid "Disk I/O"
msgstr "Disk I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Dokumentacija"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "Unesite email adresu za resetiranje lozinke"
msgid "Enter email address..."
msgstr "Unesite email adresu..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Greška"
@@ -445,10 +346,6 @@ msgstr "Premašuje {0}{1} u posljednjih {2, plural, one {# minuta} other {# minu
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "Postojeći sistemi koji nisu definirani u <0>config.yml</0> će biti izbrisani. Molimo Vas napravite redovite sigurnosne kopije."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Izvoz konfiguracije"
@@ -457,10 +354,6 @@ msgstr "Izvoz konfiguracije"
msgid "Export your current systems configuration."
msgstr "Izvoz trenutne sistemske konfiguracije."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Provjera autentičnosti nije uspjela"
@@ -480,14 +373,9 @@ msgstr "Ažuriranje upozorenja nije uspjelo"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "Za <0>{min}</0> {min, plural, one {minutu} other {minute}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Mreža"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew naredba"
@@ -546,27 +433,6 @@ msgstr "Izgled"
msgid "Light"
msgstr "Svijetlo"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Odjava"
@@ -615,7 +481,6 @@ msgstr "Upotreba memorije"
msgid "Memory usage of docker containers"
msgstr "Upotreba memorije Docker spremnika"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Ime"
@@ -632,19 +497,10 @@ msgstr "Mrežni promet Docker spremnika"
msgid "Network traffic of public interfaces"
msgstr "Mrežni promet javnih sučelja"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Nema rezultata."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "Prilikom svakog ponovnog pokretanja, sustavi u bazi podataka biti će ažurirani kako bi odgovarali sustavima definiranim u datoteci."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Otvori menu"
@@ -682,12 +536,6 @@ msgstr "Prebrišite postojeća upozorenja"
msgid "Page"
msgstr "Stranica"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Stranice / Postavke"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Javni Ključ"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Pročitaj"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Primljeno"
@@ -782,24 +631,10 @@ msgstr "Primljeno"
msgid "Reset Password"
msgstr "Resetiraj Lozinku"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Nastavi"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Spremite adresu pomoću tipke enter ili zareza. Ostavite prazno kako biste onemogućili obavijesti e-poštom."
@@ -825,7 +660,8 @@ msgstr "Pretraži za sisteme ili postavke..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Pogledajte <0>postavke obavijesti</0> da biste konfigurirali način primanja upozorenja."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Poslano"
@@ -833,6 +669,7 @@ msgstr "Poslano"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Postavlja zadani vremenski raspon za grafikone kada se sustav gleda."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "SMTP postavke"
msgid "Sort By"
msgstr "Sortiraj po"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
@@ -876,16 +708,10 @@ msgstr "Swap Iskorištenost"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Sistem"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Sistemi"
@@ -908,10 +734,6 @@ msgstr ""
msgid "Temperature"
msgstr "Temperatura"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperature sistemskih senzora"
@@ -924,6 +746,14 @@ msgstr "Testni <0>URL</0>"
msgid "Test notification sent"
msgstr "Testna obavijest poslana"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "Agent mora biti pokrenut na sistemu da bi se spojio. Kopirajte instalacijske komande za agenta ispod."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "Agent mora biti pokrenut na sistemu da bi se spojio. Kopirajte <0>docker-compose.yml</0> za agenta ispod."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Zatim se prijavite u backend i resetirajte lozinku korisničkog računa u tablici korisnika."
@@ -932,10 +762,6 @@ msgstr "Zatim se prijavite u backend i resetirajte lozinku korisničkog računa
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Ova radnja se ne može poništiti. Ovo će trajno izbrisati sve trenutne zapise za {name} iz baze podataka."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Protok {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Uključi/isključi rešetku"
msgid "Toggle theme"
msgstr "Uključi/isključi temu"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Pokreće se kada bilo koji senzor prijeđe prag"
@@ -1012,15 +807,6 @@ 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"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "Vrijeme rada"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Iskorištenost"
@@ -1048,6 +833,7 @@ msgstr "Iskorištenost root datotečnog sustava"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Iskorišteno"
@@ -1056,18 +842,10 @@ msgstr "Iskorišteno"
msgid "Users"
msgstr "Korisnici"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Prikaz"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Vidljiva polja"
@@ -1084,19 +862,14 @@ msgstr "Želite li nam pomoći da naše prijevode učinimo još boljim? Posjetit
msgid "Webhook / Push notifications"
msgstr "Webhook / Push obavijest"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows naredba"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Piši"
@@ -1111,4 +884,3 @@ msgstr "YAML Konfiguracija"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Vaše korisničke postavke su ažurirane."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: hu\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Hungarian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# nap} other {# nap}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# óra} other {# óra}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# óra} other {# óra}}"
msgid "1 hour"
msgstr "1 óra"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 hét"
@@ -50,11 +39,6 @@ msgstr "1 hét"
msgid "12 hours"
msgstr "12 óra"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 óra"
@@ -63,22 +47,11 @@ msgstr "24 óra"
msgid "30 days"
msgstr "30 nap"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Műveletek"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktív riasztások"
@@ -103,6 +76,9 @@ msgstr "URL hozzáadása"
msgid "Adjust display options for charts."
msgstr "Állítsa be a diagram megjelenítését."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Admin"
msgid "Agent"
msgstr "Ügynök"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Minden rendszer"
msgid "Are you sure you want to delete {name}?"
msgstr "Biztosan törölni szeretnéd {name}-t?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Az automatikus másolás biztonságos környezetet igényel."
@@ -188,22 +154,11 @@ msgstr "A Beszel a <0>Shoutrrr</0>-t használja a népszerű értesítési szolg
msgid "Binary"
msgstr "Bináris"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Gyorsítótár / Pufferelések"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Mégsem"
@@ -211,14 +166,6 @@ msgstr "Mégsem"
msgid "Caution - potential data loss"
msgstr "Figyelem - potenciális adatvesztés"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Általános alkalmazásbeállítások módosítása."
@@ -239,7 +186,7 @@ msgstr "Ellenőrizd a naplót a további részletekért."
msgid "Check your notification service"
msgstr "Ellenőrizd az értesítési szolgáltatásodat"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Kattints a másoláshoz"
@@ -257,12 +204,7 @@ msgstr "Konfiguráld, hogyan kapod az értesítéseket."
msgid "Confirm password"
msgstr "Jelszó megerősítése"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Tovább"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Vágólapra másolva"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Docker compose másolása"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Docker run másolása"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Hoszt másolása"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Linux parancs másolása"
@@ -300,25 +234,13 @@ msgstr "Linux parancs másolása"
msgid "Copy text"
msgstr "Szöveg másolása"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU használat"
@@ -326,11 +248,6 @@ msgstr "CPU használat"
msgid "Create account"
msgstr "Fiók létrehozása"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Alapértelmezett időszak"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Törlés"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Lemez"
@@ -362,10 +274,6 @@ msgstr "Lemez"
msgid "Disk I/O"
msgstr "Lemez I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Dokumentáció"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "E-mail cím megadása a jelszó visszaállításához"
msgid "Enter email address..."
msgstr "Adja meg az e-mail címet..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Hiba"
@@ -445,10 +346,6 @@ msgstr "Túllépi a {0}{1} értéket az elmúlt {2, plural, one {# percben} othe
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "A <0>config.yml</0> fájlban nem definiált meglévő rendszerek törlésre kerülnek. Kérjük, készítsen rendszeres biztonsági mentéseket."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Konfiguráció exportálása"
@@ -457,10 +354,6 @@ msgstr "Konfiguráció exportálása"
msgid "Export your current systems configuration."
msgstr "Exportálja a jelenlegi rendszerkonfigurációt."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Hitelesítés sikertelen"
@@ -480,14 +373,9 @@ msgstr "Nem sikerült frissíteni a riasztást"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Szűrő..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "A <0>{min}</0> {min, plural, one {perc} other {percek}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Rács"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew parancs"
@@ -546,27 +433,6 @@ msgstr "Elrendezés"
msgid "Light"
msgstr "Világos"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Kijelentkezés"
@@ -615,7 +481,6 @@ msgstr "Memóriahasználat"
msgid "Memory usage of docker containers"
msgstr "Docker konténerek memória használata"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Név"
@@ -632,19 +497,10 @@ msgstr "Docker konténerek hálózati forgalma"
msgid "Network traffic of public interfaces"
msgstr "Nyilvános interfészek hálózati forgalma"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Nincs találat."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "Minden újraindításkor az adatbázisban lévő rendszerek frissítésre kerülnek, hogy megfeleljenek a fájlban meghatározott rendszereknek."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Menü megnyitása"
@@ -682,12 +536,6 @@ msgstr "Felülírja a meglévő riasztásokat"
msgid "Page"
msgstr "Oldal"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Oldalak / Beállítások"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Nyilvános kulcs"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Olvasás"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Fogadott"
@@ -782,24 +631,10 @@ msgstr "Fogadott"
msgid "Reset Password"
msgstr "Jelszó visszaállítása"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Folytatás"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Mentse el a címet az Enter billentyű vagy a vessző használatával. Hagyja üresen az e-mail értesítések letiltásához."
@@ -825,7 +660,8 @@ msgstr "Keresés rendszerek vagy beállítások után..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Lásd <0>az értesítési beállításokat</0>, hogy konfigurálja, hogyan kap értesítéseket."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Elküldve"
@@ -833,6 +669,7 @@ msgstr "Elküldve"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Beállítja az alapértelmezett időtartamot a diagramokhoz, amikor egy rendszert néznek."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "SMTP beállítások"
msgid "Sort By"
msgstr "Rendezés"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Állapot"
@@ -876,16 +708,10 @@ msgstr "Swap használat"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Rendszer"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Rendszer"
@@ -908,10 +734,6 @@ msgstr ""
msgid "Temperature"
msgstr "Hőmérséklet"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "A rendszer érzékelőinek hőmérséklete"
@@ -924,6 +746,14 @@ msgstr "Teszt <0>URL</0>"
msgid "Test notification sent"
msgstr "Teszt értesítés elküldve"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "A csatlakozáshoz az ügynöknek futnia kell a rendszerben. Másolja ki az alábbi telepítési parancsot az ügynök telepítéséhez."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "A csatlakozáshoz az ügynöknek futnia kell a rendszerben. Másolja az<0>docker-compose.yml</0> fájlt az ügynök futtatásához."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Ezután jelentkezzen be a backendbe, és állítsa vissza a felhasználói fiók jelszavát a felhasználók táblázatban."
@@ -932,10 +762,6 @@ msgstr "Ezután jelentkezzen be a backendbe, és állítsa vissza a felhasznál
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Ezt a műveletet nem lehet visszavonni! Véglegesen törli a {name} összes jelenlegi rekordját az adatbázisból!"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "A {extraFsName} átviteli teljesítménye"
@@ -957,37 +783,6 @@ msgstr "Rács ki- és bekapcsolása"
msgid "Toggle theme"
msgstr "Téma váltása"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Bekapcsol, ha bármelyik érzékelő túllép egy küszöbértéket"
@@ -1012,15 +807,6 @@ 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"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "Üzemidő"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Használat"
@@ -1048,6 +833,7 @@ msgstr "Root partíció kihasználtsága"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Felhasznált"
@@ -1056,18 +842,10 @@ msgstr "Felhasznált"
msgid "Users"
msgstr "Felhasználók"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Nézet"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Látható mezők"
@@ -1084,19 +862,14 @@ msgstr "Szeretne segíteni nekünk abban, hogy fordításaink még jobbak legyen
msgid "Webhook / Push notifications"
msgstr "Webhook / Push értesítések"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows parancs"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Írás"
@@ -1111,4 +884,3 @@ msgstr "YAML konfiguráció"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "A felhasználói beállítások frissítésre kerültek."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: is\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Icelandic\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dagur} other {# dagar}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# klukkustund} other {# klukkustundir}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# klukkustund} other {# klukkustundir}}"
msgid "1 hour"
msgstr "1 klukkustund"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 vika"
@@ -50,11 +39,6 @@ msgstr "1 vika"
msgid "12 hours"
msgstr "12 klukkustundir"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 klukkustundir"
@@ -63,22 +47,11 @@ msgstr "24 klukkustundir"
msgid "30 days"
msgstr "30 dagar"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Aðgerðir"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Virkar tilkynningar"
@@ -103,6 +76,9 @@ msgstr "Bæta við léni"
msgid "Adjust display options for charts."
msgstr ""
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Admin"
msgid "Agent"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Öll kerfi"
msgid "Are you sure you want to delete {name}?"
msgstr "Ertu viss um að þú viljir eyða {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Sjálfvisk afritun krefst öruggs samhengis."
@@ -188,22 +154,11 @@ msgstr "Beszel notar <0>Shoutrrr</0> til að tengjast vinsælum tilkynningaþjó
msgid "Binary"
msgstr "Binary"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Skyndiminni / Biðminni"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Hætta við"
@@ -211,14 +166,6 @@ msgstr "Hætta við"
msgid "Caution - potential data loss"
msgstr "Aðvörun - möguleiki á gagnatapi"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Breyta almennum stillingum."
@@ -239,7 +186,7 @@ msgstr "Skoðaðu logga til að sjá meiri upplýsingar."
msgid "Check your notification service"
msgstr "Athugaðu tilkynningaþjónustuna þína"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Smelltu til að afrita"
@@ -257,12 +204,7 @@ msgstr "Stilltu hvernig þú vilt fá tilkynningar."
msgid "Confirm password"
msgstr "Staðfestu lykilorð"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Halda áfram"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Afritað í klippiborð"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Afrita docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Afrita docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Afrita host"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Afrita Linux aðgerð"
@@ -300,25 +234,13 @@ msgstr "Afrita Linux aðgerð"
msgid "Copy text"
msgstr "Afrita texta"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "Örgjörvi"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Örgjörva notkun"
@@ -326,11 +248,6 @@ msgstr "Örgjörva notkun"
msgid "Create account"
msgstr "Búa til aðgang"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Sjálfgefið tímabil"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Eyða"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Diskur"
@@ -362,10 +274,6 @@ msgstr "Diskur"
msgid "Disk I/O"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Skjal"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "Settu netfang til að endursetja lykilorð"
msgid "Enter email address..."
msgstr "Settu inn Netfang..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Villa"
@@ -445,10 +346,6 @@ msgstr "Fór yfir {0}{1} á síðustu {2, plural, one {# mínútu} other {# mín
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr ""
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr ""
@@ -457,10 +354,6 @@ msgstr ""
msgid "Export your current systems configuration."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Villa í auðkenningu"
@@ -480,14 +373,9 @@ msgstr "Mistókst að uppfæra tilkynningu"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Sía..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr ""
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew skipun"
@@ -546,27 +433,6 @@ msgstr ""
msgid "Light"
msgstr "Ljóst"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Útskrá"
@@ -615,7 +481,6 @@ msgstr "Minnisnotkun"
msgid "Memory usage of docker containers"
msgstr "Minnisnotkun docker kerfa"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Nafn"
@@ -632,19 +497,10 @@ msgstr "Net traffík docker kerfa"
msgid "Network traffic of public interfaces"
msgstr ""
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Engar niðurstöður fundust."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Opna valmynd"
@@ -682,12 +536,6 @@ msgstr "Yfirskrifa núverandi tilkynningu"
msgid "Page"
msgstr "Síða"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Síða / Stillingar"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Dreifilykill"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Lesa"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Móttekið"
@@ -782,24 +631,10 @@ msgstr "Móttekið"
msgid "Reset Password"
msgstr "Endurstilla lykilorð"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Halda áfram"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr ""
@@ -825,7 +660,8 @@ msgstr "Leita að kerfum eða stillingum..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr ""
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Sent"
@@ -833,6 +669,7 @@ msgstr "Sent"
msgid "Sets the default time range for charts when a system is viewed."
msgstr ""
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "SMTP stillingar"
msgid "Sort By"
msgstr "Raða eftir"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Staða"
@@ -876,16 +708,10 @@ msgstr "Skipti minni"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Kerfi"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Kerfi"
@@ -908,10 +734,6 @@ msgstr ""
msgid "Temperature"
msgstr "Hitastig"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Hitastig kerfa skynjara"
@@ -924,6 +746,14 @@ msgstr "Prufa <0>URL</0>"
msgid "Test notification sent"
msgstr "Prufu tilkynning send"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr ""
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr ""
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Skráðu þig þá inní bakendann og endurstilltu lykilorðið þitt inni í notenda töflunni."
@@ -932,10 +762,6 @@ msgstr "Skráðu þig þá inní bakendann og endurstilltu lykilorðið þitt in
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Þessi aðgerð er óafturkvæmanleg. Þetta mun eyða gögnum fyrir {name} varanlega úr gagnagrunninum."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr ""
@@ -957,37 +783,6 @@ msgstr ""
msgid "Toggle theme"
msgstr "Velja þema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Virkjast þegar einhver skynjari fer yfir þröskuld"
@@ -1012,15 +807,6 @@ 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"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr ""
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr ""
@@ -1048,6 +833,7 @@ msgstr ""
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Notað"
@@ -1056,18 +842,10 @@ msgstr "Notað"
msgid "Users"
msgstr "Notendur"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Skoða"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Sjáanlegir reitir"
@@ -1084,19 +862,14 @@ msgstr ""
msgid "Webhook / Push notifications"
msgstr "Webhook / Tilkynningar"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows skipun"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Skrifa"
@@ -1111,4 +884,3 @@ msgstr ""
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Notenda stillingar vistaðar."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: it\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Italian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# giorno} other {# giorni}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# ora} other {# ore}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# ora} other {# ore}}"
msgid "1 hour"
msgstr "1 ora"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 settimana"
@@ -50,11 +39,6 @@ msgstr "1 settimana"
msgid "12 hours"
msgstr "12 ore"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 ore"
@@ -63,22 +47,11 @@ msgstr "24 ore"
msgid "30 days"
msgstr "30 giorni"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Azioni"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Avvisi Attivi"
@@ -103,6 +76,9 @@ msgstr "Aggiungi URL"
msgid "Adjust display options for charts."
msgstr "Regola le opzioni di visualizzazione per i grafici."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Amministratore"
msgid "Agent"
msgstr "Agente"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Tutti i Sistemi"
msgid "Are you sure you want to delete {name}?"
msgstr "Sei sicuro di voler eliminare {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "La copia automatica richiede un contesto sicuro."
@@ -188,22 +154,11 @@ msgstr "Beszel utilizza <0>Shoutrrr</0> per integrarsi con i servizi di notifica
msgid "Binary"
msgstr "Binario"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / Buffer"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Annulla"
@@ -211,14 +166,6 @@ msgstr "Annulla"
msgid "Caution - potential data loss"
msgstr "Attenzione - possibile perdita di dati"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Modifica le opzioni generali dell'applicazione."
@@ -239,7 +186,7 @@ msgstr "Controlla i log per maggiori dettagli."
msgid "Check your notification service"
msgstr "Controlla il tuo servizio di notifica"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Clicca per copiare"
@@ -257,12 +204,7 @@ msgstr "Configura come ricevere le notifiche di avviso."
msgid "Confirm password"
msgstr "Conferma password"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Continua"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Copiato negli appunti"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Copia docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Copia docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "Copia env"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Copia host"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Copia comando Linux"
@@ -300,25 +234,13 @@ msgstr "Copia comando Linux"
msgid "Copy text"
msgstr "Copia testo"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "Copia il comando di installazione per l'agente qui sotto, o registra gli agenti automaticamente con un <0>token universale</0>."
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr "Copia il contenuto<0>docker-compose.yml</0> per l'agente qui sotto, o registra gli agenti automaticamente con un <1>token universale</1>."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "Copia YAML"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Utilizzo CPU"
@@ -326,11 +248,6 @@ msgstr "Utilizzo CPU"
msgid "Create account"
msgstr "Crea account"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Periodo di tempo predefinito"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Elimina"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "Elimina impronta digitale"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disco"
@@ -362,10 +274,6 @@ msgstr "Disco"
msgid "Disk I/O"
msgstr "I/O Disco"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Documentazione"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Offline"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "Inserisci l'indirizzo email per reimpostare la password"
msgid "Enter email address..."
msgstr "Inserisci l'indirizzo email..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Errore"
@@ -445,10 +346,6 @@ msgstr "Supera {0}{1} negli ultimi {2, plural, one {# minuto} other {# minuti}}"
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/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Esporta configurazione"
@@ -457,10 +354,6 @@ msgstr "Esporta configurazione"
msgid "Export your current systems configuration."
msgstr "Esporta la configurazione attuale dei tuoi sistemi."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Autenticazione fallita"
@@ -480,14 +373,9 @@ msgstr "Aggiornamento dell'avviso fallito"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filtra..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "Per <0>{min}</0> {min, plural, one {minuto} other {minuti}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Griglia"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Comando Homebrew"
@@ -546,27 +433,6 @@ msgstr "Aspetto"
msgid "Light"
msgstr "Chiaro"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr "Caricamento medio 15m"
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr "Caricamento medio 5m"
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Disconnetti"
@@ -615,7 +481,6 @@ msgstr "Utilizzo Memoria"
msgid "Memory usage of docker containers"
msgstr "Utilizzo della memoria dei container Docker"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Nome"
@@ -632,19 +497,10 @@ msgstr "Traffico di rete dei container Docker"
msgid "Network traffic of public interfaces"
msgstr "Traffico di rete delle interfacce pubbliche"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Nessun risultato trovato."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "Ad ogni riavvio, i sistemi nel database verranno aggiornati per corrispondere ai sistemi definiti nel file."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Apri menu"
@@ -682,12 +536,6 @@ msgstr "Sovrascrivi avvisi esistenti"
msgid "Page"
msgstr "Pagina"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Pagine / Impostazioni"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Chiave Pub"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Lettura"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Ricevuto"
@@ -782,24 +631,10 @@ msgstr "Ricevuto"
msgid "Reset Password"
msgstr "Reimposta Password"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Riprendi"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "Ruota token"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: 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."
@@ -825,7 +660,8 @@ msgstr "Cerca sistemi o impostazioni..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Vedi <0>impostazioni di notifica</0> per configurare come ricevere gli avvisi."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Inviato"
@@ -833,6 +669,7 @@ msgstr "Inviato"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Imposta l'intervallo di tempo predefinito per i grafici quando viene visualizzato un sistema."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "Impostazioni SMTP"
msgid "Sort By"
msgstr "Ordina per"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Stato"
@@ -876,16 +708,10 @@ msgstr "Utilizzo Swap"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Sistema"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Sistemi"
@@ -908,10 +734,6 @@ msgstr "Temperatura"
msgid "Temperature"
msgstr "Temperatura"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperature dei sensori di sistema"
@@ -924,6 +746,14 @@ msgstr "Test <0>URL</0>"
msgid "Test notification sent"
msgstr "Notifica di test inviata"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "L'agente deve essere in esecuzione sul sistema per connettersi. Copia il comando di installazione per l'agente qui sotto."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "L'agente deve essere in esecuzione sul sistema per connettersi. Copia il<0>docker-compose.yml</0> per l'agente qui sotto."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Quindi accedi al backend e reimposta la password del tuo account utente nella tabella degli utenti."
@@ -932,10 +762,6 @@ msgstr "Quindi accedi al backend e reimposta la password del tuo account utente
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Questa azione non può essere annullata. Questo eliminerà permanentemente tutti i record attuali per {name} dal database."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Throughput di {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Attiva/disattiva griglia"
msgid "Toggle theme"
msgstr "Attiva/disattiva tema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "Token"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "Token e Impronte Digitali"
#: 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 "I token consentono agli agenti di connettersi e registrarsi. Le impronte digitali sono identificatori stabili unici per ogni sistema, impostati alla prima connessione."
#: src/components/routes/settings/tokens-fingerprints.tsx
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/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Attiva quando un sensore supera una soglia"
@@ -1012,15 +807,6 @@ 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"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "Token universale"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "Tempo di attività"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Utilizzo"
@@ -1048,6 +833,7 @@ msgstr "Utilizzo della partizione root"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Utilizzato"
@@ -1056,18 +842,10 @@ msgstr "Utilizzato"
msgid "Users"
msgstr "Utenti"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Vista"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Colonne visibili"
@@ -1084,19 +862,14 @@ msgstr "Vuoi aiutarci a migliorare ulteriormente le nostre traduzioni? Dai un'oc
msgid "Webhook / Push notifications"
msgstr "Notifiche Webhook / Push"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "Quando abilitato, questo token consente agli agenti di auto-registrarsi senza creazione preventiva del sistema. Scade dopo un'ora o al riavvio dell'hub."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Comando Windows"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Scrittura"
@@ -1111,4 +884,3 @@ msgstr "Configurazione YAML"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Le impostazioni utente sono state aggiornate."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ja\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-13 10:13\n"
"Last-Translator: \n"
"Language-Team: Japanese\n"
"Plural-Forms: nplurals=1; plural=0;\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# 日} 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/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# 時間} other {# 時間}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# 時間} other {# 時間}}"
msgid "1 hour"
msgstr "1時間"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr "1分"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1週間"
@@ -50,11 +39,6 @@ msgstr "1週間"
msgid "12 hours"
msgstr "12時間"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr "15分"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24時間"
@@ -63,22 +47,11 @@ msgstr "24時間"
msgid "30 days"
msgstr "30日間"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr "5分"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "アクション"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr "アクティブ"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "アクティブなアラート"
@@ -103,6 +76,9 @@ msgstr "URLを追加"
msgid "Adjust display options for charts."
msgstr "チャートの表示オプションを調整します。"
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "管理者"
msgid "Agent"
msgstr "エージェント"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr "アラート履歴"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "すべてのシステム"
msgid "Are you sure you want to delete {name}?"
msgstr "{name}を削除してもよろしいですか?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr "よろしいですか?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "自動コピーには安全なコンテキストが必要です。"
@@ -188,22 +154,11 @@ msgstr "Beszelは<0>Shoutrrr</0>を使用して、人気のある通知サービ
msgid "Binary"
msgstr "バイナリ"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr "ビット (Kbps, Mbps, Gbps)"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr "バイト (KB/s, MB/s, GB/s)"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "キャッシュ / バッファ"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "キャンセル"
@@ -211,14 +166,6 @@ msgstr "キャンセル"
msgid "Caution - potential data loss"
msgstr "注意 - データ損失の可能性"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr "セルシウス (°C)"
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr "メトリックの表示単位を変更します。"
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "一般的なアプリケーションオプションを変更します。"
@@ -239,7 +186,7 @@ msgstr "詳細についてはログを確認してください。"
msgid "Check your notification service"
msgstr "通知サービスを確認してください"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "クリックしてコピー"
@@ -257,12 +204,7 @@ msgstr "アラート通知の受信方法を設定します。"
msgid "Confirm password"
msgstr "パスワードを確認"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr "接続が切断されました"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "続行"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "クリップボードにコピーされました"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "docker compose をコピー"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "docker run をコピー"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "環境変数をコピー"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "ホストをコピー"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Linuxコマンドをコピー"
@@ -300,25 +234,13 @@ msgstr "Linuxコマンドをコピー"
msgid "Copy text"
msgstr "テキストをコピー"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "下記のエージェントのインストールコマンドをコピーするか、<0>ユニバーサルトークン</0>を使用してエージェントを自動登録してください。"
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr "下記のエージェントの<0>docker-compose.yml</0>内容をコピーするか、<1>ユニバーサルトークン</1>を使用してエージェントを自動登録してください。"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "YAMLをコピー"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU使用率"
@@ -326,11 +248,6 @@ msgstr "CPU使用率"
msgid "Create account"
msgstr "アカウントを作成"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr "作成日"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "デフォルトの期間"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "削除"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "フィンガープリントを削除"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "ディスク"
@@ -362,10 +274,6 @@ msgstr "ディスク"
msgid "Disk I/O"
msgstr "ディスクI/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr "ディスク単位"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "ドキュメント"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "停止"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr "期間"
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "パスワードをリセットするためにメールアドレスを入
msgid "Enter email address..."
msgstr "メールアドレスを入力..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "エラー"
@@ -445,10 +346,6 @@ msgstr "過去{2, plural, one {# 分} other {# 分}}で{0}{1}を超えていま
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "<0>config.yml</0>に定義されていない既存のシステムは削除されます。定期的にバックアップを作成してください。"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr "エクスポート"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "設定をエクスポート"
@@ -457,10 +354,6 @@ msgstr "設定をエクスポート"
msgid "Export your current systems configuration."
msgstr "現在のシステム設定をエクスポートします。"
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr "華氏 (°F)"
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "認証に失敗しました"
@@ -480,14 +373,9 @@ msgstr "アラートの更新に失敗しました"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "フィルター..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr "フィンガープリント"
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "<0>{min}</0> {min, plural, one {分} other {分}}の間"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "グリッド"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew コマンド"
@@ -546,27 +433,6 @@ msgstr "レイアウト"
msgid "Light"
msgstr "ライト"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr "ロードアベレージ"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr "ロードアベレージ (15分)"
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr "ロードアベレージ (1分)"
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr "ロードアベレージ (5分)"
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr "ロードアベレージ"
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "ログアウト"
@@ -615,7 +481,6 @@ msgstr "メモリ使用率"
msgid "Memory usage of docker containers"
msgstr "Dockerコンテナのメモリ使用率"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "名前"
@@ -632,19 +497,10 @@ msgstr "Dockerコンテナのネットワークトラフィック"
msgid "Network traffic of public interfaces"
msgstr "パブリックインターフェースのネットワークトラフィック"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr "ネットワーク単位"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "結果が見つかりませんでした。"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr "結果がありません。"
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "再起動のたびに、データベース内のシステムはファイルに定義されたシステムに一致するように更新されます。"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "メニューを開く"
@@ -682,12 +536,6 @@ msgstr "既存のアラートを上書き"
msgid "Page"
msgstr "ページ"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr "{1}ページ中{0}ページ目"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "ページ / 設定"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "公開鍵"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "読み取り"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "受信"
@@ -782,24 +631,10 @@ msgstr "受信"
msgid "Reset Password"
msgstr "パスワードをリセット"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr "解決済み"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "再開"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "トークンをローテート"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr "ページあたりの行数"
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Enterキーまたはカンマを使用してアドレスを保存します。空白のままにするとメール通知が無効になります。"
@@ -825,7 +660,8 @@ msgstr "システムまたは設定を検索..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "アラートの受信方法を設定するには<0>通知設定</0>を参照してください。"
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "送信"
@@ -833,6 +669,7 @@ msgstr "送信"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "システムを表示する際のチャートのデフォルトの時間範囲を設定します。"
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "SMTP設定"
msgid "Sort By"
msgstr "並び替え基準"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr "状態"
#: src/lib/utils.ts
msgid "Status"
msgstr "ステータス"
@@ -876,16 +708,10 @@ msgstr "スワップ使用量"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "システム"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr "システムのロードアベレージの推移"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "システム"
@@ -908,10 +734,6 @@ msgstr "温度"
msgid "Temperature"
msgstr "温度"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr "温度単位"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "システムセンサーの温度"
@@ -924,6 +746,14 @@ msgstr "テスト<0>URL</0>"
msgid "Test notification sent"
msgstr "テスト通知が送信されました"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "接続するにはエージェントがシステム上で実行されている必要があります。以下のエージェントのインストールコマンドをコピーしてください。"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "接続するにはエージェントがシステム上で実行されている必要があります。以下のエージェント用<0>docker-compose.yml</0>をコピーしてください。"
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "その後、バックエンドにログインして、ユーザーテーブルでユーザーアカウントのパスワードをリセットしてください。"
@@ -932,10 +762,6 @@ msgstr "その後、バックエンドにログインして、ユーザーテー
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "この操作は元に戻せません。これにより、データベースから{name}のすべての現在のレコードが永久に削除されます。"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr "これにより、選択したすべてのレコードがデータベースから完全に削除されます。"
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName}のスループット"
@@ -957,37 +783,6 @@ msgstr "グリッドを切り替え"
msgid "Toggle theme"
msgstr "テーマを切り替え"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "トークン"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "トークンとフィンガープリント"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr "トークンはエージェントの接続と登録を可能にします。フィンガープリントは各システム固有の安定した識別子で、初回接続時に設定されます。"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "トークンとフィンガープリントは、ハブへのWebSocket接続の認証に使用されます。"
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr "1分間のロードアベレージがしきい値を超えたときにトリガーされます"
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr "15分間のロードアベレージがしきい値を超えたときにトリガーされます"
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr "5分間のロードアベレージがしきい値を超えたときにトリガーされます"
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "センサーがしきい値を超えたときにトリガーされます"
@@ -1012,15 +807,6 @@ msgstr "ステータスが上から下に切り替わるときにトリガーさ
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "ディスクの使用量がしきい値を超えたときにトリガーされます"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr "単位の設定"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "ユニバーサルトークン"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "稼働時間"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "使用量"
@@ -1048,6 +833,7 @@ msgstr "ルートパーティションの使用量"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "使用中"
@@ -1056,18 +842,10 @@ msgstr "使用中"
msgid "Users"
msgstr "ユーザー"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "値"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "表示"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr "直近200件のアラートを表示します。"
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "表示列"
@@ -1078,25 +856,20 @@ msgstr "表示するのに十分なレコードを待っています"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
msgstr "翻訳をさらに良くするためにご協力をお願いします。詳細については<0>Crowdin</0>をご覧ください。"
msgstr "翻訳をさらに良くするためにご協力いただけますか?詳細については<0>Crowdin</0>をご覧ください。"
#: src/components/routes/settings/notifications.tsx
msgid "Webhook / Push notifications"
msgstr "Webhook / プッシュ通知"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "有効にすると、このトークンはエージェントが事前のシステム作成なしに自己登録することを可能にします。1時間後またはハブの再起動時に期限切れになります。"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows コマンド"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "書き込み"
@@ -1111,4 +884,3 @@ msgstr "YAML設定"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "ユーザー設定が更新されました。"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ko\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-07 10:06\n"
"Last-Translator: \n"
"Language-Team: Korean\n"
"Plural-Forms: nplurals=1; plural=0;\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# 일} 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/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# 시간} other {# 시간}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# 시간} other {# 시간}}"
msgid "1 hour"
msgstr "1시간"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr "1분"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1주"
@@ -50,11 +39,6 @@ msgstr "1주"
msgid "12 hours"
msgstr "12시간"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr "15분"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24시간"
@@ -63,22 +47,11 @@ msgstr "24시간"
msgid "30 days"
msgstr "30일"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr "5분"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "작업"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr "활성"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "활성화된 알림들"
@@ -103,6 +76,9 @@ msgstr "URL 추가"
msgid "Adjust display options for charts."
msgstr "차트 표시 옵션 변경."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "관리자"
msgid "Agent"
msgstr "에이전트"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr "알림 기록"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "모든 시스템"
msgid "Are you sure you want to delete {name}?"
msgstr "{name}을(를) 삭제하시겠습니까?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr "확실합니까?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "자동 복사는 안전한 컨텍스트가 필요합니다."
@@ -146,7 +112,7 @@ msgstr "평균"
#: src/components/routes/system.tsx
msgid "Average CPU utilization of containers"
msgstr "Docker 컨테이너의 평균 CPU 사용량"
msgstr "컨테이너의 평균 CPU 사용량"
#. placeholder {0}: data.alert.unit
#: src/components/alerts/alerts-system.tsx
@@ -188,22 +154,11 @@ msgstr "Beszel은 여러 인기 있는 알림 서비스와 연동하기 위해 <
msgid "Binary"
msgstr "실행 파일"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr "비트 (Kbps, Mbps, Gbps)"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr "바이트 (KB/s, MB/s, GB/s)"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "캐시 / 버퍼"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "취소"
@@ -211,14 +166,6 @@ msgstr "취소"
msgid "Caution - potential data loss"
msgstr "주의 - 데이터 손실 가능성"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr "섭씨 (°C)"
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr "메트릭의 표시 단위를 변경합니다."
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "일반 애플리케이션 옵션 변경."
@@ -239,7 +186,7 @@ msgstr "자세한 내용은 로그를 확인하세요."
msgid "Check your notification service"
msgstr "알림 서비스를 확인하세요."
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "클릭하여 복사"
@@ -257,12 +204,7 @@ msgstr "알림을 수신할 방법을 설정하세요."
msgid "Confirm password"
msgstr "비밀번호 확인"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr "연결이 끊겼습니다"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "계속"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "클립보드에 복사됨"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "docker compose 내용 복사"
msgstr "docker compose 복사"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "docker run 명령어 복사"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "환경 복사"
msgstr "docker run 복사"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "호스트 복사"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "리눅스 명령어 복사"
@@ -300,25 +234,13 @@ msgstr "리눅스 명령어 복사"
msgid "Copy text"
msgstr "텍스트 복사"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "아래 에이전트의 설치 명령을 복사하거나 <0>범용 토큰</0>으로 에이전트를 자동으로 등록하세요."
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr "아래 에이전트의 <0>docker-compose.yml</0> 내용을 복사하거나 <1>범용 토큰</1>으로 에이전트를 자동으로 등록하세요."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "YAML 복사"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU 사용량"
@@ -326,11 +248,6 @@ msgstr "CPU 사용량"
msgid "Create account"
msgstr "계정 생성"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr "생성됨"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "기본 기간"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "삭제"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "지문 삭제"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "디스크"
@@ -362,10 +274,6 @@ msgstr "디스크"
msgid "Disk I/O"
msgstr "디스크 I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr "디스크 단위"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "문서"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "오프라인"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr "기간"
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "비밀번호를 재설정하려면 이메일 주소를 입력하세요"
msgid "Enter email address..."
msgstr "이메일 주소 입력..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "오류"
@@ -445,10 +346,6 @@ msgstr "마지막 {2, plural, one {# 분} other {# 분}} 동안 {0}{1} 초과"
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "<0>config.yml</0>에 정의되지 않은 기존 시스템은 삭제됩니다. 정기적으로 백업을 하세요."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr "내보내기"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "구성 내보내기"
@@ -457,10 +354,6 @@ msgstr "구성 내보내기"
msgid "Export your current systems configuration."
msgstr "현재 시스템 구성 내보내기"
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr "화씨 (°F)"
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "인증 실패"
@@ -480,14 +373,9 @@ msgstr "알림 수정 실패"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "필터..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr "지문"
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "<0>{min}</0> {min, plural, one {분} other {분}} 동안"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "그리드"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew 명령어"
@@ -546,27 +433,6 @@ msgstr "레이아웃"
msgid "Light"
msgstr "밝게"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr "부하 평균"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr "부하 평균 15분"
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr "부하 평균 1분"
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr "부하 평균 5분"
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr "부하 평균"
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "로그아웃"
@@ -615,7 +481,6 @@ msgstr "메모리 사용량"
msgid "Memory usage of docker containers"
msgstr "Docker 컨테이너의 메모리 사용량"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "이름"
@@ -632,19 +497,10 @@ msgstr "Docker 컨테이너의 네트워크 트래픽"
msgid "Network traffic of public interfaces"
msgstr "공용 인터페이스의 네트워크 트래픽"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr "네트워크 단위"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "결과가 없습니다."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr "결과 없음."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "매 시작 시, 데이터베이스가 파일에 정의된 시스템과 일치하도록 업데이트됩니다."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "메뉴 열기"
@@ -682,12 +536,6 @@ msgstr "기존 알림 덮어쓰기"
msgid "Page"
msgstr "페이지"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr "{1}페이지 중 {0}페이지"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "페이지 / 설정"
@@ -715,7 +563,7 @@ msgstr "일시 중지"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "일시 정지됨"
msgstr "일시정지됨"
#: src/components/routes/settings/notifications.tsx
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "공개 키"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "읽기"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "수신됨"
@@ -782,24 +631,10 @@ msgstr "수신됨"
msgid "Reset Password"
msgstr "비밀번호 재설정"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr "해결됨"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "재개"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "토큰 회전"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr "페이지당 행 수"
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Enter 키 또는 쉼표를 사용하여 주소를 저장하세요. 이메일 알림을 비활성화하려면 비워 두세요."
@@ -825,7 +660,8 @@ msgstr "시스템 또는 설정 검색..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "알림을 받는 방법을 구성하려면 <0>알림 설정</0>을 참조하세요."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "보냄"
@@ -833,6 +669,7 @@ msgstr "보냄"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "시스템을 볼 때 차트의 기본 시간 범위를 설정합니다."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "SMTP 설정"
msgid "Sort By"
msgstr "정렬 기준"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr "상태"
#: src/lib/utils.ts
msgid "Status"
msgstr "상태"
@@ -876,16 +708,10 @@ msgstr "스왑 사용량"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "시스템"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr "시간에 따른 시스템 부하 평균"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "시스템"
@@ -908,10 +734,6 @@ msgstr "온도"
msgid "Temperature"
msgstr "온도"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr "온도 단위"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "시스템 센서의 온도"
@@ -924,6 +746,14 @@ msgstr "테스트 <0>URL</0>"
msgid "Test notification sent"
msgstr "테스트 알림이 전송되었습니다."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "에이전트가 시스템에서 실행 중이어야 연결할 수 있습니다. 아래의 에이전트 설치 명령을 복사하세요."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "에이전트가 시스템에서 실행 중이어야 연결할 수 있습니다. 아래의 <0>docker-compose.yml</0>을 복사하세요."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "그런 다음 백엔드에 로그인하여 사용자 테이블에서 사용자 계정 비밀번호를 재설정하세요."
@@ -932,10 +762,6 @@ msgstr "그런 다음 백엔드에 로그인하여 사용자 테이블에서 사
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "이 작업은 되돌릴 수 없습니다. 데이터베이스에서 {name}에 대한 모든 현재 기록이 영구적으로 삭제됩니다."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr "선택한 모든 레코드를 데이터베이스에서 영구적으로 삭제합니다."
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName}의 처리량"
@@ -957,37 +783,6 @@ msgstr "그리드 전환"
msgid "Toggle theme"
msgstr "테마 전환"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "토큰"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "토큰 및 지문"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr "토큰은 에이전트가 연결하고 등록할 수 있도록 합니다. 지문은 첫 연결 시 설정되는 각 시스템의 고유한 안정적인 식별자입니다."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "토큰과 지문은 허브에 대한 WebSocket 연결을 인증하는 데 사용됩니다."
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr "1분 부하 평균이 임계값을 초과하면 트리거됩니다."
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr "15분 부하 평균이 임계값을 초과하면 트리거됩니다."
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr "5분 부하 평균이 임계값을 초과하면 트리거됩니다."
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "센서가 임계값을 초과할 때 트리거됩니다."
@@ -1012,15 +807,6 @@ msgstr "시스템의 전원이 켜지거나 꺼질때 트리거됩니다."
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "디스크 사용량이 임계값을 초과할 때 트리거됩니다."
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr "단위 기본 설정"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "범용 토큰"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "가동 시간"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "사용량"
@@ -1048,6 +833,7 @@ msgstr "루트 파티션의 사용량"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "사용됨"
@@ -1056,18 +842,10 @@ msgstr "사용됨"
msgid "Users"
msgstr "사용자"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "값"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "보기"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr "최근 200개의 알림을 봅니다."
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "표시할 열"
@@ -1078,25 +856,20 @@ msgstr "표시할 충분한 기록을 기다리는 중"
#: src/components/routes/settings/general.tsx
msgid "Want to help improve our translations? Check <0>Crowdin</0> for details."
msgstr "번역을 개선하는데 도움을 주시겠습니까? 자세한 내용은 <0>Crowdin</0>을 확인해 주세요."
msgstr "번역을 더 좋게 만드는 데 도움을 주시겠습니까? 자세한 내용은 <0>Crowdin</0>을 확인세요."
#: src/components/routes/settings/notifications.tsx
msgid "Webhook / Push notifications"
msgstr "Webhook / 푸시 알림"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "활성화하면 이 토큰을 통해 에이전트가 사전 시스템 생성 없이 자체 등록할 수 있습니다. 1시간 후 또는 허브 재시작 시 만료됩니다."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows 명령어"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "쓰기"
@@ -1111,4 +884,3 @@ msgstr "YAML 구성"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "사용자 설정이 업데이트되었습니다."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: nl\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Dutch\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dag} other {# dagen}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# uur} other {# uren}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# uur} other {# uren}}"
msgid "1 hour"
msgstr "1 uur"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 week"
@@ -50,11 +39,6 @@ msgstr "1 week"
msgid "12 hours"
msgstr "12 uren"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 uren"
@@ -63,22 +47,11 @@ msgstr "24 uren"
msgid "30 days"
msgstr "30 dagen"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Acties"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Actieve waarschuwingen"
@@ -103,6 +76,9 @@ msgstr "Voeg URL toe"
msgid "Adjust display options for charts."
msgstr "Weergaveopties voor grafieken aanpassen."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Admin"
msgid "Agent"
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Alle systemen"
msgid "Are you sure you want to delete {name}?"
msgstr "Weet je zeker dat je {name} wilt verwijderen?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Automatisch kopiëren vereist een veilige context."
@@ -188,22 +154,11 @@ msgstr "Beszel gebruikt <0>Shoutrr</0> om te integreren met populaire meldingsdi
msgid "Binary"
msgstr "Binair"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / Buffers"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Annuleren"
@@ -211,14 +166,6 @@ msgstr "Annuleren"
msgid "Caution - potential data loss"
msgstr "Opgelet - potentieel gegevensverlies"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Wijzig algemene applicatie opties."
@@ -239,7 +186,7 @@ msgstr "Controleer de logs voor meer details."
msgid "Check your notification service"
msgstr "Controleer je meldingsservice"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Klik om te kopiëren"
@@ -257,12 +204,7 @@ msgstr "Configureer hoe je waarschuwingsmeldingen ontvangt."
msgid "Confirm password"
msgstr "Bevestig wachtwoord"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Volgende"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Gekopieerd naar het klembord"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Docker compose kopiëren"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Docker run kopiëren"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "Env kopiëren"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopieer host"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopieer Linux-opdracht"
@@ -300,25 +234,13 @@ msgstr "Kopieer Linux-opdracht"
msgid "Copy text"
msgstr "Kopieer tekst"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "Kopieer de installatie opdracht voor de agent hieronder, of registreer agenten automatisch met een <0>universele 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 "Kopieer de<0>docker-compose.yml</0> inhoud voor de agent hieronder, of registreer agenten automatisch met een <1>universele token</1>."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "YAML kopiëren"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Processorgebruik"
@@ -326,11 +248,6 @@ msgstr "Processorgebruik"
msgid "Create account"
msgstr "Account aanmaken"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Standaard tijdsduur"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Verwijderen"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "Vingerafdruk verwijderen"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Schijf"
@@ -362,10 +274,6 @@ msgstr "Schijf"
msgid "Disk I/O"
msgstr "Schijf I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Documentatie"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Offline"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "Voer een e-mailadres in om het wachtwoord opnieuw in te stellen"
msgid "Enter email address..."
msgstr "Voer een e-mailadres in..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Fout"
@@ -445,10 +346,6 @@ msgstr "Overschrijdt {0}{1} in de laatste {2, plural, one {# minuut} other {# mi
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "Bestaande systemen die niet gedefinieerd zijn in <0>config.yml</0> zullen worden verwijderd. Maak regelmatige backups."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Configuratie exporteren"
@@ -457,10 +354,6 @@ msgstr "Configuratie exporteren"
msgid "Export your current systems configuration."
msgstr "Exporteer je huidige systeemconfiguratie."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Authenticatie mislukt"
@@ -480,14 +373,9 @@ msgstr "Bijwerken waarschuwing mislukt"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr "Vingerafdruk"
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "Voor <0>{min}</0> {min, plural, one {minuut} other {minuten}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Raster"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew-commando"
@@ -546,27 +433,6 @@ msgstr "Indeling"
msgid "Light"
msgstr "Licht"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr "Gemiddelde Belasting 15m"
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr "Gemiddelde Belasting 5m"
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Afmelden"
@@ -615,7 +481,6 @@ msgstr "Geheugengebruik"
msgid "Memory usage of docker containers"
msgstr "Geheugengebruik van docker containers"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Naam"
@@ -632,19 +497,10 @@ msgstr "Netwerkverkeer van docker containers"
msgid "Network traffic of public interfaces"
msgstr "Netwerkverkeer van publieke interfaces"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Geen resultaten gevonden."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "Bij elke herstart zullen systemen in de database worden bijgewerkt om overeen te komen met de systemen die in het bestand zijn gedefinieerd."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Open menu"
@@ -682,12 +536,6 @@ msgstr "Overschrijf bestaande waarschuwingen"
msgid "Page"
msgstr "Pagina"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Pagina's / Instellingen"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Publieke sleutel"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Lezen"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Ontvangen"
@@ -782,24 +631,10 @@ msgstr "Ontvangen"
msgid "Reset Password"
msgstr "Wachtwoord resetten"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Hervatten"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "Roteer Token"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Bewaar het adres met de enter-toets of komma. Laat leeg om e-mailmeldingen uit te schakelen."
@@ -825,7 +660,8 @@ msgstr "Zoek naar systemen of instellingen..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Zie <0>notificatie-instellingen</0> om te configureren hoe je meldingen ontvangt."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Verzonden"
@@ -833,6 +669,7 @@ msgstr "Verzonden"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Stelt het standaard tijdsbereik voor grafieken in wanneer een systeem wordt bekeken."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "SMTP-instellingen"
msgid "Sort By"
msgstr "Sorteren op"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
@@ -876,16 +708,10 @@ msgstr "Swap gebruik"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Systeem"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Systemen"
@@ -908,10 +734,6 @@ msgstr "Temperatuur"
msgid "Temperature"
msgstr "Temperatuur"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperatuur van systeem sensoren"
@@ -924,6 +746,14 @@ msgstr "Test <0>URL</0>"
msgid "Test notification sent"
msgstr "Testmelding verzonden"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "De agent moet op het systeem draaien om te verbinden. Kopieer het installatiecommando voor de agent hieronder."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "De agent moet op het systeem draaien om te verbinden. Kopieer de<0>docker-compose.yml</0> voor de agent hieronder."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Log vervolgens in op de backend en reset het wachtwoord van je gebruikersaccount in het gebruikersoverzicht."
@@ -932,10 +762,6 @@ msgstr "Log vervolgens in op de backend en reset het wachtwoord van je gebruiker
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Deze actie kan niet ongedaan worden gemaakt. Dit zal alle huidige records voor {name} permanent verwijderen uit de database."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Doorvoer van {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Schakel raster"
msgid "Toggle theme"
msgstr "Schakel thema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "Token"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "Tokens & Vingerafdrukken"
#: 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 "Tokens staan agenten toe om verbinding te maken met en te registreren. Vingerafdrukken zijn stabiele Ids deze zijn uniek voor elk systeem, ingesteld bij eerste verbinding."
#: src/components/routes/settings/tokens-fingerprints.tsx
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/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr "Triggert wanneer de 15 minuten gemiddelde belasting een drempelwaarde overschrijdt"
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr "Triggert wanneer de 5 minuten gemiddelde belasting een drempelwaarde overschrijdt"
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Triggert wanneer een sensor een drempelwaarde overschrijdt"
@@ -1012,15 +807,6 @@ 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"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "Universele token"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "Actief"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Gebruik"
@@ -1048,6 +833,7 @@ msgstr "Gebruik van root-partitie"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Gebruikt"
@@ -1056,18 +842,10 @@ msgstr "Gebruikt"
msgid "Users"
msgstr "Gebruikers"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Weergave"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Zichtbare kolommen"
@@ -1084,19 +862,14 @@ msgstr "Wil je ons helpen onze vertalingen nog beter te maken? Bekijk <0>Crowdin
msgid "Webhook / Push notifications"
msgstr "Webhook / Pushmeldingen"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "Wanneer ingeschakeld kunnen agenten zich met dit token registreren zonder dat er vooraf een systeem aangemaakt hoeft te worden. Het token verloopt na één uur of bij herstart van de hub."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows-commando"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Schrijven"
@@ -1111,4 +884,3 @@ msgstr "YAML Configuratie"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Je gebruikersinstellingen zijn bijgewerkt."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: no\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Norwegian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dag} other {# dager}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# time} other {# timer}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# time} other {# timer}}"
msgid "1 hour"
msgstr "1 time"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 uke"
@@ -50,11 +39,6 @@ msgstr "1 uke"
msgid "12 hours"
msgstr "12 timer"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 timer"
@@ -63,22 +47,11 @@ msgstr "24 timer"
msgid "30 days"
msgstr "30 dager"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Handlinger"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktive Alarmer"
@@ -103,6 +76,9 @@ msgstr "Legg Til URL"
msgid "Adjust display options for charts."
msgstr "Juster visningsalternativer for diagrammer."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Admin"
msgid "Agent"
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Alle Systemer"
msgid "Are you sure you want to delete {name}?"
msgstr "Er du sikker på at du vil slette {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Automatisk kopiering krever en sikker kontekst."
@@ -188,22 +154,11 @@ msgstr "Beszel bruker <0>Shoutrrr</0> for integrering mot populære meldingstjen
msgid "Binary"
msgstr "Binær"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / Buffere"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Avbryt"
@@ -211,14 +166,6 @@ msgstr "Avbryt"
msgid "Caution - potential data loss"
msgstr "Advarsel - potensielt tap av data"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Endre generelle program-innstillinger."
@@ -239,7 +186,7 @@ msgstr "Sjekk loggene for flere detaljer."
msgid "Check your notification service"
msgstr "Sjekk din meldingstjeneste"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Klikk for å kopiere"
@@ -257,12 +204,7 @@ msgstr "Konfigurer hvordan du vil motta alarmvarsler."
msgid "Confirm password"
msgstr "Bekreft passord"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Fortsett"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Kopiert til utklippstavlen"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Kopier docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Kopier docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopier vert"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopier Linux-kommando"
@@ -300,25 +234,13 @@ msgstr "Kopier Linux-kommando"
msgid "Copy text"
msgstr "Kopier tekst"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU-bruk"
@@ -326,11 +248,6 @@ msgstr "CPU-bruk"
msgid "Create account"
msgstr "Opprett konto"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Standard tidsperiode"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Slett"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
@@ -362,10 +274,6 @@ msgstr "Disk"
msgid "Disk I/O"
msgstr "Disk I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Dokumentasjon"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Nede"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "Skriv inn e-postadresse for å nullstille passordet"
msgid "Enter email address..."
msgstr "Skriv inn e-postadresse..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Feil"
@@ -445,10 +346,6 @@ msgstr "Overstiger {0}{1} {2, plural, one {det siste minuttet} other {de siste #
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "Eksisterende systemer som ikke er er definert i <0>config.yml</0> vil bli slettet. Vennligst ta jevnlige sikkerhetskopier."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Eksporter konfigurasjon"
@@ -457,10 +354,6 @@ msgstr "Eksporter konfigurasjon"
msgid "Export your current systems configuration."
msgstr "Eksporter din nåværende systemkonfigurasjon"
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Autentisering mislyktes"
@@ -480,14 +373,9 @@ msgstr "Kunne ikke oppdatere alarm"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "I <0>{min}</0> {min, plural, one {minutt} other {minutter}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Rutenett"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew-kommando"
@@ -546,27 +433,6 @@ msgstr "Layout"
msgid "Light"
msgstr "Lyst"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Logg Ut"
@@ -615,7 +481,6 @@ msgstr "Minnebruk"
msgid "Memory usage of docker containers"
msgstr "Minnebruk av docker-konteinere"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Navn"
@@ -632,19 +497,10 @@ msgstr "Nettverkstrafikk av docker-konteinere"
msgid "Network traffic of public interfaces"
msgstr "Nettverkstrafikk av eksterne nettverksgrensesnitt"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Ingen resultater funnet."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "Ved hver omstart vil systemer i databasen bli oppdatert til å matche systemene definert i fila."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Åpne meny"
@@ -682,12 +536,6 @@ msgstr "Overskriv eksisterende alarmer"
msgid "Page"
msgstr "Side"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Sider / Innstillinger"
@@ -715,7 +563,7 @@ msgstr "Pause"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "Satt på Pause"
msgstr "Pauset"
#: src/components/routes/settings/notifications.tsx
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Offentlig Nøkkel"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Lesing"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Mottatt"
@@ -782,24 +631,10 @@ msgstr "Mottatt"
msgid "Reset Password"
msgstr "Nullstill Passord"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Gjenoppta"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Lagre adressen med Enter-tasten eller komma. La feltet være tomt for å deaktivere e-postvarsler."
@@ -825,7 +660,8 @@ msgstr "Søk etter systemer eller innstillinger..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Se <0>varslingsinnstillingene</0> for å konfigurere hvordan du vil motta varsler."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Sendt"
@@ -833,6 +669,7 @@ msgstr "Sendt"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Angir standard tidsperiode for diagrammer når et system vises."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "SMTP-innstillinger"
msgid "Sort By"
msgstr "Sorter Etter"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
@@ -876,16 +708,10 @@ msgstr "Swap-bruk"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "System"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Systemer"
@@ -908,10 +734,6 @@ msgstr "Temp"
msgid "Temperature"
msgstr "Temperatur"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperaturer på system-sensorer"
@@ -924,6 +746,14 @@ msgstr "Test <0>URL</0>"
msgid "Test notification sent"
msgstr "Test-varsling sendt"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "Agenten må kjøre på systemet du vil koble til. Kopier installasjons-kommandoen for agenten under."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "Agenten må kjøre på systemet du vil koble til. Kopier <0>docker-compose.yml</0> for agenten under."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Logg deretter inn i backend og nullstill passordet på din konto i users-tabellen."
@@ -932,10 +762,6 @@ msgstr "Logg deretter inn i backend og nullstill passordet på din konto i users
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Denne handlingen kan ikke omgjøres. Dette vil slette alle poster for {name} permanent fra databasen."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Gjennomstrømning av {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Rutenett av/på"
msgid "Toggle theme"
msgstr "Tema av/på"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Slår inn når enhver sensor overstiger en grenseverdi"
@@ -1012,15 +807,6 @@ 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"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "Oppetid"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Forbruk"
@@ -1048,6 +833,7 @@ msgstr "Forbruk av rot-partisjon"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Brukt"
@@ -1056,18 +842,10 @@ msgstr "Brukt"
msgid "Users"
msgstr "Brukere"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Visning"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Synlige Felter"
@@ -1084,19 +862,14 @@ msgstr "Vil du hjelpe oss med å gjøre oversettelsene enda bedre? Ta en titt p
msgid "Webhook / Push notifications"
msgstr "Webhook / Push-varslinger"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows-kommando"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Skriving"
@@ -1111,4 +884,3 @@ msgstr "YAML Konfigurasjon"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Dine brukerinnstillinger har blitt oppdatert."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: pl\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Polish\n"
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dzień} few {# dni} many {# dni} other {# dni}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {godzinę} few {# godziny} many {# godzin} other {# godziny}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {godzinę} few {# godziny} many {# godzin} other {#
msgid "1 hour"
msgstr "1 godzina"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 tydzień"
@@ -50,11 +39,6 @@ msgstr "1 tydzień"
msgid "12 hours"
msgstr "12 godzin"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 godziny"
@@ -63,22 +47,11 @@ msgstr "24 godziny"
msgid "30 days"
msgstr "30 dni"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Akcje"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktywne alerty"
@@ -103,6 +76,9 @@ msgstr "Dodaj URL"
msgid "Adjust display options for charts."
msgstr "Dostosuj opcje wyświetlania wykresów."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Admin"
msgid "Agent"
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Wszystkie systemy"
msgid "Are you sure you want to delete {name}?"
msgstr "Czy na pewno chcesz usunąć {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Automatyczne kopiowanie wymaga bezpiecznego kontekstu."
@@ -188,22 +154,11 @@ msgstr "Beszel używa <0>Shoutrrr</0> do integracji z popularnych serwisami powi
msgid "Binary"
msgstr "Plik binarny"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Pamięć podręczna / Bufory"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Anuluj"
@@ -211,14 +166,6 @@ msgstr "Anuluj"
msgid "Caution - potential data loss"
msgstr "Uwaga- potencjalna utrata danych."
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Zmiana ogólnych ustawień aplikacji."
@@ -239,7 +186,7 @@ msgstr "Sprawdź logi, aby uzyskać więcej informacji."
msgid "Check your notification service"
msgstr "Sprawdź swój serwis powiadomień"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Kliknij, aby skopiować"
@@ -257,12 +204,7 @@ msgstr "Skonfiguruj sposób otrzymywania powiadomień."
msgid "Confirm password"
msgstr "Potwierdź hasło"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Kontynuuj"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Skopiowano do schowka"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Skopiuj docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Skopiuj docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopiuj host"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopiuj polecenie Linux"
@@ -300,25 +234,13 @@ msgstr "Kopiuj polecenie Linux"
msgid "Copy text"
msgstr "Kopiuj tekst"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "Procesor"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Użycie procesora"
@@ -326,11 +248,6 @@ msgstr "Użycie procesora"
msgid "Create account"
msgstr "Utwórz konto"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Domyślny przedział czasu"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Usuń"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Dysk"
@@ -362,10 +274,6 @@ msgstr "Dysk"
msgid "Disk I/O"
msgstr "Dysk I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,20 +302,15 @@ msgstr "Dokumentacja"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Nie działa"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr "Edytuj"
msgstr ""
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
@@ -426,10 +329,8 @@ msgstr "Wprowadź adres e-mail, aby zresetować hasło"
msgid "Enter email address..."
msgstr "Wprowadź adres e-mail..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Błąd"
@@ -445,10 +346,6 @@ msgstr "Przekracza {0}{1} w ciągu ostatnich {2, plural, one {# minuty} other {#
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "Istniejące systemy, które nie są zdefiniowane w <0>config.yml</0>, zostaną usunięte. Proszę regularnie tworzyć kopie zapasowe."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Eksportuj konfigurację"
@@ -457,10 +354,6 @@ msgstr "Eksportuj konfigurację"
msgid "Export your current systems configuration."
msgstr "Eksportuj aktualną konfigurację systemów."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Błąd autoryzacji"
@@ -480,14 +373,9 @@ msgstr "Nie udało się zaktualizować powiadomienia"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filtruj..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "Na <0>{min}</0> {min, plural, one {minutę} other {minut}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Siatka"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Polecenie Homebrew"
@@ -546,27 +433,6 @@ msgstr "Układ"
msgid "Light"
msgstr "Jasny"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Wyloguj"
@@ -595,7 +461,7 @@ msgstr "Zarządzaj preferencjami wyświetlania i powiadomień."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "Instrukcja ręcznej konfiguracji"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
@@ -615,7 +481,6 @@ msgstr "Wykorzystanie pamięci"
msgid "Memory usage of docker containers"
msgstr "Użycie pamięci przez kontenery Docker."
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Nazwa"
@@ -632,19 +497,10 @@ msgstr "Ruch sieciowy kontenerów Docker."
msgid "Network traffic of public interfaces"
msgstr "Ruch sieciowy interfejsów publicznych"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Brak wyników."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "Przy każdym ponownym uruchomieniu systemy w bazie danych będą aktualizowane, aby odpowiadały systemom zdefiniowanym w pliku."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Otwórz menu"
@@ -682,12 +536,6 @@ msgstr "Nadpisz istniejące alerty"
msgid "Page"
msgstr "Strona"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Strony / Ustawienia"
@@ -703,7 +551,7 @@ msgstr "Hasło musi mieć co najmniej 8 znaków."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr "Hasło musi być mniejsze niż 72 bajty."
msgstr ""
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Klucz publiczny"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Czytaj"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Otrzymane"
@@ -782,24 +631,10 @@ msgstr "Otrzymane"
msgid "Reset Password"
msgstr "Resetuj hasło"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Wznów"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Zapisz adres, używając klawisza enter lub przecinka. Pozostaw puste, aby wyłączyć powiadomienia e-mail."
@@ -811,7 +646,7 @@ msgstr "Zapisz ustawienia"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "Zapisz system"
msgstr ""
#: src/components/navbar.tsx
msgid "Search"
@@ -825,7 +660,8 @@ msgstr "Szukaj systemów lub ustawień..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Zobacz <0>ustawienia powiadomień</0>, aby skonfigurować sposób, w jaki otrzymujesz powiadomienia."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Wysłane"
@@ -833,6 +669,7 @@ msgstr "Wysłane"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Ustawia domyślny zakres czasowy dla wykresów, gdy system jest wyświetlony."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "Ustawienia SMTP"
msgid "Sort By"
msgstr "Sortuj według"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
@@ -876,16 +708,10 @@ msgstr "Użycie pamięci wymiany"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "System"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Systemy"
@@ -901,17 +727,13 @@ msgstr "Tabela"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "Temperatura"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Temperatura"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperatury czujników systemowych."
@@ -924,6 +746,14 @@ msgstr "Test <0>URL</0>"
msgid "Test notification sent"
msgstr "Testowe powiadomienie wysłane."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "Agent musi być uruchomiony na systemie, aby nawiązać połączenie. Skopiuj poniżej polecenie instalacji agenta."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "Agent musi być uruchomiony na systemie, aby nawiązać połączenie. Skopiuj poniżej plik <0>docker-compose.yml</0> dla agenta."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Następnie zaloguj się do panelu administracyjnego i zresetuj hasło do konta użytkownika w tabeli użytkowników."
@@ -932,10 +762,6 @@ msgstr "Następnie zaloguj się do panelu administracyjnego i zresetuj hasło d
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Tej akcji nie można cofnąć. Spowoduje to trwałe usunięcie wszystkich bieżących rekordów dla {name} z bazy danych."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Przepustowość {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Przełącz siatkę"
msgid "Toggle theme"
msgstr "Zmień motyw"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Wyzwalane, gdy jakikolwiek czujnik przekroczy ustalony próg."
@@ -1012,20 +807,11 @@ 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"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr "Działa"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Updated in real time. Click on a system to view information."
@@ -1037,8 +823,7 @@ msgstr "Czas pracy"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Wykorzystanie"
@@ -1048,6 +833,7 @@ msgstr "Użycie partycji głównej"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Używane"
@@ -1056,18 +842,10 @@ msgstr "Używane"
msgid "Users"
msgstr "Użytkownicy"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Widok"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Widoczne kolumny"
@@ -1084,19 +862,14 @@ msgstr "Chcesz pomóc nam uczynić nasze tłumaczenia jeszcze lepszymi? Sprawdź
msgid "Webhook / Push notifications"
msgstr "Webhook / Powiadomienia push"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Polecenie Windows"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Napisz"
@@ -1111,4 +884,3 @@ msgstr "Konfiguracja YAML"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Twoje ustawienia użytkownika zostały zaktualizowane."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: pt\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Portuguese\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dia} other {# dias}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# hora} other {# horas}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# hora} other {# horas}}"
msgid "1 hour"
msgstr "1 hora"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 semana"
@@ -50,11 +39,6 @@ msgstr "1 semana"
msgid "12 hours"
msgstr "12 horas"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 horas"
@@ -63,22 +47,11 @@ msgstr "24 horas"
msgid "30 days"
msgstr "30 dias"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Ações"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Alertas Ativos"
@@ -103,6 +76,9 @@ msgstr "Adicionar URL"
msgid "Adjust display options for charts."
msgstr "Ajustar opções de exibição para gráficos."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Admin"
msgid "Agent"
msgstr "Agente"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Todos os Sistemas"
msgid "Are you sure you want to delete {name}?"
msgstr "Tem certeza de que deseja excluir {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "A cópia automática requer um contexto seguro."
@@ -188,22 +154,11 @@ msgstr "Beszel usa <0>Shoutrrr</0> para integrar com serviços de notificação
msgid "Binary"
msgstr "Binário"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / Buffers"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Cancelar"
@@ -211,14 +166,6 @@ msgstr "Cancelar"
msgid "Caution - potential data loss"
msgstr "Cuidado - possível perda de dados"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Alterar opções gerais do aplicativo."
@@ -239,7 +186,7 @@ msgstr "Verifique os logs para mais detalhes."
msgid "Check your notification service"
msgstr "Verifique seu serviço de notificação"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Clique para copiar"
@@ -257,12 +204,7 @@ msgstr "Configure como você recebe notificações de alerta."
msgid "Confirm password"
msgstr "Confirmar senha"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Continuar"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Copiado para a área de transferência"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Copiar docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Copiar docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "Copiar variáveis de ambiente"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Copiar host"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Copiar comando Linux"
@@ -300,25 +234,13 @@ msgstr "Copiar comando Linux"
msgid "Copy text"
msgstr "Copiar texto"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "Copie o comando de instalação do agente abaixo, ou registre agentes automaticamente com um <0>token universal</0>."
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr "Copie o conteúdo do <0>docker-compose.yml</0> do agente abaixo, ou registre agentes automaticamente com um <1>token universal</1>."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "Copiar YAML"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Uso de CPU"
@@ -326,11 +248,6 @@ msgstr "Uso de CPU"
msgid "Create account"
msgstr "Criar conta"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Período de tempo padrão"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Excluir"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "Excluir impressão digital"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disco"
@@ -362,10 +274,6 @@ msgstr "Disco"
msgid "Disk I/O"
msgstr "E/S de Disco"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,14 +302,9 @@ msgstr "Documentação"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "“Desligado”"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
@@ -426,10 +329,8 @@ msgstr "Digite o endereço de email para redefinir a senha"
msgid "Enter email address..."
msgstr "Digite o endereço de email..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Erro"
@@ -445,10 +346,6 @@ msgstr "Excede {0}{1} no último {2, plural, one {# minuto} other {# minutos}}"
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/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Exportar configuração"
@@ -457,10 +354,6 @@ msgstr "Exportar configuração"
msgid "Export your current systems configuration."
msgstr "Exporte a configuração atual dos seus sistemas."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Falha na autenticação"
@@ -480,14 +373,9 @@ msgstr "Falha ao atualizar alerta"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filtrar..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "Por <0>{min}</0> {min, plural, one {minuto} other {minutos}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Grade"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Comando Homebrew"
@@ -546,27 +433,6 @@ msgstr "Aspeto"
msgid "Light"
msgstr "Claro"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Sair"
@@ -595,7 +461,7 @@ msgstr "Gerenciar preferências de exibição e notificação."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "Instruções de configuração manual"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
@@ -615,7 +481,6 @@ msgstr "Uso de Memória"
msgid "Memory usage of docker containers"
msgstr "Uso de memória dos contêineres Docker"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Nome"
@@ -632,19 +497,10 @@ msgstr "Tráfego de rede dos contêineres Docker"
msgid "Network traffic of public interfaces"
msgstr "Tráfego de rede das interfaces públicas"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Nenhum resultado encontrado."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "A cada reinício, os sistemas no banco de dados serão atualizados para corresponder aos sistemas definidos no arquivo."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Abrir menu"
@@ -682,12 +536,6 @@ msgstr "Sobrescrever alertas existentes"
msgid "Page"
msgstr "Página"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Páginas / Configurações"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Chave Pública"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Ler"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Recebido"
@@ -782,24 +631,10 @@ msgstr "Recebido"
msgid "Reset Password"
msgstr "Redefinir Senha"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Retomar"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "Rotacionar token"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: 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."
@@ -825,7 +660,8 @@ msgstr "Pesquisar por sistemas ou configurações..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Veja <0>configurações de notificação</0> para configurar como você recebe alertas."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Enviado"
@@ -833,6 +669,7 @@ msgstr "Enviado"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Define o intervalo de tempo padrão para gráficos quando um sistema é visualizado."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "Configurações SMTP"
msgid "Sort By"
msgstr "Ordenar Por"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
@@ -876,16 +708,10 @@ msgstr "Uso de Swap"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Sistema"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Sistemas"
@@ -908,10 +734,6 @@ msgstr "Temp"
msgid "Temperature"
msgstr "Temperatura"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperaturas dos sensores do sistema"
@@ -924,6 +746,14 @@ msgstr "Testar <0>URL</0>"
msgid "Test notification sent"
msgstr "Notificação de teste enviada"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "O agente deve estar em execução no sistema para conectar. Copie o comando de instalação para o agente abaixo."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "O agente deve estar em execução no sistema para conectar. Copie o <0>docker-compose.yml</0> para o agente abaixo."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Em seguida, faça login no backend e redefina a senha da sua conta de usuário na tabela de usuários."
@@ -932,10 +762,6 @@ msgstr "Em seguida, faça login no backend e redefina a senha da sua conta de us
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Esta ação não pode ser desfeita. Isso excluirá permanentemente todos os registros atuais de {name} do banco de dados."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Taxa de transferência de {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Alternar grade"
msgid "Toggle theme"
msgstr "Alternar tema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "Tokens e Impressões Digitais"
#: 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 "Os tokens permitem que os agentes se conectem e registrem. As impressões digitais são identificadores estáveis únicos para cada sistema, definidos na primeira conexão."
#: src/components/routes/settings/tokens-fingerprints.tsx
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/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Dispara quando qualquer sensor excede um limite"
@@ -1012,20 +807,11 @@ 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"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "Token universal"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr "“Ligado”"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Updated in real time. Click on a system to view information."
@@ -1037,8 +823,7 @@ msgstr "Tempo de Atividade"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Uso"
@@ -1048,6 +833,7 @@ msgstr "Uso da partição raiz"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Usado"
@@ -1056,18 +842,10 @@ msgstr "Usado"
msgid "Users"
msgstr "Usuários"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Visual"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Campos Visíveis"
@@ -1084,19 +862,14 @@ msgstr "Quer nos ajudar a melhorar ainda mais nossas traduções? Confira <0>Cro
msgid "Webhook / Push notifications"
msgstr "Notificações Webhook / Push"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "Quando habilitado, este token permite que os agentes se registrem automaticamente sem criação prévia do sistema. Expira após uma hora ou na reinicialização do hub."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Comando Windows"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Escrever"
@@ -1111,4 +884,3 @@ msgstr "Configuração YAML"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "As configurações do seu usuário foram atualizadas."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: ru\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-25 07:41\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Russian\n"
"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# день} 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 "Выбрано {0} из {1} строк."
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# час} other {# часов}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# час} other {# часов}}"
msgid "1 hour"
msgstr "1 час"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr "1 мин"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 неделя"
@@ -50,11 +39,6 @@ msgstr "1 неделя"
msgid "12 hours"
msgstr "12 часов"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr "15 мин"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 часа"
@@ -63,22 +47,11 @@ msgstr "24 часа"
msgid "30 days"
msgstr "30 дней"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr "5 мин"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Действия"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr "Активно"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Активные оповещения"
@@ -103,6 +76,9 @@ msgstr "Добавить URL"
msgid "Adjust display options for charts."
msgstr "Настроить параметры отображения для графиков."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Администратор"
msgid "Agent"
msgstr "Агент"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr "История оповещений"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Все системы"
msgid "Are you sure you want to delete {name}?"
msgstr "Вы уверены, что хотите удалить {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr "Вы уверены?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Автоматическое копирование требует безопасного контекста."
@@ -188,22 +154,11 @@ msgstr "Beszel использует <0>Shoutrrr</0> для интеграции
msgid "Binary"
msgstr "Двоичный"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr "Биты (Кбит/с, Мбит/с, Гбит/с)"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr "Байты (Кбайт/с, Мбайт/с, Гбайт/с)"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Кэш / Буферы"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Отмена"
@@ -211,14 +166,6 @@ msgstr "Отмена"
msgid "Caution - potential data loss"
msgstr "Внимание - возможная потеря данных"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr "Цельсий (°C)"
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr "Изменить единицы измерения для метрик."
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Изменить общие параметры приложения."
@@ -239,7 +186,7 @@ msgstr "Проверьте журналы для получения более
msgid "Check your notification service"
msgstr "Проверьте ваш сервис уведомлений"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Нажмите, чтобы скопировать"
@@ -257,12 +204,7 @@ msgstr "Настройте, как вы получаете уведомлени
msgid "Confirm password"
msgstr "Подтвердите пароль"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr "Нет соединения"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Продолжить"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Скопировано в буфер обмена"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Скопировать docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Скопировать docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "Скопировать env"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Копировать хост"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Копировать команду Linux"
@@ -300,25 +234,13 @@ msgstr "Копировать команду Linux"
msgid "Copy text"
msgstr "Копировать текст"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr "Скопируйте команду для установки агента ниже, или зарегистрируйте агентов автоматически с помощью <0>универсального токена</0>."
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr "Скопируйте содержимое <0>docker-compose.yml</0> для агента ниже, или зарегистрируйте агентов автоматически с помощью <1>универсального токена</1>."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "Скопировать YAML"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "Использование CPU"
@@ -326,11 +248,6 @@ msgstr "Использование CPU"
msgid "Create account"
msgstr "Создать аккаунт"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr "Создано"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Период по умолчанию"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Удалить"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "Удалить отпечаток"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Диск"
@@ -362,10 +274,6 @@ msgstr "Диск"
msgid "Disk I/O"
msgstr "Дисковый ввод/вывод"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr "Единицы измерения температуры"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Документация"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Не в сети"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr "Длительность"
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "Введите адрес электронной почты для сб
msgid "Enter email address..."
msgstr "Введите адрес электронной почты..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Ошибка"
@@ -445,10 +346,6 @@ msgstr "Превышает {0}{1} за последние {2, plural, one {# м
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "Существующие системы, не определенные в <0>config.yml</0>, будут удалены. Пожалуйста, делайте регулярные резервные копии."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr "Экспорт"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Экспорт конфигурации"
@@ -457,10 +354,6 @@ msgstr "Экспорт конфигурации"
msgid "Export your current systems configuration."
msgstr "Экспортируйте текущую конфигурацию систем."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr "Фаренгейт (°F)"
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Не удалось аутентифицировать"
@@ -480,14 +373,9 @@ msgstr "Не удалось обновить оповещение"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Фильтр..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr "Отпечаток"
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "На <0>{min}</0> {min, plural, one {минуту} other {минут}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Сетка"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Команда Homebrew"
@@ -546,27 +433,6 @@ msgstr "Макет"
msgid "Light"
msgstr "Светлая"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr "Средняя загрузка"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr "Средняя загрузка за 15м"
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr "Средняя загрузка за 1м"
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr "Средняя загрузка за 5м"
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr "Ср. загрузка"
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Выйти"
@@ -615,7 +481,6 @@ msgstr "Использование памяти"
msgid "Memory usage of docker containers"
msgstr "Использование памяти контейнерами Docker"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Имя"
@@ -632,19 +497,10 @@ msgstr "Сетевой трафик контейнеров Docker"
msgid "Network traffic of public interfaces"
msgstr "Сетевой трафик публичных интерфейсов"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr "Единицы измерения скорости сети"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Результаты не найдены."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr "Нет результатов."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "При каждом перезапуске системы в базе данных будут обновлены в соответствии с системами, определенными в файле."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Открыть меню"
@@ -682,12 +536,6 @@ msgstr "Перезаписать существующие оповещения"
msgid "Page"
msgstr "Страница"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr "Страница {0} из {1}"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Страницы / Настройки"
@@ -715,7 +563,7 @@ msgstr "Пауза"
#: src/components/systems-table/systems-table.tsx
msgid "Paused"
msgstr "Пауза"
msgstr "Приостановлено"
#: src/components/routes/settings/notifications.tsx
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Ключ"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Чтение"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Получено"
@@ -782,24 +631,10 @@ msgstr "Получено"
msgid "Reset Password"
msgstr "Сбросить пароль"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr "Завершено"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Возобновить"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "Обновить токен"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr "Строк на странице"
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Сохраните адрес, используя клавишу ввода или запятую. Оставьте пустым, чтобы отключить уведомления по электронной почте."
@@ -825,7 +660,8 @@ msgstr "Поиск систем или настроек..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Смотрите <0>настройки уведомлений</0>, чтобы настроить, как вы получаете оповещения."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Отправлено"
@@ -833,6 +669,7 @@ msgstr "Отправлено"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Устанавливает диапазон времени по умолчанию для графиков при просмотре системы."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "Настройки SMTP"
msgid "Sort By"
msgstr "Сортировать по"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr "Состояние"
#: src/lib/utils.ts
msgid "Status"
msgstr "Статус"
@@ -876,16 +708,10 @@ msgstr "Использование подкачки"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Система"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr "Средняя загрузка системы за время"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Системы"
@@ -908,10 +734,6 @@ msgstr "Темп"
msgid "Temperature"
msgstr "Температура"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr "Температура"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Температуры датчиков системы"
@@ -924,6 +746,14 @@ msgstr "Тест <0>URL</0>"
msgid "Test notification sent"
msgstr "Тестовое уведомление отправлено"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "Агент должен работать на системе для подключения. Скопируйте команду установки агента ниже."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "Агент должен работать на системе для подключения. Скопируйте <0>docker-compose.yml</0> для агента ниже."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Затем войдите в бэкенд и сбросьте пароль вашей учетной записи в таблице пользователей."
@@ -932,10 +762,6 @@ msgstr "Затем войдите в бэкенд и сбросьте парол
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Это действие не может быть отменено. Это навсегда удалит все текущие записи для {name} из базы данных."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr "Это навсегда удалит все выбранные записи из базы данных."
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Пропускная способность {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Переключить сетку"
msgid "Toggle theme"
msgstr "Переключить тему"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr "Токен"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "Токены и отпечатки"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr "Токены позволяют агентам подключаться и регистрироваться. Отпечатки являются постоянными идентификаторами, уникальными для каждой системы, которые создаются при первом подключении."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "Токены и отпечатки используются для аутентификации соединений WebSocket с хабом."
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr "Срабатывает, когда средняя загрузка за 1 минуту превышает порог"
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr "Срабатывает, когда средняя загрузка за 15 минут превышает порог"
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr "Срабатывает, когда средняя загрузка за 5 минут превышает порог"
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Срабатывает, когда любой датчик превышает порог"
@@ -1012,15 +807,6 @@ msgstr "Срабатывает, когда статус переключаетс
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Срабатывает, когда использование любого диска превышает порог"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr "Параметры единиц измерения"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "Универсальный токен"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "Время работы"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Использование"
@@ -1048,6 +833,7 @@ msgstr "Использование корневого раздела"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Использовано"
@@ -1056,18 +842,10 @@ msgstr "Использовано"
msgid "Users"
msgstr "Пользователи"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Значение"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Вид"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr "Просмотреть 200 последних оповещений."
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Видимые столбцы"
@@ -1084,19 +862,14 @@ msgstr "Хотите помочь нам улучшить наши перево
msgid "Webhook / Push notifications"
msgstr "Webhook / Push уведомления"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr "Если включено, этот токен позволяет агентам регистрироваться самостоятельно без предварительного создания системы. Истекает через час или при перезапуске хаба."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Команда Windows"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Запись"
@@ -1111,4 +884,3 @@ msgstr "YAML конфигурация"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Ваши настройки пользователя были обновлены."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: sl\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Slovenian\n"
"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dan} two {# dneva} few {# dni} other {# dni}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# ura} two {# uri} few {# ur} other {# ur}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# ura} two {# uri} few {# ur} other {# ur}}"
msgid "1 hour"
msgstr "1 ura"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 teden"
@@ -50,11 +39,6 @@ msgstr "1 teden"
msgid "12 hours"
msgstr "12 ur"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 ur"
@@ -63,22 +47,11 @@ msgstr "24 ur"
msgid "30 days"
msgstr "30 dni"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Dejanja"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktivna opozorila"
@@ -103,6 +76,9 @@ msgstr "Dodaj URL"
msgid "Adjust display options for charts."
msgstr "Prilagodi možnosti prikaza za grafikone."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Administrator"
msgid "Agent"
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Vsi sistemi"
msgid "Are you sure you want to delete {name}?"
msgstr "Ali ste prepričani, da želite izbrisati {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Za samodejno kopiranje je potreben varen kontekst."
@@ -188,22 +154,11 @@ msgstr "Beszel uporablja <0>Shoutrrr</0> za integracijo s priljubljenimi storitv
msgid "Binary"
msgstr "Binarno"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Predpomnilnik / medpomnilniki"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Prekliči"
@@ -211,14 +166,6 @@ msgstr "Prekliči"
msgid "Caution - potential data loss"
msgstr "Pozor - možna izguba podatkov"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Spremeni splošne možnosti aplikacije."
@@ -239,7 +186,7 @@ msgstr "Za več podrobnosti preverite dnevnike."
msgid "Check your notification service"
msgstr "Preverite storitev obveščanja"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Klikni za kopiranje"
@@ -257,12 +204,7 @@ msgstr "Nastavi način prejemanja opozorilnih obvestil."
msgid "Confirm password"
msgstr "Potrdite geslo"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Nadaljuj"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Kopirano v odložišče"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Kopiraj docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Kopiraj docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopiraj gostitelja"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopiraj Linux ukaz"
@@ -300,25 +234,13 @@ msgstr "Kopiraj Linux ukaz"
msgid "Copy text"
msgstr "Kopiraj besedilo"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU poraba"
@@ -326,11 +248,6 @@ msgstr "CPU poraba"
msgid "Create account"
msgstr "Ustvari račun"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Privzeto časovno obdobje"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Izbriši"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
@@ -362,10 +274,6 @@ msgstr "Disk"
msgid "Disk I/O"
msgstr "Disk I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Dokumentacija"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "Vnesite e-poštni naslov za ponastavitev gesla"
msgid "Enter email address..."
msgstr "Vnesite e-poštni naslov..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Napaka"
@@ -445,10 +346,6 @@ msgstr "Preseženo {0}{1} v zadnjih {2, plural, one {# minuti} other {# minutah}
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "Obstoječi sistemi, ki niso definirani v <0>config.yml</0>, bodo izbrisani. Prosimo, naredite redne varnostne kopije."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Izvozi nastavitve"
@@ -457,10 +354,6 @@ msgstr "Izvozi nastavitve"
msgid "Export your current systems configuration."
msgstr "Izvozi trenutne nastavitve sistema."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Preverjanje pristnosti ni uspelo"
@@ -480,14 +373,9 @@ msgstr "Opozorila ni bilo mogoče posodobiti"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "Za <0>{min}</0> {min, plural, one {minuto} other {minut}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Mreža"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Ukaz Homebrew"
@@ -546,27 +433,6 @@ msgstr "Postavitev"
msgid "Light"
msgstr "Svetlo"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Odjava"
@@ -615,7 +481,6 @@ msgstr "Poraba pomnilnika"
msgid "Memory usage of docker containers"
msgstr "Poraba pomnilnika docker kontejnerjev"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Naziv"
@@ -632,19 +497,10 @@ msgstr "Omrežni promet docker kontejnerjev"
msgid "Network traffic of public interfaces"
msgstr "Omrežni promet javnih vmesnikov"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Ni rezultatov."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "Ob vsakem ponovnem zagonu bodo sistemi v zbirki podatkov posodobljeni, da se bodo ujemali s sistemi, definiranimi v datoteki."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Odpri menu"
@@ -682,12 +536,6 @@ msgstr "Prepiši obstoječe alarme"
msgid "Page"
msgstr "Stran"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Strani / Nastavitve"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Javni ključ"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Preberano"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Prejeto"
@@ -782,24 +631,10 @@ msgstr "Prejeto"
msgid "Reset Password"
msgstr "Ponastavi geslo"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Nadaljuj"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Shranite naslov s tipko enter ali vejico. Pustite prazno, da onemogočite e-poštna obvestila."
@@ -825,7 +660,8 @@ msgstr "Iskanje sistemov ali nastavitev..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Glejte <0>nastavitve obvestil</0>, da nastavite način prejemanja opozoril."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Poslano"
@@ -833,6 +669,7 @@ msgstr "Poslano"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Nastavi privzeti časovni obseg za grafikone, ko si ogledujete sistem."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "SMTP nastavitve"
msgid "Sort By"
msgstr "Razvrsti po"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
@@ -876,16 +708,10 @@ msgstr "Swap uporaba"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Sistemsko"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Sistemi"
@@ -908,10 +734,6 @@ msgstr ""
msgid "Temperature"
msgstr "Temperatura"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperature sistemskih senzorjev"
@@ -924,6 +746,14 @@ msgstr "Preveri <0>URL</0>"
msgid "Test notification sent"
msgstr "Testno obvestilo je poslano"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "Za vzpostavitev povezave mora biti agent zagnan v sistemu. Kopirajte spodnji namestitveni ukaz za agenta."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "Za vzpostavitev povezave mora biti agent zagnan v sistemu. Kopirajte <0>docker-compose.yml</0> za spodnjega agenta."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Nato se prijavite v zaledni sistem in ponastavite geslo svojega uporabniškega računa v tabeli uporabnikov."
@@ -932,10 +762,6 @@ msgstr "Nato se prijavite v zaledni sistem in ponastavite geslo svojega uporabni
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Tega dejanja ni mogoče razveljaviti. To bo trajno izbrisalo vse trenutne zapise za {name} iz zbirke podatkov."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Prepustnost {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Preklopi način mreže"
msgid "Toggle theme"
msgstr "Obrni temo"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Sproži se, ko kateri koli senzor preseže prag"
@@ -1012,15 +807,6 @@ msgstr "Sproži se, ko se stanje preklaplja med gor in dol"
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Sproži se, ko uporaba katerega koli diska preseže prag"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "Čas delovanja"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Uporaba"
@@ -1048,6 +833,7 @@ msgstr "Uporaba korenske particije"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Uporabljeno"
@@ -1056,18 +842,10 @@ msgstr "Uporabljeno"
msgid "Users"
msgstr "Uporabniki"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Pogled"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Vidna polja"
@@ -1084,19 +862,14 @@ msgstr "Ali nam želite pomagati, da bomo naše prevode še izboljšali? Za več
msgid "Webhook / Push notifications"
msgstr "Webhook / potisna obvestila"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Ukaz Windows"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Pisanje"
@@ -1111,4 +884,3 @@ msgstr "YAML nastavitev"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Vaše uporabniške nastavitve so posodobljene."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: sv\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Swedish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# dag} other {# dagar}}"
#. 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 ""
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# timme} other {# timmar}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# timme} other {# timmar}}"
msgid "1 hour"
msgstr "1 timme"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr ""
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 vecka"
@@ -50,11 +39,6 @@ msgstr "1 vecka"
msgid "12 hours"
msgstr "12 timmar"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr ""
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 timmar"
@@ -63,22 +47,11 @@ msgstr "24 timmar"
msgid "30 days"
msgstr "30 dagar"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr ""
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Åtgärder"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr ""
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktiva larm"
@@ -103,6 +76,9 @@ msgstr "Lägg till URL"
msgid "Adjust display options for charts."
msgstr "Justera visningsalternativ för diagram."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Admin"
msgid "Agent"
msgstr "Agent"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr ""
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Alla system"
msgid "Are you sure you want to delete {name}?"
msgstr "Är du säker på att du vill ta bort {name}?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr ""
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Automatisk kopiering kräver en säker kontext."
@@ -188,22 +154,11 @@ msgstr "Beszel använder <0>Shoutrrr</0> för att integrera med populära aviser
msgid "Binary"
msgstr "Binär"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr ""
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr ""
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Cache / Buffertar"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "Avbryt"
@@ -211,14 +166,6 @@ msgstr "Avbryt"
msgid "Caution - potential data loss"
msgstr "Varning - potentiell dataförlust"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr ""
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Ändra allmänna programalternativ."
@@ -239,7 +186,7 @@ msgstr "Kontrollera loggarna för mer information."
msgid "Check your notification service"
msgstr "Kontrollera din aviseringstjänst"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Klicka för att kopiera"
@@ -257,12 +204,7 @@ msgstr "Konfigurera hur du tar emot larmaviseringar."
msgid "Confirm password"
msgstr "Bekräfta lösenord"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Fortsätt"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Kopierat till urklipp"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Kopiera docker compose"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Kopiera docker run"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Kopiera värd"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Kopiera Linux-kommando"
@@ -300,25 +234,13 @@ msgstr "Kopiera Linux-kommando"
msgid "Copy text"
msgstr "Kopiera text"
#: src/components/add-system.tsx
msgid "Copy the installation command for the agent below, or register agents automatically with a <0>universal token</0>."
msgstr ""
#: src/components/add-system.tsx
msgid "Copy the<0>docker-compose.yml</0> content for the agent below, or register agents automatically with a <1>universal token</1>."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU-användning"
@@ -326,11 +248,6 @@ msgstr "CPU-användning"
msgid "Create account"
msgstr "Skapa konto"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr ""
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Standardtidsperiod"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Ta bort"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
@@ -362,10 +274,6 @@ msgstr "Disk"
msgid "Disk I/O"
msgstr "Disk I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,16 +302,11 @@ msgstr "Dokumentation"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr ""
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
@@ -426,10 +329,8 @@ msgstr "Ange e-postadress för att återställa lösenord"
msgid "Enter email address..."
msgstr "Ange e-postadress..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Fel"
@@ -445,10 +346,6 @@ msgstr "Överskrider {0}{1} under de senaste {2, plural, one {# minuten} other {
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "Befintliga system som inte definieras i <0>config.yml</0> kommer att tas bort. Gör regelbundna säkerhetskopior."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr ""
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Exportera konfiguration"
@@ -457,10 +354,6 @@ msgstr "Exportera konfiguration"
msgid "Export your current systems configuration."
msgstr "Exportera din nuvarande systemkonfiguration."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr ""
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Autentisering misslyckades"
@@ -480,14 +373,9 @@ msgstr "Kunde inte uppdatera larm"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filtrera..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr ""
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "Under <0>{min}</0> {min, plural, one {minut} other {minuter}}"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Rutnät"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew-kommando"
@@ -546,27 +433,6 @@ msgstr "Layout"
msgid "Light"
msgstr "Ljust"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr ""
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr ""
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr ""
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Logga ut"
@@ -615,7 +481,6 @@ msgstr "Minnesanvändning"
msgid "Memory usage of docker containers"
msgstr "Minnesanvändning för dockercontainrar"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Namn"
@@ -632,19 +497,10 @@ msgstr "Nätverkstrafik för dockercontainrar"
msgid "Network traffic of public interfaces"
msgstr "Nätverkstrafik för publika gränssnitt"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr ""
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Inga resultat hittades."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr ""
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "Vid varje omstart kommer systemen i databasen att uppdateras för att matcha systemen som definieras i filen."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Öppna menyn"
@@ -682,12 +536,6 @@ msgstr "Skriv över befintliga larm"
msgid "Page"
msgstr "Sida"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr ""
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Sidor / Inställningar"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Offentlig nyckel"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Läs"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Mottaget"
@@ -782,24 +631,10 @@ msgstr "Mottaget"
msgid "Reset Password"
msgstr "Återställ lösenord"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Återuppta"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr ""
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr ""
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Spara adressen med Enter-tangenten eller komma. Lämna tomt för att inaktivera e-postaviseringar."
@@ -825,7 +660,8 @@ msgstr "Sök efter system eller inställningar..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Se <0>aviseringsinställningar</0> för att konfigurera hur du tar emot larm."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Skickat"
@@ -833,6 +669,7 @@ msgstr "Skickat"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Anger standardtidsintervallet för diagram när ett system visas."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "SMTP-inställningar"
msgid "Sort By"
msgstr "Sortera efter"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr ""
#: src/lib/utils.ts
msgid "Status"
msgstr "Status"
@@ -876,16 +708,10 @@ msgstr "Swap-användning"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "System"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr ""
#: src/components/navbar.tsx
msgid "Systems"
msgstr "System"
@@ -908,10 +734,6 @@ msgstr ""
msgid "Temperature"
msgstr "Temperatur"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr ""
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Temperaturer för systemsensorer"
@@ -924,6 +746,14 @@ msgstr "Testa <0>URL</0>"
msgid "Test notification sent"
msgstr "Testavisering skickad"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "Agenten måste köras på systemet för att ansluta. Kopiera installationskommandot för agenten nedan."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "Agenten måste köras på systemet för att ansluta. Kopiera <0>docker-compose.yml</0> för agenten nedan."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Logga sedan in på backend och återställ ditt användarkontos lösenord i användartabellen."
@@ -932,10 +762,6 @@ msgstr "Logga sedan in på backend och återställ ditt användarkontos lösenor
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Den här åtgärden kan inte ångras. Detta kommer permanent att ta bort alla aktuella poster för {name} från databasen."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr ""
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "Genomströmning av {extraFsName}"
@@ -957,37 +783,6 @@ msgstr "Växla rutnät"
msgid "Toggle theme"
msgstr "Växla tema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr ""
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Utlöses när någon sensor överskrider ett tröskelvärde"
@@ -1012,15 +807,6 @@ msgstr "Utlöses när status växlar mellan upp och ner"
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Utlöses när användningen av någon disk överskrider ett tröskelvärde"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr ""
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr ""
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
@@ -1037,8 +823,7 @@ msgstr "Drifttid"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Användning"
@@ -1048,6 +833,7 @@ msgstr "Användning av rotpartitionen"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Använt"
@@ -1056,18 +842,10 @@ msgstr "Använt"
msgid "Users"
msgstr "Användare"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Visa"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Synliga fält"
@@ -1084,19 +862,14 @@ msgstr "Vill du hjälpa oss att göra våra översättningar ännu bättre? Koll
msgid "Webhook / Push notifications"
msgstr "Webhook / Push-aviseringar"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation. Expires after one hour or on hub restart."
msgstr ""
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows-kommando"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Skriv"
@@ -1111,4 +884,3 @@ msgstr "YAML-konfiguration"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Dina användarinställningar har uppdaterats."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: tr\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 23:54\n"
"PO-Revision-Date: 2025-03-06 07:27\n"
"Last-Translator: \n"
"Language-Team: Turkish\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -23,12 +23,6 @@ msgstr ""
msgid "{0, plural, one {# day} other {# days}}"
msgstr "{0, plural, one {# gün} other {# gü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 "{1} satırdan {0} tanesi seçildi."
#: src/components/routes/system.tsx
msgid "{hours, plural, one {# hour} other {# hours}}"
msgstr "{hours, plural, one {# saat} other {# saat}}"
@@ -37,11 +31,6 @@ msgstr "{hours, plural, one {# saat} other {# saat}}"
msgid "1 hour"
msgstr "1 saat"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr "1 dk"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1 hafta"
@@ -50,11 +39,6 @@ msgstr "1 hafta"
msgid "12 hours"
msgstr "12 saat"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr "15 dk"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24 saat"
@@ -63,22 +47,11 @@ msgstr "24 saat"
msgid "30 days"
msgstr "30 gün"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr "5 dk"
#. Table column
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Actions"
msgstr "Eylemler"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Active"
msgstr "Aktif"
#: src/components/routes/home.tsx
msgid "Active Alerts"
msgstr "Aktif Uyarılar"
@@ -103,6 +76,9 @@ msgstr "URL Ekle"
msgid "Adjust display options for charts."
msgstr "Grafikler için görüntüleme seçeneklerini ayarlayın."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
msgid "Admin"
@@ -112,12 +88,6 @@ msgstr "Yönetici"
msgid "Agent"
msgstr "Aracı"
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Alert History"
msgstr "Uyarı Geçmişi"
#: src/components/alerts/alert-button.tsx
#: src/components/alerts/alert-button.tsx
msgid "Alerts"
@@ -132,10 +102,6 @@ msgstr "Tüm Sistemler"
msgid "Are you sure you want to delete {name}?"
msgstr "{name} silmek istediğinizden emin misiniz?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
msgstr "Emin misiniz?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Otomatik kopyalama güvenli bir bağlam gerektirir."
@@ -188,22 +154,11 @@ msgstr "Beszel, popüler bildirim hizmetleriyle entegre olmak için <0>Shoutrrr<
msgid "Binary"
msgstr "İkili"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bits (Kbps, Mbps, Gbps)"
msgstr "Bit (Kbps, Mbps, Gbps)"
#: src/components/routes/settings/general.tsx
#: src/components/routes/settings/general.tsx
msgid "Bytes (KB/s, MB/s, GB/s)"
msgstr "Bayt (KB/s, MB/s, GB/s)"
#: src/components/charts/mem-chart.tsx
msgid "Cache / Buffers"
msgstr "Önbellek / Tamponlar"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Cancel"
msgstr "İptal"
@@ -211,14 +166,6 @@ msgstr "İptal"
msgid "Caution - potential data loss"
msgstr "Dikkat - potansiyel veri kaybı"
#: src/components/routes/settings/general.tsx
msgid "Celsius (°C)"
msgstr "Santigrat (°C)"
#: src/components/routes/settings/general.tsx
msgid "Change display units for metrics."
msgstr "Metrikler için görüntüleme birimlerini değiştirin."
#: src/components/routes/settings/general.tsx
msgid "Change general application options."
msgstr "Genel uygulama seçeneklerini değiştirin."
@@ -239,7 +186,7 @@ msgstr "Daha fazla ayrıntı için günlükleri kontrol edin."
msgid "Check your notification service"
msgstr "Bildirim hizmetinizi kontrol edin"
#: src/components/ui/input-copy.tsx
#: src/components/add-system.tsx
msgid "Click to copy"
msgstr "Kopyalamak için tıklayın"
@@ -257,12 +204,7 @@ msgstr "Uyarı bildirimlerini nasıl alacağınızı yapılandırın."
msgid "Confirm password"
msgstr "Şifreyi onayla"
#: src/components/routes/home.tsx
msgid "Connection is down"
msgstr "Bağlantı kesildi"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Continue"
msgstr "Devam et"
@@ -271,28 +213,20 @@ msgid "Copied to clipboard"
msgstr "Panoya kopyalandı"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker compose file content"
msgid "Copy docker compose"
msgstr "Docker compose kopyala"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy docker run command"
msgid "Copy docker run"
msgstr "Docker run kopyala"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Environment variables"
msgid "Copy env"
msgstr "Ortam değişkenlerini kopyala"
#: src/components/systems-table/systems-table.tsx
msgid "Copy host"
msgstr "Ana bilgisayarı kopyala"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy Linux command"
msgstr "Linux komutunu kopyala"
@@ -300,25 +234,13 @@ msgstr "Linux komutunu kopyala"
msgid "Copy text"
msgstr "Metni kopyala"
#: 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 "Aşağıdaki agent için kurulum komutunu kopyalayın veya <0>evrensel token</0> ile agentları otomatik olarak kaydedin."
#: 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 "Aşağıdaki agent için <0>docker-compose.yml</0> içeriğini kopyalayın veya <1>evrensel token</1> ile agentları otomatik olarak kaydedin."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "YAML'ı kopyala"
#: src/components/systems-table/systems-table.tsx
msgid "CPU"
msgstr "CPU"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "CPU Usage"
msgstr "CPU Kullanımı"
@@ -326,11 +248,6 @@ msgstr "CPU Kullanımı"
msgid "Create account"
msgstr "Hesap oluştur"
#. Context: date created
#: src/components/alerts-history-columns.tsx
msgid "Created"
msgstr "Oluşturuldu"
#. Dark theme
#: src/components/mode-toggle.tsx
msgid "Dark"
@@ -346,14 +263,9 @@ msgid "Default time period"
msgstr "Varsayılan zaman dilimi"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Delete"
msgstr "Sil"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "Parmak izini sil"
#: src/components/systems-table/systems-table.tsx
msgid "Disk"
msgstr "Disk"
@@ -362,10 +274,6 @@ msgstr "Disk"
msgid "Disk I/O"
msgstr "Disk G/Ç"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
msgstr "Disk birimi"
#: src/lib/utils.ts
#: src/components/routes/system.tsx
#: src/components/charts/disk-chart.tsx
@@ -394,20 +302,15 @@ msgstr "Dokümantasyon"
#. Context: System is down
#: src/lib/utils.ts
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Down"
msgstr "Kapalı"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
msgstr "Süre"
msgstr ""
#: src/components/add-system.tsx
#: src/components/systems-table/systems-table.tsx
msgid "Edit"
msgstr "Düzenle"
msgstr ""
#: src/components/login/forgot-pass-form.tsx
#: src/components/login/auth-form.tsx
@@ -426,10 +329,8 @@ msgstr "Şifreyi sıfırlamak için e-posta adresini girin"
msgid "Enter email address..."
msgstr "E-posta adresini girin..."
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/notifications.tsx
#: src/components/routes/settings/config-yaml.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/login/auth-form.tsx
msgid "Error"
msgstr "Hata"
@@ -445,10 +346,6 @@ msgstr "Son {2, plural, one {# dakika} other {# dakika}} içinde {0}{1} aşıyor
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
msgstr "<0>config.yml</0> içinde tanımlanmayan mevcut sistemler silinecektir. Lütfen düzenli yedekler alın."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr "Dışa aktar"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Yapılandırmayı dışa aktar"
@@ -457,10 +354,6 @@ msgstr "Yapılandırmayı dışa aktar"
msgid "Export your current systems configuration."
msgstr "Mevcut sistem yapılandırmanızı dışa aktarın."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
msgstr "Fahrenhayt (°F)"
#: src/lib/utils.ts
msgid "Failed to authenticate"
msgstr "Kimlik doğrulama başarısız"
@@ -480,14 +373,9 @@ msgstr "Uyarı güncellenemedi"
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Filter..."
msgstr "Filtrele..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr "Parmak izi"
#: src/components/alerts/alerts-system.tsx
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
msgstr "<0>{min}</0> {min, plural, one {dakika} other {dakika}} için"
@@ -511,7 +399,6 @@ msgid "Grid"
msgstr "Izgara"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Homebrew command"
msgstr "Homebrew komutu"
@@ -546,27 +433,6 @@ msgstr "Düzen"
msgid "Light"
msgstr "Açık"
#: src/components/routes/system.tsx
msgid "Load Average"
msgstr "Yük Ortalaması"
#: src/lib/utils.ts
msgid "Load Average 15m"
msgstr "Yük Ortalaması 15d"
#: src/lib/utils.ts
msgid "Load Average 1m"
msgstr "Yük Ortalaması 1d"
#: src/lib/utils.ts
msgid "Load Average 5m"
msgstr "Yük Ortalaması 5d"
#. Short label for load average
#: src/components/systems-table/systems-table.tsx
msgid "Load Avg"
msgstr "Yük Ort."
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Çıkış Yap"
@@ -595,7 +461,7 @@ msgstr "Görüntüleme ve bildirim tercihlerini yönetin."
#: src/components/add-system.tsx
msgid "Manual setup instructions"
msgstr "Manuel kurulum talimatları"
msgstr ""
#. Chart select field. Please try to keep this short.
#: src/components/routes/system.tsx
@@ -615,7 +481,6 @@ msgstr "Bellek Kullanımı"
msgid "Memory usage of docker containers"
msgstr "Docker konteynerlerinin bellek kullanımı"
#: src/components/alerts-history-columns.tsx
#: src/components/add-system.tsx
msgid "Name"
msgstr "Ad"
@@ -632,19 +497,10 @@ msgstr "Docker konteynerlerinin ağ trafiği"
msgid "Network traffic of public interfaces"
msgstr "Genel arayüzlerin ağ trafiği"
#. Context: Bytes or bits
#: src/components/routes/settings/general.tsx
msgid "Network unit"
msgstr "Ağ birimi"
#: src/components/command-palette.tsx
msgid "No results found."
msgstr "Sonuç bulunamadı."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "No results."
msgstr "Sonuç yok."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
@@ -665,8 +521,6 @@ msgid "On each restart, systems in the database will be updated to match the sys
msgstr "Her yeniden başlatmada, veritabanındaki sistemler dosyada tanımlanan sistemlerle eşleşecek şekilde güncellenecektir."
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Open menu"
msgstr "Menüyü aç"
@@ -682,12 +536,6 @@ msgstr "Mevcut uyarıların üzerine yaz"
msgid "Page"
msgstr "Sayfa"
#. placeholder {0}: table.getState().pagination.pageIndex + 1
#. placeholder {1}: table.getPageCount()
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Page {0} of {1}"
msgstr "Sayfa {0} / {1}"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "Sayfalar / Ayarlar"
@@ -703,7 +551,7 @@ msgstr "Şifre en az 8 karakter olmalıdır."
#: src/components/login/auth-form.tsx
msgid "Password must be less than 72 bytes."
msgstr "Parola 72 bayttan küçük olmalıdır."
msgstr ""
#: src/components/login/forgot-pass-form.tsx
msgid "Password reset request received"
@@ -769,12 +617,13 @@ msgid "Public Key"
msgstr "Genel Anahtar"
#. Disk read
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Read"
msgstr "Oku"
#: src/components/routes/system.tsx
#. Network bytes received (download)
#: src/components/charts/area-chart.tsx
msgid "Received"
msgstr "Alındı"
@@ -782,24 +631,10 @@ msgstr "Alındı"
msgid "Reset Password"
msgstr "Şifreyi Sıfırla"
#: src/components/alerts-history-columns.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Resolved"
msgstr "Çözüldü"
#: src/components/systems-table/systems-table.tsx
msgid "Resume"
msgstr "Devam et"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "Token'ı döndür"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
msgstr "Sayfa başına satır"
#: src/components/routes/settings/notifications.tsx
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
msgstr "Adresleri enter tuşu veya virgül ile kaydedin. E-posta bildirimlerini devre dışı bırakmak için boş bırakın."
@@ -811,7 +646,7 @@ msgstr "Ayarları Kaydet"
#: src/components/add-system.tsx
msgid "Save system"
msgstr "Sistemi kaydet"
msgstr ""
#: src/components/navbar.tsx
msgid "Search"
@@ -825,7 +660,8 @@ msgstr "Sistemler veya ayarlar için ara..."
msgid "See <0>notification settings</0> to configure how you receive alerts."
msgstr "Uyarıları nasıl alacağınızı yapılandırmak için <0>bildirim ayarlarını</0> inceleyin."
#: src/components/routes/system.tsx
#. Network bytes sent (upload)
#: src/components/charts/area-chart.tsx
msgid "Sent"
msgstr "Gönderildi"
@@ -833,6 +669,7 @@ msgstr "Gönderildi"
msgid "Sets the default time range for charts when a system is viewed."
msgstr "Bir sistem görüntülendiğinde grafikler için varsayılan zaman aralığını ayarlar."
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -856,11 +693,6 @@ msgstr "SMTP ayarları"
msgid "Sort By"
msgstr "Sıralama Ölçütü"
#. Context: alert state (active or resolved)
#: src/components/alerts-history-columns.tsx
msgid "State"
msgstr "Durum"
#: src/lib/utils.ts
msgid "Status"
msgstr "Durum"
@@ -876,16 +708,10 @@ msgstr "Takas Kullanımı"
#. System theme
#: src/lib/utils.ts
#: src/components/mode-toggle.tsx
#: src/components/alerts-history-columns.tsx
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "System"
msgstr "Sistem"
#: src/components/routes/system.tsx
msgid "System load averages over time"
msgstr "Zaman içindeki sistem yükü ortalamaları"
#: src/components/navbar.tsx
msgid "Systems"
msgstr "Sistemler"
@@ -901,17 +727,13 @@ msgstr "Tablo"
#. Temperature label in systems table
#: src/components/systems-table/systems-table.tsx
msgid "Temp"
msgstr "Sıc"
msgstr ""
#: src/lib/utils.ts
#: src/components/routes/system.tsx
msgid "Temperature"
msgstr "Sıcaklık"
#: src/components/routes/settings/general.tsx
msgid "Temperature unit"
msgstr "Sıcaklık birimi"
#: src/components/routes/system.tsx
msgid "Temperatures of system sensors"
msgstr "Sistem sensörlerinin sıcaklıkları"
@@ -924,6 +746,14 @@ msgstr "Test <0>URL</0>"
msgid "Test notification sent"
msgstr "Test bildirimi gönderildi"
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
msgstr "Bağlanmak için aracının sistemde çalışıyor olması gerekir. Aşağıdaki aracı kurulum komutunu kopyalayın."
#: src/components/add-system.tsx
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
msgstr "Bağlanmak için aracının sistemde çalışıyor olması gerekir. Aşağıdaki <0>docker-compose.yml</0> dosyasını kopyalayın."
#: src/components/login/forgot-pass-form.tsx
msgid "Then log into the backend and reset your user account password in the users table."
msgstr "Ardından arka uca giriş yapın ve kullanıcılar tablosunda kullanıcı hesabı şifrenizi sıfırlayın."
@@ -932,10 +762,6 @@ msgstr "Ardından arka uca giriş yapın ve kullanıcılar tablosunda kullanıc
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr "Bu işlem geri alınamaz. Bu, veritabanından {name} için tüm mevcut kayıtları kalıcı olarak silecektir."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
msgstr "Bu, seçilen tüm kayıtları veritabanından kalıcı olarak silecektir."
#: src/components/routes/system.tsx
msgid "Throughput of {extraFsName}"
msgstr "{extraFsName} verimliliği"
@@ -957,37 +783,6 @@ msgstr "Izgarayı değiştir"
msgid "Toggle theme"
msgstr "Temayı değiştir"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Token"
msgstr ""
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
#: src/components/routes/settings/layout.tsx
msgid "Tokens & Fingerprints"
msgstr "Token'lar ve Parmak İzleri"
#: 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 "Token'lar agentların bağlanıp kaydolmasına izin verir. Parmak izleri her sisteme özgü kararlı tanımlayıcılardır ve ilk bağlantıda ayarlanır."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "Token'lar ve parmak izleri hub'a WebSocket bağlantılarını doğrulamak için kullanılır."
#: src/lib/utils.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr "1 dakikalık yük ortalaması bir eşiği aştığında tetiklenir"
#: src/lib/utils.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr "15 dakikalık yük ortalaması bir eşiği aştığında tetiklenir"
#: src/lib/utils.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr "5 dakikalık yük ortalaması bir eşiği aştığında tetiklenir"
#: src/lib/utils.ts
msgid "Triggers when any sensor exceeds a threshold"
msgstr "Herhangi bir sensör bir eşiği aştığında tetiklenir"
@@ -1012,20 +807,11 @@ msgstr "Durum yukarı ve aşağı arasında değiştiğinde tetiklenir"
msgid "Triggers when usage of any disk exceeds a threshold"
msgstr "Herhangi bir diskin kullanımı bir eşiği aştığında tetiklenir"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr "Birim tercihleri"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Universal token"
msgstr "Evrensel token"
#. Context: System is up
#: src/components/systems-table/systems-table.tsx
#: src/components/routes/system.tsx
msgid "Up"
msgstr "ık"
msgstr ""
#: src/components/systems-table/systems-table.tsx
msgid "Updated in real time. Click on a system to view information."
@@ -1037,8 +823,7 @@ msgstr "Çalışma Süresi"
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
msgid "Usage"
msgstr "Kullanım"
@@ -1048,6 +833,7 @@ msgstr "Kök bölümün kullanımı"
#: src/components/charts/swap-chart.tsx
#: src/components/charts/mem-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Used"
msgstr "Kullanıldı"
@@ -1056,18 +842,10 @@ msgstr "Kullanıldı"
msgid "Users"
msgstr "Kullanıcılar"
#: src/components/alerts-history-columns.tsx
msgid "Value"
msgstr "Değer"
#: src/components/systems-table/systems-table.tsx
msgid "View"
msgstr "Görüntüle"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "View your 200 most recent alerts."
msgstr "En son 200 uyarınızı görüntüleyin."
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Görünür Alanlar"
@@ -1084,19 +862,14 @@ msgstr "Çevirilerimizi daha iyi hale getirmemize yardımcı olmak ister misiniz
msgid "Webhook / Push notifications"
msgstr "Webhook / Anlık bildirimler"
#: 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 "Etkinleştirildiğinde, bu token agentların önceden sistem oluşturmadan kendilerini kaydetmelerine izin verir. Bir saat sonra veya hub yeniden başlatıldığında sona erer."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgctxt "Button to copy install command"
msgid "Windows command"
msgstr "Windows komutu"
#. Disk write
#: src/components/routes/system.tsx
#: src/components/routes/system.tsx
#: src/components/charts/area-chart.tsx
#: src/components/charts/area-chart.tsx
msgid "Write"
msgstr "Yaz"
@@ -1111,4 +884,3 @@ msgstr "YAML Yapılandırması"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."
msgstr "Kullanıcı ayarlarınız güncellendi."

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