diff --git a/src/components/InfiniteTable/InfiniteTable.tsx b/src/components/InfiniteTable/InfiniteTable.tsx index 753099f..113533c 100644 --- a/src/components/InfiniteTable/InfiniteTable.tsx +++ b/src/components/InfiniteTable/InfiniteTable.tsx @@ -47,6 +47,9 @@ export type InfiniteTableProps = Omit< onAllRowSelectedModeChange?: (allRowSelectedMode: boolean) => void; footer?: React.ReactNode; footerHeight?: number; + hasStatusColumn?: boolean; + onRowStatus?: (item: any) => any; + statusComponent?: (status: any) => React.ReactNode; }; export type InfiniteTableRef = { @@ -73,6 +76,9 @@ const InfiniteTableComp = forwardRef( allRowSelectedMode: allRowSelectedModeProps, footer, footerHeight = 50, + onRowStatus, + statusComponent, + hasStatusColumn = false, } = props; const gridRef = useRef(null); @@ -88,6 +94,7 @@ const InfiniteTableComp = forwardRef( gridRef, containerRef, columnsPersistedStateRef, + hasStatusColumn, }); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -144,41 +151,60 @@ const InfiniteTableComp = forwardRef( const defaultColDef = useMemo(() => ({}), []); const colDefs = useMemo((): ColDef[] => { + const checkboxColumn = { + checkboxSelection: true, + suppressMovable: true, + sortable: false, + lockPosition: true, + pinned: "left", + maxWidth: 50, + resizable: false, + headerComponent: () => ( + 0 + } + allRowSelectedMode={allRowSelectedMode} + onHeaderCheckboxChange={onHeaderCheckboxChange} + /> + ), + } as ColDef; + + const restOfColumns = columns.map((column) => ({ + field: column.key, + sortable: false, + headerName: column.title, + cellRenderer: column.render + ? (cell: any) => column.render(cell.value) + : undefined, + })); + + const statusColumn = { + field: "$status", + suppressMovable: true, + sortable: false, + lockPosition: true, + maxWidth: 50, + pinned: "left", + resizable: false, + headerComponent: () => null, + cellRenderer: (cell: any) => statusComponent?.(cell.value), + } as ColDef; + return [ - { - checkboxSelection: true, - suppressMovable: true, - sortable: false, - lockPosition: true, - pinned: "left", - maxWidth: 50, - resizable: false, - headerComponent: () => ( - 0 - } - allRowSelectedMode={allRowSelectedMode} - onHeaderCheckboxChange={onHeaderCheckboxChange} - /> - ), - }, - ...columns.map((column) => ({ - field: column.key, - sortable: false, - headerName: column.title, - cellRenderer: column.render - ? (cell: any) => column.render(cell.value) - : undefined, - })), + checkboxColumn, + ...(hasStatusColumn ? [statusColumn] : []), + ...restOfColumns, ]; }, [ allRowSelectedMode, columns, + hasStatusColumn, internalSelectedRowKeys.length, onHeaderCheckboxChange, + statusComponent, totalRows, ]); @@ -191,7 +217,22 @@ const InfiniteTableComp = forwardRef( if (data.length < endRow - startRow) { lastRow = startRow + data.length; } - params.successCallback(data, lastRow); + + // We must call onRowStatus for each item of the data array and merge the result + // with the data array + const finalData = hasStatusColumn + ? await Promise.all( + data.map(async (item) => { + const status = await onRowStatus?.(item); + return { + ...item, + $status: status, + }; + }), + ) + : data; + + params.successCallback(finalData, lastRow); if (allRowSelectedModeRef.current) { gridRef?.current?.api.forEachNode((node) => { node.setSelected(true); @@ -219,8 +260,10 @@ const InfiniteTableComp = forwardRef( }, [ autoSizeColumnsIfNecessary, + hasStatusColumn, onGetSelectedRowKeys, onRequestData, + onRowStatus, selectedRowKeysPendingToRender, setSelectedRowKeysPendingToRender, ], diff --git a/src/components/InfiniteTable/useAutoFitColumns.ts b/src/components/InfiniteTable/useAutoFitColumns.ts index 2d9666b..40ea020 100644 --- a/src/components/InfiniteTable/useAutoFitColumns.ts +++ b/src/components/InfiniteTable/useAutoFitColumns.ts @@ -6,13 +6,20 @@ export const useAutoFitColumns = ({ gridRef, containerRef, columnsPersistedStateRef, + hasStatusColumn, }: { gridRef: RefObject; containerRef: RefObject; columnsPersistedStateRef: RefObject; + hasStatusColumn: boolean; }) => { const firstTimeResized = useRef(false); + const columnsToIgnore = ["0"]; // 0 is for header checkbox column + if (hasStatusColumn) { + columnsToIgnore.push("$status"); + } + const remainingBlankSpace = useCallback( (allColumns: Array>) => { const totalColumnWidth = allColumns?.reduce( @@ -36,12 +43,14 @@ export const useAutoFitColumns = ({ if (!allColumns) return; const blankSpace = remainingBlankSpace(allColumns); if (blankSpace > 0) { - const spacePerColumn = blankSpace / (allColumns.length - 1); // we skip the first checkbox column, since it's not resizable + const spacePerColumn = + blankSpace / (allColumns.length - columnsToIgnore.length); const state = gridRef?.current?.api.getColumnState()!; const newState = state.map((col: any) => ({ ...col, - // colId 0 is the checkbox column - width: col.colId !== "0" ? col.width + spacePerColumn : col.width, + width: columnsToIgnore.includes(col.colId) + ? col.width + : col.width + spacePerColumn, })); gridRef?.current?.api.applyColumnState({ state: newState }); } diff --git a/src/stories/InfiniteTable.stories.tsx b/src/stories/InfiniteTable.stories.tsx index d84170a..5d6a87f 100644 --- a/src/stories/InfiniteTable.stories.tsx +++ b/src/stories/InfiniteTable.stories.tsx @@ -88,6 +88,10 @@ export const HeavyTable = (): React.ReactElement => { return columnsState ? JSON.parse(columnsState) : undefined; }} footer={

This is a footer

} + onRowStatus={(record: any) => { + return record.id; + }} + statusComponent={(status: any) => {status}} /> );