import { Trans } from "@lingui/react/macro" import { t } from "@lingui/core/macro" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { $publicKey, pb } from "@/lib/stores" import { cn, copyToClipboard, isReadOnlyUser, useLocalStorage } from "@/lib/utils" import { i18n } from "@lingui/core" import { useStore } from "@nanostores/react" import { ChevronDownIcon, Copy, ExternalLinkIcon, PlusIcon } from "lucide-react" import { memo, useRef, useState } from "react" import { basePath, navigate } from "./router" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "./ui/dropdown-menu" import { SystemRecord } from "@/types" import { AppleIcon, DockerIcon, TuxIcon, WindowsIcon } from "./ui/icons" export function AddSystemButton({ className }: { className?: string }) { const [open, setOpen] = useState(false) let opened = useRef(false) if (open) { opened.current = true } return ( {opened.current && } ) } function copyDockerCompose(port = "45876", publicKey: string) { copyToClipboard(`services: beszel-agent: image: "henrygd/beszel-agent" container_name: "beszel-agent" restart: unless-stopped network_mode: host volumes: - /var/run/docker.sock:/var/run/docker.sock:ro # monitor other disks / partitions by mounting a folder in /extra-filesystems # - /mnt/disk/.beszel:/extra-filesystems/sda1:ro environment: LISTEN: ${port} KEY: "${publicKey}"`) } function copyDockerRun(port = "45876", publicKey: string) { copyToClipboard( `docker run -d --name beszel-agent --network host --restart unless-stopped -v /var/run/docker.sock:/var/run/docker.sock:ro -e KEY="${publicKey}" -e LISTEN=${port} henrygd/beszel-agent:latest` ) } function copyLinuxCommand(port = "45876", publicKey: string, brew = false) { let cmd = `curl -sL https://get.beszel.dev${ brew ? "/brew" : "" } -o /tmp/install-agent.sh && chmod +x /tmp/install-agent.sh && /tmp/install-agent.sh -p ${port} -k "${publicKey}"` // brew script does not support --china-mirrors if (!brew && (i18n.locale + navigator.language).includes("zh-CN")) { cmd += ` --china-mirrors` } copyToClipboard(cmd) } function copyWindowsCommand(port = "45876", publicKey: string) { copyToClipboard( `& iwr -useb https://get.beszel.dev -OutFile "$env:TEMP\\install-agent.ps1"; & Powershell -ExecutionPolicy Bypass -File "$env:TEMP\\install-agent.ps1" -Key "${publicKey}" -Port ${port}` ) } /** * SystemDialog component for adding or editing a system. * @param {Object} props - The component props. * @param {function} props.setOpen - Function to set the open state of the dialog. * @param {SystemRecord} [props.system] - Optional system record for editing an existing system. */ export const SystemDialog = memo(({ setOpen, system }: { setOpen: (open: boolean) => void; system?: SystemRecord }) => { const publicKey = useStore($publicKey) const port = useRef(null) const [hostValue, setHostValue] = useState(system?.host ?? "") const isUnixSocket = hostValue.startsWith("/") const [tab, setTab] = useLocalStorage("as-tab", "docker") async function handleSubmit(e: SubmitEvent) { e.preventDefault() const formData = new FormData(e.target as HTMLFormElement) const data = Object.fromEntries(formData) as Record data.users = pb.authStore.record!.id try { setOpen(false) if (system) { await pb.collection("systems").update(system.id, { ...data, status: "pending" }) } else { await pb.collection("systems").create(data) } navigate(basePath) // console.log(record) } catch (e) { console.log(e) } } return ( { setHostValue(system?.host ?? "") }} > {system ? `${t`Edit`} ${system?.name}` : Add New System} Docker Binary {/* Docker (set tab index to prevent auto focusing content in edit system dialog) */} The agent must be running on the system to connect. Copy the docker-compose.yml for the agent below. {/* Binary */} The agent must be running on the system to connect. Copy the installation command for the agent below.
{ setHostValue(e.target.value) }} />

Click to copy

{/* Docker */} copyDockerCompose(isUnixSocket ? hostValue : port.current?.value, publicKey)} icon={} dropdownItems={[ { text: t({ message: "Copy docker run", context: "Button to copy docker run command" }), onClick: () => copyDockerRun(isUnixSocket ? hostValue : port.current?.value, publicKey), icons: [], }, ]} /> {/* Binary */} } onClick={() => copyLinuxCommand(isUnixSocket ? hostValue : port.current?.value, publicKey)} dropdownItems={[ { text: t({ message: "Homebrew command", context: "Button to copy install command" }), onClick: () => copyLinuxCommand(isUnixSocket ? hostValue : port.current?.value, publicKey, true), icons: [, ], }, { text: t({ message: "Windows command", context: "Button to copy install command" }), onClick: () => copyWindowsCommand(isUnixSocket ? hostValue : port.current?.value, publicKey), icons: [], }, { text: t`Manual setup instructions`, url: "https://beszel.dev/guide/agent-installation#binary", icons: [], }, ]} /> {/* Save */}
) }) interface DropdownItem { text: string onClick?: () => void url?: string icons?: React.ReactNode[] } interface CopyButtonProps { text: string onClick: () => void dropdownItems: DropdownItem[] icon?: React.ReactNode } const CopyButton = memo((props: CopyButtonProps) => { return (
{props.dropdownItems.map((item, index) => { const className = "cursor-pointer flex items-center gap-1.5" return item.url ? ( {item.text} {item.icons?.map((icon) => icon)} ) : ( {item.text} {item.icons?.map((icon) => icon)} ) })}
) })