From 68c7c65e14d1133be50fa6cde06737e5c4d8a4ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Decr=C3=A9?= Date: Wed, 13 Nov 2024 10:16:40 +0100 Subject: [PATCH] refacto(SimpleList): deprecate linkType => rowClick --- docs/SimpleList.md | 21 +-- .../src/list/SimpleList/SimpleList.tsx | 155 ++++++++++++------ 2 files changed, 116 insertions(+), 60 deletions(-) diff --git a/docs/SimpleList.md b/docs/SimpleList.md index 2bf275370cf..a8df09b35a3 100644 --- a/docs/SimpleList.md +++ b/docs/SimpleList.md @@ -28,7 +28,7 @@ export const PostList = () => ( primaryText={record => record.title} secondaryText={record => `${record.views} views`} tertiaryText={record => new Date(record.published_at).toLocaleDateString()} - linkType={record => record.canEdit ? "edit" : "show"} + rowClick={record => record.canEdit ? "edit" : "show"} rowSx={record => ({ backgroundColor: record.nb_views >= 500 ? '#efe' : 'white' })} /> @@ -44,7 +44,7 @@ export const PostList = () => ( | `primaryText` | Optional | mixed | record representation | The primary text to display. | | `secondaryText` | Optional | mixed | | The secondary text to display. | | `tertiaryText` | Optional | mixed | | The tertiary text to display. | -| `linkType` | Optional |mixed | `"edit"` | The target of each item click. | +| `rowClick` | Optional |mixed | `"edit"` | The action to trigger when the user clicks on a row. | | `leftAvatar` | Optional | function | | A function returning an `` component to display before the primary text. | | `leftIcon` | Optional | function | | A function returning an `` component to display before the primary text. | | `rightAvatar` | Optional | function | | A function returning an `` component to display after the primary text. | @@ -80,9 +80,9 @@ This prop should be a function returning an `` component. When present, This prop should be a function returning an `` component. When present, the `` renders a `` before the `` -## `linkType` +## `rowClick` -The `` items link to the edition page by default. You can also set the `linkType` prop to `show` directly to link to the `` page instead. +The `` items link to the edition page by default. You can also set the `rowClick` prop to `show` directly to link to the `` page instead. ```jsx import { List, SimpleList } from 'react-admin'; @@ -93,17 +93,18 @@ export const PostList = () => ( primaryText={record => record.title} secondaryText={record => `${record.views} views`} tertiaryText={record => new Date(record.published_at).toLocaleDateString()} - linkType="show" + rowClick="show" /> ); ``` -`linkType` accepts the following values: +`rowClick` accepts the following values: -* `linkType="edit"`: links to the edit page. This is the default behavior. -* `linkType="show"`: links to the show page. -* `linkType={false}`: does not create any link. +* `rowClick="edit"`: links to the edit page. This is the default behavior. +* `rowClick="show"`: links to the show page. +* `rowClick={false}`: does not link to anything. +* `rowClick={(id, resource, record) => path}`: path can be any of the above values ## `primaryText` @@ -254,7 +255,7 @@ export const PostList = () => { primaryText={record => record.title} secondaryText={record => `${record.views} views`} tertiaryText={record => new Date(record.published_at).toLocaleDateString()} - linkType={record => record.canEdit ? "edit" : "show"} + rowClick={record => record.canEdit ? "edit" : "show"} /> ) : ( diff --git a/packages/ra-ui-materialui/src/list/SimpleList/SimpleList.tsx b/packages/ra-ui-materialui/src/list/SimpleList/SimpleList.tsx index 72c071530b4..dd308c82822 100644 --- a/packages/ra-ui-materialui/src/list/SimpleList/SimpleList.tsx +++ b/packages/ra-ui-materialui/src/list/SimpleList/SimpleList.tsx @@ -1,11 +1,7 @@ -import * as React from 'react'; -import { styled } from '@mui/material/styles'; import type { SxProps } from '@mui/material'; -import { isValidElement, ReactNode, ReactElement } from 'react'; import { Avatar, List, - ListProps, ListItem, ListItemAvatar, ListItemButton, @@ -13,22 +9,31 @@ import { ListItemProps, ListItemSecondaryAction, ListItemText, + ListProps, } from '@mui/material'; -import { Link } from 'react-router-dom'; +import { styled } from '@mui/material/styles'; import { Identifier, RaRecord, RecordContextProvider, sanitizeListRestProps, + useGetRecordRepresentation, useListContextWithProps, useResourceContext, - useGetRecordRepresentation, - useCreatePath, useTranslate, } from 'ra-core'; +import * as React from 'react'; +import { isValidElement, ReactElement, ReactNode } from 'react'; +import { Link } from 'react-router-dom'; -import { SimpleListLoading } from './SimpleListLoading'; import { ListNoResults } from '../ListNoResults'; +import { SimpleListLoading } from './SimpleListLoading'; + +import { useGetPathForRecordCallback } from 'ra-core'; +import { useCallback } from 'react'; +import { useNavigate } from 'react-router-dom'; + +import { RowClickFunction } from 'react-admin'; /** * The component renders a list of records as a Material UI . @@ -44,7 +49,8 @@ import { ListNoResults } from '../ListNoResults'; * - leftIcon: same * - rightAvatar: same * - rightIcon: same - * - linkType: 'edit' or 'show', or a function returning 'edit' or 'show' based on the record + * - linkType: deprecated 'edit' or 'show', or a function returning 'edit' or 'show' based on the record + * - rowClick: The action to trigger when the user clicks on a row. @see https://marmelab.com/react-admin/Datagrid.html#rowclick * - rowStyle: function returning a style object based on (record, index) * - rowSx: function returning a sx object based on (record, index) * @@ -65,7 +71,7 @@ import { ListNoResults } from '../ListNoResults'; * * ); */ -export const SimpleList = ( +export const SimpleListJarvi = ( props: SimpleListProps ) => { const { @@ -74,7 +80,8 @@ export const SimpleList = ( hasBulkActions, leftAvatar, leftIcon, - linkType = 'edit', + linkType, + rowClick = 'edit', primaryText, rightAvatar, rightIcon, @@ -84,8 +91,9 @@ export const SimpleList = ( rowStyle, ...rest } = props; - const { data, isPending, total } = - useListContextWithProps(props); + const { data, isPending, total } = useListContextWithProps( + props + ); const resource = useResourceContext(props); const getRecordRepresentation = useGetRecordRepresentation(resource); const translate = useTranslate(); @@ -131,7 +139,9 @@ export const SimpleList = ( ( _: primaryText, }) : isValidElement(primaryText) - ? primaryText - : // @ts-ignore - primaryText( - record, - record.id - ) + ? primaryText + : // @ts-ignore + primaryText(record, record.id) : getRecordRepresentation(record)} {!!tertiaryText && @@ -189,14 +196,14 @@ export const SimpleList = ( } ) : isValidElement( - tertiaryText - ) - ? tertiaryText - : // @ts-ignore - tertiaryText( - record, - record.id - )} + tertiaryText + ) + ? tertiaryText + : // @ts-ignore + tertiaryText( + record, + record.id + )} ))} @@ -209,9 +216,9 @@ export const SimpleList = ( _: secondaryText, }) : isValidElement(secondaryText) - ? secondaryText - : // @ts-ignore - secondaryText(record, record.id)) + ? secondaryText + : // @ts-ignore + secondaryText(record, record.id)) } /> {(rightAvatar || rightIcon) && ( @@ -249,7 +256,27 @@ export interface SimpleListProps leftAvatar?: FunctionToElement; leftIcon?: FunctionToElement; primaryText?: FunctionToElement | ReactElement | string; + /** + * @deprecated use rowClick instead + */ linkType?: string | FunctionLinkType | false; + + /** + * The action to trigger when the user clicks on a row. + * + * @see https://marmelab.com/react-admin/Datagrid.html#rowclick + * @example + * import { List, Datagrid } from 'react-admin'; + * + * export const PostList = () => ( + * + * + * ... + * + * + * ); + */ + rowClick?: string | RowClickFunction | false; rightAvatar?: FunctionToElement; rightIcon?: FunctionToElement; secondaryText?: FunctionToElement | ReactElement | string; @@ -270,35 +297,61 @@ const LinkOrNot = ( ) => { const { classes: classesOverride, + //@deprecated: use rowClick instead linkType, + rowClick, resource, id, children, record, ...rest } = props; - const createPath = useCreatePath(); - const type = - typeof linkType === 'function' ? linkType(record, id) : linkType; - if (type === false) { - return ( - - {children} - - ); - } + const navigate = useNavigate(); + const getPathForRecord = useGetPathForRecordCallback(); + const handleClick = useCallback( + async event => { + event.persist(); + const link = + // v this is to maintain compatibility with deprecated linkType + typeof linkType === 'function' + ? linkType(record, id) + : typeof linkType !== 'undefined' + ? linkType + : // v this is the new way to handle links + typeof rowClick === 'function' + ? (record, resource) => + rowClick(record.id, resource, record) + : typeof rowClick !== 'undefined' + ? rowClick + : 'edit'; + const path = await getPathForRecord({ + record, + resource, + link, + }); + console.debug('LinkOrNot handleClick', { + event, + path, + record, + resource, + link, + rowClick, + linkType, + }); + if (path === false || path == null) { + return; + } + navigate(path, { + state: { _scrollToTop: true }, + }); + }, + [record, resource, rowClick, navigate, getPathForRecord] + ); + return ( // @ts-ignore - + {children} ); @@ -307,7 +360,9 @@ const LinkOrNot = ( export type FunctionLinkType = (record: RaRecord, id: Identifier) => string; export interface LinkOrNotProps { - linkType: string | FunctionLinkType | false; + // @deprecated: use rowClick instead + linkType?: string | FunctionLinkType | false; + rowClick?: string | RowClickFunction | false; resource?: string; id: Identifier; record: RaRecord;