import { ColumnDef, ColumnFiltersState, getFilteredRowModel, SortingState, getSortedRowModel, flexRender, VisibilityState, getCoreRowModel, useReactTable, Row, Table as TableType, } from "@tanstack/react-table" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Button } from "@/components/ui/button" import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { SystemRecord } from "@/types" import { ArrowUpDownIcon, LayoutGridIcon, LayoutListIcon, ArrowDownIcon, ArrowUpIcon, Settings2Icon, EyeIcon, FilterIcon, } from "lucide-react" import { memo, useEffect, useMemo, useState } from "react" import { $systems } from "@/lib/stores" import { useStore } from "@nanostores/react" import { cn, runOnce, useLocalStorage } from "@/lib/utils" import { $router, Link } from "../router" import { useLingui, Trans } from "@lingui/react/macro" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card" import { Input } from "@/components/ui/input" import { getPagePath } from "@nanostores/router" import SystemsTableColumns, { ActionsButton, IndicatorDot } from "./systems-table-columns" import AlertButton from "../alerts/alert-button" import { SystemStatus } from "@/lib/enums" type ViewMode = "table" | "grid" type StatusFilter = "all" | "up" | "down" | "paused" const preloadSystemDetail = runOnce(() => import("@/components/routes/system.tsx")) export default function SystemsTable() { const data = useStore($systems) const { i18n, t } = useLingui() const [filter, setFilter] = useState() const [statusFilter, setStatusFilter] = useState("all") const [sorting, setSorting] = useState([{ id: "system", desc: false }]) const [columnFilters, setColumnFilters] = useState([]) const [columnVisibility, setColumnVisibility] = useLocalStorage("cols", {}) const [viewMode, setViewMode] = useLocalStorage("viewMode", window.innerWidth > 1024 ? "table" : "grid") const locale = i18n.locale // Filter data based on status filter const filteredData = useMemo(() => { if (statusFilter === "all") { return data } return data.filter((system) => system.status === statusFilter) }, [data, statusFilter]) useEffect(() => { if (filter !== undefined) { table.getColumn("system")?.setFilterValue(filter) } }, [filter]) const columnDefs = useMemo(() => SystemsTableColumns(viewMode), [viewMode]) const table = useReactTable({ data: filteredData, columns: columnDefs, getCoreRowModel: getCoreRowModel(), onSortingChange: setSorting, getSortedRowModel: getSortedRowModel(), onColumnFiltersChange: setColumnFilters, getFilteredRowModel: getFilteredRowModel(), onColumnVisibilityChange: setColumnVisibility, state: { sorting, columnFilters, columnVisibility, }, defaultColumn: { // sortDescFirst: true, invertSorting: true, sortUndefined: "last", minSize: 0, size: 900, maxSize: 900, }, }) const rows = table.getRowModel().rows const columns = table.getAllColumns() const visibleColumns = table.getVisibleLeafColumns() // TODO: hiding temp then gpu messes up table headers const CardHead = useMemo(() => { return (
All Systems Updated in real time. Click on a system to view information.
setFilter(e.target.value)} className="px-4" />
Layout setViewMode(view as ViewMode)} > e.preventDefault()} className="gap-2"> Table e.preventDefault()} className="gap-2"> Grid
Status setStatusFilter(value as StatusFilter)} > e.preventDefault()}> All Systems e.preventDefault()}> Up e.preventDefault()}> Down e.preventDefault()}> Paused
Sort By
{columns.map((column) => { if (!column.getCanSort()) return null let Icon = // if current sort column, show sort direction if (sorting[0]?.id === column.id) { if (sorting[0]?.desc) { Icon = } else { Icon = } } return ( { e.preventDefault() setSorting([{ id: column.id, desc: sorting[0]?.id === column.id && !sorting[0]?.desc }]) }} key={column.id} > {Icon} {/* @ts-ignore */} {column.columnDef.name()} ) })}
Visible Fields
{columns .filter((column) => column.getCanHide()) .map((column) => { return ( e.preventDefault()} checked={column.getIsVisible()} onCheckedChange={(value) => column.toggleVisibility(!!value)} > {/* @ts-ignore */} {column.columnDef.name()} ) })}
) }, [visibleColumns.length, sorting, viewMode, locale, statusFilter]) return ( {CardHead}
{viewMode === "table" ? ( // table layout
) : ( // grid layout
{rows?.length ? ( rows.map((row) => { return }) ) : (
No systems found.
)}
)}
) } const AllSystemsTable = memo( ({ table, rows, colLength }: { table: TableType; rows: Row[]; colLength: number }) => { return ( {rows.length ? ( rows.map((row) => ( )) ) : ( No systems found. )}
) } ) function SystemsTableHead({ table, colLength }: { table: TableType; colLength: number }) { const { i18n } = useLingui() return useMemo(() => { return ( {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => { return ( {flexRender(header.column.columnDef.header, header.getContext())} ) })} ))} ) }, [i18n.locale, colLength]) } const SystemTableRow = memo( ({ row, length, colLength }: { row: Row; length: number; colLength: number }) => { const system = row.original const { t } = useLingui() return useMemo(() => { return ( {row.getVisibleCells().map((cell) => ( 10 ? "py-2" : "py-2.5"} > {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} ) }, [system, system.status, colLength, t]) } ) const SystemCard = memo( ({ row, table, colLength }: { row: Row; table: TableType; colLength: number }) => { const system = row.original const { t } = useLingui() return useMemo(() => { return (
{system.name}
{table.getColumn("actions")?.getIsVisible() && (
)}
{table.getAllColumns().map((column) => { if (!column.getIsVisible() || column.id === "system" || column.id === "actions") return null const cell = row.getAllCells().find((cell) => cell.column.id === column.id) if (!cell) return null // @ts-ignore const { Icon, name } = column.columnDef as ColumnDef return (
{column.id === "lastSeen" ? ( ) : ( Icon && )}
{name()}:
{flexRender(cell.column.columnDef.cell, cell.getContext())}
) })}
{row.original.name}
) }, [system, colLength, t]) } )