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 (@MBilalShafi) #15109

Merged
merged 2 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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.
:::

### 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'],
},
},
});

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