import React, {useEffect, useRef, useCallback} from 'react';
import {
useTable,
useExpanded,
useRowSelect,
usePagination,
useResizeColumns,
useSortBy,
useFlexLayout
} from 'react-table';
import { Checkbox, Spinner } from '@blueprintjs/core';
import classnames from 'classnames';
import { FixedSizeList } from 'react-window'
import { ConditionalWrapper } from 'utils';
import { useUpdateEffect } from 'hooks';
const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, ...rest }, ref) => {
return ();
}
);
export default function DataTable({
columns,
data,
loading,
onFetchData,
onSelectedRowsChange,
manualSortBy = 'false',
selectionColumn = false,
expandSubRows = true,
className,
noResults = 'This report does not contain any data.',
expanded = {},
rowClassNames,
stickyHeader = true,
virtualizedRows = false,
fixedSizeHeight = 100,
fixedItemSize = 30,
payload,
expandable = false,
expandToggleColumn = 2,
noInitialFetch = false,
spinnerProps = { size: 40 },
}) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
page,
rows,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
selectedFlatRows,
totalColumnsWidth,
getToggleAllRowsExpandedProps,
isAllRowsExpanded,
// Get the state from the instance
state: { pageIndex, pageSize, sortBy, selectedRowIds, selectedRows },
} = useTable(
{
columns,
data: data,
initialState: { pageIndex: 0, expanded }, // Pass our hoisted table state
manualPagination: true, // Tell the usePagination
// hook that we'll handle our own data fetching
// This means we'll also have to provide our own
// pageCount.
// pageCount: controlledPageCount,
getSubRows: row => row.children,
manualSortBy,
expandSubRows,
payload,
autoResetSelectedRows: false,
},
useSortBy,
useExpanded,
useRowSelect,
usePagination,
useResizeColumns,
useFlexLayout,
hooks => {
hooks.visibleColumns.push(columns => [
// Let's make a column for selection
...(selectionColumn) ? [{
id: 'selection',
disableResizing: true,
minWidth: 42,
width: 42,
maxWidth: 42,
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllRowsSelectedProps }) => (
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
),
className: 'selection',
...(typeof selectionColumn === 'object') ? selectionColumn : {},
}] : [],
...columns,
])
}
);
const isInitialMount = useRef(noInitialFetch);
// When these table states change, fetch new data!
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
onFetchData && onFetchData({ pageIndex, pageSize, sortBy })
}
}, [pageIndex, pageSize, sortBy]);
useUpdateEffect(() => {
onSelectedRowsChange && onSelectedRowsChange(selectedFlatRows);
}, [selectedRowIds, onSelectedRowsChange]);
// Renders table cell.
const RenderCell = useCallback(({ row, cell, index }) => (
({children}
)}
>
{
// Use the row.canExpand and row.getToggleRowExpandedProps prop getter
// to build the toggle for expanding a row
(row.canExpand && expandable && index === expandToggleColumn) && (
)
}
{ cell.render('Cell') }
), [expandable, expandToggleColumn]);
// Renders table row.
const RenderRow = useCallback(({ style = {}, row }) => {
prepareRow(row);
const rowClasses = rowClassNames && rowClassNames(row);
return (
{row.cells.map((cell, i) => {
const index = i + 1;
return
{ RenderCell({ cell, row, index }) }
})}
);
}, [prepareRow, rowClassNames, expandable, RenderCell, expandToggleColumn]);
// Renders virtualize circle table rows.
const RenderVirtualizedRows = useCallback(({ index, style }) => {
const row = rows[index];
return RenderRow({ row, style });
}, [RenderRow, rows]);
const RenderPage = useCallback(({ style, index } = {}) => {
return page.map((row, index) => RenderRow({ row }));
}, [RenderRow, page]);
// Renders fixed size tbody.
const RenderTBody = useCallback(() => {
return (virtualizedRows) ? (
{RenderVirtualizedRows}
) : RenderPage();
}, [fixedSizeHeight, rows, fixedItemSize, virtualizedRows,
RenderVirtualizedRows, RenderPage]);
return (
{headerGroups.map(headerGroup => (
{headerGroup.headers.map((column, index) => (
{(expandable && (index + 1) === expandToggleColumn) && (
)}
{column.render('Header')}
{column.isSorted && (
)}
{column.canResize && (
)}
))}
))}
{ !loading && RenderTBody() }
{ !loading && (page.length === 0) && (
)}
{ loading && (
) }
)
}