Skip to content

Commit

Permalink
Merge branch 'master' into popular-features-demo-corner-border
Browse files Browse the repository at this point in the history
  • Loading branch information
KenanYusuf authored Jan 30, 2025
2 parents 8da65d5 + 1ea3ae2 commit 156f4a4
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 59 deletions.
2 changes: 2 additions & 0 deletions packages/x-data-grid-generator/src/hooks/useMockServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type UseMockServerResponse = {
getChildrenCount?: (row: GridRowModel) => number;
fetchRows: (url: string) => Promise<GridGetRowsResponse>;
loadNewData: () => void;
isReady: boolean;
};

type DataSet = 'Commodity' | 'Employee' | 'Movies';
Expand Down Expand Up @@ -367,5 +368,6 @@ export const useMockServer = (
loadNewData: () => {
setIndex((oldIndex) => oldIndex + 1);
},
isReady: Boolean(data?.rows?.length),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ export const useDataGridPremiumComponent = (
useGridRowGrouping(apiRef, props);
useGridHeaderFiltering(apiRef, props);
useGridTreeData(apiRef, props);
useGridDataSource(apiRef, props);
useGridAggregation(apiRef, props);
useGridDataSource(apiRef, props);
useGridKeyboardNavigation(apiRef, props);
useGridRowSelection(apiRef, props);
useGridCellSelection(apiRef, props);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
GRID_AGGREGATION_ROOT_FOOTER_ROW_ID,
GRID_ROOT_GROUP_ID,
} from '@mui/x-data-grid-premium';
import { SinonSpy, spy } from 'sinon';
import { spy } from 'sinon';
import { getColumnHeaderCell } from 'test/utils/helperFn';

const isJSDOM = /jsdom/.test(window.navigator.userAgent);
Expand All @@ -22,9 +22,17 @@ describe('<DataGridPremium /> - Data source aggregation', () => {
const { render } = createRenderer();

let apiRef: RefObject<GridApi | null>;
let getRowsSpy: SinonSpy;
const fetchRowsSpy = spy();
let mockServer: ReturnType<typeof useMockServer>;

// TODO: Resets strictmode calls, need to find a better fix for this, maybe an AbortController?
function Reset() {
React.useLayoutEffect(() => {
fetchRowsSpy.resetHistory();
}, []);
return null;
}

function TestDataSourceAggregation(
props: Partial<DataGridPremiumProps> & {
getAggregatedValue?: GridDataSource['getAggregatedValue'];
Expand All @@ -39,8 +47,8 @@ describe('<DataGridPremium /> - Data source aggregation', () => {

const { fetchRows } = mockServer;

const dataSource: GridDataSource = React.useMemo(
() => ({
const dataSource: GridDataSource = React.useMemo(() => {
return {
getRows: async (params: GridGetRowsParams) => {
const urlParams = new URLSearchParams({
filterModel: JSON.stringify(params.filterModel),
Expand All @@ -49,6 +57,8 @@ describe('<DataGridPremium /> - Data source aggregation', () => {
aggregationModel: JSON.stringify(params.aggregationModel),
});

fetchRowsSpy(params);

const getRowsResponse = await fetchRows(
`https://mui.com/x/api/data-grid?${urlParams.toString()}`,
);
Expand All @@ -64,12 +74,8 @@ describe('<DataGridPremium /> - Data source aggregation', () => {
((row, field) => {
return row[`${field}Aggregate`];
}),
}),
[fetchRows, getAggregatedValueProp],
);

getRowsSpy?.restore();
getRowsSpy = spy(dataSource, 'getRows');
};
}, [fetchRows, getAggregatedValueProp]);

const baselineProps = {
unstable_dataSource: dataSource,
Expand All @@ -84,8 +90,13 @@ describe('<DataGridPremium /> - Data source aggregation', () => {
},
};

if (!mockServer.isReady) {
return null;
}

return (
<div style={{ width: 300, height: 300 }}>
<Reset />
<DataGridPremium apiRef={apiRef} {...baselineProps} {...rest} />
</div>
);
Expand All @@ -100,7 +111,7 @@ describe('<DataGridPremium /> - Data source aggregation', () => {
it('should show aggregation option in the column menu', async () => {
const { user } = render(<TestDataSourceAggregation />);
await waitFor(() => {
expect(getRowsSpy.callCount).to.be.greaterThan(0);
expect(fetchRowsSpy.callCount).to.be.greaterThan(0);
});
await user.click(within(getColumnHeaderCell(0)).getByLabelText('Menu'));
expect(screen.queryByLabelText('Aggregation')).not.to.equal(null);
Expand All @@ -109,7 +120,7 @@ describe('<DataGridPremium /> - Data source aggregation', () => {
it('should not show aggregation option in the column menu when no aggregation function is defined', async () => {
const { user } = render(<TestDataSourceAggregation aggregationFunctions={{}} />);
await waitFor(() => {
expect(getRowsSpy.callCount).to.be.greaterThan(0);
expect(fetchRowsSpy.callCount).to.be.greaterThan(0);
});
await user.click(within(getColumnHeaderCell(0)).getByLabelText('Menu'));
expect(screen.queryByLabelText('Aggregation')).to.equal(null);
Expand All @@ -124,9 +135,10 @@ describe('<DataGridPremium /> - Data source aggregation', () => {
/>,
);
await waitFor(() => {
expect(getRowsSpy.callCount).to.be.greaterThan(0);
expect(fetchRowsSpy.callCount).to.be.greaterThan(0);
});
expect(getRowsSpy.args[0][0].aggregationModel).to.deep.equal({ id: 'size' });

expect(fetchRowsSpy.lastCall.args[0].aggregationModel).to.deep.equal({ id: 'size' });
});

it('should show the aggregation footer row when aggregation is enabled', async () => {
Expand All @@ -146,12 +158,13 @@ describe('<DataGridPremium /> - Data source aggregation', () => {
});

it('should derive the aggregation values using `dataSource.getAggregatedValue`', async () => {
const getAggregatedValue = () => 'Agg value';
render(
<TestDataSourceAggregation
initialState={{
aggregation: { model: { id: 'size' } },
}}
getAggregatedValue={() => 'Agg value'}
getAggregatedValue={getAggregatedValue}
/>,
);
await waitFor(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { throttle } from '@mui/x-internals/throttle';
import { unstable_debounce as debounce } from '@mui/utils';
import {
useGridApiEventHandler,
useGridSelector,
gridSortModelSelector,
gridFilterModelSelector,
GridEventListener,
Expand Down Expand Up @@ -70,11 +69,6 @@ export const useGridDataSourceLazyLoader = (

const [lazyLoadingRowsUpdateStrategyActive, setLazyLoadingRowsUpdateStrategyActive] =
React.useState(false);
const sortModel = useGridSelector(privateApiRef, gridSortModelSelector);
const filterModel = useGridSelector(privateApiRef, gridFilterModelSelector);
const paginationModel = useGridSelector(privateApiRef, gridPaginationModelSelector);
const filteredSortedRowIds = useGridSelector(privateApiRef, gridFilteredSortedRowIdsSelector);
const dimensions = useGridSelector(privateApiRef, gridDimensionsSelector);
const renderedRowsIntervalCache = React.useRef(INTERVAL_CACHE_INITIAL_STATE);
const previousLastRowIndex = React.useRef(0);
const loadingTrigger = React.useRef<LoadingTrigger | null>(null);
Expand All @@ -97,20 +91,25 @@ export const useGridDataSourceLazyLoader = (
return params;
}

const paginationModel = gridPaginationModelSelector(privateApiRef);

return {
...params,
start: params.start - (params.start % paginationModel.pageSize),
end: params.end + paginationModel.pageSize - (params.end % paginationModel.pageSize) - 1,
};
},
[paginationModel],
[privateApiRef],
);

const resetGrid = React.useCallback(() => {
privateApiRef.current.setLoading(true);
privateApiRef.current.unstable_dataSource.cache.clear();
rowsStale.current = true;
previousLastRowIndex.current = 0;
const paginationModel = gridPaginationModelSelector(privateApiRef);
const sortModel = gridSortModelSelector(privateApiRef);
const filterModel = gridFilterModelSelector(privateApiRef);
const getRowsParams: GridGetRowsParams = {
start: 0,
end: paginationModel.pageSize - 1,
Expand All @@ -119,7 +118,7 @@ export const useGridDataSourceLazyLoader = (
};

fetchRows(getRowsParams);
}, [privateApiRef, sortModel, filterModel, paginationModel.pageSize, fetchRows]);
}, [privateApiRef, fetchRows]);

const ensureValidRowCount = React.useCallback(
(previousLoadingTrigger: LoadingTrigger, newLoadingTrigger: LoadingTrigger) => {
Expand Down Expand Up @@ -280,6 +279,8 @@ export const useGridDataSourceLazyLoader = (
rebuildSkeletonRows();
}

const filteredSortedRowIds = gridFilteredSortedRowIdsSelector(privateApiRef);

const startingIndex =
typeof fetchParams.start === 'string'
? Math.max(filteredSortedRowIds.indexOf(fetchParams.start), 0)
Expand All @@ -303,13 +304,7 @@ export const useGridDataSourceLazyLoader = (
);
privateApiRef.current.requestPipeProcessorsApplication('hydrateRows');
},
[
privateApiRef,
filteredSortedRowIds,
updateLoadingTrigger,
rebuildSkeletonRows,
addSkeletonRows,
],
[privateApiRef, updateLoadingTrigger, rebuildSkeletonRows, addSkeletonRows],
);

const handleRowCountChange = React.useCallback(() => {
Expand All @@ -333,12 +328,16 @@ export const useGridDataSourceLazyLoader = (
return;
}

const dimensions = gridDimensionsSelector(privateApiRef.current.state);
const position = newScrollPosition.top + dimensions.viewportInnerSize.height;
const target = dimensions.contentSize.height - props.scrollEndThreshold;

if (position >= target) {
previousLastRowIndex.current = renderContext.lastRowIndex;

const paginationModel = gridPaginationModelSelector(privateApiRef);
const sortModel = gridSortModelSelector(privateApiRef);
const filterModel = gridFilterModelSelector(privateApiRef);
const getRowsParams: GridGetRowsParams = {
start: renderContext.lastRowIndex,
end: renderContext.lastRowIndex + paginationModel.pageSize - 1,
Expand All @@ -347,19 +346,11 @@ export const useGridDataSourceLazyLoader = (
};

privateApiRef.current.setLoading(true);

fetchRows(adjustRowParams(getRowsParams));
}
},
[
privateApiRef,
props.scrollEndThreshold,
sortModel,
filterModel,
dimensions,
paginationModel.pageSize,
adjustRowParams,
fetchRows,
],
[privateApiRef, props.scrollEndThreshold, adjustRowParams, fetchRows],
);

const handleRenderedRowsIntervalChange = React.useCallback<
Expand All @@ -370,6 +361,8 @@ export const useGridDataSourceLazyLoader = (
return;
}

const sortModel = gridSortModelSelector(privateApiRef);
const filterModel = gridFilterModelSelector(privateApiRef);
const getRowsParams: GridGetRowsParams = {
start: params.firstRowIndex,
end: params.lastRowIndex,
Expand All @@ -389,10 +382,7 @@ export const useGridDataSourceLazyLoader = (
lastRowToRender: params.lastRowIndex,
};

const currentVisibleRows = getVisibleRows(privateApiRef, {
pagination: props.pagination,
paginationMode: props.paginationMode,
});
const currentVisibleRows = getVisibleRows(privateApiRef);

const skeletonRowsSection = findSkeletonRowsSection({
apiRef: privateApiRef,
Expand All @@ -412,27 +402,26 @@ export const useGridDataSourceLazyLoader = (

fetchRows(adjustRowParams(getRowsParams));
},
[
privateApiRef,
props.pagination,
props.paginationMode,
sortModel,
filterModel,
adjustRowParams,
fetchRows,
],
[privateApiRef, adjustRowParams, fetchRows],
);

const throttledHandleRenderedRowsIntervalChange = React.useMemo(
() => throttle(handleRenderedRowsIntervalChange, props.unstable_lazyLoadingRequestThrottleMs),
[props.unstable_lazyLoadingRequestThrottleMs, handleRenderedRowsIntervalChange],
);
React.useEffect(() => {
return () => {
throttledHandleRenderedRowsIntervalChange.clear();
};
}, [throttledHandleRenderedRowsIntervalChange]);

const handleGridSortModelChange = React.useCallback<GridEventListener<'sortModelChange'>>(
(newSortModel) => {
rowsStale.current = true;
throttledHandleRenderedRowsIntervalChange.clear();
previousLastRowIndex.current = 0;
const renderContext = gridRenderContextSelector(privateApiRef);
const paginationModel = gridPaginationModelSelector(privateApiRef);
const rangeParams =
loadingTrigger.current === LoadingTrigger.VIEWPORT
? {
Expand All @@ -444,6 +433,8 @@ export const useGridDataSourceLazyLoader = (
end: paginationModel.pageSize - 1,
};

const filterModel = gridFilterModelSelector(privateApiRef);

const getRowsParams: GridGetRowsParams = {
...rangeParams,
sortModel: newSortModel,
Expand All @@ -453,13 +444,17 @@ export const useGridDataSourceLazyLoader = (
privateApiRef.current.setLoading(true);
debouncedFetchRows(adjustRowParams(getRowsParams));
},
[privateApiRef, filterModel, paginationModel.pageSize, adjustRowParams, debouncedFetchRows],
[privateApiRef, adjustRowParams, debouncedFetchRows, throttledHandleRenderedRowsIntervalChange],
);

const handleGridFilterModelChange = React.useCallback<GridEventListener<'filterModelChange'>>(
(newFilterModel) => {
rowsStale.current = true;
throttledHandleRenderedRowsIntervalChange.clear();
previousLastRowIndex.current = 0;

const paginationModel = gridPaginationModelSelector(privateApiRef);
const sortModel = gridSortModelSelector(privateApiRef);
const getRowsParams: GridGetRowsParams = {
start: 0,
end: paginationModel.pageSize - 1,
Expand All @@ -470,7 +465,7 @@ export const useGridDataSourceLazyLoader = (
privateApiRef.current.setLoading(true);
debouncedFetchRows(getRowsParams);
},
[privateApiRef, sortModel, paginationModel.pageSize, debouncedFetchRows],
[privateApiRef, debouncedFetchRows, throttledHandleRenderedRowsIntervalChange],
);

const handleStrategyActivityChange = React.useCallback<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ describeSkipIf(isJSDOM)('<DataGridPro /> - Data source', () => {
let apiRef: RefObject<GridApi | null>;
let mockServer: ReturnType<typeof useMockServer>;

// TODO: Resets strictmode calls, need to find a better fix for this, maybe an AbortController?
function Reset() {
React.useLayoutEffect(() => {
fetchRowsSpy.resetHistory();
}, []);
return null;
}

function TestDataSource(props: Partial<DataGridProProps> & { shouldRequestsFail?: boolean }) {
apiRef = useGridApiRef();
mockServer = useMockServer(
Expand All @@ -62,7 +70,6 @@ describeSkipIf(isJSDOM)('<DataGridPro /> - Data source', () => {
const { fetchRows } = mockServer;

const dataSource: GridDataSource = React.useMemo(() => {
fetchRowsSpy.resetHistory();
return {
getRows: async (params: GridGetRowsParams) => {
const urlParams = new URLSearchParams({
Expand All @@ -84,8 +91,13 @@ describeSkipIf(isJSDOM)('<DataGridPro /> - Data source', () => {
};
}, [fetchRows]);

if (!mockServer.isReady) {
return null;
}

return (
<div style={{ width: 300, height: 300 }}>
<Reset />
<DataGridPro
apiRef={apiRef}
columns={mockServer.columns}
Expand Down
Loading

0 comments on commit 156f4a4

Please # to comment.