Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 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 '@superset-ui/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,56 @@ const getSortIcon = (sortState: SortState[], colId: string | null) => {
return null;
};

/**
* Auto-opens the filter popover and focuses the correct input field.
Comment thread
amaannawab923 marked this conversation as resolved.
Outdated
* Used when restoring filter state after server-side filtering to maintain UX continuity.
*
* @param column - AG Grid column instance
* @param api - AG Grid API instance
* @param filterRef - React ref to the filter DOM container
* @param setFilterVisible - State setter to control filter popover visibility
* @param lastFilteredInputPosition - Position of the last filtered input
*/
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;

// Clear children safely without innerHTML to prevent XSS
while (filterRef.current.firstChild) {
filterRef.current.removeChild(filterRef.current.firstChild);
}
filterRef.current.appendChild(filterEl);

// Focus the correct input based on lastFilteredInputPosition
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 +121,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 Down Expand Up @@ -102,18 +167,44 @@ const CustomHeader: React.FC<CustomHeaderParams> = ({
else clearSort();
};

const handleFilterClick = async (e: React.MouseEvent) => {
e.stopPropagation();
const handleFilterClick = async (e?: React.MouseEvent) => {
if (e) {
e.stopPropagation();
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the event triggering this be undefined?

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 = '';
// Clear children safely without innerHTML to prevent XSS
while (filterRef.current.firstChild) {
filterRef.current.removeChild(filterRef.current.firstChild);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? There is no user input involved here

filterRef.current.appendChild(filterEl);
}
};

Comment thread
amaannawab923 marked this conversation as resolved.
// Auto-open filter popover for the last filtered column
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,6 +141,8 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
showTotals,
width,
onColumnStateChange,
onFilterChanged,
metricColumns = [],
chartState,
}) => {
const gridRef = useRef<AgGridReact>(null);
Expand All @@ -146,12 +152,24 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
const lastCapturedStateRef = useRef<string | null>(null);

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 +350,29 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
[onColumnStateChange],
);

const handleFilterChanged = useCallback(async () => {
const completeFilterState = await getCompleteFilterState(
gridRef,
metricColumns,
);

// Guard clause: Only call onFilterChanged if filter model has actually changed
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 +397,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 +465,7 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
rowSelection="multiple"
animateRows
onCellClicked={handleCrossFilter}
onFilterChanged={handleFilterChanged}
onStateUpdated={handleGridStateChange}
initialState={gridInitialState}
maintainColumnOrder
Expand Down Expand Up @@ -520,6 +557,9 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
serverPaginationData?.sortBy || [],
),
isActiveFilterValue,
lastFilteredColumn: serverPaginationData?.lastFilteredColumn,
lastFilteredInputPosition:
serverPaginationData?.lastFilteredInputPosition,
}}
/>
{serverPagination && (
Expand Down
Loading
Loading