mirror of
https://github.com/apache/superset.git
synced 2026-04-27 03:55:47 +00:00
feat(ag-grid): Server Side Filtering for Column Level Filters (#35683)
This commit is contained in:
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -137,6 +141,8 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
|
||||
showTotals,
|
||||
width,
|
||||
onColumnStateChange,
|
||||
onFilterChanged,
|
||||
metricColumns = [],
|
||||
chartState,
|
||||
}) => {
|
||||
const gridRef = useRef<AgGridReact>(null);
|
||||
@@ -144,14 +150,27 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
|
||||
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>(
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
onFilterChanged,
|
||||
metricColumns,
|
||||
serverPaginationData?.agGridFilterModel,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
hasServerPageLengthChanged &&
|
||||
@@ -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
|
||||
}
|
||||
@@ -429,6 +493,7 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
|
||||
rowSelection="multiple"
|
||||
animateRows
|
||||
onCellClicked={handleCrossFilter}
|
||||
onFilterChanged={handleFilterChanged}
|
||||
onStateUpdated={handleGridStateChange}
|
||||
initialState={gridInitialState}
|
||||
maintainColumnOrder
|
||||
@@ -520,6 +585,9 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
|
||||
serverPaginationData?.sortBy || [],
|
||||
),
|
||||
isActiveFilterValue,
|
||||
lastFilteredColumn: serverPaginationData?.lastFilteredColumn,
|
||||
lastFilteredInputPosition:
|
||||
serverPaginationData?.lastFilteredInputPosition,
|
||||
}}
|
||||
/>
|
||||
{serverPagination && (
|
||||
|
||||
Reference in New Issue
Block a user