Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

edit / show title prop: add 'false' and callback choices #9770

Open
wants to merge 4 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 13 additions & 2 deletions docs/Edit.md
Expand Up @@ -521,7 +521,13 @@ To override the style of all instances of `<Edit>` components using the [applica

By default, the title for the Edit view is “Edit [resource_name] #[record_id]”.

You can customize this title by specifying a custom `title` prop:
You can customize this title by specifying a custom `title` prop

The `title` prop can be one of:
- `false` to hide the title
- string
- React element
- callback with the signature (record: RaRecord) => string

```jsx
const PostTitle = () => {
Expand All @@ -534,9 +540,14 @@ export const PostEdit = () => (
...
</Edit>
);

export const OtherPostEdit = () => (
<Edit title={record=>`Edit Post ${record?.title}`}>
...
</Edit>
)
```

The `title` value can be a string or a React element.

## `transform`

Expand Down
4 changes: 3 additions & 1 deletion docs/Show.md
Expand Up @@ -71,7 +71,9 @@ That's enough to display the post show view above.
| `queryOptions` | Optional | `object` | | The options to pass to the `useQuery` hook
| `resource` | Optional | `string` | | The resource name, e.g. `posts`
| `sx` | Optional | `object` | | Override or extend the styles applied to the component
| `title` | Optional | `string | ReactElement` | | The title to display in the App Bar
| `title` | Optional | *titleType | | The title to display in the App Bar see [Edit](./Edit.md#title)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick (non-blocking): ‏You could also add another example in the title section of this doc, just like you did for Edit.


*`titleType = string | ReactElement | false | (arg0?: RaRecord) => string`

## `actions`

Expand Down
18 changes: 13 additions & 5 deletions packages/ra-ui-materialui/src/detail/EditView.tsx
Expand Up @@ -37,16 +37,24 @@ export const EditView = (props: EditViewProps) => {
if (!children) {
return null;
}
let titleComponent = null;
if (title !== false) {
const newTitle = typeof title === 'function' ? title(record) : title;

titleComponent = (
<Title
title={newTitle}
defaultTitle={defaultTitle}
preferenceKey={`${resource}.show.title`}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue:

Suggested change
preferenceKey={`${resource}.show.title`}
preferenceKey={`${resource}.edit.title`}

/>
);
}
return (
<Root
className={clsx('edit-page', className)}
{...sanitizeRestProps(rest)}
>
<Title
title={title}
defaultTitle={defaultTitle}
preferenceKey={`${resource}.edit.title`}
/>
{titleComponent}
{finalActions}
<div
className={clsx(EditClasses.main, {
Expand Down
13 changes: 12 additions & 1 deletion packages/ra-ui-materialui/src/detail/Show.spec.tsx
Expand Up @@ -16,7 +16,13 @@ import { Route, Routes } from 'react-router-dom';
import { render, screen, waitFor } from '@testing-library/react';

import { AdminContext } from '../AdminContext';
import { Default, Actions, Basic, Component } from './Show.stories';
import {
Default,
Actions,
Basic,
Component,
CustomTitle,
} from './Show.stories';
import { Show } from './Show';

describe('<Show />', () => {
Expand Down Expand Up @@ -126,6 +132,11 @@ describe('<Show />', () => {
expect(screen.getByTestId('custom-component')).toBeDefined();
});

it('should display a custom title', async () => {
render(<CustomTitle />);
await screen.findByText('book_1_test');
});

Comment on lines +135 to +139
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: ‏Why not add tests for Edit too?

describe('defaultTitle', () => {
const defaultShowProps = {
id: '123',
Expand Down
14 changes: 14 additions & 0 deletions packages/ra-ui-materialui/src/detail/Show.stories.tsx
Expand Up @@ -121,6 +121,20 @@ export const Aside = () => (
</TestMemoryRouter>
);

const PostShowWithCustomTitle = () => (
<Show title={book => `book_${book?.id}_test`}>
<BookTitle />
</Show>
);

export const CustomTitle = () => (
<TestMemoryRouter initialEntries={['/books/1/show']}>
<Admin dataProvider={dataProvider}>
<Resource name="books" show={PostShowWithCustomTitle} />
</Admin>
</TestMemoryRouter>
);

const CustomWrapper = ({ children }) => (
<Box
sx={{ padding: 2, width: 200, border: 'solid 1px black' }}
Expand Down
28 changes: 20 additions & 8 deletions packages/ra-ui-materialui/src/detail/ShowView.tsx
Expand Up @@ -3,15 +3,17 @@ import PropTypes from 'prop-types';
import { Card } from '@mui/material';
import { styled } from '@mui/material/styles';
import clsx from 'clsx';
import { useShowContext, useResourceDefinition } from 'ra-core';
import { useShowContext, useResourceDefinition, RaRecord } from 'ra-core';

import { ShowProps } from '../types';
import { ShowActions } from './ShowActions';
import { Title } from '../layout';

const defaultActions = <ShowActions />;

export const ShowView = (props: ShowViewProps) => {
export const ShowView = <RecordType extends RaRecord = any>(
props: ShowViewProps<RecordType>
) => {
const {
actions,
aside,
Expand All @@ -32,16 +34,24 @@ export const ShowView = (props: ShowViewProps) => {
if (!children || (!record && emptyWhileLoading)) {
return null;
}
let titleComponent = null;
if (title !== false) {
const newTitle = typeof title === 'function' ? title(record) : title;

titleComponent = (
<Title
title={newTitle}
defaultTitle={defaultTitle}
preferenceKey={`${resource}.show.title`}
/>
);
}
return (
<Root
className={clsx('show-page', className)}
{...sanitizeRestProps(rest)}
>
<Title
title={title}
defaultTitle={defaultTitle}
preferenceKey={`${resource}.show.title`}
/>
{titleComponent}
{finalActions !== false && finalActions}
<div
className={clsx(ShowClasses.main, {
Expand All @@ -55,7 +65,9 @@ export const ShowView = (props: ShowViewProps) => {
);
};

export type ShowViewProps = ShowProps;
export type ShowViewProps<RecordType extends RaRecord = any> = ShowProps<
RecordType
>;
Comment on lines +68 to +70
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: ‏Why did you need that change?


ShowView.propTypes = {
actions: PropTypes.oneOfType([PropTypes.element, PropTypes.bool]),
Expand Down
12 changes: 10 additions & 2 deletions packages/ra-ui-materialui/src/types.ts
Expand Up @@ -32,7 +32,11 @@ export interface EditProps<
redirect?: RedirectionSideEffect;
resource?: string;
transform?: TransformData;
title?: string | ReactElement;
title?:
| string
| ReactElement
| false
| ((arg0: RecordType | undefined) => string);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

polish:

Suggested change
| ((arg0: RecordType | undefined) => string);
| ((record: RecordType | undefined) => string);

sx?: SxProps;
}

Expand Down Expand Up @@ -73,7 +77,11 @@ export interface ShowProps<RecordType extends RaRecord = any> {
id?: Identifier;
queryOptions?: UseQueryOptions<RecordType> & { meta?: any };
resource?: string;
title?: string | ReactElement;
title?:
| string
| ReactElement
| false
| ((arg0: RecordType | undefined) => string);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

polish:

Suggested change
| ((arg0: RecordType | undefined) => string);
| ((record: RecordType | undefined) => string);

sx?: SxProps;
}

Expand Down