This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 4ae8fe71225 fix: size 'Drill to detail' table header correctly (#44807)
4ae8fe71225 is described below

commit 4ae8fe712250851cf285cdecafee336470179766
Author: mattmc3 <[email protected]>
AuthorDate: Thu Oct 1 19:50:28 2026 -0400

    fix: size 'Drill to detail' table header correctly (#44807)
---
 .../src/components/Table/VirtualTable.test.tsx     | 83 ++++++++++++++++++++++
 .../src/components/Table/VirtualTable.tsx          | 20 +++---
 2 files changed, 95 insertions(+), 8 deletions(-)

diff --git 
a/superset-frontend/packages/superset-ui-core/src/components/Table/VirtualTable.test.tsx
 
b/superset-frontend/packages/superset-ui-core/src/components/Table/VirtualTable.test.tsx
index f78c55a9381..1a984afd54f 100644
--- 
a/superset-frontend/packages/superset-ui-core/src/components/Table/VirtualTable.test.tsx
+++ 
b/superset-frontend/packages/superset-ui-core/src/components/Table/VirtualTable.test.tsx
@@ -20,6 +20,28 @@ import { render, screen, waitFor } from 
'@superset-ui/core/spec';
 import type { ColumnsType } from 'antd/es/table';
 import { Table } from './index';
 
+// jsdom never measures the container, so tests that need a width set this one.
+let mockTableWidth: number | undefined;
+jest.mock('react-resize-detector', () => {
+  const { useEffect } = jest.requireActual('react');
+  return {
+    useResizeDetector: ({
+      onResize,
+    }: {
+      onResize?: (width?: number) => void;
+    }) => {
+      useEffect(() => {
+        if (mockTableWidth !== undefined) onResize?.(mockTableWidth);
+      }, [onResize]);
+      return { ref: () => undefined };
+    },
+  };
+});
+
+afterEach(() => {
+  mockTableWidth = undefined;
+});
+
 // These tests exercise VirtualTable's react-window v2 `Grid` wiring
 // (`cellComponent`/`cellProps`/`gridRef`), which previously had no direct
 // coverage - `Table.test.tsx` only exercises the non-virtualized code path.
@@ -120,3 +142,64 @@ test('cell render functions receive their row data via 
cellProps rather than a s
     expect(screen.getByText('rendered:Number')).toBeInTheDocument();
   });
 });
+
+// The header is antd's own <table>; the body Grid is sized to the columns.
+const virtualHeaderWidth = (columns: ColumnsType<BasicData>) => {
+  const { container } = render(
+    <Table
+      columns={columns}
+      data={testData}
+      virtualize
+      height={200}
+      usePagination={false}
+    />,
+  );
+  return () =>
+    container
+      .querySelector<HTMLTableElement>('.virtual-table thead')
+      ?.closest('table')?.style.width;
+};
+
+test('virtualized table header is as wide as its columns, not the viewport', 
async () => {
+  const width = virtualHeaderWidth(testColumns);
+  await waitFor(() => expect(width()).toBe('300px'));
+});
+
+test('virtualized table header width ignores non-numeric column widths', async 
() => {
+  const width = virtualHeaderWidth([
+    testColumns[0],
+    { ...testColumns[1], width: '20%' },
+  ]);
+  await waitFor(() => expect(width()).toBe('150px'));
+});
+
+test('virtualized table header width survives a non-numeric width beside an 
unsized column', async () => {
+  const width = virtualHeaderWidth([
+    { ...testColumns[0], width: '20%' },
+    { title: 'Column Type', dataIndex: 'columnType', key: 'columnType' },
+  ]);
+  // The unsized column gets the 50px minimum; the '20%' one adds nothing.
+  await waitFor(() => expect(width()).toBe('50px'));
+});
+
+test('virtualized table header includes the stretched last column', async () 
=> {
+  mockTableWidth = 400;
+  const width = virtualHeaderWidth(testColumns);
+  await waitFor(() => expect(width()).toBe('400px'));
+});
+
+test('virtualized table does not stretch a non-numeric last column', async () 
=> {
+  mockTableWidth = 400;
+  const width = virtualHeaderWidth([
+    testColumns[0],
+    { ...testColumns[1], width: '20%' },
+  ]);
+  await waitFor(() => expect(width()).toBe('150px'));
+});
+
+test('virtualized table header falls back to the given scroll.x when no width 
is numeric', async () => {
+  const width = virtualHeaderWidth(
+    testColumns.map(column => ({ ...column, width: '50%' })),
+  );
+  await waitFor(() => expect(width()).toBe('100vw'));
+});
diff --git 
a/superset-frontend/packages/superset-ui-core/src/components/Table/VirtualTable.tsx
 
b/superset-frontend/packages/superset-ui-core/src/components/Table/VirtualTable.tsx
index 53ef9f30e0a..585eda982a2 100644
--- 
a/superset-frontend/packages/superset-ui-core/src/components/Table/VirtualTable.tsx
+++ 
b/superset-frontend/packages/superset-ui-core/src/components/Table/VirtualTable.tsx
@@ -152,11 +152,12 @@ const VirtualTable = <RecordType extends object>(
   const widthColumnCount = columns!.filter(({ width }) => !width).length;
   let staticColWidthTotal = 0;
   columns?.forEach(column => {
-    if (column.width) {
-      staticColWidthTotal += column.width as number;
+    if (typeof column.width === 'number') {
+      staticColWidthTotal += column.width;
     }
   });
 
+  // Sum of numeric widths; also sizes the antd header (scroll.x) to match the 
Grid.
   let totalWidth = 0;
   const defaultWidth = Math.max(
     Math.floor((tableWidth - staticColWidthTotal) / widthColumnCount),
@@ -169,7 +170,9 @@ const VirtualTable = <RecordType extends object>(
       if (!column.width) {
         modifiedColumn.width = defaultWidth;
       }
-      totalWidth += modifiedColumn.width as number;
+      if (typeof modifiedColumn.width === 'number') {
+        totalWidth += modifiedColumn.width;
+      }
       return modifiedColumn;
     }) ?? [];
 
@@ -177,10 +180,11 @@ const VirtualTable = <RecordType extends object>(
    * There are cases where a user could set the width of each column and the 
total width is less than width of
    * the table.  In this case we will stretch the last column to use the extra 
space
    */
-  if (totalWidth < tableWidth) {
-    const lastColumn = mergedColumns[mergedColumns.length - 1];
-    lastColumn.width =
-      (lastColumn.width as number) + Math.floor(tableWidth - totalWidth);
+  const lastColumn = mergedColumns[mergedColumns.length - 1];
+  if (totalWidth < tableWidth && typeof lastColumn?.width === 'number') {
+    const extra = Math.floor(tableWidth - totalWidth);
+    lastColumn.width += extra;
+    totalWidth += extra;
   }
 
   const gridRef = useRef<GridImperativeAPI>(null);
@@ -288,7 +292,7 @@ const VirtualTable = <RecordType extends object>(
           body: renderVirtualList,
         }}
         pagination={pagination ? modifiedPagination : false}
-        scroll={scroll}
+        scroll={{ ...scroll, x: totalWidth || scroll?.x }}
         columns={mergedColumns}
       />
     </div>

Reply via email to