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 12 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
51 changes: 33 additions & 18 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,24 +65,37 @@ 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}
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}
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
42 changes: 42 additions & 0 deletions packages/grid/_modules_/grid/components/cell/GridSkeletonCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import * as React from 'react';
import clsx from 'clsx';
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((props: GridSkeletonCellProps) => {
DanailH marked this conversation as resolved.
Show resolved Hide resolved
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}
/>
);
});

GridSkeletonCell.displayName = 'GridSkeletonCell';
DanailH marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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((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>
);
});
GridSkeletonRowCells.displayName = 'GridSkeletonRowCells';
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 @@ -240,6 +240,25 @@ export const useStyles = makeStyles(
},
},
},
'& .MuiDataGrid-skeletonCell': {
display: 'block',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
borderBottom: `1px solid ${borderColor}`,
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(1),
'&::before': {
content: '""',
display: 'block',
width: '100%',
height: '100%',
'-webkit-animation': `3000ms ${theme.transitions.easing.easeInOut} $skeleton infinite`,
animation: `3000ms ${theme.transitions.easing.easeInOut} $skeleton infinite`,
background: theme.palette.grey[300],
willChange: 'transform-origin, transform, opacity',
},
},
'& .MuiDataGrid-cell': {
display: 'block',
overflow: 'hidden',
Expand Down Expand Up @@ -377,7 +396,50 @@ export const useStyles = makeStyles(
},
};
}
return gridStyle;
return {
...gridStyle,
'@keyframes skeleton': {
'0%': {
opacity: 0.3,
transform: 'scaleX(0)',
transformOrigin: 'left',
},
'20%': {
opacity: 1,
transform: 'scaleX(1)',
transformOrigin: 'left',
},
'28%': {
transform: 'scaleX(1)',
transformOrigin: 'right',
},
'51%': {
transform: 'scaleX(0)',
transformOrigin: 'right',
},
'58%': {
transform: 'scaleX(0)',
transformOrigin: 'right',
},
'82%': {
transform: 'scaleX(1)',
transformOrigin: 'right',
},
'83%': {
transform: 'scaleX(1)',
transformOrigin: 'left',
},
'96%': {
transform: 'scaleX(0)',
transformOrigin: 'left',
},
'100%': {
opacity: 0.3,
transform: 'scaleX(0)',
transformOrigin: 'left',
},
},
};
},
{ name: 'MuiDataGrid', defaultTheme },
);
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export const GRID_COLUMN_HEADER_TITLE_CSS_CLASS = `${GRID_CSS_CLASS_PREFIX}-colu
export const GRID_DATA_CONTAINER_CSS_CLASS = 'data-container';
export const GRID_COLUMN_HEADER_DROP_ZONE_CSS_CLASS = `${GRID_CSS_CLASS_PREFIX}-columnHeader-dropZone`;
export const GRID_COLUMN_HEADER_DRAGGING_CSS_CLASS = `${GRID_CSS_CLASS_PREFIX}-columnHeader-dragging`;
export const GRID_SKELETON_CELL_CSS_CLASS = `${GRID_CSS_CLASS_PREFIX}-skeletonCell`;
6 changes: 6 additions & 0 deletions packages/grid/_modules_/grid/constants/eventsConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,3 +459,9 @@ 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';
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function buildCSV(
selectedRows: Record<string, GridRowId>,
getCellValue: (id: GridRowId, field: string) => GridCellValue,
): string {
let rowIds = [...rows.keys()];
let rowIds = [...rows.keys()].filter((id) => id.toString().indexOf('null-') !== 0);
const selectedRowIds = Object.keys(selectedRows);

if (selectedRowIds.length) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ export const useGridFilter = (apiRef: GridApiRef, rowsProp: GridRowsProp): void
const rows = sortedGridRowsSelector(state);

rows.forEach((row: GridRowModel, id: GridRowId) => {
if (id.toString().indexOf('null-') === 0) {
return;
}

const params = apiRef.current.getCellParams(id, filterItem.columnField!);

const isShown = applyFilterOnRow(params);
Expand Down
Loading