diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json
index 1370a2a26d5..9856c45f220 100644
--- a/superset-frontend/package-lock.json
+++ b/superset-frontend/package-lock.json
@@ -56,8 +56,8 @@
"@visx/xychart": "^3.5.1",
"abortcontroller-polyfill": "^1.7.8",
"ace-builds": "^1.36.3",
- "ag-grid-community": "32.2.1",
- "ag-grid-react": "32.2.1",
+ "ag-grid-community": "33.1.1",
+ "ag-grid-react": "33.1.1",
"antd": "4.10.3",
"antd-v5": "npm:antd@^5.18.0",
"bootstrap": "^3.4.1",
@@ -14444,29 +14444,32 @@
}
},
"node_modules/ag-charts-types": {
- "version": "10.2.0",
- "resolved": "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-10.2.0.tgz",
- "integrity": "sha512-PUqH1QtugpYLnlbMdeSZVf5PpT1XZVsP69qN1JXhetLtQpVC28zaj7ikwu9CMA9N9b+dBboA9QcjUQUJZVUokQ=="
+ "version": "11.1.1",
+ "resolved": "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-11.1.1.tgz",
+ "integrity": "sha512-bRmUcf5VVhEEekhX8Vk0NSwa8Te8YM/zchjyYKR2CX4vDYiwoohM1Jg9RFvbIhVbLC1S6QrPEbx5v2C6RDfpSA==",
+ "license": "MIT"
},
"node_modules/ag-grid-community": {
- "version": "32.2.1",
- "resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-32.2.1.tgz",
- "integrity": "sha512-mrnm1DnLI9Wd408mMwP+6p7lbTC3FYgzNIUPygBvNh3SzZnbzTEUJF/BTKXi+MARWtG5S0IMUYy4hqBiLbobaQ==",
+ "version": "33.1.1",
+ "resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-33.1.1.tgz",
+ "integrity": "sha512-CNubIro0ipj4nfQ5WJPG9Isp7UI6MMDvNzrPdHNf3W+IoM8Uv3RUhjEn7xQqpQHuu6o/tMjrqpacipMUkhzqnw==",
+ "license": "MIT",
"dependencies": {
- "ag-charts-types": "10.2.0"
+ "ag-charts-types": "11.1.1"
}
},
"node_modules/ag-grid-react": {
- "version": "32.2.1",
- "resolved": "https://registry.npmjs.org/ag-grid-react/-/ag-grid-react-32.2.1.tgz",
- "integrity": "sha512-lojTKsT/ncRZ81mrDa7qkIhZePfYlLCHIiAL1WbzL1mNPrglaa7QQKkE6hhhuAXvAm2uUhK1OfkMPnrqsEFldA==",
+ "version": "33.1.1",
+ "resolved": "https://registry.npmjs.org/ag-grid-react/-/ag-grid-react-33.1.1.tgz",
+ "integrity": "sha512-xJ+t2gpqUUwpFqAeDvKz/GLVR4unkOghfQBr8iIY9RAdGFarYFClJavsOa8XPVVUqEB9OIuPVFnOdtocbX0jeA==",
+ "license": "MIT",
"dependencies": {
- "ag-grid-community": "32.2.1",
+ "ag-grid-community": "33.1.1",
"prop-types": "^15.8.1"
},
"peerDependencies": {
- "react": "^16.3.0 || ^17.0.0 || ^18.0.0",
- "react-dom": "^16.3.0 || ^17.0.0 || ^18.0.0"
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/agent-base": {
diff --git a/superset-frontend/package.json b/superset-frontend/package.json
index 242d4c0dec6..44d071a1357 100644
--- a/superset-frontend/package.json
+++ b/superset-frontend/package.json
@@ -123,8 +123,8 @@
"@visx/xychart": "^3.5.1",
"abortcontroller-polyfill": "^1.7.8",
"ace-builds": "^1.36.3",
- "ag-grid-community": "32.2.1",
- "ag-grid-react": "32.2.1",
+ "ag-grid-community": "33.1.1",
+ "ag-grid-react": "33.1.1",
"antd": "4.10.3",
"antd-v5": "npm:antd@^5.18.0",
"bootstrap": "^3.4.1",
diff --git a/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx b/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx
index cbd3e10780f..03ebe37314e 100644
--- a/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx
+++ b/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx
@@ -27,6 +27,7 @@ import configureStore from 'redux-mock-store';
import { Store } from 'redux';
import thunk from 'redux-thunk';
import fetchMock from 'fetch-mock';
+import { setupAGGridModules } from 'src/setup/setupAGGridModules';
import ResultSet from 'src/SqlLab/components/ResultSet';
import {
cachedQuery,
@@ -143,6 +144,10 @@ const setup = (props?: any, store?: Store) =>
});
describe('ResultSet', () => {
+ beforeAll(() => {
+ setupAGGridModules();
+ });
+
// Add cleanup after each test
afterEach(async () => {
fetchMock.resetHistory();
@@ -363,7 +368,7 @@ describe('ResultSet', () => {
);
});
const { getByRole } = setup(mockedProps, mockStore(initialState));
- expect(getByRole('treegrid')).toBeInTheDocument();
+ expect(getByRole('grid')).toBeInTheDocument();
});
test('renders if there is a limit in query.results but not queryLimit', async () => {
@@ -381,7 +386,7 @@ describe('ResultSet', () => {
},
}),
);
- expect(getByRole('treegrid')).toBeInTheDocument();
+ expect(getByRole('grid')).toBeInTheDocument();
});
test('Async queries - renders "Fetch data preview" button when data preview has no results', () => {
@@ -409,7 +414,7 @@ describe('ResultSet', () => {
name: /fetch data preview/i,
}),
).toBeVisible();
- expect(screen.queryByRole('treegrid')).not.toBeInTheDocument();
+ expect(screen.queryByRole('grid')).not.toBeInTheDocument();
});
test('Async queries - renders "Refetch results" button when a query has no results', () => {
@@ -438,7 +443,7 @@ describe('ResultSet', () => {
name: /refetch results/i,
}),
).toBeVisible();
- expect(screen.queryByRole('treegrid')).not.toBeInTheDocument();
+ expect(screen.queryByRole('grid')).not.toBeInTheDocument();
});
test('Async queries - renders on the first call', () => {
@@ -458,7 +463,7 @@ describe('ResultSet', () => {
},
}),
);
- expect(screen.getByRole('treegrid')).toBeVisible();
+ expect(screen.getByRole('grid')).toBeVisible();
expect(
screen.queryByRole('button', {
name: /fetch data preview/i,
diff --git a/superset-frontend/src/components/FilterableTable/FilterableTable.test.tsx b/superset-frontend/src/components/FilterableTable/FilterableTable.test.tsx
index 349c390d5bd..8e07d0e97f4 100644
--- a/superset-frontend/src/components/FilterableTable/FilterableTable.test.tsx
+++ b/superset-frontend/src/components/FilterableTable/FilterableTable.test.tsx
@@ -24,8 +24,13 @@ import {
userEvent,
within,
} from 'spec/helpers/testing-library';
+import { setupAGGridModules } from 'src/setup/setupAGGridModules';
describe('FilterableTable', () => {
+ beforeAll(() => {
+ setupAGGridModules();
+ });
+
const mockedProps = {
orderedColumnKeys: ['a', 'b', 'c', 'children'],
data: [
@@ -42,7 +47,7 @@ describe('FilterableTable', () => {
const { getByRole, getByText } = render(
,
);
- expect(getByRole('treegrid')).toBeInTheDocument();
+ expect(getByRole('grid')).toBeInTheDocument();
mockedProps.data.forEach(({ b: columnBContent }) => {
expect(getByText(columnBContent)).toBeInTheDocument();
});
@@ -70,6 +75,10 @@ describe('FilterableTable', () => {
});
describe('FilterableTable sorting - RTL', () => {
+ beforeAll(() => {
+ setupAGGridModules();
+ });
+
it('sorts strings correctly', () => {
const stringProps = {
orderedColumnKeys: ['columnA'],
@@ -82,7 +91,7 @@ describe('FilterableTable sorting - RTL', () => {
};
render();
- const stringColumn = within(screen.getByRole('treegrid'))
+ const stringColumn = within(screen.getByRole('grid'))
.getByText('columnA')
.closest('[role=button]');
const gridCells = screen.getByText('Bravo').closest('[role=rowgroup]');
@@ -127,7 +136,7 @@ describe('FilterableTable sorting - RTL', () => {
};
render();
- const integerColumn = within(screen.getByRole('treegrid'))
+ const integerColumn = within(screen.getByRole('grid'))
.getByText('columnB')
.closest('[role=button]');
const gridCells = screen.getByText('21').closest('[role=rowgroup]');
@@ -162,7 +171,7 @@ describe('FilterableTable sorting - RTL', () => {
};
render();
- const floatColumn = within(screen.getByRole('treegrid'))
+ const floatColumn = within(screen.getByRole('grid'))
.getByText('columnC')
.closest('[role=button]');
const gridCells = screen.getByText('45.67').closest('[role=rowgroup]');
@@ -217,7 +226,7 @@ describe('FilterableTable sorting - RTL', () => {
};
render();
- const mixedFloatColumn = within(screen.getByRole('treegrid'))
+ const mixedFloatColumn = within(screen.getByRole('grid'))
.getByText('columnD')
.closest('[role=button]');
const gridCells = screen.getByText('48710.92').closest('[role=rowgroup]');
@@ -315,7 +324,7 @@ describe('FilterableTable sorting - RTL', () => {
};
render();
- const dsColumn = within(screen.getByRole('treegrid'))
+ const dsColumn = within(screen.getByRole('grid'))
.getByText('columnDS')
.closest('[role=button]');
const gridCells = screen.getByText('2021-01-01').closest('[role=rowgroup]');
diff --git a/superset-frontend/src/components/GridTable/GridTable.test.tsx b/superset-frontend/src/components/GridTable/GridTable.test.tsx
index 1f603c75f33..849831af6a2 100644
--- a/superset-frontend/src/components/GridTable/GridTable.test.tsx
+++ b/superset-frontend/src/components/GridTable/GridTable.test.tsx
@@ -17,6 +17,7 @@
* under the License.
*/
import { render } from 'spec/helpers/testing-library';
+import { setupAGGridModules } from 'src/setup/setupAGGridModules';
import GridTable from '.';
jest.mock('src/components/ErrorBoundary', () => ({
@@ -40,6 +41,10 @@ const mockedProps = {
height: 500,
};
+beforeAll(() => {
+ setupAGGridModules();
+});
+
test('renders a grid with 3 Table rows', () => {
const { queryByText } = render();
mockedProps.data.forEach(({ b: columnBContent }) => {
diff --git a/superset-frontend/src/components/GridTable/index.tsx b/superset-frontend/src/components/GridTable/index.tsx
index 1311148adc8..aab529fa569 100644
--- a/superset-frontend/src/components/GridTable/index.tsx
+++ b/superset-frontend/src/components/GridTable/index.tsx
@@ -16,11 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { useCallback, useMemo } from 'react';
+import { ReactNode, useCallback, useMemo } from 'react';
import { Global } from '@emotion/react';
import { css, useTheme } from '@superset-ui/core';
-import type { Column } from 'ag-grid-community';
+import type { Column, GridOptions } from 'ag-grid-community';
import { AgGridReact, type AgGridReactProps } from 'ag-grid-react';
import 'ag-grid-community/styles/ag-grid.css';
@@ -56,7 +56,7 @@ export interface TableProps {
headerName?: string;
width?: number;
comparator?: (valueA: string | number, valueB: string | number) => number;
- render?: (value: any) => React.ReactNode;
+ render?: (value: any) => ReactNode;
}[];
size?: GridSize;
@@ -159,15 +159,30 @@ function GridTable({
].slice(showRowNumber ? 0 : 1),
[rowIndexLength, columnReorderable, columns, showRowNumber, sortable],
);
- const defaultColDef: AgGridReactProps['defaultColDef'] = {
- ...(!columnReorderable && { suppressMovable: true }),
- resizable: true,
- sortable,
- filter: Boolean(enableActions),
- };
+ const defaultColDef: AgGridReactProps['defaultColDef'] = useMemo(
+ () => ({
+ ...(!columnReorderable && { suppressMovable: true }),
+ resizable: true,
+ sortable,
+ filter: Boolean(enableActions),
+ }),
+ [columnReorderable, enableActions, sortable],
+ );
const rowHeight = theme.gridUnit * (size === GridSize.Middle ? 9 : 7);
+ const gridOptions = useMemo(
+ () => ({
+ enableCellTextSelection: true,
+ ensureDomOrder: true,
+ suppressFieldDotNotation: true,
+ headerHeight: rowHeight,
+ rowSelection: 'multiple',
+ rowHeight,
+ }),
+ [rowHeight],
+ );
+
return (
({
`}
>
({
isExternalFilterPresent={isExternalFilterPresent}
doesExternalFilterPass={externalFilter}
components={gridComponents}
- gridOptions={{
- enableCellTextSelection: true,
- ensureDomOrder: true,
- suppressFieldDotNotation: true,
- headerHeight: rowHeight,
- rowSelection: 'multiple',
- rowHeight,
- }}
+ gridOptions={gridOptions}
onCellKeyDown={onKeyDown}
/>
diff --git a/superset-frontend/src/setup/setupAGGridModules.ts b/superset-frontend/src/setup/setupAGGridModules.ts
new file mode 100644
index 00000000000..63a3d97a4e8
--- /dev/null
+++ b/superset-frontend/src/setup/setupAGGridModules.ts
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import {
+ ModuleRegistry,
+ ColumnAutoSizeModule,
+ ColumnHoverModule,
+ RowAutoHeightModule,
+ RowStyleModule,
+ PaginationModule,
+ CellStyleModule,
+ TextFilterModule,
+ NumberFilterModule,
+ DateFilterModule,
+ ExternalFilterModule,
+ CsvExportModule,
+ ColumnApiModule,
+ RowApiModule,
+ CellApiModule,
+ RenderApiModule,
+ ClientSideRowModelModule,
+ CustomFilterModule,
+} from 'ag-grid-community';
+
+export const setupAGGridModules = () => {
+ ModuleRegistry.registerModules([
+ ColumnAutoSizeModule,
+ ColumnHoverModule,
+ RowAutoHeightModule,
+ RowStyleModule,
+ PaginationModule,
+ CellStyleModule,
+ TextFilterModule,
+ NumberFilterModule,
+ DateFilterModule,
+ ExternalFilterModule,
+ CsvExportModule,
+ ColumnApiModule,
+ RowApiModule,
+ CellApiModule,
+ RenderApiModule,
+ ClientSideRowModelModule,
+ CustomFilterModule,
+ ]);
+};
diff --git a/superset-frontend/src/views/App.tsx b/superset-frontend/src/views/App.tsx
index 3d1cfc3e572..970ad958707 100644
--- a/superset-frontend/src/views/App.tsx
+++ b/superset-frontend/src/views/App.tsx
@@ -35,6 +35,7 @@ import getBootstrapData from 'src/utils/getBootstrapData';
import ToastContainer from 'src/components/MessageToasts/ToastContainer';
import setupApp from 'src/setup/setupApp';
import setupPlugins from 'src/setup/setupPlugins';
+import { setupAGGridModules } from 'src/setup/setupAGGridModules';
import { routes, isFrontendRoute } from 'src/views/routes';
import { Logger, LOG_ACTIONS_SPA_NAVIGATION } from 'src/logger/LogUtils';
import setupExtensions from 'src/setup/setupExtensions';
@@ -46,6 +47,7 @@ import { ScrollToTop } from './ScrollToTop';
setupApp();
setupPlugins();
setupExtensions();
+setupAGGridModules();
const bootstrapData = getBootstrapData();