From 529cfdb45657b9307f3f5b17ece05519c8b6a7d9 Mon Sep 17 00:00:00 2001 From: Matheus Wichman Date: Wed, 4 Dec 2019 15:39:56 -0300 Subject: [PATCH] Update docs --- docs/List.md | 524 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 349 insertions(+), 175 deletions(-) diff --git a/docs/List.md b/docs/List.md index 3e9964cfe61..08cd538b66d 100644 --- a/docs/List.md +++ b/docs/List.md @@ -1,6 +1,6 @@ --- layout: default -title: "The List View" +title: 'The List View' --- # The List View @@ -17,18 +17,18 @@ The `` component renders the list layout (title, buttons, filters, paginat Here are all the props accepted by the `` component: -* [`title`](#page-title) -* [`actions`](#actions) -* [`exporter`](#exporter) -* [`bulkActionButtons`](#bulk-action-buttons) -* [`filters`](#filters) (a React element used to display the filter form) -* [`perPage`](#records-per-page) -* [`sort`](#default-sort-field) -* [`filter`](#permanent-filter) (the permanent filter used in the REST request) -* [`filterDefaultValues`](#filter-default-values) (the default values for `alwaysOn` filters) -* [`pagination`](#pagination) -* [`aside`](#aside-component) -* [`emptyState`](#empty-state) +- [`title`](#page-title) +- [`actions`](#actions) +- [`exporter`](#exporter) +- [`bulkActionButtons`](#bulk-action-buttons) +- [`filters`](#filters) (a React element used to display the filter form) +- [`perPage`](#records-per-page) +- [`sort`](#default-sort-field) +- [`filter`](#permanent-filter) (the permanent filter used in the REST request) +- [`filterDefaultValues`](#filter-default-values) (the default values for `alwaysOn` filters) +- [`pagination`](#pagination) +- [`aside`](#aside-component) +- [`empty`](#empty-page) Here is the minimal code necessary to display a list of posts: @@ -41,7 +41,9 @@ import jsonServerProvider from 'ra-data-json-server'; import { PostList } from './posts'; const App = () => ( - + ); @@ -52,7 +54,7 @@ export default App; import React from 'react'; import { List, Datagrid, TextField } from 'react-admin'; -export const PostList = (props) => ( +export const PostList = props => ( @@ -73,7 +75,7 @@ The default title for a list view is "[resource] list" (e.g. "Posts list"). Use ```jsx // in src/posts.js -export const PostList = (props) => ( +export const PostList = props => ( ... @@ -102,16 +104,17 @@ const PostActions = ({ resource, selectedIds, showFilter, - total + total, }) => ( - {filters && React.cloneElement(filters, { - resource, - showFilter, - displayedFilters, - filterValues, - context: 'button', - })} + {filters && + React.cloneElement(filters, { + resource, + showFilter, + displayedFilters, + filterValues, + context: 'button', + })} {/* Add your custom actions */} - + ); -export const PostList = (props) => ( +export const PostList = props => ( }> ... @@ -136,7 +141,10 @@ You can also use such a custom `ListActions` prop to omit or reorder buttons bas ```jsx export const PostList = ({ permissions, ...props }) => ( - }> + } + > ... ); @@ -185,7 +193,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 the `GET_MANY` verb, 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: @@ -198,14 +206,18 @@ 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, - post_title: posts[record.post_id].title, + ...record, + post_title: posts[record.post_id].title, })); - jsonExport(data, { - headers: ['id', 'post_id', 'post_title', 'body'], - }, (err, csv) => {; - downloadCSV(csv, 'comments'); - }); + jsonExport( + data, + { + headers: ['id', 'post_id', 'post_title', 'body'], + }, + (err, csv) => { + downloadCSV(csv, 'comments'); + } + ); }); }; @@ -213,7 +225,7 @@ const CommentList = props => ( ... -) +); ``` **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. @@ -242,7 +254,7 @@ const PostBulkActionButtons = props => ( ); -export const PostList = (props) => ( +export const PostList = props => ( }> ... @@ -257,10 +269,10 @@ export const PostList = (props) => ( Bulk action button components receive several props allowing them to perform their job: -* `resource`: the currently displayed resource (eg `posts`, `comments`, etc.) -* `basePath`: the current router base path for the resource (eg `/posts`, `/comments`, etc.) -* `filterValues`: the filter values. This can be useful if you want to apply your action on all items matching the filter. -* `selectedIds`: the identifiers of the currently selected items. +- `resource`: the currently displayed resource (eg `posts`, `comments`, etc.) +- `basePath`: the current router base path for the resource (eg `/posts`, `/comments`, etc.) +- `filterValues`: the filter values. This can be useful if you want to apply your action on all items matching the filter. +- `selectedIds`: the identifiers of the currently selected items. Here is an example leveraging the `useUpdateMany` hook, which sets the `views` property of all posts to `0`: @@ -360,7 +372,7 @@ const ResetViewsButton = ({ selectedIds }) => { /> ); -} +}; export default ResetViewsButton; ``` @@ -412,14 +424,14 @@ const ResetViewsButton = ({ selectedIds }) => { You can add a filter component to the list using the `filters` prop: ```jsx -const PostFilter = (props) => ( +const PostFilter = props => ( ); -export const PostList = (props) => ( +export const PostList = props => ( }> ... @@ -430,8 +442,8 @@ The filter component must be a `` with `` children. **Tip**: `` is a special component, which renders in two ways: -* as a filter button (to add new filters) -* as a filter form (to enter filter values) +- as a filter button (to add new filters) +- as a filter form (to enter filter values) It does so by inspecting its `context` prop. @@ -439,8 +451,8 @@ It does so by inspecting its `context` prop. The `Filter` component accepts the usual `className` prop but you can override many class names injected to the inner components by React-admin thanks to the `classes` property (as most Material UI components, see their [documentation about it](https://material-ui.com/customization/components/#overriding-styles-with-classes)). This property accepts the following keys: -* `form`: applied to the root element when rendering as a form. -* `button`: applied to the root element when rendering as a button. +- `form`: applied to the root element when rendering as a form. +- `button`: applied to the root element when rendering as a button. Children of the `` form are regular inputs. `` hides them all by default, except those that have the `alwaysOn` prop. @@ -452,7 +464,7 @@ By default, the list paginates results by groups of 10. You can override this se ```jsx // in src/posts.js -export const PostList = (props) => ( +export const PostList = props => ( ... @@ -464,29 +476,32 @@ export const PostList = (props) => ( Pass an object literal as the `sort` prop to determine the default `field` and `order` used for sorting: {% raw %} + ```jsx // in src/posts.js -export const PostList = (props) => ( +export const PostList = props => ( ... ); ``` + {% endraw %} -`sort` defines the *default* sort order ; the list remains sortable by clicking on column headers. +`sort` defines the _default_ sort order ; the list remains sortable by clicking on column headers. ### Disabling Sorting It is possible to disable sorting for a specific field by passing a `sortable` property set to `false`: {% raw %} + ```jsx // in src/posts.js import React from 'react'; import { List, Datagrid, TextField } from 'react-admin'; -export const PostList = (props) => ( +export const PostList = props => ( @@ -496,6 +511,7 @@ export const PostList = (props) => ( ); ``` + {% endraw %} ### Specify Sort Field @@ -503,27 +519,36 @@ export const PostList = (props) => ( By default, a column is sorted by the `source` property. To define another attribute to sort by, set it via the `sortBy` property: {% raw %} + ```jsx // in src/posts.js import React from 'react'; import { List, Datagrid, TextField } from 'react-admin'; -export const PostList = (props) => ( +export const PostList = props => ( - + `${record.author.first_name} ${record.author.last_name}`} + render={record => + `${record.author.first_name} ${record.author.last_name}` + } /> ); ``` + {% endraw %} ### Permanent Filter @@ -531,17 +556,19 @@ export const PostList = (props) => ( You can choose to always filter the list, without letting the user disable this filter - for instance to display only published posts. Write the filter to be passed to the REST client in the `filter` props: {% raw %} + ```jsx // in src/posts.js -export const PostList = (props) => ( +export const PostList = props => ( ... ); ``` + {% endraw %} -The actual filter parameter sent to the REST client is the result of the combination of the *user* filters (the ones set through the `filters` component form), and the *permanent* filter. The user cannot override the permanent filters set by way of `filter`. +The actual filter parameter sent to the REST client is the result of the combination of the _user_ filters (the ones set through the `filters` component form), and the _permanent_ filter. The user cannot override the permanent filters set by way of `filter`. ### Filter Default Values @@ -550,9 +577,10 @@ To set default values to filters, you can either pass an object literal as the ` There is one exception: inputs with `alwaysOn` don't accept `defaultValue`. You have to use the `filterDefaultValues` for those. {% raw %} + ```jsx // in src/posts.js -const PostFilter = (props) => ( +const PostFilter = props => ( @@ -560,18 +588,103 @@ const PostFilter = (props) => ( ); -export const PostList = (props) => ( - } filterDefaultValues={{ is_published: true }}> +export const PostList = props => ( + } + filterDefaultValues={{ is_published: true }} + > ... ); ``` + {% endraw %} **Tip**: The `filter` and `filterDefaultValues` props have one key difference: the `filterDefaultValues` can be overridden by the user, while the `filter` values are always sent to the data provider. Or, to put it otherwise: ```js -const filterSentToDataProvider = { ...filterDefaultValues, ...filterChosenByUser, ...filters }; +const filterSentToDataProvider = { + ...filterDefaultValues, + ...filterChosenByUser, + ...filters, +}; +``` + +### Pagination + +Here are all the props required by the component: + +- `page`: The current page number (integer). First page is `1`. +- `perPage`: The number of records per page. +- `setPage`: `function(page: number) => void`. A function that set the current page number. +- `total`: The total number of records. + +You don't need to fill these props when you pass the `Pagination` component to the `List` component through the `pagination` prop: `}>`. + +You can also replace the default pagination element by your own. For instance, you can modify the default pagination by adjusting the "rows per page" selector. + +```jsx +// in src/MyPagination.js +import { Pagination, List } from 'react-admin'; + +const PostPagination = props => ( + +); + +export const PostList = props => ( + }> + ... + +); +``` + +**Tip**: Pass an empty array to `rowsPerPageOptions` to disable the rows per page selection. + +Alternately, if you want to replace the default pagination by a "" pagination, create a pagination component like the following: + +```jsx +import Button from '@material-ui/core/Button'; +import ChevronLeft from '@material-ui/icons/ChevronLeft'; +import ChevronRight from '@material-ui/icons/ChevronRight'; +import Toolbar from '@material-ui/core/Toolbar'; + +const PostPagination = ({ page, perPage, total, setPage }) => { + const nbPages = Math.ceil(total / perPage) || 1; + return ( + nbPages > 1 && ( + + {page > 1 && ( + + )} + {page !== nbPages && ( + + )} + + ) + ); +}; + +export const PostList = props => ( + }> + ... + +); ``` ### Aside component @@ -579,6 +692,7 @@ const filterSentToDataProvider = { ...filterDefaultValues, ...filterChosenByUser You may want to display additional information on the side of the list. Use the `aside` prop for that, passing the component of your choice: {% raw %} + ```jsx const Aside = () => (
@@ -595,48 +709,55 @@ const PostList = props => ( ); ``` + {% endraw %} The `aside` component receives the same props as the `List` child component, including the following: -* `basePath`, -* `currentSort`, -* `data`, -* `defaultTitle`, -* `filterValues`, -* `ids`, -* `page`, -* `perPage`, -* `resource`, -* `selectedIds`, -* `total`, -* `version`, +- `basePath`, +- `currentSort`, +- `data`, +- `defaultTitle`, +- `filterValues`, +- `ids`, +- `page`, +- `perPage`, +- `resource`, +- `selectedIds`, +- `total`, +- `version`, That means you can display additional details of the current list in the aside component: {% raw %} + ```jsx const Aside = ({ data, ids }) => (
Posts stats - Total views: {ids.map(id => data[id]).reduce((sum, post) => sum + post.views, 0)} + Total views:{' '} + {ids.map(id => data[id]).reduce((sum, post) => sum + post.views, 0)}
); ``` + {% endraw %} -### Empty state +### Empty page + +When there is no result, and there is no active filter, and the resource has a create page, react-admin displays a special page inviting the user to create the first record. -When there is no result, and there is no active filter, and the resource has a create page then a special page inviting the user to create the first record is displayed. Use the `emptyState` prop to modify that page, passing your custom component: +You can use the `empty` prop to replace that page by a custom component: {% raw %} + ```jsx import Button from '@material-ui/core/Button'; import { CreateButton, List } from 'react-admin'; -const EmptyState = ({ basePath }) => ( +const Empty = ({ basePath, resource }) => (

No products available

Create one or import from a file
@@ -646,12 +767,26 @@ const EmptyState = ({ basePath }) => ( ); const ProductList = props => ( - } {...props}> + } {...props}> ... ); +``` -The `emptyState` component receives the same props as the `aside` prop. Read the [section above](#aside-component) to check them. +The `empty` component receives the same props as the `List` child component, including the following: + +- `basePath`, +- `currentSort`, +- `data`, +- `defaultTitle`, +- `filterValues`, +- `ids`, +- `page`, +- `perPage`, +- `resource`, +- `selectedIds`, +- `total`, +- `version`, ### Component @@ -673,7 +808,7 @@ const PostList = props => ( ... ); -``` +```` The default value for the `component` prop is `Card`. @@ -681,16 +816,17 @@ The default value for the `component` prop is `Card`. The `List` component accepts the usual `className` prop but you can override many class names injected to the inner components by React-admin thanks to the `classes` property (as most Material UI components, see their [documentation about it](https://material-ui.com/customization/components/#overriding-styles-with-classes)). This property accepts the following keys: -* `root`: alternative to using `className`. Applied to the root element. -* `header`: applied to the page header -* `actions`: applied to the actions container -* `noResults`: applied to the component shown when there is no result +- `root`: alternative to using `className`. Applied to the root element. +- `header`: applied to the page header +- `actions`: applied to the actions container +- `noResults`: applied to the component shown when there is no result Here is an example of how you can override some of these classes: You can customize the list styles by passing a `classes` object as prop, through `useStyles()`. Here is an example: {% raw %} + ```jsx import { makeStyles } from '@material-ui/core'; @@ -713,6 +849,7 @@ const PostList = props => { export PostList; ``` + {% endraw %} ## The `` component @@ -726,7 +863,9 @@ import { Admin, Resource, ListGuesser } from 'react-admin'; import jsonServerProvider from 'ra-data-json-server'; const App = () => ( - + ); @@ -746,11 +885,11 @@ The `Datagrid` component renders a list of records as a table. It is usually use Here are all the props accepted by the component: -* [`body`](#body-element) -* [`rowStyle`](#row-style-function) -* [`rowClick`](#rowclick) -* [`expand`](#expand) -* [`isRowSelectable`](#isrowselectable) +- [`body`](#body-element) +- [`rowStyle`](#row-style-function) +- [`rowClick`](#rowclick) +- [`expand`](#expand) +- [`isRowSelectable`](#isrowselectable) It renders as many columns as it receives `` children. @@ -759,7 +898,7 @@ It renders as many columns as it receives `` children. import React from 'react'; import { List, Datagrid, TextField, EditButton } from 'react-admin'; -export const PostList = (props) => ( +export const PostList = props => ( @@ -771,7 +910,7 @@ export const PostList = (props) => ( ); ``` -The `Datagrid` is an *iterator* component: it receives an array of ids, and a data store, and is supposed to iterate over the ids to display each record. Another example of iterator component is [``](#the-singlefieldlist-component). +The `Datagrid` is an _iterator_ component: it receives an array of ids, and a data store, and is supposed to iterate over the ids to display each record. Another example of iterator component is [``](#the-singlefieldlist-component). ### Body element @@ -787,14 +926,21 @@ import TableCell from '@material-ui/core/TableCell'; import TableRow from '@material-ui/core/TableRow'; import Checkbox from '@material-ui/core/Checkbox'; -const MyDatagridRow = ({ record, resource, id, onToggleItem, children, selected, basePath }) => ( +const MyDatagridRow = ({ + record, + resource, + id, + onToggleItem, + children, + selected, + basePath, +}) => ( {/* first column: selection checkbox */} - {record.selectable && onToggleItem(id)} - />} + {record.selectable && ( + onToggleItem(id)} /> + )} {/* data columns based on children */} {React.Children.map(children, field => ( @@ -809,7 +955,9 @@ const MyDatagridRow = ({ record, resource, id, onToggleItem, children, selected, ); -const MyDatagridBody = props => } />; +const MyDatagridBody = props => ( + } /> +); const MyDatagrid = props => } />; const PostList = props => ( @@ -819,7 +967,7 @@ const PostList = props => ( ... -) +); export default PostList; ``` @@ -834,11 +982,9 @@ For instance, this allows to apply a custom background to the entire row if one const postRowStyle = (record, index) => ({ backgroundColor: record.nb_views >= 500 ? '#efe' : 'white', }); -export const PostList = (props) => ( +export const PostList = props => ( - - ... - + ... ); ``` @@ -848,27 +994,26 @@ export const PostList = (props) => ( You can catch clicks on rows to redirect to the show or edit view by setting the `rowClick` prop: ```jsx -export const PostList = (props) => ( +export const PostList = props => ( - - ... - + ... ); ``` `rowClick` accepts the following values: -* "edit" to redirect to the edition vue -* "show" to redirect to the show vue -* "expand" to open the `expand` panel -* "toggleSelection" to trigger the `onToggleItem` function -* a function `(id, basePath, record) => path` to redirect to a custom path +- "edit" to redirect to the edition vue +- "show" to redirect to the show vue +- "expand" to open the `expand` panel +- "toggleSelection" to trigger the `onToggleItem` function +- a function `(id, basePath, record) => path` to redirect to a custom path **Tip**: If you pass a function, it can return `edit`, `show` or a router path. This allows to redirect to either `edit` or `show` after checking a condition on the record. For example: ```js -const postRowClick = (id, basePath, record) => record.editable ? 'edit' : 'show'; +const postRowClick = (id, basePath, record) => + record.editable ? 'edit' : 'show'; ``` **Tip**: If you pass a function, it can also return a promise allowing you to check an external API before returning a path. For example: @@ -876,7 +1021,8 @@ const postRowClick = (id, basePath, record) => record.editable ? 'edit' : 'show' ```js import fetchUserRights from './fetchUserRights'; -const postRowClick = (id, basePath, record) => fetchUserRights().then(({ canEdit }) => canEdit ? 'edit' : 'show'); +const postRowClick = (id, basePath, record) => + fetchUserRights().then(({ canEdit }) => (canEdit ? 'edit' : 'show')); ``` ### `expand` @@ -884,6 +1030,7 @@ const postRowClick = (id, basePath, record) => fetchUserRights().then(({ canEdit To show more data from the resource without adding too many columns, you can show data in an expandable panel below the row on demand, using the `expand` prop. For instance, this code shows the `body` of a post in an expandable panel: {% raw %} + ```jsx const PostPanel = ({ id, record, resource }) => (
@@ -899,22 +1046,21 @@ const PostList = props => ( -) +); ``` ### `isRowSelectable` -You can customize which rows will show a selection checkbox using the `isRowSelectable` prop. It expects a function that will receive the record of each `` and returns a boolean expression. For instance, this code shows a checkbox only for rows with an id greater than 300: +You can customize which rows will show a selection checkbox using the `isRowSelectable` prop. It expects a function that will receive the record of each `` and returns a boolean expression. For instance, this code shows a checkbox only for rows with an id greater than 300: ```jsx export const PostList = props => ( - record.id > 300 }> - ... - + record.id > 300}>... ); ``` + {% endraw %} ![expandable panel](./img/datagrid_expand.gif) @@ -946,7 +1092,7 @@ const PostList = props => ( -) +); ``` The result will be the same as in the previous snippet, except that `` encloses the content inside a material-ui ``. @@ -979,26 +1125,27 @@ const PostList = props => ( -) +); ``` ### CSS API The `Datagrid` component accepts the usual `className` prop but you can override many class names injected to the inner components by React-admin thanks to the `classes` property (as most Material UI components, see their [documentation about it](https://material-ui.com/customization/components/#overriding-styles-with-classes)). This property accepts the following keys: -* `table`: alternative to using `className`. Applied to the root element. -* `tbody`: applied to the tbody -* `headerCell`: applied to each header cell -* `row`: applied to each row -* `rowEven`: applied to each even row -* `rowOdd`: applied to each odd row -* `rowCell`: applied to each row cell +- `table`: alternative to using `className`. Applied to the root element. +- `tbody`: applied to the tbody +- `headerCell`: applied to each header cell +- `row`: applied to each row +- `rowEven`: applied to each even row +- `rowOdd`: applied to each odd row +- `rowCell`: applied to each row cell Here is an example of how you can override some of these classes: You can customize the `` styles by passing a `classes` object as prop, through `useStyles()`. Here is an example: {% raw %} + ```jsx import React from 'react'; import { makeStyles } from '@material-ui/core'; @@ -1022,6 +1169,7 @@ const PostList = props => { export PostList; ``` + {% endraw %} **Tip**: If you want to override the `header` and `cell` styles independently for each column, use the `headerClassName` and `cellClassName` props in `` components. For instance, to hide a certain column on small screens: @@ -1137,12 +1285,14 @@ For mobile devices, a `` is often unusable - there is simply not enoug import React from 'react'; import { List, SimpleList } from 'react-admin'; -export const PostList = (props) => ( +export const PostList = props => ( record.title} secondaryText={record => `${record.views} views`} - tertiaryText={record => new Date(record.published_at).toLocaleDateString()} + tertiaryText={record => + new Date(record.published_at).toLocaleDateString() + } /> ); @@ -1156,9 +1306,16 @@ export const PostList = (props) => ( // in src/posts.js import React from 'react'; import { useMediaQuery } from '@material-ui/core'; -import { List, SimpleList, Datagrid, TextField, ReferenceField, EditButton } from 'react-admin'; +import { + List, + SimpleList, + Datagrid, + TextField, + ReferenceField, + EditButton, +} from 'react-admin'; -export const PostList = (props) => { +export const PostList = props => { const isSmall = useMediaQuery(theme => theme.breakpoints.down('sm')); return ( @@ -1166,16 +1323,16 @@ export const PostList = (props) => { record.title} secondaryText={record => `${record.views} views`} - tertiaryText={record => new Date(record.published_at).toLocaleDateString()} + tertiaryText={record => + new Date(record.published_at).toLocaleDateString() + } /> ) : ( - - ... - + ... )} ); -} +}; ``` **Tip**: The `` items link to the edition page by default. You can set the `linkType` prop to `show` to link to the `` page instead. @@ -1185,12 +1342,14 @@ export const PostList = (props) => { import React from 'react'; import { List, SimpleList } from 'react-admin'; -export const PostList = (props) => ( +export const PostList = props => ( record.title} secondaryText={record => `${record.views} views`} - tertiaryText={record => new Date(record.published_at).toLocaleDateString()} + tertiaryText={record => + new Date(record.published_at).toLocaleDateString() + } linkType="show" /> @@ -1205,11 +1364,7 @@ When you want to display only one property of a list of records, instead of usin ```jsx // Display all the tags for the current post - + @@ -1222,11 +1377,7 @@ When you want to display only one property of a list of records, instead of usin ```jsx // Display all the tags for the current post - + @@ -1237,8 +1388,8 @@ When you want to display only one property of a list of records, instead of usin A `` can delegate to any iterator component - `` is just one example. An iterator component must accept at least two props: -- `ids` is an array of the ids currently displayed in the list -- `data` is an object of all the fetched data for this resource, indexed by id. +- `ids` is an array of the ids currently displayed in the list +- `data` is an object of all the fetched data for this resource, indexed by id. For instance, what if you prefer to show a list of cards rather than a datagrid? @@ -1247,6 +1398,7 @@ For instance, what if you prefer to show a list of cards rather than a datagrid? You'll need to create your own iterator component as follows: {% raw %} + ```jsx // in src/comments.js import React from 'react'; @@ -1256,38 +1408,57 @@ import CardContent from '@material-ui/core/CardContent'; import CardHeader from '@material-ui/core/CardHeader'; import Avatar from '@material-ui/core/Avatar'; import PersonIcon from '@material-ui/core/Avatar'; -import { List, TextField, DateField, ReferenceField, EditButton } from "react-admin"; +import { + List, + TextField, + DateField, + ReferenceField, + EditButton, +} from 'react-admin'; const cardStyle = { width: 300, minHeight: 300, margin: '0.5em', display: 'inline-block', - verticalAlign: 'top' + verticalAlign: 'top', }; const CommentGrid = ({ ids, data, basePath }) => (
- {ids.map(id => - - } - subheader={} - avatar={} />} - /> - - - - - about  - - - - - - - - - )} + {ids.map(id => ( + + } + subheader={ + + } + avatar={} />} + /> + + + + + about  + + + + + + + + + ))}
); CommentGrid.defaultProps = { @@ -1295,12 +1466,13 @@ CommentGrid.defaultProps = { ids: [], }; -export const CommentList = (props) => ( +export const CommentList = props => ( ); ``` + {% endraw %} As you can see, nothing prevents you from using `` components inside your own components... provided you inject the current `record`. Also, notice that components building links require the `basePath` component, which is also injected. @@ -1312,6 +1484,7 @@ You might want to display some fields or filters only to users with specific per Before rendering the `List`, react-admin calls the `authProvider.getPermissions()` method, and passes the result to the component as the `permissions` prop. It's up to your `authProvider` to return whatever you need to check roles and permissions inside your component. {% raw %} + ```jsx const UserFilter = ({ permissions, ...props }) => @@ -1351,6 +1524,7 @@ export const UserList = ({ permissions, ...props }) => { ) } ``` + {% endraw %} **Tip**: Note how the `permissions` prop is passed down to the custom `filters` component.