Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[XGrid] Make Infinite loading support rowCount #1715

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ada4c4d
Add support for detecting when virtual page changes
DanailH May 19, 2021
21196bd
Initial version
DanailH May 20, 2021
ddc90de
Remove commented out code
DanailH May 20, 2021
4c0a5b1
Add base skeleton row logic and styles
DanailH May 24, 2021
1f94832
Make new skeleton components public
DanailH May 24, 2021
e520dbc
Sort out loading on scroll and sorting
DanailH May 25, 2021
dd7af2c
Fix filter functionality
DanailH May 26, 2021
b841f96
rename loadRows option to getRows
DanailH May 27, 2021
4ab7cd0
resolve conflicts
DanailH May 27, 2021
97c86a8
Remove dead code and fix tests
DanailH May 27, 2021
802ff36
Fix styles
DanailH May 27, 2021
9dd3579
Fix server pagination
DanailH May 27, 2021
8bbbe71
Rename methods and decouple api method from grid option
DanailH May 31, 2021
6222f1e
PR comments
DanailH May 31, 2021
8fc923e
Fix trailing rows issue
DanailH May 31, 2021
369cb68
Add tests
DanailH Jun 1, 2021
60a7adc
Remove code
DanailH Jun 1, 2021
11d936a
Finished tests
DanailH Jun 2, 2021
f9f2ab1
Add docs
DanailH Jun 2, 2021
59aa187
Load one page more
DanailH Jun 9, 2021
658879f
add story
DanailH Jun 9, 2021
f81a1cf
Update docs/src/pages/components/data-grid/rows/rows.md
DanailH Jun 15, 2021
4290995
PR comments
DanailH Jun 15, 2021
323f10a
Merge branch 'feature/DataGrid-1247-rowCount-infite-loader' of github…
DanailH Jun 15, 2021
02b02de
resolve conflict
DanailH Jun 15, 2021
b481127
run prettier
DanailH Jun 15, 2021
42f0830
format docs api
DanailH Jun 15, 2021
c08eb4b
Fix docs
DanailH Jun 16, 2021
2007edd
Fix conflicts
DanailH Jun 16, 2021
cdcdfee
Resolve conflicts
DanailH Jun 22, 2021
f96f635
Add infniteLoaderMode option
DanailH Jun 22, 2021
828a186
Fix tests
DanailH Jun 22, 2021
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
1 change: 1 addition & 0 deletions docs/pages/api-docs/data-grid/data-grid.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { DataGrid } from '@material-ui/data-grid';
| <span class="prop-name">hideFooterRowCount</span> | <span class="prop-type">boolean</span> | false | If `true`, the row count in the footer is hidden. |
| <span class="prop-name">hideFooterSelectedRowCount</span> | <span class="prop-type">boolean</span> | false | If `true`, the selected row count in the footer is hidden. |
| <span class="prop-name">icons</span> | <span class="prop-type">IconsOptions</span> | | Set of icons used in the grid. |
| <span class="prop-name">infniteLoadingMode</span> | <span class="prop-type">GridFeatureMode</span> | 'client' | Infnite loading can be processed on the server or client-side. Set it to 'client' if you would like to handle the infnite loading on the client-side. Set it to 'server' if you would like to handle the infnite loading on the server-side. |
| <span class="prop-name">isCellEditable</span> | <span class="prop-type">(params: GridCellParams) => boolean</span> | | Callback fired when a cell is rendered, returns true if the cell is editable. |
| <span class="prop-name">isRowSelectable</span> | <span class="prop-type">(params: GridRowParams) => boolean</span> | | Determines if a row can be selected. |
| <span class="prop-name">loading</span> | <span class="prop-type">boolean</span> | false | If `true`, a loading overlay is displayed. |
Expand Down
1 change: 1 addition & 0 deletions docs/pages/api-docs/data-grid/grid-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import { GridApi } from '@material-ui/x-grid';
| <span class="prop-name">hideColumnMenu</span> | <span class="prop-type">() =&gt; void</span> | Hides the column menu that is open. |
| <span class="prop-name">hideFilterPanel</span> | <span class="prop-type">() =&gt; void</span> | Hides the filter panel. |
| <span class="prop-name">hidePreferences</span> | <span class="prop-type">() =&gt; void</span> | Hides the preferences panel. |
| <span class="prop-name">insertRows</span> | <span class="prop-type">(params: GridInsertRowParams) =&gt; void</span> | Inserts a new subset of Rows. |
| <span class="prop-name">isCellEditable</span> | <span class="prop-type">(params: GridCellParams) =&gt; boolean</span> | Controls if a cell is editable. |
| <span class="prop-name">isColumnVisibleInWindow</span> | <span class="prop-type">(colIndex: number) =&gt; boolean</span> | Checks if a column at the index given by `colIndex` is currently visible in the viewport. |
| <span class="prop-name">publishEvent</span> | <span class="prop-type">(name: string, ...args: any[]) =&gt; void</span> | Emits an event. |
Expand Down
1 change: 1 addition & 0 deletions docs/pages/api-docs/data-grid/x-grid.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { XGrid } from '@material-ui/x-grid';
| <span class="prop-name">hideFooterRowCount</span> | <span class="prop-type">boolean</span> | false | If `true`, the row count in the footer is hidden. |
| <span class="prop-name">hideFooterSelectedRowCount</span> | <span class="prop-type">boolean</span> | false | If `true`, the selected row count in the footer is hidden. |
| <span class="prop-name">icons</span> | <span class="prop-type">IconsOptions</span> | | Set of icons used in the grid. |
| <span class="prop-name">infniteLoadingMode</span> | <span class="prop-type">GridFeatureMode</span> | 'client' | Infnite loading can be processed on the server or client-side. Set it to 'client' if you would like to handle the infnite loading on the client-side. Set it to 'server' if you would like to handle the infnite loading on the server-side. |
| <span class="prop-name">isCellEditable</span> | <span class="prop-type">(params: GridCellParams) => boolean</span> | | Callback fired when a cell is rendered, returns true if the cell is editable. |
| <span class="prop-name">isRowSelectable</span> | <span class="prop-type">(params: GridRowParams) => boolean</span> | | Determines if a row can be selected. |
| <span class="prop-name">loading</span> | <span class="prop-type">boolean</span> | false | If `true`, a loading overlay is displayed.. |
Expand Down
8 changes: 8 additions & 0 deletions docs/src/pages/components/data-grid/events/events.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,13 @@
{
"name": "columnVisibilityChange",
"description": "Fired when a column visibility changes. Called with a GridColumnVisibilityChangeParams object."
},
{
"name": "virtualPageChange",
"description": "Fired when the virtual page changes. Called with a GridVirtualPageChangeParams object."
},
{
"name": "fetchRows",
"description": "Fired when the virtual page changes. Called with a GridFetchRowsParams object."
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as React from 'react';
import { XGrid } from '@material-ui/x-grid';
import {
useDemoData,
getRealData,
getCommodityColumns,
} from '@material-ui/x-grid-data-generator';

async function sleep(duration) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, duration);
});
}

const loadServerRows = async (newRowLength) => {
const newData = await getRealData(newRowLength, getCommodityColumns());
// Simulate network throttle
await sleep(Math.random() * 100 + 100);

return newData.rows;
};

export default function InfiniteLoadingGrid() {
const { data } = useDemoData({
dataSet: 'Commodity',
rowLength: 10,
maxColumns: 6,
});

const handleFetchRows = async (params) => {
const newRowsBatch = await loadServerRows(params.viewportPageSize);

params.api.current.insertRows({
startIndex: params.startIndex,
pageSize: params.viewportPageSize,
newRows: newRowsBatch,
});
};

return (
<div style={{ height: 400, width: '100%' }}>
<XGrid
{...data}
hideFooterPagination
rowCount={50}
sortingMode="server"
filterMode="server"
infniteLoadingMode="server"
onFetchRows={handleFetchRows}
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as React from 'react';
import { GridFetchRowsParams, GridRowData, XGrid } from '@material-ui/x-grid';
import {
useDemoData,
getRealData,
getCommodityColumns,
} from '@material-ui/x-grid-data-generator';

async function sleep(duration) {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, duration);
});
}

const loadServerRows = async (newRowLength: number): Promise<GridRowData[]> => {
const newData = await getRealData(newRowLength, getCommodityColumns());
// Simulate network throttle
await sleep(Math.random() * 100 + 100);

return newData.rows;
};

export default function InfiniteLoadingGrid() {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
export default function InfiniteLoadingGrid() {
export default function ServerInfiniteLoadingGrid() {

const { data } = useDemoData({
dataSet: 'Commodity',
rowLength: 10,
maxColumns: 6,
});

const handleFetchRows = async (params: GridFetchRowsParams) => {
const newRowsBatch: GridRowData[] = await loadServerRows(
params.viewportPageSize,
);

params.api.current.insertRows({
startIndex: params.startIndex,
pageSize: params.viewportPageSize,
newRows: newRowsBatch,
});
Comment on lines +37 to +41
Copy link
Member

@oliviertassinari oliviertassinari Jun 14, 2021

Choose a reason for hiding this comment

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

This looks wrong. The data grid is the best one to know if the resolved value is still relevant or not, not the developer at this level. I think that we should simply yield:

Suggested change
params.api.current.insertRows({
startIndex: params.startIndex,
pageSize: params.viewportPageSize,
newRows: newRowsBatch,
});
return {
startIndex: params.startIndex,
pageSize: params.viewportPageSize,
newRows: newRowsBatch,
};

Or at least, if we really want to keep this API, we need to update this demo to force the requests to resolve in the right order (ignore outdated requests). Which we don't do here.

Copy link
Member Author

Choose a reason for hiding this comment

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

The initial version was like the one you are suggesting but after discussing it with @dtassone I reworked it to match the rest of the grid's APIs. In that case the responsibility of loading the rows falls on to the developer.

Copy link
Member

@oliviertassinari oliviertassinari Jun 16, 2021

Choose a reason for hiding this comment

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

In this case, I think that it's important we update the demo to showcase a sound implementation of data fetching. It will be a good forcing function to see the complexity we are pushing to developers, it will help us evaluate if we are happy with this or prefer to internalize it. If we decide to internalize the complexity in the future, the current API is not flying, we would need to add a "token" if we want to keep an api call, or to switch to a promise.

Copy link
Member Author

Choose a reason for hiding this comment

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

I guess this is what you mean #1715 (comment). The current demo does show how to use the feature in action, it just doesn't do the filtering and sorting part.

};

return (
<div style={{ height: 400, width: '100%' }}>
<XGrid
{...data}
hideFooterPagination
rowCount={50}
sortingMode="server"
filterMode="server"
infniteLoadingMode="server"
onFetchRows={handleFetchRows}
/>
</div>
);
}
13 changes: 13 additions & 0 deletions docs/src/pages/components/data-grid/rows/rows.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ In addition, the area in which the callback provided to the `onRowsScrollEnd` is

{{"demo": "pages/components/data-grid/rows/InfiniteLoadingGrid.js", "bg": "inline", "disableAd": true}}

### Unstable Server-side infinite loading [<span class="pro"></span>](https://material-ui.com/store/items/material-ui-pro/)

By default, infinite loading works on the client-side.
To switch it to server-side, set `infniteLoadingMode="server"`.
Then the `rowCount` needs to be set and the number of initially loaded rows needs to be less than the `rowCount` value.
In addition, you need to handle the `onFetchRows` callback to fetch the rows for the corresponding index.
Finally, you need to use the `apiRef.current.insertRows()` to tell the DataGrid where to insert the newly fetched rows.

**Note**: in order for the filtering and sorting to work you need to set their modes to `server`.
You can find out more information about how to do that on the [server-side filter page](/components/data-grid/filtering/#server-side-filter) and on the [server-side sorting page](/components/data-grid/sorting/#server-side-sorting).

{{"demo": "pages/components/data-grid/rows/ServerInfiniteLoadingGrid.js", "bg": "inline", "disableAd": true}}

### apiRef [<span class="pro"></span>](https://material-ui.com/store/items/material-ui-pro/)

The second way to update rows is to use the apiRef.
Expand Down
53 changes: 34 additions & 19 deletions packages/grid/_modules_/grid/components/GridViewport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { GridEmptyCell } from './cell/GridEmptyCell';
import { GridRenderingZone } from './GridRenderingZone';
import { GridRow } from './GridRow';
import { GridRowCells } from './cell/GridRowCells';
import { GridSkeletonRowCells } from './cell/GridSkeletonRowCells';
import { GridStickyContainer } from './GridStickyContainer';
import {
gridContainerSizesSelector,
Expand Down Expand Up @@ -52,6 +53,7 @@ export const GridViewport: ViewportType = React.forwardRef<HTMLDivElement, {}>(
renderState.renderContext.firstRowIdx,
renderState.renderContext.lastRowIdx!,
);

return renderedRows.map(([id, row], idx) => (
<GridRow
className={
Expand All @@ -63,25 +65,38 @@ export const GridViewport: ViewportType = React.forwardRef<HTMLDivElement, {}>(
rowIndex={renderState.renderContext!.firstRowIdx! + idx}
>
<GridEmptyCell width={renderState.renderContext!.leftEmptyWidth} height={rowHeight} />
<GridRowCells
columns={visibleColumns}
row={row}
id={id}
height={rowHeight}
firstColIdx={renderState.renderContext!.firstColIdx!}
lastColIdx={renderState.renderContext!.lastColIdx!}
hasScrollX={scrollBarState.hasScrollX}
hasScrollY={scrollBarState.hasScrollY}
showCellRightBorder={!!options.showCellRightBorder}
extendRowFullWidth={!options.disableExtendRowFullWidth}
rowIndex={renderState.renderContext!.firstRowIdx! + idx}
cellFocus={cellFocus}
cellTabIndex={cellTabIndex}
isSelected={selectionState[id] !== undefined}
editRowState={editRowsState[id]}
cellClassName={options.classes?.cell}
getCellClassName={options.getCellClassName}
/>
{id.toString().indexOf('null-') === 0 ? (
<GridSkeletonRowCells
columns={visibleColumns}
firstColIdx={renderState.renderContext!.firstColIdx!}
lastColIdx={renderState.renderContext!.lastColIdx!}
hasScrollX={scrollBarState.hasScrollX}
hasScrollY={scrollBarState.hasScrollY}
showCellRightBorder={!!options.showCellRightBorder}
extendRowFullWidth={!options.disableExtendRowFullWidth}
rowIndex={renderState.renderContext!.firstRowIdx! + idx}
/>
) : (
Comment on lines +68 to +79
Copy link
Member

Choose a reason for hiding this comment

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

Instead of hardcoding different types of rows. How about we add an API to turn the loading state programmatically on some cells?

Suggested change
{id.toString().indexOf('null-') === 0 ? (
<GridSkeletonRowCells
columns={visibleColumns}
firstColIdx={renderState.renderContext!.firstColIdx!}
lastColIdx={renderState.renderContext!.lastColIdx!}
hasScrollX={scrollBarState.hasScrollX}
hasScrollY={scrollBarState.hasScrollY}
showCellRightBorder={!!options.showCellRightBorder}
extendRowFullWidth={!options.disableExtendRowFullWidth}
rowIndex={renderState.renderContext!.firstRowIdx! + idx}
/>
) : (

Copy link
Member

Choose a reason for hiding this comment

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

I would even argue that we could breakdown this effort once we get a good enough POC of the integration to have the skeleton standalone, and maybe use it for the infinite loading use case.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree that that is not the best solution but there is already a ticket for changing the loading visuals once this initial version is merged #1685

Copy link
Member

@oliviertassinari oliviertassinari Jun 16, 2021

Choose a reason for hiding this comment

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

I had forgotten about #1685. In this case, I propose we do #1685 first or we start here without any skeleton, no preferences. But whatever is necessary to focus on one problem at the time.

Copy link
Member Author

Choose a reason for hiding this comment

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

The problem is that without skeleton rows this feature doesn't work at all because it will just display empty rows. The UX wouldn't be great.

<GridRowCells
columns={visibleColumns}
row={row}
id={id}
height={rowHeight}
firstColIdx={renderState.renderContext!.firstColIdx!}
lastColIdx={renderState.renderContext!.lastColIdx!}
hasScrollX={scrollBarState.hasScrollX}
hasScrollY={scrollBarState.hasScrollY}
showCellRightBorder={!!options.showCellRightBorder}
extendRowFullWidth={!options.disableExtendRowFullWidth}
rowIndex={renderState.renderContext!.firstRowIdx! + idx}
cellFocus={cellFocus}
cellTabIndex={cellTabIndex}
isSelected={selectionState[id] !== undefined}
editRowState={editRowsState[id]}
cellClassName={options.classes?.cell}
getCellClassName={options.getCellClassName}
/>
)}
<GridEmptyCell width={renderState.renderContext!.rightEmptyWidth} height={rowHeight} />
</GridRow>
));
Expand Down
43 changes: 43 additions & 0 deletions packages/grid/_modules_/grid/components/cell/GridSkeletonCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as React from 'react';
import clsx from 'clsx';
import Skeleton from '@material-ui/lab/Skeleton';
oliviertassinari marked this conversation as resolved.
Show resolved Hide resolved
import { GRID_SKELETON_CELL_CSS_CLASS } from '../../constants/cssClassesConstants';

export interface GridSkeletonCellProps {
colIndex: number;
height: number;
rowIndex: number;
showRightBorder?: boolean;
width: number;
}

export const GridSkeletonCell = React.memo(function GridSkeletonCell(props: GridSkeletonCellProps) {
const { colIndex, height, rowIndex, showRightBorder, width } = props;

const cellRef = React.useRef<HTMLDivElement>(null);
const cssClasses = clsx(GRID_SKELETON_CELL_CSS_CLASS, {
'MuiDataGrid-withBorder': showRightBorder,
});

const style = {
minWidth: width,
maxWidth: width,
lineHeight: `${height - 1}px`,
minHeight: height,
maxHeight: height,
};

return (
<div
ref={cellRef}
className={cssClasses}
role="cell"
data-rowindex={rowIndex}
aria-colindex={colIndex}
style={style}
tabIndex={-1}
>
<Skeleton animation="wave" />
</div>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import * as React from 'react';
import { GridColumns } from '../../models/index';
import { GridApiContext } from '../GridApiContext';
import { gridDensityRowHeightSelector } from '../../hooks/features/density/densitySelector';
import { useGridSelector } from '../../hooks/features/core/useGridSelector';
import { GridSkeletonCell } from './GridSkeletonCell';

interface SkeletonRowCellsProps {
columns: GridColumns;
extendRowFullWidth: boolean;
firstColIdx: number;
hasScrollX: boolean;
hasScrollY: boolean;
lastColIdx: number;
rowIndex: number;
showCellRightBorder: boolean;
}

export const GridSkeletonRowCells = React.memo(function GridSkeletonRowCells(
props: SkeletonRowCellsProps,
) {
const {
columns,
firstColIdx,
hasScrollX,
hasScrollY,
lastColIdx,
rowIndex,
showCellRightBorder,
} = props;
const apiRef = React.useContext(GridApiContext);
const rowHeight = useGridSelector(apiRef, gridDensityRowHeightSelector);

const skeletonCellsProps = columns.slice(firstColIdx, lastColIdx + 1).map((column, colIdx) => {
const colIndex = firstColIdx + colIdx;
const isLastColumn = colIndex === columns.length - 1;
const removeLastBorderRight = isLastColumn && hasScrollX && !hasScrollY;
const showRightBorder = !isLastColumn
? showCellRightBorder
: !removeLastBorderRight && !props.extendRowFullWidth;

const skeletonCellProps = {
field: column.field,
width: column.width!,
height: rowHeight,
showRightBorder,
rowIndex,
colIndex,
};

return skeletonCellProps;
});

return (
<React.Fragment>
{skeletonCellsProps.map((skeletonCellProps) => (
<GridSkeletonCell key={skeletonCellProps.field} {...skeletonCellProps} />
))}
</React.Fragment>
);
});
2 changes: 2 additions & 0 deletions packages/grid/_modules_/grid/components/cell/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export * from './GridCell';
export * from './GridEditInputCell';
export * from './GridEmptyCell';
export * from './GridRowCells';
export * from './GridSkeletonRowCells';
export * from './GridSkeletonCell';
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const useStyles = makeStyles(
alignItems: 'center',
overflow: 'hidden',
},
'& .MuiDataGrid-columnHeader, & .MuiDataGrid-cell': {
'& .MuiDataGrid-columnHeader, & .MuiDataGrid-cell, & .MuiDataGrid-skeletonCell': {
WebkitTapHighlightColor: 'transparent',
lineHeight: null,
padding: '0 10px',
Expand Down Expand Up @@ -244,7 +244,7 @@ export const useStyles = makeStyles(
},
},
},
'& .MuiDataGrid-cell': {
'& .MuiDataGrid-cell, & .MuiDataGrid-skeletonCell': {
display: 'block',
overflow: 'hidden',
textOverflow: 'ellipsis',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export const GRID_COLUMN_HEADER_SEPARATOR_RESIZABLE_CSS_CLASS = `${GRID_CSS_CLAS
export const GRID_COLUMN_HEADER_TITLE_CSS_CLASS = `${GRID_CSS_CLASS_PREFIX}-columnHeaderTitleContainer`;
export const GRID_COLUMN_HEADER_DROP_ZONE_CSS_CLASS = `${GRID_CSS_CLASS_PREFIX}-columnHeaderDropZone`;
export const GRID_COLUMN_HEADER_DRAGGING_CSS_CLASS = `${GRID_CSS_CLASS_PREFIX}-${GRID_COLUMN_HEADER_CSS_CLASS_SUFFIX}--dragging`;
export const GRID_SKELETON_CELL_CSS_CLASS = `${GRID_CSS_CLASS_PREFIX}-skeletonCell`;
12 changes: 12 additions & 0 deletions packages/grid/_modules_/grid/constants/eventsConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,3 +452,15 @@ export const GRID_STATE_CHANGE = 'stateChange';
* @event
*/
export const GRID_COLUMN_VISIBILITY_CHANGE = 'columnVisibilityChange';

/**
* Fired when the virtual page changes. Called with a [[GridVirtualPageChangeParams]] object.
* @event
*/
export const GRID_VIRTUAL_PAGE_CHANGE = 'virtualPageChange';

/**
* Fired when the virtual page changes. Called with a [[GridFetchRowsParams]] object.
* @event
*/
export const GRID_FETCH_ROWS = 'fetchRows';
Loading