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

Use resource definition to set default <Datagrid rowClick> value #9466

Merged
merged 4 commits into from
Nov 23, 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
2 changes: 1 addition & 1 deletion docs/Breadcrumb.md
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,7 @@ export const SongList = () => {
useDefineAppLocation('music.songs');
return (
<List>
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="title" />
</Datagrid>
</List>
Expand Down
2 changes: 1 addition & 1 deletion docs/CustomRoutes.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ const BookList = () => {
const { authorId } = useParams();
return (
<List resource="books" filter={{ authorId }}>
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<TextField source="year" />
Expand Down
16 changes: 9 additions & 7 deletions docs/Datagrid.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Both are [Enterprise Edition](https://marmelab.com/ra-enterprise) components.
| `isRowExpandable` | Optional | Function | `() => true` | A function that returns whether a row is expandable. |
| `isRowSelectable` | Optional | Function | `() => true` | A function that returns whether a row is selectable. |
| `optimized` | Optional | Boolean | `false` | Whether to optimize the rendering of the table. |
| `rowClick` | Optional | mixed | | The action to trigger when the user clicks on a row. |
| `rowClick` | Optional | mixed | `'show'` or `'edit'` | The action to trigger when the user clicks on a row. |
| `rowStyle` | Optional | Function | | A function that returns the style to apply to a row. |
| `rowSx` | Optional | Function | | A function that returns the sx prop to apply to a row. |
| `size` | Optional | `'small'` or `'medium'` | `'small'` | The size of the table. |
Expand Down Expand Up @@ -409,7 +409,7 @@ const FullNameField = () => {

export const UserList = () => (
<List>
<Datagrid rowclick="edit">
<Datagrid>
<FullNameField source="last_name" label="Name" />
<DateField source="dob" />
<TextField source="city" />
Expand Down Expand Up @@ -676,7 +676,9 @@ const PostList = () => (

## `rowClick`

You can catch clicks on rows to redirect to the show or edit view by setting the `rowClick` prop:
By default, `<Datagrid>` will look at the current [resource definition](https://marmelab.com/react-admin/Resource.html) to determine what to do when the user clicks on a row. If the resource has a `show` page, it will redirect to the Show view. If the resource has an `edit` page, it will redirect to the Edit view. Otherwise, the row will not be clickable.

You can choose what happens when the user clicks on a row by setting the `rowClick` prop. For instance, set the `rowClick` prop to `"edit"` to redirect to the Edit view:

```tsx
import { List, Datagrid } from 'react-admin';
Expand All @@ -692,10 +694,10 @@ export const PostList = () => (

`rowClick` accepts the following values:

* "edit" to redirect to the edition view
* "show" to redirect to the show view
* "expand" to open the `expand` panel
* "toggleSelection" to trigger the `onToggleItem` function
* `"edit"` to redirect to the edition view
* `"show"` to redirect to the show view
* `"expand"` to open the `expand` panel
* `"toggleSelection"` to trigger the `onToggleItem` function
* `false` to do nothing
* a function `(id, resource, record) => path` that may return any of the above values or a custom path

Expand Down
2 changes: 1 addition & 1 deletion docs/Features.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ const BookList = () => (
<List filters={[
<ReferenceInput source="authorId" reference="authors" alwaysOn />,
]}>
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<ReferenceField source="authorId" reference="authors" />
Expand Down
2 changes: 1 addition & 1 deletion docs/List.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ export const PostList = () => {
tertiaryText={record => new Date(record.published_at).toLocaleDateString()}
/>
) : (
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<ReferenceField label="User" source="userId" reference="users">
<TextField source="name" />
Expand Down
2 changes: 1 addition & 1 deletion docs/ListTutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ export const PostList = () => {
tertiaryText={record => new Date(record.published_at).toLocaleDateString()}
/>
) : (
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<ReferenceField label="User" source="userId" reference="users">
<TextField source="name" />
Expand Down
2 changes: 1 addition & 1 deletion docs/RealtimeDataProvider.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const App = () => (

const SaleList = () => (
<ListLive>
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<TextField source="first_name" />
<TextField source="last_name" />
Expand Down
4 changes: 2 additions & 2 deletions docs/Resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export const BookList = () => {
const { authorId } = useParams();
return (
<List resource="books" filter={{ authorId }}>
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<TextField source="year" />
Expand Down Expand Up @@ -347,7 +347,7 @@ export const SongList = () => {
const { id } = useParams();
return (
<List resource="songs" filter={{ artistId: id }}>
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="title" />
<DateField source="released" />
<TextField source="writer" />
Expand Down
34 changes: 11 additions & 23 deletions docs/Tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ import { List, Datagrid, TextField, EmailField } from "react-admin";

export const UserList = () => (
<List>
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<TextField source="name" />
<TextField source="username" />
Expand Down Expand Up @@ -208,7 +208,7 @@ Let's take a moment to analyze the code of the `<UserList>` component:
```tsx
export const UserList = () => (
<List>
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<TextField source="name" />
<TextField source="username" />
Expand Down Expand Up @@ -290,7 +290,7 @@ export const UserList = () => {
tertiaryText={(record) => record.email}
/>
) : (
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<TextField source="name" />
<TextField source="username" />
Expand Down Expand Up @@ -325,7 +325,7 @@ Let's get back to `<Datagrid>`. It reads the data fetched by `<List>`, then rend

```diff
// in src/users.tsx
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<TextField source="name" />
- <TextField source="username" />
Expand All @@ -352,7 +352,7 @@ For instance, the `website` field looks like a URL. Instead of displaying it as
-import { List, SimpleList, Datagrid, TextField, EmailField } from "react-admin";
+import { List, SimpleList, Datagrid, TextField, EmailField, UrlField } from "react-admin";
// ...
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<TextField source="name" />
<EmailField source="email" />
Expand Down Expand Up @@ -396,7 +396,7 @@ You can use the `<MyUrlField>` component in `<UserList>`, instead of react-admin
+import { List, SimpleList, Datagrid, TextField, EmailField } from "react-admin";
+import MyUrlField from './MyUrlField';
// ...
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<TextField source="name" />
<EmailField source="email" />
Expand Down Expand Up @@ -484,7 +484,7 @@ import { List, Datagrid, TextField, ReferenceField } from "react-admin";

export const PostList = () => (
<List>
<Datagrid rowClick="edit">
<Datagrid>
<ReferenceField source="userId" reference="users" />
<TextField source="id" />
<TextField source="title" />
Expand Down Expand Up @@ -532,7 +532,7 @@ The `<ReferenceField>` component fetches the reference data, creates a `RecordCo

**Tip**: Look at the network tab of your browser again: react-admin deduplicates requests for users, and aggregates them in order to make only *one* HTTP request to the `/users` endpoint for the whole Datagrid. That's one of many optimizations that keep the UI fast and responsive.

To finish the post list, place the post `id` field as first column, and remove the `body` field. From a UX point of view, fields containing large chunks of text should not appear in a Datagrid, only in detail views. Also, to make the Edit action stand out, let's replace the `rowClick` action by an explicit action button:
To finish the post list, place the post `id` field as first column, and remove the `body` field. From a UX point of view, fields containing large chunks of text should not appear in a Datagrid, only in detail views. Also, to make the Edit action stand out, let's replace the default `rowClick` action by an explicit action button:

```diff
// in src/posts.tsx
Expand All @@ -541,8 +541,8 @@ To finish the post list, place the post `id` field as first column, and remove t

export const PostList = () => (
<List>
- <Datagrid rowClick="edit">
+ <Datagrid>
- <Datagrid>
+ <Datagrid rowClick={false}>
+ <TextField source="id" />
<ReferenceField source="userId" reference="users" />
- <TextField source="id" />
Expand Down Expand Up @@ -577,18 +577,6 @@ export const App = () => (
);
```

You will need to modify the user list view so that a click on a datagrid row links to the show view:

```diff
// in src/users.tsx
export const UserList = () => {
// ...
- <Datagrid rowClick="edit">
+ <Datagrid rowClick="show">
// ...
};
```

Now you can click on a user in the list to see its details:

<video controls autoplay playsinline muted loop>
Expand All @@ -604,7 +592,7 @@ But now that the `users` resource has a `show` view, you can also link to it fro
// in src/posts.tsx
export const PostList = () => (
<List>
<Datagrid rowClick="edit">
<Datagrid>
- <ReferenceField source="userId" reference="users" />
+ <ReferenceField source="userId" reference="users" link="show" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for this PR but this should probably be automatic as well (detection of the available views with the same priorities)

<TextField source="id" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ describe('<PrevNextButtons />', () => {
render(<Basic />);
const row = await screen.findByText('Deja');
fireEvent.click(row);
fireEvent.click(screen.getByLabelText('Edit'));
const next = await screen.findByLabelText('Go to next page');
fireEvent.click(next);
expect(screen.getByLabelText('First name').getAttribute('type')).toBe(
Expand All @@ -91,7 +92,6 @@ describe('<PrevNextButtons />', () => {
render(<Basic />);
const row = await screen.findByText('Deja');
fireEvent.click(row);
fireEvent.click(screen.getByLabelText('Show'));
const next = await screen.findByLabelText('Go to next page');
fireEvent.click(next);
expect(screen.queryByLabelText('First name')).toBeNull();
Expand Down
2 changes: 1 addition & 1 deletion packages/ra-ui-materialui/src/list/ListGuesser.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { Datagrid, DateField, List, NumberField, ReferenceField, TextField } fro

export const CommentList = () => (
<List>
<Datagrid rowClick="edit">
<Datagrid>
<TextField source="id" />
<TextField source="author" />
<ReferenceField source="post_id" reference="posts" />
Expand Down
6 changes: 2 additions & 4 deletions packages/ra-ui-materialui/src/list/ListGuesser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
useListContext,
useResourceContext,
RaRecord,
useResourceDefinition,
} from 'ra-core';

import { ListProps } from './List';
Expand Down Expand Up @@ -74,7 +73,6 @@ const ListViewGuesser = (
) => {
const { data } = useListContext(props);
const resource = useResourceContext();
const { hasEdit, hasShow } = useResourceDefinition(props);
const [child, setChild] = useState(null);
const {
enableLog = process.env.NODE_ENV === 'development',
Expand All @@ -93,7 +91,7 @@ const ListViewGuesser = (
);
const inferredChild = new InferredElement(
listFieldTypes.table,
{ hasEdit, hasShow },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because it's no longer necessary 🤷
(ListGuesser used these props to calculate the rowClick prop, which we no longer needed, so might as well cleanup the props we send to InferredElement... Using null is something I saw in other components (EditGuesser if my recollection is correct) so I did the same thing)

null,
inferredElements
);
setChild(inferredChild.getElement());
Expand Down Expand Up @@ -128,7 +126,7 @@ ${inferredChild.getRepresentation()}
);`
);
}
}, [data, child, resource, hasEdit, hasShow, enableLog]);
}, [data, child, resource, enableLog]);

return <ListView {...rest}>{child}</ListView>;
};
Expand Down
Loading
Loading