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

[Doc] Add documentation about <BulkUpdateFormButton> and <InputSelectorForm> #9145

Merged
merged 2 commits into from
Aug 1, 2023
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
311 changes: 310 additions & 1 deletion docs/Buttons.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ export const PostList = () => (

Partially updates the selected rows. To be used inside [the `<Datagrid bulkActionButtons>` prop](./Datagrid.md#bulkactionbuttons).

![Bulk Update button](./img/bulk-update-button.png)

#### Usage

{% raw %}
```jsx
import * as React from 'react';
Expand All @@ -285,7 +289,7 @@ export const PostList = () => (
```
{% endraw %}

![Bulk Update button](./img/bulk-update-button.png)
#### Props

| Prop | Required | Type | Default | Description |
|-------------------|----------|----------------|--------------------|---------------------------------------------------------------------------------------------------------------------|
Expand All @@ -299,6 +303,311 @@ export const PostList = () => (

**Tip:** If you choose the `'pessimistic'` or `'optimistic'` mutation mode, a confirm dialog will be displayed to the user before the mutation is executed.

### `<BulkUpdateFormButton>`

This component, part of the [enterprise edition](https://marmelab.com/ra-enterprise/modules/ra-form-layout)<img class="icon" src="./img/premium.svg" />, lets users edit multiple records at once. To be used inside [the `<Datagrid bulkActionButtons>` prop](./Datagrid.md#bulkactionbuttons).

The button opens a dialog containing the form passed as children. When the form is submitted, it will call the dataProvider's `updateMany` method with the ids of the selected records.

<video controls autoplay playsinline muted loop>
<source src="./img/BulkUpdateButton-SimpleForm.webm" type="video/webm"/>
<source src="./img/BulkUpdateButton-SimpleForm.mp4" type="video/mp4"/>
Your browser does not support the video tag.
</video>

#### Usage

`<BulkUpdateFormButton>` can be used inside `<Datagrid>`'s `bulkActionButtons`.

```tsx
import * as React from 'react';
import {
Admin,
BooleanField,
BooleanInput,
Datagrid,
DateField,
DateInput,
List,
Resource,
SimpleForm,
TextField,
} from 'react-admin';
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';

import { dataProvider } from './dataProvider';
import { i18nProvider } from './i18nProvider';

export const App = () => (
<Admin dataProvider={dataProvider} i18nProvider={i18nProvider}>
<Resource name="posts" list={PostList} />
</Admin>
);

const PostBulkUpdateButton = () => (
<BulkUpdateFormButton>
<SimpleForm>
<DateInput source="published_at" />
<BooleanInput source="is_public" />
</SimpleForm>
</BulkUpdateFormButton>
);

const PostList = () => (
<List>
<Datagrid bulkActionButtons={<PostBulkUpdateButton />}>
<TextField source="id" />
<TextField source="title" />
<DateField source="published_at" />
<BooleanField source="is_public" />
</Datagrid>
</List>
);
```

**Tip:** You are not limited to using a `<SimpleForm>` as children. You can for instance use an `<InputSelectorForm>`, which allows to select the fields to update. Check out the [`<InputSelectorForm>`](#usage-with-inputselectorform) below for more information.

#### Props

| Prop | Required | Type | Default | Description |
|-------------------|--------------|----------|-----------------|------------------------------------------------------------------------------------------------------------------------------------|
| `children` | Required (*) | Element | - | A form component to render inside the Dialog |
| `DialogProps` | - | Object | - | Additional props to pass to the [MUI Dialog](https://mui.com/material-ui/react-dialog/) |
| `mutationMode` | - | `string` | `'pessimistic'` | The mutation mode (`'undoable'`, `'pessimistic'` or `'optimistic'`) |
| `mutationOptions` | - | Object | - | Mutation options passed to [react-query](https://tanstack.com/query/v3/docs/react/reference/useMutation) when calling `updateMany` |


#### `children`

`<BulkUpdateFormButton>` expects a form component as children, such as `<SimpleForm>` or `<InputSelectorForm>`.

```tsx
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput, SimpleForm } from 'react-admin';

const PostBulkUpdateButton = () => (
<BulkUpdateFormButton>
<SimpleForm>
<DateInput source="published_at" />
<BooleanInput source="is_public" />
</SimpleForm>
</BulkUpdateFormButton>
);
```

#### `DialogProps`

The `DialogProps` prop can be used to pass additional props to the [MUI Dialog](https://mui.com/material-ui/react-dialog/).
{% raw %}
```tsx
import { Slide } from '@mui/material';
import { TransitionProps } from '@mui/material/transitions';
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput, SimpleForm } from 'react-admin';

const Transition = React.forwardRef(function Transition(
props: TransitionProps & {
children: React.ReactElement<any, any>;
},
ref: React.Ref<unknown>
) {
return <Slide direction="left" ref={ref} {...props} />;
});

const PostBulkUpdateButtonWithTransition = () => (
<BulkUpdateFormButton DialogProps={{ TransitionComponent: Transition }}>
<SimpleForm>
<DateInput source="published_at" />
<BooleanInput source="is_public" />
</SimpleForm>
</BulkUpdateFormButton>
);
```
{% endraw %}

#### `mutationMode`

Use the `mutationMode` prop to specify the [mutation mode](https://marmelab.com/react-admin/Edit.html#mutationmode).

```tsx
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput, SimpleForm } from 'react-admin';

const PostBulkUpdateButton = () => (
<BulkUpdateFormButton mutationMode="undoable">
<SimpleForm>
<DateInput source="published_at" />
<BooleanInput source="is_public" />
</SimpleForm>
</BulkUpdateFormButton>
);
```

#### `mutationOptions` and `meta`

The `mutationOptions` prop can be used to pass options to the [react-query mutation](https://react-query.tanstack.com/reference/useMutation#options) used to call the dataProvider's `updateMany` method.

{% raw %}
```tsx
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput, SimpleForm } from 'react-admin';

const PostBulkUpdateButton = () => (
<BulkUpdateFormButton mutationOptions={{ retry: false }}>
<SimpleForm>
<DateInput source="published_at" />
<BooleanInput source="is_public" />
</SimpleForm>
</BulkUpdateFormButton>
);
```
{% endraw %}

You can also use this prop to pass a `meta` object, that will be passed to the dataProvider when calling `updateMany`.
{% raw %}
```tsx
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput, SimpleForm } from 'react-admin';

const PostBulkUpdateButton = () => (
<BulkUpdateFormButton mutationOptions={{ meta: { foo: 'bar' } }}>
<SimpleForm>
<DateInput source="published_at" />
<BooleanInput source="is_public" />
</SimpleForm>
</BulkUpdateFormButton>
);
```
{% endraw %}

#### Usage with `<TabbedForm>` or other location based form layouts

`<BulkUpdateFormButton>` can be used with any form layout. However, for form layouts that are based on location by default, such as [`<TabbedForm>`](https://marmelab.com/react-admin/TabbedForm.html), you will need to disable the location syncing feature, as it may conflict with the Edit route declared by React Admin (`/<resource>/<id>`).

For instance, with `<TabbedForm>`, you can use the `syncWithLocation` prop to disable it:

```tsx
import { BulkUpdateFormButton } from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput, TabbedForm } from 'react-admin';

const PostBulkUpdateButton = () => (
<BulkUpdateFormButton>
<TabbedForm syncWithLocation={false}>
<TabbedForm.Tab label="Publication">
<DateInput source="published_at" />
</TabbedForm.Tab>
<TabbedForm.Tab label="Visibility">
<BooleanInput source="is_public" />
</TabbedForm.Tab>
</TabbedForm>
</BulkUpdateFormButton>
);
```

#### Usage With `<InputSelectorForm>`

`<BulkUpdateFormButton>` works best with `<InputSelectorForm>`, which component renders a form allowing to select the fields to update in a record.

<video controls autoplay playsinline muted loop>
<source src="./img/BulkUpdateButton-InputSelectorForm.webm" type="video/webm"/>
<source src="./img/BulkUpdateButton-InputSelectorForm.mp4" type="video/mp4"/>
Your browser does not support the video tag.
</video>

`<InputSelectorForm>` expects a list of inputs passed in the `inputs` prop. Each input must have a `label` and an `element`.

```tsx
import {
BulkUpdateFormButton,
InputSelectorForm,
} from '@react-admin/ra-form-layout';
import * as React from 'react';
import { BooleanInput, DateInput } from 'react-admin';

const PostBulkUpdateButton = () => (
<BulkUpdateFormButton>
<InputSelectorForm
inputs={[
{
label: 'Published at',
element: <DateInput source="published_at" />,
},
{
label: 'Is public',
element: <BooleanInput source="is_public" />,
},
]}
/>
</BulkUpdateFormButton>
);
```

Use the `inputs` prop to specify the list of inputs from which the user can pick. Each input must have a `label` and an `element`.

```tsx
import { InputSelectorForm } from '@react-admin/ra-form-layout';
import * as React from 'react';
import {
BooleanInput,
DateInput,
SelectArrayInput,
TextInput,
} from 'react-admin';

const PostEdit = () => (
<InputSelectorForm
inputs={[
{
label: 'Title',
element: <TextInput source="title" />,
},
{
label: 'Body',
element: <TextInput source="body" multiline />,
},
{
label: 'Published at',
element: <DateInput source="published_at" />,
},
{
label: 'Is public',
element: <BooleanInput source="is_public" />,
},
{
label: 'Tags',
element: (
<SelectArrayInput
source="tags"
choices={[
{ id: 'react', name: 'React' },
{ id: 'vue', name: 'Vue' },
{ id: 'solid', name: 'Solid' },
{ id: 'programming', name: 'Programming' },
]}
/>
),
},
]}
/>
);
```

#### Limitations

If you look under the hood, you will see that `<BulkUpdateFormButton>` provides a `<SaveContext>` to its children, which allows them to call `updateMany` with the ids of the selected records.

However since we are in the context of a list, there is no `<RecordContext>` available. Hence, the following inputs cannot work inside a `<BulkUpdateFormButton>`:

- `<ReferenceOneInput>`
- `<ReferenceManyInput>`
- `<ReferenceManyToManyInput>`

### `<FilterButton>`

This button is an internal component used by react-admin in [the Filter button/form combo](./FilteringTutorial.md#the-filter-buttonform-combo).
Expand Down
8 changes: 6 additions & 2 deletions docs/Datagrid.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ Finally, `<Datagrid>` inspects children for props that indicate how it should be
Your browser does not support the video tag.
</video>


Bulk action buttons are buttons that affect several records at once, like mass deletion for instance. In the `<Datagrid>` component, the bulk actions toolbar appears when a user ticks the checkboxes in the first column of the table. The user can then choose a button from the bulk actions toolbar. By default, all Datagrids have a single bulk action button, the bulk delete button. You can add other bulk action buttons by passing a custom element as the `bulkActionButtons` prop of the `<Datagrid>` component:

```jsx
Expand All @@ -173,7 +172,12 @@ export const PostList = () => (
);
```

**Tip**: React-admin provides three components that you can use in `bulkActionButtons`: [`<BulkDeleteButton>`](./Buttons.md#bulkdeletebutton), [`<BulkUpdateButton>`](./Buttons.md#bulkupdatebutton), and [`<BulkExportButton>`](./Buttons.md#bulkexportbutton).
**Tip**: React-admin provides four components that you can use in `bulkActionButtons`:

- [`<BulkDeleteButton>`](./Buttons.md#bulkdeletebutton) (enabled by default)
- [`<BulkExportButton>`](./Buttons.md#bulkexportbutton) to export only the selection
- [`<BulkUpdateButton>`](./Buttons.md#bulkupdatebutton) to immediately update the selection
- [`<BulkUpdateFormButton>`](./Buttons.md#bulkupdateformbutton) to display a form allowing to update the selection

**Tip**: You can also disable bulk actions altogether by passing `false` to the `bulkActionButtons` prop. In this case, the checkboxes column doesn't show up.

Expand Down
Binary file added docs/img/BulkUpdateButton-InputSelectorForm.mp4
Binary file not shown.
Binary file added docs/img/BulkUpdateButton-InputSelectorForm.webm
Binary file not shown.
Binary file added docs/img/BulkUpdateButton-SimpleForm.mp4
Binary file not shown.
Binary file added docs/img/BulkUpdateButton-SimpleForm.webm
Binary file not shown.