Spaces:
Sleeping
Sleeping
File size: 5,054 Bytes
c40c75a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
import { Fragment, useEffect } from "react";
import {
ColumnDef,
flexRender,
getCoreRowModel,
getExpandedRowModel,
Row,
useReactTable,
} from "@tanstack/react-table";
import {
Table,
TableHead,
TableHeaderCell,
TableBody,
TableRow,
TableCell,
} from "@tremor/react";
interface DataTableProps<TData, TValue> {
data: TData[];
columns: ColumnDef<TData, TValue>[];
renderSubComponent: (props: { row: Row<TData> }) => React.ReactElement;
getRowCanExpand: (row: Row<TData>) => boolean;
isLoading?: boolean;
expandedRequestId?: string | null;
onRowExpand?: (requestId: string | null) => void;
setSelectedKeyIdInfoView?: (keyId: string | null) => void;
loadingMessage?: string;
noDataMessage?: string;
}
export function DataTable<TData extends { request_id: string }, TValue>({
data = [],
columns,
getRowCanExpand,
renderSubComponent,
isLoading = false,
expandedRequestId,
onRowExpand,
loadingMessage = "π
Loading logs...",
noDataMessage = "No logs found",
}: DataTableProps<TData, TValue>) {
const table = useReactTable({
data,
columns,
getRowCanExpand,
getCoreRowModel: getCoreRowModel(),
getExpandedRowModel: getExpandedRowModel(),
state: {
expanded: expandedRequestId
? data.reduce((acc, row, index) => {
if (row.request_id === expandedRequestId) {
acc[index] = true;
}
return acc;
}, {} as Record<string, boolean>)
: {},
},
onExpandedChange: (updater) => {
if (!onRowExpand) return;
// Get current expanded state
const currentExpanded = expandedRequestId
? data.reduce((acc, row, index) => {
if (row.request_id === expandedRequestId) {
acc[index] = true;
}
return acc;
}, {} as Record<string, boolean>)
: {};
// Calculate new expanded state
const newExpanded = typeof updater === 'function'
? updater(currentExpanded)
: updater;
// If empty, it means we're closing the expanded row
if (Object.keys(newExpanded).length === 0) {
onRowExpand(null);
return;
}
// Find the request_id of the expanded row
const expandedIndex = Object.keys(newExpanded)[0];
const expandedRow = expandedIndex !== undefined ? data[parseInt(expandedIndex)] : null;
// Call the onRowExpand callback with the request_id
onRowExpand(expandedRow ? expandedRow.request_id : null);
},
});
// No need for the useEffect here as we're handling everything in onExpandedChange
return (
<div className="rounded-lg custom-border">
<Table className="[&_td]:py-0.5 [&_th]:py-1">
<TableHead>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHeaderCell key={header.id} className="py-1 h-8">
{header.isPlaceholder ? null : (
flexRender(
header.column.columnDef.header,
header.getContext()
)
)}
</TableHeaderCell>
);
})}
</TableRow>
))}
</TableHead>
<TableBody>
{isLoading ?
<TableRow>
<TableCell colSpan={columns.length} className="h-8 text-center">
<div className="text-center text-gray-500">
<p>{loadingMessage}</p>
</div>
</TableCell>
</TableRow>
: table.getRowModel().rows.length > 0 ?
table.getRowModel().rows.map((row) => (
<Fragment key={row.id}>
<TableRow className="h-8">
{row.getVisibleCells().map((cell) => (
<TableCell
key={cell.id}
className="py-0.5 max-h-8 overflow-hidden text-ellipsis whitespace-nowrap"
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</TableCell>
))}
</TableRow>
{row.getIsExpanded() && (
<TableRow>
<TableCell colSpan={row.getVisibleCells().length}>
{renderSubComponent({ row })}
</TableCell>
</TableRow>
)}
</Fragment>
))
: <TableRow>
<TableCell colSpan={columns.length} className="h-8 text-center">
<div className="text-center text-gray-500">
<p>{noDataMessage}</p>
</div>
</TableCell>
</TableRow>
}
</TableBody>
</Table>
</div>
);
}
|