Skip to content

Commit 040fd69

Browse files
MBilalShaficherniavskiimapache-salvaje
authored
[DataGridPremium] Reordering support for row grouping (#18251)
Co-authored-by: Andrew Cherniavskii <[email protected]> Co-authored-by: mapache-salvaje <[email protected]> Co-authored-by: Andrew <[email protected]>
1 parent 74bab6c commit 040fd69

File tree

60 files changed

+5775
-246
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+5775
-246
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# However, in order to prevent issues, editor files are ignored here.
33
.idea
44
.vscode
5+
.cursor
56

67
__diff_output__
78
.DS_STORE
@@ -26,3 +27,4 @@ performance-snapshot.json
2627
# vale downloaded config
2728
.github/styles/
2829
test-results
30+
CLAUDE.md
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import * as React from 'react';
2+
import {
3+
DataGridPremium,
4+
useGridApiRef,
5+
useKeepGroupedColumnsHidden,
6+
} from '@mui/x-data-grid-premium';
7+
import { useMovieData } from '@mui/x-data-grid-generator';
8+
9+
export default function RowGroupingGroupingValueSetter() {
10+
const data = useMovieData();
11+
const apiRef = useGridApiRef();
12+
13+
const columnsWithComposer = React.useMemo(
14+
() => [
15+
...data.columns,
16+
{
17+
field: 'composer',
18+
headerName: 'Composer',
19+
valueGetter: (value) => value?.name,
20+
groupingValueSetter: (value, row) => {
21+
return {
22+
...row,
23+
composer: {
24+
...row.composer,
25+
name: value,
26+
},
27+
};
28+
},
29+
width: 200,
30+
},
31+
{
32+
field: 'decade',
33+
headerName: 'Decade',
34+
valueGetter: (_, row) => (row.year ? Math.floor(row.year / 10) * 10 : null),
35+
groupingValueSetter: (value, row) => ({
36+
...row,
37+
// Since converting to decade is a lossy operation, directly using the decade value should be sufficient here
38+
year: value,
39+
}),
40+
renderCell: (params) =>
41+
params.value ? `${params.value.toString().slice(-2)}'s` : '',
42+
},
43+
],
44+
[data.columns],
45+
);
46+
47+
const initialState = useKeepGroupedColumnsHidden({
48+
apiRef,
49+
initialState: {
50+
rowGrouping: {
51+
model: ['composer', 'decade'],
52+
},
53+
},
54+
});
55+
56+
return (
57+
<div style={{ height: 400, width: '100%' }}>
58+
<DataGridPremium
59+
{...data}
60+
columns={columnsWithComposer}
61+
apiRef={apiRef}
62+
initialState={initialState}
63+
rowReordering
64+
/>
65+
</div>
66+
);
67+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import * as React from 'react';
2+
import {
3+
DataGridPremium,
4+
useGridApiRef,
5+
GridColDef,
6+
useKeepGroupedColumnsHidden,
7+
} from '@mui/x-data-grid-premium';
8+
import { useMovieData, Movie } from '@mui/x-data-grid-generator';
9+
10+
export default function RowGroupingGroupingValueSetter() {
11+
const data = useMovieData();
12+
const apiRef = useGridApiRef();
13+
14+
const columnsWithComposer = React.useMemo(
15+
() => [
16+
...data.columns,
17+
{
18+
field: 'composer',
19+
headerName: 'Composer',
20+
valueGetter: (value: { name: string }) => value?.name,
21+
groupingValueSetter: (value, row) => {
22+
return {
23+
...row,
24+
composer: {
25+
...row.composer,
26+
name: value,
27+
},
28+
};
29+
},
30+
width: 200,
31+
} as GridColDef<Movie, string>,
32+
{
33+
field: 'decade',
34+
headerName: 'Decade',
35+
valueGetter: (_, row) => (row.year ? Math.floor(row.year / 10) * 10 : null),
36+
groupingValueSetter: (value, row) => ({
37+
...row,
38+
// Since converting to decade is a lossy operation, directly using the decade value should be sufficient here
39+
year: value,
40+
}),
41+
renderCell: (params) =>
42+
params.value ? `${params.value.toString().slice(-2)}'s` : '',
43+
} as GridColDef<Movie, number>,
44+
],
45+
[data.columns],
46+
);
47+
48+
const initialState = useKeepGroupedColumnsHidden({
49+
apiRef,
50+
initialState: {
51+
rowGrouping: {
52+
model: ['composer', 'decade'],
53+
},
54+
},
55+
});
56+
57+
return (
58+
<div style={{ height: 400, width: '100%' }}>
59+
<DataGridPremium
60+
{...data}
61+
columns={columnsWithComposer}
62+
apiRef={apiRef}
63+
initialState={initialState}
64+
rowReordering
65+
/>
66+
</div>
67+
);
68+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<DataGridPremium
2+
{...data}
3+
columns={columnsWithComposer}
4+
apiRef={apiRef}
5+
initialState={initialState}
6+
rowReordering
7+
/>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as React from 'react';
2+
import {
3+
DataGridPremium,
4+
useGridApiRef,
5+
useKeepGroupedColumnsHidden,
6+
} from '@mui/x-data-grid-premium';
7+
import { useMovieData } from '@mui/x-data-grid-generator';
8+
9+
export default function RowGroupingReordering() {
10+
const data = useMovieData();
11+
const apiRef = useGridApiRef();
12+
13+
const initialState = useKeepGroupedColumnsHidden({
14+
apiRef,
15+
initialState: {
16+
rowGrouping: {
17+
model: ['company', 'director'],
18+
},
19+
},
20+
});
21+
22+
return (
23+
<div style={{ height: 400, width: '100%' }}>
24+
<DataGridPremium
25+
{...data}
26+
apiRef={apiRef}
27+
initialState={initialState}
28+
rowReordering
29+
/>
30+
</div>
31+
);
32+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as React from 'react';
2+
import {
3+
DataGridPremium,
4+
useGridApiRef,
5+
useKeepGroupedColumnsHidden,
6+
} from '@mui/x-data-grid-premium';
7+
import { useMovieData } from '@mui/x-data-grid-generator';
8+
9+
export default function RowGroupingReordering() {
10+
const data = useMovieData();
11+
const apiRef = useGridApiRef();
12+
13+
const initialState = useKeepGroupedColumnsHidden({
14+
apiRef,
15+
initialState: {
16+
rowGrouping: {
17+
model: ['company', 'director'],
18+
},
19+
},
20+
});
21+
22+
return (
23+
<div style={{ height: 400, width: '100%' }}>
24+
<DataGridPremium
25+
{...data}
26+
apiRef={apiRef}
27+
initialState={initialState}
28+
rowReordering
29+
/>
30+
</div>
31+
);
32+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<DataGridPremium
2+
{...data}
3+
apiRef={apiRef}
4+
initialState={initialState}
5+
rowReordering
6+
/>

docs/data/data-grid/row-grouping/row-grouping.md

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,10 @@ In the following example, the **Company** column is not groupable through the in
215215

216216
{{"demo": "RowGroupingReadOnly.js", "bg": "inline", "defaultCodeOpen": false}}
217217

218-
## Using groupingValueGetter for complex grouping value
218+
## Using groupingValueGetter() for complex grouping value
219219

220220
The grouping value must be either a string, a number, `null`, or `undefined`.
221-
If your cell value is more complex, pass a `groupingValueGetter` property to the column definition to convert it into a valid value.
221+
If your cell value is more complex, pass a `groupingValueGetter()` property to the column definition to convert it into a valid value.
222222

223223
```ts
224224
const columns: GridColDef[] = [
@@ -377,6 +377,62 @@ Row selection propagation has some limitations:
377377

378378
:::
379379

380+
## Drag-and-drop group reordering
381+
382+
With row reordering, users can reorder row groups or move rows from one group to another.
383+
To enable this feature with row grouping, pass the `rowReordering` prop to the Data Grid Premium component:
384+
385+
```tsx
386+
<DataGridPremium rowGroupingModel={['category']} rowReordering />
387+
```
388+
389+
{{"demo": "RowGroupingReordering.js", "bg": "inline", "defaultCodeOpen": false}}
390+
391+
### Reacting to group updates
392+
393+
When a row is moved from one group to another, it warrants a row update, and the row data value that was used to group this row must be updated to maintain the row grouping data integrity.
394+
395+
For example, in a Data Grid displaying movies grouped by companies, if the **Avatar** row is moved from **20th Century Fox** to the **Disney Studios** group, along with the row being updated in the row tree, the row data must be updated to reflect this change.
396+
397+
```diff
398+
// "Avatar" row
399+
{
400+
title: 'Avatar',
401+
- company: '20th Century Fox',
402+
+ company: 'Disney Studios',
403+
...
404+
}
405+
```
406+
407+
The Data Grid updates the internal row data, but for the change to persist on the server, you must use the [`processRowUpdate()`](/x/react-data-grid/editing/persistence/#the-processrowupdate-callback) callback.
408+
409+
When moving a nested group to a different parent on the same depth, there will be multiple `processRowUpdate()` calls for all the leaf descendants of the dragged group. In case some of them fail, you might see the parent node appearing in both places. Consider using the `onProcessRowUpdateError()` to show the proper feedback to the user.
410+
411+
### Usage with groupingValueSetter()
412+
413+
If you use [`colDef.groupingValueGetter()`](#using-groupingvaluegetter-for-complex-grouping-value) to handle complex grouping values and you want to group across rows, you must use the `colDef.groupingValueSetter()` to properly convert back the simple value to the complex one.
414+
415+
This method should return the updated row based on the groupKey (`value`) that corresponds to the target group.
416+
417+
```ts
418+
const columns: GridColDef[] = [
419+
{
420+
field: 'composer',
421+
groupingValueGetter: (value) => value.name,
422+
groupingValueSetter: (value, row) => ({
423+
...row,
424+
composer: {
425+
...row.composer,
426+
name: value,
427+
},
428+
}),
429+
},
430+
// ...
431+
];
432+
```
433+
434+
{{"demo": "RowGroupingGroupingValueSetter.js", "bg": "inline", "defaultCodeOpen": false}}
435+
380436
## Get all rows in a group
381437

382438
Use the `apiRef.current.getRowGroupChildren()` method to get the IDs of all rows in a group.

docs/data/data-grid/row-ordering/row-ordering.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,21 @@ This approach can also be used to change the location of the toggle column.
8585
For now, row reordering is disabled if sorting is applied to the Data Grid.
8686
:::
8787

88-
## Row reordering with tree data and grouping 🚧
88+
## Row reordering with tree data 🚧
8989

9090
:::warning
91-
This feature isn't available yet, but it is planned—you can 👍 upvote [this GitHub issue](https://github.com/mui/mui-x/issues/4821) to help us prioritize it.
91+
This feature isn't available yet, but it is planned—you can 👍 upvote [this GitHub issue](https://github.com/mui/mui-x/issues/7774) to help us prioritize it.
9292
Please don't hesitate to leave a comment there to describe your needs, especially if you have a use case we should address or you're facing specific pain points with your current solution.
9393
:::
9494

9595
With this feature, users would be able to reorder rows in use cases that also involve tree data and/or row grouping.
9696

97+
## Row reordering with row grouping [<span class="plan-premium"></span>](/x/introduction/licensing/#premium-plan 'Premium plan')
98+
99+
This feature allows users to reorder rows within grouped data to adjust the order of groups and their contents directly in the grid.
100+
101+
For more details, see [Row grouping—Drag-and-drop group reordering](/x/react-data-grid/row-grouping/#drag-and-drop-group-reordering).
102+
97103
## API
98104

99105
- [DataGrid](/x/api/data-grid/data-grid/)

docs/data/data-grid/server-side-data/row-grouping.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ The following demo uses `defaultGroupingExpansionDepth={-1}` to expand all group
104104
105105
{{"demo": "ServerSideRowGroupingGroupExpansion.js", "bg": "inline"}}
106106
107+
## Reorder row grouping rows
108+
109+
:::warning
110+
This feature isn't available yet, but it is planned—you can 👍 upvote [this GitHub issue](https://github.com/mui/mui-x/issues/18947) to help us prioritize it. Please don't hesitate to leave a comment or add some additional information.
111+
:::
112+
107113
## API
108114
109115
- [DataGrid](/x/api/data-grid/data-grid/)

0 commit comments

Comments
 (0)