Move common table functions into base component
This commit is contained in:
parent
f7b8e34905
commit
b569ec31ae
4 changed files with 88 additions and 81 deletions
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Reference in a new issue