From c7aa83f8d3ef01d64538e83405addfde0ff4daf2 Mon Sep 17 00:00:00 2001 From: Leon Sorokin Date: Wed, 16 Jul 2025 19:11:28 -0500 Subject: [PATCH] TableNG: Use Set for tracking expanded rows (#108198) --- .../src/components/Table/TableNG/TableNG.tsx | 22 ++++++++++--------- .../src/components/Table/TableNG/hooks.ts | 6 ++--- .../src/components/Table/TableNG/utils.ts | 6 ++--- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx b/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx index ea128eddafb..012424e1e28 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx @@ -159,7 +159,7 @@ export function TableNG(props: TableNGProps) { const defaultRowHeight = getDefaultRowHeight(theme, cellHeight); const defaultHeaderHeight = getDefaultRowHeight(theme, TableCellHeight.Sm); const [isInspecting, setIsInspecting] = useState(false); - const [expandedRows, setExpandedRows] = useState>({}); + const [expandedRows, setExpandedRows] = useState(() => new Set()); // vt scrollbar accounting for column auto-sizing const visibleFields = useMemo(() => getVisibleFields(data.fields), [data.fields]); @@ -517,12 +517,19 @@ export function TableNG(props: TableNGProps) { }, renderCell: ({ row }) => { if (row.__depth === 0) { + const rowIdx = row.__index; + return ( { - setExpandedRows({ ...expandedRows, [row.__index]: !expandedRows[row.__index] }); + if (expandedRows.has(rowIdx)) { + expandedRows.delete(rowIdx); + } else { + expandedRows.add(rowIdx); + } + setExpandedRows(new Set(expandedRows)); }} /> ); @@ -710,16 +717,11 @@ export function TableNG(props: TableNGProps) { * this is passed to the top-level `renderRow` prop on DataGrid. applies aria attributes and custom event handlers. */ const renderRowFactory = - ( - fields: Field[], - panelContext: PanelContext, - expandedRows: Record, - enableSharedCrosshair: boolean - ) => + (fields: Field[], panelContext: PanelContext, expandedRows: Set, enableSharedCrosshair: boolean) => (key: React.Key, props: RenderRowProps): React.ReactNode => { const { row } = props; const rowIdx = row.__index; - const isExpanded = !!expandedRows[rowIdx]; + const isExpanded = expandedRows.has(rowIdx); // Don't render non expanded child rows if (row.__depth === 1 && !isExpanded) { diff --git a/packages/grafana-ui/src/components/Table/TableNG/hooks.ts b/packages/grafana-ui/src/components/Table/TableNG/hooks.ts index c4bcabe0828..252eb362e14 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/hooks.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/hooks.ts @@ -441,7 +441,7 @@ interface UseRowHeightOptions { hasNestedFrames: boolean; defaultHeight: number; headerHeight: number; - expandedRows: Record; + expandedRows: Set; typographyCtx: TypographyCtx; } @@ -497,9 +497,9 @@ export function useRowHeight({ return (row: TableRow) => { // nested rows - if (Number(row.__depth) > 0) { + if (row.__depth > 0) { // if unexpanded, height === 0 - if (!expandedRows[row.__index]) { + if (!expandedRows.has(row.__index)) { return 0; } diff --git a/packages/grafana-ui/src/components/Table/TableNG/utils.ts b/packages/grafana-ui/src/components/Table/TableNG/utils.ts index 1cd6d279856..191e9fa76e4 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/utils.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/utils.ts @@ -512,10 +512,10 @@ export const processNestedTableRows = ( const childRows: Map = new Map(); for (const row of rows) { - if (Number(row.__depth) === 0) { + if (row.__depth === 0) { parentRows.push(row); } else { - childRows.set(Number(row.__index), row); + childRows.set(row.__index, row); } } @@ -526,7 +526,7 @@ export const processNestedTableRows = ( const result: TableRow[] = []; processedParents.forEach((row) => { result.push(row); - const childRow = childRows.get(Number(row.__index)); + const childRow = childRows.get(row.__index); if (childRow) { result.push(childRow); }