mirror of
https://github.com/fankes/beszel.git
synced 2025-10-19 01:39:34 +08:00
server table updates
This commit is contained in:
@@ -30,9 +30,9 @@ export function Home() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Dashboard</h1>
|
||||
<h1 class="my-5">Dashboard</h1>
|
||||
{systems.length && <DataTable data={systems} />}
|
||||
<pre>{JSON.stringify(systems, null, 2)}</pre>
|
||||
{/* <pre>{JSON.stringify(systems, null, 2)}</pre> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@@ -1,9 +1,14 @@
|
||||
import {
|
||||
CellContext,
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
getFilteredRowModel,
|
||||
SortingState,
|
||||
getSortedRowModel,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
useReactTable,
|
||||
Column,
|
||||
} from '@tanstack/react-table'
|
||||
|
||||
import {
|
||||
@@ -15,7 +20,22 @@ import {
|
||||
TableRow,
|
||||
} from '@/components/ui/table'
|
||||
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
|
||||
import { SystemRecord } from '@/types'
|
||||
import { MoreHorizontal, ArrowUpDown } from 'lucide-react'
|
||||
import { Link } from 'wouter-preact'
|
||||
import { useState } from 'preact/hooks'
|
||||
|
||||
function CellFormatter(info: CellContext<SystemRecord, unknown>) {
|
||||
const val = info.getValue() as number
|
||||
@@ -38,37 +58,103 @@ function CellFormatter(info: CellContext<SystemRecord, unknown>) {
|
||||
)
|
||||
}
|
||||
|
||||
function sortableHeader(column: Column<SystemRecord, unknown>, name: string) {
|
||||
return (
|
||||
<Button variant="ghost" onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}>
|
||||
{name}
|
||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
export function DataTable({ data }: { data: SystemRecord[] }) {
|
||||
// console.log('data', data)
|
||||
const columns: ColumnDef<SystemRecord>[] = [
|
||||
{
|
||||
header: 'Node',
|
||||
size: 40,
|
||||
accessorKey: 'name',
|
||||
cell: (info) => <strong>{info.getValue() as string}</strong>,
|
||||
header: ({ column }) => sortableHeader(column, 'Node'),
|
||||
},
|
||||
{
|
||||
header: 'CPU Load',
|
||||
accessorKey: 'stats.cpu',
|
||||
cell: CellFormatter,
|
||||
header: ({ column }) => sortableHeader(column, 'CPU'),
|
||||
},
|
||||
{
|
||||
header: 'RAM',
|
||||
accessorKey: 'stats.memPct',
|
||||
cell: CellFormatter,
|
||||
header: ({ column }) => sortableHeader(column, 'Memory'),
|
||||
},
|
||||
{
|
||||
header: 'Disk Usage',
|
||||
accessorKey: 'stats.diskPct',
|
||||
cell: CellFormatter,
|
||||
header: ({ column }) => sortableHeader(column, 'Disk'),
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
size: 32,
|
||||
maxSize: 32,
|
||||
cell: ({ row }) => {
|
||||
const system = row.original
|
||||
|
||||
return (
|
||||
<div class={'flex justify-end'}>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<Link class="w-full" href={`/server/${system.name}`}>
|
||||
View details
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => navigator.clipboard.writeText(system.id)}>
|
||||
Copy IP address
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Delete node</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const [sorting, setSorting] = useState<SortingState>([])
|
||||
|
||||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
onSortingChange: setSorting,
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-center py-4">
|
||||
<Input
|
||||
// @ts-ignore
|
||||
placeholder="Filter nodes..."
|
||||
value={(table.getColumn('name')?.getFilterValue() as string) ?? ''}
|
||||
onChange={(event: Event) => table.getColumn('name')?.setFilterValue(event.target.value)}
|
||||
className="max-w-sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="rounded-md border tabular-nums">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
@@ -76,7 +162,7 @@ export function DataTable({ data }: { data: SystemRecord[] }) {
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
<TableHead className="px-2" key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(header.column.columnDef.header, header.getContext())}
|
||||
@@ -91,7 +177,7 @@ export function DataTable({ data }: { data: SystemRecord[] }) {
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
<TableCell key={cell.id} style={{ width: `${cell.column.getSize()}px` }}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
@@ -107,5 +193,6 @@ export function DataTable({ data }: { data: SystemRecord[] }) {
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user