site updates

This commit is contained in:
Henry Dollman
2024-07-11 22:17:09 -04:00
parent 82888684d9
commit 477428149a
15 changed files with 197 additions and 125 deletions

View File

@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Home</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />

1
site/public/favicon.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54.7 70" fill="#2D954F"><path d="M0 54.7V0h10.2v54.7a4.8 4.8 0 0 0 1.2 3.2 6.4 6.4 0 0 0 .3.4 5.6 5.6 0 0 0 1.5 1 4.7 4.7 0 0 0 2.1.5h29.3V0h10.1v59.8H44.6V70H15.3a16.7 16.7 0 0 1-4.8-.7 15.3 15.3 0 0 1-1.3-.5q-2.9-1.1-4.9-3.1a14 14 0 0 1-2.8-4 16.5 16.5 0 0 1-.4-.9 16 16 0 0 1-1-5.4 18.6 18.6 0 0 1-.1-.7Z"/></svg>

After

Width:  |  Height:  |  Size: 369 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 421.6 140.2"><path fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-width=".9" d="M0 109.4V0h20.4v109.4a9.6 9.6 0 0 0 2.4 6.4 12.8 12.8 0 0 0 .7.7q3.1 3.1 7.1 3.1h58.6V0h20.2v119.6H89.2V140H30.6a33.4 33.4 0 0 1-9.6-1.3 30.7 30.7 0 0 1-2.7-1 30 30 0 0 1-7-4 26.8 26.8 0 0 1-2.7-2.3 28.1 28.1 0 0 1-5.5-8 33 33 0 0 1-.8-1.7 32.2 32.2 0 0 1-2.3-11 37.1 37.1 0 0 1 0-1.3ZM307 0h20.4v73.8l58.4-30.6q2 0 3-.8t1.5-2q.5-1.2.6-2.5l.1-2.3V17.8l20.4-10.2v28a29.5 29.5 0 0 1-3.8 14.4 34.6 34.6 0 0 1-.1.2 26 26 0 0 1-11 10.5 31.6 31.6 0 0 1-.5.3l-17.8 10.2 43.4 68.8h-23l-38.2-58.6-28 12.8q-2 2-3.5 3.8a7 7 0 0 0-1 1.5 5.3 5.3 0 0 0-.5 2.3V140H307V0ZM127.6 109.4v-89h20.2V0H214q5.8 0 11.3 2.3 5.5 2.3 9.8 6.3a30 30 0 0 1 6.5 9 34.4 34.4 0 0 1 .4.7 29.3 29.3 0 0 1 2.6 12.2 33.4 33.4 0 0 1 0 .1v12.6a23.3 23.3 0 0 1-1.2 7.4 26.1 26.1 0 0 1-.1.2q-1.3 3.8-3.4 7.1-2.1 3.3-4.9 6.1a48.8 48.8 0 0 1-3.3 3 39.5 39.5 0 0 1-2.3 1.8l2.4 2.4q7.6 4 12.7 11a28 28 0 0 1 3.7 6.7 22.5 22.5 0 0 1 1.4 7.9v12.6a29.4 29.4 0 0 1-2.4 11.8 28.6 28.6 0 0 1-.2.5 30.7 30.7 0 0 1-5.3 8 28.7 28.7 0 0 1-1.6 1.7q-4.3 4-9.7 6.3-5.4 2.3-11.2 2.3h-63.6q-5.8 0-10.9-2.3-5.1-2.3-8.9-6.3a28 28 0 0 1-5-7.3 33.7 33.7 0 0 1-1-2.4 33.3 33.3 0 0 1-2.2-10.6 38.6 38.6 0 0 1 0-1.7Zm20.2-89V112q0 6 5 7.3a11.8 11.8 0 0 0 2.8.3h63.6a9.2 9.2 0 0 0 5.3-1.7 13 13 0 0 0 1.7-1.4 11.2 11.2 0 0 0 2.1-2.7 9 9 0 0 0 1.1-4.4V96.8q0-2-1.6-3.9a11 11 0 0 0 0 0 57.9 57.9 0 0 0-2.2-2.4 70.3 70.3 0 0 0-1.4-1.5l-17.8-7.6-43.2 23v-23l56-30.4q1.6 0 3-2.3a12.4 12.4 0 0 0 .4-.6 18.3 18.3 0 0 0 .8-1.6q.7-1.8.8-3.1a5.2 5.2 0 0 0 0-.2V30.6a9.6 9.6 0 0 0-2.4-6.4 12.8 12.8 0 0 0-.7-.7q-3.1-3.1-7.1-3.1h-66.2ZM266.4 0H287v140.2h-20.6V0Z" font-size="12" vector-effect="non-scaling-stroke"/></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -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'

View File

@@ -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<string, number | string>[] }) {
const [containerNames, setContainerNames] = useState([] as string[])
export default function ({
chartData,
max,
}: {
chartData: Record<string, number | string>[]
max: number
}) {
const chartConfig = useMemo(() => {
console.log('chartData', chartData)
let config = {} as Record<
string,
{
@@ -24,13 +26,21 @@ export default function ({ chartData }: { chartData: Record<string, number | str
color: string
}
>
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<string, number>
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<string, number | str
color: `hsl(${hue}, 60%, 60%)`,
}
}
console.log('config', config)
return config satisfies ChartConfig
}, [chartData])
if (!containerNames.length) {
return null
if (!chartData.length) {
return <Spinner />
}
return (
@@ -53,20 +62,23 @@ export default function ({ chartData }: { chartData: Record<string, number | str
<AreaChart
accessibilityLayer
data={chartData}
margin={{
left: 12,
right: 12,
top: 12,
}}
// reverseStackOrder={true}
>
<CartesianGrid vertical={false} />
{/* <YAxis domain={[0, 250]} tickCount={5} tickLine={false} axisLine={false} tickMargin={8} /> */}
<XAxis
dataKey="time"
<YAxis
domain={[0, max]}
tickCount={5}
tickLine={false}
axisLine={false}
tickFormatter={(v) => `${v}%`}
/>
<XAxis
dataKey="time"
tickLine={true}
axisLine={false}
tickMargin={8}
minTickGap={30}
tickFormatter={formatShortTime}
/>
<ChartTooltip
@@ -76,19 +88,13 @@ export default function ({ chartData }: { chartData: Record<string, number | str
// console.log('itemSorter', item)
// return -item.value
// }}
content={
<ChartTooltipContent
// itemSorter={(item) => {
// console.log('itemSorter', item)
// return -item.value
// }}
indicator="line"
/>
}
content={<ChartTooltipContent indicator="line" />}
/>
{containerNames.map((key) => (
{Object.keys(chartConfig).map((key) => (
<Area
key={key}
// isAnimationActive={false}
animateNewValues={false}
dataKey={key}
type="natural"
fill={chartConfig[key].color}
@@ -97,15 +103,6 @@ export default function ({ chartData }: { chartData: Record<string, number | str
stackId="a"
/>
))}
{/* <Area
dataKey="other"
type="natural"
fill="var(--color-other)"
fillOpacity={0.4}
stroke="var(--color-other)"
stackId="a"
/> */}
{/* <ChartLegend content={<ChartLegendContent />} className="flex-wrap gap-y-2 mb-2" /> */}
</AreaChart>
</ChartContainer>
)

View File

@@ -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 <Spinner />
}
return (
<ChartContainer config={chartConfig} className="h-full w-full absolute aspect-auto">
<AreaChart
accessibilityLayer
data={chartData}
margin={{
left: 0,
right: 0,
top: 7,
bottom: 7,
}}
>
<AreaChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<YAxis
domain={[0, 100]}
domain={[0, max]}
tickCount={5}
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={(v) => `${v}%`}
/>
{/* todo: short time if first date is same day, otherwise short date */}

View File

@@ -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 <Spinner />
}
return (
<ChartContainer config={chartConfig} className="h-full w-full absolute aspect-auto">
<AreaChart
@@ -45,14 +50,13 @@ export default function ({
margin={{
left: 0,
right: 0,
top: 7,
bottom: 7,
top: 0,
bottom: 0,
}}
>
<CartesianGrid vertical={false} />
<YAxis
domain={[0, diskSize]}
tickCount={10}
// ticks={ticks}
tickLine={false}
axisLine={false}

View File

@@ -8,6 +8,7 @@ import {
} from '@/components/ui/chart'
import { formatShortDate, formatShortTime } from '@/lib/utils'
import { useMemo } from 'react'
import Spinner from '../spinner'
const chartConfig = {
memUsed: {
@@ -25,6 +26,10 @@ export default function ({
return Math.ceil(chartData[0]?.mem)
}, [chartData])
if (!chartData.length) {
return <Spinner />
}
return (
<ChartContainer config={chartConfig} className="h-full w-full absolute aspect-auto">
<AreaChart
@@ -33,8 +38,8 @@ export default function ({
margin={{
left: 0,
right: 0,
top: 7,
bottom: 7,
top: 0,
bottom: 0,
}}
>
<CartesianGrid vertical={false} />

View File

@@ -0,0 +1,18 @@
export function Logo({ className }: { className?: string }) {
return (
<svg viewBox="0 0 421.6 140.2" className={className}>
<path d="M0 109.4V0h20.4v109.4a9.6 9.6 0 0 0 2.4 6.4 12.8 12.8 0 0 0 .7.7q3.1 3.1 7.1 3.1h58.6V0h20.2v119.6H89.2V140H30.6a33.4 33.4 0 0 1-9.6-1.3 30.7 30.7 0 0 1-2.7-1 30 30 0 0 1-7-4 26.8 26.8 0 0 1-2.7-2.3 28.1 28.1 0 0 1-5.5-8 33 33 0 0 1-.8-1.7 32.2 32.2 0 0 1-2.3-11 37.1 37.1 0 0 1 0-1.3ZM307 0h20.4v73.8l58.4-30.6q2 0 3-.8t1.5-2q.5-1.2.6-2.5l.1-2.3V17.8l20.4-10.2v28a29.5 29.5 0 0 1-3.8 14.4 34.6 34.6 0 0 1-.1.2 26 26 0 0 1-11 10.5 31.6 31.6 0 0 1-.5.3l-17.8 10.2 43.4 68.8h-23l-38.2-58.6-28 12.8q-2 2-3.5 3.8a7 7 0 0 0-1 1.5 5.3 5.3 0 0 0-.5 2.3V140H307V0ZM127.6 109.4v-89h20.2V0H214q5.8 0 11.3 2.3 5.5 2.3 9.8 6.3a30 30 0 0 1 6.5 9 34.4 34.4 0 0 1 .4.7 29.3 29.3 0 0 1 2.6 12.2 33.4 33.4 0 0 1 0 .1v12.6a23.3 23.3 0 0 1-1.2 7.4 26.1 26.1 0 0 1-.1.2q-1.3 3.8-3.4 7.1-2.1 3.3-4.9 6.1a48.8 48.8 0 0 1-3.3 3 39.5 39.5 0 0 1-2.3 1.8l2.4 2.4q7.6 4 12.7 11a28 28 0 0 1 3.7 6.7 22.5 22.5 0 0 1 1.4 7.9v12.6a29.4 29.4 0 0 1-2.4 11.8 28.6 28.6 0 0 1-.2.5 30.7 30.7 0 0 1-5.3 8 28.7 28.7 0 0 1-1.6 1.7q-4.3 4-9.7 6.3-5.4 2.3-11.2 2.3h-63.6q-5.8 0-10.9-2.3-5.1-2.3-8.9-6.3a28 28 0 0 1-5-7.3 33.7 33.7 0 0 1-1-2.4 33.3 33.3 0 0 1-2.2-10.6 38.6 38.6 0 0 1 0-1.7Zm20.2-89V112q0 6 5 7.3a11.8 11.8 0 0 0 2.8.3h63.6a9.2 9.2 0 0 0 5.3-1.7 13 13 0 0 0 1.7-1.4 11.2 11.2 0 0 0 2.1-2.7 9 9 0 0 0 1.1-4.4V96.8q0-2-1.6-3.9a11 11 0 0 0 0 0 57.9 57.9 0 0 0-2.2-2.4 70.3 70.3 0 0 0-1.4-1.5l-17.8-7.6-43.2 23v-23l56-30.4q1.6 0 3-2.3a12.4 12.4 0 0 0 .4-.6 18.3 18.3 0 0 0 .8-1.6q.7-1.8.8-3.1a5.2 5.2 0 0 0 0-.2V30.6a9.6 9.6 0 0 0-2.4-6.4 12.8 12.8 0 0 0-.7-.7q-3.1-3.1-7.1-3.1h-66.2ZM266.4 0H287v140.2h-20.6V0Z" />
</svg>
)
}
export function Can({ className }: { className?: string }) {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" className={className}>
<path
fill="currentColor"
d="M9.5 4a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1M11 2.5a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0m0 2a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0m2-3a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0m0 2a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0m0 2a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0m-3.02.87v.07l.01.02.01.04v6.75A1.75 1.75 0 0 1 8.25 15h-3.5A1.75 1.75 0 0 1 3 13.25V6.46l.01-.02a.5.5 0 0 1 .14-.3L5 4.3V2.5a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v1.8l1.85 1.85a.5.5 0 0 1 .12.22M7 3H6v1h1zm.3 2H5.7l-1 1h3.6zm.95 9a.75.75 0 0 0 .75-.75V7H4v6.25c0 .41.34.75.75.75z"
/>
</svg>
)
}

View File

@@ -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() {
<DropdownMenuTrigger asChild>
<Button variant={'ghost'} size="icon">
<Sun className="h-[1.2rem] w-[1.2rem] dark:opacity-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] opacity-0 dark:opacity-100" />
<MoonStarIcon className="absolute h-[1.2rem] w-[1.2rem] opacity-0 dark:opacity-100" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>

View File

@@ -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<string, number | string>[]
)
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<string, number | string>
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 (
<>
<div className="grid grid-cols-2 gap-6 mb-10">
<Card className="pb-2 col-span-2">
<div className="grid gap-6 mb-10">
<Card className="pb-2">
<CardHeader>
<CardTitle>CPU Usage</CardTitle>
<CardTitle className="flex gap-2 justify-between">
<span>CPU Usage</span>
<CpuIcon className="opacity-70" />
</CardTitle>
<CardDescription>
Average usage of the one minute preceding the recorded time
</CardDescription>
</CardHeader>
<CardContent className={'pl-1 w-[calc(100%-2em)] h-52 relative'}>
{/* <Suspense fallback={<Spinner />}> */}
<CpuChart chartData={cpuChartData} />
{/* </Suspense> */}
<Suspense fallback={<Spinner />}>
<CpuChart chartData={cpuChartData.data} max={cpuChartData.max} />
</Suspense>
</CardContent>
</Card>
<Card className="pb-2">
<CardHeader>
<CardTitle className="flex gap-2 justify-between">
<span>Docker CPU Usage</span>
<CpuIcon className="opacity-70" />
</CardTitle>{' '}
<CardDescription>CPU usage of docker containers</CardDescription>
</CardHeader>
<CardContent className={'pl-1 w-[calc(100%-2em)] h-52 relative'}>
<Suspense fallback={<Spinner />}>
<ContainerCpuChart chartData={containerCpuChartData} max={cpuChartData.max} />
</Suspense>
</CardContent>
</Card>
<Card className="pb-2">
@@ -163,21 +191,6 @@ export default function ServerDetail({ name }: { name: string }) {
{/* </Suspense> */}
</CardContent>
</Card>
<Card className="pb-2 col-span-2">
<CardHeader>
<CardTitle>Container CPU Usage</CardTitle>
<CardDescription>
Average usage of the one minute preceding the recorded time
</CardDescription>
</CardHeader>
<CardContent className={'pl-1 w-[calc(100%-2em)] h-64 relative'}>
{/* <Suspense fallback={<Spinner />}> */}
{containerCpuChartData.length > 0 && (
<ContainerCpuChart chartData={containerCpuChartData} />
)}
{/* </Suspense> */}
</CardContent>
</Card>
</div>
<Card>

View File

@@ -106,7 +106,7 @@ export default function () {
// size: 70,
accessorKey: 'name',
cell: (info) => (
<span className="flex gap-1 items-center text-base">
<span className="flex gap-0.5 items-center text-base">
<span
className={cn(
'w-2.5 h-2.5 block left-0 rounded-full',
@@ -116,7 +116,7 @@ export default function () {
></span>
<Button
variant={'ghost'}
className="text-foreground/80 h-7 px-2 gap-1.5"
className="text-foreground/80 h-7 px-1.5 gap-1.5"
onClick={() => copyToClipboard(info.getValue() as string)}
>
{info.getValue() as string}

View File

@@ -42,7 +42,7 @@
--accent-foreground: 0 0% 98.04%;
--destructive: 0 56.48% 42.35%;
--destructive-foreground: 0 0% 98.04%;
--border: 240 2.86% 14%;
--border: 240 2.86% 12%;
--input: 240 3.7% 15.88%;
--ring: 240 4.88% 86%;
--radius: 0.8rem;

View File

@@ -3,13 +3,20 @@ 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 { $authenticated, $router } from './lib/stores.ts'
import { $authenticated, $router, navigate } from './lib/stores.ts'
import { ModeToggle } from './components/mode-toggle.tsx'
import { cn, updateServerList } from './lib/utils.ts'
import { buttonVariants } from './components/ui/button.tsx'
import { Github } from 'lucide-react'
import { useStore } from '@nanostores/react'
import { Toaster } from './components/ui/toaster.tsx'
import { Can, Logo } from './components/logo.tsx'
import {
TooltipProvider,
Tooltip,
TooltipTrigger,
TooltipContent,
} from '@/components/ui/tooltip.tsx'
const ServerDetail = lazy(() => import('./components/routes/server.tsx'))
const CommandPalette = lazy(() => import('./components/command-palette.tsx'))
@@ -42,31 +49,56 @@ const Layout = () => {
}
return (
<div className="container mt-7 mb-14 relative">
<div className="flex mb-4">
{/* <a
className={cn('', buttonVariants({ variant: 'ghost', size: 'icon' }))}
href="/"
title={'All servers'}
>
<HomeIcon className="h-[1.2rem] w-[1.2rem]" />
</a> */}
<div className={'flex gap-1 ml-auto'}>
<a
title={'Github'}
href={'https://github.com/henrygd'}
className={cn('', buttonVariants({ variant: 'ghost', size: 'icon' }))}
>
<Github className="h-[1.2rem] w-[1.2rem]" />
</a>
<ModeToggle />
<>
<div className="container">
<div className="flex items-center py-3.5 bg-card px-6 border bt-0 rounded-md my-5">
<TooltipProvider delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<a
href="/"
aria-label="Home"
onClick={(e) => {
e.preventDefault()
navigate('/')
}}
>
<Logo className="h-5 fill-foreground" />
</a>
</TooltipTrigger>
<TooltipContent>
<p>Home</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
<div className={'flex gap-1 ml-auto'}>
<TooltipProvider delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<a
title={'Github'}
aria-label="Github repo"
href={'https://github.com/henrygd'}
className={cn('', buttonVariants({ variant: 'ghost', size: 'icon' }))}
>
<Github className="h-[1.2rem] w-[1.2rem]" />
</a>
</TooltipTrigger>
<TooltipContent>
<p>Github Repository</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
<ModeToggle />
</div>
</div>
</div>
<App />
<CommandPalette />
<Toaster />
</div>
<div className="container mb-14 relative">
<App />
<CommandPalette />
<Toaster />
</div>
</>
)
}