Skip to content

Commit a9ac94e

Browse files
committed
docs: revamp the customizing the guessers doc
1 parent db1cb96 commit a9ac94e

7 files changed

+204
-120
lines changed

admin/customizing.md

Lines changed: 204 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,185 +1,269 @@
1-
# Customizing the Admin
1+
# Customizing the Guessers
22

3-
Customizing API Platform Admin is easy and idiomatic. The tool gives you the ability to customize everything, from the list of resource types that must be administrable to every single input or button.
3+
Using `<HydraAdmin>` or `<OpenApiAdmin>` directly is a great way to quickly get started with API Platform Admin. They will introspect your API's schema (using `@api-platform/api-doc-parser`) and automatically generate CRUD pages for all the resources it exposes. They will even [configure filtering, sorting, and real-time updates with Mercure](./schema-org.md) if your API supports it.
44

5-
To do so, you can use the React components provided by API Platform Admin itself, [React Admin](https://marmelab.com/react-admin/), [Material UI](https://material-ui.com/), [community libraries](https://github.com/brillout/awesome-react-components), or [write your own](https://reactjs.org/tutorial/tutorial.html).
5+
For some this may be enough, but you will often find yourself wanting to customize the generated pages further. For instance, you may want to:
66

7-
## Customizing the Admin's Main Page and the Resource List
7+
- Hide or reorder resources in the menu
8+
- Hide or reorder columns in the list view
9+
- Hide or reorder fields in the show, create and edit views
10+
- Customize the generated list, e.g. add a default sort order
11+
- Customize the generated create and edit views, e.g. to add a warning when there are unsaved changes
12+
- Customize the generated inputs, e.g. set a custom label or make a text input multiline
813

9-
By default, API Platform Admin automatically builds a tailored [Resource component](https://marmelab.com/react-admin/Resource.html)
10-
(and all its appropriate children) for each resource type exposed by a web API.
11-
Under the hood it uses the `@api-platform/api-doc-parser` library to parse the API documentation.
12-
The API documentation can use Hydra, OpenAPI and any other format supported by the library.
13-
Resources are listed in the order they appear in the machine-readable documentation.
14+
Such changes can't be achieved by modifying the Schema, they require customizing the React components generated by API Platform Admin.
1415

15-
However, it's also possible to display only specific resources, and to order them, while still benefiting from all discovery features provided by API Platform Admin.
16-
To cherry-pick the resources to make available through the admin, pass a list of `<ResourceGuesser>` components as children of the root component:
16+
Fortunately, API Platform Admin has you covered!
1717

18-
```javascript
19-
import { HydraAdmin, ResourceGuesser } from '@api-platform/admin';
18+
## From `<AdminGuesser>` To `<ResourceGuesser>`
2019

21-
export default () => (
22-
<HydraAdmin entrypoint="https://demo.api-platform.com">
23-
<ResourceGuesser name="books" />
24-
<ResourceGuesser name="reviews" />
20+
If you are using `<HydraAdmin>` or `<OpenApiAdmin>` directly, there is a simple way to start customizing the generated pages.
2521

26-
{/* While deprecated resources are hidden by default, using an explicit ResourceGuesser component allows to add them back. */}
27-
<ResourceGuesser name="parchments" />
28-
</HydraAdmin>
22+
Simply open your browser's developer tools and look at the console. You will see messages like this:
23+
24+
```
25+
If you want to override at least one resource, paste this content in the <AdminGuesser> component of your app:
26+
27+
<ResourceGuesser name="books" />
28+
<ResourceGuesser name="greetings" />
29+
<ResourceGuesser name="reviews" />
30+
```
31+
32+
This message tells you which resources are exposed by your API and how to customize the generated pages for each of them.
33+
34+
Let's say we'd like to hide the `greetings` resource from the menu. We can do this by replacing the `<AdminGuesser>` component (`<HydraAdmin>` in our case) children with a list of `<ResourceGuesser>`:
35+
36+
```diff
37+
-import { HydraAdmin } from "@api-platform/admin";
38+
+import { HydraAdmin, ResourceGuesser } from "@api-platform/admin";
39+
40+
const App = () => (
41+
- <HydraAdmin entrypoint={...} />
42+
+ <HydraAdmin entrypoint={...}>
43+
+ <ResourceGuesser name="books" />
44+
+ <ResourceGuesser name="reviews" />
45+
+ </HydraAdmin>
2946
);
3047
```
3148

32-
Instead of using the `<ResourceGuesser>` component provided by API Platform Admin, you can also pass custom React Admin's [Resource components](https://marmelab.com/react-admin/Resource.html), or any other React components that are supported by React Admin's [Admin](https://marmelab.com/react-admin/Admin.html).
49+
Now the `greetings` resource will no longer be displayed in the menu.
3350

34-
## Customizing the List View
51+
![Customized Admin menu](./images/admin-menu.png)
3552

36-
The list view can be customized following the same pattern:
53+
`<ResourceGuesser>` also accepts all props react-admin's [`<Resource>`](https://marmelab.com/react-admin/Resource.html) component accepts. This means that, for instance, you can use the `list` prop to use your own list component, but keep using the create, edit and show components introspected by `<ResourceGuesser>`:
3754

38-
```javascript
39-
import {
40-
HydraAdmin,
41-
ResourceGuesser,
42-
ListGuesser,
43-
FieldGuesser,
44-
} from '@api-platform/admin';
55+
```diff
56+
import { HydraAdmin, ResourceGuesser } from "@api-platform/admin";
57+
+import { BookList } from "./BookList";
4558

46-
const ReviewsList = (props) => (
47-
<ListGuesser {...props}>
48-
<FieldGuesser source="author" />
49-
<FieldGuesser source="book" />
59+
const App = () => (
60+
<HydraAdmin entrypoint={...}>
61+
- <ResourceGuesser name="books" />
62+
+ <ResourceGuesser name="books" list={BookList} />
63+
<ResourceGuesser name="reviews" />
64+
</HydraAdmin>
65+
);
66+
```
67+
68+
## Customizing the `<ListGuesser>`
69+
70+
By default, `<ResourceGuesser>` will render a `<ListGuesser>` component as the list view for a resource.
71+
72+
Again, this component will automatically introspect the API's schema and generate a list view with all the fields of the resource.
73+
74+
![Admin default generated list view](./images/admin-default-list.png)
5075

51-
{/* While deprecated fields are hidden by default, using an explicit FieldGuesser component allows to add them back. */}
52-
<FieldGuesser source="letter" />
53-
</ListGuesser>
76+
This is already usable, but may not provide the best user experience yet.
77+
78+
Here, too, to start customizing the list view, you can look at the DevTools console. You will see messages like this:
79+
80+
```
81+
If you want to override at least one field, create a BookList component with this content:
82+
83+
import { ListGuesser, FieldGuesser } from "@api-platform/admin";
84+
85+
export const BookList = () => (
86+
<ListGuesser>
87+
<FieldGuesser source="isbn" />
88+
<FieldGuesser source="title" />
89+
<FieldGuesser source="description" />
90+
<FieldGuesser source="author" />
91+
<FieldGuesser source="publicationDate" />
92+
<FieldGuesser source="reviews" />
93+
</ListGuesser>
5494
);
5595
56-
export default () => (
57-
<HydraAdmin entrypoint="https://demo.api-platform.com">
58-
<ResourceGuesser name="reviews" list={ReviewsList} />
59-
{/* ... */}
60-
</HydraAdmin>
96+
Then, update your main admin component:
97+
98+
import { HydraAdmin, ResourceGuesser } from "@api-platform/admin";
99+
import { BookList } from './BookList';
100+
101+
const App = () => (
102+
<HydraAdmin entrypoint={...}>
103+
<ResourceGuesser name="books" list={BookList} />
104+
{/* ... */}
105+
</HydraAdmin>
61106
);
62107
```
63108

64-
In this example, only the fields `author`, `book` and `letter` (that is hidden by default because it is deprecated) will be displayed. The defined order will be respected.
109+
If you follow these instructions, you will end up with the same view as before, but now you can start customizing it.
65110

66-
In addition to the `<FieldGuesser>` component, [all React Admin Fields components](https://marmelab.com/react-admin/Fields.html) can be passed as children of `<ListGuesser>`.
111+
For instance, we'll hide the 'Description' column as it takes too much space (we'll reserve that to the show view). And we will also add a default sort order to show the most recent books first.
67112

68-
## Customizing the Show View
113+
Here's how to achieve this:
69114

70-
For the show view:
115+
```diff
116+
export const BookList = () => (
117+
- <ListGuesser>
118+
+ <ListGuesser sort={{ field: 'publicationDate', order: 'DESC' }}>
119+
<FieldGuesser source="isbn" />
120+
<FieldGuesser source="title" />
121+
- <FieldGuesser source="description" />
122+
<FieldGuesser source="author" />
123+
<FieldGuesser source="publicationDate" />
124+
<FieldGuesser source="reviews" />
125+
</ListGuesser>
126+
);
127+
```
71128

72-
```javascript
73-
import {
74-
HydraAdmin,
75-
ResourceGuesser,
76-
ShowGuesser,
77-
FieldGuesser,
78-
} from '@api-platform/admin';
129+
And here is the result:
79130

80-
const ReviewsShow = (props) => (
81-
<ShowGuesser {...props}>
82-
<FieldGuesser source="author" />
83-
<FieldGuesser source="book" />
84-
<FieldGuesser source="rating" />
131+
![Admin with customized list guesser](./images/admin-custom-list-guesser.png)
85132

86-
{/* While deprecated fields are hidden by default, using an explicit FieldGuesser component allows to add them back. */}
87-
<FieldGuesser source="letter" />
133+
That's already better isn't it? 🙂
88134

89-
<FieldGuesser source="body" />
90-
<FieldGuesser source="publicationDate" />
91-
</ShowGuesser>
92-
);
135+
## Customizing the `<FieldGuesser>`
93136

94-
export default () => (
95-
<HydraAdmin entrypoint="https://demo.api-platform.com">
96-
<ResourceGuesser name="reviews" show={ReviewsShow} />
97-
{/* ... */}
98-
</HydraAdmin>
137+
Removing or reordering `<FieldGuesser>` components is not the only thing we can do. We can also customize them.
138+
139+
Indeed, `<FieldGuesser>` will forward additional props to the underlying React Admin [Field component](https://marmelab.com/react-admin/Fields.html).
140+
141+
This means we can use any [common field prop](https://marmelab.com/react-admin/Fields.html#common-field-props) on them.
142+
143+
For instance, let's add a `label` prop to customize the label of the ISBN column to be all uppercase:
144+
145+
```diff
146+
export const BookList = () => (
147+
<ListGuesser sort={{ field: 'publicationDate', order: 'DESC' }}>
148+
- <FieldGuesser source="isbn" />
149+
+ <FieldGuesser source="isbn" label="ISBN" />
150+
<FieldGuesser source="title" />
151+
<FieldGuesser source="author" />
152+
<FieldGuesser source="publicationDate" />
153+
<FieldGuesser source="reviews" />
154+
</ListGuesser>
99155
);
100156
```
101157

102-
In addition to the `<FieldGuesser>` component, [all React Admin Fields components](https://marmelab.com/react-admin/Fields.html) can be passed as children of `<ShowGuesser>`.
158+
And here is the result:
159+
160+
![Admin with customized list guesser and field guesser](./images/admin-custom-list-field-guesser.png)
103161

104-
## Customizing the Create Form
162+
## Customizing the `<ShowGuesser>`
105163

106-
Again, the same logic applies to forms. Here is how to customize the create form:
164+
Following the same principles (including looking at the DevTools console) we can customize the show view.
107165

108-
```javascript
166+
In the following example, the show view for the `books` resource was customized to make the label of the `isbn` field uppercase:
167+
168+
```tsx
109169
import {
110170
HydraAdmin,
111171
ResourceGuesser,
112-
CreateGuesser,
113-
InputGuesser,
172+
ShowGuesser,
173+
FieldGuesser,
114174
} from '@api-platform/admin';
115175

116-
const ReviewsCreate = (props) => (
117-
<CreateGuesser {...props}>
118-
<InputGuesser source="author" />
119-
<InputGuesser source="book" />
120-
<InputGuesser source="rating" />
121-
122-
{/* While deprecated fields are hidden by default, using an explicit InputGuesser component allows to add them back. */}
123-
<InputGuesser source="letter" />
124-
125-
<InputGuesser source="body" />
126-
<InputGuesser source="publicationDate" />
127-
</CreateGuesser>
176+
const BookShow = () => (
177+
<ShowGuesser>
178+
<FieldGuesser source="isbn" label="ISBN" />
179+
<FieldGuesser source="title" />
180+
<FieldGuesser source="description" />
181+
<FieldGuesser source="author" />
182+
<FieldGuesser source="publicationDate" />
183+
<FieldGuesser source="reviews" />
184+
</ShowGuesser>
128185
);
129186

130187
export default () => (
131188
<HydraAdmin entrypoint="https://demo.api-platform.com">
132-
<ResourceGuesser name="reviews" create={ReviewsCreate} />
133-
{/* ... */}
189+
<ResourceGuesser name="books" show={BookShow} />
190+
<ResourceGuesser name="reviews" />
134191
</HydraAdmin>
135192
);
136193
```
137194

138-
In addition to the `<InputGuesser>` component, [all React Admin Input components](https://marmelab.com/react-admin/Inputs.html) can be passed as children of `<CreateGuesser>`.
195+
Here is the result:
139196

140-
For instance, using an autocomplete input is straightforward, [check out the dedicated documentation entry](handling-relations.md#using-an-autocomplete-input-for-relations)!
197+
![Admin with customized show guesser](./images/admin-custom-show-guesser.png)
141198

142-
## Customizing the Edit Form
199+
## Customizing the `<EditGuesser>` and `<CreateGuesser>`
143200

144-
Finally, you can customize the edit form the same way:
201+
Customizing the `<EditGuesser>` and `<CreateGuesser>` is very similar to customizing the `<ShowGuesser>`.
145202

146-
```javascript
147-
import {
148-
HydraAdmin,
149-
ResourceGuesser,
150-
EditGuesser,
151-
InputGuesser,
152-
} from '@api-platform/admin';
203+
Again, we can start by looking at the DevTools console to get the initial code of the components.
153204

154-
const ReviewsEdit = (props) => (
155-
<EditGuesser {...props}>
156-
<InputGuesser source="author" />
157-
<InputGuesser source="book" />
158-
<InputGuesser source="rating" />
205+
```
206+
If you want to override at least one input, create a ReviewEdit component with this content:
207+
208+
import { EditGuesser, InputGuesser } from "@api-platform/admin";
209+
210+
export const ReviewEdit = () => (
211+
<EditGuesser>
212+
<InputGuesser source="rating" />
213+
<InputGuesser source="body" />
214+
<InputGuesser source="author" />
215+
<InputGuesser source="publicationDate" />
216+
<InputGuesser source="book" />
217+
</EditGuesser>
218+
);
219+
220+
Then, update your main admin component:
159221
160-
{/* While deprecated fields are hidden by default, using an explicit InputGuesser component allows to add them back. */}
161-
<InputGuesser source="letter" />
222+
import { HydraAdmin, ResourceGuesser } from "@api-platform/admin";
223+
import { ReviewEdit } from './ReviewEdit';
162224
163-
<InputGuesser source="body" />
164-
<InputGuesser source="publicationDate" />
165-
</EditGuesser>
225+
const App = () => (
226+
<HydraAdmin entrypoint={...}>
227+
<ResourceGuesser name="reviews" edit={ReviewEdit} />
228+
{/* ... */}
229+
</HydraAdmin>
166230
);
231+
```
167232

168-
export default () => (
169-
<HydraAdmin entrypoint="https://demo.api-platform.com">
170-
<ResourceGuesser edit={ReviewsEdit} />
171-
{/* ... */}
172-
</HydraAdmin>
233+
Let's customize this `ReviewEdit` component to:
234+
235+
- reorder the inputs
236+
- make the `body` input multiline
237+
- mark the `publicationDate` input as read-only
238+
239+
240+
```diff
241+
export const ReviewEdit = () => (
242+
<EditGuesser>
243+
- <InputGuesser source="rating" />
244+
- <InputGuesser source="body" />
245+
- <InputGuesser source="author" />
246+
- <InputGuesser source="publicationDate" />
247+
- <InputGuesser source="book" />
248+
+ <InputGuesser source="author" />
249+
+ <InputGuesser source="book" />
250+
+ <InputGuesser source="body" multiline />
251+
+ <InputGuesser source="rating" />
252+
+ <InputGuesser source="publicationDate" readOnly />
253+
</EditGuesser>
173254
);
174255
```
175256

176-
In addition to the `<InputGuesser>` component, [all React Admin Input components](https://marmelab.com/react-admin/Inputs.html) can be passed as children of `<EditGuesser>`.
257+
Here is the result:
177258

178-
For instance, using an autocomplete input is straightforward, [checkout the dedicated documentation entry](handling-relations.md#using-an-autocomplete-input-for-relations)!
259+
![Admin with customized edit guesser](./images/admin-custom-edit-guesser.png)
260+
261+
**Tip:** Here, we leveraged the `multiline` and `readOnly` props of the `<InputGuesser>` component. But you can use any [common input prop](https://marmelab.com/react-admin/Inputs.html#common-input-props) supported by react-admin [Inputs](https://marmelab.com/react-admin/Inputs.html) on them.
179262

180263
## Going Further
181264

182-
API Platform is built on top of [React Admin](https://marmelab.com/react-admin/).
183-
You can use all the features provided by the underlying library with API Platform Admin, including support for [authentication](https://marmelab.com/react-admin/Authentication.html), [authorization](https://marmelab.com/react-admin/Authorization.html) and deeper customization.
265+
The above examples limit to customizing the various API Platform Admin Guessers, but this is just the tip of the iceberg.
266+
267+
By leveraging React Admin components and props, you can go much further in customizing the generated pages.
184268

185-
To learn more about these capabilities, refer to [the React Admin documentation](https://marmelab.com/react-admin/documentation.html).
269+
Head to the next section, [Customizing the Admin](./customizing-the-admin.md), for step-by-step examples.
46.9 KB
Loading
97.5 KB
Loading
95 KB
Loading
51.8 KB
Loading

admin/images/admin-default-list.png

65.1 KB
Loading

admin/images/admin-menu.png

97.4 KB
Loading

0 commit comments

Comments
 (0)