Skip to content

Commit 74eff39

Browse files
authored
Merge pull request #8274 from marmelab/DatagridConfigurable
Add SelectColumns and DatagridConfigurable
2 parents b0e6bca + dfdc23c commit 74eff39

27 files changed

+1021
-79
lines changed

docs/Datagrid.md

+100
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,7 @@ The `<Datagrid>` component accepts the usual `className` prop. You can also over
695695

696696
| Rule name | Description |
697697
| ------------------------------ |--------------------------------------------------|
698+
| `& .RaDatagrid-root` | Applied to the root div element |
698699
| `& .RaDatagrid-tableWrapper` | Applied to the div that wraps table element |
699700
| `& .RaDatagrid-table` | Applied to the table element |
700701
| `& .RaDatagrid-thead` | Applied to the table header |
@@ -797,6 +798,105 @@ const PostList = () => (
797798
```
798799
{% endraw %}
799800

801+
## Showing / Hiding Columns
802+
803+
The [`<SelectColumnsButton>`](./SelectColumnsButton.md) lets users hide or show datagrid columns.
804+
805+
![SelectColumnsButton](./img/SelectColumnsButton.gif)
806+
807+
```jsx
808+
import {
809+
DatagridConfigurable,
810+
List,
811+
SelectColumnsButton,
812+
TextField,
813+
TopToolbar,
814+
} from "react-admin";
815+
816+
const PostListActions = () => (
817+
<TopToolbar>
818+
<SelectColumnsButton />
819+
</TopToolbar>
820+
);
821+
822+
const PostList = () => (
823+
<List actions={<PostListActions />}>
824+
<DatagridConfigurable>
825+
<TextField source="id" />
826+
<TextField source="title" />
827+
<TextField source="author" />
828+
<TextField source="year" />
829+
</DatagridConfigurable>
830+
</List>
831+
);
832+
```
833+
834+
`<SelectColumnsButton>` must be used in conjunction with `<DatagridConfigurable>`, the configurable version of `<Datagrid>`, described in the next section.
835+
836+
## Configurable
837+
838+
You can let end users customize the fields displayed in the `<Datagrid>` by using the `<DatagridConfigurable>` component instead.
839+
840+
![DatagridConfigurable](./img/DatagridConfigurable.gif)
841+
842+
```diff
843+
import {
844+
List,
845+
- Datagrid,
846+
+ DatagridConfigurable,
847+
TextField,
848+
} from 'react-admin';
849+
850+
const PostList = () => (
851+
<List>
852+
- <Datagrid>
853+
+ <DatagridConfigurable>
854+
<TextField source="id" />
855+
<TextField source="title" />
856+
<TextField source="author" />
857+
<TextField source="year" />
858+
- </Datagrid>
859+
+ </DatagridConfigurable>
860+
</List>
861+
);
862+
```
863+
864+
When users enter the configuration mode and select the `<Datagrid>`, they can show / hide datagrid columns. They can also use the [`<SelectColumnsButton>`](./SelectColumnsButton.md)
865+
866+
By default, `<DatagridConfigurable>` renders all child fields. But you can also omit some of them by passing an `omit` prop containing an array of field sources:
867+
868+
```jsx
869+
// by default, hide the id and author columns
870+
// users can choose to show them in configuration mode
871+
const PostList = () => (
872+
<List>
873+
<DatagridConfigurable omit={['id', 'author']}>
874+
<TextField source="id" />
875+
<TextField source="title" />
876+
<TextField source="author" />
877+
<TextField source="year" />
878+
</DatagridConfigurable>
879+
</List>
880+
);
881+
```
882+
883+
If you render more than one `<DatagridConfigurable>` in the same page, you must pass a unique `preferenceKey` prop to each one:
884+
885+
```jsx
886+
const PostList = () => (
887+
<List>
888+
<DatagridConfigurable preferenceKey="posts.datagrid">
889+
<TextField source="id" />
890+
<TextField source="title" />
891+
<TextField source="author" />
892+
<TextField source="year" />
893+
</DatagridConfigurable>
894+
</List>
895+
);
896+
```
897+
898+
`<DatagridConfigurable>` accepts the same props as `<Datagrid>`.
899+
800900
## Customizing Column Sort
801901

802902
![Sort Column Header](./img/sort-column-header.gif)

docs/Reference.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ title: "Reference"
115115
* [`<Search>`](https://marmelab.com/ra-enterprise/modules/ra-search#the-search-component)<img class="icon" src="./img/premium.svg" />
116116
* [`<SearchInput>`](./FilteringTutorial.md#searchinput)
117117
* [`<SelectArrayInput>`](./SelectArrayInput.md)
118-
* [`<SelectColumnsButton>`](https://marmelab.com/ra-enterprise/modules/ra-preferences#selectcolumnsbutton-store-datagrid-columns-in-preferences)<img class="icon" src="./img/premium.svg" />
118+
* [`<SelectColumnsButton>`](./SelectColumnsButton.md)
119119
* [`<SelectField>`](./SelectField.md)
120120
* [`<SelectInput>`](./SelectInput.md)
121121
* [`<Show>`](./Show.md#show)

docs/SelectColumnsButton.md

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
layout: default
3+
title: "The SelectColumnsButton Component"
4+
---
5+
6+
# `<SelectColumnsButton>`
7+
8+
This button lets users show or hide columns in a Datagrid. It must be used in conjunction with [`<DatagridConfigurable>`](./Datagrid.md#configurable).
9+
10+
![SelectColumnsButton](./img/SelectColumnsButton.gif)
11+
12+
```jsx
13+
import {
14+
DatagridConfigurable,
15+
List,
16+
SelectColumnsButton,
17+
TextField,
18+
TopToolbar,
19+
} from "react-admin";
20+
21+
const PostListActions = () => (
22+
<TopToolbar>
23+
<SelectColumnsButton />
24+
</TopToolbar>
25+
);
26+
27+
const PostList = () => (
28+
<List actions={<PostListActions />}>
29+
<DatagridConfigurable>
30+
<TextField source="id" />
31+
<TextField source="title" />
32+
<TextField source="author" />
33+
<TextField source="year" />
34+
</DatagridConfigurable>
35+
</List>
36+
);
37+
```
38+
39+
**Note**: `<SelectColumnsButton>` doesn't work with `<Datagrid>` - you must use `<DatagridConfigurable>` instead.
40+
41+
If you want to add the `<SelectColumnsButton>` to the usual List Actions, use the following snippet:
42+
43+
```jsx
44+
const ListActions = () => (
45+
<TopToolbar>
46+
<SelectColumnsButton />
47+
<FilterButton />
48+
<CreateButton />
49+
<ExportButton />
50+
</TopToolbar>
51+
);
52+
```
53+
54+
## `preferenceKey`
55+
56+
If you include `<SelectColumnsButton>` in a page that has more than one `<DatagridConfigurable>` (e.g. in a dasboard), you have to link the two components by giving them the same `preferenceKey`:
57+
58+
```jsx
59+
const BookList = () => {
60+
const { data, total, isLoading } = useGetList('books', {
61+
pagination: { page: 1, perPage: 10 },
62+
sort,
63+
});
64+
return (
65+
<div>
66+
<SelectColumnsButton preferenceKey="postList1" />
67+
<DatagridConfigurable
68+
preferenceKey="postList1"
69+
data={data}
70+
total={total}
71+
isLoading={isLoading}
72+
sort={sort}
73+
bulkActionButtons={false}
74+
>
75+
<TextField source="id" />
76+
<TextField source="title" />
77+
<TextField source="author" />
78+
<TextField source="year" />
79+
</DatagridConfigurable>
80+
</div>
81+
);
82+
};
83+
```

docs/img/DatagridConfigurable.gif

827 KB
Loading

docs/img/SelectColumnsButton.gif

473 KB
Loading

docs/navigation.html

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
<li {% if page.path == 'SavedQueriesList.md' %} class="active" {% endif %}><a class="nav-link" href="./SavedQueriesList.html"><code>&lt;SavedQueriesList&gt;</code></a></li>
7676
<li {% if page.path == 'Pagination.md' %} class="active" {% endif %}><a class="nav-link" href="./Pagination.html"><code>&lt;Pagination&gt;</code></a></li>
7777
<li {% if page.path == 'SortButton.md' %} class="active" {% endif %}><a class="nav-link" href="./SortButton.html"><code>&lt;SortButton&gt;</code></a></li>
78+
<li {% if page.path == 'SelectColumnsButton.md' %} class="active" {% endif %}><a class="nav-link" href="./SelectColumnsButton.html"><code>&lt;SelectColumnsButton&gt;</code></a></li>
7879
<li {% if page.path == 'useList.md' %} class="active" {% endif %}><a class="nav-link" href="./useList.html"><code>useList</code></a></li>
7980
<li {% if page.path == 'useListContext.md' %} class="active" {% endif %}><a class="nav-link" href="./useListContext.html"><code>useListContext</code></a></li>
8081
<li {% if page.path == 'useListController.md' %} class="active" {% endif %}><a class="nav-link" href="./useListController.html"><code>useListController</code></a></li>

examples/demo/src/orders/OrderList.tsx

+92-11
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Fragment, useCallback } from 'react';
33
import {
44
AutocompleteInput,
55
BooleanField,
6-
Datagrid,
6+
DatagridConfigurable,
77
DateField,
88
DateInput,
99
List,
@@ -16,6 +16,10 @@ import {
1616
TextInput,
1717
useGetList,
1818
useListContext,
19+
TopToolbar,
20+
SelectColumnsButton,
21+
FilterButton,
22+
ExportButton,
1923
} from 'react-admin';
2024
import { useMediaQuery, Divider, Tabs, Tab, Theme } from '@mui/material';
2125

@@ -25,12 +29,21 @@ import AddressField from '../visitors/AddressField';
2529
import MobileGrid from './MobileGrid';
2630
import { Customer } from '../types';
2731

32+
const ListActions = () => (
33+
<TopToolbar>
34+
<SelectColumnsButton />
35+
<FilterButton />
36+
<ExportButton />
37+
</TopToolbar>
38+
);
39+
2840
const OrderList = () => (
2941
<List
3042
filterDefaultValues={{ status: 'ordered' }}
3143
sort={{ field: 'date', order: 'DESC' }}
3244
perPage={25}
3345
filters={orderFilters}
46+
actions={<ListActions />}
3447
>
3548
<TabbedDatagrid />
3649
</List>
@@ -130,7 +143,10 @@ const TabbedDatagrid = () => {
130143
) : (
131144
<>
132145
{filterValues.status === 'ordered' && (
133-
<Datagrid optimized rowClick="edit">
146+
<DatagridConfigurable
147+
rowClick="edit"
148+
omit={['total_ex_taxes', 'delivery_fees', 'taxes']}
149+
>
134150
<DateField source="date" showTime />
135151
<TextField source="reference" />
136152
<CustomerReferenceField />
@@ -143,6 +159,27 @@ const TabbedDatagrid = () => {
143159
<AddressField />
144160
</ReferenceField>
145161
<NbItemsField />
162+
<NumberField
163+
source="total_ex_taxes"
164+
options={{
165+
style: 'currency',
166+
currency: 'USD',
167+
}}
168+
/>
169+
<NumberField
170+
source="delivery_fees"
171+
options={{
172+
style: 'currency',
173+
currency: 'USD',
174+
}}
175+
/>
176+
<NumberField
177+
source="taxes"
178+
options={{
179+
style: 'currency',
180+
currency: 'USD',
181+
}}
182+
/>
146183
<NumberField
147184
source="total"
148185
options={{
@@ -151,10 +188,13 @@ const TabbedDatagrid = () => {
151188
}}
152189
sx={{ fontWeight: 'bold' }}
153190
/>
154-
</Datagrid>
191+
</DatagridConfigurable>
155192
)}
156193
{filterValues.status === 'delivered' && (
157-
<Datagrid rowClick="edit">
194+
<DatagridConfigurable
195+
rowClick="edit"
196+
omit={['total_ex_taxes', 'delivery_fees', 'taxes']}
197+
>
158198
<DateField source="date" showTime />
159199
<TextField source="reference" />
160200
<CustomerReferenceField />
@@ -167,6 +207,27 @@ const TabbedDatagrid = () => {
167207
<AddressField />
168208
</ReferenceField>
169209
<NbItemsField />
210+
<NumberField
211+
source="total_ex_taxes"
212+
options={{
213+
style: 'currency',
214+
currency: 'USD',
215+
}}
216+
/>
217+
<NumberField
218+
source="delivery_fees"
219+
options={{
220+
style: 'currency',
221+
currency: 'USD',
222+
}}
223+
/>
224+
<NumberField
225+
source="taxes"
226+
options={{
227+
style: 'currency',
228+
currency: 'USD',
229+
}}
230+
/>
170231
<NumberField
171232
source="total"
172233
options={{
@@ -179,10 +240,13 @@ const TabbedDatagrid = () => {
179240
source="returned"
180241
sx={{ mt: -0.5, mb: -0.5 }}
181242
/>
182-
</Datagrid>
243+
</DatagridConfigurable>
183244
)}
184245
{filterValues.status === 'cancelled' && (
185-
<Datagrid rowClick="edit">
246+
<DatagridConfigurable
247+
rowClick="edit"
248+
omit={['total_ex_taxes', 'delivery_fees', 'taxes']}
249+
>
186250
<DateField source="date" showTime />
187251
<TextField source="reference" />
188252
<CustomerReferenceField />
@@ -195,6 +259,27 @@ const TabbedDatagrid = () => {
195259
<AddressField />
196260
</ReferenceField>
197261
<NbItemsField />
262+
<NumberField
263+
source="total_ex_taxes"
264+
options={{
265+
style: 'currency',
266+
currency: 'USD',
267+
}}
268+
/>
269+
<NumberField
270+
source="delivery_fees"
271+
options={{
272+
style: 'currency',
273+
currency: 'USD',
274+
}}
275+
/>
276+
<NumberField
277+
source="taxes"
278+
options={{
279+
style: 'currency',
280+
currency: 'USD',
281+
}}
282+
/>
198283
<NumberField
199284
source="total"
200285
options={{
@@ -203,11 +288,7 @@ const TabbedDatagrid = () => {
203288
}}
204289
sx={{ fontWeight: 'bold' }}
205290
/>
206-
<BooleanField
207-
source="returned"
208-
sx={{ mt: -0.5, mb: -0.5 }}
209-
/>
210-
</Datagrid>
291+
</DatagridConfigurable>
211292
)}
212293
</>
213294
)}

0 commit comments

Comments
 (0)