Files
MikrotikManager/components/data-grids/compact-data-grid.tsx
T

146 lines
4.7 KiB
TypeScript

"use client"
import { DataGridContainer, DataGridScrollArea, DataGridTable, dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid"
import { useMemo, useEffect, type ReactNode, type CSSProperties } from "react"
import {
type ColumnDef,
useTable,
} from "@tanstack/react-table"
import { DataGridShell } from "@/components/data-grids/shared/data-grid-shell"
import {
DATA_GRID_CELL_PAD,
DATA_GRID_CELL_PAD_FIRST,
DATA_GRID_CELL_PAD_LAST,
DEFAULT_DATA_GRID_LAYOUT,
} from "@/components/data-grids/shared/data-grid-layout"
import { DataGridSortHeader } from "@/components/data-grids/shared/data-grid-sort-header"
import { EmptyState } from "@/components/empty-state"
import { InboxIcon } from "lucide-react"
export interface CompactDataGridColumn<T> {
id: string
header: string
accessorKey?: keyof T & string
cell?: (row: T) => ReactNode
enableSorting?: boolean
size?: number
headerClassName?: string
cellClassName?: string
}
interface CompactDataGridProps<T extends { id: string }> {
data: T[]
columns: CompactDataGridColumn<T>[]
isLoading?: boolean
horizontalScroll?: boolean
pinnedColumnId?: string
emptyTitle?: string
emptyDescription?: string
onRowClick?: (row: T) => void
getExpandedContent?: (row: T) => ReactNode
}
function CompactDataGrid<T extends { id: string }>({
data,
columns,
isLoading,
horizontalScroll = false,
pinnedColumnId,
emptyTitle = "Нет записей",
emptyDescription,
onRowClick,
getExpandedContent,
}: CompactDataGridProps<T>) {
const columnDefs = useMemo<ColumnDef<DataGridFeatures, T>[]>(
() =>
columns.map((col, index) => ({
id: col.id,
size: col.size,
accessorKey: col.accessorKey ?? col.id,
header: ({ column }) => (
<DataGridSortHeader column={column} title={col.header} className={index === 0 ? "ml-1" : undefined} />
),
cell: ({ row }) => (col.cell ? col.cell(row.original) : String(row.getValue(col.id) ?? "—")),
enableSorting: col.enableSorting !== false,
meta: {
headerTitle: col.header,
headerClassName:
col.headerClassName ??
(index === 0
? DATA_GRID_CELL_PAD_FIRST
: index === columns.length - 1
? DATA_GRID_CELL_PAD_LAST
: DATA_GRID_CELL_PAD),
cellClassName:
col.cellClassName ??
(index === 0
? DATA_GRID_CELL_PAD_FIRST
: index === columns.length - 1
? DATA_GRID_CELL_PAD_LAST
: DATA_GRID_CELL_PAD),
...(getExpandedContent && index === 0
? { expandedContent: getExpandedContent }
: {}),
},
})),
[columns, getExpandedContent],
)
const table = useTable({
features: dataGridFeatures,
manualPagination: false,
autoResetPageIndex: false,
initialState: { pagination: { pageIndex: 0, pageSize: 50 }, columnPinning: { start: pinnedColumnId ? [pinnedColumnId] : [], end: [] } },
data,
columns: columnDefs,
getRowId: (row) => row.id,
...(getExpandedContent ? { getRowCanExpand: () => true } : {}),
})
const {pageIndex,pageSize}=table.state.pagination
useEffect(()=>{
const last=Math.max(0,Math.ceil(data.length/pageSize)-1)
if(pageIndex>last)table.setPageIndex(last)
},[data.length,pageSize,pageIndex,table])
return (
<DataGridShell
table={table}
recordCount={data.length}
tableLayout={pinnedColumnId ? { ...DEFAULT_DATA_GRID_LAYOUT, columnsPinnable: true } : undefined}
pagination={data.length > 50 || table.state.pagination.pageSize !== 50}
isLoading={isLoading}
loadingMode="skeleton"
onRowClick={
onRowClick ??
(getExpandedContent
? (row) => table.getRow(row.id).toggleExpanded()
: undefined)
}
emptyMessage={
<EmptyState
icon={<InboxIcon className="size-4" />}
title={emptyTitle}
description={emptyDescription}
className="border-0 py-10"
/>
}
>
{horizontalScroll ? (
<DataGridContainer border={false} className="w-full rounded-none border-0">
<DataGridScrollArea
orientation="horizontal"
className={pinnedColumnId ? "[&_[data-slot=scroll-area-viewport]]:[scroll-padding-inline-start:var(--pinned-column-width)]" : undefined}
style={pinnedColumnId ? { "--pinned-column-width": `${table.getColumn(pinnedColumnId)?.getSize() ?? 0}px` } as CSSProperties : undefined}
>
<DataGridTable />
</DataGridScrollArea>
</DataGridContainer>
) : undefined}
</DataGridShell>
)
}
export { CompactDataGrid, type CompactDataGridProps }