get rid of updatedSystem store

This commit is contained in:
Henry Dollman
2024-08-21 12:50:12 -04:00
parent 0590facc89
commit 55863f849c
4 changed files with 60 additions and 71 deletions

View File

@@ -1,9 +1,11 @@
import { Suspense, lazy, useEffect } from 'react'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../ui/card'
import { $hubVersion } from '@/lib/stores'
import { $alerts, $hubVersion, $systems, pb } from '@/lib/stores'
import { useStore } from '@nanostores/react'
import { GithubIcon } from 'lucide-react'
import { Separator } from '../ui/separator'
import { updateRecordList } from '@/lib/utils'
import { AlertRecord, SystemRecord } from '@/types'
const SystemsTable = lazy(() => import('../systems-table/systems-table'))
@@ -12,6 +14,18 @@ export default function () {
useEffect(() => {
document.title = 'Dashboard / Beszel'
// subscribe to real time updates for systems / alerts
pb.collection<SystemRecord>('systems').subscribe('*', (e) => {
updateRecordList(e, $systems)
})
pb.collection<AlertRecord>('alerts').subscribe('*', (e) => {
updateRecordList(e, $alerts)
})
return () => {
pb.collection('systems').unsubscribe('*')
pb.collection('alerts').unsubscribe('*')
}
}, [])
return (
@@ -34,7 +48,7 @@ export default function () {
</CardContent>
</Card>
{hubVersion && (
<div className="flex gap-1.5 justify-end items-center pr-3 sm:pr-7 mt-3.5 text-xs opacity-80">
<div className="flex gap-1.5 justify-end items-center pr-3 sm:pr-6 mt-3.5 text-xs opacity-80">
<a
href="https://github.com/henrygd/beszel"
target="_blank"
@@ -42,7 +56,7 @@ export default function () {
>
<GithubIcon className="h-3 w-3" /> GitHub
</a>
<Separator orientation="vertical" className="h-3 bg-muted-foreground" />
<Separator orientation="vertical" className="h-2.5 bg-muted-foreground opacity-70" />
<a
href="https://github.com/henrygd/beszel/releases"
target="_blank"

View File

@@ -1,4 +1,4 @@
import { $updatedSystem, $systems, pb, $chartTime } from '@/lib/stores'
import { $systems, pb, $chartTime } from '@/lib/stores'
import { ContainerStatsRecord, SystemRecord, SystemStatsRecord } from '@/types'
import { Suspense, lazy, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '../ui/card'
@@ -21,12 +21,11 @@ const BandwidthChart = lazy(() => import('../charts/bandwidth-chart'))
const ContainerNetChart = lazy(() => import('../charts/container-net-chart'))
const SwapChart = lazy(() => import('../charts/swap-chart'))
export default function ServerDetail({ name }: { name: string }) {
export default function SystemDetail({ name }: { name: string }) {
const systems = useStore($systems)
const updatedSystem = useStore($updatedSystem)
const chartTime = useStore($chartTime)
const [ticks, setTicks] = useState([] as number[])
const [server, setServer] = useState({} as SystemRecord)
const [system, setSystem] = useState({} as SystemRecord)
const [systemStats, setSystemStats] = useState([] as SystemStatsRecord[])
const [hasDockerStats, setHasDocker] = useState(false)
const [dockerCpuChartData, setDockerCpuChartData] = useState<Record<string, number | string>[]>(
@@ -58,26 +57,32 @@ export default function ServerDetail({ name }: { name: string }) {
useEffect(resetCharts, [chartTime])
useEffect(() => {
if (server.id && server.name === name) {
if (system.id && system.name === name) {
return
}
const matchingServer = systems.find((s) => s.name === name) as SystemRecord
if (matchingServer) {
setServer(matchingServer)
const matchingSystem = systems.find((s) => s.name === name) as SystemRecord
if (matchingSystem) {
setSystem(matchingSystem)
}
}, [name, server, systems])
}, [name, system, systems])
// update server when new data is available
// update system when new data is available
useEffect(() => {
if (updatedSystem.id === server.id) {
setServer(updatedSystem)
if (!system.id) {
return
}
}, [updatedSystem])
pb.collection<SystemRecord>('systems').subscribe(system.id, (e) => {
setSystem(e.record)
})
return () => {
pb.collection('systems').unsubscribe(system.id)
}
}, [system])
async function getStats<T>(collection: string): Promise<T[]> {
return await pb.collection<T>(collection).getFullList({
filter: pb.filter('system={:id} && created > {:created} && type={:type}', {
id: server.id,
id: system.id,
created: getPbTimestamp(chartTime),
type: chartTimeData[chartTime].type,
}),
@@ -112,7 +117,7 @@ export default function ServerDetail({ name }: { name: string }) {
// get stats
useEffect(() => {
if (!server.id || !chartTime) {
if (!system.id || !chartTime) {
return
}
Promise.allSettled([
@@ -128,7 +133,7 @@ export default function ServerDetail({ name }: { name: string }) {
setSystemStats(addEmptyValues(systemStats.value, expectedInterval))
}
})
}, [server, chartTime])
}, [system, chartTime])
useEffect(() => {
if (!systemStats.length) {
@@ -173,14 +178,14 @@ export default function ServerDetail({ name }: { name: string }) {
}, [])
const uptime = useMemo(() => {
let uptime = server.info?.u || 0
let uptime = system.info?.u || 0
if (uptime < 172800) {
return `${Math.trunc(uptime / 3600)} hours`
}
return `${Math.trunc(server.info?.u / 86400)} days`
}, [server.info?.u])
return `${Math.trunc(system.info?.u / 86400)} days`
}, [system.info?.u])
if (!server.id) {
if (!system.id) {
return null
}
@@ -188,11 +193,11 @@ export default function ServerDetail({ name }: { name: string }) {
<div className="grid gap-4 mb-10">
<Card>
<div className="grid gap-2 px-4 sm:px-6 pt-3 sm:pt-4 pb-5">
<h1 className="text-[1.6rem] font-semibold">{server.name}</h1>
<h1 className="text-[1.6rem] font-semibold">{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')}>
{server.status === 'up' && (
{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' }}
@@ -200,20 +205,20 @@ export default function ServerDetail({ name }: { name: string }) {
)}
<span
className={cn('relative inline-flex rounded-full h-3 w-3', {
'bg-green-500': server.status === 'up',
'bg-red-500': server.status === 'down',
'bg-primary/40': server.status === 'paused',
'bg-yellow-500': server.status === 'pending',
'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>
{server.status}
{system.status}
</div>
<Separator orientation="vertical" className="h-4 bg-primary/30" />
<div className="flex gap-1.5">
<GlobeIcon className="h-4 w-4 mt-[1px]" /> {server.host}
<GlobeIcon className="h-4 w-4 mt-[1px]" /> {system.host}
</div>
{server.info?.u && (
{system.info?.u && (
<TooltipProvider>
<Tooltip>
<Separator orientation="vertical" className="h-4 bg-primary/30" />
@@ -226,12 +231,12 @@ export default function ServerDetail({ name }: { name: string }) {
</Tooltip>
</TooltipProvider>
)}
{server.info?.m && (
{system.info?.m && (
<>
<Separator orientation="vertical" className="h-4 bg-primary/30" />
<div className="flex gap-1.5">
<CpuIcon className="h-4 w-4 mt-[1px]" />
{server.info.m} ({server.info.c}c / {server.info.t}t)
{system.info.m} ({system.info.c}c / {system.info.t}t)
</div>
</>
)}

View File

@@ -11,9 +11,6 @@ export const $authenticated = atom(pb.authStore.isValid)
/** List of system records */
export const $systems = atom([] as SystemRecord[])
/** Last updated system record (realtime) */
export const $updatedSystem = atom({} as SystemRecord)
/** List of alert records */
export const $alerts = atom([] as AlertRecord[])

View File

@@ -3,24 +3,9 @@ import React, { 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 {
$alerts,
$authenticated,
$updatedSystem,
$systems,
pb,
$publicKey,
$hubVersion,
} from './lib/stores.ts'
import { $authenticated, $systems, pb, $publicKey, $hubVersion } from './lib/stores.ts'
import { ModeToggle } from './components/mode-toggle.tsx'
import {
cn,
isAdmin,
updateAlerts,
updateFavicon,
updateRecordList,
updateSystemList,
} from './lib/utils.ts'
import { cn, isAdmin, updateAlerts, updateFavicon, updateSystemList } from './lib/utils.ts'
import { buttonVariants } from './components/ui/button.tsx'
import {
DatabaseBackupIcon,
@@ -45,7 +30,7 @@ import {
} from './components/ui/dropdown-menu.tsx'
import { AlertRecord, SystemRecord } from './types'
import { $router, Link, navigate } from './components/router.tsx'
import ServerDetail from './components/routes/system.tsx'
import SystemDetail from './components/routes/system.tsx'
// const ServerDetail = lazy(() => import('./components/routes/system.tsx'))
const CommandPalette = lazy(() => import('./components/command-palette.tsx'))
@@ -62,25 +47,13 @@ const App = () => {
$authenticated.set(pb.authStore.isValid)
})
// get version / public key
pb.send('/api/beszel/getkey', {}).then(({ key, v }) => {
$publicKey.set(key)
$hubVersion.set(v)
pb.send('/api/beszel/getkey', {}).then((data) => {
$publicKey.set(data.key)
$hubVersion.set(data.v)
})
// get servers / alerts
updateSystemList()
updateAlerts()
// subscribe to real time updates for systems / alerts
pb.collection<SystemRecord>('systems').subscribe('*', (e) => {
updateRecordList(e, $systems)
$updatedSystem.set(e.record)
})
pb.collection<AlertRecord>('alerts').subscribe('*', (e) => {
updateRecordList(e, $alerts)
})
return () => {
pb.collection('systems').unsubscribe('*')
pb.collection('alerts').unsubscribe('*')
}
}, [])
// update favicon
@@ -110,7 +83,7 @@ const App = () => {
} else if (page.path === '/') {
return <Home />
} else if (page.route === 'server') {
return <ServerDetail name={page.params.name} />
return <SystemDetail name={page.params.name} />
}
}