mirror of https://github.com/buster-so/buster.git
data grid 2
This commit is contained in:
parent
49ec28142f
commit
4d85e27391
|
@ -36,6 +36,7 @@
|
||||||
"@tanstack/react-query-devtools": "^5.71.10",
|
"@tanstack/react-query-devtools": "^5.71.10",
|
||||||
"@tanstack/react-query-persist-client": "^5.71.10",
|
"@tanstack/react-query-persist-client": "^5.71.10",
|
||||||
"@tanstack/react-table": "^8.21.2",
|
"@tanstack/react-table": "^8.21.2",
|
||||||
|
"@tanstack/react-virtual": "^3.13.6",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/prettier": "^2.7.3",
|
"@types/prettier": "^2.7.3",
|
||||||
"@types/react-color": "^3.0.13",
|
"@types/react-color": "^3.0.13",
|
||||||
|
@ -6983,6 +6984,23 @@
|
||||||
"react-dom": ">=16.8"
|
"react-dom": ">=16.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tanstack/react-virtual": {
|
||||||
|
"version": "3.13.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.6.tgz",
|
||||||
|
"integrity": "sha512-WT7nWs8ximoQ0CDx/ngoFP7HbQF9Q2wQe4nh2NB+u2486eX3nZRE40P9g6ccCVq7ZfTSH5gFOuCoVH5DLNS/aA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tanstack/virtual-core": "3.13.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tanstack/store": {
|
"node_modules/@tanstack/store": {
|
||||||
"version": "0.7.0",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.7.0.tgz",
|
||||||
|
@ -7006,6 +7024,16 @@
|
||||||
"url": "https://github.com/sponsors/tannerlinsley"
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tanstack/virtual-core": {
|
||||||
|
"version": "3.13.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.6.tgz",
|
||||||
|
"integrity": "sha512-cnQUeWnhNP8tJ4WsGcYiX24Gjkc9ALstLbHcBj1t3E7EimN6n6kHH+DPV4PpDnuw00NApQp+ViojMj1GRdwYQg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@testing-library/dom": {
|
"node_modules/@testing-library/dom": {
|
||||||
"version": "10.4.0",
|
"version": "10.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
"@tanstack/react-query-devtools": "^5.71.10",
|
"@tanstack/react-query-devtools": "^5.71.10",
|
||||||
"@tanstack/react-query-persist-client": "^5.71.10",
|
"@tanstack/react-query-persist-client": "^5.71.10",
|
||||||
"@tanstack/react-table": "^8.21.2",
|
"@tanstack/react-table": "^8.21.2",
|
||||||
|
"@tanstack/react-virtual": "^3.13.6",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/prettier": "^2.7.3",
|
"@types/prettier": "^2.7.3",
|
||||||
"@types/react-color": "^3.0.13",
|
"@types/react-color": "^3.0.13",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { IDataResult } from '@/api/asset_interfaces';
|
import type { IDataResult } from '@/api/asset_interfaces/metric';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import isEmpty from 'lodash/isEmpty';
|
import isEmpty from 'lodash/isEmpty';
|
||||||
import { AppDataGrid } from '@/components/ui/table/AppDataGrid';
|
import { AppDataGrid } from '@/components/ui/table/AppDataGrid';
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { AppDataGrid2 } from './AppDataGrid2';
|
||||||
|
|
||||||
|
const meta: Meta<typeof AppDataGrid2> = {
|
||||||
|
title: 'UI/Table/AppDataGrid2',
|
||||||
|
component: AppDataGrid2,
|
||||||
|
parameters: {
|
||||||
|
layout: 'fullscreen'
|
||||||
|
},
|
||||||
|
tags: ['autodocs']
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof AppDataGrid2>;
|
||||||
|
|
||||||
|
const sampleData = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'John Doe',
|
||||||
|
age: 30,
|
||||||
|
email: 'john@example.com',
|
||||||
|
joinDate: new Date('2023-01-15').toISOString()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Jane Smith',
|
||||||
|
age: 25,
|
||||||
|
email: 'jane@example.com',
|
||||||
|
joinDate: new Date('2023-02-20').toISOString()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Bob Johnson',
|
||||||
|
age: 35,
|
||||||
|
email: 'bob@example.com',
|
||||||
|
joinDate: new Date('2023-03-10').toISOString()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: 'Alice Brown',
|
||||||
|
age: 28,
|
||||||
|
email: 'alice@example.com',
|
||||||
|
joinDate: new Date('2023-04-05').toISOString()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: 'Michael Wilson',
|
||||||
|
age: 42,
|
||||||
|
email: 'michael@example.com',
|
||||||
|
joinDate: new Date('2023-05-12').toISOString()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: 'Sarah Davis',
|
||||||
|
age: 31,
|
||||||
|
email: 'sarah@example.com',
|
||||||
|
joinDate: new Date('2023-06-08').toISOString()
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
args: {
|
||||||
|
rows: sampleData,
|
||||||
|
resizable: true,
|
||||||
|
draggable: true,
|
||||||
|
sortable: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NonResizable: Story = {
|
||||||
|
args: {
|
||||||
|
rows: sampleData,
|
||||||
|
resizable: false,
|
||||||
|
draggable: true,
|
||||||
|
sortable: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NonDraggable: Story = {
|
||||||
|
args: {
|
||||||
|
rows: sampleData,
|
||||||
|
resizable: true,
|
||||||
|
draggable: false,
|
||||||
|
sortable: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NonSortable: Story = {
|
||||||
|
args: {
|
||||||
|
rows: sampleData,
|
||||||
|
resizable: true,
|
||||||
|
draggable: true,
|
||||||
|
sortable: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CustomColumnOrder: Story = {
|
||||||
|
args: {
|
||||||
|
rows: sampleData,
|
||||||
|
columnOrder: ['name', 'email', 'age', 'id', 'joinDate'],
|
||||||
|
resizable: true,
|
||||||
|
draggable: true,
|
||||||
|
sortable: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CustomColumnWidths: Story = {
|
||||||
|
args: {
|
||||||
|
rows: sampleData,
|
||||||
|
columnWidths: {
|
||||||
|
id: 70,
|
||||||
|
name: 180,
|
||||||
|
age: 80,
|
||||||
|
email: 220,
|
||||||
|
joinDate: 120
|
||||||
|
},
|
||||||
|
resizable: true,
|
||||||
|
draggable: true,
|
||||||
|
sortable: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CustomFormatting: Story = {
|
||||||
|
args: {
|
||||||
|
rows: sampleData,
|
||||||
|
headerFormat: (value, columnName) => columnName.toUpperCase(),
|
||||||
|
cellFormat: (value, columnName) => {
|
||||||
|
if (columnName === 'joinDate' && value instanceof Date) {
|
||||||
|
return value.toLocaleDateString();
|
||||||
|
}
|
||||||
|
if (columnName === 'age') {
|
||||||
|
return `${value} years`;
|
||||||
|
}
|
||||||
|
return String(value);
|
||||||
|
},
|
||||||
|
resizable: true,
|
||||||
|
draggable: true,
|
||||||
|
sortable: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithCallbacks: Story = {
|
||||||
|
args: {
|
||||||
|
rows: sampleData,
|
||||||
|
onReorderColumns: (columnIds) => console.log('Columns reordered:', columnIds),
|
||||||
|
onResizeColumns: (columnSizes) => console.log('Columns resized:', columnSizes),
|
||||||
|
onReady: () => console.log('Grid is ready'),
|
||||||
|
resizable: true,
|
||||||
|
draggable: true,
|
||||||
|
sortable: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ManyRows: Story = {
|
||||||
|
args: {
|
||||||
|
rows: Array.from({ length: 1000 }).map((_, index) => ({
|
||||||
|
id: index + 1,
|
||||||
|
name: `User ${index + 1}`,
|
||||||
|
age: Math.floor(Math.random() * 50) + 18,
|
||||||
|
email: `user${index + 1}@example.com`,
|
||||||
|
joinDate: new Date(
|
||||||
|
2023,
|
||||||
|
Math.floor(Math.random() * 12),
|
||||||
|
Math.floor(Math.random() * 28) + 1
|
||||||
|
).toISOString()
|
||||||
|
})),
|
||||||
|
resizable: true,
|
||||||
|
draggable: true,
|
||||||
|
sortable: true
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,268 @@
|
||||||
|
import React, { useMemo, useRef, useState, useEffect, CSSProperties } from 'react';
|
||||||
|
import {
|
||||||
|
ColumnDef,
|
||||||
|
flexRender,
|
||||||
|
getCoreRowModel,
|
||||||
|
getSortedRowModel,
|
||||||
|
useReactTable,
|
||||||
|
SortingState
|
||||||
|
} from '@tanstack/react-table';
|
||||||
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||||
|
import {
|
||||||
|
DndContext,
|
||||||
|
MouseSensor,
|
||||||
|
TouchSensor,
|
||||||
|
KeyboardSensor,
|
||||||
|
useSensor,
|
||||||
|
useSensors,
|
||||||
|
closestCenter,
|
||||||
|
DragEndEvent
|
||||||
|
} from '@dnd-kit/core';
|
||||||
|
import { arrayMove, SortableContext, horizontalListSortingStrategy } from '@dnd-kit/sortable';
|
||||||
|
import { useSortable } from '@dnd-kit/sortable';
|
||||||
|
import { CSS } from '@dnd-kit/utilities';
|
||||||
|
import sampleSize from 'lodash/sampleSize';
|
||||||
|
import { defaultCellFormat, defaultHeaderFormat } from './helpers';
|
||||||
|
import { cn } from '@/lib/classMerge';
|
||||||
|
import { restrictToHorizontalAxis } from '@dnd-kit/modifiers';
|
||||||
|
|
||||||
|
export interface AppDataGridProps {
|
||||||
|
className?: string;
|
||||||
|
resizable?: boolean;
|
||||||
|
draggable?: boolean;
|
||||||
|
sortable?: boolean;
|
||||||
|
rows: Record<string, string | number | null | Date>[];
|
||||||
|
columnOrder?: string[];
|
||||||
|
columnWidths?: Record<string, number>;
|
||||||
|
headerFormat?: (value: any, columnName: string) => string;
|
||||||
|
cellFormat?: (value: any, columnName: string) => string;
|
||||||
|
onReorderColumns?: (columnIds: string[]) => void;
|
||||||
|
onReady?: () => void;
|
||||||
|
onResizeColumns?: (
|
||||||
|
columnSizes: {
|
||||||
|
key: string;
|
||||||
|
size: number;
|
||||||
|
}[]
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SortableHeaderProps {
|
||||||
|
header: any; // Header<any, unknown>
|
||||||
|
sortable: boolean;
|
||||||
|
resizable: boolean;
|
||||||
|
}
|
||||||
|
const SortableHeader: React.FC<SortableHeaderProps> = ({ header, sortable, resizable }) => {
|
||||||
|
// Set up dnd-kit’s useSortable for this header cell.
|
||||||
|
const { attributes, listeners, isDragging, setNodeRef, transform, transition } = useSortable({
|
||||||
|
id: header.id
|
||||||
|
});
|
||||||
|
const style: CSSProperties = {
|
||||||
|
opacity: isDragging ? 0.8 : 1,
|
||||||
|
position: 'relative',
|
||||||
|
transform: CSS.Translate.toString(transform), // translate instead of transform to avoid squishing
|
||||||
|
transition: 'width transform 0.2s ease-in-out',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
width: header.column.getSize(),
|
||||||
|
zIndex: isDragging ? 1 : 0,
|
||||||
|
boxShadow: isDragging ? '0 0 10px rgba(0, 0, 0, 0.5)' : 'none'
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={style}
|
||||||
|
className="relative flex items-center border bg-gray-100 p-2 select-none"
|
||||||
|
// onClick toggles sorting if enabled
|
||||||
|
onClick={header.column.getCanSort() ? header.column.getToggleSortingHandler() : undefined}>
|
||||||
|
<div className="flex-1" ref={setNodeRef} {...attributes} {...listeners}>
|
||||||
|
{flexRender(header.column.columnDef.header, header.getContext())}
|
||||||
|
{header.column.getIsSorted() === 'asc' && <span> 🔼</span>}
|
||||||
|
{header.column.getIsSorted() === 'desc' && <span> 🔽</span>}
|
||||||
|
</div>
|
||||||
|
{resizable && (
|
||||||
|
<div
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
}}>
|
||||||
|
<div
|
||||||
|
onMouseDown={header.getResizeHandler()}
|
||||||
|
onTouchStart={header.getResizeHandler()}
|
||||||
|
className="absolute top-0 right-0 h-full w-2 cursor-col-resize select-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AppDataGrid2: React.FC<AppDataGridProps> = React.memo(
|
||||||
|
({
|
||||||
|
className = '',
|
||||||
|
resizable = true,
|
||||||
|
draggable = true,
|
||||||
|
sortable = true,
|
||||||
|
columnWidths: columnWidthsProp,
|
||||||
|
columnOrder: serverColumnOrder,
|
||||||
|
onReorderColumns,
|
||||||
|
onResizeColumns,
|
||||||
|
onReady,
|
||||||
|
rows,
|
||||||
|
headerFormat = defaultHeaderFormat,
|
||||||
|
cellFormat = defaultCellFormat
|
||||||
|
}) => {
|
||||||
|
// Get a list of fields (each field becomes a column)
|
||||||
|
const fields = useMemo(() => {
|
||||||
|
return Object.keys(rows[0] || {});
|
||||||
|
}, [rows]);
|
||||||
|
|
||||||
|
// (Optional) Use a sample of rows for preview purposes.
|
||||||
|
const sampleOfRows = useMemo(() => sampleSize(rows, 15), [rows]);
|
||||||
|
|
||||||
|
// Set up initial states for sorting, column sizing, and column order.
|
||||||
|
const [sorting, setSorting] = useState<SortingState>([]);
|
||||||
|
const [columnSizing, setColumnSizing] = useState(() => {
|
||||||
|
const initial: Record<string, number> = {};
|
||||||
|
fields.forEach((field) => {
|
||||||
|
initial[field] = columnWidthsProp?.[field] || 100;
|
||||||
|
});
|
||||||
|
return initial;
|
||||||
|
});
|
||||||
|
const [colOrder, setColOrder] = useState<string[]>(serverColumnOrder || fields);
|
||||||
|
|
||||||
|
// Build columns from fields.
|
||||||
|
const columns = useMemo<ColumnDef<any, any>[]>(
|
||||||
|
() =>
|
||||||
|
fields.map((field) => ({
|
||||||
|
id: field,
|
||||||
|
accessorKey: field,
|
||||||
|
header: () => headerFormat(field, field),
|
||||||
|
cell: (info) => cellFormat(info.getValue(), field),
|
||||||
|
enableSorting: sortable,
|
||||||
|
enableResizing: resizable
|
||||||
|
})),
|
||||||
|
[fields, headerFormat, cellFormat, sortable, resizable]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create the table instance.
|
||||||
|
const table = useReactTable({
|
||||||
|
data: rows,
|
||||||
|
columns,
|
||||||
|
state: {
|
||||||
|
sorting,
|
||||||
|
columnSizing,
|
||||||
|
columnOrder: colOrder
|
||||||
|
},
|
||||||
|
onSortingChange: setSorting,
|
||||||
|
onColumnSizingChange: setColumnSizing,
|
||||||
|
onColumnOrderChange: setColOrder,
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
getSortedRowModel: getSortedRowModel(),
|
||||||
|
columnResizeMode: 'onChange'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Notify when column sizing changes.
|
||||||
|
useEffect(() => {
|
||||||
|
if (onResizeColumns) {
|
||||||
|
const sizes = Object.entries(columnSizing).map(([key, size]) => ({ key, size }));
|
||||||
|
onResizeColumns(sizes);
|
||||||
|
}
|
||||||
|
}, [columnSizing, onResizeColumns]);
|
||||||
|
|
||||||
|
// Call onReady when the table is first set up.
|
||||||
|
useEffect(() => {
|
||||||
|
if (onReady) onReady();
|
||||||
|
}, [onReady]);
|
||||||
|
|
||||||
|
// Set up dnd-kit sensors.
|
||||||
|
const sensors = useSensors(
|
||||||
|
useSensor(MouseSensor, {
|
||||||
|
activationConstraint: {
|
||||||
|
distance: 2
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
useSensor(TouchSensor, {
|
||||||
|
activationConstraint: {
|
||||||
|
distance: 2
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
useSensor(KeyboardSensor)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Handle drag end to reorder columns.
|
||||||
|
const handleDragEnd = (event: DragEndEvent) => {
|
||||||
|
const { active, over } = event;
|
||||||
|
if (active && over && active.id !== over.id) {
|
||||||
|
const oldIndex = colOrder.indexOf(active.id as string);
|
||||||
|
const newIndex = colOrder.indexOf(over.id as string);
|
||||||
|
const newOrder = arrayMove(colOrder, oldIndex, newIndex);
|
||||||
|
setColOrder(newOrder);
|
||||||
|
if (onReorderColumns) onReorderColumns(newOrder);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up the virtualizer for infinite scrolling.
|
||||||
|
const parentRef = useRef<HTMLDivElement>(null);
|
||||||
|
const rowVirtualizer = useVirtualizer({
|
||||||
|
count: table.getRowModel().rows.length,
|
||||||
|
getScrollElement: () => parentRef.current,
|
||||||
|
estimateSize: () => 35, // estimated row height
|
||||||
|
overscan: 5
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={parentRef} className={cn('h-full w-full overflow-auto', className)}>
|
||||||
|
{/* Header */}
|
||||||
|
<div className="sticky top-0 z-10 w-full bg-gray-100">
|
||||||
|
<DndContext
|
||||||
|
sensors={sensors}
|
||||||
|
modifiers={[restrictToHorizontalAxis]}
|
||||||
|
collisionDetection={closestCenter}
|
||||||
|
onDragEnd={handleDragEnd}>
|
||||||
|
<SortableContext
|
||||||
|
items={table.getHeaderGroups()[0]?.headers.map((header) => header.id) || []}
|
||||||
|
strategy={horizontalListSortingStrategy}>
|
||||||
|
<div className="flex">
|
||||||
|
{table
|
||||||
|
.getHeaderGroups()[0]
|
||||||
|
?.headers.map((header) => (
|
||||||
|
<SortableHeader
|
||||||
|
key={header.id}
|
||||||
|
header={header}
|
||||||
|
sortable={sortable}
|
||||||
|
resizable={resizable}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</SortableContext>
|
||||||
|
</DndContext>
|
||||||
|
</div>
|
||||||
|
{/* Body */}
|
||||||
|
<div className="relative" style={{ height: `${rowVirtualizer.getTotalSize()}px` }}>
|
||||||
|
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
|
||||||
|
const row = table.getRowModel().rows[virtualRow.index];
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={row.id}
|
||||||
|
className="absolute inset-x-0 flex"
|
||||||
|
style={{
|
||||||
|
transform: `translateY(${virtualRow.start}px)`,
|
||||||
|
height: `${virtualRow.size}px`
|
||||||
|
}}>
|
||||||
|
{row.getVisibleCells().map((cell) => (
|
||||||
|
<div
|
||||||
|
key={cell.id}
|
||||||
|
className="border p-2"
|
||||||
|
style={{ width: cell.column.getSize() }}>
|
||||||
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
AppDataGrid2.displayName = 'AppDataGrid2';
|
Loading…
Reference in New Issue