site updates

This commit is contained in:
Henry Dollman
2024-07-10 16:09:08 -04:00
parent 307218d001
commit 96e4c3b9ea
7 changed files with 91 additions and 36 deletions

View File

@@ -2,20 +2,15 @@ import { useEffect } from 'react'
import { $servers, pb } from '@/lib/stores' 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 { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../ui/card'
import { useStore } from '@nanostores/react'
import { SystemRecord } from '@/types' import { SystemRecord } from '@/types'
import { updateServerList } from '@/lib/utils'
export function Home() { export function Home() {
const servers = useStore($servers)
// const [systems, setSystems] = useState([] as SystemRecord[])
useEffect(() => { useEffect(() => {
document.title = 'Home' document.title = 'Home'
}, []) }, [])
useEffect(() => { useEffect(updateServerList, [])
console.log('servers', servers)
}, [servers])
useEffect(() => { useEffect(() => {
pb.collection<SystemRecord>('systems').subscribe('*', (e) => { pb.collection<SystemRecord>('systems').subscribe('*', (e) => {
@@ -52,9 +47,9 @@ export function Home() {
<> <>
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className={'mb-3'}>All Servers</CardTitle> <CardTitle className={'mb-1.5'}>All Servers</CardTitle>
<CardDescription> <CardDescription>
Press{' '} Updated in real time. Press{' '}
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-0.5 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100"> <kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-0.5 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100">
<span className="text-xs"></span>K <span className="text-xs"></span>K
</kbd>{' '} </kbd>{' '}

View File

@@ -1,36 +1,77 @@
import { pb } from '@/lib/stores' import { $servers, pb } from '@/lib/stores'
import { SystemRecord } from '@/types' import { ContainerStatsRecord, SystemRecord } from '@/types'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useRoute } from 'wouter' import { useRoute } from 'wouter'
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '../ui/card' import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '../ui/card'
import { useStore } from '@nanostores/react'
function timestampToBrowserTime(timestamp: string) {
const date = new Date(timestamp)
return date.toLocaleString()
}
export function ServerDetail() { export function ServerDetail() {
const servers = useStore($servers)
const [_, params] = useRoute('/server/:name') const [_, params] = useRoute('/server/:name')
const [server, setServer] = useState({} as SystemRecord) const [server, setServer] = useState({} as SystemRecord)
const [containers, setContainers] = useState([] as ContainerStatsRecord[])
// const [serverId, setServerId] = useState('')
useEffect(() => { useEffect(() => {
document.title = params!.name document.title = params!.name
}, []) }, [])
useEffect(() => { useEffect(() => {
pb.collection<SystemRecord>('systems') if ($servers.get().length === 0) {
.getFirstListItem(`name="${params!.name}"`) console.log('skipping')
.then((record) => { return
setServer(record) }
console.log('running')
const matchingServer = servers.find((s) => s.name === params!.name) as SystemRecord
setServer(matchingServer)
console.log('matchingServer', matchingServer)
// pb.collection<SystemRecord>('systems')
// .getOne(serverId)
// .then((record) => {
// setServer(record)
// })
pb.collection<ContainerStatsRecord>('container_stats')
.getList(1, 2, {
filter: `system="${matchingServer.id}"`,
fields: 'created,stats',
sort: '-created',
}) })
}, []) .then((records) => {
console.log('records', records)
setContainers(records.items)
})
}, [servers])
return ( return (
<> <>
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className={'mb-3'}>{server.name}</CardTitle> <CardTitle className={'mb-3'}>{server.name}</CardTitle>
<CardDescription>5.342.34.234</CardDescription> <CardDescription>
{server.ip} - last updated: {timestampToBrowserTime(server.updated)}
</CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<pre>{JSON.stringify(server, null, 2)}</pre> <pre>{JSON.stringify(server, null, 2)}</pre>
</CardContent> </CardContent>
</Card> </Card>
<Card>
<CardHeader>
<CardTitle className={'mb-3'}>Containers</CardTitle>
</CardHeader>
<CardContent>
<pre>{JSON.stringify(containers, null, 2)}</pre>
</CardContent>
</Card>
</> </>
) )
} }

View File

@@ -239,7 +239,17 @@ export function DataTable() {
<TableBody> <TableBody>
{table.getRowModel().rows?.length ? ( {table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => ( table.getRowModel().rows.map((row) => (
<TableRow key={row.original.id} data-state={row.getIsSelected() && 'selected'}> <TableRow
key={row.original.id}
data-state={row.getIsSelected() && 'selected'}
className="cursor-pointer"
onClick={(e) => {
const target = e.target as HTMLElement
if (target.tagName !== 'BUTTON' && !target.hasAttribute('role')) {
navigate(`/server/${row.original.name}`)
}
}}
>
{row.getVisibleCells().map((cell) => ( {row.getVisibleCells().map((cell) => (
<TableCell <TableCell
key={cell.id} key={cell.id}

View File

@@ -23,7 +23,7 @@ const ThemeProviderContext = createContext<ThemeProviderState>(initialState)
export function ThemeProvider({ export function ThemeProvider({
children, children,
defaultTheme = 'system', defaultTheme = 'system',
storageKey = 'vite-ui-theme', storageKey = 'ui-theme',
...props ...props
}: ThemeProviderProps) { }: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>( const [theme, setTheme] = useState<Theme>(
@@ -62,10 +62,4 @@ export function ThemeProvider({
) )
} }
export const useTheme = () => { export const useTheme = () => useContext(ThemeProviderContext)
const context = useContext(ThemeProviderContext)
if (context === undefined) throw new Error('useTheme must be used within a ThemeProvider')
return context
}

View File

@@ -1,6 +1,8 @@
import { toast } from '@/components/ui/use-toast' import { toast } from '@/components/ui/use-toast'
import { type ClassValue, clsx } from 'clsx' import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge' import { twMerge } from 'tailwind-merge'
import { $servers, pb } from './stores'
import { SystemRecord } from '@/types'
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)) return twMerge(clsx(inputs))
@@ -21,3 +23,11 @@ export async function copyToClipboard(content: string) {
}) })
} }
} }
export const updateServerList = () => {
pb.collection<SystemRecord>('systems')
.getFullList({ sort: '+name' })
.then((records) => {
$servers.set(records)
})
}

View File

@@ -5,15 +5,14 @@ import { Route, Switch } from 'wouter'
import { Home } from './components/routes/home.tsx' import { Home } from './components/routes/home.tsx'
import { ThemeProvider } from './components/theme-provider.tsx' import { ThemeProvider } from './components/theme-provider.tsx'
import LoginPage from './components/login.tsx' import LoginPage from './components/login.tsx'
import { $authenticated, $servers, pb } from './lib/stores.ts' import { $authenticated } from './lib/stores.ts'
import { ServerDetail } from './components/routes/server.tsx' import { ServerDetail } from './components/routes/server.tsx'
import { ModeToggle } from './components/mode-toggle.tsx' import { ModeToggle } from './components/mode-toggle.tsx'
import { CommandPalette } from './components/command-palette.tsx' import { CommandPalette } from './components/command-palette.tsx'
import { cn } from './lib/utils.ts' import { cn, updateServerList } from './lib/utils.ts'
import { buttonVariants } from './components/ui/button.tsx' import { buttonVariants } from './components/ui/button.tsx'
import { Github } from 'lucide-react' import { Github } from 'lucide-react'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
import { SystemRecord } from './types'
import { Toaster } from './components/ui/toaster.tsx' import { Toaster } from './components/ui/toaster.tsx'
const App = () => { const App = () => {
@@ -24,13 +23,7 @@ const App = () => {
const Main = () => { const Main = () => {
// get servers // get servers
useEffect(() => { useEffect(updateServerList, [])
pb.collection<SystemRecord>('systems')
.getFullList({ sort: '+name' })
.then((records) => {
$servers.set(records)
})
}, [])
return ( return (
<div className="container mt-7 mb-14"> <div className="container mt-7 mb-14">

12
site/src/types.d.ts vendored
View File

@@ -17,3 +17,15 @@ export interface SystemStats {
memPct: number memPct: number
memUsed: number memUsed: number
} }
export interface ContainerStatsRecord extends RecordModel {
system: string
stats: ContainerStats
}
interface ContainerStats {
name: string
cpu: number
mem: number
mempct: number
}