diff --git a/packages/app/src/components/DBRowTable.tsx b/packages/app/src/components/DBRowTable.tsx index a60bbb9cd..d3b96c9c9 100644 --- a/packages/app/src/components/DBRowTable.tsx +++ b/packages/app/src/components/DBRowTable.tsx @@ -300,6 +300,170 @@ const SqlModal = ({ ); }; +type VirtualRowProps = { + row: TableRow; + virtualIndex: number; + virtualKey: string | number; + isHighlighted: boolean; + isExpanded: boolean; + showExpandButton: boolean; + columnsLength: number; + wrapLinesEnabled: boolean; + tableContainerRef: HTMLDivElement | null; + getRowWhere?: (row: Record) => RowWhereResult; + sourceId?: string; + source?: TSource; + onRowExpandClick: (row: Record) => void; + onToggleWrap: () => void; + measureElement: (node: Element | null) => void; + renderRowDetails?: (row: { + id: string; + aliasWith?: WithClause[]; + [key: string]: any; + }) => React.ReactNode; +}; + +// Memoized row — flushSync from tanstack-virtual reconciles all mounted rows on +// every scroll; this lets React skip the ~90 unchanged ones. +const VirtualRow = memo( + ({ + row, + virtualIndex, + virtualKey, + isHighlighted, + isExpanded, + showExpandButton, + columnsLength, + wrapLinesEnabled, + tableContainerRef, + getRowWhere, + sourceId, + source, + onRowExpandClick, + onToggleWrap, + measureElement, + renderRowDetails, + }: VirtualRowProps) => { + const rowId = getRowId(row.original); + const visibleCells = row.getVisibleCells(); + + return ( + <> + + {showExpandButton && ( + + {flexRender( + visibleCells[0].column.columnDef.cell, + visibleCells[0].getContext(), + )} + + )} + + + + + + {showExpandButton && isExpanded && ( + + {renderRowDetails?.({ + id: rowId, + aliasWith: row.original[INTERNAL_ROW_FIELDS.ALIAS_WITH], + ...row.original, + })} + + )} + + ); + }, + (prev, next) => + prev.row.id === next.row.id && + prev.virtualIndex === next.virtualIndex && + prev.isHighlighted === next.isHighlighted && + prev.isExpanded === next.isExpanded && + prev.wrapLinesEnabled === next.wrapLinesEnabled && + prev.columnsLength === next.columnsLength && + prev.showExpandButton === next.showExpandButton && + prev.tableContainerRef === next.tableContainerRef, +); +VirtualRow.displayName = 'VirtualRow'; + export const RawLogTable = memo( ({ tableId, @@ -713,6 +877,10 @@ export const RawLogTable = memo( `${tableId}-wrap-lines`, wrapLines ?? false, ); + const onToggleWrap = useCallback( + () => setWrapLinesEnabled(prev => !prev), + [setWrapLinesEnabled], + ); const [showSql, setShowSql] = useState(false); const handleSqlModalOpen = (open: boolean) => { @@ -987,133 +1155,26 @@ export const RawLogTable = memo( {items.map(virtualRow => { const row = _rows[virtualRow.index] as TableRow; const rowId = getRowId(row.original); - const isExpanded = expandedRows[rowId] ?? false; - return ( - - - {/* Expand button cell */} - {showExpandButton && ( - - {flexRender( - row.getVisibleCells()[0].column.columnDef.cell, - row.getVisibleCells()[0].getContext(), - )} - - )} - - {/* Content columns grouped back to preserve row hover/click */} - - - - - {showExpandButton && isExpanded && ( - - {renderRowDetails?.({ - id: rowId, - aliasWith: - row.original[INTERNAL_ROW_FIELDS.ALIAS_WITH], - ...row.original, - })} - - )} - + ); })}