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

Backport master to next #9866

Merged
merged 33 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
42fe077
docs: update italian locale reference
christianascone May 3, 2024
750c549
Fix crash in ListView when inside a tab
fzaninotto May 3, 2024
fb967ee
[Doc] Fix Input usage mentions disabled instead of readOnly
fzaninotto May 3, 2024
f7421b9
Fix Datagrid uses wrong element for "Select All" label
fzaninotto May 3, 2024
35ce017
Fix indentation
fzaninotto May 3, 2024
7c97257
Fix third-party test
fzaninotto May 3, 2024
9f925c0
Merge pull request #9825 from marmelab/doc-fix-input-readonly-disabled
djhi May 4, 2024
657c106
Merge pull request #9824 from marmelab/fix-listview-error-boundry
djhi May 4, 2024
1ca3178
Merge pull request #9826 from marmelab/Fix-Datagrid-uses-xrong-elemen…
djhi May 4, 2024
586bcf3
Merge branch 'marmelab:master' into master
christianascone May 4, 2024
fffb1f6
Merge pull request #9830 from christianascone/master
djhi May 6, 2024
ef0cfd9
Avoid using defaultProps
djhi May 6, 2024
a032200
Fix demo build
djhi May 6, 2024
086d978
Fix `<TitlePortal>` stories
djhi May 6, 2024
d7cead2
Minor adjustments
fzaninotto May 6, 2024
9055ddf
Merge pull request #9834 from marmelab/fix-title-portal-stories
fzaninotto May 6, 2024
a037ccf
Merge pull request #9832 from marmelab/avoid-default-props
fzaninotto May 6, 2024
6ef2e82
Add story showing global validation in TabbedForm
fzaninotto May 9, 2024
79259f0
Doc: Add missing fetchUtils import to make custom httpClient snippet …
adguernier May 13, 2024
7f1c77d
Merge pull request #9843 from marmelab/doc/add-missing-import-to-make…
slax57 May 13, 2024
a1107cc
[Doc] Embed tutorial video in create-react-admin page
fzaninotto May 14, 2024
ca3f039
fix(typescript) fix @types/react v18.2.66 issue introducing required …
ilia-os May 16, 2024
570c376
Merge pull request #9853 from ilia-os/fix/9737-types-react-v18.2.66-i…
slax57 May 17, 2024
e2767b6
[Doc] Improve doc for `<Autocomplete onCreate>` and similar props
fzaninotto May 18, 2024
094a52f
Update docs/AutocompleteInput.md
fzaninotto May 20, 2024
7364a0b
Merge pull request #9858 from marmelab/automplete-onCreate-doc
fzaninotto May 20, 2024
449bc17
Prepare changeglog for v4.16.18
fzaninotto May 20, 2024
f18d7ec
v4.16.18
fzaninotto May 20, 2024
316e4b5
Fix yarn.lock
fzaninotto May 20, 2024
0f6cb10
Merge branch 'master' into next
djhi May 22, 2024
799fd8f
Fix build
djhi May 22, 2024
506b8bb
Apply review suggestions
djhi May 22, 2024
1b0ca9f
Apply review suggestions
djhi May 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@
* [TypeScript] Make types more strict in ra-core, part II ([#9743](https://github.com/marmelab/react-admin/pull/9743)) ([fzaninotto](https://github.com/fzaninotto))
* [TypeScript] Make types more strict in ra-core ([#9741](https://github.com/marmelab/react-admin/pull/9741)) ([fzaninotto](https://github.com/fzaninotto))

## v4.16.18

* Fix `<Datagrid>` uses wrong element for "Select All" label ([#9826](https://github.com/marmelab/react-admin/pull/9826)) ([fzaninotto](https://github.com/fzaninotto))
* Fix `<ListView>` crashes when inside a tab ([#9824](https://github.com/marmelab/react-admin/pull/9824)) ([fzaninotto](https://github.com/fzaninotto))
* Fix warning about `defaultProps` in React 18.3 ([#9832](https://github.com/marmelab/react-admin/pull/9832)) ([djhi](https://github.com/djhi))
* Bump ejs from 3.1.8 to 3.1.10 ([#9814](https://github.com/marmelab/react-admin/pull/9814)) ([dependabot bot](https://github.com/dependabot))
* [Doc] Improve doc for `<Autocomplete onCreate>` and similar props ([#9858](https://github.com/marmelab/react-admin/pull/9858)) ([fzaninotto](https://github.com/fzaninotto))
* [Doc] Add missing `fetchUtils` import to make custom httpClient snippet clearer in TypeScript ([#9843](https://github.com/marmelab/react-admin/pull/9843)) ([adguernier](https://github.com/adguernier))
* [Doc] update italian locale reference ([#9830](https://github.com/marmelab/react-admin/pull/9830)) ([christianascone](https://github.com/christianascone))
* [Doc] Fix Input usage mentions `disabled` instead of `readOnly` ([#9825](https://github.com/marmelab/react-admin/pull/9825)) ([fzaninotto](https://github.com/fzaninotto))
* [Typescript] Fix compilation error in `<MenuItemLink>`, `<ResettableTextField>` and `<InspectorButton>` with latest `@types/react` ([#9853](https://github.com/marmelab/react-admin/pull/9853)) ([ilia-os](https://github.com/ilia-os))
* [Storybook] Fix `<TitlePortal>` stories ([#9834](https://github.com/marmelab/react-admin/pull/9834)) ([djhi](https://github.com/djhi))

## v4.16.17

* Fix combineDataProviders doesn't work when returned by an async function ([#9798](https://github.com/marmelab/react-admin/pull/9798)) ([fzaninotto](https://github.com/fzaninotto))
Expand All @@ -72,7 +85,7 @@
* [Doc] Update third-party Inputs to add link to Google Places AutocompleteInput ([#9771](https://github.com/marmelab/react-admin/pull/9771)) ([quentin-decre](https://github.com/quentin-decre))
* [Doc] Update `<Search>` and `<SearchWithResult>` to introduce `queryOptions` ([#9779](https://github.com/marmelab/react-admin/pull/9779)) ([erwanMarmelab](https://github.com/erwanMarmelab))
* [Doc] Update RBAC to better explain the difference between the built-in actions ([#9766](https://github.com/marmelab/react-admin/pull/9766)) ([slax57](https://github.com/slax57))
* [Doc] Fix `<SimpleForm>` has wrong import for `<RichTextInput>` ([#9775](https://github.com/marmelab/react-admin/pull/9775)) ([anthonycmain](https://github.com/anthonycmain))
* [Doc] Fix `<SimpleForm>` has wrong import for `<RichTextInput>` ([#9775](https://github.com/marmelab/react-admin/pull/9775)) ([anthonycmain](https://github.com/anthonycmain))
* [Doc] Fix `<RichTextInput>` typo on TipTap ([#9759](https://github.com/marmelab/react-admin/pull/9759)) ([adguernier](https://github.com/adguernier))
* [Doc] Update `<JsonSchemaForm>` to add details about available widgets ([#9758](https://github.com/marmelab/react-admin/pull/9758)) ([adguernier](https://github.com/adguernier))
* [TypeScript] Fix warning in `create-react-admin` ([#9728](https://github.com/marmelab/react-admin/pull/9728)) ([hbendev](https://github.com/hbendev))
Expand Down
83 changes: 67 additions & 16 deletions docs/AutocompleteInput.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,48 @@ const CreateCategory = () => {
```
{% endraw %}

If you want to customize the label of the "Create XXX" option, use [the `createItemLabel` prop](#createitemlabel).

If you just need to ask users for a single string to create the new option, you can use [the `onCreate` prop](#oncreate) instead.

## `createLabel`

When you set the `create` or `onCreate` prop, `<AutocompleteInput>` lets users create new options. By default, it renders a "Create" menu item at the bottom of the list. You can customize the label of that menu item by setting a custom translation for the `ra.action.create` key in the translation files.

![Create Label](./img/AutocompleteInput-createLabel.png)

Or, if you want to customize it just for this `<AutocompleteInput>`, use the `createLabel` prop:

You can customize the label of that menu item by setting a custom translation for the `ra.action.create` key in the translation files.

```jsx
<AutocompleteInput
source="author"
choices={authors}
onCreate={onCreate}
createLabel="Start typing to create a new item"
/>
```

## `createItemLabel`

If you set the `create` or `onCreate` prop, `<AutocompleteInput>` lets users create new options. When the text entered by the user doesn't match any option, the input renders a "Create XXX" menu item at the bottom of the list.

![Create Item Label](./img/AutocompleteInput-createItemLabel.png)

You can customize the label of that menu item by setting a custom translation for the `ra.action.create_item` key in the translation files.

Or, if you want to customize it just for this `<AutocompleteInput>`, use the `createItemLabel` prop:

```jsx
<AutocompleteInput
source="author"
choices={authors}
onCreate={onCreate}
createItemLabel="Add a new author: %{item}"
/>
```

## `debounce`

When used inside a [`<ReferenceInput>`](./ReferenceInput.md), `<AutocompleteInput>` will call `dataProvider.getList()` with the current input value as filter after a delay of 250ms. This is to avoid calling the API too often while users are typing their query.
Expand Down Expand Up @@ -367,39 +407,50 @@ const BookCreate = () => (

## `onCreate`

Use the `onCreate` prop to allow users to create new options on-the-fly. Its value must be a function. This lets you render a `prompt` to ask users about the new value. You can return either the new choice directly or a Promise resolving to the new choice.
Use the `onCreate` prop to allow users to create new options on the fly. This is equivalent to MUI's `<AutoComplete freeSolo>` prop.

<video controls playsinline muted>
<source src="./img/AutocompleteInput-onCreate.mp4" type="video/mp4"/>
Your browser does not support the video tag.
</video>

`onCreate` must be a function that adds a new choice and returns it. This function can be async. The added choice must use the same format as the other choices (usually `{ id, name }`).

In the following example, users can create a new company by typing its name in the `<AutocompleteInput>`:

{% raw %}
```js
import { AutocompleteInput, Create, SimpleForm, TextInput } from 'react-admin';

const PostCreate = () => {
const categories = [
{ name: 'Tech', id: 'tech' },
{ name: 'Lifestyle', id: 'lifestyle' },
const ContactCreate = () => {
const companies = [
{ id: 1, name: 'Globex Corp.' },
{ id: 2, name: 'Soylent Inc.' },
];
return (
<Create>
<SimpleForm>
<TextInput source="title" />
<TextInput source="first_name" />
<TextInput source="last_name" />
<AutocompleteInput
onCreate={() => {
const newCategoryName = prompt('Enter a new category');
const newCategory = { id: newCategoryName.toLowerCase(), name: newCategoryName };
categories.push(newCategory);
return newCategory;
source="company"
choices={companies}
onCreate={companyName => {
const newCompany = { id: companies.length + 1, name: companyName };
companies.push(newCompany);
return newCompany;
}}
source="category"
choices={categories}
/>
</SimpleForm>
</Create>
);
}
```
{% endraw %}

If a prompt is not enough, you can use [the `create` prop](#create) to render a custom component instead.
If you want to customize the label of the "Create XXX" option, use [the `createItemLabel` prop](#createitemlabel).

When used inside a `<ReferenceInput>`, the `onCreate` prop should create a new record in the reference resource, and return it. See [Creating a New Reference](./ReferenceInput.md#creating-a-new-reference) for more details.

If a function is not enough, you can use [the `create` prop](#create) to render a custom component instead.

## `optionText`

Expand Down
2 changes: 2 additions & 0 deletions docs/CreateReactAdmin.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ title: "The create-react-admin CLI"

`create-react-admin` is a package that generates a react-admin app scaffolding using [Vite](https://vitejs.dev/). It is designed to work on most setups and produces predictable and consistent results. It's the preferred way to create a new react-admin application.

<iframe src="https://www.youtube-nocookie.com/embed/i_TbS7quzww" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="aspect-ratio: 16 / 9;width:100%;margin-bottom:1em;"></iframe>

## Usage

Use it by running the following command:
Expand Down
2 changes: 2 additions & 0 deletions docs/DataProviders.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ const App = () => (
**Tip**: For TypeScript users, here is a typed version of the `fetchJson` function:

```ts
import { fetchUtils } from "react-admin";

const fetchJson = (url: string, options: fetchUtils.Options = {}) => {
const customHeaders = (options.headers ||
new Headers({
Expand Down
26 changes: 12 additions & 14 deletions docs/Fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,18 +288,19 @@ And see [the Material UI system documentation](https://mui.com/system/the-sx-pro

This prop defines the text alignment of the field when rendered inside a `<Datagrid>` cell. By default, datagrid values are left-aligned ; for numeric values, it's often better to right-align them. Set `textAlign` to `right` for that.

[`<NumberField>`](./NumberField.md) already uses `textAlign="right"`. Set the default value for this prop if you create a custom numeric field.

```jsx
const BasketTotal = () => {
const record = useRecordContext();
if (!record) return null;
const total = record.items.reduce((total, item) => total + item.price, 0);
return <span>{total}</span>;
}
BasketTotal.defaultProps = {
textAlign: 'right',
};
import { List, Datagrid, TextField } from 'react-admin';

const PostList = () => (
<List>
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<TextField source="author" />
<TextField source="year" textAlign="right" />
</Datagrid>
</List>
);
```

## Deep Field Source
Expand Down Expand Up @@ -387,9 +388,6 @@ const FormattedNumberField = ({ source }) => {
const record = useRecordContext();
return <NumberField sx={{ color: record && record[source] < 0 ? 'red' : '' }} source={source} />;
};
FormattedNumberField.defaultProps = {
textAlign: 'right',
};
```
{% endraw %}

Expand Down
2 changes: 1 addition & 1 deletion docs/Inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { Edit, SimpleForm, ReferenceInput, SelectInput, TextInput, required } fr
export const PostEdit = () => (
<Edit>
<SimpleForm>
<TextInput disabled source="id" />
<TextInput readOnly source="id" />
<ReferenceInput label="User" source="userId" reference="users" validate={[required()]}>
<SelectInput optionText="name" />
</ReferenceInput>
Expand Down
110 changes: 84 additions & 26 deletions docs/ReferenceInput.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,32 +166,6 @@ You can filter the query used to populate the possible values. Use the `filter`

**Note**: When users type a search term in the `<AutocompleteInput>`, this doesn't affect the `filter` prop. Check the [Customizing the filter query](#customizing-the-filter-query) section below for details on how that filter works.

## `format`

By default, children of `<ReferenceInput>` transform `null` values from the `dataProvider` into empty strings.

If you want to change this behavior, you have to pass a custom `format` prop to the `<ReferenceInput>` *child component*, because **`<ReferenceInput>` doesn't have a `format` prop**. It is the responsibility of the child component to format the input value.

For instance, if you want to transform an option value before rendering, and the selection control is an `<AutocompleteInput>` (the default), set [the `<AutocompleteInput format>` prop](./Inputs.md#format) as follows:

```jsx
import { ReferenceInput, AutocompleteInput } from 'react-admin';

<ReferenceInput source="company_id" reference="companies">
<AutocompleteInput format={value => value == null ? 'not defined' : value} />
</ReferenceInput>
```

The same goes if the child is a `<SelectInput>`:

```jsx
import { ReferenceInput, SelectInput } from 'react-admin';

<ReferenceInput source="company_id" reference="companies">
<SelectInput format={value => value === undefined ? 'not defined' : null} />
</ReferenceInput>
```

## `label`

In an `<Edit>` or `<Create>` view, the `label` prop has no effect. `<ReferenceInput>` has no label, it simply renders its child (an `<AutocompleteInput>` by default). If you need to customize the label, set the `label` prop on the child element:
Expand Down Expand Up @@ -327,6 +301,32 @@ Then to display a selector for the contact company, you should call `<ReferenceI
<ReferenceInput source="company_id" reference="companies" />
```

## Transforming The Input Value

By default, children of `<ReferenceInput>` transform `null` values from the `dataProvider` into empty strings.

If you want to change this behavior, you have to pass a custom `format` prop to the `<ReferenceInput>` *child component*, because `<ReferenceInput>` doesn't have a `format` prop. It is the responsibility of the child component to format the input value.

For instance, if you want to transform an option value before rendering, and the selection control is an `<AutocompleteInput>` (the default), set [the `<AutocompleteInput format>` prop](./Inputs.md#format) as follows:

```jsx
import { ReferenceInput, AutocompleteInput } from 'react-admin';

<ReferenceInput source="company_id" reference="companies">
<AutocompleteInput format={value => value == null ? 'not defined' : value} />
</ReferenceInput>
```

The same goes if the child is a `<SelectInput>`:

```jsx
import { ReferenceInput, SelectInput } from 'react-admin';

<ReferenceInput source="company_id" reference="companies">
<SelectInput format={value => value === undefined ? 'not defined' : null} />
</ReferenceInput>
```

## Customizing The Filter Query

By default, `<ReferenceInput>` renders an `<AutocompleteInput>`, which lets users type a search term to filter the possible values. `<ReferenceInput>` calls `dataProvider.getList()` using the search term as filter, using the format `filter: { q: [search term] }`.
Expand All @@ -341,6 +341,64 @@ const filterToQuery = searchText => ({ name_ilike: `%${searchText}%` });
</ReferenceInput>
```

## Creating a New Reference

When users don't find the reference they are looking for in the list of possible values, they need to create a new reference. If they have to quit the current form to create the reference, they may lose the data they have already entered. So a common feature for `<ReferenceInput>` is to let users create a new reference on the fly.

<iframe src="https://www.youtube-nocookie.com/embed/CIUp5MF6A1M" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="aspect-ratio: 16 / 9;width:100%;margin-bottom:1em;"></iframe>

Children of `<ReferenceInput>` (`<AutocompleteInput>`, `<SelectInput>`, etc.) allow the creation of new choices via the `onCreate` prop. This displays a new "Create new" option in the list of choices. You can leverage this capability to create a new reference record.

The following example is a contact edition form using a `<ReferenceInput>` to select the contact company. Its child `<AutocompleteInput onCreate>` allows to create a new company on the fly if it doesn't exist yet.

```tsx
export const ContactEdit = () => {
const [create] = useCreate();
const notify = useNotify();
const handleCreateCompany = async (companyName?: string) => {
if (!companyName) return;
try {
const newCompany = await create(
'companies',
{ data: { name: companyName } },
{ returnPromise: true }
);
return newCompany;
} catch (error) {
notify('An error occurred while creating the company', {
type: 'error',
});
throw(error);
}
};
return (
<Edit>
<SimpleForm>
<TextInput source="first_name" />
<TextInput source="last_name" />
<ReferenceInput source="company_id" reference="companies">
<AutocompleteInput onCreate={handleCreateCompany} />
</ReferenceInput>
</SimpleForm>
</Edit>
);
};
```

In the example above, the `handleCreateCompany` function creates a new company with the name provided by the user, and returns it so that `<AutocompleteInput>` selects it.

You can learn more about the `onCreate` prop in the documentation of the selection input components:

- [`<AutocompleteInput onCreate>`](./AutocompleteInput.md#oncreate)
- [`<SelectInput onCreate>`](./SelectInput.md#oncreate)

If you need to ask the user for more details about the new reference, you display a custom element (e.g. a dialog) when the user selects the "Create" option. use the `create` prop for that instead of `onCreate`.

You can learn more about the `create` prop in the documentation of the selection input components:

- [`<AutocompleteInput create>`](./AutocompleteInput.md#create)
- [`<SelectInput create>`](./SelectInput.md#create)

## Tree Structure

If the reference resource is a tree, use [`<ReferenceNodeInput>`](./ReferenceNodeInput.md) instead of `<ReferenceInput>`.
Expand Down
Loading
Loading