Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
53c9eba
fix(ag-grid-table): remove enterprise features to use community version
amaannawab923 Oct 2, 2025
0762079
Merge branch 'master' of https://github.com/apache/superset
amaannawab923 Oct 3, 2025
a9f1b41
Merge branch 'master' of https://github.com/apache/superset
amaannawab923 Oct 15, 2025
cfa955a
amaannawab923 Oct 16, 2025
2e00018
Merge branch 'master' of https://github.com/apache/superset
amaannawab923 Oct 27, 2025
a9ed918
Merge branch 'master' of https://github.com/apache/superset
amaannawab923 Nov 8, 2025
a3729ec
Re Implement Server Side Filtering while maintaining parity with Perm…
amaannawab923 Oct 27, 2024
38fe94a
Fix filter state initialization timing
amaannawab923 Oct 29, 2024
3eefbb8
Improve filter conversion and state management
amaannawab923 Oct 30, 2024
fa8a8a5
Add comprehensive test coverage for filters
amaannawab923 Oct 31, 2024
8af9a0b
Fix test assertions and edge cases
amaannawab923 Nov 3, 2024
5ffd361
Handle complex filter conditions and joins
amaannawab923 Nov 5, 2024
f298996
Clear filter state on non-filter actions
amaannawab923 Nov 6, 2024
ad67724
Format code with prettier
amaannawab923 Nov 7, 2024
d72db3e
Fix linting issues
amaannawab923 Nov 8, 2024
0008bd6
test change
amaannawab923 Nov 8, 2025
dd53620
temporal filters
amaannawab923 Nov 8, 2025
85dbd8b
oxlint fix
amaannawab923 Nov 8, 2025
e86214b
test fix
amaannawab923 Nov 8, 2025
baf59aa
Ag grid issues fixes (#31)
amaannawab923 Dec 17, 2025
273c937
Merge upstream/master into ag-grid-server-filters
amaannawab923 Dec 17, 2025
0eade29
Merge upstream/master into ag-grid-server-filters
amaannawab923 Jan 7, 2026
4cc0aa4
fix ci
amaannawab923 Jan 7, 2026
83c3e06
Fixed review comments
amaannawab923 Jan 8, 2026
78336f3
fix CI issues
amaannawab923 Jan 8, 2026
b1ff00d
fix test
amaannawab923 Jan 8, 2026
245aa0c
Fixed types
amaannawab923 Jan 8, 2026
f1ebac6
resolve_comments
amaannawab923 Jan 8, 2026
32b7783
fix_typescript_error
amaannawab923 Jan 8, 2026
970be99
fix_prettier
amaannawab923 Jan 8, 2026
95c8e12
Merge upstream/master into ag-grid-server-filters
amaannawab923 Jan 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,19 @@
* under the License.
*/

import { useRef, useState } from 'react';
import { useRef, useState, useEffect } from 'react';
import { t } from '@apache-superset/core';
import { ArrowDownOutlined, ArrowUpOutlined } from '@ant-design/icons';
import { Column } from '@superset-ui/core/components/ThemedAgGridReact';
import FilterIcon from './Filter';
import KebabMenu from './KebabMenu';
import {
CustomColDef,
CustomHeaderParams,
SortState,
UserProvidedColDef,
FilterInputPosition,
AGGridFilterInstance,
} from '../../types';
import CustomPopover from './CustomPopover';
import {
Expand All @@ -39,6 +42,13 @@ import {
MenuContainer,
SortIconWrapper,
} from '../../styles';
import { GridApi } from 'ag-grid-community';
import {
FILTER_POPOVER_OPEN_DELAY,
FILTER_INPUT_POSITIONS,
FILTER_CONDITION_BODY_INDEX,
FILTER_INPUT_SELECTOR,
} from '../../consts';

const getSortIcon = (sortState: SortState[], colId: string | null) => {
if (!sortState?.length || !colId) return null;
Expand All @@ -53,6 +63,43 @@ const getSortIcon = (sortState: SortState[], colId: string | null) => {
return null;
};

// Auto-opens filter popover and focuses the correct input after server-side filtering
Comment thread
amaannawab923 marked this conversation as resolved.
const autoOpenFilterAndFocus = async (
column: Column,
api: GridApi,
filterRef: React.RefObject<HTMLDivElement>,
setFilterVisible: (visible: boolean) => void,
lastFilteredInputPosition?: FilterInputPosition,
) => {
setFilterVisible(true);

const filterInstance = (await api.getColumnFilterInstance(
column,
)) as AGGridFilterInstance | null;
const filterEl = filterInstance?.eGui;

if (!filterEl || !filterRef.current) return;

filterRef.current.innerHTML = '';
filterRef.current.appendChild(filterEl);

if (filterInstance?.eConditionBodies) {
const conditionBodies = filterInstance.eConditionBodies;
const targetIndex =
lastFilteredInputPosition === FILTER_INPUT_POSITIONS.SECOND
? FILTER_CONDITION_BODY_INDEX.SECOND
: FILTER_CONDITION_BODY_INDEX.FIRST;
const targetBody = conditionBodies[targetIndex];

if (targetBody) {
const input = targetBody.querySelector(
FILTER_INPUT_SELECTOR,
) as HTMLInputElement | null;
input?.focus();
}
}
};

const CustomHeader: React.FC<CustomHeaderParams> = ({
displayName,
enableSorting,
Expand All @@ -61,7 +108,12 @@ const CustomHeader: React.FC<CustomHeaderParams> = ({
column,
api,
}) => {
const { initialSortState, onColumnHeaderClicked } = context;
const {
initialSortState,
onColumnHeaderClicked,
lastFilteredColumn,
lastFilteredInputPosition,
} = context;
const colId = column?.getColId();
const colDef = column?.getColDef() as CustomColDef;
const userColDef = column.getUserProvidedColDef() as UserProvidedColDef;
Expand All @@ -77,7 +129,6 @@ const CustomHeader: React.FC<CustomHeaderParams> = ({
const isTimeComparison = !isMain && userColDef?.timeComparisonKey;
const sortKey = isMain ? colId.replace('Main', '').trim() : colId;

// Sorting logic
const clearSort = () => {
onColumnHeaderClicked({ column: { colId: sortKey, sort: null } });
setSort(null, false);
Expand Down Expand Up @@ -106,14 +157,35 @@ const CustomHeader: React.FC<CustomHeaderParams> = ({
e.stopPropagation();
setFilterVisible(!isFilterVisible);

const filterInstance = await api.getColumnFilterInstance<any>(column);
const filterInstance = (await api.getColumnFilterInstance(
column,
)) as AGGridFilterInstance | null;
const filterEl = filterInstance?.eGui;
if (filterEl && filterRef.current) {
filterRef.current.innerHTML = '';
filterRef.current.appendChild(filterEl);
}
};

// Re-open filter popover after server refresh (delay allows AG Grid to finish rendering)
Comment thread
amaannawab923 marked this conversation as resolved.
useEffect(() => {
if (lastFilteredColumn === colId && !isFilterVisible) {
const timeoutId = setTimeout(
() =>
autoOpenFilterAndFocus(
column,
api,
filterRef,
setFilterVisible,
lastFilteredInputPosition,
),
FILTER_POPOVER_OPEN_DELAY,
);
Comment thread
amaannawab923 marked this conversation as resolved.
return () => clearTimeout(timeoutId);
}
return undefined;
}, [lastFilteredColumn, colId, lastFilteredInputPosition]);

const handleMenuClick = (e: React.MouseEvent) => {
e.stopPropagation();
setMenuVisible(!isMenuVisible);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ import Pagination from './components/Pagination';
import SearchSelectDropdown from './components/SearchSelectDropdown';
import { SearchOption, SortByItem } from '../types';
import getInitialSortState, { shouldSort } from '../utils/getInitialSortState';
import getInitialFilterModel from '../utils/getInitialFilterModel';
import { PAGE_SIZE_OPTIONS } from '../consts';
import { getCompleteFilterState } from '../utils/filterStateManager';

export interface AgGridState extends Partial<GridState> {
timestamp?: number;
Expand Down Expand Up @@ -100,6 +102,8 @@ export interface AgGridTableProps {
showTotals: boolean;
width: number;
onColumnStateChange?: (state: AgGridChartStateWithMetadata) => void;
onFilterChanged?: (filterModel: Record<string, any>) => void;
metricColumns?: string[];
gridRef?: RefObject<AgGridReact>;
chartState?: AgGridChartState;
}
Expand Down Expand Up @@ -137,21 +141,36 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
showTotals,
width,
onColumnStateChange,
onFilterChanged,
metricColumns = [],
chartState,
}) => {
const gridRef = useRef<AgGridReact>(null);
const inputRef = useRef<HTMLInputElement>(null);
const rowData = useMemo(() => data, [data]);
const containerRef = useRef<HTMLDivElement>(null);
const lastCapturedStateRef = useRef<string | null>(null);
const filterOperationVersionRef = useRef(0);

const searchId = `search-${id}`;

const initialFilterModel = getInitialFilterModel(
chartState,
serverPaginationData,
serverPagination,
);

const gridInitialState: GridState = {
...(serverPagination && {
sort: {
sortModel: getInitialSortState(serverPaginationData?.sortBy || []),
},
}),
...(initialFilterModel && {
filter: {
filterModel: initialFilterModel,
},
}),
};

const defaultColDef = useMemo<ColDef>(
Expand Down Expand Up @@ -332,6 +351,56 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
[onColumnStateChange],
);

const handleFilterChanged = useCallback(async () => {
filterOperationVersionRef.current += 1;
const currentVersion = filterOperationVersionRef.current;

const completeFilterState = await getCompleteFilterState(
gridRef,
metricColumns,
);

// Skip stale operations from rapid filter changes
if (currentVersion !== filterOperationVersionRef.current) {
return;
}

// Reject invalid filter states (e.g., text filter on numeric column)
if (completeFilterState.originalFilterModel) {
const filterModel = completeFilterState.originalFilterModel;
const hasInvalidFilterType = Object.entries(filterModel).some(
([colId, filter]: [string, any]) => {
if (
filter?.filterType === 'text' &&
metricColumns?.includes(colId)
) {
return true;
}
return false;
},
);

if (hasInvalidFilterType) {
return;
}
}

if (
!isEqual(
serverPaginationData?.agGridFilterModel,
completeFilterState.originalFilterModel,
)
) {
if (onFilterChanged) {
onFilterChanged(completeFilterState);
}
}
Comment thread
amaannawab923 marked this conversation as resolved.
}, [
onFilterChanged,
metricColumns,
serverPaginationData?.agGridFilterModel,
]);

useEffect(() => {
if (
hasServerPageLengthChanged &&
Expand All @@ -356,19 +425,14 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
// This will make columns fill the grid width
params.api.sizeColumnsToFit();

// Restore saved AG Grid state from permalink if available
if (chartState && params.api) {
// Restore saved column state from permalink if available
// Note: filterModel is now handled via gridInitialState for better performance
if (chartState?.columnState && params.api) {
try {
if (chartState.columnState) {
params.api.applyColumnState?.({
state: chartState.columnState as ColumnState[],
applyOrder: true,
});
}

if (chartState.filterModel) {
params.api.setFilterModel?.(chartState.filterModel);
}
params.api.applyColumnState?.({
state: chartState.columnState as ColumnState[],
applyOrder: true,
});
} catch {
// Silently fail if state restoration fails
}
Expand Down Expand Up @@ -429,6 +493,7 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
rowSelection="multiple"
animateRows
onCellClicked={handleCrossFilter}
onFilterChanged={handleFilterChanged}
onStateUpdated={handleGridStateChange}
initialState={gridInitialState}
maintainColumnOrder
Expand Down Expand Up @@ -520,6 +585,9 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
serverPaginationData?.sortBy || [],
),
isActiveFilterValue,
lastFilteredColumn: serverPaginationData?.lastFilteredColumn,
lastFilteredInputPosition:
serverPaginationData?.lastFilteredInputPosition,
}}
/>
{serverPagination && (
Expand Down
Loading
Loading