mirror of
https://github.com/fankes/beszel.git
synced 2025-10-19 17:59:28 +08:00
rtl layout progress and updates to arabic translations
This commit is contained in:
Binary file not shown.
@@ -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" />
|
||||
|
19
beszel/site/package-lock.json
generated
19
beszel/site/package-lock.json
generated
@@ -14,6 +14,7 @@
|
||||
"@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",
|
||||
@@ -31,7 +32,6 @@
|
||||
"cmdk": "^1.0.0",
|
||||
"d3-time": "^3.1.0",
|
||||
"i18next": "^23.16.4",
|
||||
"i18next-browser-languagedetector": "^8.0.0",
|
||||
"lucide-react": "^0.452.0",
|
||||
"nanostores": "^0.11.3",
|
||||
"pocketbase": "^0.21.5",
|
||||
@@ -50,6 +50,7 @@
|
||||
"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"
|
||||
},
|
||||
@@ -4153,15 +4154,6 @@
|
||||
"@babel/runtime": "^7.23.2"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next-browser-languagedetector": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz",
|
||||
"integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.23.2"
|
||||
}
|
||||
},
|
||||
"node_modules/internmap": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
|
||||
@@ -5344,6 +5336,13 @@
|
||||
"tailwindcss": ">=3.0.0 || insiders"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss-rtl": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss-rtl/-/tailwindcss-rtl-0.9.0.tgz",
|
||||
"integrity": "sha512-y7yC8QXjluDBEFMSX33tV6xMYrf0B3sa+tOB5JSQb6/G6laBU313a+Z+qxu55M1Qyn8tDMttjomsA8IsJD+k+w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tailwindcss/node_modules/picocolors": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
|
||||
|
@@ -15,6 +15,7 @@
|
||||
"@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",
|
||||
@@ -50,6 +51,7 @@
|
||||
"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"
|
||||
},
|
||||
|
@@ -41,8 +41,7 @@ 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) {
|
||||
@@ -73,7 +72,7 @@ export function AddSystemButton({ className }: { className?: string }) {
|
||||
variant="outline"
|
||||
className={cn("flex gap-1 max-xs:h-[2.4rem]", className, isReadOnlyUser() && "hidden")}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4 -ml-1" />
|
||||
<PlusIcon className="h-4 w-4 -ms-1" />
|
||||
{t("add")}
|
||||
<span className="hidden sm:inline">{t("system")}</span>
|
||||
</Button>
|
||||
@@ -104,31 +103,31 @@ export function AddSystemButton({ className }: { className?: string }) {
|
||||
<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">
|
||||
<Label htmlFor="name" className="text-end">
|
||||
{t("add_system.name")}
|
||||
</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-right">
|
||||
<Label htmlFor="host" className="text-end">
|
||||
{t("add_system.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">
|
||||
<Label htmlFor="port" className="text-end">
|
||||
{t("add_system.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">
|
||||
<Label htmlFor="pkey" className="text-end whitespace-pre">
|
||||
{t("add_system.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"
|
||||
"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}>
|
||||
@@ -137,7 +136,7 @@ export function AddSystemButton({ className }: { className?: string }) {
|
||||
<Button
|
||||
type="button"
|
||||
variant={"link"}
|
||||
className="absolute right-0"
|
||||
className="absolute end-0"
|
||||
onClick={() => copyToClipboard(publicKey)}
|
||||
>
|
||||
<Copy className="h-4 w-4 " />
|
||||
@@ -152,7 +151,7 @@ export function AddSystemButton({ className }: { className?: string }) {
|
||||
</div>
|
||||
{/* Docker */}
|
||||
<TabsContent value="docker">
|
||||
<DialogFooter className="flex justify-end gap-2 sm:w-[calc(100%+20px)] sm:-ml-[20px]">
|
||||
<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)}>
|
||||
{t("copy")} docker compose
|
||||
</Button>
|
||||
@@ -161,7 +160,7 @@ export function AddSystemButton({ className }: { className?: string }) {
|
||||
</TabsContent>
|
||||
{/* Binary */}
|
||||
<TabsContent value="binary">
|
||||
<DialogFooter className="flex justify-end gap-2 sm:w-[calc(100%+20px)] sm:-ml-[20px]">
|
||||
<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)}>
|
||||
{t("copy")} linux {t("add_system.command")}
|
||||
</Button>
|
||||
|
@@ -78,11 +78,11 @@ function TheContent({
|
||||
<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" />
|
||||
<GlobeIcon className="me-1.5 h-3.5 w-3.5" />
|
||||
{t("all_systems")}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
@@ -59,7 +59,7 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
|
||||
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>
|
||||
@@ -76,7 +76,7 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<LayoutDashboard className="mr-2 h-4 w-4" />
|
||||
<LayoutDashboard className="me-2 h-4 w-4" />
|
||||
<span>{t("command.dashboard")}</span>
|
||||
<CommandShortcut>{t("command.page")}</CommandShortcut>
|
||||
</CommandItem>
|
||||
@@ -86,7 +86,7 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<SettingsIcon className="mr-2 h-4 w-4" />
|
||||
<SettingsIcon className="me-2 h-4 w-4" />
|
||||
<span>{t("settings.settings")}</span>
|
||||
<CommandShortcut>{t("settings.settings")}</CommandShortcut>
|
||||
</CommandItem>
|
||||
@@ -97,7 +97,7 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<MailIcon className="mr-2 h-4 w-4" />
|
||||
<MailIcon className="me-2 h-4 w-4" />
|
||||
<span>{t("settings.notifications.title")}</span>
|
||||
<CommandShortcut>{t("settings.settings")}</CommandShortcut>
|
||||
</CommandItem>
|
||||
@@ -107,7 +107,7 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
|
||||
window.location.href = "https://github.com/henrygd/beszel/blob/main/readme.md"
|
||||
}}
|
||||
>
|
||||
<Github className="mr-2 h-4 w-4" />
|
||||
<Github className="me-2 h-4 w-4" />
|
||||
<span>{t("command.documentation")}</span>
|
||||
<CommandShortcut>GitHub</CommandShortcut>
|
||||
</CommandItem>
|
||||
@@ -123,7 +123,7 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
|
||||
window.open("/_/", "_blank")
|
||||
}}
|
||||
>
|
||||
<UsersIcon className="mr-2 h-4 w-4" />
|
||||
<UsersIcon className="me-2 h-4 w-4" />
|
||||
<span>{t("user_dm.users")}</span>
|
||||
<CommandShortcut>{t("command.admin")}</CommandShortcut>
|
||||
</CommandItem>
|
||||
@@ -133,7 +133,7 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
|
||||
window.open("/_/#/logs", "_blank")
|
||||
}}
|
||||
>
|
||||
<LogsIcon className="mr-2 h-4 w-4" />
|
||||
<LogsIcon className="me-2 h-4 w-4" />
|
||||
<span>{t("user_dm.logs")}</span>
|
||||
<CommandShortcut>{t("command.admin")}</CommandShortcut>
|
||||
</CommandItem>
|
||||
@@ -143,7 +143,7 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
|
||||
window.open("/_/#/settings/backups", "_blank")
|
||||
}}
|
||||
>
|
||||
<DatabaseBackupIcon className="mr-2 h-4 w-4" />
|
||||
<DatabaseBackupIcon className="me-2 h-4 w-4" />
|
||||
<span>{t("user_dm.backups")}</span>
|
||||
<CommandShortcut>{t("command.admin")}</CommandShortcut>
|
||||
</CommandItem>
|
||||
@@ -154,7 +154,7 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
|
||||
window.open("/_/#/settings/auth-providers", "_blank")
|
||||
}}
|
||||
>
|
||||
<LockKeyholeIcon className="mr-2 h-4 w-4" />
|
||||
<LockKeyholeIcon className="me-2 h-4 w-4" />
|
||||
<span>{t("user_dm.auth_providers")}</span>
|
||||
<CommandShortcut>{t("command.admin")}</CommandShortcut>
|
||||
</CommandItem>
|
||||
@@ -165,7 +165,7 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
|
||||
window.open("/_/#/settings/mail", "_blank")
|
||||
}}
|
||||
>
|
||||
<MailIcon className="mr-2 h-4 w-4" />
|
||||
<MailIcon className="me-2 h-4 w-4" />
|
||||
<span>{t("command.SMTP_settings")}</span>
|
||||
<CommandShortcut>{t("command.admin")}</CommandShortcut>
|
||||
</CommandItem>
|
||||
|
@@ -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>
|
||||
)
|
||||
}
|
||||
|
@@ -38,13 +38,12 @@ export default function Navbar() {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<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.15rem] md:h-[1.25em] fill-foreground" />
|
||||
<Link href="/" aria-label="Home" className="p-2 pl-0 me-3">
|
||||
<Logo className="h-[1.1rem] md:h-5 fill-foreground" />
|
||||
</Link>
|
||||
|
||||
<SearchButton t={t} />
|
||||
|
||||
<div className={"flex ml-auto items-center"}>
|
||||
<div className="flex items-center ms-auto">
|
||||
<LangToggle />
|
||||
<ModeToggle />
|
||||
<Link
|
||||
@@ -106,7 +105,7 @@ export default function Navbar() {
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<AddSystemButton className="ml-2" />
|
||||
<AddSystemButton className="ms-2" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -125,14 +124,14 @@ function SearchButton({ t }: { t: TFunction<"translation", undefined> }) {
|
||||
<>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="hidden md:block text-sm text-muted-foreground px-4 mx-3"
|
||||
className="hidden md:block text-sm text-muted-foreground px-4"
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<SearchIcon className="mr-1.5 h-4 w-4" />
|
||||
<SearchIcon className="me-1.5 h-4 w-4" />
|
||||
{t("search")}
|
||||
<span className="sr-only">{t("search")}</span>
|
||||
<span className="flex items-center ml-3.5">
|
||||
<span className="flex items-center ms-3.5">
|
||||
<Kbd>{isMac ? "⌘" : "Ctrl"}</Kbd>
|
||||
<Kbd>K</Kbd>
|
||||
</span>
|
||||
|
@@ -110,7 +110,7 @@ export default function () {
|
||||
<Input
|
||||
placeholder={t("filter")}
|
||||
onChange={(e) => setFilter(e.target.value)}
|
||||
className="w-full md:w-56 lg:w-72 ml-auto px-4"
|
||||
className="w-full md:w-56 lg:w-72 ms-auto px-4"
|
||||
/>
|
||||
</div>
|
||||
</CardHeader>
|
||||
@@ -122,7 +122,7 @@ export default function () {
|
||||
</Card>
|
||||
|
||||
{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"
|
||||
|
@@ -66,6 +66,7 @@ export default function ConfigYaml() {
|
||||
</div>
|
||||
{configContent && (
|
||||
<Textarea
|
||||
dir="ltr"
|
||||
autoFocus
|
||||
defaultValue={configContent}
|
||||
spellCheck="false"
|
||||
|
@@ -78,8 +78,12 @@ function CellFormatter(info: CellContext<SystemRecord, unknown>) {
|
||||
|
||||
function sortableHeader(column: Column<SystemRecord, unknown>, name: string, Icon: any, hideSortIcon = false) {
|
||||
return (
|
||||
<Button variant="ghost" className="h-9 px-3" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
|
||||
<Icon className="mr-2 h-4 w-4" />
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-9 px-3 rtl:ml-auto flex"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||
>
|
||||
<Icon className="me-2 h-4 w-4" />
|
||||
{name}
|
||||
{!hideSortIcon && <ArrowUpDownIcon className="ml-2 h-4 w-4" />}
|
||||
</Button>
|
||||
@@ -110,7 +114,7 @@ export default function SystemsTable({ filter }: { filter?: string }) {
|
||||
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",
|
||||
@@ -176,7 +180,7 @@ export default function SystemsTable({ filter }: { filter?: string }) {
|
||||
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" }}
|
||||
|
@@ -44,12 +44,12 @@ 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"
|
||||
|
||||
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"
|
||||
|
||||
|
@@ -40,7 +40,7 @@ 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(
|
||||
@@ -115,7 +115,7 @@ 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"
|
||||
|
||||
|
@@ -42,7 +42,7 @@ const DialogContent = React.forwardRef<
|
||||
{...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,12 +52,12 @@ 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"
|
||||
|
||||
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"
|
||||
|
||||
|
@@ -17,7 +17,7 @@ const Switch = React.forwardRef<
|
||||
>
|
||||
<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"
|
||||
"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>
|
||||
|
@@ -46,7 +46,7 @@ const TableHead = React.forwardRef<HTMLTableCellElement, React.ThHTMLAttributes<
|
||||
<th
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
||||
"h-12 px-4 text-start align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import i18n from "i18next"
|
||||
import { initReactI18next } from "react-i18next"
|
||||
import enTranslations from "../locales/en/translation.json"
|
||||
import { $direction } from "./stores"
|
||||
|
||||
// Custom language detector to use localStorage
|
||||
const languageDetector: any = {
|
||||
@@ -62,6 +63,9 @@ export async function setLang(locale: string) {
|
||||
const messages = await loadMessages(locale)
|
||||
i18n.addResourceBundle(locale, "translation", messages)
|
||||
await i18n.changeLanguage(locale)
|
||||
const dir = i18n.dir(locale)
|
||||
document.dir = dir
|
||||
$direction.set(dir)
|
||||
}
|
||||
|
||||
// Initialize with detected/saved language
|
||||
|
@@ -1,4 +1,8 @@
|
||||
[
|
||||
{
|
||||
"lang": "ar",
|
||||
"label": "العربية"
|
||||
},
|
||||
{
|
||||
"lang": "de",
|
||||
"label": "Deutsch"
|
||||
|
@@ -39,3 +39,6 @@ export const $containerFilter = atom("")
|
||||
|
||||
/** Fallback copy to clipboard dialog content */
|
||||
export const $copyContent = atom("")
|
||||
|
||||
/** Direction for localization */
|
||||
export const $direction = atom<"ltr" | "rtl">("ltr")
|
||||
|
@@ -1,227 +1,227 @@
|
||||
{
|
||||
"all_systems": "جميع الأنظمة",
|
||||
"filter": "تصفية...",
|
||||
"copy": "نسخ",
|
||||
"add": "إضافة",
|
||||
"search": "بحث",
|
||||
"system": "نظام",
|
||||
"systems": "الأنظمة",
|
||||
"cancel": "إلغاء",
|
||||
"continue": "متابعة",
|
||||
"minutes_zero": "",
|
||||
"minutes_one": "{{count}} دقيقة",
|
||||
"minutes_two": "",
|
||||
"minutes_few": "",
|
||||
"minutes_many": "",
|
||||
"minutes_other": "{{count}} دقائق",
|
||||
"hours_zero": "",
|
||||
"hours_one": "{{count}} ساعة",
|
||||
"hours_two": "",
|
||||
"hours_few": "",
|
||||
"hours_many": "",
|
||||
"hours_other": "{{count}} ساعات",
|
||||
"days_zero": "",
|
||||
"days_one": "",
|
||||
"days_two": "",
|
||||
"days_few": "",
|
||||
"days_many": "",
|
||||
"days_other": "{{count}} أيام",
|
||||
"weeks_zero": "",
|
||||
"weeks_one": "{{count}} أسبوع",
|
||||
"weeks_two": "",
|
||||
"weeks_few": "",
|
||||
"weeks_many": "",
|
||||
"weeks_other": "",
|
||||
"home": {
|
||||
"active_alerts": "التنبيهات النشطة",
|
||||
"active_des": "يتجاوز {{value}}{{unit}} في آخر ",
|
||||
"subtitle": "يتم التحديث في الوقت الفعلي. انقر على نظام لعرض المعلومات."
|
||||
},
|
||||
"systems_table": {
|
||||
"system": "النظام",
|
||||
"memory": "الذاكرة",
|
||||
"cpu": "المعالج",
|
||||
"disk": "القرص",
|
||||
"net": "الشبكة",
|
||||
"agent": "الوكيل",
|
||||
"no_systems_found": "لم يتم العثور على أنظمة.",
|
||||
"open_menu": "فتح القائمة",
|
||||
"resume": "استئناف",
|
||||
"pause": "إيقاف مؤقت",
|
||||
"copy_host": "نسخ المضيف",
|
||||
"delete": "حذف",
|
||||
"delete_confirm": "هل أنت متأكد أنك تريد حذف {{name}}؟",
|
||||
"delete_confirm_des_1": "لا يمكن التراجع عن هذا الإجراء. سيؤدي هذا إلى حذف جميع السجلات الحالية نهائياً لـ",
|
||||
"delete_confirm_des_2": "من قاعدة البيانات."
|
||||
},
|
||||
"alerts": {
|
||||
"title": "التنبيهات",
|
||||
"subtitle_1": "راجع",
|
||||
"notification_settings": "إعدادات الإشعارات",
|
||||
"subtitle_2": "لتكوين كيفية استلام التنبيهات.",
|
||||
"overwrite_existing_alerts": "استبدال التنبيهات الموجودة",
|
||||
"info": {
|
||||
"status": "الحالة",
|
||||
"status_des": "يتم التشغيل عند تبديل الحالة بين متصل ومنقطع.",
|
||||
"cpu_usage": "استخدام المعالج",
|
||||
"cpu_usage_des": "يتم التشغيل عندما يتجاوز استخدام المعالج الحد.",
|
||||
"memory_usage": "استخدام الذاكرة",
|
||||
"memory_usage_des": "يتم التشغيل عندما يتجاوز استخدام الذاكرة الحد.",
|
||||
"disk_usage": "استخدام القرص",
|
||||
"disk_usage_des": "يتم التشغيل عندما يتجاوز استخدام أي قرص الحد.",
|
||||
"bandwidth": "النطاق الترددي",
|
||||
"bandwidth_des": "يتم التشغيل عندما يتجاوز استخدام الشبكة الحد.",
|
||||
"temperature": "",
|
||||
"temperature_des": ""
|
||||
},
|
||||
"average_exceeds": "المتوسط يتجاوز",
|
||||
"for": "لمدة"
|
||||
},
|
||||
"settings": {
|
||||
"settings": "الإعدادات",
|
||||
"subtitle": "إدارة تفضيلات العرض والإشعارات.",
|
||||
"save_settings": "حفظ الإعدادات",
|
||||
"export_configuration": "تصدير الإعدادات",
|
||||
"general": {
|
||||
"title": "عام",
|
||||
"subtitle": "تغيير خيارات التطبيق العامة.",
|
||||
"language": {
|
||||
"title": "اللغة",
|
||||
"subtitle_1": "هل تريد مساعدتنا في تحسين ترجماتنا؟ راجع",
|
||||
"subtitle_2": "للمزيد من التفاصيل.",
|
||||
"preferred_language": "اللغة المفضلة"
|
||||
},
|
||||
"chart_options": {
|
||||
"title": "خيارات المخطط",
|
||||
"subtitle": "ضبط خيارات عرض المخططات.",
|
||||
"default_time_period": "الفترة الزمنية الافتراضية",
|
||||
"default_time_period_des": "يحدد النطاق الزمني الافتراضي للمخططات عند عرض النظام."
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"title": "الإشعارات",
|
||||
"subtitle_1": "تكوين كيفية استلام إشعارات التنبيه.",
|
||||
"subtitle_2": "هل تبحث عن مكان إنشاء التنبيهات؟ انقر على رمز الجرس",
|
||||
"subtitle_3": "في جدول الأنظمة.",
|
||||
"email": {
|
||||
"title": "إشعارات البريد الإلكتروني",
|
||||
"please": "الرجاء",
|
||||
"configure_an_SMTP_server": "تكوين خادم SMTP",
|
||||
"to_ensure_alerts_are_delivered": "لضمان تسليم التنبيهات.",
|
||||
"to_email_s": "إلى البريد الإلكتروني",
|
||||
"enter_email_address": "أدخل عنوان البريد الإلكتروني...",
|
||||
"des": "احفظ العنوان باستخدام مفتاح الإدخال أو الفاصلة. اتركه فاغاً لتعطيل إشعارات البريد الإلكتروني."
|
||||
},
|
||||
"webhook_push": {
|
||||
"title": "إشعارات Webhook / Push",
|
||||
"des_1": "يستخدم Beszel",
|
||||
"des_2": "للتكامل مع خدمات الإشعارات الشائعة.",
|
||||
"add_url": "إضافة URL"
|
||||
}
|
||||
},
|
||||
"yaml_config": {
|
||||
"short_title": "تكوين YAML",
|
||||
"title": "تكوين YAML",
|
||||
"subtitle": "تصدير تكوين النظام الحالي.",
|
||||
"des_1": "يستخدم النظام",
|
||||
"des_2": "ملف تكوين لإدارة البيانات",
|
||||
"des_3": "عند كل إعادة تشغيل، سيتم تحديث الأنظمة في قاعدة البيانات لتطابق الأنظمة المحددة في الملف.",
|
||||
"alert": {
|
||||
"title": "تحذير - احتمال فقدان البيانات",
|
||||
"des_1": "الأنظمة الموجودة غير المحددة في",
|
||||
"des_2": "سيتم حذفها. يرجى النسخ الاحتياطي بانتظام."
|
||||
}
|
||||
},
|
||||
"language": "اللغة"
|
||||
},
|
||||
"user_dm": {
|
||||
"users": "المستخدمون",
|
||||
"logs": "السجلات",
|
||||
"backups": "النسخ الاحتياطي",
|
||||
"auth_providers": "مزودو المصادقة",
|
||||
"log_out": "تسجيل الخروج"
|
||||
},
|
||||
"themes": {
|
||||
"toggle_theme": "تبديل السمة",
|
||||
"light": "فاتح",
|
||||
"dark": "داكن",
|
||||
"system": "النظام"
|
||||
},
|
||||
"add_system": {
|
||||
"add_new_system": "إضافة نظام جديد",
|
||||
"binary": "الملف الثنائي",
|
||||
"dialog_des_1": "يجب تشغيل العميل على الخادم للاتصال. انسخ",
|
||||
"dialog_des_2": "إلى الخادم المستهدف للتثبيت.",
|
||||
"name": "الاسم",
|
||||
"host_ip": "المضيف/IP",
|
||||
"port": "المنفذ",
|
||||
"key": "المفتاح العام",
|
||||
"click_to_copy": "انقر للنسخ",
|
||||
"command": "الأمر",
|
||||
"add_system": "إضافة نظام"
|
||||
},
|
||||
"command": {
|
||||
"search": "البحث في الإعدادات أو الأنظمة...",
|
||||
"pages_settings": "الصفحات / الإعدادات",
|
||||
"dashboard": "لوحة التحكم",
|
||||
"documentation": "التوثيق",
|
||||
"SMTP_settings": "إعدادات SMTP",
|
||||
"page": "الصفحة",
|
||||
"admin": "المسؤول"
|
||||
},
|
||||
"monitor": {
|
||||
"toggle_grid": "تبديل الشبكة",
|
||||
"average": "المتوسط",
|
||||
"max_1_min": "أقصى 1 دقيقة",
|
||||
"total_cpu_usage": "إجمالي استخدام المعالج",
|
||||
"cpu_des": "استخدام المعالج على مستوى النظام",
|
||||
"docker_cpu_usage": "استخدام معالج Docker",
|
||||
"docker_cpu_des": "متوسط استخدام المعالج للحاويات",
|
||||
"total_memory_usage": "إجمالي استخدام الذاكرة",
|
||||
"memory_des": "الاستخدام الدقيق في وقت التسجيل",
|
||||
"docker_memory_usage": "استخدام ذاكرة Docker",
|
||||
"docker_memory_des": "استخدام الذاكرة لحاويات Docker",
|
||||
"disk_space": "مساحة القرص",
|
||||
"disk_des": "استخدام القسم الجذر",
|
||||
"disk_io": "إدخال/إخراج القرص",
|
||||
"disk_io_des": "معدل نقل نظام الملفات الجذر",
|
||||
"bandwidth": "النطاق الترددي",
|
||||
"bandwidth_des": "حركة الشبكة للواجهات العامة",
|
||||
"docker_network_io": "إدخال/إخراج شبكة Docker",
|
||||
"docker_network_io_des": "حركة الشبكة لحاويات Docker",
|
||||
"swap_usage": "استخدام المبادلة",
|
||||
"swap_des": "مساحة المبادلة المستخدمة من قبل النظام",
|
||||
"temperature": "درجة الحرارة",
|
||||
"temperature_des": "درجات حرارة مستشعرات النظام",
|
||||
"usage": "الاستخدام",
|
||||
"disk_usage_of": "استخدام القرص لـ",
|
||||
"throughput_of": "معدل نقل",
|
||||
"waiting_for": "في انتظار سجلات كافية للعرض",
|
||||
"cache_buffers": "ذاكرة التخزين المؤقت / المخازن المؤقتة",
|
||||
"read": "قراءة",
|
||||
"write": "كتابة",
|
||||
"sent": "مرسل",
|
||||
"received": "مستلم",
|
||||
"used": "مستخدم"
|
||||
},
|
||||
"auth": {
|
||||
"login": "الرجاء تسجيل الدخول إلى حسابك",
|
||||
"reset": "أدخل البريد الإلكتروني لإعادة تعيين كلمة المرور",
|
||||
"create": "الرجاء إنشاء حساب مسؤول",
|
||||
"create_account": "إنشاء حساب",
|
||||
"sign_in": "تسجيل الدخول",
|
||||
"openid_des": "يدعم Beszel OpenID Connect والعديد من مزودي مصادقة OAuth2.",
|
||||
"please_view_the": "الرجاء مراجعة",
|
||||
"for_instructions": "للتعليمات.",
|
||||
"forgot_password": "نسيت كلمة المرور؟",
|
||||
"reset_password": "إعادة تعيين كلمة المرور",
|
||||
"command_line_instructions": "تعليمات سطر الأوامر",
|
||||
"command_1": "إذا فقدت كلمة مرور حساب المسؤول، يمكنك إعادة تعيينها باستخدام الأمر التالي.",
|
||||
"command_2": "ثم قم بتسجيل الدخول إلى الخلفية وإعادة تعيين كلمة مرور حساب المستخدم في جدول المستخدمين."
|
||||
},
|
||||
"clipboard": {
|
||||
"copied": "تم النسخ إلى الحافظة",
|
||||
"title": "نسخ النص",
|
||||
"des": "النسخ التلقائي يتطلب سياق آمن."
|
||||
}
|
||||
"all_systems": "جميع الأنظمة",
|
||||
"filter": "تصفية...",
|
||||
"copy": "نسخ",
|
||||
"add": "إضافة",
|
||||
"search": "بحث",
|
||||
"system": "نظام",
|
||||
"systems": "الأنظمة",
|
||||
"cancel": "إلغاء",
|
||||
"continue": "متابعة",
|
||||
"minutes_zero": "٠ دقائق",
|
||||
"minutes_one": "{{count}} دقيقة",
|
||||
"minutes_two": "{{count}} دقيقتان",
|
||||
"minutes_few": "{{count}} دقائق",
|
||||
"minutes_many": "{{count}} دقيقة",
|
||||
"minutes_other": "{{count}} دقائق",
|
||||
"hours_zero": "٠ ساعات",
|
||||
"hours_one": "{{count}} ساعة",
|
||||
"hours_two": "{{count}} ساعتان",
|
||||
"hours_few": "{{count}} ساعات",
|
||||
"hours_many": "{{count}} ساعة",
|
||||
"hours_other": "{{count}} ساعات",
|
||||
"days_zero": "٠ أيام",
|
||||
"days_one": "{{count}} يوم",
|
||||
"days_two": "{{count}} يومان",
|
||||
"days_few": "{{count}} أيام",
|
||||
"days_many": "{{count}} يومًا",
|
||||
"days_other": "{{count}} أيام",
|
||||
"weeks_zero": "٠ أسابيع",
|
||||
"weeks_one": "{{count}} أسبوع",
|
||||
"weeks_two": "{{count}} أسبوعان",
|
||||
"weeks_few": "{{count}} أسابيع",
|
||||
"weeks_many": "{{count}} أسبوعًا",
|
||||
"weeks_other": "{{count}} أسابيع",
|
||||
"home": {
|
||||
"active_alerts": "التنبيهات النشطة",
|
||||
"active_des": "يتجاوز {{value}}{{unit}} في آخر ",
|
||||
"subtitle": "يتم التحديث في الوقت الفعلي. انقر على نظام لعرض المعلومات."
|
||||
},
|
||||
"systems_table": {
|
||||
"system": "النظام",
|
||||
"memory": "الذاكرة",
|
||||
"cpu": "المعالج",
|
||||
"disk": "القرص",
|
||||
"net": "الشبكة",
|
||||
"agent": "الوكيل",
|
||||
"no_systems_found": "لم يتم العثور على أنظمة.",
|
||||
"open_menu": "فتح القائمة",
|
||||
"resume": "استئناف",
|
||||
"pause": "إيقاف مؤقت",
|
||||
"copy_host": "نسخ المضيف",
|
||||
"delete": "حذف",
|
||||
"delete_confirm": "هل أنت متأكد أنك تريد حذف {{name}}؟",
|
||||
"delete_confirm_des_1": "لا يمكن التراجع عن هذا الإجراء. سيؤدي هذا إلى حذف جميع السجلات الحالية نهائياً لـ",
|
||||
"delete_confirm_des_2": "من قاعدة البيانات."
|
||||
},
|
||||
"alerts": {
|
||||
"title": "التنبيهات",
|
||||
"subtitle_1": "راجع",
|
||||
"notification_settings": "إعدادات الإشعارات",
|
||||
"subtitle_2": "لتكوين كيفية استلام التنبيهات.",
|
||||
"overwrite_existing_alerts": "استبدال التنبيهات الموجودة",
|
||||
"info": {
|
||||
"status": "الحالة",
|
||||
"status_des": "يتم التشغيل عند تبديل الحالة بين متصل ومنقطع.",
|
||||
"cpu_usage": "استخدام المعالج",
|
||||
"cpu_usage_des": "يتم التشغيل عندما يتجاوز استخدام المعالج الحد.",
|
||||
"memory_usage": "استخدام الذاكرة",
|
||||
"memory_usage_des": "يتم التشغيل عندما يتجاوز استخدام الذاكرة الحد.",
|
||||
"disk_usage": "استخدام القرص",
|
||||
"disk_usage_des": "يتم التشغيل عندما يتجاوز استخدام أي قرص الحد.",
|
||||
"bandwidth": "النطاق الترددي",
|
||||
"bandwidth_des": "يتم التشغيل عندما يتجاوز استخدام الشبكة الحد.",
|
||||
"temperature": "درجة الحرارة",
|
||||
"temperature_des": "يتم التشغيل عندما يتجاوز أي مستشعر الحد المسموح به."
|
||||
},
|
||||
"average_exceeds": "المتوسط يتجاوز",
|
||||
"for": "لمدة"
|
||||
},
|
||||
"settings": {
|
||||
"settings": "الإعدادات",
|
||||
"subtitle": "إدارة تفضيلات العرض والإشعارات.",
|
||||
"save_settings": "حفظ الإعدادات",
|
||||
"export_configuration": "تصدير الإعدادات",
|
||||
"general": {
|
||||
"title": "عام",
|
||||
"subtitle": "تغيير خيارات التطبيق العامة.",
|
||||
"language": {
|
||||
"title": "اللغة",
|
||||
"subtitle_1": "هل تريد مساعدتنا في تحسين ترجماتنا؟ راجع",
|
||||
"subtitle_2": "للمزيد من التفاصيل.",
|
||||
"preferred_language": "اللغة المفضلة"
|
||||
},
|
||||
"chart_options": {
|
||||
"title": "خيارات المخطط",
|
||||
"subtitle": "ضبط خيارات عرض المخططات.",
|
||||
"default_time_period": "الفترة الزمنية الافتراضية",
|
||||
"default_time_period_des": "يحدد النطاق الزمني الافتراضي للمخططات عند عرض النظام."
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"title": "الإشعارات",
|
||||
"subtitle_1": "تكوين كيفية استلام إشعارات التنبيه.",
|
||||
"subtitle_2": "هل تبحث عن مكان إنشاء التنبيهات؟ انقر على رمز الجرس",
|
||||
"subtitle_3": "في جدول الأنظمة.",
|
||||
"email": {
|
||||
"title": "إشعارات البريد الإلكتروني",
|
||||
"please": "الرجاء",
|
||||
"configure_an_SMTP_server": "تكوين خادم SMTP",
|
||||
"to_ensure_alerts_are_delivered": "لضمان تسليم التنبيهات.",
|
||||
"to_email_s": "إلى البريد الإلكتروني",
|
||||
"enter_email_address": "أدخل عنوان البريد الإلكتروني...",
|
||||
"des": "احفظ العنوان باستخدام مفتاح الإدخال أو الفاصلة. اتركه فاغاً لتعطيل إشعارات البريد الإلكتروني."
|
||||
},
|
||||
"webhook_push": {
|
||||
"title": "إشعارات Webhook / Push",
|
||||
"des_1": "يستخدم Beszel",
|
||||
"des_2": "للتكامل مع خدمات الإشعارات الشائعة.",
|
||||
"add_url": "إضافة URL"
|
||||
}
|
||||
},
|
||||
"yaml_config": {
|
||||
"short_title": "تكوين YAML",
|
||||
"title": "تكوين YAML",
|
||||
"subtitle": "تصدير تكوين النظام الحالي.",
|
||||
"des_1": "يستخدم النظام",
|
||||
"des_2": "ملف تكوين لإدارة البيانات",
|
||||
"des_3": "عند كل إعادة تشغيل، سيتم تحديث الأنظمة في قاعدة البيانات لتطابق الأنظمة المحددة في الملف.",
|
||||
"alert": {
|
||||
"title": "تحذير - احتمال فقدان البيانات",
|
||||
"des_1": "الأنظمة الموجودة غير المحددة في",
|
||||
"des_2": "سيتم حذفها. يرجى النسخ الاحتياطي بانتظام."
|
||||
}
|
||||
},
|
||||
"language": "اللغة"
|
||||
},
|
||||
"user_dm": {
|
||||
"users": "المستخدمون",
|
||||
"logs": "السجلات",
|
||||
"backups": "النسخ الاحتياطي",
|
||||
"auth_providers": "مزودو المصادقة",
|
||||
"log_out": "تسجيل الخروج"
|
||||
},
|
||||
"themes": {
|
||||
"toggle_theme": "تبديل السمة",
|
||||
"light": "فاتح",
|
||||
"dark": "داكن",
|
||||
"system": "النظام"
|
||||
},
|
||||
"add_system": {
|
||||
"add_new_system": "إضافة نظام جديد",
|
||||
"binary": "الملف الثنائي",
|
||||
"dialog_des_1": "يجب تشغيل العميل على الخادم للاتصال. انسخ",
|
||||
"dialog_des_2": "إلى الخادم المستهدف للتثبيت.",
|
||||
"name": "الاسم",
|
||||
"host_ip": "المضيف/IP",
|
||||
"port": "المنفذ",
|
||||
"key": "المفتاح العام",
|
||||
"click_to_copy": "انقر للنسخ",
|
||||
"command": "الأمر",
|
||||
"add_system": "إضافة نظام"
|
||||
},
|
||||
"command": {
|
||||
"search": "البحث في الإعدادات أو الأنظمة...",
|
||||
"pages_settings": "الصفحات / الإعدادات",
|
||||
"dashboard": "لوحة التحكم",
|
||||
"documentation": "التوثيق",
|
||||
"SMTP_settings": "إعدادات SMTP",
|
||||
"page": "الصفحة",
|
||||
"admin": "المسؤول"
|
||||
},
|
||||
"monitor": {
|
||||
"toggle_grid": "تبديل الشبكة",
|
||||
"average": "المتوسط",
|
||||
"max_1_min": "أقصى 1 دقيقة",
|
||||
"total_cpu_usage": "إجمالي استخدام المعالج",
|
||||
"cpu_des": "استخدام المعالج على مستوى النظام",
|
||||
"docker_cpu_usage": "استخدام معالج Docker",
|
||||
"docker_cpu_des": "متوسط استخدام المعالج للحاويات",
|
||||
"total_memory_usage": "إجمالي استخدام الذاكرة",
|
||||
"memory_des": "الاستخدام الدقيق في وقت التسجيل",
|
||||
"docker_memory_usage": "استخدام ذاكرة Docker",
|
||||
"docker_memory_des": "استخدام الذاكرة لحاويات Docker",
|
||||
"disk_space": "مساحة القرص",
|
||||
"disk_des": "استخدام القسم الجذر",
|
||||
"disk_io": "إدخال/إخراج القرص",
|
||||
"disk_io_des": "معدل نقل نظام الملفات الجذر",
|
||||
"bandwidth": "النطاق الترددي",
|
||||
"bandwidth_des": "حركة الشبكة للواجهات العامة",
|
||||
"docker_network_io": "إدخال/إخراج شبكة Docker",
|
||||
"docker_network_io_des": "حركة الشبكة لحاويات Docker",
|
||||
"swap_usage": "استخدام المبادلة",
|
||||
"swap_des": "مساحة المبادلة المستخدمة من قبل النظام",
|
||||
"temperature": "درجة الحرارة",
|
||||
"temperature_des": "درجات حرارة مستشعرات النظام",
|
||||
"usage": "الاستخدام",
|
||||
"disk_usage_of": "استخدام القرص لـ",
|
||||
"throughput_of": "معدل نقل",
|
||||
"waiting_for": "في انتظار سجلات كافية للعرض",
|
||||
"cache_buffers": "ذاكرة التخزين المؤقت / المخازن المؤقتة",
|
||||
"read": "قراءة",
|
||||
"write": "كتابة",
|
||||
"sent": "مرسل",
|
||||
"received": "مستلم",
|
||||
"used": "مستخدم"
|
||||
},
|
||||
"auth": {
|
||||
"login": "الرجاء تسجيل الدخول إلى حسابك",
|
||||
"reset": "أدخل البريد الإلكتروني لإعادة تعيين كلمة المرور",
|
||||
"create": "الرجاء إنشاء حساب مسؤول",
|
||||
"create_account": "إنشاء حساب",
|
||||
"sign_in": "تسجيل الدخول",
|
||||
"openid_des": "يدعم Beszel OpenID Connect والعديد من مزودي مصادقة OAuth2.",
|
||||
"please_view_the": "الرجاء مراجعة",
|
||||
"for_instructions": "للتعليمات.",
|
||||
"forgot_password": "نسيت كلمة المرور؟",
|
||||
"reset_password": "إعادة تعيين كلمة المرور",
|
||||
"command_line_instructions": "تعليمات سطر الأوامر",
|
||||
"command_1": "إذا فقدت كلمة مرور حساب المسؤول، يمكنك إعادة تعيينها باستخدام الأمر التالي.",
|
||||
"command_2": "ثم قم بتسجيل الدخول إلى الخلفية وإعادة تعيين كلمة مرور حساب المستخدم في جدول المستخدمين."
|
||||
},
|
||||
"clipboard": {
|
||||
"copied": "تم النسخ إلى الحافظة",
|
||||
"title": "نسخ النص",
|
||||
"des": "النسخ التلقائي يتطلب سياق آمن."
|
||||
}
|
||||
}
|
||||
|
@@ -4,7 +4,8 @@ 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 { $authenticated, $systems, pb, $publicKey, $hubVersion, $copyContent } from "./lib/stores.ts"
|
||||
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"
|
||||
@@ -77,29 +78,30 @@ const App = () => {
|
||||
const Layout = () => {
|
||||
const authenticated = useStore($authenticated)
|
||||
const copyContent = useStore($copyContent)
|
||||
|
||||
if (!authenticated) {
|
||||
return (
|
||||
<Suspense>
|
||||
<LoginPage />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
const direction = useStore($direction)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="container">
|
||||
<Navbar />
|
||||
</div>
|
||||
<div className="container mb-14 relative">
|
||||
<App />
|
||||
{copyContent && (
|
||||
<Suspense>
|
||||
<CopyToClipboardDialog content={copyContent} />
|
||||
</Suspense>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
<DirectionProvider dir={direction}>
|
||||
{!authenticated ? (
|
||||
<Suspense>
|
||||
<LoginPage />
|
||||
</Suspense>
|
||||
) : (
|
||||
<>
|
||||
<div className="container">
|
||||
<Navbar />
|
||||
</div>
|
||||
<div className="container mb-14 relative">
|
||||
<App />
|
||||
{copyContent && (
|
||||
<Suspense>
|
||||
<CopyToClipboardDialog content={copyContent} />
|
||||
</Suspense>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</DirectionProvider>
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -92,6 +92,7 @@ module.exports = {
|
||||
},
|
||||
plugins: [
|
||||
require("tailwindcss-animate"),
|
||||
require("tailwindcss-rtl"),
|
||||
function ({ addVariant }) {
|
||||
addVariant("light", ".light &")
|
||||
},
|
||||
|
Reference in New Issue
Block a user