diff --git a/docs/Buttons.md b/docs/Buttons.md index e847274f67f..3108ff23478 100644 --- a/docs/Buttons.md +++ b/docs/Buttons.md @@ -154,16 +154,99 @@ The following buttons are designed to be used in List views. Exports the current list, with filter applied, but without pagination. It relies on [the `exporter` function](./List.md#exporter) passed to the `` component, via the `ListContext`. It's disabled for empty lists. +By default, the `` is included in the List actions. + +```jsx +import { CreateButton, ExportButton, TopToolbar } from 'react-admin'; + +const PostListActions = ({ basePath }) => ( + + + + + +); + +export const PostList = (props) => ( + } {...props}> + ... + +); +``` + +![Export button](./img/export-button.png) + | Prop | Required | Type | Default | Description | | ------------ | -------- | --------------- | ------------------ | ----------------------------------- | | `maxResults` | Optional | `number` | 1000 | Maximum number of records to export | | `label` | Optional | `string` | 'ra.action.export' | label or translation message to use | -| `icon` | Optional | `React.element` | - | iconElement, e.g. `` | +| `icon` | Optional | `React.element` | `` | iconElement, e.g. `` | | `exporter` | Optional | `function` | - | Override the List exporter function | +### `` + +Same as ``, except it only exports the selected rows instead of the entire list. To be used inside [the `` prop](./List.md#bulkactionbuttons). + +```jsx +import * as React from 'react'; +import { Fragment } from 'react'; +import { BulkDeleteButton, BulkExportButton } from 'react-admin'; + +const PostBulkActionButtons = ({ basePath }) => ( + + + + +); + +export const PostList = (props) => ( + }> + ... + +); +``` + +![Bulk Export button](./img/bulk-export-button.png) + +| Prop | Required | Type | Default | Description | +| ------------ | -------- | --------------- | ------------------ | ----------------------------------- | +| `label` | Optional | `string` | 'ra.action.export' | label or translation message to use | +| `icon` | Optional | `React.element` | `` | iconElement, e.g. `` | +| `exporter` | Optional | `function` | - | Override the List exporter function | ### `` -### `` + +Deletes the selected rows. To be used inside [the `` prop](./List.md#bulkactionbuttons) (where it's enabled by default). + +```jsx +import * as React from 'react'; +import { Fragment } from 'react'; +import { BulkDeleteButton, BulkExportButton } from 'react-admin'; + +const PostBulkActionButtons = ({ basePath }) => ( + + + + +); + +export const PostList = (props) => ( + }> + ... + +); +``` + +![Bulk Delete button](./img/bulk-delete-button.png) + +| Prop | Required | Type | Default | Description | +| ------------ | -------- | --------------- | ------------------ | ----------------------------------- | +| `label` | Optional | `string` | 'ra.action.delete' | label or translation message to use | +| `icon` | Optional | `React.element` | `` | iconElement, e.g. `` | +| `exporter` | Optional | `function` | - | Override the List exporter function | +| `undoable` | Optional | `boolean` | true | Allow users to cancel the deletion | + +### `` ### `` ## Record Buttons diff --git a/docs/img/bulk-delete-button.png b/docs/img/bulk-delete-button.png new file mode 100644 index 00000000000..aa01e5853fe Binary files /dev/null and b/docs/img/bulk-delete-button.png differ diff --git a/docs/img/bulk-export-button.png b/docs/img/bulk-export-button.png new file mode 100644 index 00000000000..eecbf3f76b6 Binary files /dev/null and b/docs/img/bulk-export-button.png differ diff --git a/docs/img/create-button-fab.png b/docs/img/create-button-fab.png index 5bb45fe4126..d5c32190b2b 100644 Binary files a/docs/img/create-button-fab.png and b/docs/img/create-button-fab.png differ diff --git a/docs/img/export-button.png b/docs/img/export-button.png new file mode 100644 index 00000000000..6d960822505 Binary files /dev/null and b/docs/img/export-button.png differ diff --git a/packages/ra-core/src/controller/useListContext.ts b/packages/ra-core/src/controller/useListContext.ts index 4e7b8601ecc..9c951c577e9 100644 --- a/packages/ra-core/src/controller/useListContext.ts +++ b/packages/ra-core/src/controller/useListContext.ts @@ -109,6 +109,65 @@ const useListContext = ( ); }; +/** + * Extract only the list controller props + * + * @param {Object} props Props passed to the useListContext hook + * + * @returns {ListControllerProps} List controller props + */ +const extractListContextProps = ({ + basePath, + currentSort, + data, + defaultTitle, + displayedFilters, + filterValues, + hasCreate, + hideFilter, + ids, + loaded, + loading, + onSelect, + onToggleItem, + onUnselectItems, + page, + perPage, + resource, + selectedIds, + setFilters, + setPage, + setPerPage, + setSort, + showFilter, + total, +}) => ({ + basePath, + currentSort, + data, + defaultTitle, + displayedFilters, + filterValues, + hasCreate, + hideFilter, + ids, + loaded, + loading, + onSelect, + onToggleItem, + onUnselectItems, + page, + perPage, + resource, + selectedIds, + setFilters, + setPage, + setPerPage, + setSort, + showFilter, + total, +}); + export default useListContext; /** diff --git a/packages/ra-ui-materialui/src/button/BulkDeleteButton.tsx b/packages/ra-ui-materialui/src/button/BulkDeleteButton.tsx index 4317a69b443..9708cadcb8b 100644 --- a/packages/ra-ui-materialui/src/button/BulkDeleteButton.tsx +++ b/packages/ra-ui-materialui/src/button/BulkDeleteButton.tsx @@ -8,6 +8,29 @@ import BulkDeleteWithUndoButton, { BulkDeleteWithUndoButtonProps, } from './BulkDeleteWithUndoButton'; +/** + * Deletes the selected rows. + * + * To be used inside the prop (where it's enabled by default). + * + * @example // basic usage + * import * as React from 'react'; + * import { Fragment } from 'react'; + * import { BulkDeleteButton, BulkExportButton } from 'react-admin'; + * + * const PostBulkActionButtons = ({ basePath }) => ( + * + * + * + * + * ); + * + * export const PostList = (props) => ( + * }> + * ... + * + * ); + */ const BulkDeleteButton: FC = ({ undoable, ...props }) => undoable ? ( diff --git a/packages/ra-ui-materialui/src/button/BulkDeleteWithUndoButton.tsx b/packages/ra-ui-materialui/src/button/BulkDeleteWithUndoButton.tsx index f5d28ee8b41..df3a68a2137 100644 --- a/packages/ra-ui-materialui/src/button/BulkDeleteWithUndoButton.tsx +++ b/packages/ra-ui-materialui/src/button/BulkDeleteWithUndoButton.tsx @@ -11,6 +11,7 @@ import { useUnselectAll, CRUD_DELETE_MANY, useResourceContext, + useListContext, } from 'ra-core'; import Button, { ButtonProps } from './Button'; @@ -39,9 +40,9 @@ const BulkDeleteWithUndoButton: FC = props => { icon, label, onClick, - selectedIds, ...rest } = props; + const { selectedIds } = useListContext(props); const classes = useStyles(props); const notify = useNotify(); const unselectAll = useUnselectAll(); diff --git a/packages/ra-ui-materialui/src/button/BulkExportButton.tsx b/packages/ra-ui-materialui/src/button/BulkExportButton.tsx index bf09101352b..af73e405a54 100644 --- a/packages/ra-ui-materialui/src/button/BulkExportButton.tsx +++ b/packages/ra-ui-materialui/src/button/BulkExportButton.tsx @@ -13,6 +13,29 @@ import { import Button, { ButtonProps } from './Button'; +/** + * Export the selected rows + * + * To be used inside the prop. + * + * @example // basic usage + * import * as React from 'react'; + * import { Fragment } from 'react'; + * import { BulkDeleteButton, BulkExportButton } from 'react-admin'; + * + * const PostBulkActionButtons = ({ basePath }) => ( + * + * + * + * + * ); + * + * export const PostList = (props) => ( + * }> + * ... + * + * ); + */ const BulkExportButton: FunctionComponent = props => { const { onClick, diff --git a/packages/ra-ui-materialui/src/list/BulkActionsToolbar.tsx b/packages/ra-ui-materialui/src/list/BulkActionsToolbar.tsx index 3b007009dda..72c22831d72 100644 --- a/packages/ra-ui-materialui/src/list/BulkActionsToolbar.tsx +++ b/packages/ra-ui-materialui/src/list/BulkActionsToolbar.tsx @@ -33,6 +33,9 @@ const useStyles = makeStyles( 'height' )}, ${theme.transitions.create('min-height')}`, }, + topToolbar: { + paddingTop: theme.spacing(2), + }, buttons: {}, collapsed: { minHeight: 0, @@ -93,7 +96,7 @@ const BulkActionsToolbar: FC = props => { })} - + {Children.map(children, child => isValidElement(child) ? cloneElement(child, { diff --git a/packages/ra-ui-materialui/src/list/filter/FilterButton.tsx b/packages/ra-ui-materialui/src/list/filter/FilterButton.tsx index 7931a9fb2b8..203d18fde4f 100644 --- a/packages/ra-ui-materialui/src/list/filter/FilterButton.tsx +++ b/packages/ra-ui-materialui/src/list/filter/FilterButton.tsx @@ -12,6 +12,7 @@ import { makeStyles } from '@material-ui/core/styles'; import ContentFilter from '@material-ui/icons/FilterList'; import classnames from 'classnames'; import lodashGet from 'lodash/get'; +import { useListContext, useResourceContext } from 'ra-core'; import { FilterButtonMenuItem } from './FilterButtonMenuItem'; import Button from '../../button/Button'; @@ -25,16 +26,11 @@ const useStyles = makeStyles( ); const FilterButton = (props: FilterButtonProps): JSX.Element => { - const { - filters, - displayedFilters = {}, - filterValues, - showFilter, - classes: classesOverride, - className, - resource, - ...rest - } = props; + const { filters, classes: classesOverride, className, ...rest } = props; + const resource = useResourceContext(props); + const { displayedFilters = {}, filterValues, showFilter } = useListContext( + props + ); const [open, setOpen] = useState(false); const anchorEl = useRef(); const classes = useStyles(props);