Openstatus www.openstatus.dev
at 0d239ea3d5b1c416d7932148029c5bc4cbc062af 168 lines 5.3 kB view raw
1"use client"; 2 3import type { 4 ColumnDef, 5 ColumnFiltersState, 6 ExpandedState, 7 PaginationState, 8 Row, 9 SortingState, 10 VisibilityState, 11} from "@tanstack/react-table"; 12import { 13 flexRender, 14 getCoreRowModel, 15 getExpandedRowModel, 16 getFilteredRowModel, 17 getPaginationRowModel, 18 getSortedRowModel, 19 useReactTable, 20} from "@tanstack/react-table"; 21import * as React from "react"; 22 23import { 24 Table, 25 TableBody, 26 TableCell, 27 TableHead, 28 TableHeader, 29 TableRow, 30} from "@openstatus/ui"; 31 32import { cn } from "@/lib/utils"; 33import { DataTablePagination } from "./data-table-pagination"; 34import { DataTableToolbar } from "./data-table-toolbar"; 35 36interface DataTableProps<TData, TValue> { 37 columns: ColumnDef<TData, TValue>[]; 38 data: TData[]; 39 renderSubComponent(props: { row: Row<TData> }): React.ReactElement<unknown>; 40 getRowCanExpand(row: Row<TData>): boolean; 41 autoResetExpanded?: boolean; 42 defaultColumnFilters?: ColumnFiltersState; 43 defaultPagination?: PaginationState; 44 defaultVisibility?: VisibilityState; 45 // allowedPeriods?: Period[]; REMIDNER: disabled unallowed periods 46} 47 48export function DataTable<TData, TValue>({ 49 columns, 50 data, 51 renderSubComponent, 52 getRowCanExpand, 53 autoResetExpanded, 54 defaultColumnFilters = [], 55 defaultPagination = { pageIndex: 0, pageSize: 10 }, 56 defaultVisibility = {}, 57}: DataTableProps<TData, TValue>) { 58 const [sorting, setSorting] = React.useState<SortingState>([]); 59 const [columnFilters, setColumnFilters] = 60 React.useState<ColumnFiltersState>(defaultColumnFilters); 61 const [expanded, setExpanded] = React.useState<ExpandedState>({}); 62 const [pagination, setPagination] = 63 React.useState<PaginationState>(defaultPagination); 64 const [columnVisibility, setColumnVisibility] = 65 React.useState<VisibilityState>(defaultVisibility); 66 67 const table = useReactTable({ 68 data, 69 columns, 70 getCoreRowModel: getCoreRowModel(), 71 onPaginationChange: setPagination, 72 getPaginationRowModel: getPaginationRowModel(), 73 onSortingChange: setSorting, 74 getSortedRowModel: getSortedRowModel(), 75 onColumnFiltersChange: setColumnFilters, 76 getFilteredRowModel: getFilteredRowModel(), 77 onExpandedChange: setExpanded, 78 getExpandedRowModel: getExpandedRowModel(), 79 onColumnVisibilityChange: setColumnVisibility, 80 getRowCanExpand, 81 autoResetExpanded, 82 state: { 83 sorting, 84 columnFilters, 85 expanded, 86 pagination, 87 columnVisibility, 88 }, 89 }); 90 91 return ( 92 <div className="space-y-3"> 93 <DataTableToolbar table={table} /> 94 <div className="rounded-md border"> 95 <Table> 96 <TableHeader className="bg-muted/50"> 97 {table.getHeaderGroups().map((headerGroup) => ( 98 <TableRow key={headerGroup.id}> 99 {headerGroup.headers.map((header) => { 100 return ( 101 <TableHead key={header.id}> 102 {header.isPlaceholder 103 ? null 104 : flexRender( 105 header.column.columnDef.header, 106 header.getContext(), 107 )} 108 </TableHead> 109 ); 110 })} 111 </TableRow> 112 ))} 113 </TableHeader> 114 <TableBody> 115 {table.getRowModel().rows?.length ? ( 116 table.getRowModel().rows.map((row) => ( 117 <React.Fragment key={row.id}> 118 <TableRow 119 data-state={ 120 (row.getIsSelected() || row.getIsExpanded()) && "selected" 121 } 122 onClick={() => { 123 if (!row.getCanExpand()) return; 124 // REMINDER: this is a workaround for single row expansion 125 if (!row.getIsExpanded()) table.resetExpanded(); 126 row.toggleExpanded(); 127 }} 128 className={cn(row.getCanExpand() && "cursor-pointer")} 129 > 130 {row.getVisibleCells().map((cell) => ( 131 <TableCell key={cell.id}> 132 {flexRender( 133 cell.column.columnDef.cell, 134 cell.getContext(), 135 )} 136 </TableCell> 137 ))} 138 </TableRow> 139 {row.getIsExpanded() && ( 140 <TableRow 141 data-state="expanded" 142 className="hover:bg-muted/10 data-[state=expanded]:bg-muted/10" 143 > 144 {/* 2nd row is a custom 1 cell row */} 145 <TableCell colSpan={row.getVisibleCells().length}> 146 {renderSubComponent({ row })} 147 </TableCell> 148 </TableRow> 149 )} 150 </React.Fragment> 151 )) 152 ) : ( 153 <TableRow> 154 <TableCell 155 colSpan={columns.length} 156 className="h-24 text-center" 157 > 158 No results. 159 </TableCell> 160 </TableRow> 161 )} 162 </TableBody> 163 </Table> 164 </div> 165 <DataTablePagination table={table} /> 166 </div> 167 ); 168}