You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ju...@apache.org on 2026/08/07 18:13:44 UTC
(superset) branch 6.2 updated (210da7f0ae6 -> 428b1067825)
This is an automated email from the ASF dual-hosted git repository.
justinpark pushed a change to branch 6.2
in repository https://gitbox.apache.org/repos/asf/superset.git
from 210da7f0ae6 fix(mcp): generic auth errors, required token expiry, and safer auth logging (#40646)
new 04bebf040c6 fix(sqllab): Invalid multi sorting state in table header (#40680)
new 14b24bd76f6 fix(sqllab): invalid height in ResultTable (#37408)
new 428b1067825 perf(TimeTable): skip rendering TableView while the window is resizing (#42097)
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../src/SqlLab/components/QueryTable/index.tsx | 26 +--
.../src/SqlLab/components/QueryTable/styles.ts | 1 +
.../src/SqlLab/components/ResultSet/index.tsx | 32 ++--
.../src/components/GridTable/Header.test.tsx | 186 ++++++++++++++++-----
.../src/components/GridTable/Header.tsx | 52 ++----
.../visualizations/TimeTable/TimeTable.test.tsx | 51 +++++-
.../src/visualizations/TimeTable/TimeTable.tsx | 53 ++++--
7 files changed, 278 insertions(+), 123 deletions(-)
(superset) 03/03: perf(TimeTable): skip rendering TableView while the window is resizing (#42097)
Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
justinpark pushed a commit to branch 6.2
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 428b10678257ef9ec949e7ab9cc5e2f07644014a
Author: JUST.in DO IT <ju...@airbnb.com>
AuthorDate: Wed Aug 5 10:41:39 2026 -0700
perf(TimeTable): skip rendering TableView while the window is resizing (#42097)
(cherry picked from commit 657e2d2267ac34a4a39ef6c052a0a1bfa8b17972)
---
.../visualizations/TimeTable/TimeTable.test.tsx | 51 ++++++++++++++++++++-
.../src/visualizations/TimeTable/TimeTable.tsx | 53 +++++++++++++++++-----
2 files changed, 92 insertions(+), 12 deletions(-)
diff --git a/superset-frontend/src/visualizations/TimeTable/TimeTable.test.tsx b/superset-frontend/src/visualizations/TimeTable/TimeTable.test.tsx
index b973e3b2fe0..c85711571a9 100644
--- a/superset-frontend/src/visualizations/TimeTable/TimeTable.test.tsx
+++ b/superset-frontend/src/visualizations/TimeTable/TimeTable.test.tsx
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { render, screen, within } from '@superset-ui/core/spec';
+import { act, fireEvent, render, screen, within } from '@superset-ui/core/spec';
import TimeTable from './TimeTable';
const mockData = {
@@ -185,6 +185,55 @@ test('should handle column type sparkline correctly', () => {
});
});
+test('should hide the table while the window is resizing and reveal it again after the debounce delay', () => {
+ jest.useFakeTimers();
+
+ const { container } = render(<TimeTable {...defaultProps} />);
+ const timeTable = container.querySelector('[data-test="time-table"]');
+
+ expect(timeTable).not.toHaveStyle('display: none');
+
+ act(() => {
+ fireEvent(window, new Event('resize'));
+ });
+ expect(timeTable).toHaveStyle('display: none');
+
+ act(() => {
+ jest.advanceTimersByTime(499);
+ });
+ expect(timeTable).toHaveStyle('display: none');
+
+ act(() => {
+ jest.advanceTimersByTime(1);
+ });
+ expect(timeTable).not.toHaveStyle('display: none');
+
+ jest.clearAllTimers();
+ jest.useRealTimers();
+});
+
+test('should clear the resize listener and pending timer on unmount', () => {
+ jest.useFakeTimers();
+ const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener');
+
+ const { unmount } = render(<TimeTable {...defaultProps} />);
+
+ act(() => {
+ fireEvent(window, new Event('resize'));
+ });
+
+ unmount();
+
+ expect(removeEventListenerSpy).toHaveBeenCalledWith(
+ 'resize',
+ expect.any(Function),
+ );
+
+ removeEventListenerSpy.mockRestore();
+ jest.clearAllTimers();
+ jest.useRealTimers();
+});
+
test('should not render empty table due to missing column id property', () => {
render(<TimeTable {...defaultProps} />);
diff --git a/superset-frontend/src/visualizations/TimeTable/TimeTable.tsx b/superset-frontend/src/visualizations/TimeTable/TimeTable.tsx
index 31f4e6e47e4..dee944805c1 100644
--- a/superset-frontend/src/visualizations/TimeTable/TimeTable.tsx
+++ b/superset-frontend/src/visualizations/TimeTable/TimeTable.tsx
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { useMemo, ReactNode } from 'react';
+import { useMemo, useRef, useState, useEffect, ReactNode } from 'react';
import { InfoTooltip, TableView } from '@superset-ui/core/components';
import { t } from '@apache-superset/core/translation';
import { styled } from '@apache-superset/core/theme';
@@ -24,8 +24,11 @@ import { sortNumberWithMixedTypes, processTimeTableData } from './utils';
import { ValueCell, LeftCell, Sparkline } from './components';
import type { TimeTableProps } from './types';
+const RESIZE_DEBOUNCE_MS = 500;
+
// @z-index-above-dashboard-charts + 1 = 11
-const TimeTableStyles = styled.div<{ height?: number }>`
+const TimeTableStyles = styled.div<{ height?: number; hideTable?: boolean }>`
+ ${props => props.hideTable && 'display: none;'}
height: ${props => props.height}px;
overflow: auto;
@@ -43,6 +46,30 @@ const TimeTable = ({
rows,
url = '',
}: TimeTableProps) => {
+ // Hide TableView as soon as the window starts resizing, and only show it
+ // again once resizing has stopped for RESIZE_DEBOUNCE_MS.
+ const resizeTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(
+ undefined,
+ );
+ const [isSizeStable, setIsSizeStable] = useState(true);
+
+ useEffect(() => {
+ const handleResize = () => {
+ setIsSizeStable(false);
+ clearTimeout(resizeTimerRef.current);
+ resizeTimerRef.current = setTimeout(() => {
+ setIsSizeStable(true);
+ }, RESIZE_DEBOUNCE_MS);
+ };
+
+ window.addEventListener('resize', handleResize);
+
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ clearTimeout(resizeTimerRef.current);
+ };
+ }, []);
+
const memoizedColumns = useMemo(
() => [
{
@@ -115,21 +142,25 @@ const TimeTable = ({
});
}, [columnConfigs, data, rowType, rows, url]);
- const defaultSort =
- rowType === 'column' && columnConfigs.length
- ? [
- {
- id: columnConfigs[0].key,
- desc: true,
- },
- ]
- : [];
+ const defaultSort = useMemo(
+ () =>
+ rowType === 'column' && columnConfigs.length
+ ? [
+ {
+ id: columnConfigs[0].key,
+ desc: true,
+ },
+ ]
+ : [],
+ [rowType, columnConfigs],
+ );
return (
<TimeTableStyles
data-test="time-table"
className={className}
height={height}
+ hideTable={!isSizeStable}
>
<TableView
className="table-no-hover"
(superset) 02/03: fix(sqllab): invalid height in ResultTable (#37408)
Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
justinpark pushed a commit to branch 6.2
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 14b24bd76f65d4fe451046ed552a9f8985f1b2b1
Author: JUST.in DO IT <ju...@airbnb.com>
AuthorDate: Wed Jul 8 09:09:45 2026 +0900
fix(sqllab): invalid height in ResultTable (#37408)
(cherry picked from commit 866f8c51ee2f5a1fc4ccc39ca58f190d32b9cc80)
---
.../src/SqlLab/components/QueryTable/index.tsx | 26 +++++-------------
.../src/SqlLab/components/QueryTable/styles.ts | 1 +
.../src/SqlLab/components/ResultSet/index.tsx | 32 ++++++++--------------
3 files changed, 20 insertions(+), 39 deletions(-)
diff --git a/superset-frontend/src/SqlLab/components/QueryTable/index.tsx b/superset-frontend/src/SqlLab/components/QueryTable/index.tsx
index 2ba0985aed7..7ec5a592cca 100644
--- a/superset-frontend/src/SqlLab/components/QueryTable/index.tsx
+++ b/superset-frontend/src/SqlLab/components/QueryTable/index.tsx
@@ -28,7 +28,7 @@ import {
} from '@superset-ui/core/components';
import ProgressBar from '@superset-ui/core/components/ProgressBar';
import { t } from '@apache-superset/core/translation';
-import { QueryResponse, QueryState } from '@superset-ui/core';
+import { QueryResponse } from '@superset-ui/core';
import { useTheme } from '@apache-superset/core/theme';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
@@ -397,24 +397,12 @@ const QueryTable = ({
modalBody={
selectedQuery ? (
<ModalResultSetWrapper>
- {(() => {
- const height =
- reduxQueries[selectedQuery.id]?.state ===
- QueryState.Success &&
- reduxQueries[selectedQuery.id]?.results
- ? Math.floor(window.innerHeight * 0.5)
- : undefined;
- return (
- <ResultSet
- showSql
- queryId={selectedQuery.id}
- displayLimit={displayLimit}
- defaultQueryLimit={1000}
- useFixedHeight
- height={height}
- />
- );
- })()}
+ <ResultSet
+ showSql
+ queryId={selectedQuery.id}
+ displayLimit={displayLimit}
+ defaultQueryLimit={1000}
+ />
</ModalResultSetWrapper>
) : null
}
diff --git a/superset-frontend/src/SqlLab/components/QueryTable/styles.ts b/superset-frontend/src/SqlLab/components/QueryTable/styles.ts
index 30bb0fb71e5..231703e43d7 100644
--- a/superset-frontend/src/SqlLab/components/QueryTable/styles.ts
+++ b/superset-frontend/src/SqlLab/components/QueryTable/styles.ts
@@ -45,4 +45,5 @@ export const ModalResultSetWrapper = styled.div`
flex-direction: column;
overflow: hidden;
max-height: 50vh;
+ height: 500px;
`;
diff --git a/superset-frontend/src/SqlLab/components/ResultSet/index.tsx b/superset-frontend/src/SqlLab/components/ResultSet/index.tsx
index d1858e730a8..abd8ba171c0 100644
--- a/superset-frontend/src/SqlLab/components/ResultSet/index.tsx
+++ b/superset-frontend/src/SqlLab/components/ResultSet/index.tsx
@@ -105,14 +105,12 @@ export interface ResultSetProps {
csv?: boolean;
database?: Record<string, any>;
displayLimit: number;
- height?: number;
queryId: string;
search?: boolean;
showSql?: boolean;
showSqlInline?: boolean;
visualize?: boolean;
defaultQueryLimit: number;
- useFixedHeight?: boolean;
}
const ResultContainer = styled.div`
@@ -163,14 +161,12 @@ const ResultSet = ({
csv = true,
database = {},
displayLimit,
- height,
queryId,
search = true,
showSql = false,
showSqlInline = false,
visualize = true,
defaultQueryLimit,
- useFixedHeight = false,
}: ResultSetProps) => {
const user = useSelector(({ user }: SqlLabRootState) => user, shallowEqual);
const streamingThreshold = useSelector(
@@ -743,22 +739,18 @@ const ResultSet = ({
/>
)}
</div>
- {useFixedHeight && height !== undefined ? (
- <ResultTable {...tableProps} height={height} />
- ) : (
- <div
- css={css`
- flex: 1 1 auto;
- padding-bottom: ${theme.sizeUnit * 3}px;
- `}
- >
- <AutoSizer disableWidth>
- {({ height: autoHeight }) => (
- <ResultTable {...tableProps} height={autoHeight} />
- )}
- </AutoSizer>
- </div>
- )}
+ <div
+ css={css`
+ flex: 1 1 auto;
+ padding-bottom: ${theme.sizeUnit * 3}px;
+ `}
+ >
+ <AutoSizer disableWidth>
+ {({ height: autoHeight }) => (
+ <ResultTable {...tableProps} height={autoHeight} />
+ )}
+ </AutoSizer>
+ </div>
</ResultContainer>
<StreamingExportModal
visible={showStreamingModal}
(superset) 01/03: fix(sqllab): Invalid multi sorting state in table header (#40680)
Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
justinpark pushed a commit to branch 6.2
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 04bebf040c6d0dc1ca34220ea90fa6a8e849ed4a
Author: JUST.in DO IT <ju...@airbnb.com>
AuthorDate: Thu Jun 25 06:43:02 2026 +0900
fix(sqllab): Invalid multi sorting state in table header (#40680)
(cherry picked from commit b955c90de40fc6ee09b3b38b4bb97ff67a11b934)
---
.../src/components/GridTable/Header.test.tsx | 186 ++++++++++++++++-----
.../src/components/GridTable/Header.tsx | 52 ++----
2 files changed, 166 insertions(+), 72 deletions(-)
diff --git a/superset-frontend/src/components/GridTable/Header.test.tsx b/superset-frontend/src/components/GridTable/Header.test.tsx
index cc747ee8762..0140fcfacdc 100644
--- a/superset-frontend/src/components/GridTable/Header.test.tsx
+++ b/superset-frontend/src/components/GridTable/Header.test.tsx
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import type { Column, GridApi } from 'ag-grid-community';
+import type { Column, GridApi, IHeaderParams } from 'ag-grid-community';
import { act, fireEvent, render } from 'spec/helpers/testing-library';
import { Header } from './Header';
import { PIVOT_COL_ID } from './constants';
@@ -38,9 +38,70 @@ jest.mock('@superset-ui/core/components/Icons', () => {
};
});
-class MockApi extends EventTarget {
+class MockColumn {
+ private colListeners = new Map<string, Set<Function>>();
+
+ sortValue: string | null = 'asc';
+
+ sortIndexValue: number | null = null;
+
+ getColId() {
+ return '123';
+ }
+
+ isPinnedLeft() {
+ return true;
+ }
+
+ isPinnedRight() {
+ return false;
+ }
+
+ isVisible() {
+ return true;
+ }
+
+ getSort() {
+ return this.sortValue;
+ }
+
+ getSortIndex() {
+ return this.sortIndexValue;
+ }
+
+ addEventListener(eventType: string, listener: Function) {
+ if (!this.colListeners.has(eventType)) {
+ this.colListeners.set(eventType, new Set());
+ }
+ this.colListeners.get(eventType)!.add(listener);
+ }
+
+ removeEventListener(eventType: string, listener: Function) {
+ this.colListeners.get(eventType)?.delete(listener);
+ }
+
+ triggerEvent(eventType: string) {
+ this.colListeners.get(eventType)?.forEach(listener => listener({}));
+ }
+}
+
+class MockOtherColumn extends MockColumn {
+ getColId() {
+ return 'other-col';
+ }
+}
+
+class MockApi {
+ mockColumn = new MockColumn();
+
+ otherColumn = new MockOtherColumn();
+
getAllDisplayedColumns() {
- return [];
+ return [this.mockColumn, this.otherColumn];
+ }
+
+ getColumns() {
+ return [this.mockColumn, this.otherColumn];
}
isDestroyed() {
@@ -48,48 +109,76 @@ class MockApi extends EventTarget {
}
}
+const mockApi = new MockApi();
+
const mockedProps = {
displayName: 'test column',
- setSort: jest.fn(),
+ progressSort: jest.fn(),
enableSorting: true,
- column: {
- getColId: () => '123',
- isPinnedLeft: () => true,
- isPinnedRight: () => false,
- getSort: () => 'asc',
- getSortIndex: () => null,
- } as any as Column,
- api: new MockApi() as any as GridApi,
-};
+ column: mockApi.mockColumn as any as Column,
+ api: mockApi as any as GridApi,
+} as unknown as IHeaderParams;
test('renders display name for the column', () => {
const { queryByText } = render(<Header {...mockedProps} />);
expect(queryByText(mockedProps.displayName)).toBeInTheDocument();
});
-test('sorts by clicking a column header', () => {
- const { getByText, queryByTestId } = render(<Header {...mockedProps} />);
+test('calls progressSort without shiftKey on click', () => {
+ const { getByText } = render(<Header {...mockedProps} />);
fireEvent.click(getByText(mockedProps.displayName));
- expect(mockedProps.setSort).toHaveBeenCalledWith('asc', false);
- expect(queryByTestId('mock-sort-asc')).toBeInTheDocument();
- fireEvent.click(getByText(mockedProps.displayName));
- expect(mockedProps.setSort).toHaveBeenCalledWith('desc', false);
- expect(queryByTestId('mock-sort-desc')).toBeInTheDocument();
- fireEvent.click(getByText(mockedProps.displayName));
- expect(mockedProps.setSort).toHaveBeenCalledWith(null, false);
- expect(queryByTestId('mock-sort-asc')).not.toBeInTheDocument();
- expect(queryByTestId('mock-sort-desc')).not.toBeInTheDocument();
+ expect(mockedProps.progressSort).toHaveBeenCalledWith(false);
});
-test('synchronizes the current sort when sortChanged event occurred', async () => {
- const { findByTestId } = render(<Header {...mockedProps} />);
+test('calls progressSort with shiftKey on shift-click', () => {
+ const { getByText } = render(<Header {...mockedProps} />);
+ fireEvent.click(getByText(mockedProps.displayName), { shiftKey: true });
+ expect(mockedProps.progressSort).toHaveBeenCalledWith(true);
+});
+
+test('synchronizes sort icon when columnStateUpdated fires on column', async () => {
+ const { findByTestId, queryByTestId } = render(<Header {...mockedProps} />);
+ expect(queryByTestId('mock-sort-asc')).not.toBeInTheDocument();
+
act(() => {
- mockedProps.api.dispatchEvent(new Event('sortChanged'));
+ mockApi.mockColumn.triggerEvent('columnStateUpdated');
});
+
const sortAsc = await findByTestId('mock-sort-asc');
expect(sortAsc).toBeInTheDocument();
});
+test('shows sortIndex label when multi-sort is active', async () => {
+ const { findByText } = render(<Header {...mockedProps} />);
+
+ act(() => {
+ mockApi.mockColumn.sortIndexValue = 1;
+ mockApi.otherColumn.sortValue = 'desc';
+ mockApi.mockColumn.triggerEvent('columnStateUpdated');
+ });
+
+ const label = await findByText('2');
+ expect(label).toBeInTheDocument();
+});
+
+test('hides sortIndex label when multi-sort is cleared', async () => {
+ const { queryByText } = render(<Header {...mockedProps} />);
+
+ act(() => {
+ mockApi.mockColumn.sortIndexValue = 1;
+ mockApi.otherColumn.sortValue = 'desc';
+ mockApi.mockColumn.triggerEvent('columnStateUpdated');
+ });
+
+ act(() => {
+ mockApi.mockColumn.sortIndexValue = null;
+ mockApi.otherColumn.sortValue = null;
+ mockApi.mockColumn.triggerEvent('columnStateUpdated');
+ });
+
+ expect(queryByText('2')).not.toBeInTheDocument();
+});
+
test('disable menu when enableFilterButton is false', () => {
const { queryByText, queryByTestId } = render(
<Header {...mockedProps} enableFilterButton={false} />,
@@ -99,18 +188,39 @@ test('disable menu when enableFilterButton is false', () => {
});
test('hide display name for PIVOT_COL_ID', () => {
+ const pivotColumn = new MockColumn();
+ (pivotColumn as any).getColId = () => PIVOT_COL_ID;
+
const { queryByText } = render(
- <Header
- {...mockedProps}
- column={
- {
- getColId: () => PIVOT_COL_ID,
- isPinnedLeft: () => true,
- isPinnedRight: () => false,
- getSortIndex: () => null,
- } as any as Column
- }
- />,
+ <Header {...mockedProps} column={pivotColumn as any as Column} />,
);
expect(queryByText(mockedProps.displayName)).not.toBeInTheDocument();
});
+
+test('does not attach click handler when enableSorting is false', () => {
+ const { getByText } = render(
+ <Header {...mockedProps} enableSorting={false} />,
+ );
+ const cell = getByText(mockedProps.displayName).closest(
+ '.ag-header-cell-label',
+ );
+ expect(cell).not.toHaveAttribute('role', 'button');
+});
+
+test('does not call progressSort on click when enableSorting is false', () => {
+ const progressSort = jest.fn();
+ const { getByText } = render(
+ <Header {...mockedProps} enableSorting={false} progressSort={progressSort} />,
+ );
+ fireEvent.click(getByText(mockedProps.displayName));
+ expect(progressSort).not.toHaveBeenCalled();
+});
+
+test('does not render sort icons when enableSorting is false', () => {
+ const { queryByTestId } = render(
+ <Header {...mockedProps} enableSorting={false} />,
+ );
+ expect(queryByTestId('mock-sort')).not.toBeInTheDocument();
+ expect(queryByTestId('mock-sort-asc')).not.toBeInTheDocument();
+ expect(queryByTestId('mock-sort-desc')).not.toBeInTheDocument();
+});
diff --git a/superset-frontend/src/components/GridTable/Header.tsx b/superset-frontend/src/components/GridTable/Header.tsx
index ece0a8eb251..3c11618caf8 100644
--- a/superset-frontend/src/components/GridTable/Header.tsx
+++ b/superset-frontend/src/components/GridTable/Header.tsx
@@ -16,26 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { useCallback, useEffect, useRef, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import type { IHeaderParams, Column, SortDirection } from 'ag-grid-community';
+
import { t } from '@apache-superset/core/translation';
import { styled, useTheme } from '@apache-superset/core/theme';
-import type { Column, GridApi } from 'ag-grid-community';
-
import { Icons } from '@superset-ui/core/components/Icons';
+
import { PIVOT_COL_ID } from './constants';
import { HeaderMenu } from './HeaderMenu';
-interface Params {
- enableFilterButton?: boolean;
- enableSorting?: boolean;
- displayName: string;
- column: Column;
- api: GridApi;
- setSort: (sort: string | null, multiSort: boolean) => void;
-}
-
-const SORT_DIRECTION = [null, 'asc', 'desc'];
-
const HeaderCell = styled.div`
display: flex;
flex: 1;
@@ -81,30 +71,26 @@ const IconPlaceholder = styled.div`
top: 0;
`;
-export const Header: React.FC<Params> = ({
+export const Header: React.FC<IHeaderParams> = ({
enableFilterButton,
enableSorting,
displayName,
- setSort,
+ progressSort,
column,
api,
-}: Params) => {
+}: IHeaderParams) => {
const theme = useTheme();
const colId = column.getColId();
const pinnedLeft = column.isPinnedLeft();
const pinnedRight = column.isPinnedRight();
- const sortOption = useRef<number>(0);
const [invisibleColumns, setInvisibleColumns] = useState<Column[]>([]);
- const [currentSort, setCurrentSort] = useState<string | null>(null);
+ const [currentSort, setCurrentSort] = useState<SortDirection>(null);
const [sortIndex, setSortIndex] = useState<number | null>();
const onSort = useCallback(
- event => {
- sortOption.current = (sortOption.current + 1) % SORT_DIRECTION.length;
- const sort = SORT_DIRECTION[sortOption.current];
- setSort(sort, event.shiftKey);
- setCurrentSort(sort);
+ (event: React.MouseEvent) => {
+ progressSort(event.shiftKey);
},
- [setSort],
+ [progressSort],
);
const onVisibleChange = useCallback(
(isVisible: boolean) => {
@@ -117,24 +103,22 @@ export const Header: React.FC<Params> = ({
[api],
);
- const onSortChanged = useCallback(() => {
+ const syncSortState = useCallback(() => {
const hasMultiSort = api
.getAllDisplayedColumns()
- .some(c => c.getSortIndex());
- const updatedSortIndex = column.getSortIndex();
- sortOption.current = SORT_DIRECTION.indexOf(column.getSort() ?? null);
+ .some(c => c.getColId() !== colId && c.getSort() !== null);
setCurrentSort(column.getSort() ?? null);
- setSortIndex(hasMultiSort ? updatedSortIndex : null);
- }, [api, column]);
+ setSortIndex(hasMultiSort ? column.getSortIndex() : null);
+ }, [api, column, colId]);
useEffect(() => {
- api.addEventListener('sortChanged', onSortChanged);
+ column.addEventListener('columnStateUpdated', syncSortState);
return () => {
if (api.isDestroyed()) return;
- api.removeEventListener('sortChanged', onSortChanged);
+ column.removeEventListener('columnStateUpdated', syncSortState);
};
- }, [api, onSortChanged]);
+ }, [column, syncSortState]);
return (
<>