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

[RFR] Migrate export button #3640

Merged
merged 5 commits into from
Sep 3, 2019
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
51 changes: 51 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -906,3 +906,54 @@ There are two breaking changes in the new `<AutocompleteInput>`:
- highlightFirstSuggestion={true}
/>
```

## The `exporter` function has changed signature

In a `List`, you can pass a custom `exporter` function to control the data downloaded by users when they cllick on the "Export" button.

```jsx
const CommentList = props => (
<List {...props} exporter={exportComments}>
// ...
</List>
)
```

In react-admin v3, you can still pass an `exporter` function this way, but its signature has changed:

```diff
-const exportComments = (data, fetchRelaterRecords, dispatch) => {
+const exportComments = (data, fetchRelaterRecords, dataProvider) => {
// ...
}
```

If you used `dispatch` to call the dataProvider using an action creator with a `callback` side effect, you will see that the v3 version makes your exporter code much simpler. If you used it to dispatch custom side effects (like notification or redirect), we recommend that you override the `<ExportButton>` component completely - it'll be much easier to maintain.

As a base, here is the simplified `ExportButton` code:

```jsx
import {
downloadCSV,
useDataProvider,
useNotify,
GET_LIST,
} from 'react-admin';
import jsonExport from 'jsonexport/dist';

const ExportButton = ({ sort, filter, maxResults = 1000, resource }) => {
const dataProvider = useDataProvider();
const notify = useNotify();
const payload = { sort, filter, pagination: { page: 1, perPage: maxResults }}
const handleClick = dataProvider(GET_LIST, resource, payload)
.then(({ data }) => jsonExport(data, (err, csv) => downloadCSV(csv, resource)))
.catch(error => notify('ra.notification.http_error', 'warning'));

return (
<Button
label="Export"
onClick={handleClick}
/>
);
};
```
7 changes: 3 additions & 4 deletions docs/List.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ const PostList = props => (
)
```

In many cases, you'll need more than simple object manipulation. You'll need to *augment* your objects based on relationships. For instance, the export for comments should include the title of the related post - but the export only exposes a `post_id` by default. For that purpose, the exporter receives a `fetchRelatedRecords` function as second parameter. It fetches related records using your `dataProvider` and Redux, and returns a promise.
In many cases, you'll need more than simple object manipulation. You'll need to *augment* your objects based on relationships. For instance, the export for comments should include the title of the related post - but the export only exposes a `post_id` by default. For that purpose, the exporter receives a `fetchRelatedRecords` function as second parameter. It fetches related records using your `dataProvider` and the `GET_MANY` verb, and returns a promise.

Here is an example for a Comments exporter, fetching related Posts:

Expand All @@ -194,6 +194,7 @@ import { List, downloadCSV } from 'react-admin';
import jsonExport from 'jsonexport/dist';

const exporter = (records, fetchRelatedRecords) => {
// will call dataProvider(GET_MANY, 'posts', { ids: records.map(record => record.post_id) }), ignoring duplicate and empty post_id
fetchRelatedRecords(records, 'post_id', 'posts').then(posts => {
const data = records.map(record => ({
...record,
Expand All @@ -214,9 +215,7 @@ const CommentList = props => (
)
```

Under the hood, `fetchRelatedRecords()` uses react-admin's sagas, which trigger the loading spinner while loading. As a bonus, all the records fetched during an export are kepts in the main Redux store, so further browsing the admin will be accelerated.

**Tip**: If you need to call another `dataProvider` verb in the exporter, take advantage of the third parameter passed to the function: `dispatch()`. It allows you to call any Redux action. Combine it with [the `callback` side effect](./Actions.md#custom-sagas) to grab the result in a callback.
**Tip**: If you need to call another verb in the exporter, take advantage of the third parameter passed to the function: it's the `dataProvider` function.

**Tip**: The `<ExportButton>` limits the main request to the `dataProvider` to 1,000 records. If you want to increase or decrease this limit, pass a `maxResults` prop to the `<ExportButton>` in a custom `<ListActions>` component, as explained in the previous section.

Expand Down
162 changes: 0 additions & 162 deletions packages/ra-ui-materialui/src/button/ExportButton.js

This file was deleted.

Loading