diff --git a/docs/Features.md b/docs/Features.md index 352fdbe7b1e..7ceca691c68 100644 --- a/docs/Features.md +++ b/docs/Features.md @@ -17,7 +17,7 @@ We've crafted the API of react-admin's components and hooks to be as **intuitive React-admin provides the **best-in-class documentation**, demo apps, and support. Error messages are clear and actionable. Thanks to extensive TypeScript types and JSDoc, it's easy to use react-admin in any IDE. The API is stable and **breaking changes are very rare**. You can debug your app with the [query](./DataProviders.md#enabling-query-logs) and [form](https://react-hook-form.com/dev-tools) developer tools, and inspect the react-admin code right in your browser. -That probably explains why more than 3,000 new apps are published every month using react-admin. +That probably explains why more than 3,000 new apps are published every month using react-admin. So react-admin is not just the assembly of [react-query](https://react-query.tanstack.com/), [react-hook-form](https://marmelab.com/react-admin/assets/techs/react-hook-form.jpeg), [react-router](https://reacttraining.com/react-router/), [Material UI](https://mui.com/material-ui/getting-started/) and [Emotion](https://github.com/emotion-js/emotion). It's a **framework** made to speed up and facilitate the development of single-page apps in React. @@ -61,7 +61,7 @@ Which kind of API? **All kinds**. React-admin is backend agnostic. It doesn't ca React-admin ships with [more than 50 adapters](./DataProviderList.md) for popular API flavors, and gives you all the tools to build your own adapter. This works thanks to a powerful abstraction layer called the [Data Provider](./DataProviders.md). -In a react-admin app, you don't write API Calls. Instead, you communicate with your API using a set of high-level functions, called "Data Provider methods". For instance, to fetch a list of posts, you call the `getList()` method, passing the resource name and the query parameters. +In a react-admin app, you don't write API Calls. Instead, you communicate with your API using a set of high-level functions, called "Data Provider methods". For instance, to fetch a list of posts, you call the `getList()` method, passing the resource name and the query parameters. ```jsx import { useState, useEffect } from 'react'; @@ -73,10 +73,10 @@ const PostList = () => { const [isLoading, setIsLoading] = useState(true); const dataProvider = useDataProvider(); useEffect(() => { - dataProvider.getList('posts', { + dataProvider.getList('posts', { pagination: { page: 1, perPage: 10 }, sort: { field: 'published_at', order: 'DESC' }, - filter: { status: 'published' } + filter: { status: 'published' } }) .then(({ data }) => setPosts(data)) .catch(error => setError(error)) @@ -121,7 +121,7 @@ const PostList = () => { React-admin is also **backend agnostic for authentication and authorization**. Whether your API uses JWT, OAuth, a third-party provider like Auth0 or Cognito, or even Azure Active Directory, you can communicate with the authentication backend through an adapter object called [the Auth Provider](./Authentication.md). -You can then use specialized hooks on your components to restrict access. For instance, to forbid anonymous access, use `useAuthenticated`: +You can then use specialized hooks on your components to restrict access. For instance, to forbid anonymous access, use `useAuthenticated`: ```jsx import { useAuthenticated } from 'react-admin'; @@ -140,7 +140,7 @@ export default MyPage; ## Relationships -APIs often expose a relational model, i.e. endpoints returning foreign keys to other endpoints. **React-admin leverages relational APIs** to provide smart components that display related records and components that allow editing of related records. +APIs often expose a relational model, i.e. endpoints returning foreign keys to other endpoints. **React-admin leverages relational APIs** to provide smart components that display related records and components that allow editing of related records. ``` ┌──────────────┐ ┌────────────────┐ @@ -153,7 +153,7 @@ APIs often expose a relational model, i.e. endpoints returning foreign keys to o └──────────────┘ └────────────────┘ ``` -For instance, `` displays the name of a related record, like the name of an author for a book. +For instance, `` displays the name of a related record, like the name of an author for a book. ```jsx const BookList = () => ( @@ -170,7 +170,7 @@ const BookList = () => ( ![ReferenceField](./img/reference-field-link.png) -You don't need anything fancy on the API side to support that. Simple CRUD routes for both the `books` and `authors` resources are enough. `` will fetch the book authors via one single API call: +You don't need anything fancy on the API side to support that. Simple CRUD routes for both the `books` and `authors` resources are enough. `` will fetch the book authors via one single API call: ``` GET https://my.api.url/authors?filter={ids:[1,2,3,4,5,6,7]} @@ -263,7 +263,7 @@ And if the default design isn't good enough for you, you can easily customize it Modern web apps are often very visually pleasing, but they can be difficult to use due to low information density. End users need a lot of scrolling and clicking to complete moderately complex tasks. -On the other hand, the default React-admin skin is designed to be dense, giving **more space to the content and less to the chrome**, which allows for faster user interaction. +On the other hand, the default React-admin skin is designed to be dense, giving **more space to the content and less to the chrome**, which allows for faster user interaction. [![Dense layout](./img/dense.webp)](https://marmelab.com/react-admin-demo/#/) @@ -273,7 +273,7 @@ And for mobile users, react-admin renders a different layout with larger margins ## Guessers & Scaffolding -When mapping a new API route to a CRUD view, adding fields one by one can be tedious. React-admin provides a set of guessers that can automatically **generate a complete CRUD UI based on an API response**. +When mapping a new API route to a CRUD view, adding fields one by one can be tedious. React-admin provides a set of guessers that can automatically **generate a complete CRUD UI based on an API response**. For instance, the following code will generate a complete CRUD UI for the `posts` resource: @@ -341,7 +341,7 @@ In most admin and B2B apps, the most common task is to look for a record. React- -These features rely on powerful components with an intuitive API. For instance, you can set the Filter Button/Form Combo with the `` prop, using the same input components as in edition forms: +These features rely on powerful components with an intuitive API. For instance, you can set the Filter Button/Form Combo with the `` prop, using the same input components as in edition forms: ```jsx import { List, TextInput } from 'react-admin'; @@ -365,7 +365,7 @@ Check the following chapters to learn more about each search and filtering compo - [``](./StackedFilters.md) - [``](./Search.md) -Users often apply the same filters over and over again. Saved Queries **let users save a combination of filters** and sort parameters into a new, personal filter, that persists between sessions. +Users often apply the same filters over and over again. Saved Queries **let users save a combination of filters** and sort parameters into a new, personal filter, that persists between sessions. -In addition to [the usual input types](./Inputs.md) (``, ``, ``, etc.), you can use the `` in the `filters` array. This input is designed especially for the [`Filter Form`](./FilterForm.md). It's like a `` with a magnifier glass icon - exactly the type of input users look for when they want to do a full-text search. +In addition to [the usual input types](./Inputs.md) (``, ``, ``, etc.), you can use the `` in the `filters` array. This input is designed especially for the [`Filter Form`](./FilterForm.md). It's like a `` with a magnifier glass icon - exactly the type of input users look for when they want to do a full-text search. ```jsx import { SearchInput, TextInput } from 'react-admin'; @@ -116,7 +116,7 @@ In the example given above, the `q` filter triggers a full-text search on all fi -Users usually dislike using their keyboard to filter a list (especially on mobile). A good way to satisfy this user requirement is to turn filters into *quick filter*. A Quick filter is a filter with a non-editable `defaultValue`. Users can only enable or disable them. +Users usually dislike using their keyboard to filter a list (especially on mobile). A good way to satisfy this user requirement is to turn filters into *quick filter*. A Quick filter is a filter with a non-editable `defaultValue`. Users can only enable or disable them. Here is how to implement a generic `` component: @@ -139,7 +139,7 @@ const postFilters = [ ``` {% endraw %} -**Tip**: It's currently not possible to use two quick filters for the same source. +**Tip**: It's currently not possible to use two quick filters for the same source. ## The `` Sidebar @@ -283,11 +283,11 @@ Check the [`` documentation](./StackedFilters.md) for more infor Your browser does not support the video tag. -Although list filters allow to make precise queries using per-field criteria, users often prefer simpler interfaces like full-text search. After all, that's what they use every day on search engines, email clients, and in their file explorer. +Although list filters allow to make precise queries using per-field criteria, users often prefer simpler interfaces like full-text search. After all, that's what they use every day on search engines, email clients, and in their file explorer. If you want to display a full-text search allowing to look for any record in the admin using a single form input, check out [the `` component](./Search.md), an [Enterprise Edition](https://marmelab.com/ra-enterprise) exclusive. -`` can plug to any existing search engine (ElasticSearch, Lucene, or custom search engine), and lets you customize the search results to provide quick navigation to related items, turning the search engine into an "Omnibox": +`` can plug to any existing search engine (ElasticSearch, Lucene, or custom search engine), and lets you customize the search results to provide quick navigation to related items, turning the search engine into an "Omnibox": -For mode details about the global search, check the [`` documentation](./Search.md). +For mode details about the global search, check the [`` documentation](./Search.md). ## Filter Query Parameter -React-admin uses the `filter` query parameter from the URL to determine the filters to apply to the list. +React-admin uses the `filter` query parameter from the URL to determine the filters to apply to the list. Here is a typical List page URL in a react-admin application: @@ -325,7 +325,7 @@ When a user adds or remove a filter, react-admin changes the `filter` query para **Tip**: Once a user sets a filter, react-admin persists the filter value in the application state, so that when the user comes back to the list, they should see the filtered list. That's a design choice. -**Tip**: You can change the filters programmatically by updating the query parameter, e.g. using the `` component or the `useNavigate()` hook from `react-router-dom`. +**Tip**: You can change the filters programmatically by updating the query parameter, e.g. using the `` component or the `useNavigate()` hook from `react-router-dom`. ## Linking To A Pre-Filtered List @@ -351,7 +351,7 @@ const LinkToRelatedProducts = () => { search: `filter=${JSON.stringify({ category_id: record.id })}`, }} > - All posts with the category {record.name} ; + All posts with the category {record.name} ; ) : null; }; @@ -425,7 +425,7 @@ export default { -Saved Queries let users save a combination of filters and sort parameters into a new, personal filter. Saved queries persist between sessions, so users can find their custom queries even after closing and reopening the admin. Saved queries are available both for the Filter Button/Form combo and for the `` Sidebar. It's enabled by default for the Filter Button/Form combo but you have to add it yourself in the `` Sidebar. +Saved Queries let users save a combination of filters and sort parameters into a new, personal filter. Saved queries persist between sessions, so users can find their custom queries even after closing and reopening the admin. Saved queries are available both for the Filter Button/Form combo and for the `` Sidebar. It's enabled by default for the Filter Button/Form combo but you have to add it yourself in the `` Sidebar. `` is a complement to `` sections for the filter sidebar @@ -469,7 +469,7 @@ const SongList = () => ( If neither the Filter button/form combo nor the `` sidebar match your need, you can always build your own. React-admin provides shortcuts to facilitate the development of custom filters. -For instance, by default, the filter button/form combo doesn't provide a submit button, and submits automatically after the user has finished interacting with the form. This provides a smooth user experience, but for some APIs, it can cause too many calls. +For instance, by default, the filter button/form combo doesn't provide a submit button, and submits automatically after the user has finished interacting with the form. This provides a smooth user experience, but for some APIs, it can cause too many calls. In that case, the solution is to process the filter when users click on a submit button, rather than when they type values in form inputs. React-admin doesn't provide any component for that, but it's a good opportunity to illustrate the internals of the filter functionality. We'll actually provide an alternative implementation to the Filter button/form combo. @@ -511,7 +511,7 @@ const PostFilterButton = () => { }; ``` -Normally, `showFilter()` adds one input to the `displayedFilters` list. As the filter form will be entirely hidden or shown, we use `showFilter()` with a virtual "main" input, which represents the entire form. +Normally, `showFilter()` adds one input to the `displayedFilters` list. As the filter form will be entirely hidden or shown, we use `showFilter()` with a virtual "main" input, which represents the entire form. ### Custom Filter Form diff --git a/docs/List.md b/docs/List.md index d6c5ceffef9..9df4a70d4a6 100644 --- a/docs/List.md +++ b/docs/List.md @@ -5,7 +5,7 @@ title: "The List Component" # `` -The `` component is the root component for list pages. It fetches a list of records from the data provider, puts it in a [`ListContext`](./useListContext.md), renders the default list page layout (title, buttons, filters, pagination), and renders its children. Usual children of ``, like [``](./Datagrid.md), are responsible for displaying the list of records. +The `` component is the root component for list pages. It fetches a list of records from the data provider, puts it in a [`ListContext`](./useListContext.md), renders the default list page layout (title, buttons, filters, pagination), and renders its children. Usual children of ``, like [``](./Datagrid.md), are responsible for displaying the list of records. ![Simple posts list](./img/simple-post-list.png) @@ -46,7 +46,7 @@ export default App; That's enough to display a basic post list, with functional sort and pagination. -You can find more advanced examples of `` usage in the [demos](./Demos.md). +You can find more advanced examples of `` usage in the [demos](./Demos.md). ## Props @@ -83,7 +83,7 @@ By default, the `` view displays a toolbar on top of the list. It contains - A `` to display the filter form if you set [the `filters` prop](#filters-filter-inputs) - A `` if the resource has a creation view, or if you set [the `hasCreate` prop](#hascreate) -- An `` +- An `` ![Actions Toolbar](./img/actions-toolbar.png) @@ -98,6 +98,7 @@ import { List, SelectColumnsButton, TopToolbar, + SearchInput, } from 'react-admin'; import IconEvent from '@mui/icons-material/Event'; @@ -111,7 +112,7 @@ const ListActions = () => ( ); const postFilters = [ - , + , , ]; @@ -127,7 +128,7 @@ export const PostList = () => ( Use the `useListContext` hook to customize the actions depending on the list context, and the `usePermissions` to show/hide buttons depending on permissions. For example, you can hide the `` when the user doesn't have the right permission, and disable the `` when the list is empty: ```jsx -import { +import { useListContext, usePermissions, TopToolbar, @@ -200,7 +201,7 @@ const Aside = () => { ``` {% endraw %} -The `aside` prop is also the preferred way to add a [Filter Sidebar](./FilteringTutorial.md#the-filterlist-sidebar) to a list view: +The `aside` prop is also the preferred way to add a [Filter Sidebar](./FilteringTutorial.md#the-filterlist-sidebar) to a list view: {% raw %} ```jsx @@ -278,7 +279,7 @@ React-admin provides several components that can read and display a list of reco - [``](./SimpleList.md) displays records in a list without many details - suitable for mobile devices - [``](./TreeWithDetails.md) displays records in a tree structure - [``](./Calendar.md) displays event records in a calendar -- [``](./SingleFieldList.md) displays records inline, showing one field per record +- [``](./SingleFieldList.md) displays records inline, showing one field per record So for instance, you can use a `` instead of a `` on mobile devices: @@ -352,7 +353,7 @@ const PostList = () => ( ); -// use a custom component as root component +// use a custom component as root component const PostList = () => ( ... @@ -379,7 +380,7 @@ const PostList = () => ( ## `disableAuthentication` -By default, all pages using `` require the user to be authenticated - any anonymous access redirects the user to the login page. +By default, all pages using `` require the user to be authenticated - any anonymous access redirects the user to the login page. If you want to allow anonymous access to a List page, set the `disableAuthentication` prop to `true`. @@ -465,7 +466,7 @@ const ProductList = () => ( ``` {% endraw %} -The `empty` component can call the `useListContext()` hook to receive the same props as the `List` child component. +The `empty` component can call the `useListContext()` hook to receive the same props as the `List` child component. You can also set the `empty` props value to `false` to bypass the empty page display and render an empty list instead. @@ -527,7 +528,7 @@ const SimpleBookList = () => { } ``` -The `` prop provides a convenient shortcut for that use case. When enabled, `` won't render its child until `data` is defined. +The `` prop provides a convenient shortcut for that use case. When enabled, `` won't render its child until `data` is defined. ```diff const BookList = () => ( @@ -641,7 +642,7 @@ You can add an array of filter Inputs to the List using the `filters` prop: ```jsx const postFilters = [ - , + , , ]; @@ -656,7 +657,7 @@ export const PostList = () => ( **Tip**: Filters will render as disabled inputs or menu items (depending on filter context) if passed the prop `disabled`. -Filter Inputs are regular inputs. `` hides them all by default, except those that have the `alwaysOn` prop. +Filter Inputs are regular inputs. `` hides them all by default, except those that have the `alwaysOn` prop. You can also display filters as a sidebar: @@ -667,7 +668,7 @@ You can also display filters as a sidebar: -For more details about customizing filters, see the [Filtering the List](./FilteringTutorial.md#filtering-the-list) documentation. +For more details about customizing filters, see the [Filtering the List](./FilteringTutorial.md#filtering-the-list) documentation. ## `filter`: Permanent Filter @@ -782,7 +783,7 @@ export const PostList = () => ( ## `queryOptions` -`` accepts a `queryOptions` prop to pass options to the react-query client. +`` accepts a `queryOptions` prop to pass options to the react-query client. This can be useful e.g. to pass [a custom `meta`](./Actions.md#meta-parameter) to the `dataProvider.getList()` call. @@ -856,7 +857,7 @@ export const PostList = () => ( `sort` defines the *default* sort order ; the list remains sortable by clicking on column headers. -For more details on list sort, see the [Sorting The List](./ListTutorial.md#sorting-the-list) section below. +For more details on list sort, see the [Sorting The List](./ListTutorial.md#sorting-the-list) section below. ## `storeKey` @@ -960,7 +961,7 @@ Here is an example: {% raw %} ```jsx const PostList = () => ( -