From fa9e25786443da06b3d08b71cf29d6c9320c1c24 Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Wed, 10 Jul 2024 19:26:18 -0400 Subject: [PATCH] site updates --- site/bun.lockb | Bin 126391 -> 138189 bytes site/package.json | 7 +- site/src/components/command-palette.tsx | 5 +- site/src/components/cpu-chart.tsx | 117 ++++++ site/src/components/example-chart.tsx | 53 +++ site/src/components/loader.tsx | 0 site/src/components/login.tsx | 8 +- site/src/components/routes/home.tsx | 12 +- site/src/components/routes/server.tsx | 36 +- .../components/server-table/data-table.tsx | 11 +- site/src/components/spinner.tsx | 9 + site/src/components/ui/chart.tsx | 361 ++++++++++++++++++ site/src/index.css | 19 + site/src/lib/stores.ts | 13 + site/src/lib/utils.ts | 11 + site/src/main.tsx | 65 ++-- 16 files changed, 670 insertions(+), 57 deletions(-) create mode 100644 site/src/components/cpu-chart.tsx create mode 100644 site/src/components/example-chart.tsx create mode 100644 site/src/components/loader.tsx create mode 100644 site/src/components/spinner.tsx create mode 100644 site/src/components/ui/chart.tsx diff --git a/site/bun.lockb b/site/bun.lockb index 961a586c97aa565149a0af3e1650ed8683d6c1bc..5fde890fd74a5a7c91497fbab9eaf81cbcad590f 100755 GIT binary patch delta 32719 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 delta 25666 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 + + + + formatDateShort(value)} + /> + } /> + + + + ) +} diff --git a/site/src/components/example-chart.tsx b/site/src/components/example-chart.tsx new file mode 100644 index 0000000..5fbb4a6 --- /dev/null +++ b/site/src/components/example-chart.tsx @@ -0,0 +1,53 @@ +'use client' + +import { Bar, BarChart, CartesianGrid, XAxis } from 'recharts' + +import { + ChartConfig, + ChartContainer, + ChartLegend, + ChartLegendContent, + ChartTooltip, + ChartTooltipContent, +} from '@/components/ui/chart' + +const chartData = [ + { month: 'January', desktop: 186, mobile: 80 }, + { month: 'February', desktop: 305, mobile: 200 }, + { month: 'March', desktop: 237, mobile: 120 }, + { month: 'April', desktop: 73, mobile: 190 }, + { month: 'May', desktop: 209, mobile: 130 }, + { month: 'June', desktop: 214, mobile: 140 }, +] + +const chartConfig = { + desktop: { + label: 'Desktop', + color: '#2563eb', + }, + mobile: { + label: 'Mobile', + color: '#60a5fa', + }, +} satisfies ChartConfig + +export function Component() { + return ( + + + + value.slice(0, 3)} + /> + } /> + } /> + + + + + ) +} diff --git a/site/src/components/loader.tsx b/site/src/components/loader.tsx new file mode 100644 index 0000000..e69de29 diff --git a/site/src/components/login.tsx b/site/src/components/login.tsx index 996df0d..4aa4b2f 100644 --- a/site/src/components/login.tsx +++ b/site/src/components/login.tsx @@ -1,11 +1,9 @@ -import { Link } from 'wouter' - import { cn } from '@/lib/utils' import { buttonVariants } from '@/components/ui/button' import { UserAuthForm } from '@/components/user-auth-form' import { ChevronLeft } from 'lucide-react' -export default function LoginPage() { +export default function () { return ( diff --git a/site/src/components/routes/home.tsx b/site/src/components/routes/home.tsx index 68645bb..3a9a46c 100644 --- a/site/src/components/routes/home.tsx +++ b/site/src/components/routes/home.tsx @@ -1,11 +1,13 @@ -import { useEffect } from 'react' +import { Suspense, lazy, useEffect } from 'react' import { $servers, pb } from '@/lib/stores' -import { DataTable } from '../server-table/data-table' +// import { DataTable } from '../server-table/data-table' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../ui/card' import { SystemRecord } from '@/types' import { updateServerList } from '@/lib/utils' -export function Home() { +const DataTable = lazy(() => import('../server-table/data-table')) + +export default function () { useEffect(() => { document.title = 'Home' }, []) @@ -57,7 +59,9 @@ export function Home() { - + + + diff --git a/site/src/components/routes/server.tsx b/site/src/components/routes/server.tsx index 85cb68b..7cc0e20 100644 --- a/site/src/components/routes/server.tsx +++ b/site/src/components/routes/server.tsx @@ -1,24 +1,32 @@ import { $servers, pb } from '@/lib/stores' import { ContainerStatsRecord, SystemRecord } from '@/types' -import { useEffect, useState } from 'react' -import { useRoute } from 'wouter' +import { Suspense, lazy, useEffect, useState } from 'react' import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '../ui/card' import { useStore } from '@nanostores/react' +import Spinner from '../spinner' +// import { CpuChart } from '../cpu-chart' + +const CpuChart = lazy(() => import('../cpu-chart')) function timestampToBrowserTime(timestamp: string) { const date = new Date(timestamp) return date.toLocaleString() } -export function ServerDetail() { +// function addColors(objects: Record[]) { +// objects.forEach((obj, index) => { +// const hue = ((index * 360) / objects.length) % 360 // Distribute hues evenly +// obj.fill = `hsl(${hue}, 100%, 50%)` // Set fill to HSL color with full saturation and 50% lightness +// }) +// } + +export default function ServerDetail({ name }: { name: string }) { const servers = useStore($servers) - const [_, params] = useRoute('/server/:name') const [server, setServer] = useState({} as SystemRecord) const [containers, setContainers] = useState([] as ContainerStatsRecord[]) - // const [serverId, setServerId] = useState('') useEffect(() => { - document.title = params!.name + document.title = name }, []) useEffect(() => { @@ -27,7 +35,7 @@ export function ServerDetail() { return } console.log('running') - const matchingServer = servers.find((s) => s.name === params!.name) as SystemRecord + const matchingServer = servers.find((s) => s.name === name) as SystemRecord setServer(matchingServer) @@ -52,6 +60,20 @@ export function ServerDetail() { return ( <> +
+ + + CPU Usage + Showing total visitors for the last 30 minutes + + + }> + + + + +
+ {server.name} diff --git a/site/src/components/server-table/data-table.tsx b/site/src/components/server-table/data-table.tsx index 8653e54..2c65265 100644 --- a/site/src/components/server-table/data-table.tsx +++ b/site/src/components/server-table/data-table.tsx @@ -48,18 +48,15 @@ import { MoreHorizontal, ArrowUpDown, Copy, - RefreshCcw, Server, Cpu, MemoryStick, HardDrive, } from 'lucide-react' import { useMemo, useState } from 'react' -import { navigate } from 'wouter/use-browser-location' -import { $servers, pb } from '@/lib/stores' +import { $servers, pb, navigate } from '@/lib/stores' import { useStore } from '@nanostores/react' import { AddServerButton } from '../add-server' -import clsx from 'clsx' import { cn, copyToClipboard } from '@/lib/utils' function CellFormatter(info: CellContext) { @@ -74,7 +71,7 @@ function CellFormatter(info: CellContext) {
@@ -97,7 +94,7 @@ function sortableHeader(column: Column, name: string, Ico ) } -export function DataTable() { +export default function () { const data = useStore($servers) const [deleteServer, setDeleteServer] = useState({} as SystemRecord) const [sorting, setSorting] = useState([]) @@ -111,7 +108,7 @@ export function DataTable() { cell: (info) => ( + +
+ ) +} diff --git a/site/src/components/ui/chart.tsx b/site/src/components/ui/chart.tsx new file mode 100644 index 0000000..1b7cbc8 --- /dev/null +++ b/site/src/components/ui/chart.tsx @@ -0,0 +1,361 @@ +import * as React from "react" +import * as RechartsPrimitive from "recharts" + +import { cn } from "@/lib/utils" + +// Format: { THEME_NAME: CSS_SELECTOR } +const THEMES = { light: "", dark: ".dark" } as const + +export type ChartConfig = { + [k in string]: { + label?: React.ReactNode + icon?: React.ComponentType + } & ( + | { color?: string; theme?: never } + | { color?: never; theme: Record } + ) +} + +type ChartContextProps = { + config: ChartConfig +} + +const ChartContext = React.createContext(null) + +function useChart() { + const context = React.useContext(ChartContext) + + if (!context) { + throw new Error("useChart must be used within a ") + } + + return context +} + +const ChartContainer = React.forwardRef< + HTMLDivElement, + React.ComponentProps<"div"> & { + config: ChartConfig + children: React.ComponentProps< + typeof RechartsPrimitive.ResponsiveContainer + >["children"] + } +>(({ id, className, children, config, ...props }, ref) => { + const uniqueId = React.useId() + const chartId = `chart-${id || uniqueId.replace(/:/g, "")}` + + return ( + +
+ + + {children} + +
+
+ ) +}) +ChartContainer.displayName = "Chart" + +const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { + const colorConfig = Object.entries(config).filter( + ([_, config]) => config.theme || config.color + ) + + if (!colorConfig.length) { + return null + } + + return ( +
@@ -23,9 +21,9 @@ export default function LoginPage() {

- + Don't have an account? Sign Up - +