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

[DataGridPremium] Server-side data source with row grouping #13826

Merged
merged 46 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
ac19bcd
[DataGridPremium] Server-side row grouping
MBilalShafi Jul 15, 2024
b83928f
Lint
MBilalShafi Jul 15, 2024
222da23
Merge branch 'master' into datasource-row-grouping
MBilalShafi Sep 4, 2024
d8b762b
Adjust according to the changes done on master
MBilalShafi Sep 4, 2024
26ed96e
Support sort and filter on normal non-grouping columns
MBilalShafi Sep 6, 2024
bb06da1
Merge branch 'master' into datasource-row-grouping
MBilalShafi Sep 6, 2024
ad92678
Update documentation
MBilalShafi Sep 6, 2024
02d1ab3
Update tag
MBilalShafi Sep 6, 2024
342594a
Docs update
MBilalShafi Sep 7, 2024
435ecdf
Merge branch 'master' into datasource-row-grouping
MBilalShafi Sep 9, 2024
5d4220d
Add support for groupingValueGetter
MBilalShafi Sep 9, 2024
58daf43
Merge branch 'master' into datasource-row-grouping
MBilalShafi Sep 12, 2024
d1712de
Typo
MBilalShafi Sep 12, 2024
66ab0c8
Support rows with missing groups on mock server
MBilalShafi Sep 12, 2024
f072523
Fix argos' regression
MBilalShafi Sep 12, 2024
7580c46
Lint
MBilalShafi Sep 12, 2024
3780ddd
Update sidebar
MBilalShafi Sep 12, 2024
c92106d
Improve some documentation
MBilalShafi Sep 12, 2024
43c6e16
Enable client side aggregation
MBilalShafi Sep 12, 2024
0160a0a
Cleanup
MBilalShafi Sep 13, 2024
4e832b3
Docs updates
MBilalShafi Sep 13, 2024
5f6f0c6
Add commodities demo
MBilalShafi Sep 13, 2024
779b29d
Add toolbar to the demo
MBilalShafi Sep 14, 2024
b1a955c
Remove in-progress icon
MBilalShafi Sep 14, 2024
7dd206d
Add info section to docs
MBilalShafi Sep 16, 2024
d3aad07
Docs improvement
MBilalShafi Sep 16, 2024
ed631de
Support expansion using keyboard
MBilalShafi Sep 16, 2024
17f9f33
Update
MBilalShafi Sep 16, 2024
966718e
Merge branch 'master' into datasource-row-grouping
MBilalShafi Sep 20, 2024
e1f7a6a
Rename constants
MBilalShafi Sep 20, 2024
900e127
Make the selector memoized
MBilalShafi Sep 28, 2024
74ff1de
Merge branch 'master' into datasource-row-grouping
MBilalShafi Sep 28, 2024
c9fec5a
Merge branch 'master' into datasource-row-grouping
MBilalShafi Oct 3, 2024
5303c54
Merge branch 'master' into datasource-row-grouping
MBilalShafi Oct 11, 2024
509d264
Resolve a few comments
MBilalShafi Oct 11, 2024
0744856
Update documentation
MBilalShafi Oct 11, 2024
5f929f1
Fix types + lint
MBilalShafi Oct 11, 2024
8c623d0
Use pipe processing for row grouping params
MBilalShafi Oct 11, 2024
c60b757
Update a line of doc
MBilalShafi Oct 11, 2024
6ee149a
Merge branch 'master' into datasource-row-grouping
MBilalShafi Oct 17, 2024
ba0ab94
Use enums
MBilalShafi Oct 18, 2024
d685bb4
Merge branch 'master' into datasource-row-grouping
MBilalShafi Oct 21, 2024
7491df5
Adjust as per #15013
MBilalShafi Oct 21, 2024
d849c38
Reduce row size in the commodity demo
MBilalShafi Oct 24, 2024
1b5bd36
Allow grouping number fields
MBilalShafi Oct 24, 2024
10747b1
Remove the breaking change
MBilalShafi Oct 24, 2024
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
16 changes: 12 additions & 4 deletions docs/data/data-grid/row-grouping/row-grouping.md
MBilalShafi marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ In the following example, movies are grouped based on their production `company`

{{"demo": "RowGroupingBasicExample.js", "bg": "inline", "defaultCodeOpen": false}}

:::info
If you are looking for row grouping on the server-side, see [server-side row grouping](/x/react-data-grid/server-side-data/row-grouping/).
:::

## Grouping criteria

### Initialize the row grouping
Expand Down Expand Up @@ -252,6 +256,10 @@ Use the `setRowChildrenExpansion` method on `apiRef` to programmatically set the

{{"demo": "RowGroupingSetChildrenExpansion.js", "bg": "inline", "defaultCodeOpen": false}}

:::warning
The `apiRef.current.setRowChildrenExpansion` method is not compatible with the [server-side tree data](/x/react-data-grid/server-side-data/tree-data/) and [server-side row grouping](/x/react-data-grid/server-side-data/row-grouping/). Use `apiRef.current.unstable_dataSource.fetchRows` instead.
Copy link
Member

Choose a reason for hiding this comment

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

Curious, why it is not compatible? Could it call the data source to apply the behavior or is there a strong feasibility blocker?
(Question applies to both get and set methods)

Copy link
Member Author

Choose a reason for hiding this comment

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

Data source changes a bit how expansion works.
When the user expands a row, fetchRows is called, which fetches the rows internally and only on success it calls setRowChildrenExpansion internally which only updates the isExpanded state of the respective rowNode.

If the user tries to call setRowChildrenExpansion there will be no rows to show, only the expand icon will shift to expanded form, thus setRowChildrenExpansion is no longer recommended to use with the data source.

Copy link
Member

Choose a reason for hiding this comment

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

Good point @joserodolfofreitas
@MBilalShafi Couldn't we potentially update setRowChildrenExpansion to fetch rows if the data source is being used?

Copy link
Member

Choose a reason for hiding this comment

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

I missed the conversation here.
Should we create an issue to make these approaches compatible?

Copy link
Member Author

@MBilalShafi MBilalShafi Oct 29, 2024

Choose a reason for hiding this comment

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

Couldn't we potentially update setRowChildrenExpansion to fetch rows if the data source is being used?

@cherniavskii We certainly could. Mostly a DX decision. It hasn't been done in the current implementation because setRowChildrenExpansion sounds like (or anticipated as) a state setter (or a pure function), hiding the fetch part behind would be less aligned with a user's expectation as it will now have 3 possible outcomes.

  1. Set the state right away (no data source)
  2. Set the state after some time (waiting time of the BE API)
  3. Never set the state (fetching failed)

Using it from within fetchRows makes sense if it's understood to be only responsible for 1, or we may have to change its current perception.

What do you think?

:::

### Customize grouping cell indent

To change the default cell indent, you can use the `--DataGrid-cellOffsetMultiplier` CSS variable:
Expand Down Expand Up @@ -280,10 +288,6 @@ If you are rendering leaves with the `leafField` property of `groupingColDef`, t

You can force the filtering to be applied on another grouping criteria with the `mainGroupingCriteria` property of `groupingColDef`

:::warning
This feature is not yet compatible with `sortingMode = "server"` and `filteringMode = "server"`.
:::

{{"demo": "RowGroupingFilteringSingleGroupingColDef.js", "bg": "inline", "defaultCodeOpen": false}}

### Multiple grouping columns
Expand Down Expand Up @@ -376,6 +380,10 @@ const rows = apiRef.current.getRowGroupChildren({

{{"demo": "RowGroupingGetRowGroupChildren.js", "bg": "inline", "defaultCodeOpen": false}}

:::warning
The `apiRef.current.getRowGroupChildren` method is not compatible with the [server-side row grouping](/x/react-data-grid/server-side-data/row-grouping/) since all the rows might not be available to get at a given instance.
:::

## Row group panel 🚧

:::warning
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import * as React from 'react';
import {
DataGridPremium,
useGridApiRef,
useKeepGroupedColumnsHidden,
} from '@mui/x-data-grid-premium';
import { useMockServer } from '@mui/x-data-grid-generator';
import Button from '@mui/material/Button';

export default function ServerSideRowGroupingDataGrid() {
const apiRef = useGridApiRef();

const { fetchRows, columns } = useMockServer({
rowGrouping: true,
});

const dataSource = React.useMemo(() => {
return {
getRows: async (params) => {
const urlParams = new URLSearchParams({
paginationModel: JSON.stringify(params.paginationModel),
filterModel: JSON.stringify(params.filterModel),
sortModel: JSON.stringify(params.sortModel),
groupKeys: JSON.stringify(params.groupKeys),
groupFields: JSON.stringify(params.groupFields),
});
const getRowsResponse = await fetchRows(
`https://mui.com/x/api/data-grid?${urlParams.toString()}`,
);
return {
rows: getRowsResponse.rows,
rowCount: getRowsResponse.rowCount,
};
},
getGroupKey: (row) => row.group,
getChildrenCount: (row) => row.descendantCount,
};
}, [fetchRows]);

const initialState = useKeepGroupedColumnsHidden({
apiRef,
initialState: {
rowGrouping: {
model: ['company', 'director'],
MBilalShafi marked this conversation as resolved.
Show resolved Hide resolved
},
},
});

return (
<div style={{ width: '100%' }}>
<Button
onClick={() => {
apiRef.current.unstable_dataSource.cache.clear();
}}
>
Clear cache
</Button>

<div style={{ height: 400, position: 'relative' }}>
<DataGridPremium
columns={columns}
unstable_dataSource={dataSource}
apiRef={apiRef}
initialState={initialState}
/>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import * as React from 'react';
import {
DataGridPremium,
GridDataSource,
useGridApiRef,
useKeepGroupedColumnsHidden,
} from '@mui/x-data-grid-premium';
import { useMockServer } from '@mui/x-data-grid-generator';
import Button from '@mui/material/Button';

export default function ServerSideRowGroupingDataGrid() {
const apiRef = useGridApiRef();

const { fetchRows, columns } = useMockServer({
rowGrouping: true,
});

const dataSource: GridDataSource = React.useMemo(() => {
return {
getRows: async (params) => {
const urlParams = new URLSearchParams({
paginationModel: JSON.stringify(params.paginationModel),
filterModel: JSON.stringify(params.filterModel),
sortModel: JSON.stringify(params.sortModel),
groupKeys: JSON.stringify(params.groupKeys),
groupFields: JSON.stringify(params.groupFields),
});
const getRowsResponse = await fetchRows(
`https://mui.com/x/api/data-grid?${urlParams.toString()}`,
);
return {
rows: getRowsResponse.rows,
rowCount: getRowsResponse.rowCount,
};
},
getGroupKey: (row) => row.group,
getChildrenCount: (row) => row.descendantCount,
};
}, [fetchRows]);

const initialState = useKeepGroupedColumnsHidden({
apiRef,
initialState: {
rowGrouping: {
model: ['company', 'director'],
},
},
});

return (
<div style={{ width: '100%' }}>
<Button
onClick={() => {
apiRef.current.unstable_dataSource.cache.clear();
}}
>
Clear cache
</Button>

<div style={{ height: 400, position: 'relative' }}>
<DataGridPremium
columns={columns}
unstable_dataSource={dataSource}
apiRef={apiRef}
initialState={initialState}
/>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Button
onClick={() => {
apiRef.current.unstable_dataSource.cache.clear();
}}
>
Clear cache
</Button>

<div style={{ height: 400, position: 'relative' }}>
<DataGridPremium
columns={columns}
unstable_dataSource={dataSource}
apiRef={apiRef}
initialState={initialState}
/>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import * as React from 'react';
import {
DataGridPremium,
useGridApiRef,
useKeepGroupedColumnsHidden,
} from '@mui/x-data-grid-premium';
import { useMockServer } from '@mui/x-data-grid-generator';
import Snackbar from '@mui/material/Snackbar';
import Button from '@mui/material/Button';
import Checkbox from '@mui/material/Checkbox';
import FormControlLabel from '@mui/material/FormControlLabel';
import { alpha, styled, darken, lighten } from '@mui/material/styles';

export default function ServerSideRowGroupingErrorHandling() {
const apiRef = useGridApiRef();
const [rootError, setRootError] = React.useState();
const [childrenError, setChildrenError] = React.useState();
const [shouldRequestsFail, setShouldRequestsFail] = React.useState(false);

const { fetchRows, columns } = useMockServer(
{
rowGrouping: true,
},
{},
shouldRequestsFail,
);

const dataSource = React.useMemo(() => {
return {
getRows: async (params) => {
const urlParams = new URLSearchParams({
paginationModel: JSON.stringify(params.paginationModel),
filterModel: JSON.stringify(params.filterModel),
sortModel: JSON.stringify(params.sortModel),
groupKeys: JSON.stringify(params.groupKeys),
groupFields: JSON.stringify(params.groupFields),
});
const getRowsResponse = await fetchRows(
`https://mui.com/x/api/data-grid?${urlParams.toString()}`,
);
return {
rows: getRowsResponse.rows,
rowCount: getRowsResponse.rowCount,
};
},
getGroupKey: (row) => row.group,
getChildrenCount: (row) => row.descendantCount,
};
}, [fetchRows]);

const initialState = useKeepGroupedColumnsHidden({
apiRef,
initialState: {
rowGrouping: {
model: ['company', 'director'],
},
},
});

return (
<div style={{ width: '100%' }}>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<Button
onClick={() => {
setRootError('');
apiRef.current.unstable_dataSource.fetchRows();
}}
>
Refetch rows
</Button>
<FormControlLabel
control={
<Checkbox
checked={shouldRequestsFail}
onChange={(event) => setShouldRequestsFail(event.target.checked)}
/>
}
label="Make the requests fail"
/>
</div>
<div style={{ height: 400, position: 'relative' }}>
<DataGridPremium
columns={columns}
unstable_dataSource={dataSource}
unstable_onDataSourceError={(error, params) => {
if (!params.groupKeys || params.groupKeys.length === 0) {
setRootError(error.message);
} else {
setChildrenError(
`${error.message} (Requested level: ${params.groupKeys.join(' > ')})`,
);
}
}}
unstable_dataSourceCache={null}
apiRef={apiRef}
initialState={initialState}
/>
{rootError && <ErrorOverlay error={rootError} />}
<Snackbar
open={!!childrenError}
autoHideDuration={3000}
onClose={() => setChildrenError('')}
message={childrenError}
/>
</div>
</div>
);
}

function getBorderColor(theme) {
if (theme.palette.mode === 'light') {
return lighten(alpha(theme.palette.divider, 1), 0.88);
}
return darken(alpha(theme.palette.divider, 1), 0.68);
}

const StyledDiv = styled('div')(({ theme: t }) => ({
position: 'absolute',
zIndex: 10,
fontSize: '0.875em',
top: 0,
height: '100%',
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '4px',
border: `1px solid ${getBorderColor(t)}`,
backgroundColor: t.palette.background.default,
}));

function ErrorOverlay({ error }) {
if (!error) {
return null;
}
return <StyledDiv>{error}</StyledDiv>;
}
Loading