diff --git a/CHANGELOG.md b/CHANGELOG.md index 37246417a01..0bd5fe868c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## v4.16.15 + +* Fix `useGetIdentity` regression ([#9756](https://github.com/marmelab/react-admin/pull/9756)) ([djhi](https://github.com/djhi)) +* Bump vite from 3.2.8 to 3.2.10 ([#9755](https://github.com/marmelab/react-admin/pull/9755)) ([dependabot[bot]](https://github.com/apps/dependabot)) + +## v4.16.14 + +* Fix `` does not support the variant prop ([#9751](https://github.com/marmelab/react-admin/9751)) by ([adguernier](https://github.com/marmelab/adguernier)) +* [Demo] Fix error when viewing newly created deals in CRM demo ([#9733](https://github.com/marmelab/react-admin/9733)) by ([erwanMarmelab](https://github.com/marmelab/erwanMarmelab)) +* Bump express from 4.17.3 to 4.19.2 ([#9747](https://github.com/marmelab/react-admin/9747)) by ([dependabot](https://github.com/marmelab/dependabot)) +* Bump webpack-dev-middleware from 6.1.1 to 6.1.2 ([#9739](https://github.com/marmelab/react-admin/9739)) by ([dependabot](https://github.com/marmelab/dependabot)) +* [Doc] Update `` to explain how to access the editor object ([#9731](https://github.com/marmelab/react-admin/9731)) by ([erwanMarmelab](https://github.com/marmelab/erwanMarmelab)) +* [Doc] Update "Writing a Data Provider" chapter to include test advice ([#9738](https://github.com/marmelab/react-admin/9738)) by ([fzaninotto](https://github.com/marmelab/fzaninotto)) +* [Doc] Update RBAC to mention ability to define permissions on an array of resources ([#9729](https://github.com/marmelab/react-admin/9729)) by ([erwanMarmelab](https://github.com/marmelab/erwanMarmelab)) + ## v4.16.13 * Fix `` ([#9712](https://github.com/marmelab/react-admin/pull/9712)) ([fzaninotto](https://github.com/fzaninotto)) diff --git a/cypress/package.json b/cypress/package.json index db0c2024d2a..07c659b3eb8 100644 --- a/cypress/package.json +++ b/cypress/package.json @@ -10,6 +10,6 @@ "cypress": "^10.9.0", "cypress-plugin-tab": "^1.0.5", "cypress-vite": "^1.4.0", - "express": "~4.17.3" + "express": "~4.19.2" } } diff --git a/docs/AuthProviderList.md b/docs/AuthProviderList.md index 41d427c2d21..d6e77f63d15 100644 --- a/docs/AuthProviderList.md +++ b/docs/AuthProviderList.md @@ -8,7 +8,7 @@ title: "Supported Auth Provider Backends" It's very common that your auth logic is so specific that you'll need to write your own `authProvider`. However, the community has built a few open-source Auth Providers that may fit your need:
-- ![auth0 Logo](./img/backend-logos/auth0.svg "auth0 Logo")**[Auth0](https://auth0.com/)**: [marmelab/ra-auth-auth0](https://github.com/marmelab/ra-auth-auth0/blob/main/packages/ra-auth-auth0/Readme.md) +- ![auth0 Logo](./img/backend-logos/auth0.svg "auth0 Logo")**[Auth0 by Okta](https://auth0.com/)**: [marmelab/ra-auth-auth0](https://github.com/marmelab/ra-auth-auth0/blob/main/packages/ra-auth-auth0/Readme.md) - ![amplify Logo](./img/backend-logos/amplify.svg "amplify Logo")**[AWS Amplify](https://docs.amplify.aws)**: [MrHertal/react-admin-amplify](https://github.com/MrHertal/react-admin-amplify) - ![cognito Logo](./img/backend-logos/aws.png "cognito Logo")**[AWS Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/setting-up-the-javascript-sdk.html)**: [marmelab/ra-auth-cognito](https://github.com/marmelab/ra-auth-cognito/blob/main/packages/ra-auth-cognito/Readme.md) - ![azure Logo](./img/backend-logos/microsoft.svg "azure Logo")**[Azure Active Directory (using MSAL)](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-browser)**: [marmelab/ra-auth-msal](https://github.com/marmelab/ra-auth-msal/blob/main/packages/ra-auth-msal/Readme.md) ([Tutorial](https://marmelab.com/blog/2023/09/13/active-directory-integration-tutorial.html)) diff --git a/docs/AuthRBAC.md b/docs/AuthRBAC.md index 6f37cd27ead..7b0adad68c9 100644 --- a/docs/AuthRBAC.md +++ b/docs/AuthRBAC.md @@ -98,6 +98,7 @@ Here are a few examples of permissions: - `{ action: "*", resource: "*" }`: allow everything - `{ action: "read", resource: "*" }`: allow read actions on all resources +- `{ action: "read", resource: ["companies", "people"] }`: allow read actions on a subset of resources - `{ action: ["read", "create", "edit", "export"], resource: "companies" }`: allow all actions except delete on companies - `{ action: ["write"], resource: "game.score", record: { "id": "123" } }`: allow to change the score on a particular game diff --git a/docs/Create.md b/docs/Create.md index 6a96300b6fa..fe8f1d725a5 100644 --- a/docs/Create.md +++ b/docs/Create.md @@ -561,6 +561,8 @@ Note: In order to get the `mutationOptions` being considered, you have to set th ## Linking Two Inputs + + Edition forms often contain linked inputs, e.g. country and city (the choices of the latter depending on the value of the former). React-admin relies on [react-hook-form](https://react-hook-form.com/) for form handling. You can grab the current form values using react-hook-form's [useWatch](https://react-hook-form.com/docs/usewatch) hook. diff --git a/docs/DataProviderWriting.md b/docs/DataProviderWriting.md index 87d60314588..c400e46f83c 100644 --- a/docs/DataProviderWriting.md +++ b/docs/DataProviderWriting.md @@ -7,6 +7,9 @@ title: "Writing A Data Provider" APIs are so diverse that quite often, none of [the available Data Providers](./DataProviderList.md) suit you API. In such cases, you'll have to write your own Data Provider. Don't worry, it usually takes only a couple of hours. + + + The methods of a Data Provider receive a request, and return a promise for a response. Both the request and the response format are standardized. ## Data Provider Methods @@ -150,7 +153,7 @@ dataProvider.getMany('posts', { ids: [123, 124, 125] }) ## `getManyReference` -React-admin calls `dataProvider.getManyReference()` to fetch several records related to another one. +React-admin calls `dataProvider.getManyReference()` to fetch the records related to another record. Although similar to `getList`, this method is designed for relationships. It is necessary because some APIs require a different query to fetch related records (e.g. `GET /posts/123/comments` to fetch comments related to post 123). **Interface** @@ -425,6 +428,30 @@ export default { }; ``` +## Handling Authentication + +Your API probably requires some form of authentication (e.g. a token in the `Authorization` header). It's the responsibility of [the `authProvider`](./Authentication.md) to log the user in and obtain the authentication data. React-admin doesn't provide any particular way of communicating this authentication data to the Data Provider. Most of the time, storing the authentication data in the `localStorage` is the best choice - and allows uses to open multiple tabs without having to log in again. + +Check the [Handling Authentication](./DataProviders.md#handling-authentication) section in the Data Providers introduction for an example of such a setup. + +## Testing Data Provider Methods + +A good way to test your data provider is to build a react-admin app with components that depend on it. Here is a list of components calling the data provider methods: + +| Method | Components | +| ------------------ | --------- | +| `getList` | [``](./List.md), [``](./ListGuesser.md), [``](./ListBase.md), [``](./InfiniteList.md), [``](./Count.md), [``](./Calendar.md), [``](./ReferenceInput.md), [``](./ReferenceArrayInput.md), [``](./Buttons.md#exportbutton), [``](./PrevNextButtons.md) | +| `getOne` | [``](./Show.md), [``](./ShowGuesser.md), [``](./ShowBase.md), [``](./Edit.md), [``](./EditGuesser.md), [``](./EditBase.md) | +| `getMany` | [``](./ReferenceField.md), [``](./ReferenceArrayField.md), [``](./ReferenceInput.md), [``](./ReferenceArrayInput.md) | +| `getManyReference` | [``](./ReferenceManyField.md), [``](./ReferenceOneField.md), [``](./ReferenceManyInput.md), [``](./ReferenceOneInput.md) | +| `create` | [``](./Create.md), [``](./CreateBase.md), [``](./EditableDatagrid.md), [``](./CreateInDialogButton.md) | +| `update` | [``](./Edit.md), [``](./EditGuesser.md), [``](./EditBase.md), [``](./EditableDatagrid.md), [``](./EditInDialogButton.md), [``](./UpdateButton.md) | +| `updateMany` | [``](./BulkUpdateButton.md) | +| `delete` | [``](./DeleteButton.md), [``](./EditableDatagrid.md) | +| `deleteMany` | [``](./BulkDeleteButton.md) | + +A simple react-admin app with one `` using [guessers](./Features.md#guessers--scaffolding) for the `list`, `edit`, and `show` pages is a good start. + ## The `meta` Parameter All data provider methods accept a `meta` parameter. React-admin core components never set this `meta` when calling the data provider. It's designed to let you pass additional parameters to your data provider. @@ -465,6 +492,44 @@ const { data } = dataProvider.getOne('posts', { id: 123 }) This will cause the Edit view to blink on load. If you have this problem, modify your Data Provider to return the same shape for all methods. +## `fetchJson`: Built-In HTTP Client + +Although your Data Provider can use any HTTP client (`fetch`, `axios`, etc.), react-admin suggests using a helper function called `fetchJson` that it provides. + +`fetchJson` is a wrapper around the `fetch` API that automatically handles JSON deserialization, rejects when the HTTP response isn't 2XX or 3XX, and throws a particular type of error that allows the UI to display a meaningful notification. `fetchJson` also lets you add an `Authorization` header if you pass a `user` option. + +Here is how you can use it in your Data Provider: + +```diff ++import { fetchUtils } from 'react-admin'; + ++const fetchJson = (url, options = {}) => { ++ options.user = { ++ authenticated: true, ++ // use the authentication token from local storage (given the authProvider added it there) ++ token: localStorage.getItem('token') ++ }; ++ return fetchUtils.fetchJson(url, options); ++}; +// ... + +const dataProvider = { + getList: (resource, params) => { + const { page, perPage } = params.pagination; + const { field, order } = params.sort; + const query = { + sort: JSON.stringify([field, order]), + range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]), + filter: JSON.stringify(params.filter), + }; + const url = `${apiUrl}/${resource}?${stringify(query)}`; +- return fetch(url, { method: 'GET' }); ++ return fetchJson(url, { method: 'GET' }); + }, + // ... +}; +``` + ## Example REST Implementation Let's say that you want to map the react-admin requests to a REST backend exposing the following API: diff --git a/docs/Edit.md b/docs/Edit.md index 9739c81ceb7..46a68e22484 100644 --- a/docs/Edit.md +++ b/docs/Edit.md @@ -728,6 +728,8 @@ The user will see alerts when other users update or delete the record. ## Linking Two Inputs + + Edition forms often contain linked inputs, e.g. country and city (the choices of the latter depending on the value of the former). React-admin relies on [react-hook-form](https://react-hook-form.com/) for form handling. You can grab the current form values using react-hook-form's [useWatch](https://react-hook-form.com/docs/usewatch) hook. diff --git a/docs/Form.md b/docs/Form.md index a81a50fb2b4..f0b98940c53 100644 --- a/docs/Form.md +++ b/docs/Form.md @@ -292,6 +292,8 @@ Check [the `` component](./AutoSave.md) documentation for more details ## Linking Two Inputs + + Edition forms often contain linked inputs, e.g. country and city (the choices of the latter depending on the value of the former). React-admin relies on [react-hook-form](https://react-hook-form.com/) for form handling. You can grab the current form values using react-hook-form's [useWatch](https://react-hook-form.com/docs/usewatch) hook. diff --git a/docs/JsonSchemaForm.md b/docs/JsonSchemaForm.md index 2b0f7ac12ef..10509a6c201 100644 --- a/docs/JsonSchemaForm.md +++ b/docs/JsonSchemaForm.md @@ -7,6 +7,18 @@ title: "JsonSchemaForm" This [Enterprise Edition](https://marmelab.com/ra-enterprise) component allows to render a form from a JSON Schema description based on [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form). +## Usage + +First, install the `@react-admin/ra-json-schema-form` package: + +```sh +npm install --save @react-admin/ra-json-schema-form +# or +yarn add @react-admin/ra-json-schema-form +``` + +If you have a JSON Schema description of your form based on [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form), you can use the `` component to render it. + For instance, to generate the following form: ![JsonSchemaForm](https://marmelab.com/ra-enterprise/modules/assets/jsonschemaform.webp) @@ -15,56 +27,130 @@ Configure the `` view with a `` child as follows: {% raw %} ```jsx -import { Edit } from "react-admin"; -import { JsonSchemaForm } from "@react-admin/ra-json-schema-form"; +import { Edit } from 'react-admin'; +import { JsonSchemaForm } from '@react-admin/ra-json-schema-form'; + +const CustomerEdit = () => ( + + + process.env.NODE_ENV !== 'test' && + console.log('changed', change) + } + onError={error => + process.env.NODE_ENV !== 'test' && console.log('error', error) + } + /> + +); +``` +{% endraw %} + +`` initializes the form with the current `record`, and renders it like `` does. + +It expects a `schema` prop describing the expected data shape, and a `uiSchema` prop describing the UI. + +`` is a wrapper around JsonSchema Form's `
` component, so please refer to [JsonSchema Form's documentation](https://react-jsonschema-form.readthedocs.io/en/latest/#usage) for detailed usage. + +## UI Widgets + +`` comes with the following UI widgets: + +For `boolean` fields: + +- `checkbox` (default) +- `radio` +- `select` + +For `string` fields: + +- `text` (default) +- `textarea` +- `password` +- `color` + +The built-in `string` field also supports the `format` property, and will render an appropriate widget depending on its value: + +- `email`: renders an `input[type=email]` element; +- `uri`: renders an `input[type=url]` element; +- `data-url`: Renders an `input[type=file]` element (if the string is part of an array, multiple files will be handled automatically); +- `date`: Renders an `input[type=date]` element; +- `date-time`: Renders an `input[type=datetime-local]` element. + +For `number` and `integer` fields, you can also specify the `format` to render an alternative widget: + +- `text` (default) +- `updown` +- `range` +- `radio` + +`ra-json-schema-form` comes with the an additional UI widget for `string` fields: `reference`. It's the equivalent of [react-admin's `` component](https://marmelab.com/react-admin/ReferenceInput.html). It fetches the foreign key, and uses a relationship to populate the list of options. + +Specify the `reference`, `optionText`, and other options through the `ui:options` UI schema directive: + +{% raw %} +```tsx +import { Edit } from 'react-admin'; +import { JsonSchemaForm } from '@react-admin/ra-json-schema-form'; const CustomerEdit = () => ( - - - process.env.NODE_ENV !== "test" && console.log("changed", change) - } - onError={(error) => - process.env.NODE_ENV !== "test" && console.log("error", error) - } - /> - + + + ); ``` {% endraw %} -Check [the `ra-json-schema-form` documentation](https://marmelab.com/ra-enterprise/modules/ra-json-schema-form#installation) for more details. +## I18N +`` passes all labels, descriptions and errors to react-admin's `translate` function. You can translate the form by providing custom translations via your `i18nProvider`. diff --git a/docs/NumberField.md b/docs/NumberField.md index 4ebd6f26379..120b5b5ed41 100644 --- a/docs/NumberField.md +++ b/docs/NumberField.md @@ -7,18 +7,37 @@ title: "The NumberField Component" Displays a number formatted according to the browser locale, right aligned. Ideal for floats, currencies, percentages, units, etc. -![NumberField](./img/number-field.webp)` + ## Usage -```jsx -import { NumberField } from 'react-admin'; +Use `` to display a number in a read-only way. It reads the value from the record context and formats it according to the browser locale. +```js // renders the record { id: 1234, views: 2108 } as 2 108 ``` + +When used in a `` component, `` displays the value in a right-aligned column. + +```jsx +import { List, Datagrid, NumberField } from 'react-admin'; + +const PostList = () => ( + + + {/* ... */} + + {/* ... */} + + +); +``` + +![NumberField](./img/number-field.webp)` + `` works for values that are numbers (e.g. `2108`) or strings that convert to numbers (e.g. `'2108'`). `` uses `Intl.NumberFormat()` if available, passing the `locales` and `options` props as arguments. This allows a perfect display of decimals, currencies, percentages, etc. See [Intl.NumberFormat documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat) for the `options` prop syntax. diff --git a/docs/Reference.md b/docs/Reference.md index 70f30c93b67..3c7cbd924c5 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -63,7 +63,7 @@ title: "Index" * [``](./EditableDatagrid.md) * [``](./EditGuesser.md) * [``](./Buttons.md#editbutton) -* [``](./EditDialog) +* [``](./EditDialog.md) * [``](./EditInDialogButton.md) * [``](./EmailField.md) * [``](./List.md#empty) diff --git a/docs/RichTextInput.md b/docs/RichTextInput.md index 17d7bf1548e..35a8d708589 100644 --- a/docs/RichTextInput.md +++ b/docs/RichTextInput.md @@ -44,7 +44,7 @@ export const PostEdit = () => ( | Prop | Required | Type | Default | Description | | ------ | -------- | -------- | ------- | ----------- | | `editorOptions` | Optional | `Object` | - | Options object to pass to the underlying TipTap editor. | -| `toolbar` | Optional| ReactNode | - | The toolbar to use. If not set, the default toolbar is used. | +| `toolbar` | Optional| `ReactNode` | - | The toolbar to use. If not set, the default toolbar is used. | `` also accepts the [common input props](./Inputs.md#common-input-props). @@ -171,6 +171,65 @@ const MyRichTextInput = ({ size, ...props }) => ( ); ``` +## Calling The `editor` Object + +You may want to access the TipTap `editor` object to tweak extensions, input rules, etc. (see [the TipTap editor documentation](https://tiptap.dev/docs/editor/api/editor) for details). To do so, you can assign a `ref` in the `onCreate` function in the `editorOptions` prop of your `` component, as follows: + +{% raw %} +```tsx +import React from 'react'; +import { Edit, SaveButton, SimpleForm, TextInput, Toolbar } from 'react-admin'; +import { DefaultEditorOptions, RichTextInput } from 'ra-input-rich-text'; +import { Button } from 'ra-ui-materialui'; +import { Editor } from '@tiptap/react'; + +export const PostEdit = () => { + const editorRef = React.useRef(null); + + return ( + + } + > + + { + editorRef.current = editor; + }, + }} + /> + + + ); +}; +``` +{% endraw %} + +With this ref, you can now call the `editor` methods, for instance to set the `` content when the user clicks a button: + +{% raw %} +```jsx +const MyToolbar = ({ editorRef }) => ( + + + + +); +``` +{% endraw %} + ## AI Writing Assistant Modern AI tools can be a great help for editors. React-admin proposes an AI-powered writing assistant for the `` component, called [``](./SmartRichTextInput.md): diff --git a/docs/SimpleForm.md b/docs/SimpleForm.md index d99a79af7e5..3b087c9e956 100644 --- a/docs/SimpleForm.md +++ b/docs/SimpleForm.md @@ -759,6 +759,8 @@ Check the [``](https://marmelab.com/ra-enterprise/module ## Linking Two Inputs + + Edition forms often contain linked inputs, e.g. country and city (the choices of the latter depending on the value of the former). React-admin relies on [react-hook-form](https://react-hook-form.com/) for form handling. You can grab the current form values using react-hook-form's [useWatch](https://react-hook-form.com/docs/usewatch) hook. diff --git a/docs/TabbedForm.md b/docs/TabbedForm.md index 833d57d5b09..8c633d514dc 100644 --- a/docs/TabbedForm.md +++ b/docs/TabbedForm.md @@ -913,6 +913,8 @@ Check the [``](https://marmelab.com/ra-enterprise/module ## Linking Two Inputs + + Edition forms often contain linked inputs, e.g. country and city (the choices of the latter depending on the value of the former). React-admin relies on [react-hook-form](https://react-hook-form.com/) for form handling. You can grab the current form values using react-hook-form's [useWatch](https://react-hook-form.com/docs/usewatch) hook. diff --git a/docs/useGetList.md b/docs/useGetList.md index 0754b38b135..9df254c3c5d 100644 --- a/docs/useGetList.md +++ b/docs/useGetList.md @@ -61,6 +61,8 @@ The react-query [query key](https://react-query-v3.tanstack.com/guides/query-key ## Usage +Call the `useGetList` hook when you need to fetch a list of records from the data provider. + ```jsx import { useGetList } from 'react-admin'; @@ -88,6 +90,50 @@ const LatestNews = () => { }; ``` +## Rendering Data + +If you want to use the result in a react-admin iterator component like [``](./Datagrid.md), [``](./SimpleList.md), or [``](./SingleFieldList.md), you must first create a [`ListContext`](./useListContext.md) with the data. The [`useList`](./useList.md) hook does that for you: + +```jsx +import { + useGetList, + useList, + ListContextProvider, + Datagrid, + TextField, + DateField, + NumberField, + Pagination +} from 'react-admin'; + +const LatestNews = () => { + const { data, isLoading, error } = useGetList( + 'posts', + { pagination: { page: 1, perPage: 100 } }, + ); + if (error) { return

ERROR

; } + const listContext = useList({ + data, + isLoading, + perPage: 10, + sort: { field: 'published_at', order: 'DESC' } + }); + return ( + +

Latest news

+ + + + + + +
+ ); +}; +``` + +In this example, the `useGetList` hook fetches all the posts, and displays a list of the 10 most recent posts in a ``. The `` component allows the user to navigate through the list. Users can also sort the list by clicking on the column headers. + ## Partial Pagination If your data provider doesn't return the `total` number of records (see [Partial Pagination](./DataProviderWriting.md#partial-pagination)), you can use the `pageInfo` field to determine if there are more records to fetch. @@ -127,6 +173,52 @@ const LatestNews = () => { Alternately, you can use [the `useInfiniteGetList` hook](./useInfiniteGetList.md) to keep the previous pages on screen while loading new pages - just like users see older content when they scroll down their feed on social media. +## Fetching Related Records + +If you plan on using `useGetList` to fetch a list of records related to another one (e.g. the comments for a post), you're better off using [the `` component](./ReferenceManyField.md). It will handle the loading state for you, and display a loading spinner while the data is being fetched. + +```jsx +import { ReferenceManyField } from 'react-admin'; + +const PostComments = () => { + return ( + + + + + + + + ); +}; +``` + +is the equivalent of: + +```jsx +import { useGetList } from 'react-admin'; + +const PostComments = () => { + const record = useRecordContext(); + const { data, isLoading, error } = useGetList( + 'comments', + { filter: { post_id: record.id } } + ); + if (isLoading) { return ; } + if (error) { return

ERROR

; } + const listContext = useList({ data }); + return ( + + + + + + + + ); +}; +``` + ## Refreshing The List If you want to refresh the list, you can use the `refetch` function returned by the hook: diff --git a/examples/crm/src/Header.tsx b/examples/crm/src/Header.tsx index 0d2ab0956e7..1ff9f40947d 100644 --- a/examples/crm/src/Header.tsx +++ b/examples/crm/src/Header.tsx @@ -66,14 +66,8 @@ const Header = () => { /> - - + + diff --git a/examples/crm/src/deals/DealCreate.tsx b/examples/crm/src/deals/DealCreate.tsx index 58a6c991e24..ecd4e9bb387 100644 --- a/examples/crm/src/deals/DealCreate.tsx +++ b/examples/crm/src/deals/DealCreate.tsx @@ -13,6 +13,7 @@ import { useGetIdentity, useListContext, GetListResult, + DateInput, } from 'react-admin'; import { Dialog } from '@mui/material'; import { useQueryClient } from 'react-query'; @@ -107,6 +108,11 @@ export const DealCreate = ({ open }: { open: boolean }) => { validate={validateRequired} />
+ component for react-admin, useful for editing HTML code in admin GUIs.", "author": "Gildas Garcia", "repository": "marmelab/react-admin", @@ -51,10 +51,10 @@ "@testing-library/react": "^11.2.3", "@tiptap/extension-mention": "^2.0.3", "@tiptap/suggestion": "^2.0.3", - "data-generator-retail": "^4.16.12", - "ra-core": "^4.16.12", - "ra-data-fakerest": "^4.16.12", - "ra-ui-materialui": "^4.16.13", + "data-generator-retail": "^4.16.15", + "ra-core": "^4.16.15", + "ra-data-fakerest": "^4.16.15", + "ra-ui-materialui": "^4.16.15", "react": "^17.0.0", "react-dom": "^17.0.0", "react-hook-form": "^7.43.9", diff --git a/packages/ra-input-rich-text/src/RichTextInput.stories.tsx b/packages/ra-input-rich-text/src/RichTextInput.stories.tsx index 6ff51f2b453..ed633a74fc6 100644 --- a/packages/ra-input-rich-text/src/RichTextInput.stories.tsx +++ b/packages/ra-input-rich-text/src/RichTextInput.stories.tsx @@ -12,12 +12,14 @@ import { SimpleForm, SimpleFormProps, TopToolbar, + Toolbar as RAToolbar, + SaveButton, } from 'ra-ui-materialui'; import { useWatch } from 'react-hook-form'; import fakeRestDataProvider from 'ra-data-fakerest'; import { MemoryRouter, Routes, Route } from 'react-router-dom'; import Mention from '@tiptap/extension-mention'; -import { ReactRenderer } from '@tiptap/react'; +import { Editor, ReactRenderer } from '@tiptap/react'; import tippy, { Instance as TippyInstance } from 'tippy.js'; import { DefaultEditorOptions, @@ -26,12 +28,14 @@ import { } from './RichTextInput'; import { RichTextInputToolbar } from './RichTextInputToolbar'; import { + Button, List, ListItem, ListItemButton, ListItemText, Paper, } from '@mui/material'; +import { FormatButtons } from './buttons'; export default { title: 'ra-input-rich-text/RichTextInput' }; @@ -187,6 +191,69 @@ export const Validation = (props: Partial) => ( ); +const MyRichTextInputToolbar = ({ ...props }) => { + return ( + + + + ); +}; + +export const Toolbar = (props: Partial) => ( + + {}} + {...props} + > + } /> + + + +); + +export const EditorReference = (props: Partial) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const editorRef = React.useRef(null); + + const EditorToolbar = () => ( + + + + + ); + + return ( + + } + onSubmit={() => {}} + {...props} + > + { + editorRef.current = editor; + }, + }} + /> + + + + ); +}; + const dataProvider = fakeRestDataProvider({ posts: [ { id: 1, body: 'Post 1' }, diff --git a/packages/ra-language-english/package.json b/packages/ra-language-english/package.json index 678907cbf86..6abe50ee6fe 100644 --- a/packages/ra-language-english/package.json +++ b/packages/ra-language-english/package.json @@ -1,6 +1,6 @@ { "name": "ra-language-english", - "version": "4.16.12", + "version": "4.16.15", "description": "English messages for react-admin, the frontend framework for building admin applications on top of REST/GraphQL services", "repository": { "type": "git", @@ -21,7 +21,7 @@ "watch": "tsc --outDir dist/esm --module es2015 --watch" }, "dependencies": { - "ra-core": "^4.16.12" + "ra-core": "^4.16.15" }, "devDependencies": { "rimraf": "^3.0.2", diff --git a/packages/ra-language-french/package.json b/packages/ra-language-french/package.json index 872c676ba21..0b2f8a00992 100644 --- a/packages/ra-language-french/package.json +++ b/packages/ra-language-french/package.json @@ -1,6 +1,6 @@ { "name": "ra-language-french", - "version": "4.16.12", + "version": "4.16.15", "description": "French messages for react-admin, the frontend framework for building admin applications on top of REST/GraphQL services", "repository": { "type": "git", @@ -21,7 +21,7 @@ "watch": "tsc --outDir dist/esm --module es2015 --watch" }, "dependencies": { - "ra-core": "^4.16.12" + "ra-core": "^4.16.15" }, "devDependencies": { "rimraf": "^3.0.2", diff --git a/packages/ra-no-code/package.json b/packages/ra-no-code/package.json index 25a4e28ef85..6c9b7747f91 100644 --- a/packages/ra-no-code/package.json +++ b/packages/ra-no-code/package.json @@ -1,6 +1,6 @@ { "name": "ra-no-code", - "version": "4.16.13", + "version": "4.16.15", "description": "", "files": [ "*.md", @@ -48,8 +48,8 @@ "lodash": "~4.17.5", "papaparse": "^5.3.0", "prop-types": "^15.6.1", - "ra-data-local-storage": "^4.16.12", - "react-admin": "^4.16.13", + "ra-data-local-storage": "^4.16.15", + "react-admin": "^4.16.15", "react-dropzone": "^12.0.4", "react-query": "^3.32.1" }, diff --git a/packages/ra-ui-materialui/package.json b/packages/ra-ui-materialui/package.json index cc704944711..cf1053800cb 100644 --- a/packages/ra-ui-materialui/package.json +++ b/packages/ra-ui-materialui/package.json @@ -1,6 +1,6 @@ { "name": "ra-ui-materialui", - "version": "4.16.13", + "version": "4.16.15", "description": "UI Components for react-admin with Material UI", "files": [ "*.md", @@ -35,9 +35,9 @@ "file-api": "~0.10.4", "history": "^5.1.0", "ignore-styles": "~5.0.1", - "ra-core": "^4.16.12", - "ra-i18n-polyglot": "^4.16.12", - "ra-language-english": "^4.16.12", + "ra-core": "^4.16.15", + "ra-i18n-polyglot": "^4.16.15", + "ra-language-english": "^4.16.15", "react": "^17.0.0", "react-dom": "^17.0.0", "react-hook-form": "^7.43.9", diff --git a/packages/ra-ui-materialui/src/button/UpdateButton.tsx b/packages/ra-ui-materialui/src/button/UpdateButton.tsx index 0a01ed08526..67b29f182f6 100644 --- a/packages/ra-ui-materialui/src/button/UpdateButton.tsx +++ b/packages/ra-ui-materialui/src/button/UpdateButton.tsx @@ -10,7 +10,7 @@ import { } from './UpdateWithUndoButton'; /** - * Updates the selected rows. + * Updates the current record. * * To be used inside the prop or prop. * diff --git a/packages/ra-ui-materialui/src/detail/EditView.tsx b/packages/ra-ui-materialui/src/detail/EditView.tsx index c151c6574b4..061ed9e66dc 100644 --- a/packages/ra-ui-materialui/src/detail/EditView.tsx +++ b/packages/ra-ui-materialui/src/detail/EditView.tsx @@ -39,16 +39,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 = ( + + ); + } 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, { diff --git a/packages/ra-ui-materialui/src/detail/ShowView.tsx b/packages/ra-ui-materialui/src/detail/ShowView.tsx index 5dd0cd1e0c9..1663a6351e0 100644 --- a/packages/ra-ui-materialui/src/detail/ShowView.tsx +++ b/packages/ra-ui-materialui/src/detail/ShowView.tsx @@ -3,7 +3,7 @@ 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'; @@ -11,7 +11,9 @@ 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, @@ -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, { @@ -55,7 +65,9 @@ export const ShowView = (props: ShowViewProps) => { ); }; -export type ShowViewProps = ShowProps; +export type ShowViewProps<RecordType extends RaRecord = any> = ShowProps< + RecordType +>; ShowView.propTypes = { actions: PropTypes.oneOfType([PropTypes.element, PropTypes.bool]), diff --git a/packages/ra-ui-materialui/src/list/filter/FilterButton.stories.tsx b/packages/ra-ui-materialui/src/list/filter/FilterButton.stories.tsx index 80126fdc8b4..55a09d3fed5 100644 --- a/packages/ra-ui-materialui/src/list/filter/FilterButton.stories.tsx +++ b/packages/ra-ui-materialui/src/list/filter/FilterButton.stories.tsx @@ -12,6 +12,7 @@ import { TextInput, TopToolbar, SearchInput, + FilterButtonProps, } from 'react-admin'; import fakerestDataProvider from 'ra-data-fakerest'; import { @@ -162,6 +163,7 @@ const data = { const ListToolbar = (props: { postFilters: React.ReactElement[]; args: { disableSaveQuery?: boolean }; + buttonProps?: FilterButtonProps; }) => { return ( <TopToolbar> @@ -170,6 +172,7 @@ const ListToolbar = (props: { <FilterButton filters={props.postFilters} disableSaveQuery={props.args.disableSaveQuery} + {...props.buttonProps} /> <CreateButton /> </div> @@ -179,17 +182,24 @@ const ListToolbar = (props: { const PostList = (props: { postFilters: React.ReactElement[]; args: { disableSaveQuery?: boolean }; -}) => ( - <ListBase> - <ListToolbar postFilters={props.postFilters} args={props.args} /> - <Datagrid> - <TextField source="id" /> - <TextField source="title" /> - <TextField source="body" /> - </Datagrid> - <Pagination /> - </ListBase> -); + buttonProps?: FilterButtonProps; +}) => { + return ( + <ListBase> + <ListToolbar + postFilters={props.postFilters} + args={props.args} + buttonProps={props.buttonProps} + /> + <Datagrid> + <TextField source="id" /> + <TextField source="title" /> + <TextField source="body" /> + </Datagrid> + <Pagination /> + </ListBase> + ); +}; export const Basic = (args: { disableSaveQuery?: boolean }) => { const postFilters: React.ReactElement[] = [ @@ -372,3 +382,65 @@ export const WithAutoCompleteArrayInput = (args: { </MemoryRouter> ); }; + +export const Variant = () => { + const postFilters: React.ReactElement[] = [ + <TextInput + label="Title" + source="title" + defaultValue="Accusantium qui nihil voluptatum quia voluptas maxime ab similique" + />, + ]; + return ( + <MemoryRouter> + <Admin + dataProvider={fakerestDataProvider(data)} + store={memoryStore()} + > + <Resource + name="posts" + list={ + <PostList + postFilters={postFilters} + args={{}} + buttonProps={{ + variant: 'outlined', + }} + /> + } + /> + </Admin> + </MemoryRouter> + ); +}; + +export const Size = () => { + const postFilters: React.ReactElement[] = [ + <TextInput + label="Title" + source="title" + defaultValue="Accusantium qui nihil voluptatum quia voluptas maxime ab similique" + />, + ]; + return ( + <MemoryRouter> + <Admin + dataProvider={fakerestDataProvider(data)} + store={memoryStore()} + > + <Resource + name="posts" + list={ + <PostList + postFilters={postFilters} + args={{}} + buttonProps={{ + size: 'large', + }} + /> + } + /> + </Admin> + </MemoryRouter> + ); +}; diff --git a/packages/ra-ui-materialui/src/list/filter/FilterButton.tsx b/packages/ra-ui-materialui/src/list/filter/FilterButton.tsx index 8bc828ede50..a1e3ac38aea 100644 --- a/packages/ra-ui-materialui/src/list/filter/FilterButton.tsx +++ b/packages/ra-ui-materialui/src/list/filter/FilterButton.tsx @@ -8,7 +8,12 @@ import { useContext, } from 'react'; import PropTypes from 'prop-types'; -import { Menu, MenuItem, styled } from '@mui/material'; +import { + Menu, + MenuItem, + styled, + ButtonProps as MuiButtonProps, +} from '@mui/material'; import ContentFilter from '@mui/icons-material/FilterList'; import lodashGet from 'lodash/get'; import isEqual from 'lodash/isEqual'; @@ -28,6 +33,8 @@ export const FilterButton = (props: FilterButtonProps): JSX.Element => { filters: filtersProp, className, disableSaveQuery, + size, + variant, ...rest } = props; const filters = useContext(FilterContext) || filtersProp; @@ -141,6 +148,8 @@ export const FilterButton = (props: FilterButtonProps): JSX.Element => { label="ra.action.add_filter" aria-haspopup="true" onClick={handleClickButton} + variant={variant} + size={size} > <ContentFilter /> </Button> @@ -256,7 +265,9 @@ FilterButton.propTypes = { className: PropTypes.string, }; -export interface FilterButtonProps extends HtmlHTMLAttributes<HTMLDivElement> { +export interface FilterButtonProps + extends HtmlHTMLAttributes<HTMLDivElement>, + Pick<MuiButtonProps, 'variant' | 'size'> { className?: string; resource?: string; filterValues?: any; diff --git a/packages/ra-ui-materialui/src/types.ts b/packages/ra-ui-materialui/src/types.ts index 8745c05719e..43f70e59fb1 100644 --- a/packages/ra-ui-materialui/src/types.ts +++ b/packages/ra-ui-materialui/src/types.ts @@ -31,7 +31,11 @@ export interface EditProps< redirect?: RedirectionSideEffect; resource?: string; transform?: TransformData; - title?: string | ReactElement; + title?: + | string + | ReactElement + | false + | ((arg0: RecordType | undefined) => string); sx?: SxProps; } @@ -71,7 +75,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); sx?: SxProps; } diff --git a/packages/react-admin/package.json b/packages/react-admin/package.json index a3b6851cc2a..ac016c4ec14 100644 --- a/packages/react-admin/package.json +++ b/packages/react-admin/package.json @@ -1,6 +1,6 @@ { "name": "react-admin", - "version": "4.16.13", + "version": "4.16.15", "description": "A frontend Framework for building admin applications on top of REST services, using ES6, React and Material UI", "files": [ "*.md", @@ -41,10 +41,10 @@ "@mui/icons-material": "^5.0.1", "@mui/material": "^5.0.2", "history": "^5.1.0", - "ra-core": "^4.16.12", - "ra-i18n-polyglot": "^4.16.12", - "ra-language-english": "^4.16.12", - "ra-ui-materialui": "^4.16.13", + "ra-core": "^4.16.15", + "ra-i18n-polyglot": "^4.16.15", + "ra-language-english": "^4.16.15", + "ra-ui-materialui": "^4.16.15", "react-hook-form": "^7.43.9", "react-router": "^6.1.0", "react-router-dom": "^6.1.0" diff --git a/yarn.lock b/yarn.lock index 37f1a6c156a..78c40390180 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8004,30 +8004,32 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.19.2": - version: 1.19.2 - resolution: "body-parser@npm:1.19.2" +"body-parser@npm:1.20.1": + version: 1.20.1 + resolution: "body-parser@npm:1.20.1" dependencies: bytes: 3.1.2 content-type: ~1.0.4 debug: 2.6.9 - depd: ~1.1.2 - http-errors: 1.8.1 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 iconv-lite: 0.4.24 - on-finished: ~2.3.0 - qs: 6.9.7 - raw-body: 2.4.3 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.1 type-is: ~1.6.18 - checksum: 02158280b090d0ad99dfdc795b7d580762601283e4bcbd29409c11b34d5cfd737f632447a073bc2e79492d303827bd155fef2d63a333cdec18a87846221cee5e + unpipe: 1.0.0 + checksum: a202d493e2c10a33fb7413dac7d2f713be579c4b88343cd814b6df7a38e5af1901fc31044e04de176db56b16d9772aa25a7723f64478c20f4d91b1ac223bf3b8 languageName: node linkType: hard -"body-parser@npm:1.20.1": - version: 1.20.1 - resolution: "body-parser@npm:1.20.1" +"body-parser@npm:1.20.2": + version: 1.20.2 + resolution: "body-parser@npm:1.20.2" dependencies: bytes: 3.1.2 - content-type: ~1.0.4 + content-type: ~1.0.5 debug: 2.6.9 depd: 2.0.0 destroy: 1.2.0 @@ -8035,10 +8037,10 @@ __metadata: iconv-lite: 0.4.24 on-finished: 2.4.1 qs: 6.11.0 - raw-body: 2.5.1 + raw-body: 2.5.2 type-is: ~1.6.18 unpipe: 1.0.0 - checksum: a202d493e2c10a33fb7413dac7d2f713be579c4b88343cd814b6df7a38e5af1901fc31044e04de176db56b16d9772aa25a7723f64478c20f4d91b1ac223bf3b8 + checksum: 06f1438fff388a2e2354c96aa3ea8147b79bfcb1262dfcc2aae68ec13723d01d5781680657b74e9f83c808266d5baf52804032fbde2b7382b89bd8cdb273ace9 languageName: node linkType: hard @@ -9028,6 +9030,13 @@ __metadata: languageName: node linkType: hard +"content-type@npm:~1.0.5": + version: 1.0.5 + resolution: "content-type@npm:1.0.5" + checksum: b76ebed15c000aee4678c3707e0860cb6abd4e680a598c0a26e17f0bfae723ec9cc2802f0ff1bc6e4d80603719010431d2231018373d4dde10f9ccff9dadf5af + languageName: node + linkType: hard + "conventional-changelog-angular@npm:6.0.0": version: 6.0.0 resolution: "conventional-changelog-angular@npm:6.0.0" @@ -9151,13 +9160,6 @@ __metadata: languageName: node linkType: hard -"cookie@npm:0.4.2": - version: 0.4.2 - resolution: "cookie@npm:0.4.2" - checksum: beab41fbd7c20175e3a2799ba948c1dcc71ef69f23fe14eeeff59fc09f50c517b0f77098db87dbb4c55da802f9d86ee86cdc1cd3efd87760341551838d53fca2 - languageName: node - linkType: hard - "cookie@npm:0.5.0": version: 0.5.0 resolution: "cookie@npm:0.5.0" @@ -9165,6 +9167,13 @@ __metadata: languageName: node linkType: hard +"cookie@npm:0.6.0": + version: 0.6.0 + resolution: "cookie@npm:0.6.0" + checksum: f2318b31af7a31b4ddb4a678d024514df5e705f9be5909a192d7f116cfb6d45cbacf96a473fa733faa95050e7cff26e7832bb3ef94751592f1387b71c8956686 + languageName: node + linkType: hard + "core-js-compat@npm:^3.20.0, core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.32.2": version: 3.33.1 resolution: "core-js-compat@npm:3.33.1" @@ -9678,14 +9687,14 @@ __metadata: languageName: node linkType: hard -"data-generator-retail@^4.12.0, data-generator-retail@^4.16.12, data-generator-retail@workspace:examples/data-generator": +"data-generator-retail@^4.12.0, data-generator-retail@^4.16.15, data-generator-retail@workspace:examples/data-generator": version: 0.0.0-use.local resolution: "data-generator-retail@workspace:examples/data-generator" dependencies: cross-env: ^5.2.0 date-fns: ^2.19.0 faker: ^4.1.0 - ra-core: ^4.16.12 + ra-core: ^4.16.15 rimraf: ^3.0.2 typescript: ^5.1.3 peerDependencies: @@ -9971,13 +9980,6 @@ __metadata: languageName: node linkType: hard -"destroy@npm:~1.0.4": - version: 1.0.4 - resolution: "destroy@npm:1.0.4" - checksum: eab493808ba17a1fa22c71ef1a4e68d2c4c5222a38040606c966d2ab09117f3a7f3e05c39bffbe41a697f9de552039e43c30e46f0c3eab3faa9f82e800e172a0 - languageName: node - linkType: hard - "detect-indent@npm:^5.0.0": version: 5.0.0 resolution: "detect-indent@npm:5.0.0" @@ -10245,7 +10247,7 @@ __metadata: cypress: ^10.9.0 cypress-plugin-tab: ^1.0.5 cypress-vite: ^1.4.0 - express: ~4.17.3 + express: ~4.19.2 languageName: unknown linkType: soft @@ -11369,41 +11371,42 @@ __metadata: languageName: node linkType: hard -"express@npm:~4.17.3": - version: 4.17.3 - resolution: "express@npm:4.17.3" +"express@npm:~4.19.2": + version: 4.19.2 + resolution: "express@npm:4.19.2" dependencies: accepts: ~1.3.8 array-flatten: 1.1.1 - body-parser: 1.19.2 + body-parser: 1.20.2 content-disposition: 0.5.4 content-type: ~1.0.4 - cookie: 0.4.2 + cookie: 0.6.0 cookie-signature: 1.0.6 debug: 2.6.9 - depd: ~1.1.2 + depd: 2.0.0 encodeurl: ~1.0.2 escape-html: ~1.0.3 etag: ~1.8.1 - finalhandler: ~1.1.2 + finalhandler: 1.2.0 fresh: 0.5.2 + http-errors: 2.0.0 merge-descriptors: 1.0.1 methods: ~1.1.2 - on-finished: ~2.3.0 + on-finished: 2.4.1 parseurl: ~1.3.3 path-to-regexp: 0.1.7 proxy-addr: ~2.0.7 - qs: 6.9.7 + qs: 6.11.0 range-parser: ~1.2.1 safe-buffer: 5.2.1 - send: 0.17.2 - serve-static: 1.14.2 + send: 0.18.0 + serve-static: 1.15.0 setprototypeof: 1.2.0 - statuses: ~1.5.0 + statuses: 2.0.1 type-is: ~1.6.18 utils-merge: 1.0.1 vary: ~1.1.2 - checksum: 8fa8a8ae26bd11082b575ddfecdfe51ca535e048ebcf58455e3f813aacc1712e09a297a511efb0e4843e2d2a413cb8c1cd6b81f79371e50d7b8efb1aa6b8d5af + checksum: e82e2662ea9971c1407aea9fc3c16d6b963e55e3830cd0ef5e00b533feda8b770af4e3be630488ef8a752d7c75c4fcefb15892868eeaafe7353cb9e3e269fdcb languageName: node linkType: hard @@ -11744,21 +11747,6 @@ __metadata: languageName: node linkType: hard -"finalhandler@npm:~1.1.2": - version: 1.1.2 - resolution: "finalhandler@npm:1.1.2" - dependencies: - debug: 2.6.9 - encodeurl: ~1.0.2 - escape-html: ~1.0.3 - on-finished: ~2.3.0 - parseurl: ~1.3.3 - statuses: ~1.5.0 - unpipe: ~1.0.0 - checksum: 6a96e1f5caab085628c11d9fdceb82ba608d5e426c6913d4d918409baa271037a47f28fbba73279e8ad614f0b8fa71ea791d265e408d760793829edd8c2f4584 - languageName: node - linkType: hard - "find-cache-dir@npm:^2.0.0": version: 2.1.0 resolution: "find-cache-dir@npm:2.1.0" @@ -12881,19 +12869,6 @@ __metadata: languageName: node linkType: hard -"http-errors@npm:1.8.1": - version: 1.8.1 - resolution: "http-errors@npm:1.8.1" - dependencies: - depd: ~1.1.2 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: ">= 1.5.0 < 2" - toidentifier: 1.0.1 - checksum: f01aeecd76260a6fe7f08e192fcbe9b2f39ed20fc717b852669a69930167053b01790998275c6297d44f435cf0e30edd50c05223d1bec9bc484e6cf35b2d6f43 - languageName: node - linkType: hard - "http-errors@npm:2.0.0": version: 2.0.0 resolution: "http-errors@npm:2.0.0" @@ -16661,15 +16636,6 @@ __metadata: languageName: node linkType: hard -"on-finished@npm:~2.3.0": - version: 2.3.0 - resolution: "on-finished@npm:2.3.0" - dependencies: - ee-first: 1.1.1 - checksum: c904f9e518b11941eb60279a3cbfaf1289bd0001f600a950255b1dede9fe3df8cd74f38483550b3bb9485165166acb5db500c3b4c4337aec2815c88c96fcc2ea - languageName: node - linkType: hard - "on-headers@npm:~1.0.2": version: 1.0.2 resolution: "on-headers@npm:1.0.2" @@ -17936,13 +17902,6 @@ __metadata: languageName: node linkType: hard -"qs@npm:6.9.7": - version: 6.9.7 - resolution: "qs@npm:6.9.7" - checksum: d0274b3c2daa9e7b350fb695fc4b5f7a1e65e266d5798a07936975f0848bdca6d7ad41cded19ad4af6a6253b97e43b497e988e728eab7a286f277b6dddfbade4 - languageName: node - linkType: hard - "qs@npm:~6.5.2": version: 6.5.3 resolution: "qs@npm:6.5.3" @@ -17997,7 +17956,7 @@ __metadata: languageName: node linkType: hard -"ra-core@^4.16.12, ra-core@workspace:packages/ra-core": +"ra-core@^4.16.15, ra-core@workspace:packages/ra-core": version: 0.0.0-use.local resolution: "ra-core@workspace:packages/ra-core" dependencies: @@ -18043,7 +18002,7 @@ __metadata: languageName: unknown linkType: soft -"ra-data-fakerest@^4.12.0, ra-data-fakerest@^4.16.12, ra-data-fakerest@workspace:packages/ra-data-fakerest": +"ra-data-fakerest@^4.12.0, ra-data-fakerest@^4.16.15, ra-data-fakerest@workspace:packages/ra-data-fakerest": version: 0.0.0-use.local resolution: "ra-data-fakerest@workspace:packages/ra-data-fakerest" dependencies: @@ -18051,7 +18010,7 @@ __metadata: cross-env: ^5.2.0 expect: ^27.4.6 fakerest: ^3.0.0 - ra-core: ^4.16.12 + ra-core: ^4.16.15 rimraf: ^3.0.2 typescript: ^5.1.3 peerDependencies: @@ -18069,7 +18028,7 @@ __metadata: graphql-ast-types-browser: ~1.0.2 lodash: ~4.17.5 pluralize: ~7.0.0 - ra-data-graphql: ^4.16.12 + ra-data-graphql: ^4.16.15 rimraf: ^3.0.2 typescript: ^5.1.3 peerDependencies: @@ -18078,7 +18037,7 @@ __metadata: languageName: unknown linkType: soft -"ra-data-graphql@^4.12.0, ra-data-graphql@^4.16.12, ra-data-graphql@workspace:packages/ra-data-graphql": +"ra-data-graphql@^4.12.0, ra-data-graphql@^4.16.15, ra-data-graphql@workspace:packages/ra-data-graphql": version: 0.0.0-use.local resolution: "ra-data-graphql@workspace:packages/ra-data-graphql" dependencies: @@ -18101,7 +18060,7 @@ __metadata: dependencies: cross-env: ^5.2.0 query-string: ^7.1.1 - ra-core: ^4.16.12 + ra-core: ^4.16.15 rimraf: ^3.0.2 typescript: ^5.1.3 languageName: unknown @@ -18114,7 +18073,7 @@ __metadata: cross-env: ^5.2.0 localforage: ^1.7.1 lodash: ~4.17.5 - ra-data-fakerest: ^4.16.12 + ra-data-fakerest: ^4.16.15 rimraf: ^3.0.2 typescript: ^5.1.3 peerDependencies: @@ -18122,13 +18081,13 @@ __metadata: languageName: unknown linkType: soft -"ra-data-local-storage@^4.12.0, ra-data-local-storage@^4.16.12, ra-data-local-storage@workspace:packages/ra-data-localstorage": +"ra-data-local-storage@^4.12.0, ra-data-local-storage@^4.16.15, ra-data-local-storage@workspace:packages/ra-data-localstorage": version: 0.0.0-use.local resolution: "ra-data-local-storage@workspace:packages/ra-data-localstorage" dependencies: cross-env: ^5.2.0 lodash: ~4.17.5 - ra-data-fakerest: ^4.16.12 + ra-data-fakerest: ^4.16.15 rimraf: ^3.0.2 typescript: ^5.1.3 peerDependencies: @@ -18142,7 +18101,7 @@ __metadata: dependencies: cross-env: ^5.2.0 query-string: ^7.1.1 - ra-core: ^4.16.12 + ra-core: ^4.16.15 rimraf: ^3.0.2 typescript: ^5.1.3 peerDependencies: @@ -18157,26 +18116,26 @@ __metadata: cross-env: ^5.2.0 i18next: ^23.5.1 i18next-resources-to-backend: ^1.1.4 - ra-core: ^4.16.12 + ra-core: ^4.16.15 react-i18next: ^13.2.2 rimraf: ^3.0.2 typescript: ^5.1.3 languageName: unknown linkType: soft -"ra-i18n-polyglot@^4.12.0, ra-i18n-polyglot@^4.16.12, ra-i18n-polyglot@workspace:packages/ra-i18n-polyglot": +"ra-i18n-polyglot@^4.12.0, ra-i18n-polyglot@^4.16.15, ra-i18n-polyglot@workspace:packages/ra-i18n-polyglot": version: 0.0.0-use.local resolution: "ra-i18n-polyglot@workspace:packages/ra-i18n-polyglot" dependencies: cross-env: ^5.2.0 node-polyglot: ^2.2.2 - ra-core: ^4.16.12 + ra-core: ^4.16.15 rimraf: ^3.0.2 typescript: ^5.1.3 languageName: unknown linkType: soft -"ra-input-rich-text@^4.12.0, ra-input-rich-text@^4.16.13, ra-input-rich-text@workspace:packages/ra-input-rich-text": +"ra-input-rich-text@^4.12.0, ra-input-rich-text@^4.16.15, ra-input-rich-text@workspace:packages/ra-input-rich-text": version: 0.0.0-use.local resolution: "ra-input-rich-text@workspace:packages/ra-input-rich-text" dependencies: @@ -18198,10 +18157,10 @@ __metadata: "@tiptap/starter-kit": ^2.0.3 "@tiptap/suggestion": ^2.0.3 clsx: ^1.1.1 - data-generator-retail: ^4.16.12 - ra-core: ^4.16.12 - ra-data-fakerest: ^4.16.12 - ra-ui-materialui: ^4.16.13 + data-generator-retail: ^4.16.15 + ra-core: ^4.16.15 + ra-data-fakerest: ^4.16.15 + ra-ui-materialui: ^4.16.15 react: ^17.0.0 react-dom: ^17.0.0 react-hook-form: ^7.43.9 @@ -18218,21 +18177,21 @@ __metadata: languageName: unknown linkType: soft -"ra-language-english@^4.12.0, ra-language-english@^4.16.12, ra-language-english@workspace:packages/ra-language-english": +"ra-language-english@^4.12.0, ra-language-english@^4.16.15, ra-language-english@workspace:packages/ra-language-english": version: 0.0.0-use.local resolution: "ra-language-english@workspace:packages/ra-language-english" dependencies: - ra-core: ^4.16.12 + ra-core: ^4.16.15 rimraf: ^3.0.2 typescript: ^5.1.3 languageName: unknown linkType: soft -"ra-language-french@^4.12.0, ra-language-french@^4.16.12, ra-language-french@workspace:packages/ra-language-french": +"ra-language-french@^4.12.0, ra-language-french@^4.16.15, ra-language-french@workspace:packages/ra-language-french": version: 0.0.0-use.local resolution: "ra-language-french@workspace:packages/ra-language-french" dependencies: - ra-core: ^4.16.12 + ra-core: ^4.16.15 rimraf: ^3.0.2 typescript: ^5.1.3 languageName: unknown @@ -18253,9 +18212,9 @@ __metadata: lodash: ~4.17.5 papaparse: ^5.3.0 prop-types: ^15.6.1 - ra-data-local-storage: ^4.16.12 + ra-data-local-storage: ^4.16.15 react: ^17.0.0 - react-admin: ^4.16.13 + react-admin: ^4.16.15 react-dom: ^17.0.0 react-dropzone: ^12.0.4 react-query: ^3.32.1 @@ -18269,7 +18228,7 @@ __metadata: languageName: unknown linkType: soft -"ra-ui-materialui@^4.16.13, ra-ui-materialui@workspace:packages/ra-ui-materialui": +"ra-ui-materialui@^4.16.15, ra-ui-materialui@workspace:packages/ra-ui-materialui": version: 0.0.0-use.local resolution: "ra-ui-materialui@workspace:packages/ra-ui-materialui" dependencies: @@ -18292,9 +18251,9 @@ __metadata: lodash: ~4.17.5 prop-types: ^15.7.0 query-string: ^7.1.1 - ra-core: ^4.16.12 - ra-i18n-polyglot: ^4.16.12 - ra-language-english: ^4.16.12 + ra-core: ^4.16.15 + ra-i18n-polyglot: ^4.16.15 + ra-language-english: ^4.16.15 react: ^17.0.0 react-dom: ^17.0.0 react-dropzone: ^12.0.4 @@ -18360,27 +18319,27 @@ __metadata: languageName: node linkType: hard -"raw-body@npm:2.4.3": - version: 2.4.3 - resolution: "raw-body@npm:2.4.3" +"raw-body@npm:2.5.1, raw-body@npm:^2.4.1": + version: 2.5.1 + resolution: "raw-body@npm:2.5.1" dependencies: bytes: 3.1.2 - http-errors: 1.8.1 + http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 - checksum: e25ac143c0638dac75b7228de378f60d9438dd1a9b83ffcc6935d5a1e2d599ad3cdc9d24e80eb8cf07a7ec4f5d57a692d243abdcb2449cf11605ef9e5fe6af06 + checksum: 5dad5a3a64a023b894ad7ab4e5c7c1ce34d3497fc7138d02f8c88a3781e68d8a55aa7d4fd3a458616fa8647cc228be314a1c03fb430a07521de78b32c4dd09d2 languageName: node linkType: hard -"raw-body@npm:2.5.1, raw-body@npm:^2.4.1": - version: 2.5.1 - resolution: "raw-body@npm:2.5.1" +"raw-body@npm:2.5.2": + version: 2.5.2 + resolution: "raw-body@npm:2.5.2" dependencies: bytes: 3.1.2 http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 - checksum: 5dad5a3a64a023b894ad7ab4e5c7c1ce34d3497fc7138d02f8c88a3781e68d8a55aa7d4fd3a458616fa8647cc228be314a1c03fb430a07521de78b32c4dd09d2 + checksum: b201c4b66049369a60e766318caff5cb3cc5a900efd89bdac431463822d976ad0670912c931fdbdcf5543207daf6f6833bca57aa116e1661d2ea91e12ca692c4 languageName: node linkType: hard @@ -18471,7 +18430,7 @@ __metadata: languageName: unknown linkType: soft -"react-admin@^4.12.0, react-admin@^4.16.13, react-admin@workspace:packages/react-admin": +"react-admin@^4.12.0, react-admin@^4.16.15, react-admin@workspace:packages/react-admin": version: 0.0.0-use.local resolution: "react-admin@workspace:packages/react-admin" dependencies: @@ -18482,10 +18441,10 @@ __metadata: cross-env: ^5.2.0 expect: ^27.4.6 history: ^5.1.0 - ra-core: ^4.16.12 - ra-i18n-polyglot: ^4.16.12 - ra-language-english: ^4.16.12 - ra-ui-materialui: ^4.16.13 + ra-core: ^4.16.15 + ra-i18n-polyglot: ^4.16.15 + ra-language-english: ^4.16.15 + ra-ui-materialui: ^4.16.15 react-hook-form: ^7.43.9 react-router: ^6.1.0 react-router-dom: ^6.1.0 @@ -19810,27 +19769,6 @@ __metadata: languageName: node linkType: hard -"send@npm:0.17.2": - version: 0.17.2 - resolution: "send@npm:0.17.2" - dependencies: - debug: 2.6.9 - depd: ~1.1.2 - destroy: ~1.0.4 - encodeurl: ~1.0.2 - escape-html: ~1.0.3 - etag: ~1.8.1 - fresh: 0.5.2 - http-errors: 1.8.1 - mime: 1.6.0 - ms: 2.1.3 - on-finished: ~2.3.0 - range-parser: ~1.2.1 - statuses: ~1.5.0 - checksum: 0f92f0fcd298fcdd759dc7d501bfab79635f549ec3b885e26e4a62b3094420b355d73f2d59749b6004019a4c91db983fb1715378aa622f4bf4e21b0b79853e5c - languageName: node - linkType: hard - "send@npm:0.18.0": version: 0.18.0 resolution: "send@npm:0.18.0" @@ -19861,18 +19799,6 @@ __metadata: languageName: node linkType: hard -"serve-static@npm:1.14.2": - version: 1.14.2 - resolution: "serve-static@npm:1.14.2" - dependencies: - encodeurl: ~1.0.2 - escape-html: ~1.0.3 - parseurl: ~1.3.3 - send: 0.17.2 - checksum: 4583f8bec8daa74df58fd7415e6f58039223becbb6c7ac0e6386c4fbe5c825195df92c73f999a1404487ae1d1bd1d20dd7ae11bc19f8788225770d1960bbeaea - languageName: node - linkType: hard - "serve-static@npm:1.15.0": version: 1.15.0 resolution: "serve-static@npm:1.15.0" @@ -20010,13 +19936,13 @@ __metadata: lodash: ~4.17.5 prop-types: ^15.7.2 proxy-polyfill: ^0.3.0 - ra-data-fakerest: ^4.16.12 - ra-i18n-polyglot: ^4.16.12 - ra-input-rich-text: ^4.16.13 - ra-language-english: ^4.16.12 - ra-language-french: ^4.16.12 + ra-data-fakerest: ^4.16.15 + ra-i18n-polyglot: ^4.16.15 + ra-input-rich-text: ^4.16.15 + ra-language-english: ^4.16.15 + ra-language-french: ^4.16.15 react: ^17.0.0 - react-admin: ^4.16.13 + react-admin: ^4.16.15 react-app-polyfill: ^1.0.4 react-dom: ^17.0.0 react-hook-form: ^7.43.9 @@ -20356,7 +20282,7 @@ __metadata: languageName: node linkType: hard -"statuses@npm:>= 1.5.0 < 2, statuses@npm:~1.5.0": +"statuses@npm:>= 1.5.0 < 2": version: 1.5.0 resolution: "statuses@npm:1.5.0" checksum: e433900956357b3efd79b1c547da4d291799ac836960c016d10a98f6a810b1b5c0dcc13b5a7aa609a58239b5190e1ea176ad9221c2157d2fd1c747393e6b2940 @@ -21787,8 +21713,8 @@ __metadata: linkType: hard "vite@npm:^3.2.0": - version: 3.2.8 - resolution: "vite@npm:3.2.8" + version: 3.2.10 + resolution: "vite@npm:3.2.10" dependencies: esbuild: ^0.15.9 fsevents: ~2.3.2 @@ -21820,7 +21746,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: fd91c07e75381f17f7e0b212e75b313075ea7634dd84b91859d34fa8eb26dc02201af5ee0be0b087fdac86c90d447e4bfeb9588d308fafecaf3b44a868a46c41 + checksum: c5316e393ea392131c2fb7985bd89a4e10ec4bb656a52d709f2f975cb59d59ce6e479aabcc90e572ba1762ce3644195bd30c70e11dd552b3236bab2638206021 languageName: node linkType: hard @@ -21913,8 +21839,8 @@ __metadata: linkType: hard "webpack-dev-middleware@npm:^6.1.1": - version: 6.1.1 - resolution: "webpack-dev-middleware@npm:6.1.1" + version: 6.1.2 + resolution: "webpack-dev-middleware@npm:6.1.2" dependencies: colorette: ^2.0.10 memfs: ^3.4.12 @@ -21926,7 +21852,7 @@ __metadata: peerDependenciesMeta: webpack: optional: true - checksum: f8f5b7f7591fa3e4d4008b28ab2b5c13367a24587257e3e37cff31e2d8a6c859de5294af83c79e8faf3137db194377f392fffacdf5010b5c1311eba6f9b71568 + checksum: 90c415a770c7db493f4a7d8f3308d761ff63249f628fa8a133eac5a61e849cdf658398e189fc2d95ce0ea884641363f964db6b269c6cea877765321dd7f14b9a languageName: node linkType: hard