From 9dbb674cd07f9168c088cbc04ff2771d416fb5d8 Mon Sep 17 00:00:00 2001 From: Kmaschta <kevin@marmelab.com> Date: Tue, 10 Dec 2019 10:56:23 +0100 Subject: [PATCH 1/4] Make pagination more extendable --- .../ra-ui-materialui/src/list/Pagination.js | 16 ++++++++--- .../src/list/PaginationActions.js | 27 ++++++++++++++----- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/packages/ra-ui-materialui/src/list/Pagination.js b/packages/ra-ui-materialui/src/list/Pagination.js index 8c107e735b9..d19bc2a32dc 100644 --- a/packages/ra-ui-materialui/src/list/Pagination.js +++ b/packages/ra-ui-materialui/src/list/Pagination.js @@ -3,8 +3,8 @@ import PropTypes from 'prop-types'; import { TablePagination, Toolbar, useMediaQuery } from '@material-ui/core'; import { useTranslate, sanitizeListRestProps } from 'ra-core'; -import PaginationActions from './PaginationActions'; -import PaginationLimit from './PaginationLimit'; +import DefaultPaginationActions from './PaginationActions'; +import DefaultPaginationLimit from './PaginationLimit'; const emptyArray = []; @@ -16,6 +16,8 @@ const Pagination = ({ total, setPage, setPerPage, + ActionsComponent, + limit, ...rest }) => { useEffect(() => { @@ -64,8 +66,9 @@ const Pagination = ({ ); if (total === 0) { - return loading ? <Toolbar variant="dense" /> : <PaginationLimit />; + return loading ? <Toolbar variant="dense" /> : limit; } + if (isSmall) { return ( <TablePagination @@ -80,6 +83,7 @@ const Pagination = ({ /> ); } + return ( <TablePagination count={total} @@ -87,7 +91,7 @@ const Pagination = ({ page={page - 1} onChangePage={handlePageChange} onChangeRowsPerPage={handlePerPageChange} - ActionsComponent={PaginationActions} + ActionsComponent={ActionsComponent} component="span" labelRowsPerPage={translate('ra.navigation.page_rows_per_page')} labelDisplayedRows={labelDisplayedRows} @@ -106,10 +110,14 @@ Pagination.propTypes = { setPage: PropTypes.func, setPerPage: PropTypes.func, total: PropTypes.number, + ActionsComponent: PropTypes.node, + limit: PropTypes.element, }; Pagination.defaultProps = { rowsPerPageOptions: [5, 10, 25], + ActionsComponent: DefaultPaginationActions, + limit: <DefaultPaginationLimit />, }; export default React.memo(Pagination); diff --git a/packages/ra-ui-materialui/src/list/PaginationActions.js b/packages/ra-ui-materialui/src/list/PaginationActions.js index a89a44c8288..03fa90b15f4 100644 --- a/packages/ra-ui-materialui/src/list/PaginationActions.js +++ b/packages/ra-ui-materialui/src/list/PaginationActions.js @@ -24,6 +24,8 @@ function PaginationActions({ rowsPerPage, count, onChangePage, + color, + size, }) { const classes = useStyles({ classes: classesOverride }); const translate = useTranslate(); @@ -102,12 +104,12 @@ function PaginationActions({ </span> ) : ( <Button + size={size} className="page-number" - color={pageNum === page + 1 ? 'default' : 'primary'} + color={pageNum === page + 1 ? 'default' : color} key={pageNum} data-page={pageNum - 1} onClick={gotoPage} - size="small" > {pageNum} </Button> @@ -116,16 +118,20 @@ function PaginationActions({ }; const nbPages = getNbPages(); - if (nbPages === 1) return <div className={classes.actions} />; + + if (nbPages === 1) { + return <div className={classes.actions} />; + } + return ( <div className={classes.actions}> {page > 0 && ( <Button - color="primary" + color={color} + size={size} key="prev" onClick={prevPage} className="previous-page" - size="small" > <ChevronLeft /> {translate('ra.navigation.prev')} @@ -134,11 +140,11 @@ function PaginationActions({ {renderPageNums()} {page !== nbPages - 1 && ( <Button - color="primary" + color={color} + size={size} key="next" onClick={nextPage} className="next-page" - size="small" > {translate('ra.navigation.next')} <ChevronRight /> @@ -162,6 +168,13 @@ PaginationActions.propTypes = { onChangePage: PropTypes.func.isRequired, page: PropTypes.number.isRequired, rowsPerPage: PropTypes.number.isRequired, + color: PropTypes.oneOf(['primary', 'secondary']), + size: PropTypes.oneOf(['small', 'medium', 'large']), +}; + +PaginationActions.defaultProps = { + color: 'primary', + size: 'small', }; export default React.memo(PaginationActions); From 6bdcb006d698e5734d27a59c7445be1b190c7258 Mon Sep 17 00:00:00 2001 From: Kmaschta <kevin@marmelab.com> Date: Tue, 10 Dec 2019 14:35:04 +0100 Subject: [PATCH 2/4] Document pagination --- docs/List.md | 145 +++++++++++++++++++++++++++++---------------------- 1 file changed, 83 insertions(+), 62 deletions(-) diff --git a/docs/List.md b/docs/List.md index f24ed33d5c4..ab84201726c 100644 --- a/docs/List.md +++ b/docs/List.md @@ -573,68 +573,6 @@ export const PostList = (props) => ( const filterSentToDataProvider = { ...filterDefaultValues, ...filterChosenByUser, ...filters }; ``` -### Pagination - -Here are all the props required by the <Pagination> 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: `<List pagination={<Pagination />}>`. - -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 => <Pagination rowsPerPageOptions={[10, 25, 50, 100]} {...props} />; - -export const PostList = (props) => ( - <List {...props} pagination={<PostPagination />}> - ... - </List> -); -``` - -**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 "<previous - next>" 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 && - <Toolbar> - {page > 1 && - <Button color="primary" key="prev" icon={ChevronLeft} onClick={() => setPage(page - 1)}> - Prev - </Button> - } - {page !== nbPages && - <Button color="primary" key="next" icon={ChevronRight} onClick={() => setPage(page + 1)} labelPosition="before"> - Next - </Button> - } - </Toolbar> - ); -} - -export const PostList = (props) => ( - <List {...props} pagination={<PostPagination />}> - ... - </List> -); -``` - ### Aside component 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: @@ -1388,3 +1326,86 @@ export const UserList = ({ permissions, ...props }) => { {% endraw %} **Tip**: Note how the `permissions` prop is passed down to the custom `filters` component. + +## Pagination + +Here are all the props required by the <Pagination> 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. +* `ActionsComponent`: A composant that displays the pagination buttons (default: `PaginationActions`) +* `limit`: An element that is displayed if there is no data to shpw (default: `<PaginationLimit>`) + +You don't need to fill these props when you pass the `Pagination` component to the `List` component through the `pagination` prop: `<List pagination={<Pagination />}>`. + +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 => <Pagination rowsPerPageOptions={[10, 25, 50, 100]} {...props} />; + +export const PostList = (props) => ( + <List {...props} pagination={<PostPagination />}> + ... + </List> +); +``` + +**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 "<previous - next>" 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 && + <Toolbar> + {page > 1 && + <Button color="primary" key="prev" icon={ChevronLeft} onClick={() => setPage(page - 1)}> + Prev + </Button> + } + {page !== nbPages && + <Button color="primary" key="next" icon={ChevronRight} onClick={() => setPage(page + 1)} labelPosition="before"> + Next + </Button> + } + </Toolbar> + ); +} + +export const PostList = (props) => ( + <List {...props} pagination={<PostPagination />}> + ... + </List> +); +``` + +But if you just want to change the color property of the pagination button, you can extend the existing components: + +```jsx +import { + List, + Pagination as RaPagination, + PaginationActions as RaPaginationActions, +} from 'react-admin'; + +export const PaginationActions = props => <RaPaginationActions {...props} color="secondary" />; + +export const Pagination = props => <RaPagination {...props} ActionsComponent={PaginationActions} />; + +export const UserList = props => ( + <List {...props} pagination={<Pagination />}> + </List> +); +``` From 0af09488e3ae9719482faaf1511bfb11b0ed15ab Mon Sep 17 00:00:00 2001 From: Kmaschta <kevin@marmelab.com> Date: Tue, 10 Dec 2019 15:00:26 +0100 Subject: [PATCH 3/4] Code Review --- docs/List.md | 2 +- packages/ra-ui-materialui/src/list/Pagination.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/List.md b/docs/List.md index ab84201726c..bca83339962 100644 --- a/docs/List.md +++ b/docs/List.md @@ -1335,7 +1335,7 @@ Here are all the props required by the <Pagination> component: * `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. -* `ActionsComponent`: A composant that displays the pagination buttons (default: `PaginationActions`) +* `actions`: A component that displays the pagination buttons (default: `PaginationActions`) * `limit`: An element that is displayed if there is no data to shpw (default: `<PaginationLimit>`) You don't need to fill these props when you pass the `Pagination` component to the `List` component through the `pagination` prop: `<List pagination={<Pagination />}>`. diff --git a/packages/ra-ui-materialui/src/list/Pagination.js b/packages/ra-ui-materialui/src/list/Pagination.js index d19bc2a32dc..92cad22e594 100644 --- a/packages/ra-ui-materialui/src/list/Pagination.js +++ b/packages/ra-ui-materialui/src/list/Pagination.js @@ -16,7 +16,7 @@ const Pagination = ({ total, setPage, setPerPage, - ActionsComponent, + actions, limit, ...rest }) => { @@ -91,7 +91,7 @@ const Pagination = ({ page={page - 1} onChangePage={handlePageChange} onChangeRowsPerPage={handlePerPageChange} - ActionsComponent={ActionsComponent} + ActionsComponent={actions} component="span" labelRowsPerPage={translate('ra.navigation.page_rows_per_page')} labelDisplayedRows={labelDisplayedRows} @@ -110,13 +110,13 @@ Pagination.propTypes = { setPage: PropTypes.func, setPerPage: PropTypes.func, total: PropTypes.number, - ActionsComponent: PropTypes.node, + actions: PropTypes.node, limit: PropTypes.element, }; Pagination.defaultProps = { rowsPerPageOptions: [5, 10, 25], - ActionsComponent: DefaultPaginationActions, + actions: DefaultPaginationActions, limit: <DefaultPaginationLimit />, }; From e9937eb79b3f3d89b79c076ed5a7afae2480d462 Mon Sep 17 00:00:00 2001 From: Francois Zaninotto <francois@marmelab.com> Date: Wed, 11 Dec 2019 08:56:12 +0100 Subject: [PATCH 4/4] fix typo --- docs/List.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/List.md b/docs/List.md index bca83339962..c7b083103b7 100644 --- a/docs/List.md +++ b/docs/List.md @@ -1336,7 +1336,7 @@ Here are all the props required by the <Pagination> component: * `setPage`: `function(page: number) => void`. A function that set the current page number. * `total`: The total number of records. * `actions`: A component that displays the pagination buttons (default: `PaginationActions`) -* `limit`: An element that is displayed if there is no data to shpw (default: `<PaginationLimit>`) +* `limit`: An element that is displayed if there is no data to show (default: `<PaginationLimit>`) You don't need to fill these props when you pass the `Pagination` component to the `List` component through the `pagination` prop: `<List pagination={<Pagination />}>`.