mirror of
https://github.com/henrygd/beszel.git
synced 2025-12-18 03:06:16 +01:00
update alerts dialog and icon imports
This commit is contained in:
@@ -8,7 +8,7 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import { BellIcon } from 'lucide-react'
|
||||
import { BellIcon, CpuIcon, HardDriveIcon, MemoryStickIcon, ServerIcon } from 'lucide-react'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
@@ -16,6 +16,7 @@ import { AlertRecord, SystemRecord } from '@/types'
|
||||
import { lazy, Suspense, useMemo, useState } from 'react'
|
||||
import { toast } from './ui/use-toast'
|
||||
import { Link } from './router'
|
||||
import { EthernetIcon, ThermometerIcon } from './ui/icons'
|
||||
|
||||
const Slider = lazy(() => import('./ui/slider'))
|
||||
|
||||
@@ -65,22 +66,25 @@ export default function AlertsButton({ system }: { system: SystemRecord }) {
|
||||
system={system}
|
||||
alerts={systemAlerts}
|
||||
name="CPU"
|
||||
title="CPU Usage"
|
||||
title="CPU usage"
|
||||
description="Triggers when CPU usage exceeds a threshold."
|
||||
Icon={CpuIcon}
|
||||
/>
|
||||
<AlertWithSlider
|
||||
system={system}
|
||||
alerts={systemAlerts}
|
||||
name="Memory"
|
||||
title="Memory Usage"
|
||||
title="Memory usage"
|
||||
description="Triggers when memory usage exceeds a threshold."
|
||||
Icon={MemoryStickIcon}
|
||||
/>
|
||||
<AlertWithSlider
|
||||
system={system}
|
||||
alerts={systemAlerts}
|
||||
name="Disk"
|
||||
title="Disk Usage"
|
||||
title="Disk usage"
|
||||
description="Triggers when root usage exceeds a threshold."
|
||||
Icon={HardDriveIcon}
|
||||
/>
|
||||
<AlertWithSlider
|
||||
system={system}
|
||||
@@ -89,6 +93,7 @@ export default function AlertsButton({ system }: { system: SystemRecord }) {
|
||||
title="Bandwidth"
|
||||
description="Triggers when combined up/down exceeds a threshold."
|
||||
unit=" MB/s"
|
||||
Icon={EthernetIcon}
|
||||
/>
|
||||
<AlertWithSlider
|
||||
system={system}
|
||||
@@ -97,6 +102,7 @@ export default function AlertsButton({ system }: { system: SystemRecord }) {
|
||||
title="Temperature"
|
||||
description="Triggers when any sensor exceeds a threshold."
|
||||
unit=" °C"
|
||||
Icon={ThermometerIcon}
|
||||
/>
|
||||
</div>
|
||||
</DialogContent>
|
||||
@@ -114,11 +120,13 @@ function AlertStatus({ system, alerts }: { system: SystemRecord; alerts: AlertRe
|
||||
return (
|
||||
<label
|
||||
htmlFor="alert-status"
|
||||
className="flex flex-row items-center justify-between gap-4 rounded-lg border p-4 cursor-pointer"
|
||||
className="flex flex-row items-center justify-between gap-4 rounded-lg border border-muted-foreground/15 hover:border-muted-foreground/20 transition-colors duration-100 p-4 cursor-pointer"
|
||||
>
|
||||
<div className="grid gap-1 select-none">
|
||||
<p className="font-semibold">System Status</p>
|
||||
<span className="block text-sm text-foreground opacity-80">
|
||||
<p className="font-semibold flex gap-3 items-center">
|
||||
<ServerIcon className="h-4 w-4 opacity-85" /> System status
|
||||
</p>
|
||||
<span className="block text-sm text-muted-foreground">
|
||||
Triggers when status switches between up and down.
|
||||
</span>
|
||||
</div>
|
||||
@@ -161,6 +169,7 @@ function AlertWithSlider({
|
||||
description,
|
||||
unit = '%',
|
||||
max = 99,
|
||||
Icon,
|
||||
}: {
|
||||
system: SystemRecord
|
||||
alerts: AlertRecord[]
|
||||
@@ -169,32 +178,39 @@ function AlertWithSlider({
|
||||
description: string
|
||||
unit?: string
|
||||
max?: number
|
||||
Icon: React.FC<React.SVGProps<SVGSVGElement>>
|
||||
}) {
|
||||
const [pendingChange, setPendingChange] = useState(false)
|
||||
const [liveValue, setLiveValue] = useState(80)
|
||||
const [liveMinutes, setLiveMinutes] = useState(10)
|
||||
|
||||
const key = name.replaceAll(' ', '-')
|
||||
|
||||
const alert = useMemo(() => {
|
||||
const alert = alerts.find((alert) => alert.name === name)
|
||||
if (alert) {
|
||||
setLiveValue(alert.value)
|
||||
setLiveMinutes(alert.min || 1)
|
||||
}
|
||||
return alert
|
||||
}, [alerts])
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border">
|
||||
<div className="rounded-lg border border-muted-foreground/15 hover:border-muted-foreground/20 transition-colors duration-100 group">
|
||||
<label
|
||||
htmlFor={`alert-${name}`}
|
||||
htmlFor={`v${key}`}
|
||||
className={cn('flex flex-row items-center justify-between gap-4 cursor-pointer p-4', {
|
||||
'pb-0': !!alert,
|
||||
})}
|
||||
>
|
||||
<div className="grid gap-1 select-none">
|
||||
<p className="font-semibold">{title}</p>
|
||||
<span className="block text-sm text-foreground opacity-80">{description}</span>
|
||||
<p className="font-semibold flex gap-3 items-center">
|
||||
<Icon className="h-4 w-4 opacity-85" /> {title}
|
||||
</p>
|
||||
{!alert && <span className="block text-sm text-muted-foreground">{description}</span>}
|
||||
</div>
|
||||
<Switch
|
||||
id={`alert-${name}`}
|
||||
id={`v${key}`}
|
||||
className={cn('transition-opacity', pendingChange && 'opacity-40')}
|
||||
checked={!!alert}
|
||||
value={!!alert ? 'on' : 'off'}
|
||||
@@ -212,6 +228,7 @@ function AlertWithSlider({
|
||||
user: pb.authStore.model!.id,
|
||||
name,
|
||||
value: liveValue,
|
||||
min: liveMinutes,
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -223,27 +240,52 @@ function AlertWithSlider({
|
||||
/>
|
||||
</label>
|
||||
{alert && (
|
||||
<div className="flex mt-2 mb-3 gap-3 px-4">
|
||||
<Suspense>
|
||||
<Slider
|
||||
defaultValue={[liveValue]}
|
||||
onValueCommit={(val) => {
|
||||
pb.collection('alerts').update(alert.id, {
|
||||
value: val[0],
|
||||
})
|
||||
}}
|
||||
onValueChange={(val) => {
|
||||
setLiveValue(val[0])
|
||||
}}
|
||||
min={1}
|
||||
max={max}
|
||||
// step={1}
|
||||
/>
|
||||
<div className="grid sm:grid-cols-2 mt-1.5 gap-5 px-4 pb-5 tabular-nums text-muted-foreground">
|
||||
<Suspense fallback={<div className="h-10" />}>
|
||||
<div>
|
||||
<label htmlFor={`v${key}`} className="text-sm block h-8">
|
||||
Exceeds{' '}
|
||||
<strong className="text-foreground">
|
||||
{liveValue}
|
||||
{unit}
|
||||
</strong>
|
||||
</label>
|
||||
<div className="flex gap-3">
|
||||
<Slider
|
||||
id={`v${key}`}
|
||||
defaultValue={[liveValue]}
|
||||
onValueCommit={(val) => {
|
||||
pb.collection('alerts').update(alert.id, {
|
||||
value: val[0],
|
||||
})
|
||||
}}
|
||||
onValueChange={(val) => setLiveValue(val[0])}
|
||||
min={1}
|
||||
max={max}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor={`t${key}`} className="text-sm block h-8">
|
||||
For <strong className="text-foreground">{liveMinutes}</strong> minute
|
||||
{liveMinutes > 1 && 's'}
|
||||
</label>
|
||||
<div className="flex gap-3">
|
||||
<Slider
|
||||
id={`t${key}`}
|
||||
defaultValue={[liveMinutes]}
|
||||
onValueCommit={(val) => {
|
||||
pb.collection('alerts').update(alert.id, {
|
||||
min: val[0],
|
||||
})
|
||||
}}
|
||||
onValueChange={(val) => setLiveMinutes(val[0])}
|
||||
min={1}
|
||||
max={60}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Suspense>
|
||||
<span className="tabular-nums tracking-tighter text-[.92em] shrink-0">
|
||||
{liveValue}
|
||||
{unit}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user