Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/ArsFy/beszel into ArsFy-main
Browse files Browse the repository at this point in the history
  • Loading branch information
henrygd committed Oct 29, 2024
2 parents 9e6ee8d + 2c66f93 commit e64fad9
Show file tree
Hide file tree
Showing 26 changed files with 1,700 additions and 249 deletions.
Binary file modified beszel/site/bun.lockb
Binary file not shown.
3 changes: 3 additions & 0 deletions beszel/site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@
"clsx": "^2.1.1",
"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",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-i18next": "^15.1.0",
"recharts": "^2.13.0",
"tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7",
Expand Down
194 changes: 119 additions & 75 deletions beszel/site/src/components/add-system.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import {
DialogTrigger,
} 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'
Expand All @@ -18,8 +24,11 @@ import { useState, useRef, MutableRefObject } from 'react'
import { useStore } from '@nanostores/react'
import { cn, copyToClipboard, isReadOnlyUser } from '@/lib/utils'
import { navigate } from './router'
import { useTranslation } from 'react-i18next'

export function AddSystemButton({ className }: { className?: string }) {
const { t } = useTranslation()

const [open, setOpen] = useState(false)
const port = useRef() as MutableRefObject<HTMLInputElement>
const publicKey = useStore($publicKey)
Expand All @@ -41,6 +50,10 @@ export function AddSystemButton({ className }: { className?: string }) {
# FILESYSTEM: /dev/sda1 # override the root partition / device for disk I/O stats`)
}

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) {
e.preventDefault()
const formData = new FormData(e.target as HTMLFormElement)
Expand All @@ -64,85 +77,116 @@ export function AddSystemButton({ className }: { className?: string }) {
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>
{t('add')}<span className="hidden xs:inline">{t('system')}</span>
</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 />
</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>
<Tabs defaultValue="docker">
<DialogHeader>
<DialogTitle className="mb-2">{t('add_system.add_new_system')}</DialogTitle>
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="docker">Docker</TabsTrigger>
<TabsTrigger value="binary">{t('add_system.binary')}</TabsTrigger>
</TabsList>
</DialogHeader>
{/* Docker */}
<TabsContent value="docker">
<DialogDescription className={'mb-4'}>
{t('add_system.dialog_des_1')}{' '}
<code className="bg-muted px-1 rounded-sm">docker-compose.yml</code> {t('add_system.dialog_des_2')}
</DialogDescription>
</TabsContent>
{/* Binary */}
<TabsContent value="binary">
<DialogDescription className={'mb-4'}>
{t('add_system.dialog_des_1')}{' '}
<code className="bg-muted px-1 rounded-sm">install command</code> {t('add_system.dialog_des_2')}
</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-right">
{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">
{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">
{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">
{t('add_system.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>{t('add_system.click_to_copy')}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
</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">
<Button
type="button"
variant={'ghost'}
onClick={() => copyDockerCompose(port.current.value)}
>
{t('copy')} docker compose
</Button>
<Button>{t('add_system.add_system')}</Button>
</DialogFooter>
</TabsContent>
{/* Binary */}
<TabsContent value="binary">
<DialogFooter className="flex justify-end gap-2">
<Button
type="button"
variant={'ghost'}
onClick={() => copyInstallCommand(port.current.value)}
>
{t('copy')} linux {t('add_system.command')}
</Button>
<Button>{t('add_system.add_system')}</Button>
</DialogFooter>
</TabsContent>
</form>
</Tabs>
</DialogContent>
</Dialog>
)
Expand Down
15 changes: 9 additions & 6 deletions beszel/site/src/components/alerts/alert-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ 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 { useTranslation } from 'react-i18next'

export default memo(function AlertsButton({ system }: { system: SystemRecord }) {
const alerts = useStore($alerts)
Expand Down Expand Up @@ -54,6 +55,8 @@ function TheContent({
}: {
data: { system: SystemRecord; alerts: AlertRecord[]; systemAlerts: AlertRecord[] }
}) {
const { t } = useTranslation()

const [overwriteExisting, setOverwriteExisting] = useState<boolean | 'indeterminate'>(false)
const systems = $systems.get()

Expand All @@ -69,13 +72,13 @@ function TheContent({
return (
<>
<DialogHeader>
<DialogTitle className="text-xl">Alerts</DialogTitle>
<DialogTitle className="text-xl">{t('alerts.title')}</DialogTitle>
<DialogDescription>
See{' '}
{t('alerts.subtitle_1')}{' '}
<Link href="/settings/notifications" className="link">
notification settings
{t('alerts.notification_settings')}
</Link>{' '}
to configure how you receive alerts.
{t('alerts.subtitle_2')}
</DialogDescription>
</DialogHeader>
<Tabs defaultValue="system">
Expand All @@ -86,7 +89,7 @@ function TheContent({
</TabsTrigger>
<TabsTrigger value="global">
<GlobeIcon className="mr-1.5 h-3.5 w-3.5" />
All systems
{t('all_systems')}
</TabsTrigger>
</TabsList>
<TabsContent value="system">
Expand All @@ -107,7 +110,7 @@ function TheContent({
checked={overwriteExisting}
onCheckedChange={setOverwriteExisting}
/>
Overwrite existing alerts
{t('alerts.overwrite_existing_alerts')}
</label>
<div className="grid gap-3">
{data.map((d) => (
Expand Down
12 changes: 7 additions & 5 deletions beszel/site/src/components/alerts/alerts-system.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { lazy, Suspense, useRef, useState } from 'react'
import { toast } from '../ui/use-toast'
import { RecordOptions } from 'pocketbase'
import { newQueue, Queue } from '@henrygd/queue'
import { useTranslation } from 'react-i18next'

interface AlertData {
checked?: boolean
Expand Down Expand Up @@ -157,6 +158,8 @@ export function SystemAlertGlobal({
}

function AlertContent({ data }: { data: AlertData }) {
const { t } = useTranslation()

const { key } = data

const hasSliders = !('single' in data.alert)
Expand Down Expand Up @@ -185,10 +188,10 @@ function AlertContent({ data }: { data: AlertData }) {
>
<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}
<Icon className="h-4 w-4 opacity-85" /> {t(data.alert.name)}
</p>
{!showSliders && (
<span className="block text-sm text-muted-foreground">{data.alert.desc}</span>
<span className="block text-sm text-muted-foreground">{t(data.alert.desc)}</span>
)}
</div>
<Switch
Expand All @@ -205,7 +208,7 @@ function AlertContent({ data }: { data: AlertData }) {
<Suspense fallback={<div className="h-10" />}>
<div>
<p id={`v${key}`} className="text-sm block h-8">
Average exceeds{' '}
{t('alerts.average_exceeds')}{' '}
<strong className="text-foreground">
{value}
{data.alert.unit}
Expand All @@ -224,8 +227,7 @@ function AlertContent({ data }: { data: AlertData }) {
</div>
<div>
<p id={`t${key}`} className="text-sm block h-8">
For <strong className="text-foreground">{min}</strong> minute
{min > 1 && 's'}
{t('alerts.for')} <strong className="text-foreground">{min}</strong> {min > 1 ? t('alerts.minutes') : t('alerts.minute')}
</p>
<div className="flex gap-3">
<Slider
Expand Down
Loading

0 comments on commit e64fad9

Please sign in to comment.