Move common table functions into base component

This commit is contained in:
jeffvli 2023-01-06 17:59:02 -08:00
parent f7b8e34905
commit b569ec31ae
4 changed files with 88 additions and 81 deletions

View file

@ -1,10 +1,14 @@
import { Ref, forwardRef, useRef } from 'react'; import { Ref, forwardRef, useRef, useEffect, useCallback, useMemo } from 'react';
import type { import type {
ICellRendererParams, ICellRendererParams,
ValueGetterParams, ValueGetterParams,
IHeaderParams, IHeaderParams,
ValueFormatterParams, ValueFormatterParams,
ColDef, ColDef,
ColumnMovedEvent,
NewColumnsLoadedEvent,
GridReadyEvent,
GridSizeChangedEvent,
} from '@ag-grid-community/core'; } from '@ag-grid-community/core';
import type { AgGridReactProps } from '@ag-grid-community/react'; import type { AgGridReactProps } from '@ag-grid-community/react';
import { AgGridReact } from '@ag-grid-community/react'; import { AgGridReact } from '@ag-grid-community/react';
@ -316,11 +320,25 @@ export const getColumnDefs = (columns: PersistedTableColumn[]) => {
}; };
interface VirtualTableProps extends AgGridReactProps { interface VirtualTableProps extends AgGridReactProps {
autoFitColumns?: boolean;
autoHeight?: boolean;
deselectOnClickOutside?: boolean; deselectOnClickOutside?: boolean;
} }
export const VirtualTable = forwardRef( export const VirtualTable = forwardRef(
({ deselectOnClickOutside, ...rest }: VirtualTableProps, ref: Ref<AgGridReactType | null>) => { (
{
autoFitColumns,
deselectOnClickOutside,
autoHeight,
onColumnMoved,
onNewColumnsLoaded,
onGridReady,
onGridSizeChanged,
...rest
}: VirtualTableProps,
ref: Ref<AgGridReactType | null>,
) => {
const tableRef = useRef<AgGridReactType | null>(null); const tableRef = useRef<AgGridReactType | null>(null);
const mergedRef = useMergedRef(ref, tableRef); const mergedRef = useMergedRef(ref, tableRef);
@ -329,6 +347,58 @@ export const VirtualTable = forwardRef(
return deselectOnClickOutside ? tableRef?.current?.api?.deselectAll() : undefined; return deselectOnClickOutside ? tableRef?.current?.api?.deselectAll() : undefined;
}); });
const defaultColumnDefs: ColDef = useMemo(() => {
return {
lockPinned: true,
lockVisible: true,
resizable: true,
};
}, []);
// Auto fit columns on column change
useEffect(() => {
if (autoFitColumns) tableRef?.current?.api?.sizeColumnsToFit();
}, [autoFitColumns]);
// Reset row heights on row height change
useEffect(() => {
tableRef?.current?.api?.resetRowHeights();
tableRef?.current?.api?.redrawRows();
}, [rest.rowHeight]);
const handleColumnMoved = useCallback(
(e: ColumnMovedEvent) => {
onColumnMoved?.(e);
if (autoFitColumns) e.api.sizeColumnsToFit();
},
[autoFitColumns, onColumnMoved],
);
const handleNewColumnsLoaded = useCallback(
(e: NewColumnsLoadedEvent) => {
onNewColumnsLoaded?.(e);
if (autoFitColumns) e.api?.sizeColumnsToFit();
},
[autoFitColumns, onNewColumnsLoaded],
);
const handleGridReady = useCallback(
(e: GridReadyEvent) => {
onGridReady?.(e);
if (autoHeight) e.api.setDomLayout('autoHeight');
if (autoFitColumns) e.api.sizeColumnsToFit();
},
[autoHeight, autoFitColumns, onGridReady],
);
const handleGridSizeChanged = useCallback(
(e: GridSizeChangedEvent) => {
onGridSizeChanged?.(e);
if (autoFitColumns) e.api.sizeColumnsToFit();
},
[autoFitColumns, onGridSizeChanged],
);
return ( return (
<TableWrapper <TableWrapper
ref={deselectRef} ref={deselectRef}
@ -336,11 +406,22 @@ export const VirtualTable = forwardRef(
> >
<AgGridReact <AgGridReact
ref={mergedRef} ref={mergedRef}
animateRows
suppressContextMenu
suppressCopyRowsToClipboard
suppressMoveWhenRowDragging suppressMoveWhenRowDragging
suppressPaginationPanel
suppressScrollOnNewData suppressScrollOnNewData
defaultColDef={defaultColumnDefs}
enableCellChangeFlash={false}
headerHeight={36} headerHeight={36}
rowBuffer={30} rowBuffer={30}
rowSelection="multiple"
{...rest} {...rest}
onColumnMoved={handleColumnMoved}
onGridReady={handleGridReady}
onGridSizeChanged={handleGridSizeChanged}
onNewColumnsLoaded={handleNewColumnsLoaded}
/> />
</TableWrapper> </TableWrapper>
); );

View file

@ -60,14 +60,6 @@ export const AlbumDetailContent = ({ tableRef }: AlbumDetailContentProps) => {
[page.table.columns], [page.table.columns],
); );
const defaultColumnDefs: ColDef = useMemo(() => {
return {
lockPinned: true,
lockVisible: true,
resizable: true,
};
}, []);
const [pagination, setPagination] = useSetState({ const [pagination, setPagination] = useSetState({
artist: 0, artist: 0,
}); });
@ -223,33 +215,20 @@ export const AlbumDetailContent = ({ tableRef }: AlbumDetailContentProps) => {
<Box ref={tableContainerRef}> <Box ref={tableContainerRef}>
<VirtualTable <VirtualTable
ref={tableRef} ref={tableRef}
animateRows autoFitColumns
autoHeight
deselectOnClickOutside deselectOnClickOutside
detailRowAutoHeight
maintainColumnOrder
suppressCellFocus suppressCellFocus
suppressCopyRowsToClipboard
suppressHorizontalScroll suppressHorizontalScroll
suppressLoadingOverlay suppressLoadingOverlay
suppressMoveWhenRowDragging
suppressPaginationPanel
suppressRowDrag suppressRowDrag
suppressScrollOnNewData
columnDefs={columnDefs} columnDefs={columnDefs}
defaultColDef={defaultColumnDefs}
enableCellChangeFlash={false} enableCellChangeFlash={false}
getRowId={(data) => data.data.id} getRowId={(data) => data.data.id}
rowData={detailQuery.data?.songs} rowData={detailQuery.data?.songs}
rowHeight={60} rowHeight={60}
rowSelection="multiple" rowSelection="multiple"
onCellContextMenu={handleContextMenu} onCellContextMenu={handleContextMenu}
onGridReady={(params) => {
params.api.setDomLayout('autoHeight');
params.api.sizeColumnsToFit();
}}
onGridSizeChanged={(params) => {
params.api.sizeColumnsToFit();
}}
onRowDoubleClicked={handleRowDoubleClick} onRowDoubleClicked={handleRowDoubleClick}
/> />
</Box> </Box>

View file

@ -2,7 +2,6 @@ import type { Ref } from 'react';
import { useState, forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react'; import { useState, forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
import type { import type {
CellDoubleClickedEvent, CellDoubleClickedEvent,
ColDef,
RowClassRules, RowClassRules,
RowDragEvent, RowDragEvent,
RowNode, RowNode,
@ -68,13 +67,6 @@ export const PlayQueue = forwardRef(({ type }: QueueProps, ref: Ref<any>) => {
})); }));
const columnDefs = useMemo(() => getColumnDefs(tableConfig.columns), [tableConfig.columns]); const columnDefs = useMemo(() => getColumnDefs(tableConfig.columns), [tableConfig.columns]);
const defaultColumnDefs: ColDef = useMemo(() => {
return {
lockPinned: true,
lockVisible: true,
resizable: true,
};
}, []);
const handleDoubleClick = (e: CellDoubleClickedEvent) => { const handleDoubleClick = (e: CellDoubleClickedEvent) => {
const playerData = setCurrentTrack(e.data.uniqueId); const playerData = setCurrentTrack(e.data.uniqueId);
@ -196,20 +188,6 @@ export const PlayQueue = forwardRef(({ type }: QueueProps, ref: Ref<any>) => {
} }
}, [currentSong, previousSong, tableConfig.followCurrentSong]); }, [currentSong, previousSong, tableConfig.followCurrentSong]);
// Auto resize the columns when the column config changes
useEffect(() => {
if (tableConfig.autoFit) {
const { api } = tableRef?.current || {};
api?.sizeColumnsToFit();
}
}, [tableConfig.autoFit, tableConfig.columns]);
useEffect(() => {
const { api } = tableRef?.current || {};
api?.resetRowHeights();
api?.redrawRows();
}, [tableConfig.rowHeight]);
return ( return (
<ErrorBoundary FallbackComponent={ErrorFallback}> <ErrorBoundary FallbackComponent={ErrorFallback}>
<VirtualGridContainer> <VirtualGridContainer>
@ -217,23 +195,14 @@ export const PlayQueue = forwardRef(({ type }: QueueProps, ref: Ref<any>) => {
<VirtualTable <VirtualTable
ref={mergedRef} ref={mergedRef}
alwaysShowHorizontalScroll alwaysShowHorizontalScroll
animateRows
maintainColumnOrder
rowDragEntireRow rowDragEntireRow
rowDragMultiRow rowDragMultiRow
suppressCopyRowsToClipboard autoFitColumns={tableConfig.autoFit}
suppressMoveWhenRowDragging
suppressRowDrag
suppressScrollOnNewData
columnDefs={columnDefs} columnDefs={columnDefs}
defaultColDef={defaultColumnDefs}
enableCellChangeFlash={false}
getRowId={(data) => data.data.uniqueId} getRowId={(data) => data.data.uniqueId}
rowBuffer={30}
rowClassRules={rowClassRules} rowClassRules={rowClassRules}
rowData={queue} rowData={queue}
rowHeight={tableConfig.rowHeight || 40} rowHeight={tableConfig.rowHeight || 40}
rowSelection="multiple"
onCellDoubleClicked={handleDoubleClick} onCellDoubleClicked={handleDoubleClick}
onColumnMoved={handleColumnChange} onColumnMoved={handleColumnChange}
onColumnResized={debouncedColumnChange} onColumnResized={debouncedColumnChange}

View file

@ -87,14 +87,6 @@ export const PlaylistDetailContent = ({ tableRef }: PlaylistDetailContentProps)
[page.table.columns], [page.table.columns],
); );
const defaultColumnDefs: ColDef = useMemo(() => {
return {
lockPinned: true,
lockVisible: true,
resizable: true,
};
}, []);
const handleContextMenu = (e: CellContextMenuEvent) => { const handleContextMenu = (e: CellContextMenuEvent) => {
if (!e.event) return; if (!e.event) return;
const clickEvent = e.event as MouseEvent; const clickEvent = e.event as MouseEvent;
@ -268,21 +260,14 @@ export const PlaylistDetailContent = ({ tableRef }: PlaylistDetailContentProps)
<Box ref={tableContainerRef}> <Box ref={tableContainerRef}>
<VirtualTable <VirtualTable
ref={tableRef} ref={tableRef}
animateRows autoFitColumns
autoHeight
deselectOnClickOutside deselectOnClickOutside
detailRowAutoHeight
maintainColumnOrder
suppressCellFocus suppressCellFocus
suppressCopyRowsToClipboard
suppressHorizontalScroll suppressHorizontalScroll
suppressLoadingOverlay suppressLoadingOverlay
suppressMoveWhenRowDragging
suppressPaginationPanel
suppressRowDrag suppressRowDrag
suppressScrollOnNewData
columnDefs={columnDefs} columnDefs={columnDefs}
defaultColDef={defaultColumnDefs}
enableCellChangeFlash={false}
getRowId={(data) => { getRowId={(data) => {
// It's possible that there are duplicate song ids in a playlist // It's possible that there are duplicate song ids in a playlist
return `${data.data.id}-${data.data.pageIndex}`; return `${data.data.id}-${data.data.pageIndex}`;
@ -291,13 +276,6 @@ export const PlaylistDetailContent = ({ tableRef }: PlaylistDetailContentProps)
rowHeight={60} rowHeight={60}
rowSelection="multiple" rowSelection="multiple"
onCellContextMenu={handleContextMenu} onCellContextMenu={handleContextMenu}
onGridReady={(params) => {
params.api.setDomLayout('autoHeight');
params.api.sizeColumnsToFit();
}}
onGridSizeChanged={(params) => {
params.api.sizeColumnsToFit();
}}
onRowDoubleClicked={handleRowDoubleClick} onRowDoubleClicked={handleRowDoubleClick}
/> />
</Box> </Box>