diff --git a/site/index.html b/site/index.html index 22e3fed..800e4d6 100644 --- a/site/index.html +++ b/site/index.html @@ -2,7 +2,7 @@ - + Home diff --git a/site/public/favicon.svg b/site/public/favicon.svg new file mode 100644 index 0000000..3d846cb --- /dev/null +++ b/site/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/site/public/ubik-reiswar.svg b/site/public/ubik-reiswar.svg new file mode 100644 index 0000000..6e17d50 --- /dev/null +++ b/site/public/ubik-reiswar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/site/public/vite.svg b/site/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/site/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/site/src/components/add-server.tsx b/site/src/components/add-server.tsx index 550defc..f8cb8d2 100644 --- a/site/src/components/add-server.tsx +++ b/site/src/components/add-server.tsx @@ -26,8 +26,8 @@ export function AddServerButton() { function copyDockerCompose(port: string) { copyToClipboard(`services: agent: - image: 'henrygd/monitor-agent' - container_name: 'monitor-agent' + image: 'henrygd/ubik-agent' + container_name: 'ubik-agent' restart: unless-stopped ports: - '${port}:45876' diff --git a/site/src/components/charts/container-cpu-chart.tsx b/site/src/components/charts/container-cpu-chart.tsx index 9a0162f..d39b136 100644 --- a/site/src/components/charts/container-cpu-chart.tsx +++ b/site/src/components/charts/container-cpu-chart.tsx @@ -4,19 +4,21 @@ import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts' import { ChartConfig, ChartContainer, - ChartLegend, - ChartLegendContent, ChartTooltip, ChartTooltipContent, } from '@/components/ui/chart' -import { useMemo, useState } from 'react' +import { useMemo } from 'react' import { formatShortDate, formatShortTime } from '@/lib/utils' +import Spinner from '../spinner' -export default function ({ chartData }: { chartData: Record[] }) { - const [containerNames, setContainerNames] = useState([] as string[]) - +export default function ({ + chartData, + max, +}: { + chartData: Record[] + max: number +}) { const chartConfig = useMemo(() => { - console.log('chartData', chartData) let config = {} as Record< string, { @@ -24,13 +26,21 @@ export default function ({ chartData }: { chartData: Record - const lastRecord = chartData.at(-1) - // @ts-ignore - let allKeys = new Set(Object.keys(lastRecord)) - allKeys.delete('time') - const keys = Array.from(allKeys) - keys.sort((a, b) => (lastRecord![b] as number) - (lastRecord![a] as number)) - setContainerNames(keys) + const totalUsage = {} as Record + for (let stats of chartData) { + for (let key in stats) { + if (key === 'time') { + continue + } + if (!(key in totalUsage)) { + totalUsage[key] = 0 + } + // @ts-ignore + totalUsage[key] += stats[key] + } + } + let keys = Object.keys(totalUsage) + keys.sort((a, b) => (totalUsage[a] > totalUsage[b] ? -1 : 1)) const length = keys.length for (let i = 0; i < length; i++) { const key = keys[i] @@ -40,12 +50,11 @@ export default function ({ chartData }: { chartData: Record } return ( @@ -53,20 +62,23 @@ export default function ({ chartData }: { chartData: Record - {/* */} - `${v}%`} + /> + { - // console.log('itemSorter', item) - // return -item.value - // }} - indicator="line" - /> - } + content={} /> - {containerNames.map((key) => ( + {Object.keys(chartConfig).map((key) => ( ))} - {/* */} - {/* } className="flex-wrap gap-y-2 mb-2" /> */} ) diff --git a/site/src/components/charts/cpu-chart.tsx b/site/src/components/charts/cpu-chart.tsx index b5e3e9c..d4c3ba9 100644 --- a/site/src/components/charts/cpu-chart.tsx +++ b/site/src/components/charts/cpu-chart.tsx @@ -7,6 +7,8 @@ import { ChartTooltipContent, } from '@/components/ui/chart' import { formatShortDate, formatShortTime } from '@/lib/utils' +import { useEffect } from 'react' +import Spinner from '../spinner' // for (const data of chartData) { // data.month = formatDateShort(data.month) // } @@ -18,26 +20,26 @@ const chartConfig = { }, } satisfies ChartConfig -export default function ({ chartData }: { chartData: { time: string; cpu: number }[] }) { +export default function ({ + chartData, + max, +}: { + chartData: { time: string; cpu: number }[] + max: number +}) { + if (!chartData?.length) { + return + } + return ( - + `${v}%`} /> {/* todo: short time if first date is same day, otherwise short date */} diff --git a/site/src/components/charts/disk-chart.tsx b/site/src/components/charts/disk-chart.tsx index bf405d7..b4023b9 100644 --- a/site/src/components/charts/disk-chart.tsx +++ b/site/src/components/charts/disk-chart.tsx @@ -8,6 +8,7 @@ import { } from '@/components/ui/chart' import { formatShortDate, formatShortTime } from '@/lib/utils' import { useMemo } from 'react' +import Spinner from '../spinner' // for (const data of chartData) { // data.month = formatDateShort(data.month) // } @@ -37,6 +38,10 @@ export default function ({ // return ticks // }, [diskSize]) + if (!chartData.length) { + return + } + return ( + } + return ( diff --git a/site/src/components/logo.tsx b/site/src/components/logo.tsx new file mode 100644 index 0000000..3a2681f --- /dev/null +++ b/site/src/components/logo.tsx @@ -0,0 +1,18 @@ +export function Logo({ className }: { className?: string }) { + return ( + + + + ) +} + +export function Can({ className }: { className?: string }) { + return ( + + + + ) +} diff --git a/site/src/components/mode-toggle.tsx b/site/src/components/mode-toggle.tsx index 90e1157..8ce1f1b 100644 --- a/site/src/components/mode-toggle.tsx +++ b/site/src/components/mode-toggle.tsx @@ -1,4 +1,4 @@ -import { Moon, Sun } from 'lucide-react' +import { MoonStarIcon, Sun } from 'lucide-react' import { Button } from '@/components/ui/button' import { @@ -17,7 +17,7 @@ export function ModeToggle() { diff --git a/site/src/components/routes/server.tsx b/site/src/components/routes/server.tsx index 82bb280..61a1d6e 100644 --- a/site/src/components/routes/server.tsx +++ b/site/src/components/routes/server.tsx @@ -1,5 +1,5 @@ import { $servers, pb } from '@/lib/stores' -import { ContainerStatsRecord, SystemRecord, SystemStats, SystemStatsRecord } from '@/types' +import { ContainerStatsRecord, SystemRecord, SystemStatsRecord } from '@/types' import { Suspense, lazy, useEffect, useState } from 'react' import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '../ui/card' import { useStore } from '@nanostores/react' @@ -8,6 +8,7 @@ import CpuChart from '../charts/cpu-chart' import MemChart from '../charts/mem-chart' import DiskChart from '../charts/disk-chart' import ContainerCpuChart from '../charts/container-cpu-chart' +import { CpuIcon } from 'lucide-react' // const CpuChart = lazy(() => import('../cpu-chart')) @@ -29,7 +30,9 @@ export default function ServerDetail({ name }: { name: string }) { const [containers, setContainers] = useState([] as ContainerStatsRecord[]) const [serverStats, setServerStats] = useState([] as SystemStatsRecord[]) - const [cpuChartData, setCpuChartData] = useState({} as { time: string; cpu: number }[]) + const [cpuChartData, setCpuChartData] = useState( + {} as { max: number; data: { time: string; cpu: number }[] } + ) const [memChartData, setMemChartData] = useState( {} as { time: string; mem: number; memUsed: number }[] ) @@ -40,6 +43,16 @@ export default function ServerDetail({ name }: { name: string }) { [] as Record[] ) + useEffect(() => { + document.title = name + return () => { + setContainerCpuChartData([]) + setCpuChartData({} as { max: number; data: { time: string; cpu: number }[] }) + setMemChartData([] as { time: string; mem: number; memUsed: number }[]) + setDiskChartData([] as { time: string; disk: number; diskUsed: number }[]) + } + }, [name]) + // get stats useEffect(() => { if (!('name' in server)) { @@ -71,15 +84,14 @@ export default function ServerDetail({ name }: { name: string }) { memData.push({ time: created, mem: stats.mem, memUsed: stats.memUsed }) diskData.push({ time: created, disk: stats.disk, diskUsed: stats.diskUsed }) } - setCpuChartData(cpuData.reverse()) + setCpuChartData({ + max: Math.ceil(Math.max(...cpuData.map((d) => d.cpu))), + data: cpuData.reverse(), + }) setMemChartData(memData.reverse()) setDiskChartData(diskData.reverse()) }, [serverStats]) - useEffect(() => { - document.title = name - }, [name]) - useEffect(() => { if ($servers.get().length === 0) { console.log('skipping') @@ -117,28 +129,44 @@ export default function ServerDetail({ name }: { name: string }) { for (let { created, stats } of containers) { let obj = { time: created } as Record for (let { name, cpu } of stats) { - obj[name] = cpu * 10 + obj[name] = cpu } containerCpuData.push(obj) } setContainerCpuChartData(containerCpuData.reverse()) - console.log('containerCpuData', containerCpuData) }, [containers]) return ( <> -
- +
+ - CPU Usage + + CPU Usage + + Average usage of the one minute preceding the recorded time - {/* }> */} - - {/* */} + }> + + + + + + + + Docker CPU Usage + + {' '} + CPU usage of docker containers + + + }> + + @@ -163,21 +191,6 @@ export default function ServerDetail({ name }: { name: string }) { {/* */} - - - Container CPU Usage - - Average usage of the one minute preceding the recorded time - - - - {/* }> */} - {containerCpuChartData.length > 0 && ( - - )} - {/* */} - -
diff --git a/site/src/components/server-table/data-table.tsx b/site/src/components/server-table/data-table.tsx index 2c65265..26d00fd 100644 --- a/site/src/components/server-table/data-table.tsx +++ b/site/src/components/server-table/data-table.tsx @@ -106,7 +106,7 @@ export default function () { // size: 70, accessorKey: 'name', cell: (info) => ( - +