mirror of
https://github.com/henrygd/beszel.git
synced 2025-11-25 06:26:09 +00:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
233349fb2a | ||
|
|
c54e6ff0ea | ||
|
|
98c4102f72 | ||
|
|
640ee7a88e | ||
|
|
8a85246a0b | ||
|
|
655bfc95ca | ||
|
|
37a066e6bd | ||
|
|
9e959a6b7b | ||
|
|
2b6560b9e1 | ||
|
|
d8836d53bf | ||
|
|
aa15876aa2 | ||
|
|
7ca960b521 | ||
|
|
4eaedcf825 | ||
|
|
b337ba1d7f | ||
|
|
c9b72f724f | ||
|
|
35d8996e00 | ||
|
|
6e61c5f1e4 | ||
|
|
6bb147c349 | ||
|
|
3668aa4e8e | ||
|
|
4c324bff73 | ||
|
|
741575df15 | ||
|
|
055fc39305 | ||
|
|
5ae3a38204 | ||
|
|
44747e75b0 | ||
|
|
e4f22ebb01 | ||
|
|
bfb848a1ec | ||
|
|
c16c7830a4 | ||
|
|
8f383c9f5e | ||
|
|
5b68556a9a | ||
|
|
cb1c481f54 | ||
|
|
a93ff63605 | ||
|
|
856683610a | ||
|
|
b9fda9dd0b | ||
|
|
7e27fee006 | ||
|
|
f65d19ad84 | ||
|
|
94f771fc1c | ||
|
|
0ac3d20162 | ||
|
|
df0f3a154f | ||
|
|
6419178d87 | ||
|
|
91714ba0e6 | ||
|
|
b5ba5054a5 | ||
|
|
6f38077ca0 | ||
|
|
7f82aafff9 | ||
|
|
14a4715eb8 | ||
|
|
e4f1936698 | ||
|
|
4f62a07da6 | ||
|
|
1a1fcebc46 | ||
|
|
f9f7db17d4 | ||
|
|
929d94f705 | ||
|
|
2c4ea6f52a | ||
|
|
3505b215a2 | ||
|
|
8827996553 | ||
|
|
556a6b49db | ||
|
|
180ec83a17 | ||
|
|
062796b38c | ||
|
|
67f88188e1 | ||
|
|
3209c53201 | ||
|
|
ec7aa80928 | ||
|
|
f6e391f8a9 | ||
|
|
e64fad9584 | ||
|
|
9e6ee8d239 | ||
|
|
2c66f93101 | ||
|
|
5c2e2d7d36 | ||
|
|
376e8d4621 | ||
|
|
ec7cb53d93 | ||
|
|
b7176fc8f3 | ||
|
|
f8fc74116c | ||
|
|
4094df3a61 | ||
|
|
a5f9e2615c | ||
|
|
4a78ce1b16 | ||
|
|
f8f1e01cb4 | ||
|
|
c7463f2b9f | ||
|
|
a975466fc7 | ||
|
|
539c0ccb1d |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -11,3 +11,7 @@ dist
|
||||
beszel/cmd/hub/hub
|
||||
beszel/cmd/agent/agent
|
||||
node_modules
|
||||
beszel/build
|
||||
*timestamp*
|
||||
.swc
|
||||
beszel/site/src/locales/**/*.ts
|
||||
35
beszel/Makefile
Normal file
35
beszel/Makefile
Normal file
@@ -0,0 +1,35 @@
|
||||
# Default OS/ARCH values
|
||||
OS ?= $(shell go env GOOS)
|
||||
ARCH ?= $(shell go env GOARCH)
|
||||
# Skip building the web UI if true
|
||||
SKIP_WEB ?= false
|
||||
|
||||
.PHONY: tidy build-agent build-hub build clean lint
|
||||
.DEFAULT_GOAL := build
|
||||
|
||||
tidy:
|
||||
go mod tidy
|
||||
|
||||
build-web-ui:
|
||||
@if command -v bun >/dev/null 2>&1; then \
|
||||
bun install --cwd ./site && \
|
||||
bun run --cwd ./site build; \
|
||||
else \
|
||||
npm install --prefix ./site && \
|
||||
npm run --prefix ./site build; \
|
||||
fi
|
||||
|
||||
build-agent: tidy
|
||||
CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o ./build/beszel-agent_$(OS)_$(ARCH) -ldflags "-w -s" beszel/cmd/agent
|
||||
|
||||
build-hub: tidy $(if $(filter false,$(SKIP_WEB)),build-web-ui)
|
||||
CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o ./build/beszel_$(OS)_$(ARCH) -ldflags "-w -s" beszel/cmd/hub
|
||||
|
||||
build: build-agent build-hub
|
||||
|
||||
clean:
|
||||
go clean
|
||||
rm -rf ./build
|
||||
|
||||
lint:
|
||||
golangci-lint run
|
||||
@@ -9,43 +9,44 @@ require (
|
||||
github.com/goccy/go-json v0.10.3
|
||||
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61
|
||||
github.com/pocketbase/dbx v1.10.1
|
||||
github.com/pocketbase/pocketbase v0.22.22
|
||||
github.com/pocketbase/pocketbase v0.22.23
|
||||
github.com/rhysd/go-github-selfupdate v1.2.3
|
||||
github.com/shirou/gopsutil/v4 v4.24.9
|
||||
github.com/shirou/gopsutil/v4 v4.24.10
|
||||
github.com/spf13/cast v1.7.0
|
||||
github.com/spf13/cobra v1.8.1
|
||||
golang.org/x/crypto v0.28.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7 // indirect
|
||||
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.32.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.41 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.42 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 // indirect
|
||||
github.com/aws/smithy-go v1.22.0 // 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.0 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/ebitengine/purego v0.8.1 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.6 // indirect
|
||||
github.com/ganigeorgiev/fexpr v0.4.1 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
@@ -72,7 +73,7 @@ require (
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/tcnksm/go-gitconfig v0.1.2 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||
github.com/tklauser/numcpus v0.9.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
@@ -89,8 +90,8 @@ require (
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||
google.golang.org/api v0.201.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
|
||||
google.golang.org/api v0.204.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||
google.golang.org/grpc v1.67.1 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852 // indirect
|
||||
|
||||
101
beszel/go.sum
101
beszel/go.sum
@@ -1,10 +1,10 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE=
|
||||
cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
|
||||
cloud.google.com/go/auth v0.9.8 h1:+CSJ0Gw9iVeSENVCKJoLHhdUykDgXSc4Qn+gu2BRtR8=
|
||||
cloud.google.com/go/auth v0.9.8/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
|
||||
cloud.google.com/go/auth v0.10.0 h1:tWlkvFAh+wwTOzXIjrwM64karR1iTBZ/GRr0S/DULYo=
|
||||
cloud.google.com/go/auth v0.10.0/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.5 h1:2p29+dePqsCHPP1bqDJcKj4qxRyYCcbzKpFyKGt3MTk=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.5/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8=
|
||||
cloud.google.com/go/compute v1.14.0 h1:hfm2+FfxVmnRlh6LpB7cg1ZNU+5edAHmW679JePztk0=
|
||||
cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
|
||||
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
|
||||
@@ -26,42 +26,42 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/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.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.3 h1:T0dRlFBKcdaUPGNtkBSwHZxrtis8CQU17UpNBZYd0wk=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.3/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 h1:pT3hpW0cOHRJx8Y0DfJUEQuqPild8jRGmSFmBgvydr0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6/go.mod h1:j/I2++U0xX+cr44QjHay4Cvxj6FUbnxrgmqN3H1jTZA=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.0 h1:FosVYWcqEtWNxHn8gB/Vs6jOlNwSoyOCA/g/sxyySOQ=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.0/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0gizGINCOWxSLY9W8=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 h1:TMH3f/SCAWdNtXXVPPu5D6wrr4G5hI1rAxbcocKfC7Q=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33 h1:X+4YY5kZRI/cOoSMVMGTqFXHAMg1bvvay7IBcqHpybQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33/go.mod h1:DPynzu+cn92k5UQ6tZhX+wfTB4ah6QDU/NgdHqatmvk=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.1 h1:oxIvOUXy8x0U3fR//0eq+RdCKimWI900+SV+10xsCBw=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.1/go.mod h1:bRQcttQJiARbd5JZxw6wG0yIK3eLeSCPdg6uqmmlIiI=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.42 h1:sBP0RPjBU4neGpIYyx8mkU2QqLPl5u9cmdTWVzIpHkM=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.42/go.mod h1:FwZBfU530dJ26rv9saAbxa9Ej3eF/AK0OAY86k13n4M=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 h1:68jFVtt3NulEzojFesM/WVarlFpCaXLKaBxDpzkQ9OQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18/go.mod h1:Fjnn5jQVIo6VyedMc0/EhPpfNlPl7dHV916O6B+49aE=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.35 h1:ihPPdcCVSN0IvBByXwqVp28/l4VosBZ6sDulcvU2J7w=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.35/go.mod h1:JkgEhs3SVF51Dj3m1Bj+yL8IznpxzkwlA3jLg3x7Kls=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 h1:Jw50LwEkVjuVzE1NzkhNKkBf9cRN7MtE1F/b2cOKTUM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22/go.mod h1:Y/SmAyPcOTmpeVaWSzSKiILfXTVJwrGmYZhcRbhWuEY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 h1:981MHwBaRZM7+9QSR6XamDzF/o7ouUGxFzr+nVSIhrs=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22/go.mod h1:1RA1+aBEfn+CAB/Mh0MB6LsdCYCnjZm7tKXtnk499ZQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21 h1:7edmS3VOBDhK00b/MwGtGglCm7hhwNYnjJs/PgFdMQE=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21/go.mod h1:Q9o5h4HoIWG8XfzxqiuK/CGUbepCJ8uTlaE3bAbxytQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.22 h1:yV+hCAHZZYJQcwAaszoBNwLbPItHvApxT0kVIw6jRgs=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.22/go.mod h1:kbR1TL8llqB1eGnVbybcA4/wgScxdylOdyAd51yxPdw=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2 h1:4FMHqLfk0efmTqhXVRL5xYRqlEBNBiRI7N6w4jsEdd4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2/go.mod h1:LWoqeWlK9OZeJxsROW2RqrSPvQHKTpp69r/iDjwsSaw=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 h1:s7NA1SOw8q/5c0wr8477yOPp0z+uBaXBnLE0XYb0POA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 h1:t7iUP9+4wdc5lt3E41huP+GvQZJD38WLsgVp4iOtAjg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2/go.mod h1:/niFCtmuQNxqx9v8WAPq5qh7EH25U4BF6tjoyq9bObM=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0 h1:xA6XhTF7PE89BCNHJbQi8VvPzcgMtmGC5dr8S8N7lHk=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0/go.mod h1:cB6oAuus7YXRZhWCc1wIwPywwZ1XwweNp2TVAEGYeB8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 h1:bSYXVyUzoTHoKalBmwaZxs97HU9DWWI3ehHSAMa7xOk=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 h1:AhmO1fHINP9vFYUE0LHzCWg/LfUWUF+zFPEcY9QXb7o=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2/go.mod h1:o8aQygT2+MVP0NaV6kbdE1YnnIM8RRVQzoeUH45GOdI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 h1:CiS7i0+FUe+/YY1GvIBLLrR/XNGZ4CtM1Ll0XavNuVo=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.3 h1:kT6BcZsmMtNkP/iYMcRG+mIEA/IbeiUimXtGmqF39y0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.3/go.mod h1:Z8uGua2k4PPaGOYn66pK02rhMrot3Xk3tpBuUFPomZU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 h1:qcxX0JYlgWH3hpPUnd6U0ikcl6LLA9sLkXE2w1fpMvY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3/go.mod h1:cLSNEmI45soc+Ef8K/L+8sEA3A3pYFEYf5B5UI+6bH4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.3 h1:ZC7Y/XgKUxwqcdhO5LE8P6oGP1eh6xlQReWNKfhvJno=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.3/go.mod h1:WqfO7M9l9yUAw0HcHaikwRd/H6gzYdz7vjejCA5e2oY=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2 h1:p9TNFL8bFUMd+38YIpTAXpoxyz0MxC7FlbFEH4P4E1U=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2/go.mod h1:fNjyo0Coen9QTwQLWeV6WO2Nytwiu+cCcWaTdKCAqqE=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 h1:UTpsIf0loCIWEbrqdLb+0RxnTXfWh2vhw4nQmFi4nPc=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.3/go.mod h1:FZ9j3PFHHAR+w0BSEjK955w5YD2UwB/l/H0yAK3MJvI=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 h1:2YCmIXv3tmiItw0LlYf6v7gEHebLY45kBEnPezbUKyU=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3/go.mod h1:u19stRyNPxGhj6dRm+Cdgu6N75qnbW7+QN0q0dsAk58=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 h1:wVnQ6tigGsRqSWDEEyH6lSAJ9OyFUsSnbaUWChuSGzs=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.32.3/go.mod h1:VZa9yTFyj4o10YGsmDO4gbQJUvvhY72fhumT8W4LqsE=
|
||||
github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM=
|
||||
github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
@@ -84,14 +84,14 @@ github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCO
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE=
|
||||
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE=
|
||||
github.com/ebitengine/purego v0.8.1/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.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
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=
|
||||
@@ -217,8 +217,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pocketbase/dbx v1.10.1 h1:cw+vsyfCJD8YObOVeqb93YErnlxwYMkNZ4rwN0G0AaA=
|
||||
github.com/pocketbase/dbx v1.10.1/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
|
||||
github.com/pocketbase/pocketbase v0.22.22 h1:iA128U+cmM9euxPpuCN7blmQ2FZNzOix2aUUcnbbQu8=
|
||||
github.com/pocketbase/pocketbase v0.22.22/go.mod h1:u+l7T04g7eBXetoodXLch3WoV/QonRf1qYq+2vuTKuI=
|
||||
github.com/pocketbase/pocketbase v0.22.23 h1:cnjSiBcMf7VIhXmoBmZCAV8qKYkOubHCOQQPZMKFBAk=
|
||||
github.com/pocketbase/pocketbase v0.22.23/go.mod h1:h2ojT2pqBWH9LLl1aiawkwXiICKtzZA/kjM/8VhydR4=
|
||||
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=
|
||||
@@ -229,8 +229,8 @@ 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.24.9 h1:KIV+/HaHD5ka5f570RZq+2SaeFsb/pq+fp2DGNWYoOI=
|
||||
github.com/shirou/gopsutil/v4 v4.24.9/go.mod h1:3fkaHNeYsUFCGZ8+9vZVWtbyM1k2eRnlL+bWO8Bxa/Q=
|
||||
github.com/shirou/gopsutil/v4 v4.24.10 h1:7VOzPtfw/5YDU+jLEoBwXwxJbQetULywoSV4RYY7HkM=
|
||||
github.com/shirou/gopsutil/v4 v4.24.10/go.mod h1:s4D/wg+ag4rG0WO7AiTj2BeYCRhym0vM7DHbZRxnIT8=
|
||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
@@ -251,8 +251,8 @@ github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPg
|
||||
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.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
||||
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
|
||||
github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
|
||||
github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI=
|
||||
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=
|
||||
@@ -364,8 +364,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
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.201.0 h1:+7AD9JNM3tREtawRMu8sOjSbb8VYcYXJG/2eEOmfDu0=
|
||||
google.golang.org/api v0.201.0/go.mod h1:HVY0FCHVs89xIW9fzf/pBvOEm+OolHa86G/txFezyq4=
|
||||
google.golang.org/api v0.204.0 h1:3PjmQQEDkR/ENVZZwIYB4W/KzYtN8OrqnNcHWpeR8E4=
|
||||
google.golang.org/api v0.204.0/go.mod h1:69y8QSoKIbL9F94bWgWAq6wGqGwyjBgi2y8rAK8zLag=
|
||||
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=
|
||||
@@ -373,12 +373,12 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID
|
||||
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-20241007155032-5fefd90f89a9 h1:nFS3IivktIU5Mk6KQa+v6RKkHUpdQpphqGNLxqNnbEk=
|
||||
google.golang.org/genproto v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:tEzYTYZxbmVNOu0OAFH9HzdJtLn6h4Aj89zzlBCdHms=
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||
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=
|
||||
@@ -398,6 +398,7 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
|
||||
@@ -62,7 +62,9 @@ func (a *Agent) Run(pubKey []byte, addr string) {
|
||||
if sensors, exists := os.LookupEnv("SENSORS"); exists {
|
||||
a.sensorsWhitelist = make(map[string]struct{})
|
||||
for _, sensor := range strings.Split(sensors, ",") {
|
||||
a.sensorsWhitelist[sensor] = struct{}{}
|
||||
if sensor != "" {
|
||||
a.sensorsWhitelist[sensor] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,11 +41,20 @@ func (a *Agent) initializeDiskInfo() {
|
||||
if _, exists := a.fsStats[key]; !exists {
|
||||
if root {
|
||||
slog.Info("Detected root device", "name", key)
|
||||
// check if root device is in /proc/diskstats, use fallback if not
|
||||
// Check if root device is in /proc/diskstats, use fallback if not
|
||||
if _, exists := diskIoCounters[key]; !exists {
|
||||
slog.Warn("Device not found in diskstats", "name", key)
|
||||
key = findFallbackIoDevice(filesystem, diskIoCounters, a.fsStats)
|
||||
slog.Info("Using I/O fallback", "name", key)
|
||||
slog.Info("Using I/O fallback", "device", device, "mountpoint", mountpoint, "fallback", key)
|
||||
}
|
||||
} else {
|
||||
// Check if non-root has diskstats and fall back to folder name if not
|
||||
// Scenario: device is encrypted and named luks-2bcb02be-999d-4417-8d18-5c61e660fb6e - not in /proc/diskstats.
|
||||
// However, the device can be specified by mounting folder from luks device at /extra-filesystems/sda1
|
||||
if _, exists := diskIoCounters[key]; !exists {
|
||||
efBase := filepath.Base(mountpoint)
|
||||
if _, exists := diskIoCounters[efBase]; exists {
|
||||
key = efBase
|
||||
}
|
||||
}
|
||||
}
|
||||
a.fsStats[key] = &system.FsStats{Root: root, Mountpoint: mountpoint}
|
||||
@@ -114,7 +123,7 @@ func (a *Agent) initializeDiskInfo() {
|
||||
mountpoint := filepath.Join(efPath, folder.Name())
|
||||
slog.Debug("/extra-filesystems", "mountpoint", mountpoint)
|
||||
if !existingMountpoints[mountpoint] {
|
||||
a.fsStats[folder.Name()] = &system.FsStats{Mountpoint: mountpoint}
|
||||
addFsStat(folder.Name(), mountpoint, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,8 @@ func (dm *dockerManager) getDockerStats() ([]*container.Stats, error) {
|
||||
clear(dm.validIds)
|
||||
}
|
||||
|
||||
var failedContainters []container.ApiInfo
|
||||
|
||||
for _, ctr := range *dm.apiContainerList {
|
||||
ctr.IdShort = ctr.Id[:12]
|
||||
dm.validIds[ctr.IdShort] = struct{}{}
|
||||
@@ -74,18 +76,33 @@ func (dm *dockerManager) getDockerStats() ([]*container.Stats, error) {
|
||||
defer dm.dequeue()
|
||||
err := dm.updateContainerStats(ctr)
|
||||
if err != nil {
|
||||
dm.deleteContainerStatsSync(ctr.IdShort)
|
||||
// retry once
|
||||
err = dm.updateContainerStats(ctr)
|
||||
if err != nil {
|
||||
slog.Error("Error getting container stats", "err", err)
|
||||
}
|
||||
dm.containerStatsMutex.Lock()
|
||||
delete(dm.containerStatsMap, ctr.IdShort)
|
||||
failedContainters = append(failedContainters, ctr)
|
||||
dm.containerStatsMutex.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
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))
|
||||
// time.Sleep(time.Millisecond * 1100)
|
||||
for _, ctr := range failedContainters {
|
||||
dm.wg.Add(1)
|
||||
go func() {
|
||||
defer dm.wg.Done()
|
||||
err = dm.updateContainerStats(ctr)
|
||||
if err != nil {
|
||||
slog.Error("Error getting container stats", "err", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
dm.wg.Wait()
|
||||
}
|
||||
|
||||
// populate final stats and remove old / invalid container stats
|
||||
stats := make([]*container.Stats, 0, containersLength)
|
||||
for id, v := range dm.containerStatsMap {
|
||||
|
||||
@@ -171,33 +171,36 @@ func (a *Agent) getSystemStats() system.Stats {
|
||||
}
|
||||
}
|
||||
|
||||
// temperatures
|
||||
temps, err := sensors.TemperaturesWithContext(a.sensorsContext)
|
||||
if err != nil {
|
||||
// err.(*sensors.Warnings).Verbose = true
|
||||
slog.Debug("Sensor error", "err", err)
|
||||
}
|
||||
slog.Debug("Temperature", "sensors", temps)
|
||||
if len(temps) > 0 {
|
||||
systemStats.Temperatures = make(map[string]float64, len(temps))
|
||||
for i, sensor := range temps {
|
||||
// skip if temperature is 0
|
||||
if sensor.Temperature <= 0 || sensor.Temperature >= 200 {
|
||||
continue
|
||||
}
|
||||
if _, ok := systemStats.Temperatures[sensor.SensorKey]; ok {
|
||||
// if key already exists, append int to key
|
||||
systemStats.Temperatures[sensor.SensorKey+"_"+strconv.Itoa(i)] = twoDecimals(sensor.Temperature)
|
||||
} else {
|
||||
systemStats.Temperatures[sensor.SensorKey] = twoDecimals(sensor.Temperature)
|
||||
}
|
||||
// temperatures (skip if sensors whitelist is set to empty string)
|
||||
if a.sensorsWhitelist != nil && len(a.sensorsWhitelist) == 0 {
|
||||
slog.Debug("Skipping temperature collection")
|
||||
} else {
|
||||
temps, err := sensors.TemperaturesWithContext(a.sensorsContext)
|
||||
if err != nil {
|
||||
slog.Debug("Sensor error", "err", err)
|
||||
}
|
||||
// remove sensors from systemStats if whitelist exists and sensor is not in whitelist
|
||||
// (do this here instead of in initial loop so we have correct keys if int was appended)
|
||||
if a.sensorsWhitelist != nil {
|
||||
for key := range systemStats.Temperatures {
|
||||
if _, nameInWhitelist := a.sensorsWhitelist[key]; !nameInWhitelist {
|
||||
delete(systemStats.Temperatures, key)
|
||||
slog.Debug("Temperature", "sensors", temps)
|
||||
if len(temps) > 0 {
|
||||
systemStats.Temperatures = make(map[string]float64, len(temps))
|
||||
for i, sensor := range temps {
|
||||
// skip if temperature is 0
|
||||
if sensor.Temperature <= 0 || sensor.Temperature >= 200 {
|
||||
continue
|
||||
}
|
||||
if _, ok := systemStats.Temperatures[sensor.SensorKey]; ok {
|
||||
// if key already exists, append int to key
|
||||
systemStats.Temperatures[sensor.SensorKey+"_"+strconv.Itoa(i)] = twoDecimals(sensor.Temperature)
|
||||
} else {
|
||||
systemStats.Temperatures[sensor.SensorKey] = twoDecimals(sensor.Temperature)
|
||||
}
|
||||
}
|
||||
// remove sensors from systemStats if whitelist exists and sensor is not in whitelist
|
||||
// (do this here instead of in initial loop so we have correct keys if int was appended)
|
||||
if a.sensorsWhitelist != nil {
|
||||
for key := range systemStats.Temperatures {
|
||||
if _, nameInWhitelist := a.sensorsWhitelist[key]; !nameInWhitelist {
|
||||
delete(systemStats.Temperatures, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
222
beszel/internal/hub/config.go
Normal file
222
beszel/internal/hub/config.go
Normal file
@@ -0,0 +1,222 @@
|
||||
package hub
|
||||
|
||||
import (
|
||||
"beszel/internal/entities/system"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/labstack/echo/v5"
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/apis"
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
"github.com/spf13/cast"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Systems []SystemConfig `yaml:"systems"`
|
||||
}
|
||||
|
||||
type SystemConfig struct {
|
||||
Name string `yaml:"name"`
|
||||
Host string `yaml:"host"`
|
||||
Port uint16 `yaml:"port"`
|
||||
Users []string `yaml:"users"`
|
||||
}
|
||||
|
||||
// Syncs systems with the config.yml file
|
||||
func (h *Hub) syncSystemsWithConfig() error {
|
||||
configPath := filepath.Join(h.app.DataDir(), "config.yml")
|
||||
configData, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var config Config
|
||||
err = yaml.Unmarshal(configData, &config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse config.yml: %v", err)
|
||||
}
|
||||
|
||||
if len(config.Systems) == 0 {
|
||||
log.Println("No systems defined in config.yml.")
|
||||
return nil
|
||||
}
|
||||
|
||||
var firstUser *models.Record
|
||||
|
||||
// Create a map of email to user ID
|
||||
userEmailToID := make(map[string]string)
|
||||
users, err := h.app.Dao().FindRecordsByExpr("users", dbx.NewExp("id != ''"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(users) > 0 {
|
||||
firstUser = users[0]
|
||||
for _, user := range users {
|
||||
userEmailToID[user.GetString("email")] = user.Id
|
||||
}
|
||||
}
|
||||
|
||||
// add default settings for systems if not defined in config
|
||||
for i := range config.Systems {
|
||||
system := &config.Systems[i]
|
||||
if system.Port == 0 {
|
||||
system.Port = 45876
|
||||
}
|
||||
if len(users) > 0 && len(system.Users) == 0 {
|
||||
// default to first user if none are defined
|
||||
system.Users = []string{firstUser.Id}
|
||||
} else {
|
||||
// Convert email addresses to user IDs
|
||||
userIDs := make([]string, 0, len(system.Users))
|
||||
for _, email := range system.Users {
|
||||
if id, ok := userEmailToID[email]; ok {
|
||||
userIDs = append(userIDs, id)
|
||||
} else {
|
||||
log.Printf("User %s not found", email)
|
||||
}
|
||||
}
|
||||
system.Users = userIDs
|
||||
}
|
||||
}
|
||||
|
||||
// Get existing systems
|
||||
existingSystems, err := h.app.Dao().FindRecordsByExpr("systems", dbx.NewExp("id != ''"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a map of existing systems for easy lookup
|
||||
existingSystemsMap := make(map[string]*models.Record)
|
||||
for _, system := range existingSystems {
|
||||
key := 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))
|
||||
if existingSystem, ok := existingSystemsMap[key]; ok {
|
||||
// Update existing system
|
||||
existingSystem.Set("name", sysConfig.Name)
|
||||
existingSystem.Set("users", sysConfig.Users)
|
||||
existingSystem.Set("port", sysConfig.Port)
|
||||
if err := h.app.Dao().SaveRecord(existingSystem); err != nil {
|
||||
return err
|
||||
}
|
||||
delete(existingSystemsMap, key)
|
||||
} else {
|
||||
// Create new system
|
||||
systemsCollection, err := h.app.Dao().FindCollectionByNameOrId("systems")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find systems collection: %v", err)
|
||||
}
|
||||
newSystem := models.NewRecord(systemsCollection)
|
||||
newSystem.Set("name", sysConfig.Name)
|
||||
newSystem.Set("host", sysConfig.Host)
|
||||
newSystem.Set("port", sysConfig.Port)
|
||||
newSystem.Set("users", sysConfig.Users)
|
||||
newSystem.Set("info", system.Info{})
|
||||
newSystem.Set("status", "pending")
|
||||
if err := h.app.Dao().SaveRecord(newSystem); err != nil {
|
||||
return fmt.Errorf("failed to create new system: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete systems not in config
|
||||
for _, system := range existingSystemsMap {
|
||||
if err := h.app.Dao().DeleteRecord(system); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Systems synced with config.yml")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generates content for the config.yml file as a YAML string
|
||||
func (h *Hub) generateConfigYAML() (string, error) {
|
||||
// Fetch all systems from the database
|
||||
systems, err := h.app.Dao().FindRecordsByFilter("systems", "id != ''", "name", -1, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Create a Config struct to hold the data
|
||||
config := Config{
|
||||
Systems: make([]SystemConfig, 0, len(systems)),
|
||||
}
|
||||
|
||||
// Fetch all users at once
|
||||
allUserIDs := make([]string, 0)
|
||||
for _, system := range systems {
|
||||
allUserIDs = append(allUserIDs, system.GetStringSlice("users")...)
|
||||
}
|
||||
userEmailMap, err := h.getUserEmailMap(allUserIDs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Populate the Config struct with system data
|
||||
for _, system := range systems {
|
||||
userIDs := system.GetStringSlice("users")
|
||||
userEmails := make([]string, 0, len(userIDs))
|
||||
for _, userID := range userIDs {
|
||||
if email, ok := userEmailMap[userID]; ok {
|
||||
userEmails = append(userEmails, email)
|
||||
}
|
||||
}
|
||||
|
||||
sysConfig := SystemConfig{
|
||||
Name: system.GetString("name"),
|
||||
Host: system.GetString("host"),
|
||||
Port: cast.ToUint16(system.Get("port")),
|
||||
Users: userEmails,
|
||||
}
|
||||
config.Systems = append(config.Systems, sysConfig)
|
||||
}
|
||||
|
||||
// Marshal the Config struct to YAML
|
||||
yamlData, err := yaml.Marshal(&config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Add a header to the YAML
|
||||
yamlData = append([]byte("# Values for port and users are optional.\n# Defaults are port 45876 and the first created user.\n\n"), yamlData...)
|
||||
|
||||
return string(yamlData), nil
|
||||
}
|
||||
|
||||
// New helper function to get a map of user IDs to emails
|
||||
func (h *Hub) getUserEmailMap(userIDs []string) (map[string]string, error) {
|
||||
users, err := h.app.Dao().FindRecordsByIds("users", userIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userEmailMap := make(map[string]string, len(users))
|
||||
for _, user := range users {
|
||||
userEmailMap[user.Id] = user.GetString("email")
|
||||
}
|
||||
|
||||
return userEmailMap, nil
|
||||
}
|
||||
|
||||
// Returns the current config.yml file as a JSON object
|
||||
func (h *Hub) getYamlConfig(c echo.Context) error {
|
||||
requestData := apis.RequestInfo(c)
|
||||
if requestData.AuthRecord == nil || requestData.AuthRecord.GetString("role") != "admin" {
|
||||
return apis.NewForbiddenError("Forbidden", nil)
|
||||
}
|
||||
configContent, err := h.generateConfigYAML()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.JSON(200, map[string]string{"config": configContent})
|
||||
}
|
||||
@@ -42,6 +42,8 @@ type Hub struct {
|
||||
am *alerts.AlertManager
|
||||
um *users.UserManager
|
||||
rm *records.RecordManager
|
||||
systemStats *models.Collection
|
||||
containerStats *models.Collection
|
||||
}
|
||||
|
||||
func NewHub(app *pocketbase.PocketBase) *Hub {
|
||||
@@ -56,14 +58,10 @@ func NewHub(app *pocketbase.PocketBase) *Hub {
|
||||
}
|
||||
|
||||
func (h *Hub) Run() {
|
||||
// rm := records.NewRecordManager(h.app)
|
||||
// am := alerts.NewAlertManager(h.app)
|
||||
// um := users.NewUserManager(h.app)
|
||||
|
||||
// loosely check if it was executed using "go run"
|
||||
isGoRun := strings.HasPrefix(os.Args[0], os.TempDir())
|
||||
|
||||
// // enable auto creation of migration files when making collection changes in the Admin UI
|
||||
// enable auto creation of migration files when making collection changes in the Admin UI
|
||||
migratecmd.MustRegister(h.app, h.app.RootCmd, migratecmd.Config{
|
||||
// (the isGoRun check is to enable it only during development)
|
||||
Automigrate: isGoRun,
|
||||
@@ -93,7 +91,8 @@ func (h *Hub) Run() {
|
||||
if err := h.app.Dao().SaveCollection(usersCollection); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
// sync systems with config
|
||||
return h.syncSystemsWithConfig()
|
||||
})
|
||||
|
||||
// serve web ui
|
||||
@@ -128,7 +127,11 @@ func (h *Hub) Run() {
|
||||
// delete old records once every hour
|
||||
scheduler.MustAdd("delete old records", "8 * * * *", h.rm.DeleteOldRecords)
|
||||
// create longer records every 10 minutes
|
||||
scheduler.MustAdd("create longer records", "*/10 * * * *", h.rm.CreateLongerRecords)
|
||||
scheduler.MustAdd("create longer records", "*/10 * * * *", func() {
|
||||
if systemStats, containerStats, err := h.getCollections(); err == nil {
|
||||
h.rm.CreateLongerRecords([]*models.Collection{systemStats, containerStats})
|
||||
}
|
||||
})
|
||||
scheduler.Start()
|
||||
return nil
|
||||
})
|
||||
@@ -153,6 +156,8 @@ func (h *Hub) Run() {
|
||||
})
|
||||
// send test notification
|
||||
e.Router.GET("/api/beszel/send-test-notification", h.am.SendTestNotification)
|
||||
// API endpoint to get config.yml content
|
||||
e.Router.GET("/api/beszel/config-yaml", h.getYamlConfig)
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -289,37 +294,61 @@ func (h *Hub) updateSystem(record *models.Record) {
|
||||
return
|
||||
}
|
||||
// update system record
|
||||
dao := h.app.Dao()
|
||||
record.Set("status", "up")
|
||||
record.Set("info", systemData.Info)
|
||||
if err := h.app.Dao().SaveRecord(record); err != nil {
|
||||
if err := dao.SaveRecord(record); err != nil {
|
||||
h.app.Logger().Error("Failed to update record: ", "err", err.Error())
|
||||
}
|
||||
// add new system_stats record
|
||||
system_stats, _ := h.app.Dao().FindCollectionByNameOrId("system_stats")
|
||||
systemStatsRecord := models.NewRecord(system_stats)
|
||||
systemStatsRecord.Set("system", record.Id)
|
||||
systemStatsRecord.Set("stats", systemData.Stats)
|
||||
systemStatsRecord.Set("type", "1m")
|
||||
if err := h.app.Dao().SaveRecord(systemStatsRecord); err != nil {
|
||||
h.app.Logger().Error("Failed to save record: ", "err", err.Error())
|
||||
}
|
||||
// add new container_stats record
|
||||
if len(systemData.Containers) > 0 {
|
||||
container_stats, _ := h.app.Dao().FindCollectionByNameOrId("container_stats")
|
||||
containerStatsRecord := models.NewRecord(container_stats)
|
||||
containerStatsRecord.Set("system", record.Id)
|
||||
containerStatsRecord.Set("stats", systemData.Containers)
|
||||
containerStatsRecord.Set("type", "1m")
|
||||
if err := h.app.Dao().SaveRecord(containerStatsRecord); err != nil {
|
||||
// add system_stats and container_stats records
|
||||
if systemStats, containerStats, err := h.getCollections(); err != nil {
|
||||
h.app.Logger().Error("Failed to get collections: ", "err", err.Error())
|
||||
} else {
|
||||
// add new system_stats record
|
||||
systemStatsRecord := models.NewRecord(systemStats)
|
||||
systemStatsRecord.Set("system", record.Id)
|
||||
systemStatsRecord.Set("stats", systemData.Stats)
|
||||
systemStatsRecord.Set("type", "1m")
|
||||
if err := dao.SaveRecord(systemStatsRecord); err != nil {
|
||||
h.app.Logger().Error("Failed to save record: ", "err", err.Error())
|
||||
}
|
||||
// add new container_stats record
|
||||
if len(systemData.Containers) > 0 {
|
||||
containerStatsRecord := models.NewRecord(containerStats)
|
||||
containerStatsRecord.Set("system", record.Id)
|
||||
containerStatsRecord.Set("stats", systemData.Containers)
|
||||
containerStatsRecord.Set("type", "1m")
|
||||
if err := dao.SaveRecord(containerStatsRecord); err != nil {
|
||||
h.app.Logger().Error("Failed to save record: ", "err", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// system info alerts (todo: extra fs alerts)
|
||||
if err := h.am.HandleSystemAlerts(record, systemData.Info, systemData.Stats.Temperatures, systemData.Stats.ExtraFs); err != nil {
|
||||
h.app.Logger().Error("System alerts error", "err", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// return system_stats and container_stats collections
|
||||
func (h *Hub) getCollections() (*models.Collection, *models.Collection, error) {
|
||||
if h.systemStats == nil {
|
||||
systemStats, err := h.app.Dao().FindCollectionByNameOrId("system_stats")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
h.systemStats = systemStats
|
||||
}
|
||||
if h.containerStats == nil {
|
||||
containerStats, err := h.app.Dao().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 *models.Record, status string) {
|
||||
if record.GetString("status") != status {
|
||||
|
||||
@@ -32,7 +32,7 @@ type RecordDeletionData struct {
|
||||
retention time.Duration
|
||||
}
|
||||
|
||||
type RecordStats []*struct {
|
||||
type RecordStats []struct {
|
||||
Stats []byte `db:"stats"`
|
||||
}
|
||||
|
||||
@@ -41,9 +41,9 @@ func NewRecordManager(app *pocketbase.PocketBase) *RecordManager {
|
||||
}
|
||||
|
||||
// Create longer records by averaging shorter records
|
||||
func (rm *RecordManager) CreateLongerRecords() {
|
||||
func (rm *RecordManager) CreateLongerRecords(collections []*models.Collection) {
|
||||
// start := time.Now()
|
||||
recordData := []LongerRecordData{
|
||||
longerRecordData := []LongerRecordData{
|
||||
{
|
||||
shorterType: "1m",
|
||||
// change to 9 from 10 to allow edge case timing or short pauses
|
||||
@@ -78,17 +78,11 @@ func (rm *RecordManager) CreateLongerRecords() {
|
||||
return err
|
||||
}
|
||||
|
||||
// need *models.Collection to create a new record with models.NewRecord
|
||||
collections := map[string]*models.Collection{}
|
||||
for _, collectionName := range []string{"system_stats", "container_stats"} {
|
||||
collection, _ := txDao.FindCollectionByNameOrId(collectionName)
|
||||
collections[collectionName] = collection
|
||||
}
|
||||
|
||||
// loop through all active systems, time periods, and collections
|
||||
for _, system := range activeSystems {
|
||||
// log.Println("processing system", system.GetString("name"))
|
||||
for _, recordData := range recordData {
|
||||
for i := range longerRecordData {
|
||||
recordData := longerRecordData[i]
|
||||
// log.Println("processing longer record type", recordData.longerType)
|
||||
// add one minute padding for longer records because they are created slightly later than the job start time
|
||||
longerRecordPeriod := time.Now().UTC().Add(recordData.longerTimeDuration + time.Minute)
|
||||
@@ -112,14 +106,6 @@ func (rm *RecordManager) CreateLongerRecords() {
|
||||
// get shorter records from the past x minutes
|
||||
var stats RecordStats
|
||||
|
||||
// allShorterRecords, err := txDao.FindRecordsByExpr(
|
||||
// collection,
|
||||
// dbx.NewExp(
|
||||
// "type = {:type} AND system = {:system} AND created > {:created}",
|
||||
// dbx.Params{"type": recordData.shorterType, "system": system.Id, "created": shorterRecordPeriod},
|
||||
// ),
|
||||
// )
|
||||
|
||||
err := txDao.DB().
|
||||
Select("stats").
|
||||
From(collection.Name).
|
||||
@@ -173,8 +159,8 @@ func (rm *RecordManager) AverageSystemStats(records RecordStats) system.Stats {
|
||||
tempCount := float64(0)
|
||||
|
||||
var stats system.Stats
|
||||
for _, record := range records {
|
||||
json.Unmarshal(record.Stats, &stats)
|
||||
for i := range records {
|
||||
json.Unmarshal(records[i].Stats, &stats)
|
||||
sum.Cpu += stats.Cpu
|
||||
sum.Mem += stats.Mem
|
||||
sum.MemUsed += stats.MemUsed
|
||||
@@ -276,13 +262,14 @@ func (rm *RecordManager) AverageContainerStats(records RecordStats) []container.
|
||||
count := float64(len(records))
|
||||
|
||||
var containerStats []container.Stats
|
||||
for _, record := range records {
|
||||
for i := range records {
|
||||
// Reset the slice length to 0, but keep the capacity
|
||||
containerStats = containerStats[:0]
|
||||
if err := json.Unmarshal(record.Stats, &containerStats); err != nil {
|
||||
if err := json.Unmarshal(records[i].Stats, &containerStats); err != nil {
|
||||
return []container.Stats{}
|
||||
}
|
||||
for _, stat := range containerStats {
|
||||
for i := range containerStats {
|
||||
stat := containerStats[i]
|
||||
if _, ok := sums[stat.Name]; !ok {
|
||||
sums[stat.Name] = &container.Stats{Name: stat.Name}
|
||||
}
|
||||
|
||||
8
beszel/site/.prettierrc
Normal file
8
beszel/site/.prettierrc
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"useTabs": true,
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"singleQuote": false,
|
||||
"printWidth": 120
|
||||
}
|
||||
Binary file not shown.
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "default",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "src/index.css",
|
||||
"baseColor": "gray",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils"
|
||||
}
|
||||
}
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "default",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "src/index.css",
|
||||
"baseColor": "gray",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg" />
|
||||
|
||||
15
beszel/site/lingui.config.ts
Normal file
15
beszel/site/lingui.config.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { LinguiConfig } from "@lingui/conf"
|
||||
|
||||
const config: LinguiConfig = {
|
||||
locales: ["en", "ar", "de", "es", "fr", "it", "ja", "ko", "pt", "tr", "ru", "uk", "vi", "zh-CN", "zh-HK"],
|
||||
sourceLocale: "en",
|
||||
compileNamespace: "ts",
|
||||
catalogs: [
|
||||
{
|
||||
path: "<rootDir>/src/locales/{locale}/{locale}",
|
||||
include: ["src"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default config
|
||||
3356
beszel/site/package-lock.json
generated
3356
beszel/site/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,16 +5,22 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
"build": "lingui extract --overwrite && lingui compile && vite build",
|
||||
"preview": "vite preview",
|
||||
"sync": "lingui extract --overwrite && lingui compile",
|
||||
"sync_and_purge": "lingui extract --overwrite --clean && lingui compile"
|
||||
},
|
||||
"dependencies": {
|
||||
"@henrygd/queue": "^1.0.7",
|
||||
"@lingui/detect-locale": "^4.13.0",
|
||||
"@lingui/macro": "^4.13.0",
|
||||
"@lingui/react": "^4.13.0",
|
||||
"@nanostores/react": "^0.7.3",
|
||||
"@nanostores/router": "^0.11.0",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.2",
|
||||
"@radix-ui/react-checkbox": "^1.1.2",
|
||||
"@radix-ui/react-dialog": "^1.1.2",
|
||||
"@radix-ui/react-direction": "^1.1.0",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
"@radix-ui/react-select": "^2.1.2",
|
||||
@@ -26,7 +32,6 @@
|
||||
"@radix-ui/react-toast": "^1.2.2",
|
||||
"@radix-ui/react-tooltip": "^1.1.3",
|
||||
"@tanstack/react-table": "^8.20.5",
|
||||
"@vitejs/plugin-react": "^4.3.2",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.0",
|
||||
@@ -42,12 +47,17 @@
|
||||
"valibot": "^0.36.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lingui/cli": "^4.13.0",
|
||||
"@lingui/swc-plugin": "^4.1.0",
|
||||
"@lingui/vite-plugin": "^4.13.0",
|
||||
"@types/bun": "^1.1.11",
|
||||
"@types/react": "^18.3.11",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@vitejs/plugin-react-swc": "^3.7.1",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"postcss": "^8.4.47",
|
||||
"tailwindcss": "^3.4.14",
|
||||
"tailwindcss-rtl": "^0.9.0",
|
||||
"typescript": "^5.6.3",
|
||||
"vite": "^5.4.9"
|
||||
},
|
||||
@@ -55,5 +65,8 @@
|
||||
"@nanostores/router": {
|
||||
"nanostores": "^0.11.3"
|
||||
}
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/linux-arm64": "^0.21.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -7,17 +7,19 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@/components/ui/dialog'
|
||||
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '@/components/ui/tooltip'
|
||||
} from "@/components/ui/dialog"
|
||||
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { $publicKey, pb } from '@/lib/stores'
|
||||
import { Copy, PlusIcon } from 'lucide-react'
|
||||
import { useState, useRef, MutableRefObject } from 'react'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { cn, copyToClipboard, isReadOnlyUser } from '@/lib/utils'
|
||||
import { navigate } from './router'
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { $publicKey, pb } from "@/lib/stores"
|
||||
import { Copy, PlusIcon } from "lucide-react"
|
||||
import { useState, useRef, MutableRefObject } from "react"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { cn, copyToClipboard, isReadOnlyUser } from "@/lib/utils"
|
||||
import { navigate } from "./router"
|
||||
import { Trans } from "@lingui/macro"
|
||||
|
||||
export function AddSystemButton({ className }: { className?: string }) {
|
||||
const [open, setOpen] = useState(false)
|
||||
@@ -37,8 +39,13 @@ export function AddSystemButton({ className }: { className?: string }) {
|
||||
# - /mnt/disk1/.beszel:/extra-filesystems/disk1:ro
|
||||
environment:
|
||||
PORT: ${port}
|
||||
KEY: "${publicKey}"
|
||||
# FILESYSTEM: /dev/sda1 # override the root partition / device for disk I/O stats`)
|
||||
KEY: "${publicKey}"`)
|
||||
}
|
||||
|
||||
function copyInstallCommand(port: string) {
|
||||
copyToClipboard(
|
||||
`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}"`
|
||||
)
|
||||
}
|
||||
|
||||
async function handleSubmit(e: SubmitEvent) {
|
||||
@@ -48,8 +55,8 @@ export function AddSystemButton({ className }: { className?: string }) {
|
||||
data.users = pb.authStore.model!.id
|
||||
try {
|
||||
setOpen(false)
|
||||
await pb.collection('systems').create(data)
|
||||
navigate('/')
|
||||
await pb.collection("systems").create(data)
|
||||
navigate("/")
|
||||
// console.log(record)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
@@ -61,88 +68,119 @@ export function AddSystemButton({ className }: { className?: string }) {
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className={cn('flex gap-1 max-xs:h-[2.4rem]', className, isReadOnlyUser() && 'hidden')}
|
||||
className={cn("flex gap-1 max-xs:h-[2.4rem]", className, isReadOnlyUser() && "hidden")}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4 -ml-1" />
|
||||
Add <span className="hidden xs:inline">System</span>
|
||||
<PlusIcon className="h-4 w-4 -ms-1" />
|
||||
<Trans>
|
||||
Add <span className="hidden sm:inline">System</span>
|
||||
</Trans>
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="w-[90%] sm:max-w-[425px] rounded-lg">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="mb-2">Add New System</DialogTitle>
|
||||
<DialogDescription>
|
||||
The agent must be running on the system to connect. Copy the{' '}
|
||||
<code className="bg-muted px-1 rounded-sm">docker-compose.yml</code> for the agent
|
||||
below.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<form onSubmit={handleSubmit as any}>
|
||||
<div className="grid gap-3 mt-1 mb-4">
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<Label htmlFor="name" className="text-right">
|
||||
Name
|
||||
</Label>
|
||||
<Input id="name" name="name" className="col-span-3" required />
|
||||
<DialogContent className="w-[90%] sm:max-w-[440px] rounded-lg">
|
||||
<Tabs defaultValue="docker">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="mb-2">
|
||||
<Trans>Add New System</Trans>
|
||||
</DialogTitle>
|
||||
<TabsList className="grid w-full grid-cols-2">
|
||||
<TabsTrigger value="docker">Docker</TabsTrigger>
|
||||
<TabsTrigger value="binary">
|
||||
<Trans>Binary</Trans>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</DialogHeader>
|
||||
{/* Docker */}
|
||||
<TabsContent value="docker">
|
||||
<DialogDescription className="mb-4 leading-normal">
|
||||
<Trans>
|
||||
The agent must be running on the system to connect. Copy the
|
||||
<code className="bg-muted px-1 rounded-sm leading-3">docker-compose.yml</code> for the agent below.
|
||||
</Trans>
|
||||
</DialogDescription>
|
||||
</TabsContent>
|
||||
{/* Binary */}
|
||||
<TabsContent value="binary">
|
||||
<DialogDescription className="mb-4 leading-normal">
|
||||
<Trans>
|
||||
The agent must be running on the system to connect. Copy the installation command for the agent below.
|
||||
</Trans>
|
||||
</DialogDescription>
|
||||
</TabsContent>
|
||||
<form onSubmit={handleSubmit as any}>
|
||||
<div className="grid gap-3 mt-1 mb-4">
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<Label htmlFor="name" className="text-end">
|
||||
<Trans>Name</Trans>
|
||||
</Label>
|
||||
<Input id="name" name="name" className="col-span-3" required />
|
||||
</div>
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<Label htmlFor="host" className="text-end">
|
||||
<Trans>Host / IP</Trans>
|
||||
</Label>
|
||||
<Input id="host" name="host" className="col-span-3" required />
|
||||
</div>
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<Label htmlFor="port" className="text-end">
|
||||
<Trans>Port</Trans>
|
||||
</Label>
|
||||
<Input ref={port} name="port" id="port" defaultValue="45876" className="col-span-3" required />
|
||||
</div>
|
||||
<div className="grid grid-cols-4 items-center gap-4 relative">
|
||||
<Label htmlFor="pkey" className="text-end whitespace-pre">
|
||||
<Trans comment="Use 'Key' if your language requires many more characters">Public Key</Trans>
|
||||
</Label>
|
||||
<Input readOnly id="pkey" value={publicKey} className="col-span-3" required></Input>
|
||||
<div
|
||||
className={
|
||||
"h-6 w-24 bg-gradient-to-r rtl:bg-gradient-to-l from-transparent to-background to-65% absolute end-1 pointer-events-none"
|
||||
}
|
||||
></div>
|
||||
<TooltipProvider delayDuration={100}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant={"link"}
|
||||
className="absolute end-0"
|
||||
onClick={() => copyToClipboard(publicKey)}
|
||||
>
|
||||
<Copy className="h-4 w-4 " />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>
|
||||
<Trans>Click to copy</Trans>
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<Label htmlFor="host" className="text-right">
|
||||
Host / IP
|
||||
</Label>
|
||||
<Input id="host" name="host" className="col-span-3" required />
|
||||
</div>
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<Label htmlFor="port" className="text-right">
|
||||
Port
|
||||
</Label>
|
||||
<Input
|
||||
ref={port}
|
||||
name="port"
|
||||
id="port"
|
||||
defaultValue="45876"
|
||||
className="col-span-3"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 items-center gap-4 relative">
|
||||
<Label htmlFor="pkey" className="text-right whitespace-pre">
|
||||
Public Key
|
||||
</Label>
|
||||
<Input readOnly id="pkey" value={publicKey} className="col-span-3" required></Input>
|
||||
<div
|
||||
className={
|
||||
'h-6 w-24 bg-gradient-to-r from-transparent to-background to-65% absolute right-1 pointer-events-none'
|
||||
}
|
||||
></div>
|
||||
<TooltipProvider delayDuration={100}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant={'link'}
|
||||
className="absolute right-0"
|
||||
onClick={() => copyToClipboard(publicKey)}
|
||||
>
|
||||
<Copy className="h-4 w-4 " />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Click to copy</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter className="flex justify-end gap-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant={'ghost'}
|
||||
onClick={() => copyDockerCompose(port.current.value)}
|
||||
>
|
||||
Copy docker compose
|
||||
</Button>
|
||||
<Button>Add system</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
{/* Docker */}
|
||||
<TabsContent value="docker">
|
||||
<DialogFooter className="flex justify-end gap-2 sm:w-[calc(100%+20px)] sm:-ms-[20px]">
|
||||
<Button type="button" variant={"ghost"} onClick={() => copyDockerCompose(port.current.value)}>
|
||||
<Trans>Copy</Trans> docker compose
|
||||
</Button>
|
||||
<Button>
|
||||
<Trans>Add system</Trans>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</TabsContent>
|
||||
{/* Binary */}
|
||||
<TabsContent value="binary">
|
||||
<DialogFooter className="flex justify-end gap-2 sm:w-[calc(100%+20px)] sm:-ms-[20px]">
|
||||
<Button type="button" variant={"ghost"} onClick={() => copyInstallCommand(port.current.value)}>
|
||||
<Trans>Copy Linux command</Trans>
|
||||
</Button>
|
||||
<Button>
|
||||
<Trans>Add system</Trans>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</TabsContent>
|
||||
</form>
|
||||
</Tabs>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { memo, useState } from 'react'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { $alerts, $systems } from '@/lib/stores'
|
||||
import { memo, useState } from "react"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { $alerts, $systems } from "@/lib/stores"
|
||||
import {
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
@@ -8,15 +8,16 @@ import {
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import { BellIcon, GlobeIcon, ServerIcon } from 'lucide-react'
|
||||
import { alertInfo, cn } from '@/lib/utils'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { AlertRecord, SystemRecord } from '@/types'
|
||||
import { Link } from '../router'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Checkbox } from '../ui/checkbox'
|
||||
import { SystemAlert, SystemAlertGlobal } from './alerts-system'
|
||||
} from "@/components/ui/dialog"
|
||||
import { BellIcon, GlobeIcon, ServerIcon } from "lucide-react"
|
||||
import { alertInfo, cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { AlertRecord, SystemRecord } from "@/types"
|
||||
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)
|
||||
@@ -28,16 +29,10 @@ export default memo(function AlertsButton({ system }: { system: SystemRecord })
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
aria-label="Alerts"
|
||||
data-nolink
|
||||
onClick={() => setOpened(true)}
|
||||
>
|
||||
<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,
|
||||
className={cn("h-[1.2em] w-[1.2em] pointer-events-none", {
|
||||
"fill-primary": active,
|
||||
})}
|
||||
/>
|
||||
</Button>
|
||||
@@ -54,7 +49,7 @@ function TheContent({
|
||||
}: {
|
||||
data: { system: SystemRecord; alerts: AlertRecord[]; systemAlerts: AlertRecord[] }
|
||||
}) {
|
||||
const [overwriteExisting, setOverwriteExisting] = useState<boolean | 'indeterminate'>(false)
|
||||
const [overwriteExisting, setOverwriteExisting] = useState<boolean | "indeterminate">(false)
|
||||
const systems = $systems.get()
|
||||
|
||||
const data = Object.keys(alertInfo).map((key) => {
|
||||
@@ -69,24 +64,28 @@ function TheContent({
|
||||
return (
|
||||
<>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-xl">Alerts</DialogTitle>
|
||||
<DialogTitle className="text-xl">
|
||||
<Trans>Alerts</Trans>
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
See{' '}
|
||||
<Link href="/settings/notifications" className="link">
|
||||
notification settings
|
||||
</Link>{' '}
|
||||
to configure how you receive alerts.
|
||||
<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="mr-2 h-3.5 w-3.5" />
|
||||
<ServerIcon className="me-2 h-3.5 w-3.5" />
|
||||
{system.name}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="global">
|
||||
<GlobeIcon className="mr-1.5 h-3.5 w-3.5" />
|
||||
All systems
|
||||
<GlobeIcon className="me-1.5 h-3.5 w-3.5" />
|
||||
<Trans>All Systems</Trans>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="system">
|
||||
@@ -107,17 +106,11 @@ function TheContent({
|
||||
checked={overwriteExisting}
|
||||
onCheckedChange={setOverwriteExisting}
|
||||
/>
|
||||
Overwrite existing alerts
|
||||
<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}
|
||||
/>
|
||||
<SystemAlertGlobal key={d.key} data={d} overwrite={overwriteExisting} alerts={alerts} systems={systems} />
|
||||
))}
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { pb } from '@/lib/stores'
|
||||
import { alertInfo, cn } from '@/lib/utils'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { AlertRecord, SystemRecord } from '@/types'
|
||||
import { lazy, Suspense, useRef, useState } from 'react'
|
||||
import { toast } from '../ui/use-toast'
|
||||
import { RecordOptions } from 'pocketbase'
|
||||
import { newQueue, Queue } from '@henrygd/queue'
|
||||
import { 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 { toast } from "../ui/use-toast"
|
||||
import { RecordOptions } from "pocketbase"
|
||||
import { newQueue, Queue } from "@henrygd/queue"
|
||||
import { Trans, t, Plural } from "@lingui/macro"
|
||||
|
||||
interface AlertData {
|
||||
checked?: boolean
|
||||
@@ -13,19 +14,19 @@ interface AlertData {
|
||||
min?: number
|
||||
updateAlert?: (checked: boolean, value: number, min: number) => void
|
||||
key: keyof typeof alertInfo
|
||||
alert: (typeof alertInfo)[keyof typeof alertInfo]
|
||||
alert: AlertInfo
|
||||
system: SystemRecord
|
||||
}
|
||||
|
||||
const Slider = lazy(() => import('@/components/ui/slider'))
|
||||
const Slider = lazy(() => import("@/components/ui/slider"))
|
||||
|
||||
let queue: Queue
|
||||
|
||||
const failedUpdateToast = () =>
|
||||
toast({
|
||||
title: 'Failed to update alert',
|
||||
description: 'Please check logs for more details.',
|
||||
variant: 'destructive',
|
||||
title: t`Failed to update alert`,
|
||||
description: t`Please check logs for more details.`,
|
||||
variant: "destructive",
|
||||
})
|
||||
|
||||
export function SystemAlert({
|
||||
@@ -42,11 +43,11 @@ export function SystemAlert({
|
||||
data.updateAlert = async (checked: boolean, value: number, min: number) => {
|
||||
try {
|
||||
if (alert && !checked) {
|
||||
await pb.collection('alerts').delete(alert.id)
|
||||
await pb.collection("alerts").delete(alert.id)
|
||||
} else if (alert && checked) {
|
||||
await pb.collection('alerts').update(alert.id, { value, min, triggered: false })
|
||||
await pb.collection("alerts").update(alert.id, { value, min, triggered: false })
|
||||
} else if (checked) {
|
||||
pb.collection('alerts').create({
|
||||
pb.collection("alerts").create({
|
||||
system: system.id,
|
||||
user: pb.authStore.model!.id,
|
||||
name: data.key,
|
||||
@@ -75,7 +76,7 @@ export function SystemAlertGlobal({
|
||||
systems,
|
||||
}: {
|
||||
data: AlertData
|
||||
overwrite: boolean | 'indeterminate'
|
||||
overwrite: boolean | "indeterminate"
|
||||
alerts: AlertRecord[]
|
||||
systems: SystemRecord[]
|
||||
}) {
|
||||
@@ -110,9 +111,7 @@ export function SystemAlertGlobal({
|
||||
continue
|
||||
}
|
||||
// find matching existing alert
|
||||
const existingAlert = alerts.find(
|
||||
(alert) => alert.system === system.id && data.key === alert.name
|
||||
)
|
||||
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)
|
||||
@@ -127,13 +126,13 @@ export function SystemAlertGlobal({
|
||||
if (existingAlert) {
|
||||
// console.log('updating', system.name)
|
||||
queue
|
||||
.add(() => pb.collection('alerts').update(existingAlert.id, recordData, requestOptions))
|
||||
.add(() => pb.collection("alerts").update(existingAlert.id, recordData, requestOptions))
|
||||
.catch(failedUpdateToast)
|
||||
} else {
|
||||
// console.log('creating', system.name)
|
||||
queue
|
||||
.add(() =>
|
||||
pb.collection('alerts').create(
|
||||
pb.collection("alerts").create(
|
||||
{
|
||||
system: system.id,
|
||||
user: pb.authStore.model!.id,
|
||||
@@ -147,7 +146,7 @@ export function SystemAlertGlobal({
|
||||
}
|
||||
} else if (existingAlert) {
|
||||
// console.log('deleting', system.name)
|
||||
queue.add(() => pb.collection('alerts').delete(existingAlert.id)).catch(failedUpdateToast)
|
||||
queue.add(() => pb.collection("alerts").delete(existingAlert.id)).catch(failedUpdateToast)
|
||||
}
|
||||
}
|
||||
systemsWithExistingAlerts.current.populatedSet = true
|
||||
@@ -159,7 +158,7 @@ export function SystemAlertGlobal({
|
||||
function AlertContent({ data }: { data: AlertData }) {
|
||||
const { key } = data
|
||||
|
||||
const hasSliders = !('single' in data.alert)
|
||||
const hasSliders = !("single" in data.alert)
|
||||
|
||||
const [checked, setChecked] = useState(data.checked || false)
|
||||
const [min, setMin] = useState(data.min || (hasSliders ? 10 : 0))
|
||||
@@ -172,24 +171,21 @@ function AlertContent({ data }: { data: AlertData }) {
|
||||
|
||||
const Icon = alertInfo[key].icon
|
||||
|
||||
const updateAlert = (c?: boolean) =>
|
||||
data.updateAlert?.(c ?? checked, newValue.current, newMin.current)
|
||||
const updateAlert = (c?: boolean) => data.updateAlert?.(c ?? checked, newValue.current, newMin.current)
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-muted-foreground/15 hover:border-muted-foreground/20 transition-colors duration-100 group">
|
||||
<label
|
||||
htmlFor={`s${key}`}
|
||||
className={cn('flex flex-row items-center justify-between gap-4 cursor-pointer p-4', {
|
||||
'pb-0': showSliders,
|
||||
className={cn("flex flex-row items-center justify-between gap-4 cursor-pointer p-4", {
|
||||
"pb-0": showSliders,
|
||||
})}
|
||||
>
|
||||
<div className="grid gap-1 select-none">
|
||||
<p className="font-semibold flex gap-3 items-center capitalize">
|
||||
<Icon className="h-4 w-4 opacity-85" /> {data.alert.name}
|
||||
<p className="font-semibold flex gap-3 items-center">
|
||||
<Icon className="h-4 w-4 opacity-85" /> {data.alert.name()}
|
||||
</p>
|
||||
{!showSliders && (
|
||||
<span className="block text-sm text-muted-foreground">{data.alert.desc}</span>
|
||||
)}
|
||||
{!showSliders && <span className="block text-sm text-muted-foreground">{data.alert.desc()}</span>}
|
||||
</div>
|
||||
<Switch
|
||||
id={`s${key}`}
|
||||
@@ -205,11 +201,13 @@ function AlertContent({ data }: { data: AlertData }) {
|
||||
<Suspense fallback={<div className="h-10" />}>
|
||||
<div>
|
||||
<p id={`v${key}`} className="text-sm block h-8">
|
||||
Average exceeds{' '}
|
||||
<strong className="text-foreground">
|
||||
{value}
|
||||
{data.alert.unit}
|
||||
</strong>
|
||||
<Trans>
|
||||
Average exceeds{" "}
|
||||
<strong className="text-foreground">
|
||||
{value}
|
||||
{data.alert.unit}
|
||||
</strong>
|
||||
</Trans>
|
||||
</p>
|
||||
<div className="flex gap-3">
|
||||
<Slider
|
||||
@@ -218,14 +216,16 @@ function AlertContent({ data }: { data: AlertData }) {
|
||||
onValueCommit={(val) => (newValue.current = val[0]) && updateAlert()}
|
||||
onValueChange={(val) => setValue(val[0])}
|
||||
min={1}
|
||||
max={99}
|
||||
max={alertInfo[key].max ?? 99}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p id={`t${key}`} className="text-sm block h-8">
|
||||
For <strong className="text-foreground">{min}</strong> minute
|
||||
{min > 1 && 's'}
|
||||
<Trans>
|
||||
For <strong className="text-foreground">{min}</strong>{" "}
|
||||
<Plural value={min} one=" minute" other=" minutes" />
|
||||
</Trans>
|
||||
</p>
|
||||
<div className="flex gap-3">
|
||||
<Slider
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from 'recharts'
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
|
||||
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from '@/components/ui/chart'
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from "@/components/ui/chart"
|
||||
import {
|
||||
useYAxisWidth,
|
||||
cn,
|
||||
@@ -8,10 +8,12 @@ import {
|
||||
toFixedWithoutTrailingZeros,
|
||||
decimalString,
|
||||
chartMargin,
|
||||
} from '@/lib/utils'
|
||||
} from "@/lib/utils"
|
||||
// import Spinner from '../spinner'
|
||||
import { ChartData } from '@/types'
|
||||
import { memo, useMemo } from 'react'
|
||||
import { ChartData } from "@/types"
|
||||
import { memo, useMemo } from "react"
|
||||
import { t } from "@lingui/macro"
|
||||
import { useLingui } from "@lingui/react"
|
||||
|
||||
/** [label, key, color, opacity] */
|
||||
type DataKeys = [string, string, number, number]
|
||||
@@ -21,14 +23,14 @@ const getNestedValue = (path: string, max = false, data: any): number | null =>
|
||||
// a max value which doesn't exist, or the value was zero and omitted from the stats object.
|
||||
// so we check if cpum is present. if so, return 0 to make sure the zero value is displayed.
|
||||
// if not, return null - there is no max data so do not display anything.
|
||||
return `stats.${path}${max ? 'm' : ''}`
|
||||
.split('.')
|
||||
return `stats.${path}${max ? "m" : ""}`
|
||||
.split(".")
|
||||
.reduce((acc: any, key: string) => acc?.[key] ?? (data.stats?.cpum ? 0 : null), data)
|
||||
}
|
||||
|
||||
export default memo(function AreaChartDefault({
|
||||
maxToggled = false,
|
||||
unit = ' MB/s',
|
||||
unit = " MB/s",
|
||||
chartName,
|
||||
chartData,
|
||||
}: {
|
||||
@@ -38,46 +40,53 @@ export default memo(function AreaChartDefault({
|
||||
chartData: ChartData
|
||||
}) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
const { i18n } = useLingui()
|
||||
|
||||
const { chartTime } = chartData
|
||||
|
||||
const showMax = chartTime !== '1h' && maxToggled
|
||||
const showMax = chartTime !== "1h" && maxToggled
|
||||
|
||||
const dataKeys: DataKeys[] = useMemo(() => {
|
||||
// [label, key, color, opacity]
|
||||
if (chartName === 'CPU Usage') {
|
||||
return [[chartName, 'cpu', 1, 0.4]]
|
||||
} else if (chartName === 'dio') {
|
||||
if (chartName === "CPU Usage") {
|
||||
return [[t`CPU Usage`, "cpu", 1, 0.4]]
|
||||
} else if (chartName === "dio") {
|
||||
return [
|
||||
['Write', 'dw', 3, 0.3],
|
||||
['Read', 'dr', 1, 0.3],
|
||||
[t({ message: "Write", comment: "Context is disk write" }), "dw", 3, 0.3],
|
||||
[t({ message: "Read", comment: "Context is disk read" }), "dr", 1, 0.3],
|
||||
]
|
||||
} else if (chartName === 'bw') {
|
||||
} else if (chartName === "bw") {
|
||||
return [
|
||||
['Sent', 'ns', 5, 0.2],
|
||||
['Received', 'nr', 2, 0.2],
|
||||
[t({ message: "Sent", comment: "Context is network bytes sent (upload)" }), "ns", 5, 0.2],
|
||||
[t({ message: "Received", comment: "Context is network bytes received (download)" }), "nr", 2, 0.2],
|
||||
]
|
||||
} else if (chartName.startsWith('efs')) {
|
||||
} else if (chartName.startsWith("efs")) {
|
||||
return [
|
||||
['Write', `${chartName}.w`, 3, 0.3],
|
||||
['Read', `${chartName}.r`, 1, 0.3],
|
||||
[t`Write`, `${chartName}.w`, 3, 0.3],
|
||||
[t`Read`, `${chartName}.r`, 1, 0.3],
|
||||
]
|
||||
}
|
||||
return []
|
||||
}, [])
|
||||
}, [chartName, i18n.locale])
|
||||
|
||||
// console.log('Rendered at', new Date())
|
||||
|
||||
if (chartData.systemStats.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||
'opacity-100': yAxisWidth,
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<AreaChart accessibilityLayer data={chartData.systemStats} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
width={yAxisWidth}
|
||||
tickFormatter={(value) => {
|
||||
|
||||
@@ -1,33 +1,23 @@
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { $chartTime } from '@/lib/stores'
|
||||
import { chartTimeData, cn } from '@/lib/utils'
|
||||
import { ChartTimes } from '@/types'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { HistoryIcon } from 'lucide-react'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||
import { $chartTime } from "@/lib/stores"
|
||||
import { chartTimeData, cn } from "@/lib/utils"
|
||||
import { ChartTimes } from "@/types"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { HistoryIcon } from "lucide-react"
|
||||
|
||||
export default function ChartTimeSelect({ className }: { className?: string }) {
|
||||
const chartTime = useStore($chartTime)
|
||||
|
||||
return (
|
||||
<Select
|
||||
defaultValue="1h"
|
||||
value={chartTime}
|
||||
onValueChange={(value: ChartTimes) => $chartTime.set(value)}
|
||||
>
|
||||
<SelectTrigger className={cn(className, 'relative pl-10 pr-5')}>
|
||||
<HistoryIcon className="h-4 w-4 absolute left-4 top-1/2 -translate-y-1/2 opacity-85" />
|
||||
<Select defaultValue="1h" value={chartTime} onValueChange={(value: ChartTimes) => $chartTime.set(value)}>
|
||||
<SelectTrigger className={cn(className, "relative ps-10 pe-5")}>
|
||||
<HistoryIcon className="h-4 w-4 absolute start-4 top-1/2 -translate-y-1/2 opacity-85" />
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{Object.entries(chartTimeData).map(([value, { label }]) => (
|
||||
<SelectItem key={label} value={value}>
|
||||
{label}
|
||||
<SelectItem key={value} value={value}>
|
||||
{label()}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from 'recharts'
|
||||
import {
|
||||
ChartConfig,
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
xAxis,
|
||||
} from '@/components/ui/chart'
|
||||
import { memo, useMemo } from 'react'
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
|
||||
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from "@/components/ui/chart"
|
||||
import { memo, useMemo } from "react"
|
||||
import {
|
||||
useYAxisWidth,
|
||||
cn,
|
||||
@@ -16,18 +10,18 @@ import {
|
||||
toFixedFloat,
|
||||
getSizeAndUnit,
|
||||
toFixedWithoutTrailingZeros,
|
||||
} from '@/lib/utils'
|
||||
} from "@/lib/utils"
|
||||
// import Spinner from '../spinner'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { $containerFilter } from '@/lib/stores'
|
||||
import { ChartData } from '@/types'
|
||||
import { Separator } from '../ui/separator'
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { $containerFilter } from "@/lib/stores"
|
||||
import { ChartData } from "@/types"
|
||||
import { Separator } from "../ui/separator"
|
||||
|
||||
export default memo(function ContainerChart({
|
||||
dataKey,
|
||||
chartData,
|
||||
chartName,
|
||||
unit = '%',
|
||||
unit = "%",
|
||||
}: {
|
||||
dataKey: string
|
||||
chartData: ChartData
|
||||
@@ -39,7 +33,7 @@ export default memo(function ContainerChart({
|
||||
|
||||
const { containerData } = chartData
|
||||
|
||||
const isNetChart = chartName === 'net'
|
||||
const isNetChart = chartName === "net"
|
||||
|
||||
const chartConfig = useMemo(() => {
|
||||
let config = {} as Record<
|
||||
@@ -52,7 +46,7 @@ export default memo(function ContainerChart({
|
||||
const totalUsage = {} as Record<string, number>
|
||||
for (let stats of containerData) {
|
||||
for (let key in stats) {
|
||||
if (!key || key === 'created') {
|
||||
if (!key || key === "created") {
|
||||
continue
|
||||
}
|
||||
if (!(key in totalUsage)) {
|
||||
@@ -87,7 +81,7 @@ export default memo(function ContainerChart({
|
||||
tickFormatter: (value: any) => string
|
||||
}
|
||||
// tick formatter
|
||||
if (chartName === 'cpu') {
|
||||
if (chartName === "cpu") {
|
||||
obj.tickFormatter = (value) => {
|
||||
const val = toFixedWithoutTrailingZeros(value, 2) + unit
|
||||
return updateYAxisWidth(val)
|
||||
@@ -95,7 +89,7 @@ export default memo(function ContainerChart({
|
||||
} else {
|
||||
obj.tickFormatter = (value) => {
|
||||
const { v, u } = getSizeAndUnit(value, false)
|
||||
return updateYAxisWidth(`${toFixedFloat(v, 2)}${u}${isNetChart ? '/s' : ''}`)
|
||||
return updateYAxisWidth(`${toFixedFloat(v, 2)}${u}${isNetChart ? "/s" : ""}`)
|
||||
}
|
||||
}
|
||||
// tooltip formatter
|
||||
@@ -107,10 +101,10 @@ export default memo(function ContainerChart({
|
||||
return (
|
||||
<span className="flex">
|
||||
{decimalString(received)} MB/s
|
||||
<span className="opacity-70 ml-0.5"> rx </span>
|
||||
<span className="opacity-70 ms-0.5"> rx </span>
|
||||
<Separator orientation="vertical" className="h-3 mx-1.5 bg-primary/40" />
|
||||
{decimalString(sent)} MB/s
|
||||
<span className="opacity-70 ml-0.5"> tx</span>
|
||||
<span className="opacity-70 ms-0.5"> tx</span>
|
||||
</span>
|
||||
)
|
||||
} catch (e) {
|
||||
@@ -122,20 +116,24 @@ export default memo(function ContainerChart({
|
||||
}
|
||||
// data function
|
||||
if (isNetChart) {
|
||||
obj.dataFunction = (key: string, data: any) => (data[key]?.nr ?? 0) + (data[key]?.ns ?? 0)
|
||||
obj.dataFunction = (key: string, data: any) => (data[key]?.nr ?? null) + (data[key]?.ns ?? null)
|
||||
} else {
|
||||
obj.dataFunction = (key: string, data: any) => data[key]?.[dataKey] ?? 0
|
||||
obj.dataFunction = (key: string, data: any) => data[key]?.[dataKey] ?? null
|
||||
}
|
||||
return obj
|
||||
}, [])
|
||||
|
||||
// console.log('rendered at', new Date())
|
||||
|
||||
if (containerData.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||
'opacity-100': yAxisWidth,
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<AreaChart
|
||||
@@ -147,6 +145,8 @@ export default memo(function ContainerChart({
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
width={yAxisWidth}
|
||||
tickFormatter={tickFormatter}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from 'recharts'
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
|
||||
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from '@/components/ui/chart'
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from "@/components/ui/chart"
|
||||
import {
|
||||
useYAxisWidth,
|
||||
cn,
|
||||
@@ -9,9 +9,11 @@ import {
|
||||
toFixedFloat,
|
||||
chartMargin,
|
||||
getSizeAndUnit,
|
||||
} from '@/lib/utils'
|
||||
import { ChartData } from '@/types'
|
||||
import { memo } from 'react'
|
||||
} from "@/lib/utils"
|
||||
import { ChartData } from "@/types"
|
||||
import { memo } from "react"
|
||||
import { t } from "@lingui/macro"
|
||||
import { useLingui } from "@lingui/react"
|
||||
|
||||
export default memo(function DiskChart({
|
||||
dataKey,
|
||||
@@ -23,17 +25,24 @@ export default memo(function DiskChart({
|
||||
chartData: ChartData
|
||||
}) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
const { _ } = useLingui()
|
||||
|
||||
if (chartData.systemStats.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||
'opacity-100': yAxisWidth,
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<AreaChart accessibilityLayer data={chartData.systemStats} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
width={yAxisWidth}
|
||||
domain={[0, diskSize]}
|
||||
@@ -62,7 +71,7 @@ export default memo(function DiskChart({
|
||||
/>
|
||||
<Area
|
||||
dataKey={dataKey}
|
||||
name="Disk Usage"
|
||||
name={_(t`Disk Usage`)}
|
||||
type="monotoneX"
|
||||
fill="hsl(var(--chart-4))"
|
||||
fillOpacity={0.4}
|
||||
|
||||
@@ -1,36 +1,38 @@
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from 'recharts'
|
||||
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 { 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"
|
||||
|
||||
export default memo(function MemChart({ chartData }: { chartData: ChartData }) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
const { _ } = useLingui()
|
||||
|
||||
const totalMem = toFixedFloat(chartData.systemStats.at(-1)?.stats.m ?? 0, 1)
|
||||
|
||||
// console.log('rendered at', new Date())
|
||||
|
||||
if (chartData.systemStats.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* {!yAxisSet && <Spinner />} */}
|
||||
<ChartContainer
|
||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||
'opacity-100': yAxisWidth,
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<AreaChart accessibilityLayer data={chartData.systemStats} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
{totalMem && (
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
// use "ticks" instead of domain / tickcount if need more control
|
||||
domain={[0, totalMem]}
|
||||
tickCount={9}
|
||||
@@ -40,7 +42,7 @@ export default memo(function MemChart({ chartData }: { chartData: ChartData }) {
|
||||
axisLine={false}
|
||||
tickFormatter={(value) => {
|
||||
const val = toFixedFloat(value, 1)
|
||||
return updateYAxisWidth(val + ' GB')
|
||||
return updateYAxisWidth(val + " GB")
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -54,13 +56,13 @@ export default memo(function MemChart({ chartData }: { chartData: ChartData }) {
|
||||
// @ts-ignore
|
||||
itemSorter={(a, b) => a.order - b.order}
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={(item) => decimalString(item.value) + ' GB'}
|
||||
contentFormatter={(item) => decimalString(item.value) + " GB"}
|
||||
// indicator="line"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Area
|
||||
name="Used"
|
||||
name={_(t`Used`)}
|
||||
order={3}
|
||||
dataKey="stats.mu"
|
||||
type="monotoneX"
|
||||
@@ -84,7 +86,7 @@ export default memo(function MemChart({ chartData }: { chartData: ChartData }) {
|
||||
/>
|
||||
)}
|
||||
<Area
|
||||
name="Cache / Buffers"
|
||||
name={_(t`Cache / Buffers`)}
|
||||
order={1}
|
||||
dataKey="stats.mb"
|
||||
type="monotoneX"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from 'recharts'
|
||||
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts"
|
||||
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from '@/components/ui/chart'
|
||||
import { ChartContainer, ChartTooltip, ChartTooltipContent, xAxis } from "@/components/ui/chart"
|
||||
import {
|
||||
useYAxisWidth,
|
||||
cn,
|
||||
@@ -8,32 +8,36 @@ import {
|
||||
toFixedWithoutTrailingZeros,
|
||||
decimalString,
|
||||
chartMargin,
|
||||
} from '@/lib/utils'
|
||||
import { ChartData } from '@/types'
|
||||
import { memo } from 'react'
|
||||
} 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()
|
||||
|
||||
if (chartData.systemStats.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||
'opacity-100': yAxisWidth,
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<AreaChart accessibilityLayer data={chartData.systemStats} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
domain={[
|
||||
0,
|
||||
() => toFixedWithoutTrailingZeros(chartData.systemStats.at(-1)?.stats.s ?? 0.04, 2),
|
||||
]}
|
||||
domain={[0, () => toFixedWithoutTrailingZeros(chartData.systemStats.at(-1)?.stats.s ?? 0.04, 2)]}
|
||||
width={yAxisWidth}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickFormatter={(value) => updateYAxisWidth(value + ' GB')}
|
||||
tickFormatter={(value) => updateYAxisWidth(value + " GB")}
|
||||
/>
|
||||
{xAxis(chartData)}
|
||||
<ChartTooltip
|
||||
@@ -42,14 +46,14 @@ export default memo(function SwapChart({ chartData }: { chartData: ChartData })
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={(item) => decimalString(item.value) + ' GB'}
|
||||
contentFormatter={(item) => decimalString(item.value) + " GB"}
|
||||
// indicator="line"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Area
|
||||
dataKey="stats.su"
|
||||
name="Swap Usage"
|
||||
name={t`Used`}
|
||||
type="monotoneX"
|
||||
fill="hsl(var(--chart-2))"
|
||||
fillOpacity={0.4}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CartesianGrid, Line, LineChart, YAxis } from 'recharts'
|
||||
import { CartesianGrid, Line, LineChart, YAxis } from "recharts"
|
||||
|
||||
import {
|
||||
ChartContainer,
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
xAxis,
|
||||
} from '@/components/ui/chart'
|
||||
} from "@/components/ui/chart"
|
||||
import {
|
||||
useYAxisWidth,
|
||||
cn,
|
||||
@@ -15,13 +15,17 @@ import {
|
||||
toFixedWithoutTrailingZeros,
|
||||
decimalString,
|
||||
chartMargin,
|
||||
} from '@/lib/utils'
|
||||
import { ChartData } from '@/types'
|
||||
import { memo, useMemo } from 'react'
|
||||
} from "@/lib/utils"
|
||||
import { ChartData } from "@/types"
|
||||
import { memo, useMemo } from "react"
|
||||
|
||||
export default memo(function TemperatureChart({ chartData }: { chartData: ChartData }) {
|
||||
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||
|
||||
if (chartData.systemStats.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
/** Format temperature data for chart and assign colors */
|
||||
const newChartData = useMemo(() => {
|
||||
const newChartData = { data: [], colors: {} } as {
|
||||
@@ -53,19 +57,21 @@ export default memo(function TemperatureChart({ chartData }: { chartData: ChartD
|
||||
return (
|
||||
<div>
|
||||
<ChartContainer
|
||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||
'opacity-100': yAxisWidth,
|
||||
className={cn("h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity", {
|
||||
"opacity-100": yAxisWidth,
|
||||
})}
|
||||
>
|
||||
<LineChart accessibilityLayer data={newChartData.data} margin={chartMargin}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
direction="ltr"
|
||||
orientation={chartData.orientation}
|
||||
className="tracking-tighter"
|
||||
domain={[0, 'auto']}
|
||||
domain={[0, "auto"]}
|
||||
width={yAxisWidth}
|
||||
tickFormatter={(value) => {
|
||||
const val = toFixedWithoutTrailingZeros(value, 2)
|
||||
return updateYAxisWidth(val + ' °C')
|
||||
return updateYAxisWidth(val + " °C")
|
||||
}}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
@@ -79,7 +85,7 @@ export default memo(function TemperatureChart({ chartData }: { chartData: ChartD
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
|
||||
contentFormatter={(item) => decimalString(item.value) + ' °C'}
|
||||
contentFormatter={(item) => decimalString(item.value) + " °C"}
|
||||
// indicator="line"
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
Server,
|
||||
SettingsIcon,
|
||||
UsersIcon,
|
||||
} from 'lucide-react'
|
||||
} from "lucide-react"
|
||||
|
||||
import {
|
||||
CommandDialog,
|
||||
@@ -19,34 +19,36 @@ import {
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
} from '@/components/ui/command'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { $systems } from '@/lib/stores'
|
||||
import { isAdmin } from '@/lib/utils'
|
||||
import { navigate } from './router'
|
||||
} from "@/components/ui/command"
|
||||
import { useEffect } from "react"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { $systems } from "@/lib/stores"
|
||||
import { isAdmin } from "@/lib/utils"
|
||||
import { navigate } from "./router"
|
||||
import { Trans, t } from "@lingui/macro"
|
||||
|
||||
export default function CommandPalette() {
|
||||
const [open, setOpen] = useState(false)
|
||||
export default function CommandPalette({ open, setOpen }: { open: boolean; setOpen: (open: boolean) => void }) {
|
||||
const systems = useStore($systems)
|
||||
|
||||
useEffect(() => {
|
||||
const down = (e: KeyboardEvent) => {
|
||||
if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
|
||||
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
||||
e.preventDefault()
|
||||
setOpen((open) => !open)
|
||||
setOpen(!open)
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', down)
|
||||
return () => document.removeEventListener('keydown', down)
|
||||
}, [])
|
||||
document.addEventListener("keydown", down)
|
||||
return () => document.removeEventListener("keydown", down)
|
||||
}, [open, setOpen])
|
||||
|
||||
return (
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<CommandInput placeholder="Search for systems or settings..." />
|
||||
<CommandInput placeholder={t`Search for systems or settings...`} />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandEmpty>
|
||||
<Trans>No results found.</Trans>
|
||||
</CommandEmpty>
|
||||
{systems.length > 0 && (
|
||||
<>
|
||||
<CommandGroup>
|
||||
@@ -58,7 +60,7 @@ export default function CommandPalette() {
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<Server className="mr-2 h-4 w-4" />
|
||||
<Server className="me-2 h-4 w-4" />
|
||||
<span>{system.name}</span>
|
||||
<CommandShortcut>{system.host}</CommandShortcut>
|
||||
</CommandItem>
|
||||
@@ -67,106 +69,140 @@ export default function CommandPalette() {
|
||||
<CommandSeparator className="mb-1.5" />
|
||||
</>
|
||||
)}
|
||||
<CommandGroup heading="Pages / Settings">
|
||||
<CommandGroup heading={t`Pages / Settings`}>
|
||||
<CommandItem
|
||||
keywords={['home']}
|
||||
keywords={["home"]}
|
||||
onSelect={() => {
|
||||
navigate('/')
|
||||
setOpen((open) => !open)
|
||||
navigate("/")
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<LayoutDashboard className="mr-2 h-4 w-4" />
|
||||
<span>Dashboard</span>
|
||||
<CommandShortcut>Page</CommandShortcut>
|
||||
<LayoutDashboard className="me-2 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Dashboard</Trans>
|
||||
</span>
|
||||
<CommandShortcut>
|
||||
<Trans>Page</Trans>
|
||||
</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem
|
||||
onSelect={() => {
|
||||
navigate('/settings/general')
|
||||
setOpen((open) => !open)
|
||||
navigate("/settings/general")
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<SettingsIcon className="mr-2 h-4 w-4" />
|
||||
<span>Settings</span>
|
||||
<CommandShortcut>Settings</CommandShortcut>
|
||||
<SettingsIcon className="me-2 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Settings</Trans>
|
||||
</span>
|
||||
<CommandShortcut>
|
||||
<Trans>Settings</Trans>
|
||||
</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem
|
||||
keywords={['alerts']}
|
||||
keywords={["alerts"]}
|
||||
onSelect={() => {
|
||||
navigate('/settings/notifications')
|
||||
setOpen((open) => !open)
|
||||
navigate("/settings/notifications")
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<MailIcon className="mr-2 h-4 w-4" />
|
||||
<span>Notification settings</span>
|
||||
<CommandShortcut>Settings</CommandShortcut>
|
||||
<MailIcon className="me-2 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Notifications</Trans>
|
||||
</span>
|
||||
<CommandShortcut>
|
||||
<Trans>Settings</Trans>
|
||||
</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem
|
||||
keywords={['github']}
|
||||
keywords={["github"]}
|
||||
onSelect={() => {
|
||||
window.location.href = 'https://github.com/henrygd/beszel/blob/main/readme.md'
|
||||
window.location.href = "https://github.com/henrygd/beszel/blob/main/readme.md"
|
||||
}}
|
||||
>
|
||||
<Github className="mr-2 h-4 w-4" />
|
||||
<span>Documentation</span>
|
||||
<Github className="me-2 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Documentation</Trans>
|
||||
</span>
|
||||
<CommandShortcut>GitHub</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
{isAdmin() && (
|
||||
<>
|
||||
<CommandSeparator className="mb-1.5" />
|
||||
<CommandGroup heading="Admin">
|
||||
<CommandGroup heading={t`Admin`}>
|
||||
<CommandItem
|
||||
keywords={['pocketbase']}
|
||||
keywords={["pocketbase"]}
|
||||
onSelect={() => {
|
||||
setOpen(false)
|
||||
window.open('/_/', '_blank')
|
||||
window.open("/_/", "_blank")
|
||||
}}
|
||||
>
|
||||
<UsersIcon className="mr-2 h-4 w-4" />
|
||||
<span>Users</span>
|
||||
<CommandShortcut>Admin</CommandShortcut>
|
||||
<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')
|
||||
window.open("/_/#/logs", "_blank")
|
||||
}}
|
||||
>
|
||||
<LogsIcon className="mr-2 h-4 w-4" />
|
||||
<span>Logs</span>
|
||||
<CommandShortcut>Admin</CommandShortcut>
|
||||
<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')
|
||||
window.open("/_/#/settings/backups", "_blank")
|
||||
}}
|
||||
>
|
||||
<DatabaseBackupIcon className="mr-2 h-4 w-4" />
|
||||
<span>Backups</span>
|
||||
<CommandShortcut>Admin</CommandShortcut>
|
||||
<DatabaseBackupIcon className="me-2 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Backups</Trans>
|
||||
</span>
|
||||
<CommandShortcut>
|
||||
<Trans>Admin</Trans>
|
||||
</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem
|
||||
keywords={['oauth', 'oicd']}
|
||||
keywords={["oauth", "oicd"]}
|
||||
onSelect={() => {
|
||||
setOpen(false)
|
||||
window.open('/_/#/settings/auth-providers', '_blank')
|
||||
window.open("/_/#/settings/auth-providers", "_blank")
|
||||
}}
|
||||
>
|
||||
<LockKeyholeIcon className="mr-2 h-4 w-4" />
|
||||
<span>Auth Providers</span>
|
||||
<CommandShortcut>Admin</CommandShortcut>
|
||||
<LockKeyholeIcon className="me-2 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Auth Providers</Trans>
|
||||
</span>
|
||||
<CommandShortcut>
|
||||
<Trans>Admin</Trans>
|
||||
</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem
|
||||
keywords={['email']}
|
||||
keywords={["email"]}
|
||||
onSelect={() => {
|
||||
setOpen(false)
|
||||
window.open('/_/#/settings/mail', '_blank')
|
||||
window.open("/_/#/settings/mail", "_blank")
|
||||
}}
|
||||
>
|
||||
<MailIcon className="mr-2 h-4 w-4" />
|
||||
<span>SMTP settings</span>
|
||||
<CommandShortcut>Admin</CommandShortcut>
|
||||
<MailIcon className="me-2 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>SMTP settings</Trans>
|
||||
</span>
|
||||
<CommandShortcut>
|
||||
<Trans>Admin</Trans>
|
||||
</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</>
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
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 { 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 (
|
||||
<Dialog defaultOpen={true}>
|
||||
<DialogContent className="w-[90%] rounded-lg" style={{ maxWidth: 530 }}>
|
||||
<DialogContent className="w-[90%] rounded-lg md:pt-4" style={{ maxWidth: 530 }}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Could not copy to clipboard</DialogTitle>
|
||||
<DialogDescription>Please copy the text manually.</DialogDescription>
|
||||
<DialogTitle>
|
||||
<Trans>Copy text</Trans>
|
||||
</DialogTitle>
|
||||
<DialogDescription className="hidden xs:block">
|
||||
<Trans>Automatic copy requires a secure context.</Trans>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<CopyTextarea content={content} />
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Clipboard API requires a secure context (https, localhost, or *.localhost)
|
||||
</p>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
@@ -24,7 +26,7 @@ function CopyTextarea({ content }: { content: string }) {
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null)
|
||||
|
||||
const rows = useMemo(() => {
|
||||
return content.split('\n').length
|
||||
return content.split("\n").length
|
||||
}, [content])
|
||||
|
||||
useEffect(() => {
|
||||
@@ -34,7 +36,7 @@ function CopyTextarea({ content }: { content: string }) {
|
||||
}, [textareaRef])
|
||||
|
||||
useEffect(() => {
|
||||
return () => $copyContent.set('')
|
||||
return () => $copyContent.set("")
|
||||
}, [])
|
||||
|
||||
return (
|
||||
|
||||
34
beszel/site/src/components/lang-toggle.tsx
Normal file
34
beszel/site/src/components/lang-toggle.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { LanguagesIcon } from "lucide-react"
|
||||
|
||||
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 { dynamicActivate } from "@/lib/i18n"
|
||||
|
||||
export function LangToggle() {
|
||||
const { i18n } = useLingui()
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant={"ghost"} size="icon" className="hidden 450:flex">
|
||||
<LanguagesIcon className="absolute h-[1.2rem] w-[1.2rem] light:opacity-85" />
|
||||
<span className="sr-only">Language</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="grid grid-cols-3">
|
||||
{languages.map(({ lang, label, e }) => (
|
||||
<DropdownMenuItem
|
||||
key={lang}
|
||||
className={cn("px-3 flex gap-2.5", lang === i18n.locale && "font-semibold")}
|
||||
onClick={() => dynamicActivate(lang)}
|
||||
>
|
||||
<span>{e}</span> {label}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
@@ -1,28 +1,20 @@
|
||||
import { cn } from '@/lib/utils'
|
||||
import { buttonVariants } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { LoaderCircle, LockIcon, LogInIcon, MailIcon, UserIcon } from 'lucide-react'
|
||||
import { $authenticated, pb } from '@/lib/stores'
|
||||
import * as v from 'valibot'
|
||||
import { toast } from '../ui/use-toast'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTrigger,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { AuthMethodsList, OAuth2AuthConfig } from 'pocketbase'
|
||||
import { Link } from '../router'
|
||||
import { cn } from "@/lib/utils"
|
||||
import { buttonVariants } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { LoaderCircle, LockIcon, LogInIcon, MailIcon, UserIcon } from "lucide-react"
|
||||
import { $authenticated, pb } from "@/lib/stores"
|
||||
import * as v from "valibot"
|
||||
import { toast } from "../ui/use-toast"
|
||||
import { Dialog, DialogContent, DialogTrigger, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
||||
import { useCallback, useState } from "react"
|
||||
import { AuthMethodsList, OAuth2AuthConfig } from "pocketbase"
|
||||
import { Link } from "../router"
|
||||
import { Trans, t } from "@lingui/macro"
|
||||
|
||||
const honeypot = v.literal('')
|
||||
const emailSchema = v.pipe(v.string(), v.email('Invalid email address.'))
|
||||
const passwordSchema = v.pipe(
|
||||
v.string(),
|
||||
v.minLength(10, 'Password must be at least 10 characters.')
|
||||
)
|
||||
const honeypot = v.literal("")
|
||||
const emailSchema = v.pipe(v.string(), v.email(t`Invalid email address.`))
|
||||
const passwordSchema = v.pipe(v.string(), v.minLength(10, t`Password must be at least 10 characters.`))
|
||||
|
||||
const LoginSchema = v.looseObject({
|
||||
name: honeypot,
|
||||
@@ -36,9 +28,9 @@ const RegisterSchema = v.looseObject({
|
||||
v.string(),
|
||||
v.regex(
|
||||
/^(?=.*[a-zA-Z])[a-zA-Z0-9_-]+$/,
|
||||
'Invalid username. You may use alphanumeric characters, underscores, and hyphens.'
|
||||
"Invalid username. You may use alphanumeric characters, underscores, and hyphens."
|
||||
),
|
||||
v.minLength(3, 'Username must be at least 3 characters long.')
|
||||
v.minLength(3, "Username must be at least 3 characters long.")
|
||||
),
|
||||
email: emailSchema,
|
||||
password: passwordSchema,
|
||||
@@ -47,9 +39,9 @@ const RegisterSchema = v.looseObject({
|
||||
|
||||
const showLoginFaliedToast = () => {
|
||||
toast({
|
||||
title: 'Login attempt failed',
|
||||
description: 'Please check your credentials and try again',
|
||||
variant: 'destructive',
|
||||
title: t`Login attempt failed`,
|
||||
description: t`Please check your credentials and try again`,
|
||||
variant: "destructive",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -90,7 +82,7 @@ export function UserAuthForm({
|
||||
if (isFirstRun) {
|
||||
// check that passwords match
|
||||
if (password !== passwordConfirm) {
|
||||
let msg = 'Passwords do not match'
|
||||
let msg = "Passwords do not match"
|
||||
setErrors({ passwordConfirm: msg })
|
||||
return
|
||||
}
|
||||
@@ -100,17 +92,17 @@ export function UserAuthForm({
|
||||
passwordConfirm: password,
|
||||
})
|
||||
await pb.admins.authWithPassword(email, password)
|
||||
await pb.collection('users').create({
|
||||
await pb.collection("users").create({
|
||||
username,
|
||||
email,
|
||||
password,
|
||||
passwordConfirm: password,
|
||||
role: 'admin',
|
||||
role: "admin",
|
||||
verified: true,
|
||||
})
|
||||
await pb.collection('users').authWithPassword(email, password)
|
||||
await pb.collection("users").authWithPassword(email, password)
|
||||
} else {
|
||||
await pb.collection('users').authWithPassword(email, password)
|
||||
await pb.collection("users").authWithPassword(email, password)
|
||||
}
|
||||
$authenticated.set(true)
|
||||
} catch (e) {
|
||||
@@ -127,7 +119,7 @@ export function UserAuthForm({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn('grid gap-6', className)} {...props}>
|
||||
<div className={cn("grid gap-6", className)} {...props}>
|
||||
{authMethods.emailPassword && (
|
||||
<>
|
||||
<form onSubmit={handleSubmit} onChange={() => setErrors({})}>
|
||||
@@ -136,59 +128,57 @@ export function UserAuthForm({
|
||||
<div className="grid gap-1 relative">
|
||||
<UserIcon className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
|
||||
<Label className="sr-only" htmlFor="username">
|
||||
Username
|
||||
<Trans>Username</Trans>
|
||||
</Label>
|
||||
<Input
|
||||
autoFocus={true}
|
||||
id="username"
|
||||
name="username"
|
||||
required
|
||||
placeholder="username"
|
||||
placeholder={t`username`}
|
||||
type="username"
|
||||
autoCapitalize="none"
|
||||
autoComplete="username"
|
||||
autoCorrect="off"
|
||||
disabled={isLoading || isOauthLoading}
|
||||
className="pl-9"
|
||||
className="ps-9"
|
||||
/>
|
||||
{errors?.username && (
|
||||
<p className="px-1 text-xs text-red-600">{errors.username}</p>
|
||||
)}
|
||||
{errors?.username && <p className="px-1 text-xs text-red-600">{errors.username}</p>}
|
||||
</div>
|
||||
)}
|
||||
<div className="grid gap-1 relative">
|
||||
<MailIcon className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
|
||||
<Label className="sr-only" htmlFor="email">
|
||||
Email
|
||||
<Trans>Email</Trans>
|
||||
</Label>
|
||||
<Input
|
||||
id="email"
|
||||
name="email"
|
||||
required
|
||||
placeholder={isFirstRun ? 'email' : 'name@example.com'}
|
||||
placeholder={isFirstRun ? t`email` : "name@example.com"}
|
||||
type="email"
|
||||
autoCapitalize="none"
|
||||
autoComplete="email"
|
||||
autoCorrect="off"
|
||||
disabled={isLoading || isOauthLoading}
|
||||
className="pl-9"
|
||||
className="ps-9"
|
||||
/>
|
||||
{errors?.email && <p className="px-1 text-xs text-red-600">{errors.email}</p>}
|
||||
</div>
|
||||
<div className="grid gap-1 relative">
|
||||
<LockIcon className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
|
||||
<Label className="sr-only" htmlFor="pass">
|
||||
Password
|
||||
<Trans>Password</Trans>
|
||||
</Label>
|
||||
<Input
|
||||
id="pass"
|
||||
name="password"
|
||||
placeholder="password"
|
||||
placeholder={t`Password`}
|
||||
required
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
disabled={isLoading || isOauthLoading}
|
||||
className="pl-9"
|
||||
className="ps-9 lowercase"
|
||||
/>
|
||||
{errors?.password && <p className="px-1 text-xs text-red-600">{errors.password}</p>}
|
||||
</div>
|
||||
@@ -196,21 +186,19 @@ export function UserAuthForm({
|
||||
<div className="grid gap-1 relative">
|
||||
<LockIcon className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
|
||||
<Label className="sr-only" htmlFor="pass2">
|
||||
Confirm password
|
||||
<Trans>Confirm password</Trans>
|
||||
</Label>
|
||||
<Input
|
||||
id="pass2"
|
||||
name="passwordConfirm"
|
||||
placeholder="confirm password"
|
||||
placeholder={t`Confirm password`}
|
||||
required
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
disabled={isLoading || isOauthLoading}
|
||||
className="pl-9"
|
||||
className="ps-9 lowercase"
|
||||
/>
|
||||
{errors?.passwordConfirm && (
|
||||
<p className="px-1 text-xs text-red-600">{errors.passwordConfirm}</p>
|
||||
)}
|
||||
{errors?.passwordConfirm && <p className="px-1 text-xs text-red-600">{errors.passwordConfirm}</p>}
|
||||
</div>
|
||||
)}
|
||||
<div className="sr-only">
|
||||
@@ -220,11 +208,11 @@ export function UserAuthForm({
|
||||
</div>
|
||||
<button className={cn(buttonVariants())} disabled={isLoading}>
|
||||
{isLoading ? (
|
||||
<LoaderCircle className="mr-2 h-4 w-4 animate-spin" />
|
||||
<LoaderCircle className="me-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<LogInIcon className="mr-2 h-4 w-4" />
|
||||
<LogInIcon className="me-2 h-4 w-4" />
|
||||
)}
|
||||
{isFirstRun ? 'Create account' : 'Sign in'}
|
||||
{isFirstRun ? t`Create account` : t`Sign in`}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -235,7 +223,9 @@ export function UserAuthForm({
|
||||
<span className="w-full border-t" />
|
||||
</div>
|
||||
<div className="relative flex justify-center text-xs uppercase">
|
||||
<span className="bg-background px-2 text-muted-foreground">Or continue with</span>
|
||||
<span className="bg-background px-2 text-muted-foreground">
|
||||
<Trans>Or continue with</Trans>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -248,9 +238,9 @@ export function UserAuthForm({
|
||||
<button
|
||||
key={provider.name}
|
||||
type="button"
|
||||
className={cn(buttonVariants({ variant: 'outline' }), {
|
||||
'justify-self-center': !authMethods.emailPassword,
|
||||
'px-5': !authMethods.emailPassword,
|
||||
className={cn(buttonVariants({ variant: "outline" }), {
|
||||
"justify-self-center": !authMethods.emailPassword,
|
||||
"px-5": !authMethods.emailPassword,
|
||||
})}
|
||||
onClick={() => {
|
||||
setIsOauthLoading(true)
|
||||
@@ -263,9 +253,9 @@ export function UserAuthForm({
|
||||
if (!authWindow) {
|
||||
setIsOauthLoading(false)
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'Please enable pop-ups for this site',
|
||||
variant: 'destructive',
|
||||
title: t`Error`,
|
||||
description: t`Please enable pop-ups for this site`,
|
||||
variant: "destructive",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -273,7 +263,7 @@ export function UserAuthForm({
|
||||
authWindow.location.href = url
|
||||
}
|
||||
}
|
||||
pb.collection('users')
|
||||
pb.collection("users")
|
||||
.authWithOAuth2(oAuthOpts)
|
||||
.then(() => {
|
||||
$authenticated.set(pb.authStore.isValid)
|
||||
@@ -286,14 +276,14 @@ export function UserAuthForm({
|
||||
disabled={isLoading || isOauthLoading}
|
||||
>
|
||||
{isOauthLoading ? (
|
||||
<LoaderCircle className="mr-2 h-4 w-4 animate-spin" />
|
||||
<LoaderCircle className="me-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<img
|
||||
className="mr-2 h-4 w-4 dark:invert"
|
||||
className="me-2 h-4 w-4 dark:invert"
|
||||
src={`/static/${provider.name}.svg`}
|
||||
alt=""
|
||||
onError={(e) => {
|
||||
e.currentTarget.src = '/static/lock.svg'
|
||||
e.currentTarget.src = "/static/lock.svg"
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -307,26 +297,32 @@ export function UserAuthForm({
|
||||
// only show GitHub button / dialog during onboarding
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<button type="button" className={cn(buttonVariants({ variant: 'outline' }))}>
|
||||
<img className="mr-2 h-4 w-4 dark:invert" src="/static/github.svg" alt="" />
|
||||
<button type="button" className={cn(buttonVariants({ variant: "outline" }))}>
|
||||
<img className="me-2 h-4 w-4 dark:invert" src="/static/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>OAuth 2 / OIDC support</DialogTitle>
|
||||
<DialogTitle>
|
||||
<Trans>OAuth 2 / OIDC support</Trans>
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="text-primary/70 text-[0.95em] contents">
|
||||
<p>Beszel supports OpenID Connect and many OAuth2 authentication providers.</p>
|
||||
<p>
|
||||
Please view the{' '}
|
||||
<a
|
||||
href="https://github.com/henrygd/beszel/blob/main/readme.md#oauth--oidc-integration"
|
||||
className={cn(buttonVariants({ variant: 'link' }), 'p-0 h-auto')}
|
||||
>
|
||||
GitHub README
|
||||
</a>{' '}
|
||||
for instructions.
|
||||
<Trans>Beszel supports OpenID Connect and many OAuth2 authentication providers.</Trans>
|
||||
</p>
|
||||
<p>
|
||||
<Trans>
|
||||
Please see{" "}
|
||||
<a
|
||||
href="https://github.com/henrygd/beszel/blob/main/readme.md#oauth--oidc-integration"
|
||||
className={cn(buttonVariants({ variant: "link" }), "p-0 h-auto")}
|
||||
>
|
||||
the documentation
|
||||
</a>{" "}
|
||||
for instructions.
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
</DialogContent>
|
||||
@@ -338,7 +334,7 @@ export function UserAuthForm({
|
||||
href="/forgot-password"
|
||||
className="text-sm mx-auto hover:text-brand underline underline-offset-4 opacity-70 hover:opacity-100 transition-opacity"
|
||||
>
|
||||
Forgot password?
|
||||
<Trans>Forgot password?</Trans>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
import { LoaderCircle, MailIcon, SendHorizonalIcon } from 'lucide-react'
|
||||
import { Input } from '../ui/input'
|
||||
import { Label } from '../ui/label'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { toast } from '../ui/use-toast'
|
||||
import { buttonVariants } from '../ui/button'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { pb } from '@/lib/stores'
|
||||
import { Dialog, DialogHeader } from '../ui/dialog'
|
||||
import { DialogContent, DialogTrigger, DialogTitle } from '../ui/dialog'
|
||||
import { LoaderCircle, MailIcon, SendHorizonalIcon } from "lucide-react"
|
||||
import { Input } from "../ui/input"
|
||||
import { Label } from "../ui/label"
|
||||
import { useCallback, useState } from "react"
|
||||
import { toast } from "../ui/use-toast"
|
||||
import { buttonVariants } from "../ui/button"
|
||||
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({
|
||||
title: 'Login attempt failed',
|
||||
description: 'Please check your credentials and try again',
|
||||
variant: 'destructive',
|
||||
title: t`Login attempt failed`,
|
||||
description: t`Please check your credentials and try again`,
|
||||
variant: "destructive",
|
||||
})
|
||||
}
|
||||
|
||||
export default function ForgotPassword() {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false)
|
||||
const [email, setEmail] = useState('')
|
||||
const [email, setEmail] = useState("")
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
@@ -27,16 +28,16 @@ export default function ForgotPassword() {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
// console.log(email)
|
||||
await pb.collection('users').requestPasswordReset(email)
|
||||
await pb.collection("users").requestPasswordReset(email)
|
||||
toast({
|
||||
title: 'Password reset request received',
|
||||
description: `Check ${email} for a reset link.`,
|
||||
title: t`Password reset request received`,
|
||||
description: t`Check ${email} for a reset link.`,
|
||||
})
|
||||
} catch (e) {
|
||||
showLoginFaliedToast()
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
setEmail('')
|
||||
setEmail("")
|
||||
}
|
||||
},
|
||||
[email]
|
||||
@@ -49,7 +50,7 @@ export default function ForgotPassword() {
|
||||
<div className="grid gap-1 relative">
|
||||
<MailIcon className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
|
||||
<Label className="sr-only" htmlFor="email">
|
||||
Email
|
||||
<Trans>Email</Trans>
|
||||
</Label>
|
||||
<Input
|
||||
value={email}
|
||||
@@ -63,37 +64,40 @@ export default function ForgotPassword() {
|
||||
autoComplete="email"
|
||||
autoCorrect="off"
|
||||
disabled={isLoading}
|
||||
className="pl-9"
|
||||
className="ps-9"
|
||||
/>
|
||||
</div>
|
||||
<button className={cn(buttonVariants())} disabled={isLoading}>
|
||||
{isLoading ? (
|
||||
<LoaderCircle className="mr-2 h-4 w-4 animate-spin" />
|
||||
<LoaderCircle className="me-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<SendHorizonalIcon className="mr-2 h-4 w-4" />
|
||||
<SendHorizonalIcon className="me-2 h-4 w-4" />
|
||||
)}
|
||||
Reset password
|
||||
<Trans>Reset Password</Trans>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<button className="text-sm mx-auto hover:text-brand underline underline-offset-4 opacity-70 hover:opacity-100 transition-opacity">
|
||||
Command line instructions
|
||||
<Trans>Command line instructions</Trans>
|
||||
</button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-[33em]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Command line instructions</DialogTitle>
|
||||
<DialogTitle>
|
||||
<Trans>Command line instructions</Trans>
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<p className="text-primary/70 text-[0.95em] leading-relaxed">
|
||||
If you've lost the password to your admin account, you may reset it using the following
|
||||
command.
|
||||
<Trans>
|
||||
If you've lost the password to your admin account, you may reset it using the following command.
|
||||
</Trans>
|
||||
</p>
|
||||
<p className="text-primary/70 text-[0.95em] leading-relaxed">
|
||||
Then log into the backend and reset your user account password in the users table.
|
||||
<Trans>Then log into the backend and reset your user account password in the users table.</Trans>
|
||||
</p>
|
||||
<code className="bg-muted rounded-sm py-0.5 px-2.5 mr-auto text-sm">
|
||||
<code className="bg-muted rounded-sm py-0.5 px-2.5 me-auto text-sm">
|
||||
beszel admin update youremail@example.com newpassword
|
||||
</code>
|
||||
</DialogContent>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { UserAuthForm } from '@/components/login/auth-form'
|
||||
import { Logo } from '../logo'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { pb } from '@/lib/stores'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import ForgotPassword from './forgot-pass-form'
|
||||
import { $router } from '../router'
|
||||
import { AuthMethodsList } from 'pocketbase'
|
||||
import { UserAuthForm } from "@/components/login/auth-form"
|
||||
import { Logo } from "../logo"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { pb } from "@/lib/stores"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import ForgotPassword from "./forgot-pass-form"
|
||||
import { $router } from "../router"
|
||||
import { AuthMethodsList } from "pocketbase"
|
||||
import { t } from "@lingui/macro"
|
||||
|
||||
export default function () {
|
||||
const page = useStore($router)
|
||||
@@ -13,15 +14,15 @@ export default function () {
|
||||
const [authMethods, setAuthMethods] = useState<AuthMethodsList>()
|
||||
|
||||
useEffect(() => {
|
||||
document.title = 'Login / Beszel'
|
||||
document.title = t`Login` + " / Beszel"
|
||||
|
||||
pb.send('/api/beszel/first-run', {}).then(({ firstRun }) => {
|
||||
pb.send("/api/beszel/first-run", {}).then(({ firstRun }) => {
|
||||
setFirstRun(firstRun)
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
pb.collection('users')
|
||||
pb.collection("users")
|
||||
.listAuthMethods()
|
||||
.then((methods) => {
|
||||
setAuthMethods(methods)
|
||||
@@ -30,11 +31,11 @@ export default function () {
|
||||
|
||||
const subtitle = useMemo(() => {
|
||||
if (isFirstRun) {
|
||||
return 'Please create an admin account'
|
||||
} else if (page?.path === '/forgot-password') {
|
||||
return 'Enter email address to reset password'
|
||||
return t`Please create an admin account`
|
||||
} else if (page?.path === "/forgot-password") {
|
||||
return t`Enter email address to reset password`
|
||||
} else {
|
||||
return 'Please sign in to your account'
|
||||
return t`Please sign in to your account`
|
||||
}
|
||||
}, [isFirstRun, page])
|
||||
|
||||
@@ -44,7 +45,7 @@ export default function () {
|
||||
|
||||
return (
|
||||
<div className="min-h-svh grid items-center py-12">
|
||||
<div className="grid gap-5 w-full px-4 mx-auto" style={{ maxWidth: '22em' }}>
|
||||
<div className="grid gap-5 w-full px-4 mx-auto" style={{ maxWidth: "22em" }}>
|
||||
<div className="text-center">
|
||||
<h1 className="mb-3">
|
||||
<Logo className="h-7 fill-foreground mx-auto" />
|
||||
@@ -52,7 +53,7 @@ export default function () {
|
||||
</h1>
|
||||
<p className="text-sm text-muted-foreground">{subtitle}</p>
|
||||
</div>
|
||||
{page?.path === '/forgot-password' ? (
|
||||
{page?.path === "/forgot-password" ? (
|
||||
<ForgotPassword />
|
||||
) : (
|
||||
<UserAuthForm isFirstRun={isFirstRun} authMethods={authMethods} />
|
||||
|
||||
@@ -2,7 +2,16 @@ export function Logo({ className }: { className?: string }) {
|
||||
return (
|
||||
// Righteous
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 285 75" className={className}>
|
||||
<path d="M146.4 73.1h-30.5V59.8h30.5a3.2 3.2 0 0 0 2.3-1 3.2 3.2 0 0 0 1-2.3q0-.8-.3-1.3a1.5 1.5 0 0 0-.7-.6 4.7 4.7 0 0 0-1-.3l-1.3-.1h-13.9q-3.4 0-6.5-1.3-3-1.3-5.2-3.6a16.9 16.9 0 0 1-3.6-5.3 16.3 16.3 0 0 1-1.3-6.5 16.4 16.4 0 0 1 1.3-6.4q1.3-3.1 3.6-5.4 2.2-2.2 5.2-3.5a16.3 16.3 0 0 1 6.5-1.3h27v13.3h-27a3.2 3.2 0 0 0-2.3 1 3.2 3.2 0 0 0-1 2.3 3.3 3.3 0 0 0 1 2.4 3.3 3.3 0 0 0 1.2.8 3.2 3.2 0 0 0 1.1.2h13.9a18.1 18.1 0 0 1 6 1 17.3 17.3 0 0 1 .4.2q3 1.1 5.3 3.2a15.1 15.1 0 0 1 3.6 4.9 14.7 14.7 0 0 1 1.3 5.4 17.2 17.2 0 0 1 0 .9 16 16 0 0 1-1 5.8 15.4 15.4 0 0 1-.3.7 17.3 17.3 0 0 1-3.6 5.2 16.4 16.4 0 0 1-5.3 3.6 16.2 16.2 0 0 1-6.4 1.3Zm64.5-13.3v13.3h-43.6l22-39h-22V21h43.6l-22 39h22ZM35 73.1H0v-70h35q4.4 0 8.2 1.6a21.4 21.4 0 0 1 6.6 4.6q2.9 2.8 4.5 6.6 1.7 3.8 1.7 8.2a15.4 15.4 0 0 1-.3 3.2 17.6 17.6 0 0 1-.2.8 19.4 19.4 0 0 1-1.5 4 17 17 0 0 1-2.4 3.4 13.5 13.5 0 0 1-2.6 2.3 12.5 12.5 0 0 1-.4.3q1.7 1 3 2.5 1.4 1.6 2.4 3.5a18.3 18.3 0 0 1 1.5 4A17.4 17.4 0 0 1 56 51a15.3 15.3 0 0 1 0 1.1q0 4.3-1.7 8.2a21.4 21.4 0 0 1-4.5 6.6q-2.8 2.9-6.6 4.5-3.8 1.7-8.2 1.7Zm76-43L86 60.4l1.5.3a16.7 16.7 0 0 0 1.6 0q2 0 3.8-.4 1.8-.6 3.4-1.6 1.6-1 2.8-2.4a12.8 12.8 0 0 0 2-3.2l9.8 9.8q-1.9 2.6-4.3 4.7a27 27 0 0 1-5.2 3.6 26.1 26.1 0 0 1-6 2.2 26.8 26.8 0 0 1-6.3.8 26.4 26.4 0 0 1-10.4-2 26.2 26.2 0 0 1-8.5-5.8 26.7 26.7 0 0 1-5.5-8.3 30.4 30.4 0 0 1-.2-.4q-2.1-5-2.1-11.1a31.9 31.9 0 0 1 .7-7 27 27 0 0 1 1.4-4.3 27 27 0 0 1 3.8-6.6 24.5 24.5 0 0 1 2-2.2 26 26 0 0 1 8.4-5.6 27 27 0 0 1 10.4-2 26.3 26.3 0 0 1 6.4.8 26.9 26.9 0 0 1 6 2.2q2.7 1.5 5.2 3.6 2.4 2.1 4.3 4.8Zm152.3 0-25 30.2 1.5.3a16.7 16.7 0 0 0 1.6 0q2 0 3.8-.4 1.8-.6 3.4-1.6 1.5-1 2.8-2.4a12.8 12.8 0 0 0 2-3.2l9.8 9.8q-1.9 2.6-4.3 4.7a27 27 0 0 1-5.2 3.6 26.1 26.1 0 0 1-6 2.2 26.8 26.8 0 0 1-6.3.8 26.4 26.4 0 0 1-10.4-2 26.2 26.2 0 0 1-8.5-5.8A26.7 26.7 0 0 1 217 58a30.4 30.4 0 0 1-.2-.4q-2.1-5-2.1-11.1a31.9 31.9 0 0 1 .7-7 27 27 0 0 1 1.4-4.3 27 27 0 0 1 3.8-6.6 24.5 24.5 0 0 1 2-2.2 26 26 0 0 1 8.4-5.6 27 27 0 0 1 10.4-2 26.3 26.3 0 0 1 6.4.8 26.9 26.9 0 0 1 6 2.2q2.7 1.5 5.2 3.6 2.4 2.1 4.3 4.8ZM283.4 0v73.1H270V0h13.4ZM14 17v14.1h21a7 7 0 0 0 2.3-.4 6.6 6.6 0 0 0 .4-.1Q39 30 40 29a6.9 6.9 0 0 0 1.5-2.3q.5-1.3.5-2.7a7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.5q-.6-1.2-1.5-2.2a7 7 0 0 0-2.3-1.5 6.9 6.9 0 0 0-2.5-.5 7.9 7.9 0 0 0-.2 0H14Zm0 28.1v14h21a7 7 0 0 0 2.3-.4 6.6 6.6 0 0 0 .4-.2Q39 58 40 57.1a7 7 0 0 0 1.5-2.3 6.9 6.9 0 0 0 .5-2.5 7.9 7.9 0 0 0 0-.2 7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 48 40 47a7 7 0 0 0-2.3-1.4 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Zm63.3 8.3 15.5-20.6a8 8 0 0 0-1.4-.4 7 7 0 0 0-.4 0 17.2 17.2 0 0 0-1.6-.1 19.2 19.2 0 0 0-.3 0 13.3 13.3 0 0 0-5.1 1q-2.5 1-4.2 2.8a13.1 13.1 0 0 0-2.5 3.6 15.5 15.5 0 0 0-.3.9 14.7 14.7 0 0 0-1 3.5 18.7 18.7 0 0 0 0 2.4 17.6 17.6 0 0 0 0 .7v.8a29.4 29.4 0 0 0 0 .1 19.2 19.2 0 0 0 .2 2 20.2 20.2 0 0 0 .4 1.6 18.6 18.6 0 0 0 0 .2 7.5 7.5 0 0 0 .4.9 6 6 0 0 0 .3.6Zm152.3 0L245 32.8a8 8 0 0 0-1.4-.4 7 7 0 0 0-.4 0 17.2 17.2 0 0 0-1.6-.1 19.2 19.2 0 0 0-.3 0 13.3 13.3 0 0 0-5.1 1q-2.5 1-4.2 2.8a13.1 13.1 0 0 0-2.5 3.6 15.5 15.5 0 0 0-.4.9 14.7 14.7 0 0 0-.8 3.5 18.7 18.7 0 0 0-.2 2.4 17.6 17.6 0 0 0 0 .7v.8a29.4 29.4 0 0 0 .1.1 19.2 19.2 0 0 0 .2 2 20.2 20.2 0 0 0 .4 1.6 18.6 18.6 0 0 0 0 .2 7.5 7.5 0 0 0 .4.9 6 6 0 0 0 .3.6Z" />
|
||||
{/* <defs>
|
||||
<linearGradient id="gradient" x1="0%" y1="20%" x2="100%" y2="120%">
|
||||
<stop offset="0%" style={{ stopColor: "#747bff" }} />
|
||||
<stop offset="100%" style={{ stopColor: "#24eb5c" }} />
|
||||
</linearGradient>
|
||||
</defs> */}
|
||||
<path
|
||||
// fill="url(#gradient)"
|
||||
d="M146.4 73.1h-30.5V59.8h30.5a3.2 3.2 0 0 0 2.3-1 3.2 3.2 0 0 0 1-2.3q0-.8-.3-1.3a1.5 1.5 0 0 0-.7-.6 4.7 4.7 0 0 0-1-.3l-1.3-.1h-13.9q-3.4 0-6.5-1.3-3-1.3-5.2-3.6a16.9 16.9 0 0 1-3.6-5.3 16.3 16.3 0 0 1-1.3-6.5 16.4 16.4 0 0 1 1.3-6.4q1.3-3.1 3.6-5.4 2.2-2.2 5.2-3.5a16.3 16.3 0 0 1 6.5-1.3h27v13.3h-27a3.2 3.2 0 0 0-2.3 1 3.2 3.2 0 0 0-1 2.3 3.3 3.3 0 0 0 1 2.4 3.3 3.3 0 0 0 1.2.8 3.2 3.2 0 0 0 1.1.2h13.9a18.1 18.1 0 0 1 6 1 17.3 17.3 0 0 1 .4.2q3 1.1 5.3 3.2a15.1 15.1 0 0 1 3.6 4.9 14.7 14.7 0 0 1 1.3 5.4 17.2 17.2 0 0 1 0 .9 16 16 0 0 1-1 5.8 15.4 15.4 0 0 1-.3.7 17.3 17.3 0 0 1-3.6 5.2 16.4 16.4 0 0 1-5.3 3.6 16.2 16.2 0 0 1-6.4 1.3Zm64.5-13.3v13.3h-43.6l22-39h-22V21h43.6l-22 39h22ZM35 73.1H0v-70h35q4.4 0 8.2 1.6a21.4 21.4 0 0 1 6.6 4.6q2.9 2.8 4.5 6.6 1.7 3.8 1.7 8.2a15.4 15.4 0 0 1-.3 3.2 17.6 17.6 0 0 1-.2.8 19.4 19.4 0 0 1-1.5 4 17 17 0 0 1-2.4 3.4 13.5 13.5 0 0 1-2.6 2.3 12.5 12.5 0 0 1-.4.3q1.7 1 3 2.5 1.4 1.6 2.4 3.5a18.3 18.3 0 0 1 1.5 4A17.4 17.4 0 0 1 56 51a15.3 15.3 0 0 1 0 1.1q0 4.3-1.7 8.2a21.4 21.4 0 0 1-4.5 6.6q-2.8 2.9-6.6 4.5-3.8 1.7-8.2 1.7Zm76-43L86 60.4l1.5.3a16.7 16.7 0 0 0 1.6 0q2 0 3.8-.4 1.8-.6 3.4-1.6 1.6-1 2.8-2.4a12.8 12.8 0 0 0 2-3.2l9.8 9.8q-1.9 2.6-4.3 4.7a27 27 0 0 1-5.2 3.6 26.1 26.1 0 0 1-6 2.2 26.8 26.8 0 0 1-6.3.8 26.4 26.4 0 0 1-10.4-2 26.2 26.2 0 0 1-8.5-5.8 26.7 26.7 0 0 1-5.5-8.3 30.4 30.4 0 0 1-.2-.4q-2.1-5-2.1-11.1a31.9 31.9 0 0 1 .7-7 27 27 0 0 1 1.4-4.3 27 27 0 0 1 3.8-6.6 24.5 24.5 0 0 1 2-2.2 26 26 0 0 1 8.4-5.6 27 27 0 0 1 10.4-2 26.3 26.3 0 0 1 6.4.8 26.9 26.9 0 0 1 6 2.2q2.7 1.5 5.2 3.6 2.4 2.1 4.3 4.8Zm152.3 0-25 30.2 1.5.3a16.7 16.7 0 0 0 1.6 0q2 0 3.8-.4 1.8-.6 3.4-1.6 1.5-1 2.8-2.4a12.8 12.8 0 0 0 2-3.2l9.8 9.8q-1.9 2.6-4.3 4.7a27 27 0 0 1-5.2 3.6 26.1 26.1 0 0 1-6 2.2 26.8 26.8 0 0 1-6.3.8 26.4 26.4 0 0 1-10.4-2 26.2 26.2 0 0 1-8.5-5.8A26.7 26.7 0 0 1 217 58a30.4 30.4 0 0 1-.2-.4q-2.1-5-2.1-11.1a31.9 31.9 0 0 1 .7-7 27 27 0 0 1 1.4-4.3 27 27 0 0 1 3.8-6.6 24.5 24.5 0 0 1 2-2.2 26 26 0 0 1 8.4-5.6 27 27 0 0 1 10.4-2 26.3 26.3 0 0 1 6.4.8 26.9 26.9 0 0 1 6 2.2q2.7 1.5 5.2 3.6 2.4 2.1 4.3 4.8ZM283.4 0v73.1H270V0h13.4ZM14 17v14.1h21a7 7 0 0 0 2.3-.4 6.6 6.6 0 0 0 .4-.1Q39 30 40 29a6.9 6.9 0 0 0 1.5-2.3q.5-1.3.5-2.7a7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.5q-.6-1.2-1.5-2.2a7 7 0 0 0-2.3-1.5 6.9 6.9 0 0 0-2.5-.5 7.9 7.9 0 0 0-.2 0H14Zm0 28.1v14h21a7 7 0 0 0 2.3-.4 6.6 6.6 0 0 0 .4-.2Q39 58 40 57.1a7 7 0 0 0 1.5-2.3 6.9 6.9 0 0 0 .5-2.5 7.9 7.9 0 0 0 0-.2 7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 48 40 47a7 7 0 0 0-2.3-1.4 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Zm63.3 8.3 15.5-20.6a8 8 0 0 0-1.4-.4 7 7 0 0 0-.4 0 17.2 17.2 0 0 0-1.6-.1 19.2 19.2 0 0 0-.3 0 13.3 13.3 0 0 0-5.1 1q-2.5 1-4.2 2.8a13.1 13.1 0 0 0-2.5 3.6 15.5 15.5 0 0 0-.3.9 14.7 14.7 0 0 0-1 3.5 18.7 18.7 0 0 0 0 2.4 17.6 17.6 0 0 0 0 .7v.8a29.4 29.4 0 0 0 0 .1 19.2 19.2 0 0 0 .2 2 20.2 20.2 0 0 0 .4 1.6 18.6 18.6 0 0 0 0 .2 7.5 7.5 0 0 0 .4.9 6 6 0 0 0 .3.6Zm152.3 0L245 32.8a8 8 0 0 0-1.4-.4 7 7 0 0 0-.4 0 17.2 17.2 0 0 0-1.6-.1 19.2 19.2 0 0 0-.3 0 13.3 13.3 0 0 0-5.1 1q-2.5 1-4.2 2.8a13.1 13.1 0 0 0-2.5 3.6 15.5 15.5 0 0 0-.4.9 14.7 14.7 0 0 0-.8 3.5 18.7 18.7 0 0 0-.2 2.4 17.6 17.6 0 0 0 0 .7v.8a29.4 29.4 0 0 0 .1.1 19.2 19.2 0 0 0 .2 2 20.2 20.2 0 0 0 .4 1.6 18.6 18.6 0 0 0 0 .2 7.5 7.5 0 0 0 .4.9 6 6 0 0 0 .3.6Z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,39 +1,54 @@
|
||||
import { LaptopIcon, MoonStarIcon, SunIcon } from 'lucide-react'
|
||||
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 { 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 { setTheme } = useTheme()
|
||||
const { theme, setTheme } = useTheme()
|
||||
|
||||
const options = [
|
||||
{
|
||||
theme: "light",
|
||||
Icon: SunIcon,
|
||||
label: <Trans comment="Light theme">Light</Trans>,
|
||||
},
|
||||
{
|
||||
theme: "dark",
|
||||
Icon: MoonStarIcon,
|
||||
label: <Trans comment="Dark theme">Dark</Trans>,
|
||||
},
|
||||
{
|
||||
theme: "system",
|
||||
Icon: LaptopIcon,
|
||||
label: <Trans comment="System theme">System</Trans>,
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant={'ghost'} size="icon">
|
||||
<Button variant={"ghost"} size="icon" aria-label={t`Toggle theme`}>
|
||||
<SunIcon className="h-[1.2rem] w-[1.2rem] dark:opacity-0" />
|
||||
<MoonStarIcon className="absolute h-[1.2rem] w-[1.2rem] opacity-0 dark:opacity-100" />
|
||||
<span className="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem onClick={() => setTheme('light')}>
|
||||
<SunIcon className="mr-2.5 h-4 w-4" />
|
||||
Light
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setTheme('dark')}>
|
||||
<MoonStarIcon className="mr-2.5 h-4 w-4" />
|
||||
Dark
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setTheme('system')}>
|
||||
<LaptopIcon className="mr-2.5 h-4 w-4" />
|
||||
System
|
||||
</DropdownMenuItem>
|
||||
{options.map((opt) => {
|
||||
const selected = opt.theme === theme
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={opt.theme}
|
||||
className={cn("px-2.5", selected ? "font-semibold" : "")}
|
||||
onClick={() => setTheme(opt.theme as "dark" | "light" | "system")}
|
||||
>
|
||||
<opt.Icon className={cn("me-2 h-4 w-4 opacity-80", selected && "opacity-100")} />
|
||||
{opt.label}
|
||||
</DropdownMenuItem>
|
||||
)
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
|
||||
154
beszel/site/src/components/navbar.tsx
Normal file
154
beszel/site/src/components/navbar.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
import { useState, lazy, Suspense } from "react"
|
||||
import { Button, buttonVariants } from "@/components/ui/button"
|
||||
import {
|
||||
DatabaseBackupIcon,
|
||||
LockKeyholeIcon,
|
||||
LogOutIcon,
|
||||
LogsIcon,
|
||||
SearchIcon,
|
||||
ServerIcon,
|
||||
SettingsIcon,
|
||||
UserIcon,
|
||||
UsersIcon,
|
||||
} from "lucide-react"
|
||||
import { Link } from "./router"
|
||||
import { LangToggle } from "./lang-toggle"
|
||||
import { ModeToggle } from "./mode-toggle"
|
||||
import { Logo } from "./logo"
|
||||
import { pb } from "@/lib/stores"
|
||||
import { cn, isReadOnlyUser, isAdmin } from "@/lib/utils"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
import { AddSystemButton } from "./add-system"
|
||||
import { Trans } from "@lingui/macro"
|
||||
|
||||
const CommandPalette = lazy(() => import("./command-palette"))
|
||||
|
||||
const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0
|
||||
|
||||
export default function Navbar() {
|
||||
return (
|
||||
<div className="flex items-center h-14 md:h-16 bg-card px-4 pe-3 sm:px-6 border bt-0 rounded-md my-4">
|
||||
<Link href="/" aria-label="Home" className="p-2 ps-0 me-3">
|
||||
<Logo className="h-[1.1rem] md:h-5 fill-foreground" />
|
||||
</Link>
|
||||
<SearchButton />
|
||||
|
||||
<div className="flex items-center ms-auto">
|
||||
<LangToggle />
|
||||
<ModeToggle />
|
||||
<Link
|
||||
href="/settings/general"
|
||||
aria-label="Settings"
|
||||
className={cn("", buttonVariants({ variant: "ghost", size: "icon" }))}
|
||||
>
|
||||
<SettingsIcon className="h-[1.2rem] w-[1.2rem]" />
|
||||
</Link>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button aria-label="User Actions" className={cn("", buttonVariants({ variant: "ghost", size: "icon" }))}>
|
||||
<UserIcon className="h-[1.2rem] w-[1.2rem]" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align={isReadOnlyUser() ? "end" : "center"} className="min-w-44">
|
||||
<DropdownMenuLabel>{pb.authStore.model?.email}</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
{isAdmin() && (
|
||||
<>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href="/_/" target="_blank">
|
||||
<UsersIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Users</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href="/_/#/collections?collectionId=2hz5ncl8tizk5nx" target="_blank">
|
||||
<ServerIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Systems</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href="/_/#/logs" target="_blank">
|
||||
<LogsIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Logs</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href="/_/#/settings/backups" target="_blank">
|
||||
<DatabaseBackupIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Backups</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href="/_/#/settings/auth-providers" target="_blank">
|
||||
<LockKeyholeIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Auth Providers</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuItem onSelect={() => pb.authStore.clear()}>
|
||||
<LogOutIcon className="me-2.5 h-4 w-4" />
|
||||
<span>
|
||||
<Trans>Log Out</Trans>
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<AddSystemButton className="ms-2" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function SearchButton() {
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const Kbd = ({ children }: { children: React.ReactNode }) => (
|
||||
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100">
|
||||
{children}
|
||||
</kbd>
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="hidden md:block text-sm text-muted-foreground px-4"
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<SearchIcon className="me-1.5 h-4 w-4" />
|
||||
<Trans>Search</Trans>
|
||||
<span className="flex items-center ms-3.5">
|
||||
<Kbd>{isMac ? "⌘" : "Ctrl"}</Kbd>
|
||||
<Kbd>K</Kbd>
|
||||
</span>
|
||||
</span>
|
||||
</Button>
|
||||
<Suspense>
|
||||
<CommandPalette open={open} setOpen={setOpen} />
|
||||
</Suspense>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
import { createRouter } from '@nanostores/router'
|
||||
import { createRouter } from "@nanostores/router"
|
||||
|
||||
export const $router = createRouter(
|
||||
{
|
||||
home: '/',
|
||||
server: '/system/:name',
|
||||
settings: '/settings/:name?',
|
||||
home: "/",
|
||||
server: "/system/:name",
|
||||
settings: "/settings/:name?",
|
||||
forgot_password: "/forgot-password",
|
||||
},
|
||||
{ links: false }
|
||||
)
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { Suspense, lazy, useEffect, useMemo, useState } from 'react'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../ui/card'
|
||||
import { $alerts, $hubVersion, $systems, pb } from '@/lib/stores'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { GithubIcon } from 'lucide-react'
|
||||
import { Separator } from '../ui/separator'
|
||||
import { alertInfo, updateRecordList, updateSystemList } from '@/lib/utils'
|
||||
import { AlertRecord, SystemRecord } from '@/types'
|
||||
import { Input } from '../ui/input'
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
|
||||
import { Link } from '../router'
|
||||
import { Suspense, lazy, useEffect, useMemo } from "react"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"
|
||||
import { $alerts, $hubVersion, $systems, pb } from "@/lib/stores"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { GithubIcon } from "lucide-react"
|
||||
import { Separator } from "../ui/separator"
|
||||
import { alertInfo, updateRecordList, updateSystemList } from "@/lib/utils"
|
||||
import { AlertRecord, SystemRecord } from "@/types"
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||
import { Link } from "../router"
|
||||
import { Plural, t, Trans } from "@lingui/macro"
|
||||
|
||||
const SystemsTable = lazy(() => import('../systems-table/systems-table'))
|
||||
const SystemsTable = lazy(() => import("../systems-table/systems-table"))
|
||||
|
||||
export default function () {
|
||||
export default function Home() {
|
||||
const hubVersion = useStore($hubVersion)
|
||||
const [filter, setFilter] = useState<string>()
|
||||
|
||||
const alerts = useStore($alerts)
|
||||
const systems = useStore($systems)
|
||||
|
||||
@@ -32,21 +32,21 @@ export default function () {
|
||||
}, [alerts])
|
||||
|
||||
useEffect(() => {
|
||||
document.title = 'Dashboard / Beszel'
|
||||
document.title = t`Dashboard` + " / Beszel"
|
||||
|
||||
// make sure we have the latest list of systems
|
||||
updateSystemList()
|
||||
|
||||
// subscribe to real time updates for systems / alerts
|
||||
pb.collection<SystemRecord>('systems').subscribe('*', (e) => {
|
||||
pb.collection<SystemRecord>("systems").subscribe("*", (e) => {
|
||||
updateRecordList(e, $systems)
|
||||
})
|
||||
// todo: add toast if new triggered alert comes in
|
||||
pb.collection<AlertRecord>('alerts').subscribe('*', (e) => {
|
||||
pb.collection<AlertRecord>("alerts").subscribe("*", (e) => {
|
||||
updateRecordList(e, $alerts)
|
||||
})
|
||||
return () => {
|
||||
pb.collection('systems').unsubscribe('*')
|
||||
pb.collection("systems").unsubscribe("*")
|
||||
// pb.collection('alerts').unsubscribe('*')
|
||||
}
|
||||
}, [])
|
||||
@@ -58,7 +58,9 @@ export default function () {
|
||||
<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>Active Alerts</CardTitle>
|
||||
<CardTitle>
|
||||
<Trans>Active Alerts</Trans>
|
||||
</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="max-sm:p-2">
|
||||
@@ -73,11 +75,13 @@ export default function () {
|
||||
>
|
||||
<info.icon className="h-4 w-4" />
|
||||
<AlertTitle>
|
||||
{alert.sysname} {info.name}
|
||||
{alert.sysname} {info.name().toLowerCase().replace("cpu", "CPU")}
|
||||
</AlertTitle>
|
||||
<AlertDescription>
|
||||
Exceeds {alert.value}
|
||||
{info.unit} average in last {alert.min} min
|
||||
<Trans>
|
||||
Exceeds {alert.value}
|
||||
{info.unit} in last <Plural value={alert.min} one="# minute" other="# minutes" />
|
||||
</Trans>
|
||||
</AlertDescription>
|
||||
<Link
|
||||
href={`/system/${encodeURIComponent(alert.sysname!)}`}
|
||||
@@ -92,35 +96,12 @@ export default function () {
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
<Card>
|
||||
<CardHeader className="pb-5 px-2 sm:px-6 max-sm:pt-5 max-sm:pb-1">
|
||||
<div className="grid md:flex gap-3 w-full items-end">
|
||||
<div className="px-2 sm:px-1">
|
||||
<CardTitle className="mb-2.5">All Systems</CardTitle>
|
||||
<CardDescription>
|
||||
Updated in real time. Press{' '}
|
||||
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-0.5 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100">
|
||||
<span className="text-xs">⌘</span>K
|
||||
</kbd>{' '}
|
||||
to open the command palette.
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Input
|
||||
placeholder="Filter..."
|
||||
onChange={(e) => setFilter(e.target.value)}
|
||||
className="w-full md:w-56 lg:w-80 ml-auto px-4"
|
||||
/>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="max-sm:p-2">
|
||||
<Suspense>
|
||||
<SystemsTable filter={filter} />
|
||||
</Suspense>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Suspense>
|
||||
<SystemsTable />
|
||||
</Suspense>
|
||||
|
||||
{hubVersion && (
|
||||
<div className="flex gap-1.5 justify-end items-center pr-3 sm:pr-6 mt-3.5 text-xs opacity-80">
|
||||
<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"
|
||||
target="_blank"
|
||||
|
||||
97
beszel/site/src/components/routes/settings/config-yaml.tsx
Normal file
97
beszel/site/src/components/routes/settings/config-yaml.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import { isAdmin } from "@/lib/utils"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { redirectPage } from "@nanostores/router"
|
||||
import { $router } from "@/components/router"
|
||||
import { AlertCircleIcon, FileSlidersIcon, LoaderCircleIcon } from "lucide-react"
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||
import { pb } from "@/lib/stores"
|
||||
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>("")
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const ButtonIcon = isLoading ? LoaderCircleIcon : FileSlidersIcon
|
||||
|
||||
async function fetchConfig() {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
const { config } = await pb.send<{ config: string }>("/api/beszel/config-yaml", {})
|
||||
setConfigContent(config)
|
||||
} catch (error: any) {
|
||||
toast({
|
||||
title: t`Error`,
|
||||
description: error.message,
|
||||
variant: "destructive",
|
||||
})
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAdmin()) {
|
||||
redirectPage($router, "settings", { name: "general" })
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<h3 className="text-xl font-medium mb-2">
|
||||
<Trans>YAML Configuration</Trans>
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
<Trans>Export your current systems configuration.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
<Separator className="my-4" />
|
||||
<div className="space-y-2">
|
||||
<div className="mb-4">
|
||||
<p className="text-sm text-muted-foreground leading-relaxed my-1">
|
||||
<Trans>
|
||||
Systems may be managed in a <code className="bg-muted rounded-sm px-1 text-primary">config.yml</code> file
|
||||
inside your data directory.
|
||||
</Trans>
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
<Trans>
|
||||
On each restart, systems in the database will be updated to match the systems defined in the file.
|
||||
</Trans>
|
||||
</p>
|
||||
<Alert className="my-4 border-destructive text-destructive w-auto table md:pe-6">
|
||||
<AlertCircleIcon className="h-4 w-4 stroke-destructive" />
|
||||
<AlertTitle>
|
||||
<Trans>Caution - potential data loss</Trans>
|
||||
</AlertTitle>
|
||||
<AlertDescription>
|
||||
<p>
|
||||
<Trans>
|
||||
Existing systems not defined in <code>config.yml</code> will be deleted. Please make regular backups.
|
||||
</Trans>
|
||||
</p>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
{configContent && (
|
||||
<Textarea
|
||||
dir="ltr"
|
||||
autoFocus
|
||||
defaultValue={configContent}
|
||||
spellCheck="false"
|
||||
rows={Math.min(25, configContent.split("\n").length)}
|
||||
className="font-mono whitespace-pre"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Separator className="my-5" />
|
||||
<Button type="button" className="mt-2 flex items-center gap-1" onClick={fetchConfig} disabled={isLoading}>
|
||||
<ButtonIcon className={clsx("h-4 w-4 me-0.5", isLoading && "animate-spin")} />
|
||||
<Trans>Export configuration</Trans>
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { chartTimeData } from '@/lib/utils'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { LoaderCircleIcon, SaveIcon } from 'lucide-react'
|
||||
import { UserSettings } from '@/types'
|
||||
import { saveSettings } from './layout'
|
||||
import { useState } from 'react'
|
||||
// import { Input } from '@/components/ui/input'
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||
import { chartTimeData } from "@/lib/utils"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
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 { setLang } from "@/lib/i18n"
|
||||
|
||||
export default function SettingsProfilePage({ userSettings }: { userSettings: UserSettings }) {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const { i18n } = useLingui()
|
||||
|
||||
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault()
|
||||
@@ -30,79 +29,81 @@ export default function SettingsProfilePage({ userSettings }: { userSettings: Us
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<h3 className="text-xl font-medium mb-2">General</h3>
|
||||
<h3 className="text-xl font-medium mb-2">
|
||||
<Trans>General</Trans>
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
Change general application options.
|
||||
<Trans>Change general application options.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
<Separator className="my-4" />
|
||||
<form onSubmit={handleSubmit} className="space-y-5">
|
||||
{/* <Separator />
|
||||
<div className="space-y-2">
|
||||
<div className="mb-4">
|
||||
<h3 className="mb-1 text-lg font-medium">Language</h3>
|
||||
<h3 className="mb-1 text-lg font-medium flex items-center gap-2">
|
||||
<LanguagesIcon className="h-4 w-4" />
|
||||
<Trans>Language</Trans>
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
Internationalization will be added in a future release. Please see the{' '}
|
||||
<a href="#" className="link" target="_blank">
|
||||
discussion on GitHub
|
||||
</a>{' '}
|
||||
for more details.
|
||||
<Trans>
|
||||
Want to help us make our translations even better? Check out{" "}
|
||||
<a href="https://crowdin.com/project/beszel" className="link" target="_blank" rel="noopener noreferrer">
|
||||
Crowdin
|
||||
</a>{" "}
|
||||
for more details.
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
<Label className="block" htmlFor="lang">
|
||||
Preferred language
|
||||
<Trans>Preferred Language</Trans>
|
||||
</Label>
|
||||
<Select defaultValue="en">
|
||||
<Select value={i18n.locale} onValueChange={(lang: string) => dynamicActivate(lang)}>
|
||||
<SelectTrigger id="lang">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="en">English</SelectItem>
|
||||
{languages.map((lang) => (
|
||||
<SelectItem key={lang.lang} value={lang.lang}>
|
||||
<span className="me-2.5">{lang.e}</span>
|
||||
{lang.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div> */}
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="space-y-2">
|
||||
<div className="mb-4">
|
||||
<h3 className="mb-1 text-lg font-medium">Chart options</h3>
|
||||
<h3 className="mb-1 text-lg font-medium">
|
||||
<Trans>Chart options</Trans>
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
Adjust display options for charts.
|
||||
<Trans>Adjust display options for charts.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
<Label className="block" htmlFor="chartTime">
|
||||
Default time period
|
||||
<Trans>Default time period</Trans>
|
||||
</Label>
|
||||
<Select
|
||||
name="chartTime"
|
||||
key={userSettings.chartTime}
|
||||
defaultValue={userSettings.chartTime}
|
||||
>
|
||||
<Select name="chartTime" key={userSettings.chartTime} defaultValue={userSettings.chartTime}>
|
||||
<SelectTrigger id="chartTime">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{Object.entries(chartTimeData).map(([value, { label }]) => (
|
||||
<SelectItem key={label} value={value}>
|
||||
{label}
|
||||
<SelectItem key={value} value={value}>
|
||||
{label()}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-[0.8rem] text-muted-foreground">
|
||||
Sets the default time range for charts when a system is viewed.
|
||||
<Trans>Sets the default time range for charts when a system is viewed.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
<Separator />
|
||||
<Button
|
||||
type="submit"
|
||||
className="flex items-center gap-1.5 disabled:opacity-100"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<LoaderCircleIcon className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<SaveIcon className="h-4 w-4" />
|
||||
)}
|
||||
Save settings
|
||||
<Button type="submit" className="flex items-center gap-1.5 disabled:opacity-100" disabled={isLoading}>
|
||||
{isLoading ? <LoaderCircleIcon className="h-4 w-4 animate-spin" /> : <SaveIcon className="h-4 w-4" />}
|
||||
<Trans>Save Settings</Trans>
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,38 +1,28 @@
|
||||
import { useEffect } from 'react'
|
||||
import { Separator } from '../../ui/separator'
|
||||
import { SidebarNav } from './sidebar-nav.tsx'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card.tsx'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { $router } from '@/components/router.tsx'
|
||||
import { redirectPage } from '@nanostores/router'
|
||||
import { BellIcon, SettingsIcon } from 'lucide-react'
|
||||
import { $userSettings, pb } from '@/lib/stores.ts'
|
||||
import { toast } from '@/components/ui/use-toast.ts'
|
||||
import { UserSettings } from '@/types.js'
|
||||
import General from './general.tsx'
|
||||
import Notifications from './notifications.tsx'
|
||||
|
||||
const sidebarNavItems = [
|
||||
{
|
||||
title: 'General',
|
||||
href: '/settings/general',
|
||||
icon: SettingsIcon,
|
||||
},
|
||||
{
|
||||
title: 'Notifications',
|
||||
href: '/settings/notifications',
|
||||
icon: BellIcon,
|
||||
},
|
||||
]
|
||||
import { useEffect } from "react"
|
||||
import { Separator } from "../../ui/separator"
|
||||
import { SidebarNav } from "./sidebar-nav.tsx"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card.tsx"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { $router } from "@/components/router.tsx"
|
||||
import { redirectPage } from "@nanostores/router"
|
||||
import { BellIcon, FileSlidersIcon, SettingsIcon } from "lucide-react"
|
||||
import { $userSettings, pb } from "@/lib/stores.ts"
|
||||
import { toast } from "@/components/ui/use-toast.ts"
|
||||
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"
|
||||
|
||||
export async function saveSettings(newSettings: Partial<UserSettings>) {
|
||||
try {
|
||||
// get fresh copy of settings
|
||||
const req = await pb.collection('user_settings').getFirstListItem('', {
|
||||
fields: 'id,settings',
|
||||
const req = await pb.collection("user_settings").getFirstListItem("", {
|
||||
fields: "id,settings",
|
||||
})
|
||||
// update user settings
|
||||
const updatedSettings = await pb.collection('user_settings').update(req.id, {
|
||||
const updatedSettings = await pb.collection("user_settings").update(req.id, {
|
||||
settings: {
|
||||
...req.settings,
|
||||
...newSettings,
|
||||
@@ -40,35 +30,60 @@ export async function saveSettings(newSettings: Partial<UserSettings>) {
|
||||
})
|
||||
$userSettings.set(updatedSettings.settings)
|
||||
toast({
|
||||
title: 'Settings saved',
|
||||
description: 'Your user settings have been updated.',
|
||||
title: t`Settings saved`,
|
||||
description: t`Your user settings have been updated.`,
|
||||
})
|
||||
} catch (e) {
|
||||
// console.error('update settings', e)
|
||||
toast({
|
||||
title: 'Failed to save settings',
|
||||
description: 'Check logs for more details.',
|
||||
variant: 'destructive',
|
||||
title: t`Failed to save settings`,
|
||||
description: t`Check logs for more details.`,
|
||||
variant: "destructive",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default function SettingsLayout() {
|
||||
const { _ } = useLingui()
|
||||
|
||||
const sidebarNavItems = [
|
||||
{
|
||||
title: _(t({ message: `General`, comment: "Context: General settings" })),
|
||||
href: "/settings/general",
|
||||
icon: SettingsIcon,
|
||||
},
|
||||
{
|
||||
title: t`Notifications`,
|
||||
href: "/settings/notifications",
|
||||
icon: BellIcon,
|
||||
},
|
||||
{
|
||||
title: t`YAML Config`,
|
||||
href: "/settings/config",
|
||||
icon: FileSlidersIcon,
|
||||
admin: true,
|
||||
},
|
||||
]
|
||||
|
||||
const page = useStore($router)
|
||||
|
||||
useEffect(() => {
|
||||
document.title = 'Settings / Beszel'
|
||||
document.title = t`Settings` + " / Beszel"
|
||||
// redirect to account page if no page is specified
|
||||
if (page?.path === '/settings') {
|
||||
redirectPage($router, 'settings', { name: 'general' })
|
||||
if (page?.path === "/settings") {
|
||||
redirectPage($router, "settings", { name: "general" })
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Card className="pt-5 px-4 pb-8 sm:pt-6 sm:px-7">
|
||||
<CardHeader className="p-0">
|
||||
<CardTitle className="mb-1">Settings</CardTitle>
|
||||
<CardDescription>Manage display and notification preferences.</CardDescription>
|
||||
<CardTitle className="mb-1">
|
||||
<Trans>Settings</Trans>
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
<Trans>Manage display and notification preferences.</Trans>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
<Separator className="hidden md:block my-5" />
|
||||
@@ -78,7 +93,7 @@ export default function SettingsLayout() {
|
||||
</aside>
|
||||
<div className="flex-1">
|
||||
{/* @ts-ignore */}
|
||||
<SettingsContent name={page?.params?.name ?? 'general'} />
|
||||
<SettingsContent name={page?.params?.name ?? "general"} />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
@@ -90,9 +105,11 @@ function SettingsContent({ name }: { name: string }) {
|
||||
const userSettings = useStore($userSettings)
|
||||
|
||||
switch (name) {
|
||||
case 'general':
|
||||
case "general":
|
||||
return <General userSettings={userSettings} />
|
||||
case 'notifications':
|
||||
case "notifications":
|
||||
return <Notifications userSettings={userSettings} />
|
||||
case "config":
|
||||
return <ConfigYaml />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { pb } from '@/lib/stores'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { BellIcon, LoaderCircleIcon, PlusIcon, SaveIcon, Trash2Icon } from 'lucide-react'
|
||||
import { ChangeEventHandler, useEffect, useState } from 'react'
|
||||
import { toast } from '@/components/ui/use-toast'
|
||||
import { InputTags } from '@/components/ui/input-tags'
|
||||
import { UserSettings } from '@/types'
|
||||
import { saveSettings } from './layout'
|
||||
import * as v from 'valibot'
|
||||
import { isAdmin } from '@/lib/utils'
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { pb } from "@/lib/stores"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { Card } from "@/components/ui/card"
|
||||
import { BellIcon, LoaderCircleIcon, PlusIcon, SaveIcon, Trash2Icon } from "lucide-react"
|
||||
import { ChangeEventHandler, useEffect, useState } from "react"
|
||||
import { toast } from "@/components/ui/use-toast"
|
||||
import { InputTags } from "@/components/ui/input-tags"
|
||||
import { UserSettings } from "@/types"
|
||||
import { saveSettings } from "./layout"
|
||||
import * as v from "valibot"
|
||||
import { isAdmin } from "@/lib/utils"
|
||||
import { Trans, t } from "@lingui/macro"
|
||||
|
||||
interface ShoutrrrUrlCardProps {
|
||||
url: string
|
||||
@@ -36,10 +37,10 @@ const SettingsNotificationsPage = ({ userSettings }: { userSettings: UserSetting
|
||||
}, [userSettings])
|
||||
|
||||
function addWebhook() {
|
||||
setWebhooks([...webhooks, ''])
|
||||
setWebhooks([...webhooks, ""])
|
||||
// focus on the new input
|
||||
queueMicrotask(() => {
|
||||
const inputs = document.querySelectorAll('#webhooks input') as NodeListOf<HTMLInputElement>
|
||||
const inputs = document.querySelectorAll("#webhooks input") as NodeListOf<HTMLInputElement>
|
||||
inputs[inputs.length - 1]?.focus()
|
||||
})
|
||||
}
|
||||
@@ -58,9 +59,9 @@ const SettingsNotificationsPage = ({ userSettings }: { userSettings: UserSetting
|
||||
await saveSettings(parsedData)
|
||||
} catch (e: any) {
|
||||
toast({
|
||||
title: 'Failed to save settings',
|
||||
title: t`Failed to save settings`,
|
||||
description: e.message,
|
||||
variant: 'destructive',
|
||||
variant: "destructive",
|
||||
})
|
||||
}
|
||||
setIsLoading(false)
|
||||
@@ -69,59 +70,67 @@ const SettingsNotificationsPage = ({ userSettings }: { userSettings: UserSetting
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<h3 className="text-xl font-medium mb-2">Notifications</h3>
|
||||
<h3 className="text-xl font-medium mb-2">
|
||||
<Trans>Notifications</Trans>
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
Configure how you receive alert notifications.
|
||||
<Trans>Configure how you receive alert notifications.</Trans>
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground mt-1.5 leading-relaxed">
|
||||
Looking instead for where to create alerts? Click the bell{' '}
|
||||
<BellIcon className="inline h-4 w-4" /> icons in the systems table.
|
||||
<Trans>
|
||||
Looking instead for where to create alerts? Click the bell <BellIcon className="inline h-4 w-4" /> icons in
|
||||
the systems table.
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
<Separator className="my-4" />
|
||||
<div className="space-y-5">
|
||||
<div className="space-y-2">
|
||||
<div className="mb-4">
|
||||
<h3 className="mb-1 text-lg font-medium">Email notifications</h3>
|
||||
<h3 className="mb-1 text-lg font-medium">
|
||||
<Trans>Email notifications</Trans>
|
||||
</h3>
|
||||
{isAdmin() && (
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
Please{' '}
|
||||
<a href="/_/#/settings/mail" className="link" target="_blank">
|
||||
configure an SMTP server
|
||||
</a>{' '}
|
||||
to ensure alerts are delivered.{' '}
|
||||
<Trans>
|
||||
Please{" "}
|
||||
<a href="/_/#/settings/mail" className="link" target="_blank">
|
||||
configure an SMTP server
|
||||
</a>{" "}
|
||||
to ensure alerts are delivered.
|
||||
</Trans>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<Label className="block" htmlFor="email">
|
||||
To email(s)
|
||||
<Trans>To email(s)</Trans>
|
||||
</Label>
|
||||
<InputTags
|
||||
value={emails}
|
||||
onChange={setEmails}
|
||||
placeholder="Enter email address..."
|
||||
placeholder={t`Enter email address...`}
|
||||
className="w-full"
|
||||
type="email"
|
||||
id="email"
|
||||
/>
|
||||
<p className="text-[0.8rem] text-muted-foreground">
|
||||
Save address using enter key or comma. Leave blank to disable email notifications.
|
||||
<Trans>Save address using enter key or comma. Leave blank to disable email notifications.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<h3 className="mb-1 text-lg font-medium">Webhook / Push notifications</h3>
|
||||
<h3 className="mb-1 text-lg font-medium">
|
||||
<Trans>Webhook / Push notifications</Trans>
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
Beszel uses{' '}
|
||||
<a
|
||||
href="https://containrrr.dev/shoutrrr/services/overview/"
|
||||
target="_blank"
|
||||
className="link"
|
||||
>
|
||||
Shoutrrr
|
||||
</a>{' '}
|
||||
to integrate with popular notification services.
|
||||
<Trans>
|
||||
Beszel uses{" "}
|
||||
<a href="https://containrrr.dev/shoutrrr/services/overview/" target="_blank" className="link">
|
||||
Shoutrrr
|
||||
</a>{" "}
|
||||
to integrate with popular notification services.
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
{webhooks.length > 0 && (
|
||||
@@ -130,9 +139,7 @@ const SettingsNotificationsPage = ({ userSettings }: { userSettings: UserSetting
|
||||
<ShoutrrrUrlCard
|
||||
key={index}
|
||||
url={webhook}
|
||||
onUrlChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
updateWebhook(index, e.target.value)
|
||||
}
|
||||
onUrlChange={(e: React.ChangeEvent<HTMLInputElement>) => updateWebhook(index, e.target.value)}
|
||||
onRemove={() => removeWebhook(index)}
|
||||
/>
|
||||
))}
|
||||
@@ -145,8 +152,8 @@ const SettingsNotificationsPage = ({ userSettings }: { userSettings: UserSetting
|
||||
className="mt-2 flex items-center gap-1"
|
||||
onClick={addWebhook}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4 -ml-0.5" />
|
||||
Add URL
|
||||
<PlusIcon className="h-4 w-4 -ms-0.5" />
|
||||
<Trans>Add URL</Trans>
|
||||
</Button>
|
||||
</div>
|
||||
<Separator />
|
||||
@@ -156,12 +163,8 @@ const SettingsNotificationsPage = ({ userSettings }: { userSettings: UserSetting
|
||||
onClick={updateSettings}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<LoaderCircleIcon className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<SaveIcon className="h-4 w-4" />
|
||||
)}
|
||||
Save settings
|
||||
{isLoading ? <LoaderCircleIcon className="h-4 w-4 animate-spin" /> : <SaveIcon className="h-4 w-4" />}
|
||||
<Trans>Save Settings</Trans>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -173,17 +176,17 @@ const ShoutrrrUrlCard = ({ url, onUrlChange, onRemove }: ShoutrrrUrlCardProps) =
|
||||
|
||||
const sendTestNotification = async () => {
|
||||
setIsLoading(true)
|
||||
const res = await pb.send('/api/beszel/send-test-notification', { url })
|
||||
if ('err' in res && !res.err) {
|
||||
const res = await pb.send("/api/beszel/send-test-notification", { url })
|
||||
if ("err" in res && !res.err) {
|
||||
toast({
|
||||
title: 'Test notification sent',
|
||||
description: 'Check your notification service',
|
||||
title: t`Test notification sent`,
|
||||
description: t`Check your notification service`,
|
||||
})
|
||||
} else {
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: res.err ?? 'Failed to send test notification',
|
||||
variant: 'destructive',
|
||||
title: t`Error`,
|
||||
description: res.err ?? t`Failed to send test notification`,
|
||||
variant: "destructive",
|
||||
})
|
||||
}
|
||||
setIsLoading(false)
|
||||
@@ -200,29 +203,18 @@ const ShoutrrrUrlCard = ({ url, onUrlChange, onRemove }: ShoutrrrUrlCardProps) =
|
||||
value={url}
|
||||
onChange={onUrlChange}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
className="w-20 md:w-28"
|
||||
disabled={isLoading || url === ''}
|
||||
onClick={sendTestNotification}
|
||||
>
|
||||
<Button type="button" variant="outline" disabled={isLoading || url === ""} onClick={sendTestNotification}>
|
||||
{isLoading ? (
|
||||
<LoaderCircleIcon className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<span>
|
||||
Test <span className="hidden md:inline">URL</span>
|
||||
<Trans>
|
||||
Test <span className="hidden sm:inline">URL</span>
|
||||
</Trans>
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="shrink-0"
|
||||
aria-label="Delete"
|
||||
onClick={onRemove}
|
||||
>
|
||||
<Button type="button" variant="outline" size="icon" className="shrink-0" aria-label="Delete" onClick={onRemove}>
|
||||
<Trash2Icon className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
import React from 'react'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { buttonVariants } from '../../ui/button'
|
||||
import { $router, Link, navigate } from '../../router'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import React from "react"
|
||||
import { cn, isAdmin } from "@/lib/utils"
|
||||
import { buttonVariants } from "../../ui/button"
|
||||
import { $router, Link, navigate } from "../../router"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
|
||||
interface SidebarNavProps extends React.HTMLAttributes<HTMLElement> {
|
||||
items: {
|
||||
href: string
|
||||
title: string
|
||||
icon?: React.FC<React.SVGProps<SVGSVGElement>>
|
||||
admin?: boolean
|
||||
}[]
|
||||
}
|
||||
|
||||
@@ -29,33 +24,36 @@ export function SidebarNav({ className, items, ...props }: SidebarNavProps) {
|
||||
<div className="md:hidden">
|
||||
<Select onValueChange={(value: string) => navigate(value)} value={page?.path}>
|
||||
<SelectTrigger className="w-full my-3.5">
|
||||
<SelectValue placeholder="Select a page" />
|
||||
<SelectValue placeholder="Select page" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.href} value={item.href}>
|
||||
<span className="flex items-center gap-2">
|
||||
{item.icon && <item.icon className="h-4 w-4" />}
|
||||
{item.title}
|
||||
</span>
|
||||
</SelectItem>
|
||||
))}
|
||||
{items.map((item) => {
|
||||
if (item.admin && !isAdmin()) return null
|
||||
return (
|
||||
<SelectItem key={item.href} value={item.href}>
|
||||
<span className="flex items-center gap-2">
|
||||
{item.icon && <item.icon className="h-4 w-4" />}
|
||||
{item.title}
|
||||
</span>
|
||||
</SelectItem>
|
||||
)
|
||||
})}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Separator />
|
||||
</div>
|
||||
|
||||
{/* Desktop View */}
|
||||
<nav className={cn('hidden md:grid gap-1', className)} {...props}>
|
||||
<nav className={cn("hidden md:grid gap-1", className)} {...props}>
|
||||
{items.map((item) => (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className={cn(
|
||||
buttonVariants({ variant: 'ghost' }),
|
||||
'flex items-center gap-3',
|
||||
page?.path === item.href ? 'bg-muted hover:bg-muted' : 'hover:bg-muted/50',
|
||||
'justify-start'
|
||||
buttonVariants({ variant: "ghost" }),
|
||||
"flex items-center gap-3",
|
||||
page?.path === item.href ? "bg-muted hover:bg-muted" : "hover:bg-muted/50",
|
||||
"justify-start"
|
||||
)}
|
||||
>
|
||||
{item.icon && <item.icon className="h-4 w-4" />}
|
||||
|
||||
@@ -1,39 +1,35 @@
|
||||
import { $systems, pb, $chartTime, $containerFilter, $userSettings } from '@/lib/stores'
|
||||
import {
|
||||
ChartData,
|
||||
ChartTimes,
|
||||
ContainerStatsRecord,
|
||||
SystemRecord,
|
||||
SystemStatsRecord,
|
||||
} from '@/types'
|
||||
import React, { lazy, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Card, CardHeader, CardTitle, CardDescription } from '../ui/card'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import Spinner from '../spinner'
|
||||
import { ClockArrowUp, CpuIcon, GlobeIcon, LayoutGridIcon, MonitorIcon, XIcon } from 'lucide-react'
|
||||
import ChartTimeSelect from '../charts/chart-time-select'
|
||||
import { chartTimeData, cn, getPbTimestamp, useLocalStorage } from '@/lib/utils'
|
||||
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 { useIntersectionObserver } from '@/lib/use-intersection-observer'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select'
|
||||
import { timeTicks } from 'd3-time'
|
||||
import { $systems, pb, $chartTime, $containerFilter, $userSettings, $direction } from "@/lib/stores"
|
||||
import { ChartData, ChartTimes, ContainerStatsRecord, SystemRecord, SystemStatsRecord } from "@/types"
|
||||
import React, { lazy, useCallback, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { Card, CardHeader, CardTitle, CardDescription } from "../ui/card"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import Spinner from "../spinner"
|
||||
import { ClockArrowUp, CpuIcon, GlobeIcon, LayoutGridIcon, MonitorIcon, XIcon } from "lucide-react"
|
||||
import ChartTimeSelect from "../charts/chart-time-select"
|
||||
import { chartTimeData, cn, getPbTimestamp, useLocalStorage } from "@/lib/utils"
|
||||
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 { 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"
|
||||
|
||||
const AreaChartDefault = lazy(() => import('../charts/area-chart'))
|
||||
const ContainerChart = lazy(() => import('../charts/container-chart'))
|
||||
const MemChart = lazy(() => import('../charts/mem-chart'))
|
||||
const DiskChart = lazy(() => import('../charts/disk-chart'))
|
||||
const SwapChart = lazy(() => import('../charts/swap-chart'))
|
||||
const TemperatureChart = lazy(() => import('../charts/temperature-chart'))
|
||||
const AreaChartDefault = lazy(() => import("../charts/area-chart"))
|
||||
const ContainerChart = lazy(() => import("../charts/container-chart"))
|
||||
const MemChart = lazy(() => import("../charts/mem-chart"))
|
||||
const DiskChart = lazy(() => import("../charts/disk-chart"))
|
||||
const SwapChart = lazy(() => import("../charts/swap-chart"))
|
||||
const TemperatureChart = lazy(() => import("../charts/temperature-chart"))
|
||||
|
||||
const cache = new Map<string, any>()
|
||||
|
||||
// create ticks and domain for charts
|
||||
function getTimeData(chartTime: ChartTimes, lastCreated: number) {
|
||||
const cached = cache.get('td')
|
||||
const cached = cache.get("td")
|
||||
if (cached && cached.chartTime === chartTime) {
|
||||
if (!lastCreated || cached.time >= lastCreated) {
|
||||
return cached.data
|
||||
@@ -42,14 +38,12 @@ function getTimeData(chartTime: ChartTimes, lastCreated: number) {
|
||||
|
||||
const now = new Date()
|
||||
const startTime = chartTimeData[chartTime].getOffset(now)
|
||||
const ticks = timeTicks(startTime, now, chartTimeData[chartTime].ticks ?? 12).map((date) =>
|
||||
date.getTime()
|
||||
)
|
||||
const ticks = timeTicks(startTime, now, chartTimeData[chartTime].ticks ?? 12).map((date) => date.getTime())
|
||||
const data = {
|
||||
ticks,
|
||||
domain: [chartTimeData[chartTime].getOffset(now).getTime(), now.getTime()],
|
||||
}
|
||||
cache.set('td', { time: now.getTime(), data, chartTime })
|
||||
cache.set("td", { time: now.getTime(), data, chartTime })
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -78,38 +72,37 @@ function addEmptyValues<T extends SystemStatsRecord | ContainerStatsRecord>(
|
||||
return modifiedRecords
|
||||
}
|
||||
|
||||
async function getStats<T>(
|
||||
collection: string,
|
||||
system: SystemRecord,
|
||||
chartTime: ChartTimes
|
||||
): Promise<T[]> {
|
||||
async function getStats<T>(collection: string, system: SystemRecord, chartTime: ChartTimes): Promise<T[]> {
|
||||
const lastCached = cache.get(`${system.id}_${chartTime}_${collection}`)?.at(-1)?.created as number
|
||||
return await pb.collection<T>(collection).getFullList({
|
||||
filter: pb.filter('system={:id} && created > {:created} && type={:type}', {
|
||||
filter: pb.filter("system={:id} && created > {:created} && type={:type}", {
|
||||
id: system.id,
|
||||
created: getPbTimestamp(chartTime, lastCached ? new Date(lastCached + 1000) : undefined),
|
||||
type: chartTimeData[chartTime].type,
|
||||
}),
|
||||
fields: 'created,stats',
|
||||
sort: 'created',
|
||||
fields: "created,stats",
|
||||
sort: "created",
|
||||
})
|
||||
}
|
||||
|
||||
export default function SystemDetail({ name }: { name: string }) {
|
||||
const direction = useStore($direction)
|
||||
const { _ } = useLingui()
|
||||
const systems = useStore($systems)
|
||||
const chartTime = useStore($chartTime)
|
||||
/** Max CPU toggle value */
|
||||
const cpuMaxStore = useState(false)
|
||||
const bandwidthMaxStore = useState(false)
|
||||
const diskIoMaxStore = useState(false)
|
||||
const [grid, setGrid] = useLocalStorage('grid', true)
|
||||
const [grid, setGrid] = useLocalStorage("grid", true)
|
||||
const [system, setSystem] = useState({} as SystemRecord)
|
||||
const [systemStats, setSystemStats] = useState([] as SystemStatsRecord[])
|
||||
const [containerData, setContainerData] = useState([] as ChartData['containerData'])
|
||||
const [containerData, setContainerData] = useState([] as ChartData["containerData"])
|
||||
const netCardRef = useRef<HTMLDivElement>(null)
|
||||
const [containerFilterBar, setContainerFilterBar] = useState(null as null | JSX.Element)
|
||||
const [bottomSpacing, setBottomSpacing] = useState(0)
|
||||
const isLongerChart = chartTime !== '1h'
|
||||
const [chartLoading, setChartLoading] = useState(true)
|
||||
const isLongerChart = chartTime !== "1h"
|
||||
|
||||
useEffect(() => {
|
||||
document.title = `${name} / Beszel`
|
||||
@@ -119,7 +112,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
setSystemStats([])
|
||||
setContainerData([])
|
||||
setContainerFilterBar(null)
|
||||
$containerFilter.set('')
|
||||
$containerFilter.set("")
|
||||
cpuMaxStore[1](false)
|
||||
bandwidthMaxStore[1](false)
|
||||
diskIoMaxStore[1](false)
|
||||
@@ -149,11 +142,11 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
if (!system.id) {
|
||||
return
|
||||
}
|
||||
pb.collection<SystemRecord>('systems').subscribe(system.id, (e) => {
|
||||
pb.collection<SystemRecord>("systems").subscribe(system.id, (e) => {
|
||||
setSystem(e.record)
|
||||
})
|
||||
return () => {
|
||||
pb.collection('systems').unsubscribe(system.id)
|
||||
pb.collection("systems").unsubscribe(system.id)
|
||||
}
|
||||
}, [system.id])
|
||||
|
||||
@@ -166,27 +159,31 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
systemStats,
|
||||
containerData,
|
||||
chartTime,
|
||||
orientation: direction === "rtl" ? "right" : "left",
|
||||
...getTimeData(chartTime, lastCreated),
|
||||
}
|
||||
}, [systemStats, containerData])
|
||||
}, [systemStats, containerData, direction])
|
||||
|
||||
// get stats
|
||||
useEffect(() => {
|
||||
if (!system.id || !chartTime) {
|
||||
return
|
||||
}
|
||||
// loading: true
|
||||
setChartLoading(true)
|
||||
Promise.allSettled([
|
||||
getStats<SystemStatsRecord>('system_stats', system, chartTime),
|
||||
getStats<ContainerStatsRecord>('container_stats', system, chartTime),
|
||||
getStats<SystemStatsRecord>("system_stats", system, chartTime),
|
||||
getStats<ContainerStatsRecord>("container_stats", system, chartTime),
|
||||
]).then(([systemStats, containerStats]) => {
|
||||
// loading: false
|
||||
setChartLoading(false)
|
||||
|
||||
const { expectedInterval } = chartTimeData[chartTime]
|
||||
// make new system stats
|
||||
const ss_cache_key = `${system.id}_${chartTime}_system_stats`
|
||||
let systemData = (cache.get(ss_cache_key) || []) as SystemStatsRecord[]
|
||||
if (systemStats.status === 'fulfilled' && systemStats.value.length) {
|
||||
systemData = systemData.concat(
|
||||
addEmptyValues(systemData, systemStats.value, expectedInterval)
|
||||
)
|
||||
if (systemStats.status === "fulfilled" && systemStats.value.length) {
|
||||
systemData = systemData.concat(addEmptyValues(systemData, systemStats.value, expectedInterval))
|
||||
if (systemData.length > 120) {
|
||||
systemData = systemData.slice(-100)
|
||||
}
|
||||
@@ -196,10 +193,8 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
// make new container stats
|
||||
const cs_cache_key = `${system.id}_${chartTime}_container_stats`
|
||||
let containerData = (cache.get(cs_cache_key) || []) as ContainerStatsRecord[]
|
||||
if (containerStats.status === 'fulfilled' && containerStats.value.length) {
|
||||
containerData = containerData.concat(
|
||||
addEmptyValues(containerData, containerStats.value, expectedInterval)
|
||||
)
|
||||
if (containerStats.status === "fulfilled" && containerStats.value.length) {
|
||||
containerData = containerData.concat(addEmptyValues(containerData, containerStats.value, expectedInterval))
|
||||
if (containerData.length > 120) {
|
||||
containerData = containerData.slice(-100)
|
||||
}
|
||||
@@ -216,7 +211,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
|
||||
// make container stats for charts
|
||||
const makeContainerData = useCallback((containers: ContainerStatsRecord[]) => {
|
||||
const containerData = [] as ChartData['containerData']
|
||||
const containerData = [] as ChartData["containerData"]
|
||||
for (let { created, stats } of containers) {
|
||||
if (!created) {
|
||||
// @ts-ignore add null value for gaps
|
||||
@@ -225,7 +220,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
}
|
||||
created = new Date(created).getTime()
|
||||
// @ts-ignore not dealing with this rn
|
||||
let containerStats: ChartData['containerData'][0] = { created }
|
||||
let containerStats: ChartData["containerData"][0] = { created }
|
||||
for (let container of stats) {
|
||||
containerStats[container.n] = container
|
||||
}
|
||||
@@ -239,26 +234,26 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
if (!system.info) {
|
||||
return []
|
||||
}
|
||||
let uptime: number | string = system.info.u
|
||||
let uptime: React.ReactNode
|
||||
if (system.info.u < 172800) {
|
||||
const hours = Math.trunc(uptime / 3600)
|
||||
uptime = `${hours} hour${hours == 1 ? '' : 's'}`
|
||||
const hours = Math.trunc(system.info.u / 3600)
|
||||
uptime = <Plural value={hours} one="# hour" other="# hours" />
|
||||
} else {
|
||||
uptime = `${Math.trunc(system.info?.u / 86400)} days`
|
||||
uptime = <Plural value={Math.trunc(system.info?.u / 86400)} one="# day" other="# days" />
|
||||
}
|
||||
return [
|
||||
{ value: system.host, Icon: GlobeIcon },
|
||||
{
|
||||
value: system.info.h,
|
||||
Icon: MonitorIcon,
|
||||
label: 'Hostname',
|
||||
label: "Hostname",
|
||||
// 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: 'Uptime' },
|
||||
{ value: system.info.k, Icon: TuxIcon, label: 'Kernel' },
|
||||
{ value: uptime, Icon: ClockArrowUp, label: t`Uptime` },
|
||||
{ value: system.info.k, Icon: TuxIcon, label: t({ comment: "Linux kernel", message: "Kernel" }) },
|
||||
{
|
||||
value: `${system.info.m} (${system.info.c}c${system.info.t ? `/${system.info.t}t` : ''})`,
|
||||
value: `${system.info.m} (${system.info.c}c${system.info.t ? `/${system.info.t}t` : ""})`,
|
||||
Icon: CpuIcon,
|
||||
hide: !system.info.m,
|
||||
},
|
||||
@@ -277,7 +272,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
return
|
||||
}
|
||||
const tooltipHeight = (Object.keys(containerData[0]).length - 11) * 17.8 - 40
|
||||
const wrapperEl = document.getElementById('chartwrap') as HTMLDivElement
|
||||
const wrapperEl = document.getElementById("chartwrap") as HTMLDivElement
|
||||
const wrapperRect = wrapperEl.getBoundingClientRect()
|
||||
const chartRect = netCardRef.current.getBoundingClientRect()
|
||||
const distanceToBottom = wrapperRect.bottom - chartRect.bottom
|
||||
@@ -288,29 +283,32 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
return null
|
||||
}
|
||||
|
||||
// if no data, show empty message
|
||||
const dataEmpty = !chartLoading && chartData.systemStats.length === 0
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="chartwrap" className="grid gap-4 mb-10 overflow-x-clip">
|
||||
{/* system info */}
|
||||
<Card>
|
||||
<div className="grid lg:flex gap-4 px-4 sm:px-6 pt-3 sm:pt-4 pb-5">
|
||||
<div className="grid xl:flex gap-4 px-4 sm:px-6 pt-3 sm:pt-4 pb-5">
|
||||
<div>
|
||||
<h1 className="text-[1.6rem] font-semibold mb-1.5">{system.name}</h1>
|
||||
<div className="flex flex-wrap items-center gap-3 gap-y-2 text-sm opacity-90">
|
||||
<div className="capitalize flex gap-2 items-center">
|
||||
<span className={cn('relative flex h-3 w-3')}>
|
||||
{system.status === 'up' && (
|
||||
<span className={cn("relative flex h-3 w-3")}>
|
||||
{system.status === "up" && (
|
||||
<span
|
||||
className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"
|
||||
style={{ animationDuration: '1.5s' }}
|
||||
style={{ animationDuration: "1.5s" }}
|
||||
></span>
|
||||
)}
|
||||
<span
|
||||
className={cn('relative inline-flex rounded-full h-3 w-3', {
|
||||
'bg-green-500': system.status === 'up',
|
||||
'bg-red-500': system.status === 'down',
|
||||
'bg-primary/40': system.status === 'paused',
|
||||
'bg-yellow-500': system.status === 'pending',
|
||||
className={cn("relative inline-flex rounded-full h-3 w-3", {
|
||||
"bg-green-500": system.status === "up",
|
||||
"bg-red-500": system.status === "down",
|
||||
"bg-primary/40": system.status === "paused",
|
||||
"bg-yellow-500": system.status === "pending",
|
||||
})}
|
||||
></span>
|
||||
</span>
|
||||
@@ -343,16 +341,16 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div className="lg:ml-auto flex items-center gap-2 max-sm:-mb-1">
|
||||
<ChartTimeSelect className="w-full lg:w-40" />
|
||||
<div className="xl:ms-auto flex items-center gap-2 max-sm:-mb-1">
|
||||
<ChartTimeSelect className="w-full xl:w-40" />
|
||||
<TooltipProvider delayDuration={100}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
aria-label="Toggle grid"
|
||||
aria-label={t`Toggle grid`}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="hidden lg:flex p-0 text-primary"
|
||||
className="hidden xl:flex p-0 text-primary"
|
||||
onClick={() => setGrid(!grid)}
|
||||
>
|
||||
{grid ? (
|
||||
@@ -362,7 +360,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
)}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Toggle grid</TooltipContent>
|
||||
<TooltipContent>{t`Toggle grid`}</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
@@ -370,28 +368,23 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
</Card>
|
||||
|
||||
{/* main charts */}
|
||||
<div className="grid lg:grid-cols-2 gap-4">
|
||||
<div className="grid xl:grid-cols-2 gap-4">
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title="Total CPU Usage"
|
||||
description={`${
|
||||
cpuMaxStore[0] && isLongerChart ? 'Max 1 min ' : 'Average'
|
||||
} system-wide CPU utilization`}
|
||||
title={_(t`CPU Usage`)}
|
||||
description={t`Average system-wide CPU utilization`}
|
||||
cornerEl={isLongerChart ? <SelectAvgMax store={cpuMaxStore} /> : null}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
chartName="CPU Usage"
|
||||
maxToggled={cpuMaxStore[0]}
|
||||
unit="%"
|
||||
/>
|
||||
<AreaChartDefault chartData={chartData} chartName="CPU Usage" maxToggled={cpuMaxStore[0]} unit="%" />
|
||||
</ChartCard>
|
||||
|
||||
{containerFilterBar && (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title="Docker CPU Usage"
|
||||
description="Average CPU utilization of containers"
|
||||
title={t`Docker CPU Usage`}
|
||||
description={t`Average CPU utilization of containers`}
|
||||
cornerEl={containerFilterBar}
|
||||
>
|
||||
<ContainerChart chartData={chartData} dataKey="c" chartName="cpu" />
|
||||
@@ -399,25 +392,27 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
)}
|
||||
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title="Total Memory Usage"
|
||||
description="Precise utilization at the recorded time"
|
||||
title={t`Memory Usage`}
|
||||
description={t`Precise utilization at the recorded time`}
|
||||
>
|
||||
<MemChart chartData={chartData} />
|
||||
</ChartCard>
|
||||
|
||||
{containerFilterBar && (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title="Docker Memory Usage"
|
||||
description="Memory usage of docker containers"
|
||||
title={t`Docker Memory Usage`}
|
||||
description={t`Memory usage of docker containers`}
|
||||
cornerEl={containerFilterBar}
|
||||
>
|
||||
<ContainerChart chartData={chartData} chartName="mem" dataKey="m" unit=" MB" />
|
||||
</ChartCard>
|
||||
)}
|
||||
|
||||
<ChartCard grid={grid} title="Disk Space" description="Usage of root partition">
|
||||
<ChartCard empty={dataEmpty} grid={grid} title={t`Disk Usage`} description={t`Usage of root partition`}>
|
||||
<DiskChart
|
||||
chartData={chartData}
|
||||
dataKey="stats.du"
|
||||
@@ -426,41 +421,36 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
</ChartCard>
|
||||
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title="Disk I/O"
|
||||
description="Throughput of root filesystem"
|
||||
title={t`Disk I/O`}
|
||||
description={t`Throughput of root filesystem`}
|
||||
cornerEl={isLongerChart ? <SelectAvgMax store={diskIoMaxStore} /> : null}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
maxToggled={diskIoMaxStore[0]}
|
||||
chartName="dio"
|
||||
/>
|
||||
<AreaChartDefault chartData={chartData} maxToggled={diskIoMaxStore[0]} chartName="dio" />
|
||||
</ChartCard>
|
||||
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title="Bandwidth"
|
||||
title={t`Bandwidth`}
|
||||
cornerEl={isLongerChart ? <SelectAvgMax store={bandwidthMaxStore} /> : null}
|
||||
description="Network traffic of public interfaces"
|
||||
description={t`Network traffic of public interfaces`}
|
||||
>
|
||||
<AreaChartDefault
|
||||
chartData={chartData}
|
||||
maxToggled={bandwidthMaxStore[0]}
|
||||
chartName="bw"
|
||||
/>
|
||||
<AreaChartDefault chartData={chartData} maxToggled={bandwidthMaxStore[0]} chartName="bw" />
|
||||
</ChartCard>
|
||||
|
||||
{containerFilterBar && containerData.length > 0 && (
|
||||
<div
|
||||
ref={netCardRef}
|
||||
className={cn({
|
||||
'col-span-full': !grid,
|
||||
"col-span-full": !grid,
|
||||
})}
|
||||
>
|
||||
<ChartCard
|
||||
title="Docker Network I/O"
|
||||
description="Includes traffic between internal services"
|
||||
empty={dataEmpty}
|
||||
title={t`Docker Network I/O`}
|
||||
description={t`Network traffic of docker containers`}
|
||||
cornerEl={containerFilterBar}
|
||||
>
|
||||
{/* @ts-ignore */}
|
||||
@@ -470,13 +460,23 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
)}
|
||||
|
||||
{(systemStats.at(-1)?.stats.su ?? 0) > 0 && (
|
||||
<ChartCard grid={grid} title="Swap Usage" description="Swap space used by the system">
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`Swap Usage`}
|
||||
description={t`Swap space used by the system`}
|
||||
>
|
||||
<SwapChart chartData={chartData} />
|
||||
</ChartCard>
|
||||
)}
|
||||
|
||||
{systemStats.at(-1)?.stats.t && (
|
||||
<ChartCard grid={grid} title="Temperature" description="Temperatures of system sensors">
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t`Temperature`}
|
||||
description={t`Temperatures of system sensors`}
|
||||
>
|
||||
<TemperatureChart chartData={chartData} />
|
||||
</ChartCard>
|
||||
)}
|
||||
@@ -484,14 +484,15 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
|
||||
{/* extra filesystem charts */}
|
||||
{Object.keys(systemStats.at(-1)?.stats.efs ?? {}).length > 0 && (
|
||||
<div className="grid lg:grid-cols-2 gap-4">
|
||||
<div className="grid xl:grid-cols-2 gap-4">
|
||||
{Object.keys(systemStats.at(-1)?.stats.efs ?? {}).map((extraFsName) => {
|
||||
return (
|
||||
<div key={extraFsName} className="contents">
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={`${extraFsName} Usage`}
|
||||
description={`Disk usage of ${extraFsName}`}
|
||||
title={`${extraFsName} ${t`Usage`}`}
|
||||
description={t`Disk usage of ${extraFsName}`}
|
||||
>
|
||||
<DiskChart
|
||||
chartData={chartData}
|
||||
@@ -500,9 +501,10 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
/>
|
||||
</ChartCard>
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={`${extraFsName} I/O`}
|
||||
description={`Throughput of ${extraFsName}`}
|
||||
description={t`Throughput of ${extraFsName}`}
|
||||
cornerEl={isLongerChart ? <SelectAvgMax store={diskIoMaxStore} /> : null}
|
||||
>
|
||||
<AreaChartDefault
|
||||
@@ -526,6 +528,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
|
||||
function ContainerFilterBar() {
|
||||
const containerFilter = useStore($containerFilter)
|
||||
const { _ } = useLingui()
|
||||
|
||||
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
$containerFilter.set(e.target.value)
|
||||
@@ -533,12 +536,7 @@ function ContainerFilterBar() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
placeholder="Filter..."
|
||||
className="pl-4 pr-8"
|
||||
value={containerFilter}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<Input placeholder={_(t`Filter...`)} className="ps-4 pe-8" value={containerFilter} onChange={handleChange} />
|
||||
{containerFilter && (
|
||||
<Button
|
||||
type="button"
|
||||
@@ -546,7 +544,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={() => $containerFilter.set("")}
|
||||
>
|
||||
<XIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
@@ -555,26 +553,22 @@ function ContainerFilterBar() {
|
||||
)
|
||||
}
|
||||
|
||||
function SelectAvgMax({
|
||||
store,
|
||||
}: {
|
||||
store: [boolean, React.Dispatch<React.SetStateAction<boolean>>]
|
||||
}) {
|
||||
function SelectAvgMax({ store }: { store: [boolean, React.Dispatch<React.SetStateAction<boolean>>] }) {
|
||||
const [max, setMax] = store
|
||||
const Icon = max ? ChartMax : ChartAverage
|
||||
|
||||
return (
|
||||
<Select value={max ? 'max' : 'avg'} onValueChange={(e) => setMax(e === 'max')}>
|
||||
<SelectTrigger className="relative pl-10 pr-5">
|
||||
<Icon className="h-4 w-4 absolute left-4 top-1/2 -translate-y-1/2 opacity-85" />
|
||||
<Select value={max ? "max" : "avg"} onValueChange={(e) => setMax(e === "max")}>
|
||||
<SelectTrigger className="relative ps-10 pe-5">
|
||||
<Icon className="h-4 w-4 absolute start-4 top-1/2 -translate-y-1/2 opacity-85" />
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem key="avg" value="avg">
|
||||
Average
|
||||
<Trans>Average</Trans>
|
||||
</SelectItem>
|
||||
<SelectItem key="max" value="max">
|
||||
Max 1 min
|
||||
<Trans comment="Chart select field. Please try to keep this short.">Max 1 min</Trans>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
@@ -586,32 +580,27 @@ function ChartCard({
|
||||
description,
|
||||
children,
|
||||
grid,
|
||||
empty,
|
||||
cornerEl,
|
||||
}: {
|
||||
title: string
|
||||
description: string
|
||||
children: React.ReactNode
|
||||
grid?: boolean
|
||||
empty?: boolean
|
||||
cornerEl?: JSX.Element | null
|
||||
}) {
|
||||
const { isIntersecting, ref } = useIntersectionObserver()
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={cn('pb-2 sm:pb-4 odd:last-of-type:col-span-full', { 'col-span-full': !grid })}
|
||||
ref={ref}
|
||||
>
|
||||
<Card className={cn("pb-2 sm:pb-4 odd:last-of-type:col-span-full", { "col-span-full": !grid })} ref={ref}>
|
||||
<CardHeader className="pb-5 pt-4 relative space-y-1 max-sm:py-3 max-sm:px-4">
|
||||
<CardTitle className="text-xl sm:text-2xl">{title}</CardTitle>
|
||||
<CardDescription>{description}</CardDescription>
|
||||
{cornerEl && (
|
||||
<div className="relative py-1 block sm:w-44 sm:absolute sm:top-2.5 sm:right-3.5">
|
||||
{cornerEl}
|
||||
</div>
|
||||
)}
|
||||
{cornerEl && <div className="relative py-1 block sm:w-44 sm:absolute sm:top-2.5 sm:end-3.5">{cornerEl}</div>}
|
||||
</CardHeader>
|
||||
<div className="pl-0 w-[calc(100%-1.6em)] h-52 relative">
|
||||
{<Spinner />}
|
||||
<div className="ps-0 w-[calc(100%-1.6em)] h-52 relative">
|
||||
{<Spinner msg={empty ? t`Waiting for enough records to display` : undefined} />}
|
||||
{isIntersecting && children}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { LoaderCircleIcon } from 'lucide-react'
|
||||
import { LoaderCircleIcon } from "lucide-react"
|
||||
|
||||
export default function () {
|
||||
export default function ({ msg }: { msg?: string }) {
|
||||
return (
|
||||
<div className="grid place-content-center h-full absolute inset-0">
|
||||
<LoaderCircleIcon className="animate-spin h-10 w-10 opacity-60" />
|
||||
<div className="flex flex-col items-center justify-center h-full absolute inset-0">
|
||||
{msg ? (
|
||||
<p className={"opacity-60 mb-2 text-center px-4"}>{msg}</p>
|
||||
) : (
|
||||
<LoaderCircleIcon className="animate-spin h-10 w-10 opacity-60" />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,29 +6,24 @@ import {
|
||||
SortingState,
|
||||
getSortedRowModel,
|
||||
flexRender,
|
||||
VisibilityState,
|
||||
getCoreRowModel,
|
||||
useReactTable,
|
||||
Column,
|
||||
} from '@tanstack/react-table'
|
||||
} from "@tanstack/react-table"
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table'
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||
|
||||
import { Button, buttonVariants } from '@/components/ui/button'
|
||||
import { Button, buttonVariants } from "@/components/ui/button"
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
|
||||
import {
|
||||
AlertDialog,
|
||||
@@ -40,9 +35,9 @@ import {
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from '@/components/ui/alert-dialog'
|
||||
} from "@/components/ui/alert-dialog"
|
||||
|
||||
import { SystemRecord } from '@/types'
|
||||
import { SystemRecord } from "@/types"
|
||||
import {
|
||||
MoreHorizontalIcon,
|
||||
ArrowUpDownIcon,
|
||||
@@ -55,14 +50,19 @@ import {
|
||||
HardDriveIcon,
|
||||
ServerIcon,
|
||||
CpuIcon,
|
||||
} from 'lucide-react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { $hubVersion, $systems, pb } from '@/lib/stores'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { cn, copyToClipboard, decimalString, isReadOnlyUser } from '@/lib/utils'
|
||||
import AlertsButton from '../alerts/alert-button'
|
||||
import { navigate } from '../router'
|
||||
import { EthernetIcon } from '../ui/icons'
|
||||
ChevronDownIcon,
|
||||
} from "lucide-react"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { $hubVersion, $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 { navigate } from "../router"
|
||||
import { EthernetIcon } from "../ui/icons"
|
||||
import { Trans, t } from "@lingui/macro"
|
||||
import { useLingui } from "@lingui/react"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"
|
||||
import { Input } from "../ui/input"
|
||||
|
||||
function CellFormatter(info: CellContext<SystemRecord, unknown>) {
|
||||
const val = info.getValue() as number
|
||||
@@ -72,8 +72,8 @@ function CellFormatter(info: CellContext<SystemRecord, unknown>) {
|
||||
<span className="grow min-w-10 block bg-muted h-[1em] relative rounded-sm overflow-hidden">
|
||||
<span
|
||||
className={cn(
|
||||
'absolute inset-0 w-full h-full origin-left',
|
||||
(val < 65 && 'bg-green-500') || (val < 90 && 'bg-yellow-500') || 'bg-red-600'
|
||||
"absolute inset-0 w-full h-full origin-left",
|
||||
(val < 65 && "bg-green-500") || (val < 90 && "bg-yellow-500") || "bg-red-600"
|
||||
)}
|
||||
style={{ transform: `scalex(${val}%)` }}
|
||||
></span>
|
||||
@@ -82,34 +82,32 @@ function CellFormatter(info: CellContext<SystemRecord, unknown>) {
|
||||
)
|
||||
}
|
||||
|
||||
function sortableHeader(
|
||||
column: Column<SystemRecord, unknown>,
|
||||
name: string,
|
||||
Icon: any,
|
||||
hideSortIcon = false
|
||||
) {
|
||||
function sortableHeader(column: Column<SystemRecord, unknown>, Icon: any, hideSortIcon = false) {
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-9 px-3"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
||||
className="h-9 px-3 flex"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||
>
|
||||
<Icon className="mr-2 h-4 w-4" />
|
||||
{name}
|
||||
{!hideSortIcon && <ArrowUpDownIcon className="ml-2 h-4 w-4" />}
|
||||
<Icon className="me-2 h-4 w-4" />
|
||||
{column.id}
|
||||
{!hideSortIcon && <ArrowUpDownIcon className="ms-2 h-4 w-4" />}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
export default function SystemsTable({ filter }: { filter?: string }) {
|
||||
export default function SystemsTable() {
|
||||
const data = useStore($systems)
|
||||
const hubVersion = useStore($hubVersion)
|
||||
const [filter, setFilter] = useState<string>()
|
||||
const [sorting, setSorting] = useState<SortingState>([])
|
||||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
|
||||
const [columnVisibility, setColumnVisibility] = useLocalStorage<VisibilityState>("cols", {})
|
||||
const { i18n } = useLingui()
|
||||
|
||||
useEffect(() => {
|
||||
if (filter !== undefined) {
|
||||
table.getColumn('name')?.setFilterValue(filter)
|
||||
table.getColumn(t`System`)?.setFilterValue(filter)
|
||||
}
|
||||
}, [filter])
|
||||
|
||||
@@ -119,23 +117,25 @@ export default function SystemsTable({ filter }: { filter?: string }) {
|
||||
// size: 200,
|
||||
size: 200,
|
||||
minSize: 0,
|
||||
accessorKey: 'name',
|
||||
accessorKey: "name",
|
||||
id: t`System`,
|
||||
enableHiding: false,
|
||||
cell: (info) => {
|
||||
const { status } = info.row.original
|
||||
return (
|
||||
<span className="flex gap-0.5 items-center text-base md:pr-5">
|
||||
<span className="flex gap-0.5 items-center text-base md:pe-5">
|
||||
<span
|
||||
className={cn('w-2 h-2 left-0 rounded-full', {
|
||||
'bg-green-500': status === 'up',
|
||||
'bg-red-500': status === 'down',
|
||||
'bg-primary/40': status === 'paused',
|
||||
'bg-yellow-500': status === 'pending',
|
||||
className={cn("w-2 h-2 left-0 rounded-full", {
|
||||
"bg-green-500": status === "up",
|
||||
"bg-red-500": status === "down",
|
||||
"bg-primary/40": status === "paused",
|
||||
"bg-yellow-500": status === "pending",
|
||||
})}
|
||||
style={{ marginBottom: '-1px' }}
|
||||
style={{ marginBottom: "-1px" }}
|
||||
></span>
|
||||
<Button
|
||||
data-nolink
|
||||
variant={'ghost'}
|
||||
variant={"ghost"}
|
||||
className="text-primary/90 h-7 px-1.5 gap-1.5"
|
||||
onClick={() => copyToClipboard(info.getValue() as string)}
|
||||
>
|
||||
@@ -145,59 +145,58 @@ export default function SystemsTable({ filter }: { filter?: string }) {
|
||||
</span>
|
||||
)
|
||||
},
|
||||
header: ({ column }) => sortableHeader(column, 'System', ServerIcon),
|
||||
header: ({ column }) => sortableHeader(column, ServerIcon),
|
||||
},
|
||||
{
|
||||
accessorKey: 'info.cpu',
|
||||
accessorKey: "info.cpu",
|
||||
id: t`CPU`,
|
||||
invertSorting: true,
|
||||
cell: CellFormatter,
|
||||
header: ({ column }) => sortableHeader(column, 'CPU', CpuIcon),
|
||||
header: ({ column }) => sortableHeader(column, CpuIcon),
|
||||
},
|
||||
{
|
||||
accessorKey: 'info.mp',
|
||||
accessorKey: "info.mp",
|
||||
id: t`Memory`,
|
||||
invertSorting: true,
|
||||
cell: CellFormatter,
|
||||
header: ({ column }) => sortableHeader(column, 'Memory', MemoryStickIcon),
|
||||
header: ({ column }) => sortableHeader(column, MemoryStickIcon),
|
||||
},
|
||||
{
|
||||
accessorKey: 'info.dp',
|
||||
accessorKey: "info.dp",
|
||||
id: t`Disk`,
|
||||
invertSorting: true,
|
||||
cell: CellFormatter,
|
||||
header: ({ column }) => sortableHeader(column, 'Disk', HardDriveIcon),
|
||||
header: ({ column }) => sortableHeader(column, HardDriveIcon),
|
||||
},
|
||||
{
|
||||
accessorFn: (originalRow) => originalRow.info.b || 0,
|
||||
id: 'n',
|
||||
id: t`Net`,
|
||||
invertSorting: true,
|
||||
size: 115,
|
||||
header: ({ column }) => sortableHeader(column, 'Net', EthernetIcon),
|
||||
header: ({ column }) => sortableHeader(column, EthernetIcon),
|
||||
cell: (info) => {
|
||||
const val = info.getValue() as number
|
||||
return (
|
||||
<span className="tabular-nums whitespace-nowrap pl-1">
|
||||
{decimalString(val, val >= 100 ? 1 : 2)} MB/s
|
||||
</span>
|
||||
<span className="tabular-nums whitespace-nowrap ps-1">{decimalString(val, val >= 100 ? 1 : 2)} MB/s</span>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'info.v',
|
||||
accessorKey: "info.v",
|
||||
id: t`Agent`,
|
||||
invertSorting: true,
|
||||
size: 50,
|
||||
header: ({ column }) => sortableHeader(column, 'Agent', WifiIcon, true),
|
||||
header: ({ column }) => sortableHeader(column, WifiIcon, true),
|
||||
cell: (info) => {
|
||||
const version = info.getValue() as string
|
||||
if (!version || !hubVersion) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<span className="flex gap-2 items-center md:pr-5 tabular-nums pl-1">
|
||||
<span className="flex gap-2 items-center md:pe-5 tabular-nums ps-1">
|
||||
<span
|
||||
className={cn(
|
||||
'w-2 h-2 left-0 rounded-full',
|
||||
version === hubVersion ? 'bg-green-500' : 'bg-yellow-500'
|
||||
)}
|
||||
style={{ marginBottom: '-1px' }}
|
||||
className={cn("w-2 h-2 left-0 rounded-full", version === hubVersion ? "bg-green-500" : "bg-yellow-500")}
|
||||
style={{ marginBottom: "-1px" }}
|
||||
></span>
|
||||
<span>{info.getValue() as string}</span>
|
||||
</span>
|
||||
@@ -205,72 +204,78 @@ export default function SystemsTable({ filter }: { filter?: string }) {
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
id: t({ message: "Actions", comment: "Table column" }),
|
||||
size: 120,
|
||||
// minSize: 0,
|
||||
cell: ({ row }) => {
|
||||
const { id, name, status, host } = row.original
|
||||
return (
|
||||
<div className={'flex justify-end items-center gap-1'}>
|
||||
<div className={"flex justify-end items-center gap-1"}>
|
||||
<AlertsButton system={row.original} />
|
||||
<AlertDialog>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size={'icon'} data-nolink>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<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">
|
||||
<DropdownMenuItem
|
||||
className={cn(isReadOnlyUser() && 'hidden')}
|
||||
className={cn(isReadOnlyUser() && "hidden")}
|
||||
onClick={() => {
|
||||
pb.collection('systems').update(id, {
|
||||
status: status === 'paused' ? 'pending' : 'paused',
|
||||
pb.collection("systems").update(id, {
|
||||
status: status === "paused" ? "pending" : "paused",
|
||||
})
|
||||
}}
|
||||
>
|
||||
{status === 'paused' ? (
|
||||
{status === "paused" ? (
|
||||
<>
|
||||
<PlayCircleIcon className="mr-2.5 h-4 w-4" />
|
||||
Resume
|
||||
<PlayCircleIcon className="me-2.5 h-4 w-4" />
|
||||
<Trans>Resume</Trans>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<PauseCircleIcon className="mr-2.5 h-4 w-4" />
|
||||
Pause
|
||||
<PauseCircleIcon className="me-2.5 h-4 w-4" />
|
||||
<Trans>Pause</Trans>
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => copyToClipboard(host)}>
|
||||
<CopyIcon className="mr-2.5 h-4 w-4" />
|
||||
Copy host
|
||||
<CopyIcon className="me-2.5 h-4 w-4" />
|
||||
<Trans>Copy host</Trans>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator className={cn(isReadOnlyUser() && 'hidden')} />
|
||||
<DropdownMenuSeparator className={cn(isReadOnlyUser() && "hidden")} />
|
||||
<AlertDialogTrigger asChild>
|
||||
<DropdownMenuItem className={cn(isReadOnlyUser() && 'hidden')}>
|
||||
<Trash2Icon className="mr-2.5 h-4 w-4" />
|
||||
Delete
|
||||
<DropdownMenuItem className={cn(isReadOnlyUser() && "hidden")}>
|
||||
<Trash2Icon className="me-2.5 h-4 w-4" />
|
||||
<Trans>Delete</Trans>
|
||||
</DropdownMenuItem>
|
||||
</AlertDialogTrigger>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Are you sure you want to delete {name}?</AlertDialogTitle>
|
||||
<AlertDialogTitle>
|
||||
<Trans>Are you sure you want to delete {name}?</Trans>
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This action cannot be undone. This will permanently delete all current records
|
||||
for <code className={'bg-muted rounded-sm px-1'}>{name}</code> from the
|
||||
database.
|
||||
<Trans>
|
||||
This action cannot be undone. This will permanently delete all current records for {name} from
|
||||
the database.
|
||||
</Trans>
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogCancel>
|
||||
<Trans>Cancel</Trans>
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className={cn(buttonVariants({ variant: 'destructive' }))}
|
||||
onClick={() => pb.collection('systems').delete(id)}
|
||||
className={cn(buttonVariants({ variant: "destructive" }))}
|
||||
onClick={() => pb.collection("systems").delete(id)}
|
||||
>
|
||||
Continue
|
||||
<Trans>Continue</Trans>
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
@@ -280,7 +285,7 @@ export default function SystemsTable({ filter }: { filter?: string }) {
|
||||
},
|
||||
},
|
||||
] as ColumnDef<SystemRecord>[]
|
||||
}, [hubVersion])
|
||||
}, [hubVersion, i18n.locale])
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
@@ -290,9 +295,11 @@ export default function SystemsTable({ filter }: { filter?: string }) {
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
},
|
||||
defaultColumn: {
|
||||
minSize: 0,
|
||||
@@ -302,64 +309,102 @@ export default function SystemsTable({ filter }: { filter?: string }) {
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="rounded-md border overflow-hidden">
|
||||
<Table>
|
||||
<TableHeader className="bg-muted/40">
|
||||
{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>
|
||||
{table.getRowModel().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(`/system/${encodeURIComponent(row.original.name)}`)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
style={{
|
||||
width:
|
||||
cell.column.getSize() === Number.MAX_SAFE_INTEGER
|
||||
? 'auto'
|
||||
: cell.column.getSize(),
|
||||
<Card>
|
||||
<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">
|
||||
<CardTitle className="mb-2.5">
|
||||
<Trans>All Systems</Trans>
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
<Trans>Updated in real time. Click on a system to view information.</Trans>
|
||||
</CardDescription>
|
||||
</div>
|
||||
<div className="flex gap-2 ms-auto w-full md:w-80">
|
||||
<Input placeholder={t`Filter...`} onChange={(e) => setFilter(e.target.value)} className="px-4" />
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">
|
||||
<Trans comment="Context: table columns">Columns</Trans>{" "}
|
||||
<ChevronDownIcon className="ms-1.5 h-4 w-4 opacity-90" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
{table
|
||||
.getAllColumns()
|
||||
.filter((column) => column.getCanHide())
|
||||
.map((column) => {
|
||||
return (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={column.id}
|
||||
checked={column.getIsVisible()}
|
||||
onCheckedChange={(value) => column.toggleVisibility(!!value)}
|
||||
>
|
||||
{column.id}
|
||||
</DropdownMenuCheckboxItem>
|
||||
)
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="max-sm:p-2">
|
||||
<div className="rounded-md border overflow-hidden">
|
||||
<Table>
|
||||
<TableHeader className="bg-muted/40">
|
||||
{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>
|
||||
{table.getRowModel().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(`/system/${encodeURIComponent(row.original.name)}`)
|
||||
}
|
||||
}}
|
||||
className={cn('overflow-hidden relative', data.length > 10 ? 'py-2' : 'py-2.5')}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
{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>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No systems found
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createContext, useContext, useEffect, useState } from 'react'
|
||||
import { createContext, useContext, useEffect, useState } from "react"
|
||||
|
||||
type Theme = 'dark' | 'light' | 'system'
|
||||
type Theme = "dark" | "light" | "system"
|
||||
|
||||
type ThemeProviderProps = {
|
||||
children: React.ReactNode
|
||||
@@ -14,7 +14,7 @@ type ThemeProviderState = {
|
||||
}
|
||||
|
||||
const initialState: ThemeProviderState = {
|
||||
theme: 'system',
|
||||
theme: "system",
|
||||
setTheme: () => null,
|
||||
}
|
||||
|
||||
@@ -22,23 +22,19 @@ const ThemeProviderContext = createContext<ThemeProviderState>(initialState)
|
||||
|
||||
export function ThemeProvider({
|
||||
children,
|
||||
defaultTheme = 'system',
|
||||
storageKey = 'ui-theme',
|
||||
defaultTheme = "system",
|
||||
storageKey = "ui-theme",
|
||||
...props
|
||||
}: ThemeProviderProps) {
|
||||
const [theme, setTheme] = useState<Theme>(
|
||||
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme
|
||||
)
|
||||
const [theme, setTheme] = useState<Theme>(() => (localStorage.getItem(storageKey) as Theme) || defaultTheme)
|
||||
|
||||
useEffect(() => {
|
||||
const root = window.document.documentElement
|
||||
|
||||
root.classList.remove('light', 'dark')
|
||||
root.classList.remove("light", "dark")
|
||||
|
||||
if (theme === 'system') {
|
||||
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
? 'dark'
|
||||
: 'light'
|
||||
if (theme === "system") {
|
||||
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
|
||||
|
||||
root.classList.add(systemTheme)
|
||||
return
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react'
|
||||
import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog'
|
||||
import * as React from "react"
|
||||
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { buttonVariants } from '@/components/ui/button'
|
||||
import { cn } from "@/lib/utils"
|
||||
import { buttonVariants } from "@/components/ui/button"
|
||||
|
||||
const AlertDialog = AlertDialogPrimitive.Root
|
||||
|
||||
@@ -16,7 +16,7 @@ const AlertDialogOverlay = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Overlay
|
||||
className={cn(
|
||||
'fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
||||
"fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -34,7 +34,7 @@ const AlertDialogContent = React.forwardRef<
|
||||
<AlertDialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -44,27 +44,20 @@ const AlertDialogContent = React.forwardRef<
|
||||
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
|
||||
|
||||
const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div className={cn('flex flex-col space-y-2 text-center sm:text-left', className)} {...props} />
|
||||
<div className={cn("flex flex-col space-y-2 text-center sm:text-start", className)} {...props} />
|
||||
)
|
||||
AlertDialogHeader.displayName = 'AlertDialogHeader'
|
||||
AlertDialogHeader.displayName = "AlertDialogHeader"
|
||||
|
||||
const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
<div className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-2", className)} {...props} />
|
||||
)
|
||||
AlertDialogFooter.displayName = 'AlertDialogFooter'
|
||||
AlertDialogFooter.displayName = "AlertDialogFooter"
|
||||
|
||||
const AlertDialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn('text-lg font-semibold', className)}
|
||||
{...props}
|
||||
/>
|
||||
<AlertDialogPrimitive.Title ref={ref} className={cn("text-lg font-semibold", className)} {...props} />
|
||||
))
|
||||
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
|
||||
|
||||
@@ -72,11 +65,7 @@ const AlertDialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn('text-sm text-muted-foreground', className)}
|
||||
{...props}
|
||||
/>
|
||||
<AlertDialogPrimitive.Description ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
|
||||
))
|
||||
AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName
|
||||
|
||||
@@ -94,7 +83,7 @@ const AlertDialogCancel = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Cancel
|
||||
ref={ref}
|
||||
className={cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', className)}
|
||||
className={cn(buttonVariants({ variant: "outline" }), "mt-2 sm:mt-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as React from 'react'
|
||||
import * as React from "react"
|
||||
// import { cva, type VariantProps } from 'class-variance-authority'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
// const alertVariants = cva(
|
||||
// "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
|
||||
// "relative w-full rounded-lg border p-4 [&>svg~*]:ps-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
|
||||
// {
|
||||
// variants: {
|
||||
// variant: {
|
||||
@@ -29,31 +29,26 @@ const Alert = React.forwardRef<
|
||||
ref={ref}
|
||||
role="alert"
|
||||
className={cn(
|
||||
'relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground bg-background text-foreground',
|
||||
"relative w-full rounded-lg border p-4 [&>svg~*]:ps-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground bg-background text-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Alert.displayName = 'Alert'
|
||||
Alert.displayName = "Alert"
|
||||
|
||||
const AlertTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<h5
|
||||
ref={ref}
|
||||
className={cn('mb-1 -mt-0.5 font-medium leading-tight tracking-tight', className)}
|
||||
{...props}
|
||||
/>
|
||||
<h5 ref={ref} className={cn("mb-1 -mt-0.5 font-medium leading-tight tracking-tight", className)} {...props} />
|
||||
)
|
||||
)
|
||||
AlertTitle.displayName = 'AlertTitle'
|
||||
AlertTitle.displayName = "AlertTitle"
|
||||
|
||||
const AlertDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn('text-sm [&_p]:leading-relaxed', className)} {...props} />
|
||||
))
|
||||
AlertDescription.displayName = 'AlertDescription'
|
||||
const AlertDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("text-sm [&_p]:leading-relaxed", className)} {...props} />
|
||||
)
|
||||
)
|
||||
AlertDescription.displayName = "AlertDescription"
|
||||
|
||||
export { Alert, AlertTitle, AlertDescription }
|
||||
|
||||
@@ -4,33 +4,26 @@ import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
||||
secondary:
|
||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
destructive:
|
||||
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
||||
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export interface BadgeProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof badgeVariants> {}
|
||||
export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}
|
||||
|
||||
function Badge({ className, variant, ...props }: BadgeProps) {
|
||||
return (
|
||||
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
||||
)
|
||||
return <div className={cn(badgeVariants({ variant }), className)} {...props} />
|
||||
}
|
||||
|
||||
export { Badge, badgeVariants }
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
import * as React from 'react'
|
||||
import { Slot } from '@radix-ui/react-slot'
|
||||
import { cva, type VariantProps } from 'class-variance-authority'
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
||||
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
||||
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: 'h-10 px-4 py-2',
|
||||
sm: 'h-9 rounded-md px-3',
|
||||
lg: 'h-11 rounded-md px-8',
|
||||
icon: 'h-10 w-10',
|
||||
default: "h-10 px-4 py-2",
|
||||
sm: "h-9 rounded-md px-3",
|
||||
lg: "h-11 rounded-md px-8",
|
||||
icon: "h-10 w-10",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default',
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -38,12 +38,10 @@ export interface ButtonProps
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : 'button'
|
||||
return (
|
||||
<Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
|
||||
)
|
||||
const Comp = asChild ? Slot : "button"
|
||||
return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
|
||||
}
|
||||
)
|
||||
Button.displayName = 'Button'
|
||||
Button.displayName = "Button"
|
||||
|
||||
export { Button, buttonVariants }
|
||||
|
||||
@@ -2,78 +2,40 @@ import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Card = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)} {...props} />
|
||||
))
|
||||
Card.displayName = "Card"
|
||||
|
||||
const CardHeader = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} />
|
||||
)
|
||||
)
|
||||
CardHeader.displayName = "CardHeader"
|
||||
|
||||
const CardTitle = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLHeadingElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<h3
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-2xl font-semibold leading-none tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<h3 ref={ref} className={cn("text-2xl font-semibold leading-none tracking-tight", className)} {...props} />
|
||||
)
|
||||
)
|
||||
CardTitle.displayName = "CardTitle"
|
||||
|
||||
const CardDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<p
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
const CardDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<p ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
|
||||
)
|
||||
)
|
||||
CardDescription.displayName = "CardDescription"
|
||||
|
||||
const CardContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
||||
))
|
||||
const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
||||
)
|
||||
CardContent.displayName = "CardContent"
|
||||
|
||||
const CardFooter = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("flex items-center p-6 pt-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => <div ref={ref} className={cn("flex items-center p-6 pt-0", className)} {...props} />
|
||||
)
|
||||
CardFooter.displayName = "CardFooter"
|
||||
|
||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
import * as React from 'react'
|
||||
import * as RechartsPrimitive from 'recharts'
|
||||
import * as React from "react"
|
||||
import * as RechartsPrimitive from "recharts"
|
||||
|
||||
import { chartTimeData, cn } from '@/lib/utils'
|
||||
import { ChartData } from '@/types'
|
||||
import { chartTimeData, cn } from "@/lib/utils"
|
||||
import { ChartData } from "@/types"
|
||||
|
||||
// Format: { THEME_NAME: CSS_SELECTOR }
|
||||
const THEMES = { light: '', dark: '.dark' } as const
|
||||
const THEMES = { light: "", dark: ".dark" } as const
|
||||
|
||||
export type ChartConfig = {
|
||||
[k in string]: {
|
||||
label?: React.ReactNode
|
||||
icon?: React.ComponentType
|
||||
} & (
|
||||
| { color?: string; theme?: never }
|
||||
| { color?: never; theme: Record<keyof typeof THEMES, string> }
|
||||
)
|
||||
} & ({ color?: string; theme?: never } | { color?: never; theme: Record<keyof typeof THEMES, string> })
|
||||
}
|
||||
|
||||
// type ChartContextProps = {
|
||||
@@ -35,13 +32,13 @@ export type ChartConfig = {
|
||||
|
||||
const ChartContainer = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.ComponentProps<'div'> & {
|
||||
React.ComponentProps<"div"> & {
|
||||
// config: ChartConfig
|
||||
children: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>['children']
|
||||
children: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>["children"]
|
||||
}
|
||||
>(({ id, className, children, ...props }, ref) => {
|
||||
const uniqueId = React.useId()
|
||||
const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`
|
||||
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
|
||||
|
||||
return (
|
||||
//<ChartContext.Provider value={{ config }}>
|
||||
@@ -60,7 +57,7 @@ const ChartContainer = React.forwardRef<
|
||||
//</ChartContext.Provider>
|
||||
)
|
||||
})
|
||||
ChartContainer.displayName = 'Chart'
|
||||
ChartContainer.displayName = "Chart"
|
||||
|
||||
// const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
|
||||
// const colorConfig = Object.entries(config).filter(([_, config]) => config.theme || config.color)
|
||||
@@ -94,9 +91,9 @@ const ChartTooltip = RechartsPrimitive.Tooltip
|
||||
const ChartTooltipContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
|
||||
React.ComponentProps<'div'> & {
|
||||
React.ComponentProps<"div"> & {
|
||||
hideLabel?: boolean
|
||||
indicator?: 'line' | 'dot' | 'dashed'
|
||||
indicator?: "line" | "dot" | "dashed"
|
||||
nameKey?: string
|
||||
labelKey?: string
|
||||
unit?: string
|
||||
@@ -109,7 +106,7 @@ const ChartTooltipContent = React.forwardRef<
|
||||
active,
|
||||
payload,
|
||||
className,
|
||||
indicator = 'line',
|
||||
indicator = "line",
|
||||
hideLabel = false,
|
||||
label,
|
||||
labelFormatter,
|
||||
@@ -144,21 +141,19 @@ const ChartTooltipContent = React.forwardRef<
|
||||
}
|
||||
|
||||
const [item] = payload
|
||||
const key = `${labelKey || item.name || 'value'}`
|
||||
const key = `${labelKey || item.name || "value"}`
|
||||
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||
const value = !labelKey && typeof label === 'string' ? label : itemConfig?.label
|
||||
const value = !labelKey && typeof label === "string" ? label : itemConfig?.label
|
||||
|
||||
if (labelFormatter) {
|
||||
return (
|
||||
<div className={cn('font-medium', labelClassName)}>{labelFormatter(value, payload)}</div>
|
||||
)
|
||||
return <div className={cn("font-medium", labelClassName)}>{labelFormatter(value, payload)}</div>
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <div className={cn('font-medium', labelClassName)}>{value}</div>
|
||||
return <div className={cn("font-medium", labelClassName)}>{value}</div>
|
||||
}, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey])
|
||||
|
||||
if (!active || !payload?.length) {
|
||||
@@ -172,14 +167,14 @@ const ChartTooltipContent = React.forwardRef<
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'grid min-w-[7rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl',
|
||||
"grid min-w-[7rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!nestLabel ? tooltipLabel : null}
|
||||
<div className="grid gap-1.5">
|
||||
{payload.map((item, index) => {
|
||||
const key = `${nameKey || item.name || item.dataKey || 'value'}`
|
||||
const key = `${nameKey || item.name || item.dataKey || "value"}`
|
||||
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||
const indicatorColor = color || item.payload.fill || item.color
|
||||
|
||||
@@ -187,8 +182,8 @@ const ChartTooltipContent = React.forwardRef<
|
||||
<div
|
||||
key={item?.name || item.dataKey}
|
||||
className={cn(
|
||||
'flex w-full items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground',
|
||||
indicator === 'dot' && 'items-center'
|
||||
"flex w-full items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
|
||||
indicator === "dot" && "items-center"
|
||||
)}
|
||||
>
|
||||
{formatter && item?.value !== undefined && item.name ? (
|
||||
@@ -199,41 +194,35 @@ const ChartTooltipContent = React.forwardRef<
|
||||
<itemConfig.icon />
|
||||
) : (
|
||||
<div
|
||||
className={cn(
|
||||
'shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]',
|
||||
{
|
||||
'h-2.5 w-2.5': indicator === 'dot',
|
||||
'w-1': indicator === 'line',
|
||||
'w-0 border-[1.5px] border-dashed bg-transparent':
|
||||
indicator === 'dashed',
|
||||
'my-0.5': nestLabel && indicator === 'dashed',
|
||||
}
|
||||
)}
|
||||
className={cn("shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]", {
|
||||
"h-2.5 w-2.5": indicator === "dot",
|
||||
"w-1": indicator === "line",
|
||||
"w-0 border-[1.5px] border-dashed bg-transparent": indicator === "dashed",
|
||||
"my-0.5": nestLabel && indicator === "dashed",
|
||||
})}
|
||||
style={
|
||||
{
|
||||
'--color-bg': indicatorColor,
|
||||
'--color-border': indicatorColor,
|
||||
"--color-bg": indicatorColor,
|
||||
"--color-border": indicatorColor,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
'flex flex-1 justify-between leading-none gap-2',
|
||||
nestLabel ? 'items-end' : 'items-center'
|
||||
"flex flex-1 justify-between leading-none gap-2",
|
||||
nestLabel ? "items-end" : "items-center"
|
||||
)}
|
||||
>
|
||||
<div className="grid gap-1.5">
|
||||
{nestLabel ? tooltipLabel : null}
|
||||
<span className="text-muted-foreground">
|
||||
{itemConfig?.label || item.name}
|
||||
</span>
|
||||
<span className="text-muted-foreground">{itemConfig?.label || item.name}</span>
|
||||
</div>
|
||||
{item.value !== undefined && (
|
||||
<span className="font-medium tabular-nums text-foreground">
|
||||
{content && typeof content === 'function'
|
||||
{content && typeof content === "function"
|
||||
? content(item, key)
|
||||
: item.value.toLocaleString() + (unit ? unit : '')}
|
||||
: item.value.toLocaleString() + (unit ? unit : "")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -247,18 +236,18 @@ const ChartTooltipContent = React.forwardRef<
|
||||
)
|
||||
}
|
||||
)
|
||||
ChartTooltipContent.displayName = 'ChartTooltip'
|
||||
ChartTooltipContent.displayName = "ChartTooltip"
|
||||
|
||||
const ChartLegend = RechartsPrimitive.Legend
|
||||
|
||||
const ChartLegendContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.ComponentProps<'div'> &
|
||||
Pick<RechartsPrimitive.LegendProps, 'payload' | 'verticalAlign'> & {
|
||||
React.ComponentProps<"div"> &
|
||||
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
|
||||
hideIcon?: boolean
|
||||
nameKey?: string
|
||||
}
|
||||
>(({ className, payload, verticalAlign = 'bottom' }, ref) => {
|
||||
>(({ className, payload, verticalAlign = "bottom" }, ref) => {
|
||||
// const { config } = useChart()
|
||||
|
||||
if (!payload?.length) {
|
||||
@@ -269,8 +258,8 @@ const ChartLegendContent = React.forwardRef<
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex items-center justify-center gap-4 gap-y-1 flex-wrap',
|
||||
verticalAlign === 'top' ? 'pb-3' : 'pt-3',
|
||||
"flex items-center justify-center gap-4 gap-y-1 flex-wrap",
|
||||
verticalAlign === "top" ? "pb-3" : "pt-3",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -283,7 +272,7 @@ const ChartLegendContent = React.forwardRef<
|
||||
key={item.value}
|
||||
className={cn(
|
||||
// 'flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground text-muted-foreground'
|
||||
'flex items-center gap-1.5 text-muted-foreground'
|
||||
"flex items-center gap-1.5 text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{/* {itemConfig?.icon && !hideIcon ? (
|
||||
@@ -304,27 +293,27 @@ const ChartLegendContent = React.forwardRef<
|
||||
</div>
|
||||
)
|
||||
})
|
||||
ChartLegendContent.displayName = 'ChartLegend'
|
||||
ChartLegendContent.displayName = "ChartLegend"
|
||||
|
||||
// Helper to extract item config from a payload.
|
||||
function getPayloadConfigFromPayload(config: ChartConfig, payload: unknown, key: string) {
|
||||
if (typeof payload !== 'object' || payload === null) {
|
||||
if (typeof payload !== "object" || payload === null) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const payloadPayload =
|
||||
'payload' in payload && typeof payload.payload === 'object' && payload.payload !== null
|
||||
"payload" in payload && typeof payload.payload === "object" && payload.payload !== null
|
||||
? payload.payload
|
||||
: undefined
|
||||
|
||||
let configLabelKey: string = key
|
||||
|
||||
if (key in payload && typeof payload[key as keyof typeof payload] === 'string') {
|
||||
if (key in payload && typeof payload[key as keyof typeof payload] === "string") {
|
||||
configLabelKey = payload[key as keyof typeof payload] as string
|
||||
} else if (
|
||||
payloadPayload &&
|
||||
key in payloadPayload &&
|
||||
typeof payloadPayload[key as keyof typeof payloadPayload] === 'string'
|
||||
typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
|
||||
) {
|
||||
configLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react'
|
||||
import * as CheckboxPrimitive from '@radix-ui/react-checkbox'
|
||||
import { Check } from 'lucide-react'
|
||||
import * as React from "react"
|
||||
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
||||
import { Check } from "lucide-react"
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Checkbox = React.forwardRef<
|
||||
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
||||
@@ -11,12 +11,12 @@ const Checkbox = React.forwardRef<
|
||||
<CheckboxPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'peer h-4 w-4 shrink-0 rounded-[.3em] border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
|
||||
"peer h-4 w-4 shrink-0 rounded-[.3em] border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<CheckboxPrimitive.Indicator className={cn('flex items-center justify-center text-current')}>
|
||||
<CheckboxPrimitive.Indicator className={cn("flex items-center justify-center text-current")}>
|
||||
<Check className="h-4 w-4" />
|
||||
</CheckboxPrimitive.Indicator>
|
||||
</CheckboxPrimitive.Root>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as React from 'react'
|
||||
import { DialogTitle, type DialogProps } from '@radix-ui/react-dialog'
|
||||
import { Command as CommandPrimitive } from 'cmdk'
|
||||
import { Search } from 'lucide-react'
|
||||
import * as React from "react"
|
||||
import { DialogTitle, type DialogProps } from "@radix-ui/react-dialog"
|
||||
import { Command as CommandPrimitive } from "cmdk"
|
||||
import { Search } from "lucide-react"
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Dialog, DialogContent } from '@/components/ui/dialog'
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
@@ -12,10 +12,7 @@ const Command = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex h-full w-full flex-col overflow-hidden bg-popover text-popover-foreground',
|
||||
className
|
||||
)}
|
||||
className={cn("flex h-full w-full flex-col overflow-hidden bg-popover text-popover-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
@@ -43,11 +40,11 @@ const CommandInput = React.forwardRef<
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<Search className="me-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
|
||||
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -63,7 +60,7 @@ const CommandList = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.List
|
||||
ref={ref}
|
||||
className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}
|
||||
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
@@ -73,9 +70,7 @@ CommandList.displayName = CommandPrimitive.List.displayName
|
||||
const CommandEmpty = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
||||
>((props, ref) => (
|
||||
<CommandPrimitive.Empty ref={ref} className="py-6 text-center text-sm" {...props} />
|
||||
))
|
||||
>((props, ref) => <CommandPrimitive.Empty ref={ref} className="py-6 text-center text-sm" {...props} />)
|
||||
|
||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||
|
||||
@@ -86,7 +81,7 @@ const CommandGroup = React.forwardRef<
|
||||
<CommandPrimitive.Group
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground',
|
||||
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -99,11 +94,7 @@ const CommandSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn('-mx-1 h-px bg-border', className)}
|
||||
{...props}
|
||||
/>
|
||||
<CommandPrimitive.Separator ref={ref} className={cn("-mx-1 h-px bg-border", className)} {...props} />
|
||||
))
|
||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||
|
||||
@@ -124,14 +115,9 @@ const CommandItem = React.forwardRef<
|
||||
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||
|
||||
const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn('ml-auto text-xs tracking-wide text-muted-foreground', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
return <span className={cn("ms-auto text-xs tracking-wide text-muted-foreground", className)} {...props} />
|
||||
}
|
||||
CommandShortcut.displayName = 'CommandShortcut'
|
||||
CommandShortcut.displayName = "CommandShortcut"
|
||||
|
||||
export {
|
||||
Command,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react'
|
||||
import * as DialogPrimitive from '@radix-ui/react-dialog'
|
||||
import { X } from 'lucide-react'
|
||||
import * as React from "react"
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
||||
import { X } from "lucide-react"
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Dialog = DialogPrimitive.Root
|
||||
|
||||
@@ -19,7 +19,7 @@ const DialogOverlay = React.forwardRef<
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
||||
"fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -36,13 +36,13 @@ const DialogContent = React.forwardRef<
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-card p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-card p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<DialogPrimitive.Close className="absolute end-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
@@ -52,17 +52,14 @@ const DialogContent = React.forwardRef<
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName
|
||||
|
||||
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div className={cn('flex flex-col space-y-1.5 text-center sm:text-left', className)} {...props} />
|
||||
<div className={cn("flex flex-col space-y-1.5 text-center sm:text-start", className)} {...props} />
|
||||
)
|
||||
DialogHeader.displayName = 'DialogHeader'
|
||||
DialogHeader.displayName = "DialogHeader"
|
||||
|
||||
const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
<div className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-3.5", className)} {...props} />
|
||||
)
|
||||
DialogFooter.displayName = 'DialogFooter'
|
||||
DialogFooter.displayName = "DialogFooter"
|
||||
|
||||
const DialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||
@@ -70,7 +67,7 @@ const DialogTitle = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn('text-lg font-semibold leading-none tracking-tight', className)}
|
||||
className={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
@@ -80,11 +77,7 @@ const DialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn('text-sm text-muted-foreground', className)}
|
||||
{...props}
|
||||
/>
|
||||
<DialogPrimitive.Description ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
|
||||
))
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
||||
|
||||
|
||||
@@ -17,182 +17,163 @@ const DropdownMenuSub = DropdownMenuPrimitive.Sub
|
||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
|
||||
|
||||
const DropdownMenuSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean
|
||||
}
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRight className="ml-auto h-4 w-4" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2.5 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
|
||||
inset && "ps-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRight className="ms-auto h-4 w-4" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
))
|
||||
DropdownMenuSubTrigger.displayName =
|
||||
DropdownMenuPrimitive.SubTrigger.displayName
|
||||
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName
|
||||
|
||||
const DropdownMenuSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuSubContent.displayName =
|
||||
DropdownMenuPrimitive.SubContent.displayName
|
||||
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName
|
||||
|
||||
const DropdownMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
))
|
||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
||||
|
||||
const DropdownMenuItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean
|
||||
}
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2.5 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
inset && "ps-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
||||
|
||||
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
||||
>(({ className, children, checked, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 ps-8 pe-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
))
|
||||
DropdownMenuCheckboxItem.displayName =
|
||||
DropdownMenuPrimitive.CheckboxItem.displayName
|
||||
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName
|
||||
|
||||
const DropdownMenuRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Circle className="h-2 w-2 fill-current" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 ps-8 pe-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Circle className="h-2 w-2 fill-current" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
))
|
||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
||||
|
||||
const DropdownMenuLabel = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean
|
||||
}
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<DropdownMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn("px-2.5 py-1.5 text-sm font-semibold", inset && "ps-8", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
||||
|
||||
const DropdownMenuSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
{...props}
|
||||
/>
|
||||
<DropdownMenuPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
|
||||
))
|
||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
||||
|
||||
const DropdownMenuShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return <span className={cn("ms-auto text-xs tracking-widest opacity-60", className)} {...props} />
|
||||
}
|
||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuRadioGroup,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SVGProps } from 'react'
|
||||
import { SVGProps } from "react"
|
||||
|
||||
// linux-logo-bold from https://github.com/phosphor-icons/core (MIT license)
|
||||
export function TuxIcon(props: SVGProps<SVGSVGElement>) {
|
||||
@@ -49,14 +49,7 @@ export function ChartMax(props: SVGProps<SVGSVGElement>) {
|
||||
// Lucide https://github.com/lucide-icons/lucide (not in package for some reason)
|
||||
export function EthernetIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeWidth="2"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<svg fill="none" stroke="currentColor" strokeLinecap="round" strokeWidth="2" viewBox="0 0 24 24" {...props}>
|
||||
<path d="m15 20 3-3h2a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h2l3 3zM6 8v1m4-1v1m4-1v1m4-1v1" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
import * as React from 'react'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { XIcon } from 'lucide-react'
|
||||
import { type InputProps } from './input'
|
||||
import { cn } from '@/lib/utils'
|
||||
import * as React from "react"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { XIcon } from "lucide-react"
|
||||
import { type InputProps } from "./input"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
type InputTagsProps = Omit<InputProps, 'value' | 'onChange'> & {
|
||||
type InputTagsProps = Omit<InputProps, "value" | "onChange"> & {
|
||||
value: string[]
|
||||
onChange: React.Dispatch<React.SetStateAction<string[]>>
|
||||
}
|
||||
|
||||
const InputTags = React.forwardRef<HTMLInputElement, InputTagsProps>(
|
||||
({ className, value, onChange, ...props }, ref) => {
|
||||
const [pendingDataPoint, setPendingDataPoint] = React.useState('')
|
||||
const [pendingDataPoint, setPendingDataPoint] = React.useState("")
|
||||
|
||||
React.useEffect(() => {
|
||||
if (pendingDataPoint.includes(',')) {
|
||||
const newDataPoints = new Set([
|
||||
...value,
|
||||
...pendingDataPoint.split(',').map((chunk) => chunk.trim()),
|
||||
])
|
||||
if (pendingDataPoint.includes(",")) {
|
||||
const newDataPoints = new Set([...value, ...pendingDataPoint.split(",").map((chunk) => chunk.trim())])
|
||||
onChange(Array.from(newDataPoints))
|
||||
setPendingDataPoint('')
|
||||
setPendingDataPoint("")
|
||||
}
|
||||
}, [pendingDataPoint, onChange, value])
|
||||
|
||||
@@ -29,14 +26,14 @@ const InputTags = React.forwardRef<HTMLInputElement, InputTagsProps>(
|
||||
if (pendingDataPoint) {
|
||||
const newDataPoints = new Set([...value, pendingDataPoint])
|
||||
onChange(Array.from(newDataPoints))
|
||||
setPendingDataPoint('')
|
||||
setPendingDataPoint("")
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'bg-background min-h-10 flex w-full flex-wrap gap-2 rounded-md border border-input px-3 py-2 text-sm placeholder:text-muted-foreground has-[:focus-visible]:outline-none ring-offset-background has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-ring has-[:focus-visible]:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
"bg-background min-h-10 flex w-full flex-wrap gap-2 rounded-md border border-input px-3 py-2 text-sm placeholder:text-muted-foreground has-[:focus-visible]:outline-none ring-offset-background has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-ring has-[:focus-visible]:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
>
|
||||
@@ -46,7 +43,7 @@ const InputTags = React.forwardRef<HTMLInputElement, InputTagsProps>(
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="ml-2 h-3 w-3"
|
||||
className="ms-2 h-3 w-3"
|
||||
onClick={() => {
|
||||
onChange(value.filter((i) => i !== item))
|
||||
}}
|
||||
@@ -60,10 +57,10 @@ const InputTags = React.forwardRef<HTMLInputElement, InputTagsProps>(
|
||||
value={pendingDataPoint}
|
||||
onChange={(e) => setPendingDataPoint(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ',') {
|
||||
if (e.key === "Enter" || e.key === ",") {
|
||||
e.preventDefault()
|
||||
addPendingDataPoint()
|
||||
} else if (e.key === 'Backspace' && pendingDataPoint.length === 0 && value.length > 0) {
|
||||
} else if (e.key === "Backspace" && pendingDataPoint.length === 0 && value.length > 0) {
|
||||
e.preventDefault()
|
||||
onChange(value.slice(0, -1))
|
||||
}
|
||||
@@ -76,6 +73,6 @@ const InputTags = React.forwardRef<HTMLInputElement, InputTagsProps>(
|
||||
}
|
||||
)
|
||||
|
||||
InputTags.displayName = 'InputTags'
|
||||
InputTags.displayName = "InputTags"
|
||||
|
||||
export { InputTags }
|
||||
|
||||
@@ -2,24 +2,21 @@ import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export interface InputProps
|
||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(({ className, type, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
Input.displayName = "Input"
|
||||
|
||||
export { Input }
|
||||
|
||||
@@ -4,20 +4,13 @@ import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const labelVariants = cva(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
)
|
||||
const labelVariants = cva("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70")
|
||||
|
||||
const Label = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
||||
VariantProps<typeof labelVariants>
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<LabelPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(labelVariants(), className)}
|
||||
{...props}
|
||||
/>
|
||||
<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
|
||||
))
|
||||
Label.displayName = LabelPrimitive.Root.displayName
|
||||
|
||||
|
||||
@@ -11,148 +11,133 @@ const SelectGroup = SelectPrimitive.Group
|
||||
const SelectValue = SelectPrimitive.Value
|
||||
|
||||
const SelectTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
))
|
||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
||||
|
||||
const SelectScrollUpButton = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
ref={ref}
|
||||
className={cn("flex cursor-default items-center justify-center py-1", className)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
))
|
||||
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
||||
|
||||
const SelectScrollDownButton = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
ref={ref}
|
||||
className={cn("flex cursor-default items-center justify-center py-1", className)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
))
|
||||
SelectScrollDownButton.displayName =
|
||||
SelectPrimitive.ScrollDownButton.displayName
|
||||
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName
|
||||
|
||||
const SelectContent = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||
>(({ className, children, position = "popper", ...props }, ref) => (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
))
|
||||
SelectContent.displayName = SelectPrimitive.Content.displayName
|
||||
|
||||
const SelectLabel = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
|
||||
{...props}
|
||||
/>
|
||||
<SelectPrimitive.Label ref={ref} className={cn("py-1.5 ps-8 pe-2 text-sm font-semibold", className)} {...props} />
|
||||
))
|
||||
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
||||
|
||||
const SelectItem = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 ps-8 pe-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
))
|
||||
SelectItem.displayName = SelectPrimitive.Item.displayName
|
||||
|
||||
const SelectSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
{...props}
|
||||
/>
|
||||
<SelectPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
|
||||
))
|
||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectGroup,
|
||||
SelectValue,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectScrollUpButton,
|
||||
SelectScrollDownButton,
|
||||
Select,
|
||||
SelectGroup,
|
||||
SelectValue,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectScrollUpButton,
|
||||
SelectScrollDownButton,
|
||||
}
|
||||
|
||||
@@ -4,26 +4,17 @@ import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Separator = React.forwardRef<
|
||||
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
|
||||
>(
|
||||
(
|
||||
{ className, orientation = "horizontal", decorative = true, ...props },
|
||||
ref
|
||||
) => (
|
||||
<SeparatorPrimitive.Root
|
||||
ref={ref}
|
||||
decorative={decorative}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"shrink-0 bg-border",
|
||||
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)
|
||||
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
|
||||
>(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => (
|
||||
<SeparatorPrimitive.Root
|
||||
ref={ref}
|
||||
decorative={decorative}
|
||||
orientation={orientation}
|
||||
className={cn("shrink-0 bg-border", orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Separator.displayName = SeparatorPrimitive.Root.displayName
|
||||
|
||||
export { Separator }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react'
|
||||
import * as SliderPrimitive from '@radix-ui/react-slider'
|
||||
import * as React from "react"
|
||||
import * as SliderPrimitive from "@radix-ui/react-slider"
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Slider = React.forwardRef<
|
||||
React.ElementRef<typeof SliderPrimitive.Root>,
|
||||
@@ -9,7 +9,7 @@ const Slider = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SliderPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn('relative flex w-full touch-none select-none items-center', className)}
|
||||
className={cn("relative flex w-full touch-none select-none items-center", className)}
|
||||
{...props}
|
||||
>
|
||||
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
|
||||
|
||||
@@ -4,23 +4,23 @@ import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Switch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 rtl:data-[state=checked]:-translate-x-5 data-[state=unchecked]:translate-x-0"
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
))
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName
|
||||
|
||||
|
||||
@@ -1,91 +1,72 @@
|
||||
import * as React from 'react'
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div className="relative w-full overflow-auto">
|
||||
<table ref={ref} className={cn('w-full caption-bottom text-sm', className)} {...props} />
|
||||
<table ref={ref} className={cn("w-full caption-bottom text-sm", className)} {...props} />
|
||||
</div>
|
||||
)
|
||||
)
|
||||
Table.displayName = 'Table'
|
||||
Table.displayName = "Table"
|
||||
|
||||
const TableHeader = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<thead ref={ref} className={cn('[&_tr]:border-b', className)} {...props} />
|
||||
))
|
||||
TableHeader.displayName = 'TableHeader'
|
||||
const TableHeader = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(
|
||||
({ className, ...props }, ref) => <thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
||||
)
|
||||
TableHeader.displayName = "TableHeader"
|
||||
|
||||
const TableBody = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tbody ref={ref} className={cn('[&_tr:last-child]:border-0', className)} {...props} />
|
||||
))
|
||||
TableBody.displayName = 'TableBody'
|
||||
const TableBody = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<tbody ref={ref} className={cn("[&_tr:last-child]:border-0", className)} {...props} />
|
||||
)
|
||||
)
|
||||
TableBody.displayName = "TableBody"
|
||||
|
||||
const TableFooter = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tfoot
|
||||
ref={ref}
|
||||
className={cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableFooter.displayName = 'TableFooter'
|
||||
const TableFooter = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<tfoot ref={ref} className={cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className)} {...props} />
|
||||
)
|
||||
)
|
||||
TableFooter.displayName = "TableFooter"
|
||||
|
||||
const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<tr
|
||||
ref={ref}
|
||||
className={cn("border-b hover:bg-muted/40 dark:hover:bg-muted/30 data-[state=selected]:bg-muted", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)
|
||||
TableRow.displayName = "TableRow"
|
||||
|
||||
const TableHead = React.forwardRef<HTMLTableCellElement, React.ThHTMLAttributes<HTMLTableCellElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<th
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'border-b hover:bg-muted/40 dark:hover:bg-muted/30 data-[state=selected]:bg-muted',
|
||||
"h-12 px-4 text-start align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pe-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)
|
||||
TableRow.displayName = 'TableRow'
|
||||
TableHead.displayName = "TableHead"
|
||||
|
||||
const TableHead = React.forwardRef<
|
||||
HTMLTableCellElement,
|
||||
React.ThHTMLAttributes<HTMLTableCellElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<th
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableHead.displayName = 'TableHead'
|
||||
const TableCell = React.forwardRef<HTMLTableCellElement, React.TdHTMLAttributes<HTMLTableCellElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<td ref={ref} className={cn("p-4 align-middle [&:has([role=checkbox])]:pe-0", className)} {...props} />
|
||||
)
|
||||
)
|
||||
TableCell.displayName = "TableCell"
|
||||
|
||||
const TableCell = React.forwardRef<
|
||||
HTMLTableCellElement,
|
||||
React.TdHTMLAttributes<HTMLTableCellElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<td
|
||||
ref={ref}
|
||||
className={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableCell.displayName = 'TableCell'
|
||||
|
||||
const TableCaption = React.forwardRef<
|
||||
HTMLTableCaptionElement,
|
||||
React.HTMLAttributes<HTMLTableCaptionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<caption ref={ref} className={cn('mt-4 text-sm text-muted-foreground', className)} {...props} />
|
||||
))
|
||||
TableCaption.displayName = 'TableCaption'
|
||||
const TableCaption = React.forwardRef<HTMLTableCaptionElement, React.HTMLAttributes<HTMLTableCaptionElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<caption ref={ref} className={cn("mt-4 text-sm text-muted-foreground", className)} {...props} />
|
||||
)
|
||||
)
|
||||
TableCaption.displayName = "TableCaption"
|
||||
|
||||
export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption }
|
||||
|
||||
@@ -6,47 +6,47 @@ import { cn } from "@/lib/utils"
|
||||
const Tabs = TabsPrimitive.Root
|
||||
|
||||
const TabsList = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||
React.ElementRef<typeof TabsPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TabsList.displayName = TabsPrimitive.List.displayName
|
||||
|
||||
const TabsTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
||||
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<TabsPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
|
||||
|
||||
const TabsContent = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
||||
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
<TabsPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TabsContent.displayName = TabsPrimitive.Content.displayName
|
||||
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
import * as React from 'react'
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||
|
||||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
'flex min-h-14 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Textarea.displayName = 'Textarea'
|
||||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"flex min-h-14 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
Textarea.displayName = "Textarea"
|
||||
|
||||
export { Textarea }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as React from 'react'
|
||||
import * as ToastPrimitives from '@radix-ui/react-toast'
|
||||
import { cva, type VariantProps } from 'class-variance-authority'
|
||||
import { X } from 'lucide-react'
|
||||
import * as React from "react"
|
||||
import * as ToastPrimitives from "@radix-ui/react-toast"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { X } from "lucide-react"
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const ToastProvider = ToastPrimitives.Provider
|
||||
|
||||
@@ -14,7 +14,7 @@ const ToastViewport = React.forwardRef<
|
||||
<ToastPrimitives.Viewport
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'fixed top-0 z-[100] flex max-h-dvh w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]',
|
||||
"fixed top-0 z-[100] flex max-h-dvh w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -23,17 +23,16 @@ const ToastViewport = React.forwardRef<
|
||||
ToastViewport.displayName = ToastPrimitives.Viewport.displayName
|
||||
|
||||
const toastVariants = cva(
|
||||
'group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full',
|
||||
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pe-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'border bg-background text-foreground',
|
||||
destructive:
|
||||
'destructive group border-destructive bg-destructive text-destructive-foreground',
|
||||
default: "border bg-background text-foreground",
|
||||
destructive: "destructive group border-destructive bg-destructive text-destructive-foreground",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -42,13 +41,7 @@ const Toast = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> & VariantProps<typeof toastVariants>
|
||||
>(({ className, variant, ...props }, ref) => {
|
||||
return (
|
||||
<ToastPrimitives.Root
|
||||
ref={ref}
|
||||
className={cn(toastVariants({ variant }), className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
return <ToastPrimitives.Root ref={ref} className={cn(toastVariants({ variant }), className)} {...props} />
|
||||
})
|
||||
Toast.displayName = ToastPrimitives.Root.displayName
|
||||
|
||||
@@ -59,7 +52,7 @@ const ToastAction = React.forwardRef<
|
||||
<ToastPrimitives.Action
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive',
|
||||
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -74,7 +67,7 @@ const ToastClose = React.forwardRef<
|
||||
<ToastPrimitives.Close
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600',
|
||||
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
|
||||
className
|
||||
)}
|
||||
toast-close=""
|
||||
@@ -89,7 +82,7 @@ const ToastTitle = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Title ref={ref} className={cn('text-sm font-semibold', className)} {...props} />
|
||||
<ToastPrimitives.Title ref={ref} className={cn("text-sm font-semibold", className)} {...props} />
|
||||
))
|
||||
ToastTitle.displayName = ToastPrimitives.Title.displayName
|
||||
|
||||
@@ -97,11 +90,7 @@ const ToastDescription = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Description
|
||||
ref={ref}
|
||||
className={cn('text-sm opacity-90', className)}
|
||||
{...props}
|
||||
/>
|
||||
<ToastPrimitives.Description ref={ref} className={cn("text-sm opacity-90", className)} {...props} />
|
||||
))
|
||||
ToastDescription.displayName = ToastPrimitives.Description.displayName
|
||||
|
||||
|
||||
@@ -1,33 +1,24 @@
|
||||
import {
|
||||
Toast,
|
||||
ToastClose,
|
||||
ToastDescription,
|
||||
ToastProvider,
|
||||
ToastTitle,
|
||||
ToastViewport,
|
||||
} from "@/components/ui/toast"
|
||||
import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from "@/components/ui/toast"
|
||||
import { useToast } from "@/components/ui/use-toast"
|
||||
|
||||
export function Toaster() {
|
||||
const { toasts } = useToast()
|
||||
const { toasts } = useToast()
|
||||
|
||||
return (
|
||||
<ToastProvider>
|
||||
{toasts.map(function ({ id, title, description, action, ...props }) {
|
||||
return (
|
||||
<Toast key={id} {...props}>
|
||||
<div className="grid gap-1">
|
||||
{title && <ToastTitle>{title}</ToastTitle>}
|
||||
{description && (
|
||||
<ToastDescription>{description}</ToastDescription>
|
||||
)}
|
||||
</div>
|
||||
{action}
|
||||
<ToastClose />
|
||||
</Toast>
|
||||
)
|
||||
})}
|
||||
<ToastViewport />
|
||||
</ToastProvider>
|
||||
)
|
||||
return (
|
||||
<ToastProvider>
|
||||
{toasts.map(function ({ id, title, description, action, ...props }) {
|
||||
return (
|
||||
<Toast key={id} {...props}>
|
||||
<div className="grid gap-1">
|
||||
{title && <ToastTitle>{title}</ToastTitle>}
|
||||
{description && <ToastDescription>{description}</ToastDescription>}
|
||||
</div>
|
||||
{action}
|
||||
<ToastClose />
|
||||
</Toast>
|
||||
)
|
||||
})}
|
||||
<ToastViewport />
|
||||
</ToastProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react'
|
||||
import * as TooltipPrimitive from '@radix-ui/react-tooltip'
|
||||
import * as React from "react"
|
||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const TooltipProvider = TooltipPrimitive.Provider
|
||||
|
||||
@@ -17,7 +17,7 @@ const TooltipContent = React.forwardRef<
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -1,130 +1,125 @@
|
||||
// Inspired by react-hot-toast library
|
||||
import * as React from "react"
|
||||
|
||||
import type {
|
||||
ToastActionElement,
|
||||
ToastProps,
|
||||
} from "@/components/ui/toast"
|
||||
import type { ToastActionElement, ToastProps } from "@/components/ui/toast"
|
||||
|
||||
const TOAST_LIMIT = 1
|
||||
const TOAST_REMOVE_DELAY = 1000000
|
||||
|
||||
type ToasterToast = ToastProps & {
|
||||
id: string
|
||||
title?: React.ReactNode
|
||||
description?: React.ReactNode
|
||||
action?: ToastActionElement
|
||||
id: string
|
||||
title?: React.ReactNode
|
||||
description?: React.ReactNode
|
||||
action?: ToastActionElement
|
||||
}
|
||||
|
||||
const actionTypes = {
|
||||
ADD_TOAST: "ADD_TOAST",
|
||||
UPDATE_TOAST: "UPDATE_TOAST",
|
||||
DISMISS_TOAST: "DISMISS_TOAST",
|
||||
REMOVE_TOAST: "REMOVE_TOAST",
|
||||
ADD_TOAST: "ADD_TOAST",
|
||||
UPDATE_TOAST: "UPDATE_TOAST",
|
||||
DISMISS_TOAST: "DISMISS_TOAST",
|
||||
REMOVE_TOAST: "REMOVE_TOAST",
|
||||
} as const
|
||||
|
||||
let count = 0
|
||||
|
||||
function genId() {
|
||||
count = (count + 1) % Number.MAX_SAFE_INTEGER
|
||||
return count.toString()
|
||||
count = (count + 1) % Number.MAX_SAFE_INTEGER
|
||||
return count.toString()
|
||||
}
|
||||
|
||||
type ActionType = typeof actionTypes
|
||||
|
||||
type Action =
|
||||
| {
|
||||
type: ActionType["ADD_TOAST"]
|
||||
toast: ToasterToast
|
||||
}
|
||||
| {
|
||||
type: ActionType["UPDATE_TOAST"]
|
||||
toast: Partial<ToasterToast>
|
||||
}
|
||||
| {
|
||||
type: ActionType["DISMISS_TOAST"]
|
||||
toastId?: ToasterToast["id"]
|
||||
}
|
||||
| {
|
||||
type: ActionType["REMOVE_TOAST"]
|
||||
toastId?: ToasterToast["id"]
|
||||
}
|
||||
| {
|
||||
type: ActionType["ADD_TOAST"]
|
||||
toast: ToasterToast
|
||||
}
|
||||
| {
|
||||
type: ActionType["UPDATE_TOAST"]
|
||||
toast: Partial<ToasterToast>
|
||||
}
|
||||
| {
|
||||
type: ActionType["DISMISS_TOAST"]
|
||||
toastId?: ToasterToast["id"]
|
||||
}
|
||||
| {
|
||||
type: ActionType["REMOVE_TOAST"]
|
||||
toastId?: ToasterToast["id"]
|
||||
}
|
||||
|
||||
interface State {
|
||||
toasts: ToasterToast[]
|
||||
toasts: ToasterToast[]
|
||||
}
|
||||
|
||||
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
|
||||
|
||||
const addToRemoveQueue = (toastId: string) => {
|
||||
if (toastTimeouts.has(toastId)) {
|
||||
return
|
||||
}
|
||||
if (toastTimeouts.has(toastId)) {
|
||||
return
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
toastTimeouts.delete(toastId)
|
||||
dispatch({
|
||||
type: "REMOVE_TOAST",
|
||||
toastId: toastId,
|
||||
})
|
||||
}, TOAST_REMOVE_DELAY)
|
||||
const timeout = setTimeout(() => {
|
||||
toastTimeouts.delete(toastId)
|
||||
dispatch({
|
||||
type: "REMOVE_TOAST",
|
||||
toastId: toastId,
|
||||
})
|
||||
}, TOAST_REMOVE_DELAY)
|
||||
|
||||
toastTimeouts.set(toastId, timeout)
|
||||
toastTimeouts.set(toastId, timeout)
|
||||
}
|
||||
|
||||
export const reducer = (state: State, action: Action): State => {
|
||||
switch (action.type) {
|
||||
case "ADD_TOAST":
|
||||
return {
|
||||
...state,
|
||||
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
|
||||
}
|
||||
switch (action.type) {
|
||||
case "ADD_TOAST":
|
||||
return {
|
||||
...state,
|
||||
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
|
||||
}
|
||||
|
||||
case "UPDATE_TOAST":
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) =>
|
||||
t.id === action.toast.id ? { ...t, ...action.toast } : t
|
||||
),
|
||||
}
|
||||
case "UPDATE_TOAST":
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) => (t.id === action.toast.id ? { ...t, ...action.toast } : t)),
|
||||
}
|
||||
|
||||
case "DISMISS_TOAST": {
|
||||
const { toastId } = action
|
||||
case "DISMISS_TOAST": {
|
||||
const { toastId } = action
|
||||
|
||||
// ! Side effects ! - This could be extracted into a dismissToast() action,
|
||||
// but I'll keep it here for simplicity
|
||||
if (toastId) {
|
||||
addToRemoveQueue(toastId)
|
||||
} else {
|
||||
state.toasts.forEach((toast) => {
|
||||
addToRemoveQueue(toast.id)
|
||||
})
|
||||
}
|
||||
// ! Side effects ! - This could be extracted into a dismissToast() action,
|
||||
// but I'll keep it here for simplicity
|
||||
if (toastId) {
|
||||
addToRemoveQueue(toastId)
|
||||
} else {
|
||||
state.toasts.forEach((toast) => {
|
||||
addToRemoveQueue(toast.id)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) =>
|
||||
t.id === toastId || toastId === undefined
|
||||
? {
|
||||
...t,
|
||||
open: false,
|
||||
}
|
||||
: t
|
||||
),
|
||||
}
|
||||
}
|
||||
case "REMOVE_TOAST":
|
||||
if (action.toastId === undefined) {
|
||||
return {
|
||||
...state,
|
||||
toasts: [],
|
||||
}
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.filter((t) => t.id !== action.toastId),
|
||||
}
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) =>
|
||||
t.id === toastId || toastId === undefined
|
||||
? {
|
||||
...t,
|
||||
open: false,
|
||||
}
|
||||
: t
|
||||
),
|
||||
}
|
||||
}
|
||||
case "REMOVE_TOAST":
|
||||
if (action.toastId === undefined) {
|
||||
return {
|
||||
...state,
|
||||
toasts: [],
|
||||
}
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.filter((t) => t.id !== action.toastId),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const listeners: Array<(state: State) => void> = []
|
||||
@@ -132,61 +127,61 @@ const listeners: Array<(state: State) => void> = []
|
||||
let memoryState: State = { toasts: [] }
|
||||
|
||||
function dispatch(action: Action) {
|
||||
memoryState = reducer(memoryState, action)
|
||||
listeners.forEach((listener) => {
|
||||
listener(memoryState)
|
||||
})
|
||||
memoryState = reducer(memoryState, action)
|
||||
listeners.forEach((listener) => {
|
||||
listener(memoryState)
|
||||
})
|
||||
}
|
||||
|
||||
type Toast = Omit<ToasterToast, "id">
|
||||
|
||||
function toast({ ...props }: Toast) {
|
||||
const id = genId()
|
||||
const id = genId()
|
||||
|
||||
const update = (props: ToasterToast) =>
|
||||
dispatch({
|
||||
type: "UPDATE_TOAST",
|
||||
toast: { ...props, id },
|
||||
})
|
||||
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
|
||||
const update = (props: ToasterToast) =>
|
||||
dispatch({
|
||||
type: "UPDATE_TOAST",
|
||||
toast: { ...props, id },
|
||||
})
|
||||
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
|
||||
|
||||
dispatch({
|
||||
type: "ADD_TOAST",
|
||||
toast: {
|
||||
...props,
|
||||
id,
|
||||
open: true,
|
||||
onOpenChange: (open) => {
|
||||
if (!open) dismiss()
|
||||
},
|
||||
},
|
||||
})
|
||||
dispatch({
|
||||
type: "ADD_TOAST",
|
||||
toast: {
|
||||
...props,
|
||||
id,
|
||||
open: true,
|
||||
onOpenChange: (open) => {
|
||||
if (!open) dismiss()
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
id: id,
|
||||
dismiss,
|
||||
update,
|
||||
}
|
||||
return {
|
||||
id: id,
|
||||
dismiss,
|
||||
update,
|
||||
}
|
||||
}
|
||||
|
||||
function useToast() {
|
||||
const [state, setState] = React.useState<State>(memoryState)
|
||||
const [state, setState] = React.useState<State>(memoryState)
|
||||
|
||||
React.useEffect(() => {
|
||||
listeners.push(setState)
|
||||
return () => {
|
||||
const index = listeners.indexOf(setState)
|
||||
if (index > -1) {
|
||||
listeners.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}, [state])
|
||||
React.useEffect(() => {
|
||||
listeners.push(setState)
|
||||
return () => {
|
||||
const index = listeners.indexOf(setState)
|
||||
if (index > -1) {
|
||||
listeners.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}, [state])
|
||||
|
||||
return {
|
||||
...state,
|
||||
toast,
|
||||
dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
toast,
|
||||
dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
|
||||
}
|
||||
}
|
||||
|
||||
export { useToast, toast }
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
--muted-foreground: 240 5.03% 64.9%;
|
||||
--accent: 240 3.7% 15.88%;
|
||||
--accent-foreground: 0 0% 98.04%;
|
||||
--destructive: 0 56.48% 42.35%;
|
||||
--destructive: 0 59% 46%;
|
||||
--destructive-foreground: 0 0% 98.04%;
|
||||
--border: 240 2.86% 12%;
|
||||
--input: 240 3.7% 15.88%;
|
||||
@@ -68,7 +68,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url('/static/InterVariable.woff2?v=4.0') format('woff2');
|
||||
src: url("/static/InterVariable.woff2?v=4.0") format("woff2");
|
||||
}
|
||||
|
||||
@layer base {
|
||||
|
||||
62
beszel/site/src/lib/i18n.ts
Normal file
62
beszel/site/src/lib/i18n.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { $direction } from "./stores"
|
||||
import { i18n } from "@lingui/core"
|
||||
import type { Messages } from "@lingui/core"
|
||||
import languages from "@/lib/languages"
|
||||
import { detect, fromUrl, 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)
|
||||
}
|
||||
|
||||
// activates locale
|
||||
function activateLocale(locale: string, messages: Messages = enMessages) {
|
||||
i18n.load(locale, messages)
|
||||
i18n.activate(locale)
|
||||
document.documentElement.lang = locale
|
||||
localStorage.setItem("lang", locale)
|
||||
$direction.set(locale.startsWith("ar") ? "rtl" : "ltr")
|
||||
}
|
||||
|
||||
// dynamically loads translations for the given locale
|
||||
export async function dynamicActivate(locale: string) {
|
||||
if (locale == "en") {
|
||||
activateLocale(locale)
|
||||
} else {
|
||||
try {
|
||||
const { messages }: { messages: Messages } = await import(`../locales/${locale}/${locale}.ts`)
|
||||
activateLocale(locale, messages)
|
||||
} catch (error) {
|
||||
console.error(`Error loading ${locale}`, error)
|
||||
activateLocale("en")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle zh variants
|
||||
if (locale?.startsWith("zh-")) {
|
||||
// map zh variants to zh-CN
|
||||
const zhVariantMap: Record<string, string> = {
|
||||
"zh-CN": "zh-CN",
|
||||
"zh-SG": "zh-CN",
|
||||
"zh-MY": "zh-CN",
|
||||
zh: "zh-CN",
|
||||
"zh-Hans": "zh-CN",
|
||||
"zh-HK": "zh-HK",
|
||||
"zh-TW": "zh-HK",
|
||||
"zh-MO": "zh-HK",
|
||||
"zh-Hant": "zh-HK",
|
||||
}
|
||||
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)
|
||||
}
|
||||
77
beszel/site/src/lib/languages.ts
Normal file
77
beszel/site/src/lib/languages.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
export default [
|
||||
{
|
||||
lang: "ar",
|
||||
label: "العربية",
|
||||
e: "🇵🇸",
|
||||
},
|
||||
{
|
||||
lang: "de",
|
||||
label: "Deutsch",
|
||||
e: "🇩🇪",
|
||||
},
|
||||
{
|
||||
lang: "en",
|
||||
label: "English",
|
||||
e: "🇺🇸",
|
||||
},
|
||||
{
|
||||
lang: "es",
|
||||
label: "Español",
|
||||
e: "🇲🇽",
|
||||
},
|
||||
{
|
||||
lang: "fr",
|
||||
label: "Français",
|
||||
e: "🇫🇷",
|
||||
},
|
||||
{
|
||||
lang: "it",
|
||||
label: "Italiano",
|
||||
e: "🇮🇹",
|
||||
},
|
||||
{
|
||||
lang: "ja",
|
||||
label: "日本語",
|
||||
e: "🇯🇵",
|
||||
},
|
||||
{
|
||||
lang: "ko",
|
||||
label: "한국어",
|
||||
e: "🇰🇷",
|
||||
},
|
||||
{
|
||||
lang: "pt",
|
||||
label: "Português",
|
||||
e: "🇧🇷",
|
||||
},
|
||||
{
|
||||
lang: "tr",
|
||||
label: "Türkçe",
|
||||
e: "🇹🇷",
|
||||
},
|
||||
{
|
||||
lang: "ru",
|
||||
label: "Русский",
|
||||
e: "🇷🇺",
|
||||
},
|
||||
{
|
||||
lang: "uk",
|
||||
label: "Українська",
|
||||
e: "🇺🇦",
|
||||
},
|
||||
{
|
||||
lang: "vi",
|
||||
label: "Tiếng Việt",
|
||||
e: "🇻🇳",
|
||||
},
|
||||
{
|
||||
lang: "zh-CN",
|
||||
label: "简体中文",
|
||||
e: "🇨🇳",
|
||||
},
|
||||
{
|
||||
lang: "zh-HK",
|
||||
label: "繁體中文",
|
||||
e: "🇭🇰",
|
||||
},
|
||||
] as const
|
||||
@@ -1,9 +1,9 @@
|
||||
import PocketBase from 'pocketbase'
|
||||
import { atom, map, WritableAtom } from 'nanostores'
|
||||
import { AlertRecord, ChartTimes, SystemRecord, UserSettings } from '@/types'
|
||||
import PocketBase from "pocketbase"
|
||||
import { atom, map, WritableAtom } from "nanostores"
|
||||
import { AlertRecord, ChartTimes, SystemRecord, UserSettings } from "@/types"
|
||||
|
||||
/** PocketBase JS Client */
|
||||
export const pb = new PocketBase('/')
|
||||
export const pb = new PocketBase("/")
|
||||
|
||||
/** Store if user is authenticated */
|
||||
export const $authenticated = atom(pb.authStore.isValid)
|
||||
@@ -15,18 +15,18 @@ export const $systems = atom([] as SystemRecord[])
|
||||
export const $alerts = atom([] as AlertRecord[])
|
||||
|
||||
/** SSH public key */
|
||||
export const $publicKey = atom('')
|
||||
export const $publicKey = atom("")
|
||||
|
||||
/** Beszel hub version */
|
||||
export const $hubVersion = atom('')
|
||||
export const $hubVersion = atom("")
|
||||
|
||||
/** Chart time period */
|
||||
export const $chartTime = atom('1h') as WritableAtom<ChartTimes>
|
||||
export const $chartTime = atom("1h") as WritableAtom<ChartTimes>
|
||||
|
||||
/** User settings */
|
||||
export const $userSettings = map<UserSettings>({
|
||||
chartTime: '1h',
|
||||
emails: [pb.authStore.model?.email || ''],
|
||||
chartTime: "1h",
|
||||
emails: [pb.authStore.model?.email || ""],
|
||||
})
|
||||
// update local storage on change
|
||||
$userSettings.subscribe((value) => {
|
||||
@@ -35,7 +35,10 @@ $userSettings.subscribe((value) => {
|
||||
})
|
||||
|
||||
/** Container chart filter */
|
||||
export const $containerFilter = atom('')
|
||||
export const $containerFilter = atom("")
|
||||
|
||||
/** Fallback copy to clipboard dialog content */
|
||||
export const $copyContent = atom('')
|
||||
export const $copyContent = atom("")
|
||||
|
||||
/** Direction for localization */
|
||||
export const $direction = atom<"ltr" | "rtl">("ltr")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
|
||||
// adapted from usehooks-ts/use-intersection-observer
|
||||
|
||||
@@ -72,7 +72,7 @@ type IntersectionReturn = {
|
||||
export function useIntersectionObserver({
|
||||
threshold = 0,
|
||||
root = null,
|
||||
rootMargin = '0%',
|
||||
rootMargin = "0%",
|
||||
freeze = true,
|
||||
initialIsIntersecting = false,
|
||||
onChange,
|
||||
@@ -84,7 +84,7 @@ export function useIntersectionObserver({
|
||||
entry: undefined,
|
||||
}))
|
||||
|
||||
const callbackRef = useRef<UseIntersectionObserverOptions['onChange']>()
|
||||
const callbackRef = useRef<UseIntersectionObserverOptions["onChange"]>()
|
||||
|
||||
callbackRef.current = onChange
|
||||
|
||||
@@ -95,7 +95,7 @@ export function useIntersectionObserver({
|
||||
if (!ref) return
|
||||
|
||||
// Ensure the browser supports the Intersection Observer API
|
||||
if (!('IntersectionObserver' in window)) return
|
||||
if (!("IntersectionObserver" in window)) return
|
||||
|
||||
// Skip if frozen
|
||||
if (frozen) return
|
||||
@@ -104,14 +104,11 @@ export function useIntersectionObserver({
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries: IntersectionObserverEntry[]): void => {
|
||||
const thresholds = Array.isArray(observer.thresholds)
|
||||
? observer.thresholds
|
||||
: [observer.thresholds]
|
||||
const thresholds = Array.isArray(observer.thresholds) ? observer.thresholds : [observer.thresholds]
|
||||
|
||||
entries.forEach((entry) => {
|
||||
const isIntersecting =
|
||||
entry.isIntersecting &&
|
||||
thresholds.some((threshold) => entry.intersectionRatio >= threshold)
|
||||
entry.isIntersecting && thresholds.some((threshold) => entry.intersectionRatio >= threshold)
|
||||
|
||||
setState({ isIntersecting, entry })
|
||||
|
||||
@@ -149,13 +146,7 @@ export function useIntersectionObserver({
|
||||
const prevRef = useRef<Element | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
!ref &&
|
||||
state.entry?.target &&
|
||||
!freeze &&
|
||||
!frozen &&
|
||||
prevRef.current !== state.entry.target
|
||||
) {
|
||||
if (!ref && state.entry?.target && !freeze && !frozen && prevRef.current !== state.entry.target) {
|
||||
prevRef.current = state.entry.target
|
||||
setState({ isIntersecting: initialIsIntersecting, entry: undefined })
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { toast } from '@/components/ui/use-toast'
|
||||
import { type ClassValue, clsx } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { $alerts, $copyContent, $systems, $userSettings, pb } from './stores'
|
||||
import { AlertRecord, ChartTimeData, ChartTimes, SystemRecord } from '@/types'
|
||||
import { RecordModel, RecordSubscription } from 'pocketbase'
|
||||
import { WritableAtom } from 'nanostores'
|
||||
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 { toast } from "@/components/ui/use-toast"
|
||||
import { type ClassValue, clsx } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
import { $alerts, $copyContent, $systems, $userSettings, pb } from "./stores"
|
||||
import { AlertInfo, AlertRecord, ChartTimeData, ChartTimes, SystemRecord } from "@/types"
|
||||
import { RecordModel, RecordSubscription } from "pocketbase"
|
||||
import { WritableAtom } from "nanostores"
|
||||
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"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
@@ -21,7 +22,7 @@ export async function copyToClipboard(content: string) {
|
||||
await navigator.clipboard.writeText(content)
|
||||
toast({
|
||||
duration,
|
||||
description: 'Copied to clipboard',
|
||||
description: t`Copied to clipboard`,
|
||||
})
|
||||
} catch (e: any) {
|
||||
$copyContent.set(content)
|
||||
@@ -29,22 +30,22 @@ export async function copyToClipboard(content: string) {
|
||||
}
|
||||
|
||||
const verifyAuth = () => {
|
||||
pb.collection('users')
|
||||
pb.collection("users")
|
||||
.authRefresh()
|
||||
.catch(() => {
|
||||
pb.authStore.clear()
|
||||
toast({
|
||||
title: 'Failed to authenticate',
|
||||
description: 'Please log in again',
|
||||
variant: 'destructive',
|
||||
title: t`Failed to authenticate`,
|
||||
description: t`Please log in again`,
|
||||
variant: "destructive",
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const updateSystemList = async () => {
|
||||
const records = await pb
|
||||
.collection<SystemRecord>('systems')
|
||||
.getFullList({ sort: '+name', fields: 'id,name,host,info,status' })
|
||||
.collection<SystemRecord>("systems")
|
||||
.getFullList({ sort: "+name", fields: "id,name,host,info,status" })
|
||||
if (records.length) {
|
||||
$systems.set(records)
|
||||
} else {
|
||||
@@ -53,52 +54,36 @@ export const updateSystemList = async () => {
|
||||
}
|
||||
|
||||
export const updateAlerts = () => {
|
||||
pb.collection('alerts')
|
||||
.getFullList<AlertRecord>({ fields: 'id,name,system,value,min,triggered', sort: 'updated' })
|
||||
pb.collection("alerts")
|
||||
.getFullList<AlertRecord>({ fields: "id,name,system,value,min,triggered", sort: "updated" })
|
||||
.then((records) => {
|
||||
$alerts.set(records)
|
||||
})
|
||||
}
|
||||
|
||||
const hourWithMinutesFormatter = new Intl.DateTimeFormat(undefined, {
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})
|
||||
export const hourWithMinutes = (timestamp: string) => {
|
||||
return hourWithMinutesFormatter.format(new Date(timestamp))
|
||||
}
|
||||
|
||||
const shortDateFormatter = new Intl.DateTimeFormat(undefined, {
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
day: "numeric",
|
||||
month: "short",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})
|
||||
export const formatShortDate = (timestamp: string) => {
|
||||
// console.log('ts', timestamp)
|
||||
return shortDateFormatter.format(new Date(timestamp))
|
||||
}
|
||||
|
||||
// const dayTimeFormatter = new Intl.DateTimeFormat(undefined, {
|
||||
// // day: 'numeric',
|
||||
// // month: 'short',
|
||||
// hour: 'numeric',
|
||||
// weekday: 'short',
|
||||
// minute: 'numeric',
|
||||
// // dateStyle: 'short',
|
||||
// })
|
||||
// export const formatDayTime = (timestamp: string) => {
|
||||
// // console.log('ts', timestamp)
|
||||
// return dayTimeFormatter.format(new Date(timestamp))
|
||||
// }
|
||||
|
||||
const dayFormatter = new Intl.DateTimeFormat(undefined, {
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
// dateStyle: 'medium',
|
||||
day: "numeric",
|
||||
month: "short",
|
||||
})
|
||||
export const formatDay = (timestamp: string) => {
|
||||
// console.log('ts', timestamp)
|
||||
return dayFormatter.format(new Date(timestamp))
|
||||
}
|
||||
|
||||
@@ -106,19 +91,14 @@ export const updateFavicon = (newIcon: string) => {
|
||||
;(document.querySelector("link[rel='icon']") as HTMLLinkElement).href = `/static/${newIcon}`
|
||||
}
|
||||
|
||||
export const isAdmin = () => pb.authStore.model?.role === 'admin'
|
||||
export const isReadOnlyUser = () => pb.authStore.model?.role === 'readonly'
|
||||
// export const isDefaultUser = () => pb.authStore.model?.role === 'user'
|
||||
export const isAdmin = () => pb.authStore.model?.role === "admin"
|
||||
export const isReadOnlyUser = () => pb.authStore.model?.role === "readonly"
|
||||
|
||||
/** Update systems / alerts list when records change */
|
||||
export function updateRecordList<T extends RecordModel>(
|
||||
e: RecordSubscription<T>,
|
||||
$store: WritableAtom<T[]>
|
||||
) {
|
||||
export function updateRecordList<T extends RecordModel>(e: RecordSubscription<T>, $store: WritableAtom<T[]>) {
|
||||
const curRecords = $store.get()
|
||||
const newRecords = []
|
||||
// console.log('e', e)
|
||||
if (e.action === 'delete') {
|
||||
if (e.action === "delete") {
|
||||
for (const server of curRecords) {
|
||||
if (server.id !== e.record.id) {
|
||||
newRecords.push(server)
|
||||
@@ -143,51 +123,51 @@ export function updateRecordList<T extends RecordModel>(
|
||||
export function getPbTimestamp(timeString: ChartTimes, d?: Date) {
|
||||
d ||= chartTimeData[timeString].getOffset(new Date())
|
||||
const year = d.getUTCFullYear()
|
||||
const month = String(d.getUTCMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getUTCDate()).padStart(2, '0')
|
||||
const hours = String(d.getUTCHours()).padStart(2, '0')
|
||||
const minutes = String(d.getUTCMinutes()).padStart(2, '0')
|
||||
const seconds = String(d.getUTCSeconds()).padStart(2, '0')
|
||||
const month = String(d.getUTCMonth() + 1).padStart(2, "0")
|
||||
const day = String(d.getUTCDate()).padStart(2, "0")
|
||||
const hours = String(d.getUTCHours()).padStart(2, "0")
|
||||
const minutes = String(d.getUTCMinutes()).padStart(2, "0")
|
||||
const seconds = String(d.getUTCSeconds()).padStart(2, "0")
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
||||
}
|
||||
|
||||
export const chartTimeData: ChartTimeData = {
|
||||
'1h': {
|
||||
type: '1m',
|
||||
"1h": {
|
||||
type: "1m",
|
||||
expectedInterval: 60_000,
|
||||
label: '1 hour',
|
||||
label: () => t`1 hour`,
|
||||
// ticks: 12,
|
||||
format: (timestamp: string) => hourWithMinutes(timestamp),
|
||||
getOffset: (endTime: Date) => timeHour.offset(endTime, -1),
|
||||
},
|
||||
'12h': {
|
||||
type: '10m',
|
||||
"12h": {
|
||||
type: "10m",
|
||||
expectedInterval: 60_000 * 10,
|
||||
label: '12 hours',
|
||||
label: () => t`12 hours`,
|
||||
ticks: 12,
|
||||
format: (timestamp: string) => hourWithMinutes(timestamp),
|
||||
getOffset: (endTime: Date) => timeHour.offset(endTime, -12),
|
||||
},
|
||||
'24h': {
|
||||
type: '20m',
|
||||
"24h": {
|
||||
type: "20m",
|
||||
expectedInterval: 60_000 * 20,
|
||||
label: '24 hours',
|
||||
label: () => t`24 hours`,
|
||||
format: (timestamp: string) => hourWithMinutes(timestamp),
|
||||
getOffset: (endTime: Date) => timeHour.offset(endTime, -24),
|
||||
},
|
||||
'1w': {
|
||||
type: '120m',
|
||||
"1w": {
|
||||
type: "120m",
|
||||
expectedInterval: 60_000 * 120,
|
||||
label: '1 week',
|
||||
label: () => t`1 week`,
|
||||
ticks: 7,
|
||||
format: (timestamp: string) => formatDay(timestamp),
|
||||
getOffset: (endTime: Date) => timeDay.offset(endTime, -7),
|
||||
},
|
||||
'30d': {
|
||||
type: '480m',
|
||||
"30d": {
|
||||
type: "480m",
|
||||
expectedInterval: 60_000 * 480,
|
||||
label: '30 days',
|
||||
label: () => t`30 days`,
|
||||
ticks: 30,
|
||||
format: (timestamp: string) => formatDay(timestamp),
|
||||
getOffset: (endTime: Date) => timeDay.offset(endTime, -30),
|
||||
@@ -202,8 +182,8 @@ export function useYAxisWidth() {
|
||||
function updateYAxisWidth(str: string) {
|
||||
if (str.length > maxChars) {
|
||||
maxChars = str.length
|
||||
const div = document.createElement('div')
|
||||
div.className = 'text-xs tabular-nums tracking-tighter table sr-only'
|
||||
const div = document.createElement("div")
|
||||
div.className = "text-xs tabular-nums tracking-tighter table sr-only"
|
||||
div.innerHTML = str
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => {
|
||||
@@ -249,7 +229,7 @@ function getStorageValue(key: string, defaultValue: any) {
|
||||
}
|
||||
|
||||
/** Hook to sync value in local storage */
|
||||
export const useLocalStorage = (key: string, defaultValue: any) => {
|
||||
export function useLocalStorage<T>(key: string, defaultValue: T) {
|
||||
key = `besz-${key}`
|
||||
const [value, setValue] = useState(() => {
|
||||
return getStorageValue(key, defaultValue)
|
||||
@@ -263,20 +243,18 @@ export const useLocalStorage = (key: string, defaultValue: any) => {
|
||||
|
||||
export async function updateUserSettings() {
|
||||
try {
|
||||
const req = await pb.collection('user_settings').getFirstListItem('', { fields: 'settings' })
|
||||
const req = await pb.collection("user_settings").getFirstListItem("", { fields: "settings" })
|
||||
$userSettings.set(req.settings)
|
||||
return
|
||||
} catch (e) {
|
||||
console.log('get settings', e)
|
||||
console.log("get settings", e)
|
||||
}
|
||||
// create user settings if error fetching existing
|
||||
try {
|
||||
const createdSettings = await pb
|
||||
.collection('user_settings')
|
||||
.create({ user: pb.authStore.model!.id })
|
||||
const createdSettings = await pb.collection("user_settings").create({ user: pb.authStore.model!.id })
|
||||
$userSettings.set(createdSettings.settings)
|
||||
} catch (e) {
|
||||
console.log('create settings', e)
|
||||
console.log("create settings", e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,51 +268,52 @@ export const getSizeAndUnit = (n: number, isGigabytes = true) => {
|
||||
const sizeInGB = isGigabytes ? n : n / 1_000
|
||||
|
||||
if (sizeInGB >= 1_000) {
|
||||
return { v: sizeInGB / 1_000, u: ' TB' }
|
||||
return { v: sizeInGB / 1_000, u: " TB" }
|
||||
} else if (sizeInGB >= 1) {
|
||||
return { v: sizeInGB, u: ' GB' }
|
||||
return { v: sizeInGB, u: " GB" }
|
||||
}
|
||||
return { v: n, u: ' MB' }
|
||||
return { v: n, u: " MB" }
|
||||
}
|
||||
|
||||
export const chartMargin = { top: 12 }
|
||||
|
||||
export const alertInfo = {
|
||||
export const alertInfo: Record<string, AlertInfo> = {
|
||||
Status: {
|
||||
name: 'Status',
|
||||
unit: '',
|
||||
name: () => t`Status`,
|
||||
unit: "",
|
||||
icon: ServerIcon,
|
||||
desc: 'Triggers when status switches between up and down.',
|
||||
desc: () => t`Triggers when status switches between up and down`,
|
||||
single: true,
|
||||
},
|
||||
CPU: {
|
||||
name: 'CPU usage',
|
||||
unit: '%',
|
||||
name: () => t`CPU Usage`,
|
||||
unit: "%",
|
||||
icon: CpuIcon,
|
||||
desc: 'Triggers when CPU usage exceeds a threshold.',
|
||||
desc: () => t`Triggers when CPU usage exceeds a threshold`,
|
||||
},
|
||||
Memory: {
|
||||
name: 'memory usage',
|
||||
unit: '%',
|
||||
name: () => t`Memory Usage`,
|
||||
unit: "%",
|
||||
icon: MemoryStickIcon,
|
||||
desc: 'Triggers when memory usage exceeds a threshold.',
|
||||
desc: () => t`Triggers when memory usage exceeds a threshold`,
|
||||
},
|
||||
Disk: {
|
||||
name: 'disk usage',
|
||||
unit: '%',
|
||||
name: () => t`Disk Usage`,
|
||||
unit: "%",
|
||||
icon: HardDriveIcon,
|
||||
desc: 'Triggers when usage of any disk exceeds a threshold.',
|
||||
desc: () => t`Triggers when usage of any disk exceeds a threshold`,
|
||||
},
|
||||
Bandwidth: {
|
||||
name: 'bandwidth',
|
||||
unit: ' MB/s',
|
||||
name: () => t`Bandwidth`,
|
||||
unit: " MB/s",
|
||||
icon: EthernetIcon,
|
||||
desc: 'Triggers when combined up/down exceeds a threshold.',
|
||||
desc: () => t`Triggers when combined up/down exceeds a threshold`,
|
||||
max: 125,
|
||||
},
|
||||
Temperature: {
|
||||
name: 'temperature',
|
||||
unit: '°C',
|
||||
name: () => t`Temperature`,
|
||||
unit: "°C",
|
||||
icon: ThermometerIcon,
|
||||
desc: 'Triggers when any sensor exceeds a threshold.',
|
||||
desc: () => t`Triggers when any sensor exceeds a threshold`,
|
||||
},
|
||||
}
|
||||
|
||||
808
beszel/site/src/locales/ar/ar.po
Normal file
808
beszel/site/src/locales/ar/ar.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: ar\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:46\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Arabic\n"
|
||||
"Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: ar\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# يوم} other {# أيام}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# ساعة} other {# ساعات}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1 ساعة"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1 أسبوع"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12 ساعة"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24 ساعة"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30 يومًا"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "إجراءات"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "التنبيهات النشطة"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "إضافة <0>نظام</0>"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "إضافة نظام جديد"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "إضافة نظام"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "إضافة عنوان URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "تعديل خيارات العرض للرسوم البيانية."
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "مسؤول"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "وكيل"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "التنبيهات"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "جميع الأنظمة"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "هل أنت متأكد أنك تريد حذف {name}؟"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "مزودو المصادقة"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "النسخ التلقائي يتطلب سياقًا آمنًا."
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "متوسط"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "متوسط استخدام وحدة المعالجة المركزية للحاويات"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "المتوسط يتجاوز <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "متوسط استخدام وحدة المعالجة المركزية على مستوى النظام"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "النسخ الاحتياطية"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "عرض النطاق الترددي"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "يدعم Beszel OpenID Connect والعديد من مزودي المصادقة OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "يستخدم Beszel <0>Shoutrrr</0> للتكامل مع خدمات الإشعارات الشهيرة."
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "ثنائي"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "ذاكرة التخزين المؤقت / المخازن المؤقتة"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "إلغاء"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "تحذير - فقدان محتمل للبيانات"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "تغيير خيارات التطبيق العامة."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "خيارات الرسم البياني"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "تحقق من {email} للحصول على رابط إعادة التعيين."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "تحقق من السجلات لمزيد من التفاصيل."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "تحقق من خدمة الإشعارات الخاصة بك"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "انقر للنسخ"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "أعمدة"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "تعليمات سطر الأوامر"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "قم بتكوين كيفية تلقي إشعارات التنبيه."
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "تأكيد كلمة المرور"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "متابعة"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "تم النسخ إلى الحافظة"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "نسخ"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "نسخ المضيف"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "نسخ أمر لينكس"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "نسخ النص"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "المعالج"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "استخدام وحدة المعالجة المركزية"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "إنشاء حساب"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "داكن"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "لوحة التحكم"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "الفترة الزمنية الافتراضية"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "حذف"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "القرص"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "إدخال/إخراج القرص"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "استخدام القرص"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "استخدام القرص لـ {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "استخدام CPU لـ Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "استخدام الذاكرة لـ Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "إدخال/إخراج الشبكة لـ Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "التوثيق"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "البريد الإلكتروني"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "البريد الإلكتروني"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "إشعارات البريد الإلكتروني"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "أدخل عنوان البريد الإلكتروني لإعادة تعيين كلمة المرور"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "أدخل عنوان البريد الإلكتروني..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "خطأ"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "يتجاوز {0}{1} في آخر {2, plural, one {# دقيقة} other {# دقائق}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
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/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "تصدير التكوين"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "تصدير تكوين الأنظمة الحالية الخاصة بك."
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "فشل في المصادقة"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "فشل في حفظ الإعدادات"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "فشل في إرسال إشعار الاختبار"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "فشل في تحديث التنبيه"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "تصفية..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "لمدة <0>{min}</0> {min, plural, one {دقيقة} other {دقائق}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "هل نسيت كلمة المرور؟"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "عام"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "مضيف / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "إذا فقدت كلمة المرور لحساب المسؤول الخاص بك، يمكنك إعادة تعيينها باستخدام الأمر التالي."
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "عنوان البريد الإلكتروني غير صالح."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "كيرنل"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "اللغة"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "فاتح"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "تسجيل الخروج"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "تسجيل الدخول"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "فشل محاولة تسجيل الدخول"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "السجلات"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "هل تبحث عن مكان لإنشاء التنبيهات؟ انقر على أيقونات الجرس <0/> في جدول الأنظمة."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "إدارة تفضيلات العرض والإشعارات."
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "1 دقيقة كحد"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "الذاكرة"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "استخدام الذاكرة"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "استخدام الذاكرة لحاويات Docker"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "الاسم"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "الشبكة"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "حركة مرور الشبكة لحاويات Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "حركة مرور الشبكة للواجهات العامة"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "لم يتم العثور على نتائج."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "لم يتم العثور على أنظمة."
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "الإشعارات"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "دعم OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "في كل إعادة تشغيل، سيتم تحديث الأنظمة في قاعدة البيانات لتتطابق مع الأنظمة المعرفة في الملف."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:219
|
||||
msgid "Open menu"
|
||||
msgstr "فتح القائمة"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "أو المتابعة باستخدام"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "الكتابة فوق التنبيهات الحالية"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "صفحة"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "الصفحات / الإعدادات"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "كلمة المرور"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "يجب أن تكون كلمة المرور مكونة من 10 أحرف على الأقل."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "تم استلام طلب إعادة تعيين كلمة المرور"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "إيقاف مؤقت"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "يرجى <0>تكوين خادم SMTP</0> لضمان تسليم التنبيهات."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "يرجى التحقق من السجلات لمزيد من التفاصيل."
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "يرجى التحقق من بيانات الاعتماد الخاصة بك والمحاولة مرة أخرى"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "يرجى إنشاء حساب مسؤول"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "يرجى تمكين النوافذ المنبثقة لهذا الموقع"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "يرجى تسجيل الدخول مرة أخرى"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "يرجى الاطلاع على <0>التوثيق</0> للحصول على التعليمات."
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "يرجى تسجيل الدخول إلى حسابك"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "المنفذ"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "الاستخدام الدقيق في الوقت المسجل"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "اللغة المفضلة"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "المفتاح العام"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "قراءة"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "تم الاستلام"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "إعادة تعيين كلمة المرور"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "استئناف"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "احفظ العنوان باستخدام مفتاح الإدخال أو الفاصلة. اتركه فارغًا لتعطيل إشعارات البريد الإلكتروني."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "حفظ الإعدادات"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "بحث"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "البحث عن الأنظمة أو الإعدادات..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "راجع <0>إعدادات الإشعارات</0> لتكوين كيفية تلقي التنبيهات."
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "تم الإرسال"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "يحدد النطاق الزمني الافتراضي للرسوم البيانية عند عرض النظام."
|
||||
|
||||
#: src/components/command-palette.tsx:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "الإعدادات"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "تم حفظ الإعدادات"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "تسجيل الدخول"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "إعدادات SMTP"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "الحالة"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "مساحة التبديل المستخدمة من قبل النظام"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "استخدام التبديل"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "النظام"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "الأنظمة"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "يمكن إدارة الأنظمة في ملف <0>config.yml</0> داخل دليل البيانات الخاص بك."
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "درجة الحرارة"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "درجات حرارة مستشعرات النظام"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "اختبار <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "تم إرسال إشعار الاختبار"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "ثم قم بتسجيل الدخول إلى الواجهة الخلفية وأعد تعيين كلمة مرور حساب المستخدم الخاص بك في جدول المستخدمين."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "لا يمكن التراجع عن هذا الإجراء. سيؤدي ذلك إلى حذف جميع السجلات الحالية لـ {name} من قاعدة البيانات بشكل دائم."
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "معدل نقل {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "معدل نقل نظام الملفات الجذر"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "إلى البريد الإلكتروني"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "تبديل الشبكة"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "تبديل السمة"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما <20><>تجاوز أي مستشعر عتبة معينة"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز الجمع بين الصعود/الهبوط عتبة معينة"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز استخدام وحدة المعالجة المركزية عتبة معينة"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز استخدام الذاكرة عتبة معينة"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "يتم التفعيل عندما يتغير الحالة بين التشغيل والإيقاف"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "يتم التفعيل عندما يتجاوز استخدام أي قرص عتبة معينة"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "محدث في الوقت الحقيقي. انقر على نظام لعرض المعلومات."
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "مدة التشغيل"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "الاستخدام"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "استخدام القسم الجذر"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "مستخدم"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "اسم المستخدم"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "اسم المستخدم"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "المستخدمون"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "في انتظار وجود سجلات كافية للعرض"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "هل تريد مساعدتنا في تحسين ترجماتنا؟ تحقق من <0>Crowdin</0> لمزيد من التفاصيل."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "إشعارات Webhook / Push"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "كتابة"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "تكوين YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "تكوين YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "تم تحديث إعدادات المستخدم الخاصة بك."
|
||||
808
beszel/site/src/locales/de/de.po
Normal file
808
beszel/site/src/locales/de/de.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: de\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:46\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: German\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: de\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# Tag} other {# Tage}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# Stunde} other {# Stunden}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1 Stunde"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1 Woche"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12 Stunden"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24 Stunden"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30 Tage"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "Aktionen"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktive Warnungen"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>System</0> hinzufügen"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "Neues System hinzufügen"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "System hinzufügen"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "URL hinzufügen"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Anzeigeoptionen für Diagramme anpassen."
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "Warnungen"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "Alle Systeme"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Möchten Sie {name} wirklich löschen?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "Authentifizierungsanbieter"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatisches Kopieren erfordert einen sicheren Kontext."
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "Durchschnitt"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Durchschnittliche CPU-Auslastung der Container"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Durchschnitt überschreitet <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Durchschnittliche systemweite CPU-Auslastung"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "Backups"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bandbreite"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel unterstützt OpenID Connect und viele OAuth2-Authentifizierungsanbieter."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel verwendet <0>Shoutrrr</0>, um sich mit beliebten Benachrichtigungsdiensten zu integrieren."
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "Binär"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Puffer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "Abbrechen"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Vorsicht - potenzieller Datenverlust"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Allgemeine Anwendungsoptionen ändern."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Diagrammoptionen"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Überprüfen Sie {email} auf einen Rücksetzlink."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Überprüfen Sie die Protokolle für weitere Details."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "Überprüfen Sie Ihren Benachrichtigungsdienst"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "Zum Kopieren klicken"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "Spalten"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "Befehlszeilenanweisungen"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Konfigurieren Sie, wie Sie Warnbenachrichtigungen erhalten."
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "Passwort bestätigen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "Fortfahren"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "In die Zwischenablage kopiert"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "Kopieren"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "Host kopieren"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Linux-Befehl kopieren"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Text kopieren"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU-Auslastung"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "Konto erstellen"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "Dunkel"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "Dashboard"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Standardzeitraum"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "Löschen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "Festplatte"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "Festplatten-I/O"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "Festplattennutzung"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Festplattennutzung von {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker-CPU-Auslastung"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker-Speichernutzung"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker-Netzwerk-I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "Dokumentation"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "E-Mail"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "E-Mail"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "E-Mail-Benachrichtigungen"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "E-Mail-Adresse eingeben, um das Passwort zurückzusetzen"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "E-Mail-Adresse eingeben..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "Fehler"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Überschreitet {0}{1} in den letzten {2, plural, one {# Minute} other {# Minuten}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Bestehende Systeme, die nicht in <0>config.yml</0> definiert sind, werden gelöscht. Bitte machen Sie regelmäßige Backups."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "Konfiguration exportieren"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Exportieren Sie Ihre aktuelle Systemkonfiguration."
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Authentifizierung fehlgeschlagen"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Einstellungen konnten nicht gespeichert werden"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Testbenachrichtigung konnte nicht gesendet werden"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Warnung konnte nicht aktualisiert werden"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Für <0>{min}</0> {min, plural, one {Minute} other {Minuten}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "Passwort vergessen?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "Allgemein"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Wenn Sie das Passwort für Ihr Administratorkonto verloren haben, können Sie es mit dem folgenden Befehl zurücksetzen."
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "Ungültige E-Mail-Adresse."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Sprache"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "Hell"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "Abmelden"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "Anmelden"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Anmeldeversuch fehlgeschlagen"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "Protokolle"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Suchen Sie stattdessen nach der Erstellung von Warnungen? Klicken Sie auf die Glocken-<0/>-Symbole in der Systemtabelle."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Anzeige- und Benachrichtigungseinstellungen verwalten."
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 Min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "Speicher"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "Speichernutzung"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Speichernutzung der Docker-Container"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "Netz"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Netzwerkverkehr der Docker-Container"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Netzwerkverkehr der öffentlichen Schnittstellen"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "Keine Ergebnisse gefunden."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "Keine Systeme gefunden."
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "Benachrichtigungen"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDC-Unterstützung"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Bei jedem Neustart werden die Systeme in der Datenbank aktualisiert, um den im Datei definierten Systemen zu entsprechen."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:219
|
||||
msgid "Open menu"
|
||||
msgstr "Menü öffnen"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "Oder fortfahren mit"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Bestehende Warnungen überschreiben"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "Seite"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Seiten / Einstellungen"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "Passwort"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "Das Passwort muss mindestens 10 Zeichen lang sein."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "Anfrage zum Zurücksetzen des Passworts erhalten"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Bitte <0>konfigurieren Sie einen SMTP-Server</0>, um sicherzustellen, dass Warnungen zugestellt werden."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Bitte überprüfen Sie die Protokolle für weitere Details."
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Bitte überprüfen Sie Ihre Anmeldedaten und versuchen Sie es erneut"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Bitte erstellen Sie ein Administratorkonto"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Bitte aktivieren Sie Pop-ups für diese Seite"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "Bitte melden Sie sich erneut an"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Bitte sehen Sie sich <0>die Dokumentation</0> für Anweisungen an."
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Bitte melden Sie sich bei Ihrem Konto an"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Genaue Nutzung zum aufgezeichneten Zeitpunkt"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Bevorzugte Sprache"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "Schlüssel"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "Lesen"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "Empfangen"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "Passwort zurücksetzen"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "Fortsetzen"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Adresse mit der Eingabetaste oder Komma speichern. Leer lassen, um E-Mail-Benachrichtigungen zu deaktivieren."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "Einstellungen speichern"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "Suche"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Nach Systemen oder Einstellungen suchen..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Siehe <0>Benachrichtigungseinstellungen</0>, um zu konfigurieren, wie Sie Warnungen erhalten."
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "Gesendet"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
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:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "Einstellungen gespeichert"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "Anmelden"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP-Einstellungen"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Vom System genutzter Swap-Speicher"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap-Nutzung"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Systeme"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Systeme können in einer <0>config.yml</0>-Datei in Ihrem Datenverzeichnis verwaltet werden."
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatur"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturen der Systemsensoren"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "Testbenachrichtigung gesendet"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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. Kopieren Sie den Installationsbefehl für den Agenten unten."
|
||||
|
||||
#: src/components/add-system.tsx:95
|
||||
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. Kopieren Sie die <0>docker-compose.yml</0> für den Agenten unten."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:98
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Melden Sie sich dann im Backend an und setzen Sie Ihr Benutzerkontopasswort in der Benutzertabelle zurück."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
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/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Durchsatz von {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Durchsatz des Root-Dateisystems"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "An E-Mail(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "Raster umschalten"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "Thema umschalten"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Löst aus, wenn ein Sensor einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die kombinierte Auf-/Abwärtsbewegung einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die CPU-Auslastung einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die Speichernutzung einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Löst aus, wenn der Status zwischen oben und unten wechselt"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Löst aus, wenn die Nutzung einer Festplatte einen Schwellenwert überschreitet"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "In Echtzeit aktualisiert. Klicken Sie auf ein System, um Informationen anzuzeigen."
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "Betriebszeit"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "Nutzung"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Nutzung der Root-Partition"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "Verwendet"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "Benutzername"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "Benutzername"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "Benutzer"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Warten auf genügend Datensätze zur Anzeige"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Möchten Sie uns helfen, unsere Übersetzungen noch besser zu machen? Schauen Sie sich <0>Crowdin</0> für weitere Details an."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push-Benachrichtigungen"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "Schreiben"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML-Konfiguration"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML-Konfiguration"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Ihre Benutzereinstellungen wurden aktualisiert."
|
||||
803
beszel/site/src/locales/en/en.po
Normal file
803
beszel/site/src/locales/en/en.po
Normal file
@@ -0,0 +1,803 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: en\n"
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# day} other {# days}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# hour} other {# hours}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1 hour"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1 week"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12 hours"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24 hours"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30 days"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "Actions"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "Active Alerts"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Add <0>System</0>"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "Add New System"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "Add system"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "Add URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Adjust display options for charts."
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "Alerts"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "All Systems"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Are you sure you want to delete {name}?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "Auth Providers"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Automatic copy requires a secure context."
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "Average"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Average CPU utilization of containers"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Average exceeds <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Average system-wide CPU utilization"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "Backups"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bandwidth"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "Binary"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffers"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "Cancel"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Caution - potential data loss"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Change general application options."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Chart options"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Check {email} for a reset link."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Check logs for more details."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "Check your notification service"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "Click to copy"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "Columns"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "Command line instructions"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Configure how you receive alert notifications."
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirm password"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "Continue"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Copied to clipboard"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "Copy"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "Copy host"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copy Linux command"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Copy text"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU Usage"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "Create account"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "Dark"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "Dashboard"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Default time period"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "Delete"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk I/O"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "Disk Usage"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Disk usage of {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU Usage"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker Memory Usage"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker Network I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "Documentation"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "email"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "Email notifications"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Enter email address to reset password"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "Enter email address..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "Error"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "Export configuration"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Export your current systems configuration."
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Failed to authenticate"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Failed to save settings"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Failed to send test notification"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Failed to update alert"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "Filter..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "Forgot password?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "General"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "Invalid email address."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Language"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "Light"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "Log Out"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "Login"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Login attempt failed"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "Logs"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Manage display and notification preferences."
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "Memory"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "Memory Usage"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Memory usage of docker containers"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "Net"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Network traffic of docker containers"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Network traffic of public interfaces"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "No results found."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "No systems found."
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "Notifications"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDC support"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:219
|
||||
msgid "Open menu"
|
||||
msgstr "Open menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "Or continue with"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Overwrite existing alerts"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "Page"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Pages / Settings"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "Password"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "Password must be at least 10 characters."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "Password reset request received"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Please check logs for more details."
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Please check your credentials and try again"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Please create an admin account"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Please enable pop-ups for this site"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "Please log in again"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Please see <0>the documentation</0> for instructions."
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Please sign in to your account"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Precise utilization at the recorded time"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Preferred Language"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "Public Key"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "Read"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "Received"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "Reset Password"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "Resume"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "Save Settings"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "Search"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Search for systems or settings..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "See <0>notification settings</0> to configure how you receive alerts."
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "Sent"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Sets the default time range for charts when a system is viewed."
|
||||
|
||||
#: src/components/command-palette.tsx:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "Settings"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "Settings saved"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "Sign in"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP settings"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Swap space used by the system"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "Swap Usage"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Systems"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "Temperature"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperatures of system sensors"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "Test notification sent"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
|
||||
#: src/components/add-system.tsx:95
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:98
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Then log into the backend and reset your user account password in the users table."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Throughput of {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Throughput of root filesystem"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "To email(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "Toggle grid"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "Toggle theme"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Triggers when any sensor exceeds a threshold"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Triggers when combined up/down exceeds a threshold"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Triggers when CPU usage exceeds a threshold"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Triggers when memory usage exceeds a threshold"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Triggers when status switches between up and down"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Triggers when usage of any disk exceeds a threshold"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Updated in real time. Click on a system to view information."
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "Uptime"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "Usage"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Usage of root partition"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "Used"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "username"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "Username"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "Users"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Waiting for enough records to display"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push notifications"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "Write"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML Config"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML Configuration"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Your user settings have been updated."
|
||||
808
beszel/site/src/locales/es/es.po
Normal file
808
beszel/site/src/locales/es/es.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: es\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:46\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Spanish\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: es-ES\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# día} other {# días}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# hora} other {# horas}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1 hora"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1 semana"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12 horas"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24 horas"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30 días"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "Acciones"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "Alertas Activas"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Agregar <0>Sistema</0>"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "Agregar Nuevo Sistema"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "Agregar sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "Agregar URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Ajustar las opciones de visualización para los gráficos."
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "Administrador"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "Agente"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "Alertas"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "Todos los Sistemas"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "¿Está seguro de que desea eliminar {name}?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "Proveedores de Autenticación"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "La copia automática requiere un contexto seguro."
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "Promedio"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Utilización promedio de CPU de los contenedores"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "El promedio excede <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Utilización promedio de CPU del sistema"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "Copias de Seguridad"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "Ancho de banda"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel admite OpenID Connect y muchos proveedores de autenticación OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel utiliza <0>Shoutrrr</0> para integrarse con servicios populares de notificación."
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "Binario"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Caché / Buffers"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Precaución - posible pérdida de datos"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Cambiar las opciones generales de la aplicación."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Opciones de Gráficos"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Revise {email} para un enlace de restablecimiento."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Revise los registros para más detalles."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "Verifique su servicio de notificaciones"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "Haga clic para copiar"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "Columnas"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "Instrucciones de línea de comandos"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Configure cómo recibe las notificaciones de alertas."
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmar contraseña"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "Continuar"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Copiado al portapapeles"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "Copiar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "Copiar host"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copiar comando de Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Copiar texto"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "Uso de CPU"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "Crear cuenta"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "Oscuro"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "Tablero"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Período de tiempo predeterminado"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "Eliminar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "Disco"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "E/S de Disco"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "Uso de Disco"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Uso de disco de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Uso de CPU de Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Uso de Memoria de Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "E/S de Red de Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "Documentación"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "correo electrónico"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "Correo electrónico"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "Notificaciones por correo"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Ingrese la dirección de correo electrónico para restablecer la contraseña"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "Ingrese dirección de correo..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "Error"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Excede {0}{1} en el último {2, plural, one {# minuto} other {# minutos}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
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/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "Exportar configuración"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Exporte la configuración actual de sus sistemas."
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Error al autenticar"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Error al guardar la configuración"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Error al enviar la notificación de prueba"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Error al actualizar la alerta"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "Filtrar..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Por <0>{min}</0> {min, plural, one {minuto} other {minutos}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "¿Olvidó su contraseña?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "General"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Si ha perdido la contraseña de su cuenta de administrador, puede restablecerla usando el siguiente comando."
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "Dirección de correo electrónico no válida."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Idioma"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "Claro"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "Cerrar Sesión"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "Iniciar sesión"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Intento de inicio de sesión fallido"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "Registros"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "¿Busca dónde crear alertas? Haga clic en los iconos de campana <0/> en la tabla de sistemas."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Administrar preferencias de visualización y notificaciones."
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "Máx 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "Memoria"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "Uso de Memoria"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Uso de memoria de los contenedores de Docker"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "Nombre"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "Red"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Tráfico de red de los contenedores de Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Tráfico de red de interfaces públicas"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "No se encontraron resultados."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "No se encontraron sistemas."
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "Notificaciones"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Soporte para OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
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:219
|
||||
msgid "Open menu"
|
||||
msgstr "Abrir menú"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "O continuar con"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Sobrescribir alertas existentes"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "Página"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Páginas / Configuraciones"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "Contraseña"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "La contraseña debe tener al menos 10 caracteres."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "Solicitud de restablecimiento de contraseña recibida"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "Pausar"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Por favor, <0>configure un servidor SMTP</0> para asegurar que las alertas sean entregadas."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Por favor, revise los registros para más detalles."
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Por favor, verifique sus credenciales e intente de nuevo"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Por favor, cree una cuenta de administrador"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Por favor, habilite las ventanas emergentes para este sitio"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "Por favor, inicie sesión de nuevo"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Por favor, consulte <0>la documentación</0> para obtener instrucciones."
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Por favor, inicie sesión en su cuenta"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "Puerto"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilización precisa en el momento registrado"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Idioma Preferido"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "Clave Pública"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "Lectura"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "Recibido"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "Restablecer Contraseña"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "Reanudar"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
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."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "Guardar Configuración"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "Buscar"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Buscar sistemas o configuraciones..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
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."
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "Enviado"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
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:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "Configuración"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "Configuración guardada"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "Iniciar sesión"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "Configuración SMTP"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "Estado"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Espacio de swap utilizado por el sistema"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "Uso de Swap"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "Sistema"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Sistemas"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Los sistemas pueden ser gestionados en un archivo <0>config.yml</0> dentro de su directorio de datos."
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturas de los sensores del sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Probar <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "Notificación de prueba enviada"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
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."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
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/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Rendimiento de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Rendimiento del sistema de archivos raíz"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "A correo(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "Alternar cuadrícula"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "Alternar tema"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Se activa cuando cualquier sensor supera un umbral"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Se activa cuando la suma de subida/bajada supera un umbral"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Se activa cuando el uso de CPU supera un umbral"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Se activa cuando el uso de memoria supera un umbral"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Se activa cuando el estado cambia entre activo e inactivo"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Se activa cuando el uso de cualquier disco supera un umbral"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Actualizado en tiempo real. Haga clic en un sistema para ver la información."
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "Tiempo de actividad"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "Uso"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Uso de la partición raíz"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "Usado"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "nombre de usuario"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "Nombre de usuario"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "Usuarios"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Esperando suficientes registros para mostrar"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "¿Quieres ayudarnos a mejorar nuestras traducciones? Consulta <0>Crowdin</0> para más detalles."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Notificaciones Webhook / Push"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "Escritura"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "Configuración YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Configuración YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Su configuración de usuario ha sido actualizada."
|
||||
808
beszel/site/src/locales/fr/fr.po
Normal file
808
beszel/site/src/locales/fr/fr.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: fr\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:46\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: French\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: fr\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# jour} other {# jours}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# heure} other {# heures}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1 heure"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1 semaine"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12 heures"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24 heures"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30 jours"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "Actions"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "Alertes actives"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Ajouter <0>Système</0>"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "Ajouter un nouveau système"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "Ajouter un système"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "Ajouter URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Ajuster les options d'affichage pour les graphiques."
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "Agent"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "Alertes"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "Tous les systèmes"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Êtes-vous sûr de vouloir supprimer {name} ?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "Fournisseurs d'authentification"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "La copie automatique nécessite un contexte sécurisé."
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "Moyenne"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Utilisation moyenne du CPU des conteneurs"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "La moyenne dépasse <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Utilisation moyenne du CPU à l'échelle du système"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "Sauvegardes"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bande passante"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel prend en charge OpenID Connect et de nombreux fournisseurs d'authentification OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel utilise <0>Shoutrrr</0> pour s'intégrer aux services de notification populaires."
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "Binaire"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Tampons"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Attention - perte de données potentielle"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Modifier les options générales de l'application."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Options de graphique"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Vérifiez {email} pour un lien de réinitialisation."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Vérifiez les journaux pour plus de détails."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "Vérifiez votre service de notification"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "Cliquez pour copier"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "Colonnes"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "Instructions en ligne de commande"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Configurez comment vous recevez les notifications d'alerte."
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmer le mot de passe"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "Continuer"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Copié dans le presse-papiers"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "Copier"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "Copier l'hôte"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copier la commande Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Copier le texte"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "Utilisation du CPU"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "Créer un compte"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "Sombre"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "Tableau de bord"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Période par défaut"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "Supprimer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "Disque"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "Entrée/Sortie disque"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "Utilisation du disque"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Utilisation du disque de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Utilisation du CPU Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Utilisation de la mémoire Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Entrée/Sortie réseau Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "Documentation"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "email"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "Notifications par email"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Entrez l'adresse email pour réinitialiser le mot de passe"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "Entrez l'adresse email..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "Erreur"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Dépasse {0}{1} dans la dernière {2, plural, one {# minute} other {# minutes}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
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/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "Exporter la configuration"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Exportez la configuration actuelle de vos systèmes."
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Échec de l'authentification"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Échec de l'enregistrement des paramètres"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Échec de l'envoi de la notification de test"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Échec de la mise à jour de l'alerte"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "Filtrer..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Pour <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "Mot de passe oublié ?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "Général"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "Hôte / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Si vous avez perdu le mot de passe de votre compte administrateur, vous pouvez le réinitialiser en utilisant la commande suivante."
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "Adresse email invalide."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "Noyau"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Langue"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "Clair"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "Déconnexion"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "Connexion"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Échec de la tentative de connexion"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "Journaux"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Vous cherchez plutôt où créer des alertes ? Cliquez sur les icônes de cloche <0/> dans le tableau des systèmes."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Gérer les préférences d'affichage et de notification."
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "Mémoire"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "Utilisation de la mémoire"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Utilisation de la mémoire des conteneurs Docker"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "Net"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Trafic réseau des conteneurs Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Trafic réseau des interfaces publiques"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "Aucun résultat trouvé."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "Aucun système trouvé."
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "Notifications"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Support OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
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:219
|
||||
msgid "Open menu"
|
||||
msgstr "Ouvrir le menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "Ou continuer avec"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Écraser les alertes existantes"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "Page"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Pages / Paramètres"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "Le mot de passe doit contenir au moins 10 caractères."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "Demande de réinitialisation du mot de passe reçue"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Veuillez <0>configurer un serveur SMTP</0> pour garantir la livraison des alertes."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Veuillez vérifier les journaux pour plus de détails."
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Veuillez vérifier vos identifiants et réessayer"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Veuillez créer un compte administrateur"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Veuillez activer les pop-ups pour ce site"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "Veuillez vous reconnecter"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Veuillez consulter <0>la documentation</0> pour les instructions."
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Veuillez vous connecter à votre compte"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilisation précise au moment enregistré"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Langue préférée"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "Clé publique"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "Lecture"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "Reçu"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "Réinitialiser le mot de passe"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "Reprendre"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
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."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "Enregistrer les paramètres"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "Recherche"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Rechercher des systèmes ou des paramètres..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
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."
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "Envoyé"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
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:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "Paramètres"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "Paramètres enregistrés"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "Se connecter"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "Paramètres SMTP"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "Statut"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Espace d'échange utilisé par le système"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "Utilisation de l'échange"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "Système"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Systèmes"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Les systèmes peuvent être gérés dans un fichier <0>config.yml</0> à l'intérieur de votre répertoire de données."
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "Température"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Températures des capteurs du système"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Tester <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "Notification de test envoyée"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
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."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
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/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Débit de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Débit du système de fichiers racine"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "Aux email(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "Basculer la grille"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "Basculer le thème"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque tout capteur dépasse un seuil"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque la montée/descente combinée dépasse un seuil"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque l'utilisation du CPU dépasse un seuil"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque l'utilisation de la mémoire dépasse un seuil"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Déclenchement lorsque le statut passe de haut en bas"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Déclenchement lorsque l'utilisation de tout disque dépasse un seuil"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Mis à jour en temps réel. Cliquez sur un système pour voir les informations."
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "Temps de fonctionnement"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "Utilisation"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Utilisation de la partition racine"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "Utilisé"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "nom d'utilisateur"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "Nom d'utilisateur"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "Utilisateurs"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "En attente de suffisamment d'enregistrements à afficher"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Vous voulez nous aider à améliorer nos traductions ? Consultez <0>Crowdin</0> pour plus de détails."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Notifications Webhook / Push"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "Écriture"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "Configuration YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Configuration YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Vos paramètres utilisateur ont été mis à jour."
|
||||
808
beszel/site/src/locales/it/it.po
Normal file
808
beszel/site/src/locales/it/it.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: it\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:47\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Italian\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: it\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# giorno} other {# giorni}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# ora} other {# ore}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1 ora"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1 settimana"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12 ore"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24 ore"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30 giorni"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "Azioni"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "Avvisi Attivi"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Aggiungi <0>Sistema</0>"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "Aggiungi Nuovo Sistema"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "Aggiungi sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "Aggiungi URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Regola le opzioni di visualizzazione per i grafici."
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "Amministratore"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "Agente"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "Avvisi"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "Tutti i Sistemi"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Sei sicuro di voler eliminare {name}?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "Provider di Autenticazione"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "La copia automatica richiede un contesto sicuro."
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "Media"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Utilizzo medio della CPU dei container"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "La media supera <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Utilizzo medio della CPU a livello di sistema"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "Backup"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "Larghezza di banda"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel supporta OpenID Connect e molti provider di autenticazione OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel utilizza <0>Shoutrrr</0> per integrarsi con i servizi di notifica popolari."
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "Binario"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffer"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "Annulla"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Attenzione - possibile perdita di dati"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Modifica le opzioni generali dell'applicazione."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Opzioni del grafico"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Controlla {email} per un link di reset."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Controlla i log per maggiori dettagli."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "Controlla il tuo servizio di notifica"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "Clicca per copiare"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "Colonne"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "Istruzioni da riga di comando"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Configura come ricevere le notifiche di avviso."
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "Conferma password"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "Continua"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Copiato negli appunti"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "Copia"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "Copia host"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copia comando Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Copia testo"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "Utilizzo CPU"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "Crea account"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "Scuro"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "Cruscotto"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Periodo di tempo predefinito"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "Elimina"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "Disco"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "I/O Disco"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "Utilizzo Disco"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Utilizzo del disco di {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Utilizzo CPU Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Utilizzo Memoria Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "I/O di Rete Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "Documentazione"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "email"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "Notifiche email"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Inserisci l'indirizzo email per reimpostare la password"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "Inserisci l'indirizzo email..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "Errore"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Supera {0}{1} negli ultimi {2, plural, one {# minuto} other {# minuti}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
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/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "Esporta configurazione"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Esporta la configurazione attuale dei tuoi sistemi."
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Autenticazione fallita"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Salvataggio delle impostazioni fallito"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Invio della notifica di test fallito"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Aggiornamento dell'avviso fallito"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "Filtra..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Per <0>{min}</0> {min, plural, one {minuto} other {minuti}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "Password dimenticata?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "Generale"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Se hai perso la password del tuo account amministratore, puoi reimpostarla utilizzando il seguente comando."
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "Indirizzo email non valido."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Lingua"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "Chiaro"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "Disconnetti"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "Accedi"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Tentativo di accesso fallito"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "Log"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Cerchi invece dove creare avvisi? Clicca sulle icone della campana <0/> nella tabella dei sistemi."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Gestisci le preferenze di visualizzazione e notifica."
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "Max 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "Memoria"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "Utilizzo Memoria"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Utilizzo della memoria dei container Docker"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "Nome"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "Rete"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Traffico di rete dei container Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Traffico di rete delle interfacce pubbliche"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "Nessun risultato trovato."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "Nessun sistema trovato."
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "Notifiche"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Supporto OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Ad ogni riavvio, i sistemi nel database verranno aggiornati per corrispondere ai sistemi definiti nel file."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:219
|
||||
msgid "Open menu"
|
||||
msgstr "Apri menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "Oppure continua con"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Sovrascrivi avvisi esistenti"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "Pagina"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Pagine / Impostazioni"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "Password"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "La password deve essere di almeno 10 caratteri."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "Richiesta di reimpostazione password ricevuta"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "Pausa"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Si prega di <0>configurare un server SMTP</0> per garantire la consegna degli avvisi."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Si prega di controllare i log per maggiori dettagli."
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Si prega di controllare le credenziali e riprovare"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Si prega di creare un account amministratore"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Si prega di abilitare i pop-up per questo sito"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "Si prega di accedere nuovamente"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Si prega di consultare <0>la documentazione</0> per le istruzioni."
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Si prega di accedere al proprio account"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "Porta"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilizzo preciso al momento registrato"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Lingua Preferita"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "Chiave Pub"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "Lettura"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "Ricevuto"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "Reimposta Password"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "Riprendi"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
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."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "Salva Impostazioni"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "Cerca"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Cerca sistemi o impostazioni..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
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."
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "Inviato"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
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:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "Impostazioni"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "Impostazioni salvate"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "Accedi"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "Impostazioni SMTP"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "Stato"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Spazio di swap utilizzato dal sistema"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "Utilizzo Swap"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "Sistema"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Sistemi"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "I sistemi possono essere gestiti in un file <0>config.yml</0> all'interno della tua directory dati."
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperature dei sensori di sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "Notifica di test inviata"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
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."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
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/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Throughput di {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Throughput del filesystem root"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "A email(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "Attiva/disattiva griglia"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "Attiva/disattiva tema"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Attiva quando un sensore supera una soglia"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Attiva quando il combinato up/down supera una soglia"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Attiva quando l'utilizzo della CPU supera una soglia"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Attiva quando l'utilizzo della memoria supera una soglia"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Attiva quando lo stato passa tra up e down"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Attiva quando l'utilizzo di un disco supera una soglia"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Aggiornato in tempo reale. Clicca su un sistema per visualizzare le informazioni."
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "Tempo di attività"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "Utilizzo"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Utilizzo della partizione root"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "Utilizzato"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "nome utente"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "Nome utente"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "Utenti"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "In attesa di abbastanza record da visualizzare"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Vuoi aiutarci a migliorare ulteriormente le nostre traduzioni? Dai un'occhiata a <0>Crowdin</0> per maggiori dettagli."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Notifiche Webhook / Push"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "Scrittura"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "Configurazione YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Configurazione YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Le impostazioni utente sono state aggiornate."
|
||||
808
beszel/site/src/locales/ja/ja.po
Normal file
808
beszel/site/src/locales/ja/ja.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: ja\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:46\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Japanese\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: ja\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# 日} other {# 日}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# 時間} other {# 時間}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1時間"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1週間"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12時間"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24時間"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30日間"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "アクション"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "アクティブなアラート"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>システム</0>を追加"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "新しいシステムを追加"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "システムを追加"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "URLを追加"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "チャートの表示オプションを調整します。"
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "管理者"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "代理"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "アラート"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "すべてのシステム"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "{name}を削除してもよろしいですか?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "認証プロバイダー"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "自動コピーには安全なコンテキストが必要です。"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "平均"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "コンテナの平均CPU使用率"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "平均が<0>{value}{0}</0>を超えています"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "システム全体の平均CPU使用率"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "バックアップ"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "帯域幅"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "BeszelはOpenID Connectと多くのOAuth2認証プロバイダーをサポートしています。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszelは<0>Shoutrrr</0>を使用して、人気のある通知サービスと統合します。"
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "バイナリ"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "キャッシュ / バッファ"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "キャンセル"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "注意 - データ損失の可能性"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "一般的なアプリケーションオプションを変更します。"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "チャートオプション"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "{email}を確認してリセットリンクを探してください。"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "詳細についてはログを確認してください。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "通知サービスを確認してください"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "クリックしてコピー"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "列"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "コマンドラインの指示"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "アラート通知の受信方法を設定します。"
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "パスワードを確認"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "続行"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "クリップボードにコピーされました"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "コピー"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "ホストをコピー"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Linuxコマンドをコピー"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "テキストをコピー"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU使用率"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "アカウントを作成"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "ダーク"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "ダッシュボード"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "デフォルトの期間"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "削除"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "ディスク"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "ディスクI/O"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "ディスク使用率"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "{extraFsName}のディスク使用率"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU使用率"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Dockerメモリ使用率"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "DockerネットワークI/O"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "ドキュメント"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "メール"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "メール"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "メール通知"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "パスワードをリセットするためにメールアドレスを入力してください"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "メールアドレスを入力..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "エラー"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "過去{2, plural, one {# 分} other {# 分}}で{0}{1}を超えています"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
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/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "設定をエクスポート"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "現在のシステム設定をエクスポートします。"
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "認証に失敗しました"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "設定の保存に失敗しました"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "テスト通知の送信に失敗しました"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "アラートの更新に失敗しました"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "フィルター..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "<0>{min}</0> {min, plural, one {分} other {分}}の間"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "パスワードをお忘れですか?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "一般"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "ホスト / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "管理者アカウントのパスワードを忘れた場合は、次のコマンドを使用してリセットできます。"
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "無効なメールアドレスです。"
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "カーネル"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "言語"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "ライト"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "ログアウト"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "ログイン"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "ログイン試行に失敗しました"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "ログ"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "アラートを作成する場所を探していますか?システムテーブルのベル<0/>アイコンをクリックしてください。"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "表示と通知の設定を管理します。"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "最大1分"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "メモリ"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "メモリ使用率"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Dockerコンテナのメモリ使用率"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "名前"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "帯域"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Dockerコンテナのネットワークトラフィック"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "パブリックインターフェースのネットワークトラフィック"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "結果が見つかりませんでした。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "システムが見つかりませんでした。"
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "通知"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDCサポート"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "再起動のたびに、データベース内のシステムはファイルに定義されたシステムに一致するように更新されます。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:219
|
||||
msgid "Open menu"
|
||||
msgstr "メニューを開く"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "または続行"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "既存のアラートを上書き"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "ページ"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "ページ / 設定"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "パスワード"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "パスワードは10文字以上でなければなりません。"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "パスワードリセットのリクエストを受け取りました"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "一時停止"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "アラートが配信されるように<0>SMTPサーバーを設定</0>してください。"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "詳細についてはログを確認してください。"
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "資格情報を確認して再試行してください"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "管理者アカウントを作成してください"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "このサイトのポップアップを有効にしてください"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "再度ログインしてください"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "手順については<0>ドキュメント</0>を参照してください。"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "アカウントにサインインしてください"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "ポート"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "記録された時点での正確な利用"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "優先言語"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "公開鍵"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "読み取り"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "受信"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "パスワードをリセット"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "再開"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Enterキーまたはカンマを使用してアドレスを保存します。空白のままにするとメール通知が無効になります。"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "設定を保存"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "検索"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "システムまたは設定を検索..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "アラートの受信方法を設定するには<0>通知設定</0>を参照してください。"
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "送信"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "システムを表示する際のチャートのデフォルトの時間範囲を設定します。"
|
||||
|
||||
#: src/components/command-palette.tsx:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "設定"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "設定が保存されました"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "サインイン"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP設定"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "ステータス"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "システムが使用するスワップ領域"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "スワップ使用量"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "システム"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "システム"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "システムはデータディレクトリ内の<0>config.yml</0>ファイルで管理できます。"
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "温度"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "システムセンサーの温度"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "テスト<0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "テスト通知が送信されました"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "その後、バックエンドにログインして、ユーザーテーブルでユーザーアカウントのパスワードをリセットしてください。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "この操作は元に戻せません。これにより、データベースから{name}のすべての現在のレコードが永久に削除されます。"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "{extraFsName}のスループット"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "ルートファイルシステムのスループット"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "メール宛"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "グリッドを切り替え"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "テーマを切り替え"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "センサーがしきい値を超えたときにトリガーされます"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "上り/下りの合計がしきい値を超えたときにトリガーされます"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "CPU使用率がしきい値を超えたときにトリガーされます"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "メモリ使用率がしきい値を超えたときにトリガーされます"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "ステータスが上から下に切り替わるときにトリガーされます"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "ディスクの使用量がしきい値を超えたときにトリガーされます"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "リアルタイムで更新されます。システムをクリックして情報を表示します。"
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "稼働時間"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "使用量"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "ルートパーティションの使用量"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "使用済み"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "ユーザー名"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "ユーザー名"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "ユーザー"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "表示するのに十分なレコードを待っています"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "翻訳をさらに良くするためにご協力いただけますか?詳細については<0>Crowdin</0>をご覧ください。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / プッシュ通知"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "書き込み"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML設定"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML設定"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "ユーザー設定が更新されました。"
|
||||
808
beszel/site/src/locales/ko/ko.po
Normal file
808
beszel/site/src/locales/ko/ko.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: ko\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:46\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Korean\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: ko\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# 일} other {# 일}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# 시간} other {# 시간}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1시간"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1주"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12시간"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24시간"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30일"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "작업"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "활성 경고"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>시스템</0> 추가"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "새 시스템 추가"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "시스템 추가"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "URL 추가"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "차트의 표시 옵션 조정."
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "관리자"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "에이젠"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "경고"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "모든 시스템"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "{name}을(를) 삭제하시겠습니까?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "인증 제공자"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "자동 복사는 안전한 컨텍스트가 필요합니다."
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "평균"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "컨테이너의 평균 CPU 사용량"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "평균이 <0>{value}{0}</0>을 초과합니다"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "시스템 전체의 평균 CPU 사용량"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "백업"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "대역폭"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel은 OpenID Connect 및 많은 OAuth2 인증 제공자를 지원합니다."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel은 <0>Shoutrrr</0>을 사용하여 인기 있는 알림 서비스와 통합합니다."
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "이진"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "캐시 / 버퍼"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "취소"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "주의 - 데이터 손실 가능성"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "일반 애플리케이션 옵션 변경."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "차트 옵션"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "{email}에서 재설정 링크를 확인하세요."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "자세한 내용은 로그를 확인하세요."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "알림 서비스를 확인하세요."
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "클릭하여 복사"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "열"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "명령줄 지침"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "경고 알림을 받는 방법을 구성하세요."
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "비밀번호 확인"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "계속"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "클립보드에 복사됨"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "복사"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "호스트 복사"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "리눅스 명령 복사"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "텍스트 복사"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU 사용량"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "계정 생성"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "어두운"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "대시보드"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "기본 시간 기간"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "삭제"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "디스크"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "디스크 I/O"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "디스크 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "{extraFsName}의 디스크 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "도커 CPU 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "도커 메모리 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "도커 네트워크 I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "문서"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "이메일"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "이메일"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "이메일 알림"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "비밀번호를 재설정하려면 이메일 주소를 입력하세요"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "이메일 주소 입력..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "오류"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "마지막 {2, plural, one {# 분} other {# 분}} 동안 {0}{1} 초과"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
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/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "구성 내보내기"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "현재 시스템 구성을 내보내기."
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "인증 실패"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "설정 저장 실패"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "테스트 알림 전송 실패"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "경고 업데이트 실패"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "필터..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "<0>{min}</0> {min, plural, one {분} other {분}} 동안"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "비밀번호를 잊으셨나요?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "일반"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "호스트 / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "관리자 계정의 비밀번호를 잃어버린 경우, 다음 명령을 사용하여 재설정할 수 있습니다."
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "잘못된 이메일 주소입니다."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "커널"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "언어"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "밝은"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "로그아웃"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "로그인"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "로그인 시도 실패"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "로그"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "경고를 생성할 위치를 찾고 계신가요? 시스템 테이블의 종 <0/> 아이콘을 클릭하세요."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "디스플레이 및 알림 환경설정을 관리하세요."
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "최대 1분"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "메모리"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "메모리 사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "도커 컨테이너의 메모리 사용량"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "이름"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "네트"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "도커 컨테이너의 네트워크 트래픽"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "공용 인터페이스의 네트워크 트래픽"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "결과가 없습니다."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "시스템을 찾을 수 없습니다."
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "알림"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDC 지원"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "각 재시작 시, 데이터베이스의 시스템이 파일에 정의된 시스템과 일치하도록 업데이트됩니다."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:219
|
||||
msgid "Open menu"
|
||||
msgstr "메뉴 열기"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "또는 계속하기"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "기존 경고 덮어쓰기"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "페이지"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "페이지 / 설정"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "비밀번호"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "비밀번호는 최소 10자 이상이어야 합니다."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "비밀번호 재설정 요청이 접수되었습니다"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "일시 중지"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "경고가 전달되도록 <0>SMTP 서버를 구성</0>하세요."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "자세한 내용은 로그를 확인하세요."
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "자격 증명을 확인하고 다시 시도하세요."
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "관리자 계정을 생성하세요."
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "이 사이트에 대한 팝업을 활성화하세요."
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "다시 로그인하세요."
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "지침은 <0>문서</0>를 참조하세요."
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "계정에 로그인하세요."
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "포트"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "기록된 시간의 정확한 사용량"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "선호 언어"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "공개 키"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "읽기"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "수신됨"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "비밀번호 재설정"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "재개"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Enter 키 또는 쉼표를 사용하여 주소를 저장하세요. 이메일 알림을 비활성화하려면 비워 두세요."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "설정 저장"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "검색"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "시스템 또는 설정 검색..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "경고를 받는 방법을 구성하려면 <0>알림 설정</0>을 참조하세요."
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "보냄"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "시스템을 볼 때 차트의 기본 시간 범위를 설정합니다."
|
||||
|
||||
#: src/components/command-palette.tsx:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "설정"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "설정이 저장되었습니다."
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "로그인"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP 설정"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "상태"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "시스템에서 사용된 스왑 공간"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "스왑 사용량"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "시스템"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "시스템"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "시스템은 데이터 디렉토리 내의 <0>config.yml</0> 파일에서 관리할 수 있습니다."
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "온도"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "시스템 센서의 온도"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "테스트 <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "테스트 알림이 전송되었습니다."
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "그런 다음 백엔드에 로그인하여 사용자 테이블에서 사용자 계정 비밀번호를 재설정하세요."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "이 작업은 되돌릴 수 없습니다. 데이터베이스에서 {name}에 대한 모든 현재 기록이 영구적으로 삭제됩니다."
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "{extraFsName}의 처리량"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "루트 파일 시스템의 처리량"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "이메일로"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "그리드 전환"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "테마 전환"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "센서가 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "상승/하강이 결합되어 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "CPU 사용량이 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "메모리 사용량이 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "상태가 상승과 하강 사이에서 전환될 때 트리거됩니다."
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "디스크 사용량이 임계값을 초과할 때 트리거됩니다."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "실시간으로 업데이트됩니다. 시스템을 클릭하여 정보를 확인하세요."
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "가동 시간"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "사용량"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "루트 파티션의 사용량"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "사용됨"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "사용자 이름"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "사용자 이름"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "사용자"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "표시할 충분한 기록을 기다리는 중"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "번역을 더 좋게 만드는 데 도움을 주시겠습니까? 자세한 내용은 <0>Crowdin</0>을 확인하세요."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / 푸시 알림"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "쓰기"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML 구성"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML 구성"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "사용자 설정이 업데이트되었습니다."
|
||||
809
beszel/site/src/locales/pl/pl.po
Normal file
809
beszel/site/src/locales/pl/pl.po
Normal file
@@ -0,0 +1,809 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: pl\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 21:51\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"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: pl\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr ""
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr ""
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr ""
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr ""
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr ""
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr ""
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr ""
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:219
|
||||
msgid "Open menu"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr ""
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr ""
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr ""
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr ""
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr ""
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr ""
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr ""
|
||||
|
||||
808
beszel/site/src/locales/pt/pt.po
Normal file
808
beszel/site/src/locales/pt/pt.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: pt\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:46\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Portuguese\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: pt-PT\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# dia} other {# dias}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# hora} other {# horas}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1 hora"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1 semana"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12 horas"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24 horas"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30 dias"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "Ações"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "Alertas Ativos"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Adicionar <0>Sistema</0>"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "Adicionar Novo Sistema"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "Adicionar sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "Adicionar URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Ajustar opções de exibição para gráficos."
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "Agente"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "Alertas"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "Todos os Sistemas"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Tem certeza de que deseja excluir {name}?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "Provedores de Autenticação"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "A cópia automática requer um contexto seguro."
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "Média"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Utilização média de CPU dos contêineres"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "A média excede <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Utilização média de CPU em todo o sistema"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "Backups"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "Largura de Banda"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel suporta OpenID Connect e muitos provedores de autenticação OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel usa <0>Shoutrrr</0> para integrar com serviços de notificação populares."
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "Binário"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Cache / Buffers"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Cuidado - possível perda de dados"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Alterar opções gerais do aplicativo."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Opções de gráfico"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Verifique {email} para um link de redefinição."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Verifique os logs para mais detalhes."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "Verifique seu serviço de notificação"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "Clique para copiar"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "Colunas"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "Instruções de linha de comando"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Configure como você recebe notificações de alerta."
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmar senha"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "Continuar"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Copiado para a área de transferência"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "Copiar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "Copiar host"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copiar comando Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Copiar texto"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "Uso de CPU"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "Criar conta"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "Escuro"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "Painel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Período de tempo padrão"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "Excluir"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "Disco"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "E/S de Disco"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "Uso de Disco"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Uso de disco de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Uso de CPU do Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Uso de Memória do Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "E/S de Rede do Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "Documentação"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "email"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "Notificações por email"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Digite o endereço de email para redefinir a senha"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "Digite o endereço de email..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "Erro"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Excede {0}{1} no último {2, plural, one {# minuto} other {# minutos}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
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/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "Exportar configuração"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Exporte a configuração atual dos seus sistemas."
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Falha na autenticação"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Falha ao salvar configurações"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Falha ao enviar notificação de teste"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Falha ao atualizar alerta"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "Filtrar..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Por <0>{min}</0> {min, plural, one {minuto} other {minutos}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "Esqueceu a senha?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "Geral"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Se você perdeu a senha da sua conta de administrador, pode redefini-la usando o seguinte comando."
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "Endereço de email inválido."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "Kernel"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Idioma"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "Claro"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "Sair"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "Entrar"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Tentativa de login falhou"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "Logs"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Procurando onde criar alertas? Clique nos ícones de sino <0/> na tabela de sistemas."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Gerenciar preferências de exibição e notificação."
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "Máx 1 min"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "Memória"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "Uso de Memória"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Uso de memória dos contêineres Docker"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "Nome"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "Rede"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Tráfego de rede dos contêineres Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Tráfego de rede das interfaces públicas"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "Nenhum resultado encontrado."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "Nenhum sistema encontrado."
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "Notificações"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Suporte a OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
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:219
|
||||
msgid "Open menu"
|
||||
msgstr "Abrir menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "Ou continue com"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Sobrescrever alertas existentes"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "Página"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Páginas / Configurações"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "Senha"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "A senha deve ter pelo menos 10 caracteres."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "Solicitação de redefinição de senha recebida"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "Pausar"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Por favor, <0>configure um servidor SMTP</0> para garantir que os alertas sejam entregues."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Por favor, verifique os logs para mais detalhes."
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Por favor, verifique suas credenciais e tente novamente"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Por favor, crie uma conta de administrador"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Por favor, habilite pop-ups para este site"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "Por favor, faça login novamente"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Por favor, veja <0>a documentação</0> para instruções."
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Por favor, entre na sua conta"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "Porta"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Utilização precisa no momento registrado"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Idioma Preferido"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "Chave Pública"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "Ler"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "Recebido"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "Redefinir Senha"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "Retomar"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
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."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "Salvar Configurações"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "Pesquisar"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Pesquisar por sistemas ou configurações..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
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."
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "Enviado"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
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:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "Configurações"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "Configurações salvas"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "Entrar"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "Configurações SMTP"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Espaço de swap usado pelo sistema"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "Uso de Swap"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "Sistema"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Sistemas"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Os sistemas podem ser gerenciados em um arquivo <0>config.yml</0> dentro do seu diretório de dados."
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "Temperatura"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Temperaturas dos sensores do sistema"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Testar <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "Notificação de teste enviada"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
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."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
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/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Taxa de transferência de {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Taxa de transferência do sistema de arquivos raiz"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "Para email(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "Alternar grade"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "Alternar tema"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Dispara quando qualquer sensor excede um limite"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Dispara quando a soma de subida/descida excede um limite"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Dispara quando o uso de CPU excede um limite"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Dispara quando o uso de memória excede um limite"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Dispara quando o status alterna entre ativo e inativo"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Dispara quando o uso de qualquer disco excede um limite"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Atualizado em tempo real. Clique em um sistema para ver informações."
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "Tempo de Atividade"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "Uso"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Uso da partição raiz"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "Usado"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "nome de usuário"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "Nome de usuário"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "Usuários"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Aguardando registros suficientes para exibir"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Quer nos ajudar a melhorar ainda mais nossas traduções? Confira <0>Crowdin</0> para mais detalhes."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Notificações Webhook / Push"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "Escrever"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "Configuração YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Configuração YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "As configurações do seu usuário foram atualizadas."
|
||||
808
beszel/site/src/locales/ru/ru.po
Normal file
808
beszel/site/src/locales/ru/ru.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: ru\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:46\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Russian\n"
|
||||
"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: ru\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# день} other {# дней}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# час} other {# часов}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1 час"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1 неделя"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12 часов"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24 часа"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30 дней"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "Действия"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "Активные оповещения"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Добавить <0>Систему</0>"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "Добавить новую систему"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "Добавить систему"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "Добавить URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Настроить параметры отображения для графиков."
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "Администратор"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "Агент"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "Оповещения"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "Все системы"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Вы уверены, что хотите удалить {name}?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "Поставщики аутентификации"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Автоматическое копирование требует безопасного контекста."
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "Среднее"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Среднее использование CPU контейнерами"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Среднее превышает <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Среднее использование CPU по всей системе"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "Резервные копии"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "Пропускная способность"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel поддерживает OpenID Connect и многих поставщиков аутентификации OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel использует <0>Shoutrrr</0> для интеграции с популярными сервисами уведомлений."
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "Двоичный"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Кэш / Буферы"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "Отмена"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Внимание - возможная потеря данных"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Изменить общие параметры приложения."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Параметры графиков"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Проверьте {email} для получения ссылки на сброс."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Проверьте журналы для получения более подробной информации."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "Проверьте ваш сервис уведомлений"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "Нажмите, чтобы скопировать"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "Столбцы"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "Инструкции командной строки"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Настройте, как вы получаете уведомления об оповещениях."
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "Подтвердите пароль"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "Продолжить"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Скопировано в буфер обмена"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "Копировать"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "Копировать хост"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Копировать команду Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Копировать текст"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "Использование CPU"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "Создать аккаунт"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "Темная"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "Панель управления"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Период по умолчанию"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "Удалить"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "Диск"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "Дисковый ввод/вывод"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "Использование диска"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Использование диска {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Использование CPU Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Использование памяти Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Сетевой ввод/вывод Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "Документация"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "электронная почта"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "Электронная почта"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "Уведомления по электронной почте"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Введите адрес электронной почты для сброса пароля"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "Введите адрес электронной почты..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "Ошибка"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Превышает {0}{1} за последние {2, plural, one {# минуту} other {# минут}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
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/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "Экспорт конфигурации"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Экспортируйте текущую конфигурацию систем."
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Не удалось аутентифицировать"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Не удалось сохранить настройки"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Не удалось отправить тестовое уведомление"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Не удалось обновить оповещение"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "Фильтр..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "На <0>{min}</0> {min, plural, one {минуту} other {минут}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "Забыли пароль?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "Общие"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "Хост / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Если вы потеряли пароль от своей учетной записи администратора, вы можете сбросить его, используя следующую команду."
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "Неверный адрес электронной почты."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "Ядро"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Язык"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "Светлая"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "Выйти"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "Вход"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Попытка входа не удалась"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "Журналы"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Ищете, где создать оповещения? Нажмите на значки колокольчика <0/> в таблице систем."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Управляйте предпочтениями отображения и уведомлений."
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "Макс 1 мин"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "Память"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "Использование памяти"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Использование памяти контейнерами Docker"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "Имя"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "Сеть"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Сетевой трафик контейнеров Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Сетевой трафик публичных интерфейсов"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "Результаты не найдены."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "Системы не найдены."
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "Уведомления"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Поддержка OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "При каждом перезапуске системы в базе данных будут обновлены в соответствии с системами, определенными в файле."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:219
|
||||
msgid "Open menu"
|
||||
msgstr "Открыть меню"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "Или продолжить с"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Перезаписать существующие оповещения"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "Страница"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Страницы / Настройки"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "Пароль"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "Пароль должен содержать не менее 10 символов."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "Запрос на сброс пароля получен"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "Пауза"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Пожалуйста, <0>настройте SMTP-сервер</0>, чтобы гарантировать доставку оповещений."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Пожалуйста, проверьте журналы для получения более подробной информации."
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Пожалуйста, проверьте свои учетные данные и попробуйте снова"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Пожалуйста, создайте учетную запись администратора"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Пожалуйста, включите всплывающие окна для этого сайта"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "Пожалуйста, войдите снова"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Пожалуйста, смотрите <0>документацию</0> для получения инструкций."
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Пожалуйста, войдите в свою учетную запись"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "Порт"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Точное использование в записанное время"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Предпочтительный язык"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "Ключ"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "Чтение"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "Получено"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "Сбросить пароль"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "Возобновить"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Сохраните адрес, используя клавишу ввода или запятую. Оставьте пустым, чтобы отключить уведомления по электронной почте."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "Сохранить настройки"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "Поиск"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Поиск систем или настроек..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Смотрите <0>настройки уведомлений</0>, чтобы настроить, как вы получаете оповещения."
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "Отправлено"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Устанавливает диапазон времени по умолчанию для графиков при просмотре системы."
|
||||
|
||||
#: src/components/command-palette.tsx:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "Настройки"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "Настройки сохранены"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "Войти"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "Настройки SMTP"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "Статус"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Используемое системой пространство подкачки"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "Использование подкачки"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "Система"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Системы"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Системы могут управляться в файле <0>config.yml</0> внутри вашего каталога данных."
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "Температура"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Температуры датчиков системы"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Тест <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "Тестовое уведомление отправлено"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Затем войдите в бэкенд и сбросьте пароль вашей учетной записи в таблице пользователей."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Это действие не может быть отменено. Это навсегда удалит все текущие записи для {name} из базы данных."
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Пропускная способность {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Пропускная способность корневой файловой системы"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "На электронную почту"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "Переключить сетку"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "Переключить тему"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Срабатывает, когда любой датчик превышает порог"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Срабатывает, когда комбинированный вход/выход превышает порог"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Срабатывает, когда использование CPU превышает порог"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Срабатывает, когда использование памяти превышает порог"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Срабатывает, когда статус переключается между включено и выключено"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Срабатывает, когда использование любого диска превышает порог"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Обновляется в реальном времени. Нажмите на систему, чтобы просмотреть информацию."
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "Время работы"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "Использование"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Использование корневого раздела"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "Использовано"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "имя пользователя"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "Имя пользователя"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "Пользователи"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Ожидание достаточного количества записей для отображения"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Хотите помочь нам улучшить наши переводы? Посетите <0>Crowdin</0> для получения более подробной информации."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push уведомления"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "Запись"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML конфигурация"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML конфигурация"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Ваши настройки пользователя были обновлены."
|
||||
808
beszel/site/src/locales/tr/tr.po
Normal file
808
beszel/site/src/locales/tr/tr.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: tr\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:46\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Turkish\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: tr\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# gün} other {# gün}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# saat} other {# saat}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1 saat"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1 hafta"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12 saat"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24 saat"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30 gün"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "Eylemler"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "Aktif Uyarılar"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "<0>Sistem</0> Ekle"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "Yeni Sistem Ekle"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "Sistem ekle"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "URL Ekle"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Grafikler için görüntüleme seçeneklerini ayarlayın."
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "Yönetici"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "Aracı"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "Uyarılar"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "Tüm Sistemler"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "{name} silmek istediğinizden emin misiniz?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "Kimlik Sağlayıcılar"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Otomatik kopyalama güvenli bir bağlam gerektirir."
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "Ortalama"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Konteynerlerin ortalama CPU kullanımı"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Ortalama <0>{value}{0}</0> aşıyor"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Sistem genelinde ortalama CPU kullanımı"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "Yedekler"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bant Genişliği"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel, OpenID Connect ve birçok OAuth2 kimlik doğrulama sağlayıcısını destekler."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel, popüler bildirim hizmetleriyle entegre olmak için <0>Shoutrrr</0> kullanır."
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "İkili"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Önbellek / Tamponlar"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "İptal"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Dikkat - potansiyel veri kaybı"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Genel uygulama seçeneklerini değiştirin."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Grafik seçenekleri"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Sıfırlama bağlantısı için {email} kontrol edin."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Daha fazla ayrıntı için günlükleri kontrol edin."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "Bildirim hizmetinizi kontrol edin"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "Kopyalamak için tıklayın"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "Sütunlar"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "Komut satırı talimatları"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Uyarı bildirimlerini nasıl alacağınızı yapılandırın."
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "Şifreyi onayla"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "Devam et"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Panoya kopyalandı"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "Kopyala"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "Ana bilgisayarı kopyala"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Linux komutunu kopyala"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Metni kopyala"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU Kullanımı"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "Hesap oluştur"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "Koyu"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "Gösterge Paneli"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Varsayılan zaman dilimi"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "Sil"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "Disk"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "Disk G/Ç"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "Disk Kullanımı"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "{extraFsName} disk kullanımı"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU Kullanımı"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker Bellek Kullanımı"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker Ağ G/Ç"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "Dokümantasyon"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "e-posta"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "E-posta"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "E-posta bildirimleri"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Şifreyi sıfırlamak için e-posta adresini girin"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "E-posta adresini girin..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "Hata"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Son {2, plural, one {# dakika} other {# dakika}} içinde {0}{1} aşıyor"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
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/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "Yapılandırmayı dışa aktar"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Mevcut sistem yapılandırmanızı dışa aktarın."
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Kimlik doğrulama başarısız"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Ayarlar kaydedilemedi"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Test bildirimi gönderilemedi"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Uyarı güncellenemedi"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "Filtrele..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "<0>{min}</0> {min, plural, one {dakika} other {dakika}} için"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "Şifrenizi mi unuttunuz?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "Genel"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "Host / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Yönetici hesabınızın şifresini kaybettiyseniz, aşağıdaki komutu kullanarak sıfırlayabilirsiniz."
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "Geçersiz e-posta adresi."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "Çekirdek"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Dil"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "Açık"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "Çıkış Yap"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "Giriş Yap"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Giriş denemesi başarısız"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "Günlükler"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Uyarı oluşturma yerini mi arıyorsunuz? Sistemler tablosundaki zil <0/> simgelerine tıklayın."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Görüntüleme ve bildirim tercihlerini yönetin."
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "Maks 1 dk"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "Bellek"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "Bellek Kullanımı"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Docker konteynerlerinin bellek kullanımı"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "Ad"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "Ağ"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Docker konteynerlerinin ağ trafiği"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Genel arayüzlerin ağ trafiği"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "Sonuç bulunamadı."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "Sistem bulunamadı."
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "Bildirimler"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "OAuth 2 / OIDC desteği"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
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:219
|
||||
msgid "Open menu"
|
||||
msgstr "Menüyü aç"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "Veya devam et"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Mevcut uyarıların üzerine yaz"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "Sayfa"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Sayfalar / Ayarlar"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "Şifre"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "Şifre en az 10 karakter olmalıdır."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "Şifre sıfırlama isteği alındı"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "Duraklat"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Uyarıların teslim edilmesini sağlamak için lütfen bir SMTP sunucusu <0>yapılandırın</0>."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Daha fazla ayrıntı için lütfen günlükleri kontrol edin."
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Lütfen kimlik bilgilerinizi kontrol edin ve tekrar deneyin"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Lütfen bir yönetici hesabı oluşturun"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Lütfen bu site için açılır pencereleri etkinleştirin"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "Lütfen tekrar giriş yapın"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Talimatlar için lütfen <0>dokümantasyonu</0> inceleyin."
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Lütfen hesabınıza giriş yapın"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Kayıtlı zamanda kesin kullanım"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Tercih Edilen Dil"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "Genel Anahtar"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "Oku"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "Alındı"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "Şifreyi Sıfırla"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "Devam et"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
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."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "Ayarları Kaydet"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "Ara"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Sistemler veya ayarlar için ara..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
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."
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "Gönderildi"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
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:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "Ayarlar"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "Ayarlar kaydedildi"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "Giriş yap"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP ayarları"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "Durum"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Sistem tarafından kullanılan takas alanı"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "Takas Kullanımı"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "Sistem"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Sistemler"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Sistemler, veri dizininizdeki bir <0>config.yml</0> dosyasında yönetilebilir."
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "Sıcaklık"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Sistem sensörlerinin sıcaklıkları"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Test <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "Test bildirimi gönderildi"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
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."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
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/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "{extraFsName} verimliliği"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Kök dosya sisteminin verimliliği"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "E-posta(lar)a"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "Izgarayı değiştir"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "Temayı değiştir"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Herhangi bir sensör bir eşiği aştığında tetiklenir"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Birleştirilmiş yukarı/aşağı bir eşiği aştığında tetiklenir"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "CPU kullanımı bir eşiği aştığında tetiklenir"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Bellek kullanımı bir eşiği aştığında tetiklenir"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Durum yukarı ve aşağı arasında değiştiğinde tetiklenir"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Herhangi bir diskin kullanımı bir eşiği aştığında tetiklenir"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Gerçek zamanlı olarak güncellenir. Bilgileri görüntülemek için bir sisteme tıklayın."
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "Çalışma Süresi"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "Kullanım"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Kök bölümün kullanımı"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "Kullanıldı"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "kullanıcı adı"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "Kullanıcı Adı"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "Kullanıcılar"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Görüntülemek için yeterli kayıt bekleniyor"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Çevirilerimizi daha iyi hale getirmemize yardımcı olmak ister misiniz? Daha fazla bilgi için <0>Crowdin</0> inceleyin."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Anlık bildirimler"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "Yaz"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML Yapılandırması"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML Yapılandırması"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Kullanıcı ayarlarınız güncellendi."
|
||||
808
beszel/site/src/locales/uk/uk.po
Normal file
808
beszel/site/src/locales/uk/uk.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: uk\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:46\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Ukrainian\n"
|
||||
"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: uk\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# день} few {# дні} many {# днів} other {# дня}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# година} few {# години} many {# годин} other {# години}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1 година"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1 тиждень"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12 годин"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24 години"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30 днів"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "Дії"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "Активні сповіщення"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Додати <0>Систему</0>"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "Додати нову систему"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "Додати систему"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "Додати URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Налаштуйте параметри відображення для графіків."
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "Адміністратор"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "Агент"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "Сповіщення"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "Всі системи"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Ви впевнені, що хочете видалити {name}?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "Постачальники автентифікації"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Автоматичне копіювання вимагає безпечного контексту."
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "Середнє"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Середнє використання CPU контейнерами"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Середнє перевищує <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Середнє використання CPU по всій системі"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "Резервні копії"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "Пропускна здатність"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel підтримує OpenID Connect та багато постачальників автентифікації OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel використовує <0>Shoutrrr</0> для інтеграції з популярними сервісами сповіщень."
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "Двійковий"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Кеш / Буфери"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "Скасувати"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Увага - можливе втрата даних"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Змінити загальні параметри програми."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Параметри графіків"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Перевірте {email} для отримання посилання на скидання."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Перевірте журнали для отримання додаткової інформації."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "Перевірте свій сервіс сповіщень"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "Натисніть, щоб скопіювати"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "Стовпці"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "Інструкції командного рядка"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Налаштуйте, як ви отримуєте сповіщення про тривоги."
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "Підтвердьте пароль"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "Продовжити"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Скопійовано в буфер обміну"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "Копіювати"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "Копіювати хост"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Копіювати команду Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Копіювати текст"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "ЦП"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "Використання ЦП"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "Створити обліковий запис"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "Темний"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "Панель управління"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Стандартний період часу"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "Видалити"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "Диск"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "Дисковий ввід/вивід"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "Використання диска"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Використання диска {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Використання ЦП Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Використання пам'яті Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Мережевий ввід/вивід Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "Документація"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "електронна пошта"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "Електронна пошта"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "Сповіщення електронною поштою"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Введіть адресу електронної пошти для скидання пароля"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "Введіть адресу електронної пошти..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "Помилка"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Перевищує {0}{1} за останні {2, plural, one {# хвилину} other {# хвилин}}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
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/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "Експорт конфігурації"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Експортуйте поточну конфігурацію систем."
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Не вдалося автентифікувати"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Не вдалося зберегти налаштування"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Не вдалося надіслати тестове сповіщення"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Не вдалося оновити сповіщення"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "Фільтр..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Протягом <0>{min}</0> {min, plural, one {хвилини} other {хвилин}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "Забули пароль?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "Загальні"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "Хост / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Якщо ви втратили пароль до свого адміністративного облікового запису, ви можете скинути його за допомогою наступної команди."
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "Неправильна адреса електронної пошти."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "Ядро"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Мова"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "Світлий"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "Вийти"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "Увійти"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Спроба входу не вдалася"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "Журнали"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Шукаєте, де створити сповіщення? Натисніть на іконки дзвінка <0/> в таблиці систем."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Керуйте параметрами відображення та сповіщень."
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "Макс 1 хв"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "Пам'ять"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "Використання пам'яті"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Використання пам'яті контейнерами Docker"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "Ім'я"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "Мережа"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Мережевий трафік контейнерів Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Мережевий трафік публічних інтерфейсів"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "Результатів не знайдено."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "Систем не знайдено."
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "Сповіщення"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Підтримка OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "При кожному перезапуску системи в базі даних будуть оновлені, щоб відповідати системам, визначеним у файлі."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:219
|
||||
msgid "Open menu"
|
||||
msgstr "Відкрити меню"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "Або продовжити з"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Перезаписати існуючі сповіщення"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "Сторінка"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Сторінки / Налаштування"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "Пароль"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "Пароль повинен містити щонайменше 10 символів."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "Запит на скидання пароля отримано"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "Пауза"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Будь ласка, <0>налаштуйте SMTP сервер</0>, щоб забезпечити доставку сповіщень."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Будь ласка, перевірте журнали для отримання додаткової інформації."
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Будь ласка, перевірте свої облікові дані та спробуйте ще раз"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Будь ласка, створіть адміністративний обліковий запис"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Будь ласка, увімкніть спливаючі вікна для цього сайту"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "Будь ласка, увійдіть знову"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Будь ласка, перегляньте <0>документацію</0> для отримання інструкцій."
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Будь ласка, увійдіть у свій обліковий запис"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "Порт"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Точне використання в записаний час"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Бажана мова"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "Ключ"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "Читання"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "Отримано"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "Скинути пароль"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "Продовжити"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Збережіть адресу, використовуючи клавішу Enter або кому. Залиште порожнім, щоб вимкнути сповіщення електронною поштою."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "Зберегти налаштування"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "Пошук"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Шукати системи або налаштування..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Перегляньте <0>налаштування сповіщень</0>, щоб налаштувати, як ви отримуєте сповіщення."
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "Відправлено"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Встановлює стандартний діапазон часу для графіків при перегляді системи."
|
||||
|
||||
#: src/components/command-palette.tsx:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "Налаштування"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "Налаштування збережено"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "Увійти"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "Налаштування SMTP"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "Статус"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Область підкачки, використана системою"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "Використання підкачки"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "Система"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Системи"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Системи можуть керуватися у файлі <0>config.yml</0> у вашій директорії даних."
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "Температура"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Температури датчиків системи"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Тест <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "Тестове сповіщення надіслано"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Потім увійдіть у бекенд і скиньте пароль вашого облікового запису користувача в таблиці користувачів."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Цю дію не можна скасувати. Це назавжди видалить всі поточні записи для {name} з бази даних."
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Пропускна здатність {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Пропускна здатність кореневої файлової системи"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "На електронну пошту"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "Перемкнути сітку"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "Перемкнути тему"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Спрацьовує, коли будь-який датчик перевищує поріг"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Спрацьовує, коли комбіноване підняття/падіння перевищує поріг"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Спрацьовує, коли використання ЦП перевищує поріг"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Спрацьовує, коли використання пам'яті перевищує поріг"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Спрацьовує, коли статус перемикається між підняттям і падінням"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Спрацьовує, коли використання будь-якого диска перевищує поріг"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Оновлюється в реальному часі. Натисніть на систему, щоб переглянути інформацію."
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "Час роботи"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "Використання"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Використання кореневого розділу"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "Використано"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "ім'я користувача"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "Ім'я користувача"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "Користувачі"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Очікування достатньої кількості записів для відображення"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Хочете допомогти нам зробити наші переклади ще кращими? Перегляньте <0>Crowdin</0> для отримання додаткової інформації."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / Push сповіщення"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "Запис"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "Конфігурація YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Конфігурація YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Ваші налаштування користувача були оновлені."
|
||||
808
beszel/site/src/locales/vi/vi.po
Normal file
808
beszel/site/src/locales/vi/vi.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: vi\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:47\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Vietnamese\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: vi\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# ngày} other {# ngày}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# giờ} other {# giờ}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1 giờ"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1 tuần"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12 giờ"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24 giờ"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30 ngày"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "Hành động"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "Cảnh báo hoạt động"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "Thêm <0>Hệ thống</0>"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "Thêm Hệ thống Mới"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "Thêm hệ thống"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "Thêm URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "Điều chỉnh tùy chọn hiển thị cho biểu đồ."
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "Quản trị viên"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "Tác nhân"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "Cảnh báo"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "Tất cả Hệ thống"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "Bạn có chắc chắn muốn xóa {name} không?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "Nhà cung cấp Xác thực"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "Sao chép tự động yêu cầu một ngữ cảnh an toàn."
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "Trung bình"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "Sử dụng CPU trung bình của các container"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "Trung bình vượt quá <0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "Sử dụng CPU trung bình toàn hệ thống"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "Sao lưu"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "Băng thông"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel hỗ trợ OpenID Connect và nhiều nhà cung cấp xác thực OAuth2."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel sử dụng <0>Shoutrrr</0> để tích hợp với các dịch vụ thông báo phổ biến."
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "Nhị phân"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "Bộ nhớ đệm / Bộ đệm"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "Hủy bỏ"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "Cẩn thận - có thể mất dữ liệu"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "Thay đổi các tùy chọn ứng dụng chung."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "Tùy chọn biểu đồ"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "Kiểm tra {email} để lấy liên kết đặt lại."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "Kiểm tra nhật ký để biết thêm chi tiết."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "Kiểm tra dịch vụ thông báo của bạn"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "Nhấp để sao chép"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "Cột"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "Hướng dẫn dòng lệnh"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "Cấu hình cách bạn nhận thông báo cảnh báo."
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "Xác nhận mật khẩu"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "Tiếp tục"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "Đã sao chép vào clipboard"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "Sao chép"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "Sao chép máy chủ"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Sao chép lệnh Linux"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "Sao chép văn bản"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "Sử dụng CPU"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "Tạo tài khoản"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "Tối"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "Bảng điều khiển"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "Thời gian mặc định"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "Xóa"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "Đĩa"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "Đĩa I/O"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "Sử dụng Đĩa"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "Sử dụng đĩa của {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Sử dụng CPU Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Sử dụng Bộ nhớ Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Mạng I/O Docker"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "Tài liệu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "email"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "Thông báo email"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "Nhập địa chỉ email để đặt lại mật khẩu"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "Nhập địa chỉ email..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "Lỗi"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "Vượt quá {0}{1} trong {2, plural, one {# phút} other {# phút}} qua"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
msgid "Existing systems not defined in <0>config.yml</0> will be deleted. Please make regular backups."
|
||||
msgstr "Các hệ thống hiện có không được định nghĩa trong <0>config.yml</0> sẽ bị xóa. Vui lòng sao lưu thường xuyên."
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "Xuất cấu hình"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "Xuất cấu hình hệ thống hiện tại của bạn."
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "Xác thực thất bại"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "Lưu cài đặt thất bại"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "Gửi thông báo thử nghiệm thất bại"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "Cập nhật cảnh báo thất bại"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "Lọc..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "Trong <0>{min}</0> {min, plural, one {phút} other {phút}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "Quên mật khẩu?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "Chung"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "Máy chủ / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "Nếu bạn đã mất mật khẩu cho tài khoản quản trị viên của mình, bạn có thể đặt lại bằng cách sử dụng lệnh sau."
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "Địa chỉ email không hợp lệ."
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "Nhân"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "Ngôn ngữ"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "Sáng"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "Đăng xuất"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "Đăng nhập"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "Nỗ lực đăng nhập thất bại"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "Nhật ký"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "Thay vào đó, bạn đang tìm nơi để tạo cảnh báo? Nhấp vào biểu tượng chuông <0/> trong bảng hệ thống."
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "Quản lý tùy chọn hiển thị và thông báo."
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "Tối đa 1 phút"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "Bộ nhớ"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "Sử dụng Bộ nhớ"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Sử dụng bộ nhớ của các container Docker"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "Tên"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "Mạng"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Lưu lượng mạng của các container Docker"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "Lưu lượng mạng của các giao diện công cộng"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "Không tìm thấy kết quả."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "Không tìm thấy hệ thống."
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "Thông báo"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "Hỗ trợ OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "Mỗi khi khởi động lại, các hệ thống trong cơ sở dữ liệu sẽ được cập nhật để khớp với các hệ thống được định nghĩa trong tệp."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:219
|
||||
msgid "Open menu"
|
||||
msgstr "Mở menu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "Hoặc tiếp tục với"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "Ghi đè các cảnh báo hiện có"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "Trang"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "Trang / Cài đặt"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "Mật khẩu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "Mật khẩu phải có ít nhất 10 ký tự."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "Yêu cầu đặt lại mật khẩu đã được nhận"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "Tạm dừng"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "Vui lòng <0>cấu hình máy chủ SMTP</0> để đảm bảo cảnh báo được gửi đi."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "Vui lòng kiểm tra nhật ký để biết thêm chi tiết."
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "Vui lòng kiểm tra thông tin đăng nhập của bạn và thử lại"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "Vui lòng tạo một tài khoản quản trị viên"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "Vui lòng bật cửa sổ bật lên cho trang web này"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "Vui lòng đăng nhập lại"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "Vui lòng xem <0>tài liệu</0> để biết hướng dẫn."
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "Vui lòng đăng nhập vào tài khoản của bạn"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "Cổng"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "Sử dụng chính xác tại thời điểm ghi nhận"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "Ngôn ngữ Ưa thích"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "Khóa"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "Đọc"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "Đã nhận"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "Đặt lại Mật khẩu"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "Tiếp tục"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "Lưu địa chỉ bằng cách sử dụng phím enter hoặc dấu phẩy. Để trống để vô hiệu hóa thông báo email."
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "Lưu Cài đặt"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "Tìm kiếm"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "Tìm kiếm hệ thống hoặc cài đặt..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "Xem <0>cài đặt thông báo</0> để cấu hình cách bạn nhận cảnh báo."
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "Đã gửi"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "Đặt phạm vi thời gian mặc định cho biểu đồ khi một hệ thống được xem."
|
||||
|
||||
#: src/components/command-palette.tsx:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "Cài đặt"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "Cài đặt đã được lưu"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "Đăng nhập"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "Cài đặt SMTP"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "Trạng thái"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "Không gian hoán đổi được sử dụng bởi hệ thống"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "Sử dụng Hoán đổi"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "Hệ thống"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "Các hệ thống"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "Các hệ thống có thể được quản lý trong tệp <0>config.yml</0> bên trong thư mục dữ liệu của bạn."
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "Nhiệt độ"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "Nhiệt độ của các cảm biến hệ thống"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "Kiểm tra <0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "Thông báo thử nghiệm đã được gửi"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
msgid "The agent must be running on the system to connect. Copy the installation command for the agent below."
|
||||
msgstr "Tác nhân phải đang chạy trên hệ thống để kết nối. Sao chép lệnh cài đặt cho tác nhân bên dưới."
|
||||
|
||||
#: src/components/add-system.tsx:95
|
||||
msgid "The agent must be running on the system to connect. Copy the<0>docker-compose.yml</0> for the agent below."
|
||||
msgstr "Tác nhân phải đang chạy trên hệ thống để kết nối. Sao chép <0>docker-compose.yml</0> cho tác nhân bên dưới."
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:98
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "Sau đó đăng nhập vào backend và đặt lại mật khẩu tài khoản người dùng của bạn trong bảng người dùng."
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "Hành động này không thể hoàn tác. Điều này sẽ xóa vĩnh viễn tất cả các bản ghi hiện tại cho {name} khỏi cơ sở dữ liệu."
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "Thông lượng của {extraFsName}"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "Thông lượng của hệ thống tệp gốc"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "Đến email(s)"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "Chuyển đổi lưới"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "Chuyển đổi chủ đề"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "Kích hoạt khi bất kỳ cảm biến nào vượt quá ngưỡng"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "Kích hoạt khi kết hợp lên/xuống vượt quá ngưỡng"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "Kích hoạt khi sử dụng CPU vượt quá ngưỡng"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "Kích hoạt khi sử dụng bộ nhớ vượt quá ngưỡng"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "Kích hoạt khi trạng thái chuyển đổi giữa lên và xuống"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "Kích hoạt khi sử dụng bất kỳ đĩa nào vượt quá ngưỡng"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "Cập nhật theo thời gian thực. Nhấp vào một hệ thống để xem thông tin."
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "Thời gian hoạt động"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "Sử dụng"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "Sử dụng phân vùng gốc"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "Đã sử dụng"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "tên người dùng"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "Tên người dùng"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "Người dùng"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "Đang chờ đủ bản ghi để hiển thị"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "Muốn giúp chúng tôi cải thiện bản dịch của mình? Xem <0>Crowdin</0> để biết thêm chi tiết."
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Thông báo Webhook / Push"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "Ghi"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "Cấu hình YAML"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "Cấu hình YAML"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "Cài đặt người dùng của bạn đã được cập nhật."
|
||||
808
beszel/site/src/locales/zh-CN/zh-CN.po
Normal file
808
beszel/site/src/locales/zh-CN/zh-CN.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: zh\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:46\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Chinese Simplified\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: zh-CN\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# 天} other {# 天}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# 小时} other {# 小时}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1小时"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1周"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12小时"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24小时"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30天"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "操作"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "活动警报"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "添加<0>系统</0>"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "添加新系统"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "添加系统"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "添加URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "调整图表的显示选项。"
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "管理员"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "代理"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "警报"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "所有系统"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "您确定要删除{name}吗?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "认证提供者"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "自动复制需要安全的上下文。"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "平均"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "容器的平均CPU使用率"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "平均值超过<0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "系统范围内的平均CPU使用率"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "备份"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "带宽"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel支持OpenID Connect和许多OAuth2认证提供者。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel使用<0>Shoutrrr</0>与流行的通知服务集成。"
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "二进制"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "缓存/缓冲区"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "取消"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "注意 - 可能的数据丢失"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "更改一般应用程序选项。"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "图表选项"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "检查{email}以获取重置链接。"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "检查日志以获取更多详细信息。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "检查您的通知服务"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "点击复制"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "列"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "命令行说明"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "配置您接收警报通知的方式。"
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "确认密码"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "继续"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "已复制到剪贴板"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "复制"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "复制主机"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "复制Linux命令"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "复制文本"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU使用率"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "创建账户"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "深色"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "仪表板"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "默认时间段"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "删除"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "磁盘"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "磁盘I/O"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "磁盘使用"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "{extraFsName}的磁盘使用"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU使用"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker内存使用"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker网络I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "文档"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "电子邮件"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "电子邮件"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "电子邮件通知"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "输入电子邮件地址以重置密码"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "输入电子邮件地址..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "错误"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "在过去的{2, plural, one {# 分钟} other {# 分钟}}中超过{0}{1}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
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/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "导出配置"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "导出您当前的系统配置。"
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "认证失败"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "保存设置失败"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "发送测试通知失败"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "更新警报失败"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "过滤..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "持续<0>{min}</0> {min, plural, one {分钟} other {分钟}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "忘记密码?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "常规"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "主机/IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "如果您丢失了管理员账户的密码,可以使用以下命令重置。"
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "无效的电子邮件地址。"
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "内核"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "语言"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "浅色"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "登出"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "登录"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "登录尝试失败"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "日志"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "在寻找创建警报的位置吗?点击系统表中的铃铛<0/>图标。"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "管理显示和通知偏好。"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "最大1分钟"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "内存"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "内存使用"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Docker容器的内存使用"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "名称"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "网络"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Docker容器的网络流量"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "公共接口的网络流量"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "未找到结果。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "未找到系统。"
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "通知"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "支持OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "每次重启时,数据库中的系统将更新以匹配文件中定义的系统。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:219
|
||||
msgid "Open menu"
|
||||
msgstr "打开菜单"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "或继续使用"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "覆盖现有警报"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "页面"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "页面/设置"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "密码"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "密码必须至少10个字符。"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "已收到密码重置请求"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "暂停"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "请<0>配置SMTP服务器</0>以确保警报被传递。"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "请检查日志以获取更多详细信息。"
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "请检查您的凭据并重试"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "请创建一个管理员账户"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "请为此网站启用弹出窗口"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "请重新登录"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "请参阅<0>文档</0>以获取说明。"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "请登录您的账户"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "端口"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "记录时间的精确使用率"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "首选语言"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "公钥"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "读取"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "接收"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "重置密码"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "恢复"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "使用回车键或逗号保存地址。留空以禁用电子邮件通知。"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "保存设置"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "搜索"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "搜索系统或设置..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "查看<0>通知设置</0>以配置您接收警报的方式。"
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "发送"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "设置查看系统时图表的默认时间范围。"
|
||||
|
||||
#: src/components/command-palette.tsx:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "设置"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "设置已保存"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "登录"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP设置"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "系统使用的交换空间"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "交换使用"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "系统"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "系统"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "系统可以在数据目录中的<0>config.yml</0>文件中管理。"
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "温度"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "系统传感器的温度"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "测试<0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "测试通知已发送"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "然后登录到后台并在用户表中重置您的用户账户密码。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "此操作无法撤销。这将永久删除数据库中{name}的所有当前记录。"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "{extraFsName}的吞吐量"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "根文件系统的吞吐量"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "发送到电子邮件"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "切换网格"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "切换主题"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "当任何传感器超过阈值时触发"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "当组合的上/下超过阈值时触发"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "当CPU使用率超过阈值时触发"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "当内存使用率超过阈值时触发"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "当状态在上和下之间切换时触发"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "当任何磁盘的使用超过阈值时触发"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "实时更新。点击系统查看信息。"
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "正常运行时间"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "使用"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "根分区的使用"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "已用"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "用户名"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "用户名"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "用户"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "等待足够的记录以显示"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "想帮助我们改进翻译吗?查看<0>Crowdin</0>以获取更多详细信息。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / 推送通知"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "写入"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML配置"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML配置"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "您的用户设置已更新。"
|
||||
808
beszel/site/src/locales/zh-HK/zh-HK.po
Normal file
808
beszel/site/src/locales/zh-HK/zh-HK.po
Normal file
@@ -0,0 +1,808 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2024-11-01 11:30-0400\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: zh\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-11-04 20:47\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Chinese Traditional, Hong Kong\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Crowdin-Project: beszel\n"
|
||||
"X-Crowdin-Project-ID: 733311\n"
|
||||
"X-Crowdin-Language: zh-HK\n"
|
||||
"X-Crowdin-File: /main/beszel/site/src/locales/en/en.po\n"
|
||||
"X-Crowdin-File-ID: 16\n"
|
||||
|
||||
#: src/components/routes/system.tsx:242
|
||||
msgid "{0, plural, one {# day} other {# days}}"
|
||||
msgstr "{0, plural, one {# 天} other {# 天}}"
|
||||
|
||||
#: src/components/routes/system.tsx:240
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
msgstr "{hours, plural, one {# 小時} other {# 小時}}"
|
||||
|
||||
#: src/lib/utils.ts:139
|
||||
msgid "1 hour"
|
||||
msgstr "1小時"
|
||||
|
||||
#: src/lib/utils.ts:162
|
||||
msgid "1 week"
|
||||
msgstr "1週"
|
||||
|
||||
#: src/lib/utils.ts:147
|
||||
msgid "12 hours"
|
||||
msgstr "12小時"
|
||||
|
||||
#: src/lib/utils.ts:155
|
||||
msgid "24 hours"
|
||||
msgstr "24小時"
|
||||
|
||||
#: src/lib/utils.ts:170
|
||||
msgid "30 days"
|
||||
msgstr "30天"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx:207
|
||||
msgid "Actions"
|
||||
msgstr "操作"
|
||||
|
||||
#: src/components/routes/home.tsx:62
|
||||
msgid "Active Alerts"
|
||||
msgstr "活動警報"
|
||||
|
||||
#: src/components/add-system.tsx:74
|
||||
msgid "Add <0>System</0>"
|
||||
msgstr "添加<0>系統</0>"
|
||||
|
||||
#: src/components/add-system.tsx:83
|
||||
msgid "Add New System"
|
||||
msgstr "添加新系統"
|
||||
|
||||
#: src/components/add-system.tsx:167
|
||||
#: src/components/add-system.tsx:178
|
||||
msgid "Add system"
|
||||
msgstr "添加系統"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:156
|
||||
msgid "Add URL"
|
||||
msgstr "添加URL"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:81
|
||||
msgid "Adjust display options for charts."
|
||||
msgstr "調整圖表的顯示選項。"
|
||||
|
||||
#: src/components/command-palette.tsx:133
|
||||
#: src/components/command-palette.tsx:146
|
||||
#: src/components/command-palette.tsx:160
|
||||
#: src/components/command-palette.tsx:174
|
||||
#: src/components/command-palette.tsx:189
|
||||
#: src/components/command-palette.tsx:204
|
||||
msgid "Admin"
|
||||
msgstr "管理員"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:186
|
||||
msgid "Agent"
|
||||
msgstr "代理"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:32
|
||||
#: src/components/alerts/alert-button.tsx:68
|
||||
msgid "Alerts"
|
||||
msgstr "警報"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:88
|
||||
#: src/components/systems-table/systems-table.tsx:317
|
||||
msgid "All Systems"
|
||||
msgstr "所有系統"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:261
|
||||
msgid "Are you sure you want to delete {name}?"
|
||||
msgstr "您確定要刪除{name}嗎?"
|
||||
|
||||
#: src/components/command-palette.tsx:186
|
||||
#: src/components/navbar.tsx:102
|
||||
msgid "Auth Providers"
|
||||
msgstr "認證提供者"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:16
|
||||
msgid "Automatic copy requires a secure context."
|
||||
msgstr "自動複製需要安全的上下文。"
|
||||
|
||||
#: src/components/routes/system.tsx:568
|
||||
msgid "Average"
|
||||
msgstr "平均"
|
||||
|
||||
#: src/components/routes/system.tsx:387
|
||||
msgid "Average CPU utilization of containers"
|
||||
msgstr "容器的平均CPU使用率"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:204
|
||||
msgid "Average exceeds <0>{value}{0}</0>"
|
||||
msgstr "平均值超過<0>{value}{0}</0>"
|
||||
|
||||
#: src/components/routes/system.tsx:376
|
||||
msgid "Average system-wide CPU utilization"
|
||||
msgstr "系統範圍內的平均CPU使用率"
|
||||
|
||||
#: src/components/command-palette.tsx:171
|
||||
#: src/components/navbar.tsx:94
|
||||
msgid "Backups"
|
||||
msgstr "備份"
|
||||
|
||||
#: src/components/routes/system.tsx:436
|
||||
#: src/lib/utils.ts:307
|
||||
msgid "Bandwidth"
|
||||
msgstr "帶寬"
|
||||
|
||||
#: src/components/login/auth-form.tsx:313
|
||||
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
|
||||
msgstr "Beszel支持OpenID Connect和許多OAuth2認證提供者。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:127
|
||||
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
|
||||
msgstr "Beszel使用<0>Shoutrrr</0>與流行的通知服務集成。"
|
||||
|
||||
#: src/components/add-system.tsx:88
|
||||
msgid "Binary"
|
||||
msgstr "二進制"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:89
|
||||
msgid "Cache / Buffers"
|
||||
msgstr "緩存/緩衝區"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:272
|
||||
msgid "Cancel"
|
||||
msgstr "取消"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:68
|
||||
msgid "Caution - potential data loss"
|
||||
msgstr "注意 - 可能的數據丟失"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:36
|
||||
msgid "Change general application options."
|
||||
msgstr "更改一般應用選項。"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:78
|
||||
msgid "Chart options"
|
||||
msgstr "圖表選項"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:34
|
||||
msgid "Check {email} for a reset link."
|
||||
msgstr "檢查{email}以獲取重置鏈接。"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:40
|
||||
msgid "Check logs for more details."
|
||||
msgstr "檢查日誌以獲取更多詳細信息。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:183
|
||||
msgid "Check your notification service"
|
||||
msgstr "檢查您的通知服務"
|
||||
|
||||
#: src/components/add-system.tsx:153
|
||||
msgid "Click to copy"
|
||||
msgstr "點擊以複製"
|
||||
|
||||
#. Context: table columns
|
||||
#: src/components/systems-table/systems-table.tsx:328
|
||||
msgid "Columns"
|
||||
msgstr "欄"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:83
|
||||
#: src/components/login/forgot-pass-form.tsx:89
|
||||
msgid "Command line instructions"
|
||||
msgstr "命令行指令"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:77
|
||||
msgid "Configure how you receive alert notifications."
|
||||
msgstr "配置您接收警報通知的方式。"
|
||||
|
||||
#: src/components/login/auth-form.tsx:189
|
||||
#: src/components/login/auth-form.tsx:194
|
||||
msgid "Confirm password"
|
||||
msgstr "確認密碼"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:278
|
||||
msgid "Continue"
|
||||
msgstr "繼續"
|
||||
|
||||
#: src/lib/utils.ts:25
|
||||
msgid "Copied to clipboard"
|
||||
msgstr "已複製到剪貼板"
|
||||
|
||||
#: src/components/add-system.tsx:164
|
||||
msgid "Copy"
|
||||
msgstr "複製"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:247
|
||||
msgid "Copy host"
|
||||
msgstr "複製主機"
|
||||
|
||||
#: src/components/add-system.tsx:175
|
||||
msgid "Copy Linux command"
|
||||
msgstr "複製Linux命令"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx:13
|
||||
msgid "Copy text"
|
||||
msgstr "複製文本"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:152
|
||||
msgid "CPU"
|
||||
msgstr "CPU"
|
||||
|
||||
#: src/components/charts/area-chart.tsx:52
|
||||
#: src/components/routes/system.tsx:375
|
||||
#: src/lib/utils.ts:289
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU使用率"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Create account"
|
||||
msgstr "創建帳戶"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx:21
|
||||
msgid "Dark"
|
||||
msgstr "深色"
|
||||
|
||||
#: src/components/command-palette.tsx:82
|
||||
#: src/components/routes/home.tsx:35
|
||||
msgid "Dashboard"
|
||||
msgstr "儀表板"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:85
|
||||
msgid "Default time period"
|
||||
msgstr "默認時間段"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:253
|
||||
msgid "Delete"
|
||||
msgstr "刪除"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:166
|
||||
msgid "Disk"
|
||||
msgstr "磁碟"
|
||||
|
||||
#: src/components/routes/system.tsx:426
|
||||
msgid "Disk I/O"
|
||||
msgstr "磁碟I/O"
|
||||
|
||||
#: src/components/charts/disk-chart.tsx:74
|
||||
#: src/components/routes/system.tsx:415
|
||||
#: src/lib/utils.ts:301
|
||||
msgid "Disk Usage"
|
||||
msgstr "磁碟使用"
|
||||
|
||||
#: src/components/routes/system.tsx:495
|
||||
msgid "Disk usage of {extraFsName}"
|
||||
msgstr "{extraFsName}的磁碟使用"
|
||||
|
||||
#: src/components/routes/system.tsx:386
|
||||
msgid "Docker CPU Usage"
|
||||
msgstr "Docker CPU使用"
|
||||
|
||||
#: src/components/routes/system.tsx:407
|
||||
msgid "Docker Memory Usage"
|
||||
msgstr "Docker記憶體使用"
|
||||
|
||||
#: src/components/routes/system.tsx:452
|
||||
msgid "Docker Network I/O"
|
||||
msgstr "Docker網絡I/O"
|
||||
|
||||
#: src/components/command-palette.tsx:125
|
||||
msgid "Documentation"
|
||||
msgstr "文檔"
|
||||
|
||||
#: src/components/login/auth-form.tsx:158
|
||||
msgid "email"
|
||||
msgstr "電子郵件"
|
||||
|
||||
#: src/components/login/auth-form.tsx:152
|
||||
#: src/components/login/forgot-pass-form.tsx:53
|
||||
msgid "Email"
|
||||
msgstr "電子郵件"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:91
|
||||
msgid "Email notifications"
|
||||
msgstr "電子郵件通知"
|
||||
|
||||
#: src/components/login/login.tsx:36
|
||||
msgid "Enter email address to reset password"
|
||||
msgstr "輸入電子郵件地址以重置密碼"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:111
|
||||
msgid "Enter email address..."
|
||||
msgstr "輸入電子郵件地址..."
|
||||
|
||||
#: src/components/login/auth-form.tsx:256
|
||||
#: src/components/routes/settings/config-yaml.tsx:28
|
||||
#: src/components/routes/settings/notifications.tsx:187
|
||||
msgid "Error"
|
||||
msgstr "錯誤"
|
||||
|
||||
#: src/components/routes/home.tsx:81
|
||||
msgid "Exceeds {0}{1} in last {2, plural, one {# minute} other {# minutes}}"
|
||||
msgstr "在過去的{2, plural, one {# 分鐘} other {# 分鐘}}中超過{0}{1}"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:72
|
||||
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/config-yaml.tsx:93
|
||||
msgid "Export configuration"
|
||||
msgstr "導出配置"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:48
|
||||
msgid "Export your current systems configuration."
|
||||
msgstr "導出您當前的系統配置。"
|
||||
|
||||
#: src/lib/utils.ts:38
|
||||
msgid "Failed to authenticate"
|
||||
msgstr "認證失敗"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:39
|
||||
#: src/components/routes/settings/notifications.tsx:62
|
||||
msgid "Failed to save settings"
|
||||
msgstr "保存設置失敗"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:188
|
||||
msgid "Failed to send test notification"
|
||||
msgstr "發送測試通知失敗"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:27
|
||||
msgid "Failed to update alert"
|
||||
msgstr "更新警報失敗"
|
||||
|
||||
#: src/components/routes/system.tsx:539
|
||||
#: src/components/systems-table/systems-table.tsx:324
|
||||
msgid "Filter..."
|
||||
msgstr "篩選..."
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:225
|
||||
msgid "For <0>{min}</0> {min, plural, one {minute} other {minutes}}"
|
||||
msgstr "持續<0>{min}</0> {min, plural, one {分鐘} other {分鐘}}"
|
||||
|
||||
#: src/components/login/auth-form.tsx:337
|
||||
msgid "Forgot password?"
|
||||
msgstr "忘記密碼?"
|
||||
|
||||
#. Context: General settings
|
||||
#: src/components/routes/settings/general.tsx:33
|
||||
#: src/components/routes/settings/layout.tsx:51
|
||||
msgid "General"
|
||||
msgstr "一般"
|
||||
|
||||
#: src/components/add-system.tsx:119
|
||||
msgid "Host / IP"
|
||||
msgstr "主機 / IP"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:93
|
||||
msgid "If you've lost the password to your admin account, you may reset it using the following command."
|
||||
msgstr "如果您丟失了管理員帳戶的密碼,可以使用以下命令重置。"
|
||||
|
||||
#: src/components/login/auth-form.tsx:16
|
||||
msgid "Invalid email address."
|
||||
msgstr "無效的電子郵件地址。"
|
||||
|
||||
#. Linux kernel
|
||||
#: src/components/routes/system.tsx:254
|
||||
msgid "Kernel"
|
||||
msgstr "內核"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:45
|
||||
msgid "Language"
|
||||
msgstr "語言"
|
||||
|
||||
#. Light theme
|
||||
#: src/components/mode-toggle.tsx:16
|
||||
msgid "Light"
|
||||
msgstr "淺色"
|
||||
|
||||
#: src/components/navbar.tsx:113
|
||||
msgid "Log Out"
|
||||
msgstr "登出"
|
||||
|
||||
#: src/components/login/login.tsx:17
|
||||
msgid "Login"
|
||||
msgstr "登錄"
|
||||
|
||||
#: src/components/login/auth-form.tsx:42
|
||||
#: src/components/login/forgot-pass-form.tsx:15
|
||||
msgid "Login attempt failed"
|
||||
msgstr "登錄嘗試失敗"
|
||||
|
||||
#: src/components/command-palette.tsx:157
|
||||
#: src/components/navbar.tsx:86
|
||||
msgid "Logs"
|
||||
msgstr "日誌"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:80
|
||||
msgid "Looking instead for where to create alerts? Click the bell <0/> icons in the systems table."
|
||||
msgstr "在尋找創建警報的位置嗎?點擊系統表中的鈴鐺<0/>圖標。"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:85
|
||||
msgid "Manage display and notification preferences."
|
||||
msgstr "管理顯示和通知偏好。"
|
||||
|
||||
#. Chart select field. Please try to keep this short.
|
||||
#: src/components/routes/system.tsx:571
|
||||
msgid "Max 1 min"
|
||||
msgstr "最大1分鐘"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:159
|
||||
msgid "Memory"
|
||||
msgstr "記憶體"
|
||||
|
||||
#: src/components/routes/system.tsx:397
|
||||
#: src/lib/utils.ts:295
|
||||
msgid "Memory Usage"
|
||||
msgstr "記憶體使用"
|
||||
|
||||
#: src/components/routes/system.tsx:408
|
||||
msgid "Memory usage of docker containers"
|
||||
msgstr "Docker容器的記憶體使用"
|
||||
|
||||
#: src/components/add-system.tsx:113
|
||||
msgid "Name"
|
||||
msgstr "名稱"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:173
|
||||
msgid "Net"
|
||||
msgstr "網絡"
|
||||
|
||||
#: src/components/routes/system.tsx:453
|
||||
msgid "Network traffic of docker containers"
|
||||
msgstr "Docker容器的網絡流量"
|
||||
|
||||
#: src/components/routes/system.tsx:438
|
||||
msgid "Network traffic of public interfaces"
|
||||
msgstr "公共接口的網絡流量"
|
||||
|
||||
#: src/components/command-palette.tsx:50
|
||||
msgid "No results found."
|
||||
msgstr "未找到結果。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:400
|
||||
msgid "No systems found."
|
||||
msgstr "未找到系統。"
|
||||
|
||||
#: src/components/command-palette.tsx:111
|
||||
#: src/components/routes/settings/layout.tsx:56
|
||||
#: src/components/routes/settings/notifications.tsx:74
|
||||
msgid "Notifications"
|
||||
msgstr "通知"
|
||||
|
||||
#: src/components/login/auth-form.tsx:308
|
||||
msgid "OAuth 2 / OIDC support"
|
||||
msgstr "支持OAuth 2 / OIDC"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:61
|
||||
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
|
||||
msgstr "每次重啟時,數據庫中的系統將更新以匹配文件中定義的系統。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:219
|
||||
msgid "Open menu"
|
||||
msgstr "打開菜單"
|
||||
|
||||
#: src/components/login/auth-form.tsx:227
|
||||
msgid "Or continue with"
|
||||
msgstr "或繼續使用"
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:109
|
||||
msgid "Overwrite existing alerts"
|
||||
msgstr "覆蓋現有警報"
|
||||
|
||||
#: src/components/command-palette.tsx:85
|
||||
msgid "Page"
|
||||
msgstr "頁面"
|
||||
|
||||
#: src/components/command-palette.tsx:72
|
||||
msgid "Pages / Settings"
|
||||
msgstr "頁面 / 設置"
|
||||
|
||||
#: src/components/login/auth-form.tsx:171
|
||||
#: src/components/login/auth-form.tsx:176
|
||||
msgid "Password"
|
||||
msgstr "密碼"
|
||||
|
||||
#: src/components/login/auth-form.tsx:17
|
||||
msgid "Password must be at least 10 characters."
|
||||
msgstr "密碼必須至少10個字符。"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:33
|
||||
msgid "Password reset request received"
|
||||
msgstr "已收到密碼重置請求"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:241
|
||||
msgid "Pause"
|
||||
msgstr "暫停"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:95
|
||||
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
|
||||
msgstr "請<0>配置SMTP服務器</0>以確保警報被傳送。"
|
||||
|
||||
#: src/components/alerts/alerts-system.tsx:28
|
||||
msgid "Please check logs for more details."
|
||||
msgstr "請檢查日誌以獲取更多詳細信息。"
|
||||
|
||||
#: src/components/login/auth-form.tsx:43
|
||||
#: src/components/login/forgot-pass-form.tsx:16
|
||||
msgid "Please check your credentials and try again"
|
||||
msgstr "請檢查您的憑證並重試"
|
||||
|
||||
#: src/components/login/login.tsx:34
|
||||
msgid "Please create an admin account"
|
||||
msgstr "請創建一個管理員帳戶"
|
||||
|
||||
#: src/components/login/auth-form.tsx:257
|
||||
msgid "Please enable pop-ups for this site"
|
||||
msgstr "請為此網站啟用彈出窗口"
|
||||
|
||||
#: src/lib/utils.ts:39
|
||||
msgid "Please log in again"
|
||||
msgstr "請重新登錄"
|
||||
|
||||
#: src/components/login/auth-form.tsx:316
|
||||
msgid "Please see <0>the documentation</0> for instructions."
|
||||
msgstr "請參閱<0>文檔</0>以獲取說明。"
|
||||
|
||||
#: src/components/login/login.tsx:38
|
||||
msgid "Please sign in to your account"
|
||||
msgstr "請登錄到您的帳戶"
|
||||
|
||||
#: src/components/add-system.tsx:125
|
||||
msgid "Port"
|
||||
msgstr "端口"
|
||||
|
||||
#: src/components/routes/system.tsx:398
|
||||
msgid "Precise utilization at the recorded time"
|
||||
msgstr "記錄時間的精確使用率"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:58
|
||||
msgid "Preferred Language"
|
||||
msgstr "首選語言"
|
||||
|
||||
#. Use 'Key' if your language requires many more characters
|
||||
#: src/components/add-system.tsx:131
|
||||
msgid "Public Key"
|
||||
msgstr "公鑰"
|
||||
|
||||
#. Context is disk read
|
||||
#: src/components/charts/area-chart.tsx:56
|
||||
#: src/components/charts/area-chart.tsx:66
|
||||
msgid "Read"
|
||||
msgstr "讀取"
|
||||
|
||||
#. Context is network bytes received (download)
|
||||
#: src/components/charts/area-chart.tsx:61
|
||||
msgid "Received"
|
||||
msgstr "接收"
|
||||
|
||||
#: src/components/login/forgot-pass-form.tsx:76
|
||||
msgid "Reset Password"
|
||||
msgstr "重置密碼"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:236
|
||||
msgid "Resume"
|
||||
msgstr "恢復"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:117
|
||||
msgid "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
msgstr "使用回車鍵或逗號保存地址。留空以禁用電子郵件通知。"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:106
|
||||
#: src/components/routes/settings/notifications.tsx:167
|
||||
msgid "Save Settings"
|
||||
msgstr "保存設置"
|
||||
|
||||
#: src/components/navbar.tsx:142
|
||||
msgid "Search"
|
||||
msgstr "搜索"
|
||||
|
||||
#: src/components/command-palette.tsx:47
|
||||
msgid "Search for systems or settings..."
|
||||
msgstr "搜索系統或設置..."
|
||||
|
||||
#: src/components/alerts/alert-button.tsx:71
|
||||
msgid "See <0>notification settings</0> to configure how you receive alerts."
|
||||
msgstr "查看<0>通知設置</0>以配置您接收警報的方式。"
|
||||
|
||||
#. Context is network bytes sent (upload)
|
||||
#: src/components/charts/area-chart.tsx:60
|
||||
msgid "Sent"
|
||||
msgstr "發送"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:100
|
||||
msgid "Sets the default time range for charts when a system is viewed."
|
||||
msgstr "設置查看系統時圖表的默認時間範圍。"
|
||||
|
||||
#: src/components/command-palette.tsx:96
|
||||
#: src/components/command-palette.tsx:99
|
||||
#: src/components/command-palette.tsx:114
|
||||
#: src/components/routes/settings/layout.tsx:71
|
||||
#: src/components/routes/settings/layout.tsx:82
|
||||
msgid "Settings"
|
||||
msgstr "設置"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:33
|
||||
msgid "Settings saved"
|
||||
msgstr "設置已保存"
|
||||
|
||||
#: src/components/login/auth-form.tsx:215
|
||||
msgid "Sign in"
|
||||
msgstr "登錄"
|
||||
|
||||
#: src/components/command-palette.tsx:201
|
||||
msgid "SMTP settings"
|
||||
msgstr "SMTP設置"
|
||||
|
||||
#: src/lib/utils.ts:282
|
||||
msgid "Status"
|
||||
msgstr "狀態"
|
||||
|
||||
#: src/components/routes/system.tsx:467
|
||||
msgid "Swap space used by the system"
|
||||
msgstr "系統使用的交換空間"
|
||||
|
||||
#: src/components/routes/system.tsx:466
|
||||
msgid "Swap Usage"
|
||||
msgstr "交換使用"
|
||||
|
||||
#. System theme
|
||||
#: src/components/mode-toggle.tsx:26
|
||||
#: src/components/systems-table/systems-table.tsx:110
|
||||
#: src/components/systems-table/systems-table.tsx:121
|
||||
msgid "System"
|
||||
msgstr "系統"
|
||||
|
||||
#: src/components/navbar.tsx:78
|
||||
msgid "Systems"
|
||||
msgstr "系統"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:55
|
||||
msgid "Systems may be managed in a <0>config.yml</0> file inside your data directory."
|
||||
msgstr "系統可以在您的數據目錄中的<0>config.yml</0>文件中管理。"
|
||||
|
||||
#: src/components/routes/system.tsx:477
|
||||
#: src/lib/utils.ts:314
|
||||
msgid "Temperature"
|
||||
msgstr "溫度"
|
||||
|
||||
#: src/components/routes/system.tsx:478
|
||||
msgid "Temperatures of system sensors"
|
||||
msgstr "系統傳感器的溫度"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:211
|
||||
msgid "Test <0>URL</0>"
|
||||
msgstr "測試<0>URL</0>"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:182
|
||||
msgid "Test notification sent"
|
||||
msgstr "測試通知已發送"
|
||||
|
||||
#: src/components/add-system.tsx:104
|
||||
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:95
|
||||
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:98
|
||||
msgid "Then log into the backend and reset your user account password in the users table."
|
||||
msgstr "然後登錄到後端並在用戶表中重置您的用戶帳戶密碼。"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:264
|
||||
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
|
||||
msgstr "此操作無法撤銷。這將永久刪除數據庫中{name}的所有當前記錄。"
|
||||
|
||||
#: src/components/routes/system.tsx:507
|
||||
msgid "Throughput of {extraFsName}"
|
||||
msgstr "{extraFsName}的吞吐量"
|
||||
|
||||
#: src/components/routes/system.tsx:427
|
||||
msgid "Throughput of root filesystem"
|
||||
msgstr "根文件系統的吞吐量"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:106
|
||||
msgid "To email(s)"
|
||||
msgstr "發送到電子郵件"
|
||||
|
||||
#: src/components/routes/system.tsx:350
|
||||
#: src/components/routes/system.tsx:363
|
||||
msgid "Toggle grid"
|
||||
msgstr "切換網格"
|
||||
|
||||
#: src/components/mode-toggle.tsx:33
|
||||
msgid "Toggle theme"
|
||||
msgstr "切換主題"
|
||||
|
||||
#: src/lib/utils.ts:317
|
||||
msgid "Triggers when any sensor exceeds a threshold"
|
||||
msgstr "當任何傳感器超過閾值時觸發"
|
||||
|
||||
#: src/lib/utils.ts:310
|
||||
msgid "Triggers when combined up/down exceeds a threshold"
|
||||
msgstr "當組合的上/下超過閾值時觸發"
|
||||
|
||||
#: src/lib/utils.ts:292
|
||||
msgid "Triggers when CPU usage exceeds a threshold"
|
||||
msgstr "當CPU使用率超過閾值時觸發"
|
||||
|
||||
#: src/lib/utils.ts:298
|
||||
msgid "Triggers when memory usage exceeds a threshold"
|
||||
msgstr "當記憶體使用率超過閾值時觸發"
|
||||
|
||||
#: src/lib/utils.ts:285
|
||||
msgid "Triggers when status switches between up and down"
|
||||
msgstr "當狀態在上和下之間切換時觸發"
|
||||
|
||||
#: src/lib/utils.ts:304
|
||||
msgid "Triggers when usage of any disk exceeds a threshold"
|
||||
msgstr "當任何磁碟的使用超過閾值時觸發"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx:320
|
||||
msgid "Updated in real time. Click on a system to view information."
|
||||
msgstr "實時更新。點擊系統查看信息。"
|
||||
|
||||
#: src/components/routes/system.tsx:253
|
||||
msgid "Uptime"
|
||||
msgstr "正常運行時間"
|
||||
|
||||
#: src/components/routes/system.tsx:494
|
||||
msgid "Usage"
|
||||
msgstr "使用"
|
||||
|
||||
#: src/components/routes/system.tsx:415
|
||||
msgid "Usage of root partition"
|
||||
msgstr "根分區的使用"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx:65
|
||||
#: src/components/charts/swap-chart.tsx:56
|
||||
msgid "Used"
|
||||
msgstr "已用"
|
||||
|
||||
#: src/components/login/auth-form.tsx:138
|
||||
msgid "username"
|
||||
msgstr "用戶名"
|
||||
|
||||
#: src/components/login/auth-form.tsx:131
|
||||
msgid "Username"
|
||||
msgstr "用戶名"
|
||||
|
||||
#: src/components/command-palette.tsx:143
|
||||
#: src/components/navbar.tsx:70
|
||||
msgid "Users"
|
||||
msgstr "用戶"
|
||||
|
||||
#: src/components/routes/system.tsx:603
|
||||
msgid "Waiting for enough records to display"
|
||||
msgstr "等待足夠的記錄以顯示"
|
||||
|
||||
#: src/components/routes/settings/general.tsx:48
|
||||
msgid "Want to help us make our translations even better? Check out <0>Crowdin</0> for more details."
|
||||
msgstr "想幫助我們改進翻譯嗎?查看<0>Crowdin</0>以獲取更多詳細信息。"
|
||||
|
||||
#: src/components/routes/settings/notifications.tsx:124
|
||||
msgid "Webhook / Push notifications"
|
||||
msgstr "Webhook / 推送通知"
|
||||
|
||||
#. Context is disk write
|
||||
#: src/components/charts/area-chart.tsx:55
|
||||
#: src/components/charts/area-chart.tsx:65
|
||||
msgid "Write"
|
||||
msgstr "寫入"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:61
|
||||
msgid "YAML Config"
|
||||
msgstr "YAML配置"
|
||||
|
||||
#: src/components/routes/settings/config-yaml.tsx:45
|
||||
msgid "YAML Configuration"
|
||||
msgstr "YAML配置"
|
||||
|
||||
#: src/components/routes/settings/layout.tsx:34
|
||||
msgid "Your user settings have been updated."
|
||||
msgstr "您的用戶設置已更新。"
|
||||
@@ -1,58 +1,24 @@
|
||||
import './index.css'
|
||||
import { Suspense, lazy, useEffect, StrictMode } from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import Home from './components/routes/home.tsx'
|
||||
import { ThemeProvider } from './components/theme-provider.tsx'
|
||||
import {
|
||||
$authenticated,
|
||||
$systems,
|
||||
pb,
|
||||
$publicKey,
|
||||
$hubVersion,
|
||||
$copyContent,
|
||||
} from './lib/stores.ts'
|
||||
import { ModeToggle } from './components/mode-toggle.tsx'
|
||||
import {
|
||||
cn,
|
||||
updateUserSettings,
|
||||
isAdmin,
|
||||
isReadOnlyUser,
|
||||
updateAlerts,
|
||||
updateFavicon,
|
||||
updateSystemList,
|
||||
} from './lib/utils.ts'
|
||||
import { buttonVariants } from './components/ui/button.tsx'
|
||||
import {
|
||||
DatabaseBackupIcon,
|
||||
LockKeyholeIcon,
|
||||
LogOutIcon,
|
||||
LogsIcon,
|
||||
ServerIcon,
|
||||
SettingsIcon,
|
||||
UserIcon,
|
||||
UsersIcon,
|
||||
} from 'lucide-react'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { Toaster } from './components/ui/toaster.tsx'
|
||||
import { Logo } from './components/logo.tsx'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuLabel,
|
||||
} from './components/ui/dropdown-menu.tsx'
|
||||
import { $router, Link } from './components/router.tsx'
|
||||
import SystemDetail from './components/routes/system.tsx'
|
||||
import { AddSystemButton } from './components/add-system.tsx'
|
||||
import "./index.css"
|
||||
// import { Suspense, lazy, useEffect, StrictMode } from "react"
|
||||
import { Suspense, lazy, useEffect } from "react"
|
||||
import ReactDOM from "react-dom/client"
|
||||
import Home from "./components/routes/home.tsx"
|
||||
import { ThemeProvider } from "./components/theme-provider.tsx"
|
||||
import { DirectionProvider } from "@radix-ui/react-direction"
|
||||
import { $authenticated, $systems, pb, $publicKey, $hubVersion, $copyContent, $direction } from "./lib/stores.ts"
|
||||
import { updateUserSettings, updateAlerts, updateFavicon, updateSystemList } from "./lib/utils.ts"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { Toaster } from "./components/ui/toaster.tsx"
|
||||
import { $router } from "./components/router.tsx"
|
||||
import SystemDetail from "./components/routes/system.tsx"
|
||||
import Navbar from "./components/navbar.tsx"
|
||||
import { I18nProvider } from "@lingui/react"
|
||||
import { i18n } from "@lingui/core"
|
||||
|
||||
// const ServerDetail = lazy(() => import('./components/routes/system.tsx'))
|
||||
const CommandPalette = lazy(() => import('./components/command-palette.tsx'))
|
||||
const LoginPage = lazy(() => import('./components/login/login.tsx'))
|
||||
const CopyToClipboardDialog = lazy(() => import('./components/copy-to-clipboard.tsx'))
|
||||
const Settings = lazy(() => import('./components/routes/settings/layout.tsx'))
|
||||
const LoginPage = lazy(() => import("./components/login/login.tsx"))
|
||||
const CopyToClipboardDialog = lazy(() => import("./components/copy-to-clipboard.tsx"))
|
||||
const Settings = lazy(() => import("./components/routes/settings/layout.tsx"))
|
||||
|
||||
const App = () => {
|
||||
const page = useStore($router)
|
||||
@@ -65,7 +31,7 @@ const App = () => {
|
||||
$authenticated.set(pb.authStore.isValid)
|
||||
})
|
||||
// get version / public key
|
||||
pb.send('/api/beszel/getkey', {}).then((data) => {
|
||||
pb.send("/api/beszel/getkey", {}).then((data) => {
|
||||
$publicKey.set(data.key)
|
||||
$hubVersion.set(data.v)
|
||||
})
|
||||
@@ -74,34 +40,34 @@ const App = () => {
|
||||
// get alerts after system list is loaded
|
||||
updateSystemList().then(updateAlerts)
|
||||
|
||||
return () => updateFavicon('favicon.svg')
|
||||
return () => updateFavicon("favicon.svg")
|
||||
}, [])
|
||||
|
||||
// update favicon
|
||||
useEffect(() => {
|
||||
if (!systems.length || !authenticated) {
|
||||
updateFavicon('favicon.svg')
|
||||
updateFavicon("favicon.svg")
|
||||
} else {
|
||||
let up = false
|
||||
for (const system of systems) {
|
||||
if (system.status === 'down') {
|
||||
updateFavicon('favicon-red.svg')
|
||||
if (system.status === "down") {
|
||||
updateFavicon("favicon-red.svg")
|
||||
return
|
||||
} else if (system.status === 'up') {
|
||||
} else if (system.status === "up") {
|
||||
up = true
|
||||
}
|
||||
}
|
||||
updateFavicon(up ? 'favicon-green.svg' : 'favicon.svg')
|
||||
updateFavicon(up ? "favicon-green.svg" : "favicon.svg")
|
||||
}
|
||||
}, [systems])
|
||||
|
||||
if (!page) {
|
||||
return <h1 className="text-3xl text-center my-14">404</h1>
|
||||
} else if (page.path === '/') {
|
||||
} else if (page.path === "/") {
|
||||
return <Home />
|
||||
} else if (page.route === 'server') {
|
||||
} else if (page.route === "server") {
|
||||
return <SystemDetail name={page.params.name} />
|
||||
} else if (page.route === 'settings') {
|
||||
} else if (page.route === "settings") {
|
||||
return (
|
||||
<Suspense>
|
||||
<Settings />
|
||||
@@ -113,113 +79,46 @@ const App = () => {
|
||||
const Layout = () => {
|
||||
const authenticated = useStore($authenticated)
|
||||
const copyContent = useStore($copyContent)
|
||||
const direction = useStore($direction)
|
||||
|
||||
if (!authenticated) {
|
||||
return (
|
||||
<Suspense>
|
||||
<LoginPage />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
useEffect(() => {
|
||||
document.documentElement.dir = direction
|
||||
}, [direction])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="container">
|
||||
<div className="flex items-center h-14 md:h-16 bg-card px-4 pr-3 sm:px-6 border bt-0 rounded-md my-4">
|
||||
<Link href="/" aria-label="Home" className={'p-2 pl-0'}>
|
||||
<Logo className="h-[1.15em] fill-foreground" />
|
||||
</Link>
|
||||
|
||||
<div className={'flex ml-auto items-center'}>
|
||||
<ModeToggle />
|
||||
<Link
|
||||
href="/settings/general"
|
||||
aria-label="Settings"
|
||||
className={cn('', buttonVariants({ variant: 'ghost', size: 'icon' }))}
|
||||
>
|
||||
<SettingsIcon className="h-[1.2rem] w-[1.2rem]" />
|
||||
</Link>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
aria-label="User Actions"
|
||||
className={cn('', buttonVariants({ variant: 'ghost', size: 'icon' }))}
|
||||
>
|
||||
<UserIcon className="h-[1.2rem] w-[1.2rem]" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align={isReadOnlyUser() ? 'end' : 'center'} className="min-w-44">
|
||||
<DropdownMenuLabel>{pb.authStore.model?.email}</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
{isAdmin() && (
|
||||
<>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href="/_/" target="_blank">
|
||||
<UsersIcon className="mr-2.5 h-4 w-4" />
|
||||
<span>Users</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href="/_/#/collections?collectionId=2hz5ncl8tizk5nx" target="_blank">
|
||||
<ServerIcon className="mr-2.5 h-4 w-4" />
|
||||
<span>Systems</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href="/_/#/logs" target="_blank">
|
||||
<LogsIcon className="mr-2.5 h-4 w-4" />
|
||||
<span>Logs</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href="/_/#/settings/backups" target="_blank">
|
||||
<DatabaseBackupIcon className="mr-2.5 h-4 w-4" />
|
||||
<span>Backups</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<a href="/_/#/settings/auth-providers" target="_blank">
|
||||
<LockKeyholeIcon className="mr-2.5 h-4 w-4" />
|
||||
<span>Auth providers</span>
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuItem onSelect={() => pb.authStore.clear()}>
|
||||
<LogOutIcon className="mr-2.5 h-4 w-4" />
|
||||
<span>Log out</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<AddSystemButton className="ml-2" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="container mb-14 relative">
|
||||
<App />
|
||||
<DirectionProvider dir={direction}>
|
||||
{!authenticated ? (
|
||||
<Suspense>
|
||||
<CommandPalette />
|
||||
<LoginPage />
|
||||
</Suspense>
|
||||
{copyContent && (
|
||||
<Suspense>
|
||||
<CopyToClipboardDialog content={copyContent} />
|
||||
</Suspense>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="container">
|
||||
<Navbar />
|
||||
</div>
|
||||
<div className="container mb-14 relative">
|
||||
<App />
|
||||
{copyContent && (
|
||||
<Suspense>
|
||||
<CopyToClipboardDialog content={copyContent} />
|
||||
</Suspense>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</DirectionProvider>
|
||||
)
|
||||
}
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('app')!).render(
|
||||
ReactDOM.createRoot(document.getElementById("app")!).render(
|
||||
// strict mode in dev mounts / unmounts components twice
|
||||
// and breaks the clipboard dialog
|
||||
//<StrictMode>
|
||||
<ThemeProvider>
|
||||
<Layout />
|
||||
<Toaster />
|
||||
</ThemeProvider>
|
||||
<I18nProvider i18n={i18n}>
|
||||
<ThemeProvider>
|
||||
<Layout />
|
||||
<Toaster />
|
||||
</ThemeProvider>
|
||||
</I18nProvider>
|
||||
//</StrictMode>
|
||||
)
|
||||
|
||||
22
beszel/site/src/types.d.ts
vendored
22
beszel/site/src/types.d.ts
vendored
@@ -1,9 +1,9 @@
|
||||
import { RecordModel } from 'pocketbase'
|
||||
import { RecordModel } from "pocketbase"
|
||||
|
||||
export interface SystemRecord extends RecordModel {
|
||||
name: string
|
||||
host: string
|
||||
status: 'up' | 'down' | 'paused' | 'pending'
|
||||
status: "up" | "down" | "paused" | "pending"
|
||||
port: string
|
||||
info: SystemInfo
|
||||
v: string
|
||||
@@ -132,13 +132,13 @@ export interface AlertRecord extends RecordModel {
|
||||
// user: string
|
||||
}
|
||||
|
||||
export type ChartTimes = '1h' | '12h' | '24h' | '1w' | '30d'
|
||||
export type ChartTimes = "1h" | "12h" | "24h" | "1w" | "30d"
|
||||
|
||||
export interface ChartTimeData {
|
||||
[key: string]: {
|
||||
type: '1m' | '10m' | '20m' | '120m' | '480m'
|
||||
type: "1m" | "10m" | "20m" | "120m" | "480m"
|
||||
expectedInterval: number
|
||||
label: string
|
||||
label: () => string
|
||||
ticks?: number
|
||||
format: (timestamp: string) => string
|
||||
getOffset: (endTime: Date) => Date
|
||||
@@ -155,13 +155,23 @@ export type UserSettings = {
|
||||
type ChartDataContainer = {
|
||||
created: number | null
|
||||
} & {
|
||||
[key: string]: key extends 'created' ? never : ContainerStats
|
||||
[key: string]: key extends "created" ? never : ContainerStats
|
||||
}
|
||||
|
||||
export interface ChartData {
|
||||
systemStats: SystemStatsRecord[]
|
||||
containerData: ChartDataContainer[]
|
||||
orientation: "right" | "left"
|
||||
ticks: number[]
|
||||
domain: number[]
|
||||
chartTime: ChartTimes
|
||||
}
|
||||
|
||||
interface AlertInfo {
|
||||
name: () => string
|
||||
unit: string
|
||||
icon: any
|
||||
desc: () => string
|
||||
single?: boolean
|
||||
max?: number
|
||||
}
|
||||
|
||||
@@ -1,103 +1,100 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ['class'],
|
||||
content: [
|
||||
'./pages/**/*.{ts,tsx}',
|
||||
'./components/**/*.{ts,tsx}',
|
||||
'./app/**/*.{ts,tsx}',
|
||||
'./src/**/*.{ts,tsx}',
|
||||
],
|
||||
prefix: '',
|
||||
darkMode: ["class"],
|
||||
content: ["./pages/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}", "./app/**/*.{ts,tsx}", "./src/**/*.{ts,tsx}"],
|
||||
prefix: "",
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: '1rem',
|
||||
padding: "1rem",
|
||||
screens: {
|
||||
'2xl': '1400px',
|
||||
"2xl": "1400px",
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: 'Inter, sans-serif',
|
||||
sans: "Inter, sans-serif",
|
||||
// body: ['Inter', 'sans-serif'],
|
||||
// display: ['Inter', 'sans-serif'],
|
||||
},
|
||||
screens: {
|
||||
xs: '425px',
|
||||
xs: "425px",
|
||||
450: "450px",
|
||||
},
|
||||
colors: {
|
||||
green: {
|
||||
50: '#EBF9F0',
|
||||
100: '#D8F3E1',
|
||||
200: '#ADE6C0',
|
||||
300: '#85DBA2',
|
||||
400: '#5ACE81',
|
||||
500: '#38BB63',
|
||||
600: '#2D954F',
|
||||
700: '#22723D',
|
||||
800: '#164B28',
|
||||
900: '#0C2715',
|
||||
950: '#06140A',
|
||||
50: "#EBF9F0",
|
||||
100: "#D8F3E1",
|
||||
200: "#ADE6C0",
|
||||
300: "#85DBA2",
|
||||
400: "#5ACE81",
|
||||
500: "#38BB63",
|
||||
600: "#2D954F",
|
||||
700: "#22723D",
|
||||
800: "#164B28",
|
||||
900: "#0C2715",
|
||||
950: "#06140A",
|
||||
},
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
ring: "hsl(var(--ring))",
|
||||
background: "hsl(var(--background))",
|
||||
foreground: "hsl(var(--foreground))",
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))',
|
||||
DEFAULT: "hsl(var(--primary))",
|
||||
foreground: "hsl(var(--primary-foreground))",
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))',
|
||||
DEFAULT: "hsl(var(--secondary))",
|
||||
foreground: "hsl(var(--secondary-foreground))",
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))',
|
||||
DEFAULT: "hsl(var(--destructive))",
|
||||
foreground: "hsl(var(--destructive-foreground))",
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))',
|
||||
DEFAULT: "hsl(var(--muted))",
|
||||
foreground: "hsl(var(--muted-foreground))",
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))',
|
||||
DEFAULT: "hsl(var(--accent))",
|
||||
foreground: "hsl(var(--accent-foreground))",
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: 'hsl(var(--popover))',
|
||||
foreground: 'hsl(var(--popover-foreground))',
|
||||
DEFAULT: "hsl(var(--popover))",
|
||||
foreground: "hsl(var(--popover-foreground))",
|
||||
},
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))',
|
||||
DEFAULT: "hsl(var(--card))",
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
sm: 'calc(var(--radius) - 4px)',
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
sm: "calc(var(--radius) - 4px)",
|
||||
},
|
||||
keyframes: {
|
||||
'accordion-down': {
|
||||
from: { height: '0' },
|
||||
to: { height: 'var(--radix-accordion-content-height)' },
|
||||
"accordion-down": {
|
||||
from: { height: "0" },
|
||||
to: { height: "var(--radix-accordion-content-height)" },
|
||||
},
|
||||
'accordion-up': {
|
||||
from: { height: 'var(--radix-accordion-content-height)' },
|
||||
to: { height: '0' },
|
||||
"accordion-up": {
|
||||
from: { height: "var(--radix-accordion-content-height)" },
|
||||
to: { height: "0" },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||
'accordion-up': 'accordion-up 0.2s ease-out',
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
require('tailwindcss-animate'),
|
||||
require("tailwindcss-animate"),
|
||||
require("tailwindcss-rtl"),
|
||||
function ({ addVariant }) {
|
||||
addVariant('light', '.light &')
|
||||
addVariant("light", ".light &")
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user