From 5ae3b229832b85319471df523057df9b235bd970 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Mon, 23 Sep 2024 12:08:42 +0200 Subject: [PATCH] Extend fetchRows API to enable request retries. Keep compatibility with the old signature --- .../GridDataSourceTreeDataGroupingCell.tsx | 2 +- .../hooks/features/dataSource/interfaces.ts | 14 +++-- .../features/dataSource/useGridDataSource.ts | 51 +++++++++++++------ .../features/treeData/useGridTreeData.tsx | 2 +- scripts/x-data-grid-premium.exports.json | 1 + scripts/x-data-grid-pro.exports.json | 1 + 6 files changed, 49 insertions(+), 22 deletions(-) diff --git a/packages/x-data-grid-pro/src/components/GridDataSourceTreeDataGroupingCell.tsx b/packages/x-data-grid-pro/src/components/GridDataSourceTreeDataGroupingCell.tsx index 79e002211adf2..cb2cec9739237 100644 --- a/packages/x-data-grid-pro/src/components/GridDataSourceTreeDataGroupingCell.tsx +++ b/packages/x-data-grid-pro/src/components/GridDataSourceTreeDataGroupingCell.tsx @@ -61,7 +61,7 @@ function GridTreeDataGroupingCellIcon(props: GridTreeDataGroupingCellIconProps) const handleClick = (event: React.MouseEvent) => { if (!rowNode.childrenExpanded) { // always fetch/get from cache the children when the node is expanded - apiRef.current.unstable_dataSource.fetchRows(id); + apiRef.current.unstable_dataSource.fetchRows({ parentId: id }); } else { apiRef.current.setRowChildrenExpansion(id, !rowNode.childrenExpanded); } diff --git a/packages/x-data-grid-pro/src/hooks/features/dataSource/interfaces.ts b/packages/x-data-grid-pro/src/hooks/features/dataSource/interfaces.ts index 90bfc4ed39de2..073c324eaa704 100644 --- a/packages/x-data-grid-pro/src/hooks/features/dataSource/interfaces.ts +++ b/packages/x-data-grid-pro/src/hooks/features/dataSource/interfaces.ts @@ -6,6 +6,12 @@ export interface GridDataSourceState { errors: Record; } +export interface FetchRowsOptions { + parentId?: GridRowId; + start?: number | string; + end?: number; +} + /** * The base data source API interface that is available in the grid [[apiRef]]. */ @@ -23,11 +29,11 @@ export interface GridDataSourceApiBase { */ setChildrenFetchError: (parentId: GridRowId, error: Error | null) => void; /** - * Fetches the rows from the server for a given `parentId`. - * If no `parentId` is provided, it fetches the root rows. - * @param {string} parentId The id of the group to be fetched. + * Fetches the rows from the server for with given options. + * If no `parentId` option is provided, it fetches the root rows. + * @param {FetchRowsOptions} options Options that allow setting the specific request params. */ - fetchRows: (parentId?: GridRowId) => void; + fetchRows: (options?: GridRowId | FetchRowsOptions) => void; /** * The data source cache object. */ diff --git a/packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSource.ts b/packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSource.ts index ac11cf4e048e7..c9a3a2a5453c3 100644 --- a/packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSource.ts +++ b/packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSource.ts @@ -8,6 +8,7 @@ import { useGridSelector, GridRowId, gridPaginationModelSelector, + gridFilteredSortedRowIdsSelector, } from '@mui/x-data-grid'; import { GridGetRowsParams, @@ -17,7 +18,12 @@ import { import { GridPrivateApiPro } from '../../../models/gridApiPro'; import { DataGridProProcessedProps } from '../../../models/dataGridProProps'; import { gridGetRowsParamsSelector, gridDataSourceErrorsSelector } from './gridDataSourceSelector'; -import { GridDataSourceApi, GridDataSourceApiBase, GridDataSourcePrivateApi } from './interfaces'; +import { + FetchRowsOptions, + GridDataSourceApi, + GridDataSourceApiBase, + GridDataSourcePrivateApi, +} from './interfaces'; import { NestedDataManager, RequestStatus, runIf } from './utils'; import { GridDataSourceCache } from '../../../models'; import { GridDataSourceCacheDefault, GridDataSourceCacheDefaultConfig } from './cache'; @@ -70,11 +76,10 @@ export const useGridDataSource = ( ).current; const paginationModel = useGridSelector(apiRef, gridPaginationModelSelector); const groupsToAutoFetch = useGridSelector(apiRef, gridRowGroupsToFetchSelector); + const filteredSortedRowIds = useGridSelector(apiRef, gridFilteredSortedRowIdsSelector); const scheduledGroups = React.useRef(0); const isLazyLoaded = !!props.unstable_dataSource && props.lazyLoading; - const rowFetchSlice = React.useRef({}); - const onError = props.unstable_onDataSourceError; const cacheChunkSize = React.useMemo(() => { @@ -108,12 +113,25 @@ export const useGridDataSource = ( ); const fetchRows = React.useCallback( - async (parentId?: GridRowId) => { + async (options?: GridRowId | FetchRowsOptions) => { const getRows = props.unstable_dataSource?.getRows; if (!getRows) { return; } + const hasDeprecatedArgument = typeof options === 'string' || typeof options === 'number'; + if (hasDeprecatedArgument) { + console.warn( + '`fetchRows` argument should be an options object (`FetchRowsOptions`). `GridRowId` argument is deprecated.', + ); + } + + const parentId = hasDeprecatedArgument || !options ? options : options.parentId; + const fetchParamsOverride = + hasDeprecatedArgument || options?.start === undefined || options?.end === undefined + ? {} + : { start: options.start, end: options.end }; + if (parentId) { nestedDataManager.queue([parentId]); return; @@ -126,15 +144,17 @@ export const useGridDataSource = ( apiRef.current.resetDataSourceState(); } - const fetchParams = { ...gridGetRowsParamsSelector(apiRef), ...rowFetchSlice.current }; - const startingIndex = fetchParams.start; + const fetchParams = { ...gridGetRowsParamsSelector(apiRef), ...fetchParamsOverride }; + const startingIndex = + typeof fetchParams.start === 'string' + ? Math.max(filteredSortedRowIds.indexOf(fetchParams.start), 0) + : fetchParams.start; + const cachedData = apiRef.current.unstable_dataSource.cache.get(fetchParams); if (cachedData !== undefined) { const rows = cachedData.rows; - if (cachedData.rowCount && cachedData.rowCount >= 0) { - apiRef.current.setRowCount(cachedData.rowCount); - } + apiRef.current.setRowCount(cachedData.rowCount === undefined ? -1 : cachedData.rowCount); if (isLazyLoaded) { apiRef.current.unstable_replaceRows(startingIndex, rows); } else { @@ -165,7 +185,9 @@ export const useGridDataSource = ( apiRef.current.setLoading(false); apiRef.current.publishEvent('rowsFetched'); } catch (error) { - apiRef.current.setRows([]); + if (!isLazyLoaded) { + apiRef.current.setRows([]); + } apiRef.current.setLoading(false); onError?.(error as Error, fetchParams); } @@ -175,15 +197,14 @@ export const useGridDataSource = ( apiRef, props.unstable_dataSource?.getRows, isLazyLoaded, + filteredSortedRowIds, onError, - rowFetchSlice, ], ); const fetchRowBatch = React.useCallback( (fetchParams: GridGetRowsParams) => { - rowFetchSlice.current = adjustRowParams(fetchParams); - return fetchRows(); + return fetchRows(adjustRowParams(fetchParams)); }, [adjustRowParams, fetchRows], ); @@ -214,9 +235,7 @@ export const useGridDataSource = ( const rows = cachedData.rows; nestedDataManager.setRequestSettled(id); apiRef.current.updateServerRows(rows, rowNode.path); - if (cachedData.rowCount && cachedData.rowCount >= 0) { - apiRef.current.setRowCount(cachedData.rowCount); - } + apiRef.current.setRowCount(cachedData.rowCount === undefined ? -1 : cachedData.rowCount); apiRef.current.setRowChildrenExpansion(id, true); apiRef.current.unstable_dataSource.setChildrenLoading(id, false); return; diff --git a/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeData.tsx b/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeData.tsx index 8f09f695627d4..39b0edf303443 100644 --- a/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeData.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeData.tsx @@ -25,7 +25,7 @@ export const useGridTreeData = ( } if (props.unstable_dataSource && !params.rowNode.childrenExpanded) { - apiRef.current.unstable_dataSource.fetchRows(params.id); + apiRef.current.unstable_dataSource.fetchRows({ parentId: params.id }); return; } diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index 6aacf6db0253d..76176c75b997c 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -36,6 +36,7 @@ { "name": "ElementSize", "kind": "Interface" }, { "name": "EMPTY_PINNED_COLUMN_FIELDS", "kind": "Variable" }, { "name": "EMPTY_RENDER_CONTEXT", "kind": "Variable" }, + { "name": "FetchRowsOptions", "kind": "Interface" }, { "name": "FilterColumnsArgs", "kind": "Interface" }, { "name": "FilterPanelPropsOverrides", "kind": "Interface" }, { "name": "FocusElement", "kind": "Interface" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index d5fdf09cdd228..6e34d400557ae 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -35,6 +35,7 @@ { "name": "ElementSize", "kind": "Interface" }, { "name": "EMPTY_PINNED_COLUMN_FIELDS", "kind": "Variable" }, { "name": "EMPTY_RENDER_CONTEXT", "kind": "Variable" }, + { "name": "FetchRowsOptions", "kind": "Interface" }, { "name": "FilterColumnsArgs", "kind": "Interface" }, { "name": "FilterPanelPropsOverrides", "kind": "Interface" }, { "name": "FocusElement", "kind": "Interface" },