diff --git a/CHANGELOG.md b/CHANGELOG.md index b47091fc2f4..e458f1bd8f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,34 @@ # Changelog +## v4.10.2 + +* Fix custom redirect in pessimistic `` or `` when using `warnWhenUnsavedChanges` ([#8882](https://github.com/marmelab/react-admin/pull/8882)) ([slax57](https://github.com/slax57)) +* Fix `create-react-admin` package manifest ([#8888](https://github.com/marmelab/react-admin/pull/8888)) ([djhi](https://github.com/djhi)) +* [Doc] Fix `` example should use the `name` prop ([#8886](https://github.com/marmelab/react-admin/pull/8886)) ([septentrion-730n](https://github.com/septentrion-730n)) +* [Doc] Update DataProvider List with `ra-strapi-rest` v4 ([#8865](https://github.com/marmelab/react-admin/pull/8865)) ([nazirov91](https://github.com/nazirov91)) + +## v4.10.1 + +* Republish all packages, including the `create-react-admin` installer ([fzaninotto](https://github.com/fzaninotto)) + +## v4.10.0 + +Note: This release wasn't published to npm, use version 4.10.1 or higher. + +* Add `create-react-admin` installer ([#8833](https://github.com/marmelab/react-admin/pull/8833)) ([djhi](https://github.com/djhi)) +* Add `` and `` components ([#8781](https://github.com/marmelab/react-admin/pull/8781)) ([fzaninotto](https://github.com/fzaninotto)) +* Add ability to change the sort, filter and selection of `` ([#8802](https://github.com/marmelab/react-admin/pull/8802)) ([fzaninotto](https://github.com/fzaninotto)) +* Add ability to configure the remove icon of `` ([#8756](https://github.com/marmelab/react-admin/pull/8756)) ([PennyJeans](https://github.com/PennyJeans)) +* Fix `` does not apply `className` to its root element (minor BC) ([#8804](https://github.com/marmelab/react-admin/pull/8804)) ([slax57](https://github.com/slax57)) +* Fix `useHandleCallback` sometimes causes infinite redirection loop ([#8861](https://github.com/marmelab/react-admin/pull/8861)) ([djhi](https://github.com/djhi)) +* Fix `` hides sidebar menu on scroll ([#8856](https://github.com/marmelab/react-admin/pull/8856)) ([slax57](https://github.com/slax57)) +* Fix `` new item's fields default empty string instead of null ([#8792](https://github.com/marmelab/react-admin/pull/8792)) ([kriskw1999](https://github.com/kriskw1999)) +* [Doc] Fix reference to Material UI ([#8857](https://github.com/marmelab/react-admin/pull/8857)) ([oliviertassinari](https://github.com/oliviertassinari)) +* [Doc] Fix Show documentation misses the `aside` prop ([#8855](https://github.com/marmelab/react-admin/pull/8855)) ([fzaninotto](https://github.com/fzaninotto)) +* [Doc] Convert GIF files to WebM ([#8767](https://github.com/marmelab/react-admin/pull/8767)) ([slax57](https://github.com/slax57)) +* [TypeScript] Add some utilities to improve generics ([#8815](https://github.com/marmelab/react-admin/pull/8815)) ([IAmVisco](https://github.com/IAmVisco)) +* [TypeScript] Improve `useRedirect` and `useCreatePath` types ([#8811](https://github.com/marmelab/react-admin/pull/8811)) ([djhi](https://github.com/djhi)) + ## v4.9.4 * Fix GraphQL data provider when using different a custom credential type ([#8847](https://github.com/marmelab/react-admin/pull/8847)) ([@rlucia](https://github.com/rlucia)) diff --git a/cypress/package.json b/cypress/package.json index cc845237e8c..b0e24115c1b 100644 --- a/cypress/package.json +++ b/cypress/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "e2e", - "version": "4.9.0", + "version": "4.10.0", "scripts": { "start": "cypress open", "test": "yarn node ./start.js" diff --git a/docs/AuthProviderList.md b/docs/AuthProviderList.md index 90b65b3ce63..714d66fd8dc 100644 --- a/docs/AuthProviderList.md +++ b/docs/AuthProviderList.md @@ -7,15 +7,15 @@ 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](https://auth0.com/)**: [ra-auth-auth0](https://github.com/marmelab/ra-auth-auth0) +- **[Auth0](https://auth0.com/)**: [marmelab/ra-auth-auth0](https://github.com/marmelab/ra-auth-auth0) - **[AWS Amplify](https://docs.amplify.aws)**: [MrHertal/react-admin-amplify](https://github.com/MrHertal/react-admin-amplify) -- **[AWS Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/setting-up-the-javascript-sdk.html)**: [ra-auth-cognito](https://github.com/marmelab/ra-auth-cognito) +- **[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) +- **[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) - **[Directus](https://directus.io/)**: [marmelab/ra-directus](https://github.com/marmelab/ra-directus) - **[Firebase Auth (Google, Facebook, GitHub, etc.)](https://firebase.google.com/docs/auth/web/firebaseui)**: [benwinding/react-admin-firebase](https://github.com/benwinding/react-admin-firebase#auth-provider) -- **[Postgrest](https://postgrest.org/): [raphiniert-com/ra-data-postgrest](https://github.com/raphiniert-com/ra-data-postgrest) -- **[Supabase](https://supabase.io/)**: [marmelab/ra-supabase](https://github.com/marmelab/ra-supabase) - **[Keycloak](https://www.keycloak.org/)**: [marmelab/ra-keycloak](https://github.com/marmelab/ra-keycloak) -- **[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) +- **[Postgrest](https://postgrest.org/)**: [raphiniert-com/ra-data-postgrest](https://github.com/raphiniert-com/ra-data-postgrest) +- **[Supabase](https://supabase.io/)**: [marmelab/ra-supabase](https://github.com/marmelab/ra-supabase) - **[SurrealDB](https://surrealdb.com/)**: [djedi23/ra-surrealdb](https://github.com/djedi23/ra-surrealdb) Beyond ready-to-use providers, you may find help in these third-party tutorials about integrating more authentication backends: diff --git a/docs/CreateReactAdmin.md b/docs/CreateReactAdmin.md new file mode 100644 index 00000000000..ea1a9a65b5c --- /dev/null +++ b/docs/CreateReactAdmin.md @@ -0,0 +1,25 @@ +--- +layout: default +title: "The create-react-admin CLI" +--- + +# `create-react-admin` + +This CLI generates a new react-admin application using [Vite](https://vitejs.dev/). Use it by running the following command: + +```sh +npx create react-admin@latest your-admin-name +# or +yarn create react-admin your-admin-name +``` + +It will then ask you to choose: +- a data provider +- a auth provider +- the names of the resources to add +- the package manager to use to install the dependencies + + \ No newline at end of file diff --git a/docs/CustomRoutes.md b/docs/CustomRoutes.md index 36730c96be4..58de405c6a0 100644 --- a/docs/CustomRoutes.md +++ b/docs/CustomRoutes.md @@ -143,8 +143,8 @@ import PeopleIcon from '@mui/icons-material/People'; export const MyMenu = () => ( - - + + }/> }/> diff --git a/docs/DataProviderList.md b/docs/DataProviderList.md index aa62b463ee6..9a29e62b2e0 100644 --- a/docs/DataProviderList.md +++ b/docs/DataProviderList.md @@ -57,7 +57,7 @@ If you can't find a Data Provider for your backend below, no worries! [Writing a * **[SQLite](https://www.sqlite.org/index.html)**: [marmelab/ra-sqlite-dataprovider](https://github.com/marmelab/ra-sqlite-dataprovider) * **[REST](https://en.wikipedia.org/wiki/Representational_state_transfer)**: [marmelab/ra-data-simple-rest](https://github.com/marmelab/react-admin/tree/master/packages/ra-data-simple-rest) * **[Spring Boot](https://spring.io/projects/spring-boot)**: [vishpat/ra-data-springboot-rest](https://github.com/vishpat/ra-data-springboot-rest) -* **[Strapi v3](https://strapi.io/)**: [nazirov91/ra-strapi-rest](https://github.com/nazirov91/ra-strapi-rest) +* **[Strapi v3/v4](https://strapi.io/)**: [nazirov91/ra-strapi-rest](https://github.com/nazirov91/ra-strapi-rest) * **[Strapi v4](https://strapi.io/)**: [garridorafa/ra-strapi-v4-rest](https://github.com/garridorafa/ra-strapi-v4-rest) * **[Supabase](https://supabase.io/)**: [marmelab/ra-supabase](https://github.com/marmelab/ra-supabase) - **[SurrealDB](https://surrealdb.com/)**: [djedi23/ra-surrealdb](https://github.com/djedi23/ra-surrealdb) diff --git a/docs/RealtimeDataProvider.md b/docs/RealtimeDataProvider.md index 3d2a456b6a8..70f514d72b4 100644 --- a/docs/RealtimeDataProvider.md +++ b/docs/RealtimeDataProvider.md @@ -5,6 +5,16 @@ title: "Realtime DataProvider Requirements" # Realtime DataProvider Requirements +`ra-realtime` provides helper functions to add real-time capabilities to an existing data provider if you use the following real-time backends: + +- [Supabase](#supabase) +- [API Platform](#api-platform) +- [Mercure](#mercure) + +For other backends, you'll need to write your own implementation. Check the [Writing a custom adapter](#writing-a-custom-adapter) section below for more information. + +## Realtime Methods & Signature + To enable real-time features, the `dataProvider` must implement three new methods: - `subscribe(topic, callback)` @@ -20,7 +30,87 @@ In addition, to support the lock features, the `dataProvider` must implement 4 m - `getLock(resource, { id, meta })` - `getLocks(resource, { meta })` -## API-Platform Adapter +## Supabase + +The `ra-realtime` package contains a function augmenting a regular (API-based) `dataProvider` with real-time methods based on the capabilities of [Supabase](https://supabase.com/docs/guides/realtime). + +This adapter subscribes to [Postgres Changes](https://supabase.com/docs/guides/realtime/extensions/postgres-changes), and transforms the events into the format expected by `ra-realtime`. + +```jsx +import { createClient } from '@supabase/supabase-js'; +import { supabaseDataProvider } from 'ra-supabase'; +import { addRealTimeMethodsBasedOnSupabase, ListLive } from '@react-admin/ra-realtime'; +import { Admin, Resource, Datagrid, TextField, EmailField } from 'react-admin'; + +const supabaseClient = createClient( + process.env.SUPABASE_URL, + process.env.SUPABASE_ANON_KEY +); + +const dataProvider = supabaseDataProvider({ + instanceUrl: process.env.SUPABASE_URL, + apiKey: process.env.SUPABASE_ANON_KEY, + supabaseClient +}); + +const realTimeDataProvider = addRealTimeMethodsBasedOnSupabase({ + dataProvider, + supabaseClient, +}); + +export const App = () => ( + + + +); + +const SaleList = () => ( + + + + + + + + +); +``` + +**Tip:** Realtime features are not enabled in Supabase by default, you need to enable them. This can be done either from the [Replication](https://app.supabase.com/project/_/database/replication) section of your Supabase Dashboard, or by running the following SQL query with the [SQL Editor](https://app.supabase.com/project/_/sql): + +```sql +begin; + +-- remove the supabase_realtime publication +drop + publication if exists supabase_realtime; + +-- re-create the supabase_realtime publication with no tables +create publication supabase_realtime; + +commit; + +-- add a table to the publication +alter + publication supabase_realtime add table sales; +alter + publication supabase_realtime add table contacts; +alter + publication supabase_realtime add table contactNotes; +``` + +Have a look at the Supabase [Replication Setup](https://supabase.com/docs/guides/realtime/extensions/postgres-changes#replication-setup) documentation section for more info. + +`addRealTimeMethodsBasedOnSupabase` accepts the following parameters: + +| Prop | Required | Type | Default | Description | +| ----------------- | -------- | ---------------- | ------- | -------------------------------------------------------- | +| `dataProvider` | Required | `DataProvider` | - | The base dataProvider to augment with realtime methods | +| `supabaseClient` | Required | `SupabaseClient` | - | The Supabase JS Client | + +**Tip**: You may choose to sign your own tokens to customize claims that can be checked in your RLS policies. In order to use these custom tokens with `addRealTimeMethodsBasedOnSupabase`, you must pass an `apikey` field in both Realtime's `headers` and `params` when creating the `supabaseClient`. Please follow the instructions from the [Supabase documentation](https://supabase.com/docs/guides/realtime/extensions/postgres-changes#custom-tokens) for more information about how to do so. + +## API-Platform The `ra-realtime` package contains a function augmenting a regular (API-based) `dataProvider` with real-time methods based on the capabilities of [API-Platform](https://api-platform.com/). Use it as follows: @@ -70,7 +160,7 @@ const GreetingsList = () => ( ); ``` -## Mercure Adapter +## Mercure The `ra-realtime` package contains a function augmenting a regular (API-based) `dataProvider` with real-time methods based on [a Mercure hub](https://mercure.rocks/). Use it as follows: @@ -95,7 +185,7 @@ const App = () => ( If you're using another transport for real-time messages (WebSockets, long polling, GraphQL subscriptions, etc.), you'll have to implement `subscribe`, `unsubscribe`, and `publish` yourself in your `dataProvider`. As an example, here is an implementation using a local variable, that `ra-realtime` uses in tests: -```ts +```jsx let subscriptions = []; const dataProvider = { diff --git a/docs/ReferenceField.md b/docs/ReferenceField.md index c4861fd620c..e8b5eb7d14d 100644 --- a/docs/ReferenceField.md +++ b/docs/ReferenceField.md @@ -79,6 +79,7 @@ With this configuration, `` wraps the user's name in a link to t | `emptyText` | Optional | `string` | '' | Defines a text to be shown when the field has no value or when the reference is missing | | `label` | Optional | `string | Function` | `resources.[resource].fields.[source]` | Label to use for the field when rendered in layout components | | `link` | Optional | `string | Function` | `edit` | Target of the link wrapping the rendered child. Set to `false` to disable the link. | +| `queryOptions` | Optional | [`UseQueryOptions`](https://tanstack.com/query/v4/docs/reference/useQuery?from=reactQueryV3&original=https://react-query-v3.tanstack.com/reference/useQuery) | `{}` | `react-query` client options | | `sortBy` | Optional | `string | Function` | `source` | Name of the field to use for sorting when used in a Datagrid | `` also accepts the [common field props](./Fields.md#common-field-props). @@ -143,6 +144,22 @@ You can also use a custom `link` function to get a custom path for the children. /> ``` +## `queryOptions` + +Use the `queryOptions` prop to pass options to the `dataProvider.getMany()` query that fetches the referenced record. + +For instance, to pass [a custom `meta`](./Actions.md#meta-parameter): + +```jsx + + + +``` + ## `reference` The resource to fetch for the related record. diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 75183e1394f..ab587aa17f4 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -17,18 +17,24 @@ Here is an overview of the result: ## Setting Up -React-admin uses React. We'll use [Vite](https://vitejs.dev/) to create an empty React app, and install the `react-admin` package: +React-admin uses React. We'll use [create-react-admin](https://github.com/marmelab/react-admin/tree/master/packages/create-react-admin) to bootstrap a new admin: ```sh -yarn create vite test-admin --template react-ts -cd test-admin/ -yarn add react-admin ra-data-json-server +yarn create react-admin test-admin +``` + +Choose **JSON Server** as the data provider, then **None** as the auth provider. Don't add any resource for now and just press **Enter**. Finally, choose either `npm` or `yarn` and press **Enter**. Once everything is installed, enter the following commands: + +```sh +cd test-admin +npm run dev +# or yarn dev ``` -You should be up and running with an empty React application on port 5173. +You should be up and running with an empty React admin application on port 5173. -**Tip**: Although this tutorial uses a TypeScript template, you can use react-admin with JavaScript if you prefer. Also, you can use [create-react-app](./CreateReactApp.md), [Next.js](./NextJs.md), [Remix](./Remix.md), or any other React framework to create your admin app. React-admin is framework-agnostic. +**Tip**: Although this tutorial uses a TypeScript template, you can use react-admin with JavaScript if you prefer. Also, you can use [Vite](https://vitejs.dev/), [create-react-app](./CreateReactApp.md), [Next.js](./NextJs.md), [Remix](./Remix.md), or any other React framework to create your admin app. React-admin is framework-agnostic. ## Using an API As Data Source @@ -70,57 +76,10 @@ JSONPlaceholder provides endpoints for users, posts, and comments. The admin we' ## Making Contact With The API Using a Data Provider -Bootstrap the admin app by replacing the `src/App.tsx` by the following code: - -```jsx -// in src/App.tsx -import { Admin } from "react-admin"; -import jsonServerProvider from "ra-data-json-server"; - -const dataProvider = jsonServerProvider('https://jsonplaceholder.typicode.com'); - -const App = () => ; - -export default App; -``` - -That's enough for react-admin to render an empty app and confirm that the setup is done: +The application has been initialized with enough code for react-admin to render an empty app and confirm that the setup is done: [![Empty Admin](./img/tutorial_empty.png)](./img/tutorial_empty.png) -Also, you should change the default Vite CSS file to look like this: - -```css -/* in src/index.css */ -body { - margin: 0; -} -``` - -Lastly, add the `Roboto` font to the `index.html` file: - -```diff -// in ./index.html - - - - - - React Admin -+ - - -
- - - -``` - -**Tip:** You can also install the `Roboto` font locally by following the instructions from the [Material UI starter guide](https://mui.com/material-ui/getting-started/installation/#roboto-font). - The `` component renders an `` component, which is the root component of a react-admin application. This component expects a `dataProvider` prop - a function capable of fetching data from an API. Since there is no standard for data exchanges between computers, you will probably have to write a custom provider to connect react-admin to your own APIs - but we'll dive into Data Providers later. For now, let's take advantage of the `ra-data-json-server` data provider, which speaks the same REST dialect as JSONPlaceholder. Now it's time to add features! diff --git a/docs/img/create-react-admin.webm b/docs/img/create-react-admin.webm new file mode 100644 index 00000000000..e3381ed92d5 Binary files /dev/null and b/docs/img/create-react-admin.webm differ diff --git a/docs/navigation.html b/docs/navigation.html index 05896641c6d..71a60d56703 100644 --- a/docs/navigation.html +++ b/docs/navigation.html @@ -2,6 +2,7 @@
  • Tutorial
  • Features
  • What's new?
  • +
  • Create React Admin
  • Create React App
  • Vite
  • Next.js
  • diff --git a/examples/crm/package.json b/examples/crm/package.json index 45d5fa3d6a5..e72209bec56 100644 --- a/examples/crm/package.json +++ b/examples/crm/package.json @@ -1,6 +1,6 @@ { "name": "react-admin-crm", - "version": "4.9.4", + "version": "4.10.2", "private": true, "dependencies": { "@mui/icons-material": "^5.0.1", @@ -12,9 +12,9 @@ "faker": "~5.4.0", "lodash": "~4.17.5", "prop-types": "^15.7.2", - "ra-data-fakerest": "^4.9.3", + "ra-data-fakerest": "^4.10.2", "react": "^17.0.0", - "react-admin": "^4.9.4", + "react-admin": "^4.10.2", "react-beautiful-dnd": "^13.0.0", "react-dom": "^17.0.0", "react-error-boundary": "^3.1.4", diff --git a/examples/data-generator/package.json b/examples/data-generator/package.json index ca78d7f9a49..84de5b7a316 100644 --- a/examples/data-generator/package.json +++ b/examples/data-generator/package.json @@ -1,6 +1,6 @@ { "name": "data-generator-retail", - "version": "4.9.3", + "version": "4.10.2", "homepage": "https://github.com/marmelab/react-admin/tree/master/examples/data-generator", "bugs": "https://github.com/marmelab/react-admin/issues", "license": "MIT", @@ -19,12 +19,12 @@ }, "devDependencies": { "cross-env": "^5.2.0", - "ra-core": "^4.9.3", + "ra-core": "^4.10.2", "rimraf": "^3.0.2", "typescript": "^4.4.0" }, "peerDependencies": { "ra-core": "^4.0.0" }, - "gitHead": "8748248e40742bbd367338e0573a00213e17d3ab" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/examples/demo/package.json b/examples/demo/package.json index 4670caaf58f..b51ab095540 100644 --- a/examples/demo/package.json +++ b/examples/demo/package.json @@ -1,6 +1,6 @@ { "name": "demo", - "version": "4.9.4", + "version": "4.10.2", "private": true, "dependencies": { "@apollo/client": "^3.3.19", @@ -10,7 +10,7 @@ "@types/recharts": "^1.8.10", "@vitejs/plugin-react": "^2.2.0", "clsx": "^1.1.1", - "data-generator-retail": "^4.9.3", + "data-generator-retail": "^4.10.2", "date-fns": "^2.19.0", "fakerest": "^3.0.0", "fetch-mock": "~9.11.0", @@ -21,16 +21,16 @@ "prop-types": "^15.6.1", "proxy-polyfill": "^0.3.0", "query-string": "^7.1.1", - "ra-data-fakerest": "^4.9.3", - "ra-data-graphql": "^4.9.4", - "ra-data-graphql-simple": "^4.9.4", - "ra-data-simple-rest": "^4.9.3", - "ra-i18n-polyglot": "^4.9.3", - "ra-input-rich-text": "^4.9.4", - "ra-language-english": "^4.9.3", - "ra-language-french": "^4.9.3", + "ra-data-fakerest": "^4.10.2", + "ra-data-graphql": "^4.10.1", + "ra-data-graphql-simple": "^4.10.1", + "ra-data-simple-rest": "^4.10.2", + "ra-i18n-polyglot": "^4.10.2", + "ra-input-rich-text": "^4.10.2", + "ra-language-english": "^4.10.2", + "ra-language-french": "^4.10.2", "react": "^17.0.0", - "react-admin": "^4.9.4", + "react-admin": "^4.10.2", "react-app-polyfill": "^2.0.0", "react-dom": "^17.0.0", "react-router": "^6.1.0", diff --git a/examples/demo/src/layout/Login.tsx b/examples/demo/src/layout/Login.tsx index 82faa7ccb49..8c02a110511 100644 --- a/examples/demo/src/layout/Login.tsx +++ b/examples/demo/src/layout/Login.tsx @@ -68,7 +68,7 @@ const Login = () => { alignItems: 'center', justifyContent: 'flex-start', background: - 'url(https://source.unsplash.com/random/1600x900)', + 'url(https://source.unsplash.com/featured/1600x900)', backgroundRepeat: 'no-repeat', backgroundSize: 'cover', }} diff --git a/examples/no-code/package.json b/examples/no-code/package.json index 8c6b013d22b..14501e2479f 100644 --- a/examples/no-code/package.json +++ b/examples/no-code/package.json @@ -1,6 +1,6 @@ { "name": "no-code", - "version": "4.9.4", + "version": "4.10.2", "private": true, "scripts": { "dev": "yarn vite", @@ -9,10 +9,10 @@ }, "dependencies": { "@mui/material": "^5.0.2", - "ra-data-local-storage": "^4.9.3", - "ra-no-code": "^4.9.4", + "ra-data-local-storage": "^4.10.2", + "ra-no-code": "^4.10.2", "react": "^17.0.0", - "react-admin": "^4.9.4", + "react-admin": "^4.10.2", "react-dom": "^17.0.0" }, "devDependencies": { diff --git a/examples/simple/package.json b/examples/simple/package.json index 6171aa2bd39..22b1f9e3b91 100644 --- a/examples/simple/package.json +++ b/examples/simple/package.json @@ -1,6 +1,6 @@ { "name": "simple", - "version": "4.9.4", + "version": "4.10.2", "private": true, "scripts": { "dev": "vite", @@ -17,13 +17,13 @@ "lodash": "~4.17.5", "prop-types": "^15.7.2", "proxy-polyfill": "^0.3.0", - "ra-data-fakerest": "^4.9.3", - "ra-i18n-polyglot": "^4.9.3", - "ra-input-rich-text": "^4.9.4", - "ra-language-english": "^4.9.3", - "ra-language-french": "^4.9.3", + "ra-data-fakerest": "^4.10.2", + "ra-i18n-polyglot": "^4.10.2", + "ra-input-rich-text": "^4.10.2", + "ra-language-english": "^4.10.2", + "ra-language-french": "^4.10.2", "react": "^17.0.0", - "react-admin": "^4.9.4", + "react-admin": "^4.10.2", "react-dom": "^17.0.0", "react-hook-form": "^7.40.0", "react-query": "^3.32.1", diff --git a/examples/tutorial/package.json b/examples/tutorial/package.json index b9f7a847dc1..e57ecee3629 100644 --- a/examples/tutorial/package.json +++ b/examples/tutorial/package.json @@ -1,6 +1,6 @@ { "name": "tutorial", - "version": "4.9.4", + "version": "4.10.2", "private": true, "type": "module", "scripts": { @@ -9,9 +9,9 @@ "preview": "vite preview" }, "dependencies": { - "ra-data-json-server": "^4.9.3", + "ra-data-json-server": "^4.10.2", "react": "^18.2.0", - "react-admin": "^4.9.4", + "react-admin": "^4.10.2", "react-dom": "^18.2.0" }, "devDependencies": { diff --git a/lerna.json b/lerna.json index 0c49e5c1abc..36db99517ad 100644 --- a/lerna.json +++ b/lerna.json @@ -5,6 +5,6 @@ "examples/simple", "packages/*" ], - "version": "4.9.4", + "version": "4.10.2", "useWorkspaces": true } diff --git a/packages/create-react-admin/README.md b/packages/create-react-admin/README.md index 5e3324e809f..585edc82d69 100644 --- a/packages/create-react-admin/README.md +++ b/packages/create-react-admin/README.md @@ -26,4 +26,8 @@ In another directory, run: ./react-admin/node_modules/.bin/create-react-admin my-admin ``` -The above command assume you cloned react-admin in the `react-admin` directory and you are running the command in this directory parent. \ No newline at end of file +The above command assume you cloned react-admin in the `react-admin` directory and you are running the command in this directory parent. + +## Miscellaneous + +This package is MIT licensed. Sponsored by [Marmelab](https://marmelab.com) and [Anthony Chan](https://github.com/ckanthony). \ No newline at end of file diff --git a/packages/create-react-admin/package.json b/packages/create-react-admin/package.json index f11887d9c2d..b7fdfd45129 100644 --- a/packages/create-react-admin/package.json +++ b/packages/create-react-admin/package.json @@ -1,7 +1,7 @@ { "name": "create-react-admin", "description": "A CLI to quickly start a new react-admin project", - "version": "0.0.1", + "version": "4.10.2", "license": "MIT", "bin": "lib/cli.js", "authors": [ @@ -15,7 +15,7 @@ "test": "prettier --check . && xo && ava" }, "files": [ - "dist" + "lib" ], "dependencies": { "execa": "^5.1.1", @@ -30,5 +30,6 @@ "devDependencies": { "@types/react": ">=17.0.0", "typescript": "^4.4.0" - } + }, + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-core/package.json b/packages/ra-core/package.json index 91410ef4898..42b446beb35 100644 --- a/packages/ra-core/package.json +++ b/packages/ra-core/package.json @@ -1,6 +1,6 @@ { "name": "ra-core", - "version": "4.9.3", + "version": "4.10.2", "description": "Core components of react-admin, a frontend Framework for building admin applications on top of REST services, using ES6, React", "files": [ "*.md", @@ -67,5 +67,5 @@ "react-is": "^17.0.2", "react-query": "^3.32.1" }, - "gitHead": "8748248e40742bbd367338e0573a00213e17d3ab" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-core/src/controller/create/useCreateController.spec.tsx b/packages/ra-core/src/controller/create/useCreateController.spec.tsx index 35205fa3ab3..a0083204814 100644 --- a/packages/ra-core/src/controller/create/useCreateController.spec.tsx +++ b/packages/ra-core/src/controller/create/useCreateController.spec.tsx @@ -1,19 +1,26 @@ -import React from 'react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; import expect from 'expect'; -import { render, act } from '@testing-library/react'; -import { Location } from 'react-router-dom'; +import React from 'react'; +import { Location, MemoryRouter, Route, Routes } from 'react-router-dom'; -import { getRecordFromLocation } from './useCreateController'; -import { CreateController } from './CreateController'; +import { + CreateContextProvider, + DataProvider, + Form, + InputProps, + useCreateController, + useInput, +} from '../..'; +import { CoreAdminContext } from '../../core'; import { testDataProvider, useCreate } from '../../dataProvider'; import { useNotificationContext } from '../../notification'; -import { CoreAdminContext } from '../../core'; import { Middleware, SaveContextProvider, useRegisterMutationMiddleware, } from '../saveContext'; -import { DataProvider } from '../..'; +import { CreateController } from './CreateController'; +import { getRecordFromLocation } from './useCreateController'; describe('useCreateController', () => { describe('getRecordFromLocation', () => { @@ -532,4 +539,61 @@ describe('useCreateController', () => { data: { foo: 'bar' }, }); }); + + it('should allow custom redirect with warnWhenUnsavedChanges', async () => { + const dataProvider = testDataProvider({ + getOne: () => Promise.resolve({ data: { id: 123 } } as any), + create: (_, { data }) => + new Promise(resolve => + setTimeout( + () => resolve({ data: { id: 123, ...data } }), + 300 + ) + ), + }); + const Input = (props: InputProps) => { + const name = props.source; + const { field } = useInput(props); + return ( + <> + + + + ); + }; + const CreateView = () => { + const controllerProps = useCreateController({ + ...defaultProps, + redirect: 'show', + }); + return ( + +
    + <> +
    Create
    + + + +
    +
    + ); + }; + const ShowView = () =>
    Show
    ; + render( + + + + } /> + } /> + + + + ); + await screen.findByText('Create'); + fireEvent.change(screen.getByLabelText('foo'), { + target: { value: 'bar' }, + }); + fireEvent.click(screen.getByText('Submit')); + expect(await screen.findByText('Show')).not.toBeNull(); + }); }); diff --git a/packages/ra-core/src/controller/edit/useEditController.spec.tsx b/packages/ra-core/src/controller/edit/useEditController.spec.tsx index 5f7e7d98804..16672f4d17f 100644 --- a/packages/ra-core/src/controller/edit/useEditController.spec.tsx +++ b/packages/ra-core/src/controller/edit/useEditController.spec.tsx @@ -1,17 +1,28 @@ -import * as React from 'react'; +import { + act, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; import expect from 'expect'; -import { act, render, screen, waitFor } from '@testing-library/react'; -import { Routes, Route } from 'react-router'; import { createMemoryHistory } from 'history'; +import * as React from 'react'; +import { MemoryRouter, Route, Routes } from 'react-router'; -import { EditController } from './EditController'; -import { DataProvider } from '../../types'; +import { + EditContextProvider, + SaveContextProvider, + useEditController, +} from '..'; import { CoreAdminContext } from '../../core'; -import { useNotificationContext } from '../../notification'; -import { SaveContextProvider } from '..'; +import { testDataProvider, useUpdate } from '../../dataProvider'; import undoableEventEmitter from '../../dataProvider/undoableEventEmitter'; +import { Form, InputProps, useInput } from '../../form'; +import { useNotificationContext } from '../../notification'; +import { DataProvider } from '../../types'; import { Middleware, useRegisterMutationMiddleware } from '../saveContext'; -import { testDataProvider, useUpdate } from '../../dataProvider'; +import { EditController } from './EditController'; describe('useEditController', () => { const defaultProps = { @@ -940,4 +951,63 @@ describe('useEditController', () => { previousData: { id: 12 }, }); }); + + it('should allow custom redirect with warnWhenUnsavedChanges in pessimistic mode', async () => { + const dataProvider = testDataProvider({ + getOne: () => Promise.resolve({ data: { id: 123 } } as any), + update: (_, { id, data }) => + new Promise(resolve => + setTimeout( + () => resolve({ data: { id, ...data } } as any), + 300 + ) + ), + }); + const Input = (props: InputProps) => { + const name = props.source; + const { field } = useInput(props); + return ( + <> + + + + ); + }; + const EditView = () => { + const controllerProps = useEditController({ + ...defaultProps, + id: 123, + redirect: 'show', + mutationMode: 'pessimistic', + }); + return ( + +
    + <> +
    Edit
    + + + +
    +
    + ); + }; + const ShowView = () =>
    Show
    ; + render( + + + + } /> + } /> + + + + ); + await screen.findByText('Edit'); + fireEvent.change(await screen.findByLabelText('foo'), { + target: { value: 'bar' }, + }); + fireEvent.click(screen.getByText('Submit')); + expect(await screen.findByText('Show')).not.toBeNull(); + }); }); diff --git a/packages/ra-core/src/controller/useReference.ts b/packages/ra-core/src/controller/useReference.ts index 0c239388a2c..825d7da1004 100644 --- a/packages/ra-core/src/controller/useReference.ts +++ b/packages/ra-core/src/controller/useReference.ts @@ -5,7 +5,7 @@ import { UseQueryOptions } from 'react-query'; interface UseReferenceProps { id: Identifier; reference: string; - options?: UseQueryOptions; + options?: UseQueryOptions & { meta?: any }; } export interface UseReferenceResult { @@ -40,6 +40,7 @@ export interface UseReferenceResult { * @param {Object} option * @param {string} option.reference The linked resource name * @param {string} option.id The id of the reference + * @param {Object} option.options Options passed to the dataProvider * * @returns {UseReferenceResult} The reference record */ diff --git a/packages/ra-core/src/form/useWarnWhenUnsavedChanges.tsx b/packages/ra-core/src/form/useWarnWhenUnsavedChanges.tsx index 8787bf2505c..9758d3e6d50 100644 --- a/packages/ra-core/src/form/useWarnWhenUnsavedChanges.tsx +++ b/packages/ra-core/src/form/useWarnWhenUnsavedChanges.tsx @@ -55,6 +55,14 @@ export const useWarnWhenUnsavedChanges = ( ) { unblock(); tx.retry(); + } else { + if (isSubmitting) { + // Retry the transition (possibly several times) until the form is no longer submitting. + // The value of 100ms is arbitrary, it allows to give some time between retries. + setTimeout(() => { + tx.retry(); + }, 100); + } } }); diff --git a/packages/ra-data-fakerest/package.json b/packages/ra-data-fakerest/package.json index 14fc992f15e..9f7235676fc 100644 --- a/packages/ra-data-fakerest/package.json +++ b/packages/ra-data-fakerest/package.json @@ -1,6 +1,6 @@ { "name": "ra-data-fakerest", - "version": "4.9.3", + "version": "4.10.2", "description": "JSON Server data provider for react-admin", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", @@ -41,12 +41,12 @@ }, "devDependencies": { "cross-env": "^5.2.0", - "ra-core": "^4.9.3", + "ra-core": "^4.10.2", "rimraf": "^3.0.2", "typescript": "^4.4.0" }, "peerDependencies": { "ra-core": "^4.0.0" }, - "gitHead": "8748248e40742bbd367338e0573a00213e17d3ab" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-data-graphql-simple/package.json b/packages/ra-data-graphql-simple/package.json index 47453b350f8..ddec415511f 100644 --- a/packages/ra-data-graphql-simple/package.json +++ b/packages/ra-data-graphql-simple/package.json @@ -1,6 +1,6 @@ { "name": "ra-data-graphql-simple", - "version": "4.9.4", + "version": "4.10.1", "description": "A GraphQL simple data provider for react-admin", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", @@ -37,7 +37,7 @@ "graphql-ast-types-browser": "~1.0.2", "lodash": "~4.17.5", "pluralize": "~7.0.0", - "ra-data-graphql": "^4.9.4" + "ra-data-graphql": "^4.10.1" }, "peerDependencies": { "graphql": "^15.6.0", @@ -49,5 +49,5 @@ "rimraf": "^3.0.2", "typescript": "^4.4.0" }, - "gitHead": "8748248e40742bbd367338e0573a00213e17d3ab" + "gitHead": "65189b7cea65cc57190f41f77b84fdb290b68e29" } diff --git a/packages/ra-data-graphql/package.json b/packages/ra-data-graphql/package.json index af29bdc9cc5..76aaa5b8f16 100644 --- a/packages/ra-data-graphql/package.json +++ b/packages/ra-data-graphql/package.json @@ -1,6 +1,6 @@ { "name": "ra-data-graphql", - "version": "4.9.4", + "version": "4.10.1", "description": "A GraphQL data provider for react-admin", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", @@ -47,5 +47,5 @@ "rimraf": "^3.0.2", "typescript": "^4.4.0" }, - "gitHead": "8748248e40742bbd367338e0573a00213e17d3ab" + "gitHead": "65189b7cea65cc57190f41f77b84fdb290b68e29" } diff --git a/packages/ra-data-json-server/package.json b/packages/ra-data-json-server/package.json index c2395ce71f4..c742e0c436c 100644 --- a/packages/ra-data-json-server/package.json +++ b/packages/ra-data-json-server/package.json @@ -1,6 +1,6 @@ { "name": "ra-data-json-server", - "version": "4.9.3", + "version": "4.10.2", "description": "JSON Server data provider for react-admin", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", @@ -26,12 +26,12 @@ }, "dependencies": { "query-string": "^7.1.1", - "ra-core": "^4.9.3" + "ra-core": "^4.10.2" }, "devDependencies": { "cross-env": "^5.2.0", "rimraf": "^3.0.2", "typescript": "^4.4.0" }, - "gitHead": "8748248e40742bbd367338e0573a00213e17d3ab" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-data-localforage/package.json b/packages/ra-data-localforage/package.json index 0f2d5e7c1e2..a9f89a5fa06 100644 --- a/packages/ra-data-localforage/package.json +++ b/packages/ra-data-localforage/package.json @@ -1,6 +1,6 @@ { "name": "ra-data-local-forage", - "version": "4.9.3", + "version": "4.10.2", "description": "LocalForage data provider for react-admin", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", @@ -42,7 +42,7 @@ "dependencies": { "localforage": "^1.7.1", "lodash": "~4.17.5", - "ra-data-fakerest": "^4.9.3" + "ra-data-fakerest": "^4.10.2" }, "devDependencies": { "cross-env": "^5.2.0", @@ -52,5 +52,5 @@ "peerDependencies": { "ra-core": "*" }, - "gitHead": "8748248e40742bbd367338e0573a00213e17d3ab" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-data-localstorage/package.json b/packages/ra-data-localstorage/package.json index e14a43557ca..1f5c1b6f846 100644 --- a/packages/ra-data-localstorage/package.json +++ b/packages/ra-data-localstorage/package.json @@ -1,6 +1,6 @@ { "name": "ra-data-local-storage", - "version": "4.9.3", + "version": "4.10.2", "description": "Local storage data provider for react-admin", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", @@ -38,7 +38,7 @@ }, "dependencies": { "lodash": "~4.17.5", - "ra-data-fakerest": "^4.9.3" + "ra-data-fakerest": "^4.10.2" }, "devDependencies": { "cross-env": "^5.2.0", @@ -48,5 +48,5 @@ "peerDependencies": { "ra-core": "*" }, - "gitHead": "8748248e40742bbd367338e0573a00213e17d3ab" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-data-simple-rest/package.json b/packages/ra-data-simple-rest/package.json index d3fbd3e3dbe..1a584b040ee 100644 --- a/packages/ra-data-simple-rest/package.json +++ b/packages/ra-data-simple-rest/package.json @@ -1,6 +1,6 @@ { "name": "ra-data-simple-rest", - "version": "4.9.3", + "version": "4.10.2", "description": "Simple REST data provider for react-admin", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", @@ -29,12 +29,12 @@ }, "devDependencies": { "cross-env": "^5.2.0", - "ra-core": "^4.9.3", + "ra-core": "^4.10.2", "rimraf": "^3.0.2", "typescript": "^4.4.0" }, "peerDependencies": { "ra-core": "^4.0.0" }, - "gitHead": "8748248e40742bbd367338e0573a00213e17d3ab" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-i18n-polyglot/package.json b/packages/ra-i18n-polyglot/package.json index 3fbcc080bbd..d552aba63cd 100644 --- a/packages/ra-i18n-polyglot/package.json +++ b/packages/ra-i18n-polyglot/package.json @@ -1,6 +1,6 @@ { "name": "ra-i18n-polyglot", - "version": "4.9.3", + "version": "4.10.2", "description": "Polyglot i18n provider for react-admin", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", @@ -26,12 +26,12 @@ }, "dependencies": { "node-polyglot": "^2.2.2", - "ra-core": "^4.9.3" + "ra-core": "^4.10.2" }, "devDependencies": { "cross-env": "^5.2.0", "rimraf": "^3.0.2", "typescript": "^4.4.0" }, - "gitHead": "8748248e40742bbd367338e0573a00213e17d3ab" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-input-rich-text/package.json b/packages/ra-input-rich-text/package.json index 6515ad5033a..14f9616f339 100644 --- a/packages/ra-input-rich-text/package.json +++ b/packages/ra-input-rich-text/package.json @@ -1,6 +1,6 @@ { "name": "ra-input-rich-text", - "version": "4.9.4", + "version": "4.10.2", "description": " component for react-admin, useful for editing HTML code in admin GUIs.", "author": "Gildas Garcia", "repository": "marmelab/react-admin", @@ -49,15 +49,15 @@ "@mui/icons-material": "^5.0.1", "@mui/material": "^5.0.2", "@testing-library/react": "^11.2.3", - "data-generator-retail": "^4.9.3", - "ra-core": "^4.9.3", - "ra-data-fakerest": "^4.9.3", - "ra-ui-materialui": "^4.9.4", + "data-generator-retail": "^4.10.2", + "ra-core": "^4.10.2", + "ra-data-fakerest": "^4.10.2", + "ra-ui-materialui": "^4.10.2", "react": "^17.0.0", "react-dom": "^17.0.0", "react-hook-form": "^7.40.0", "rimraf": "^3.0.2", "typescript": "^4.4.0" }, - "gitHead": "6eb0f6fcbe3ba237b507f3506d230b3445c0a764" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-language-english/package.json b/packages/ra-language-english/package.json index 9005637ce66..632fb03cf1f 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.9.3", + "version": "4.10.2", "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.9.3" + "ra-core": "^4.10.2" }, "devDependencies": { "rimraf": "^3.0.2", @@ -39,5 +39,5 @@ "url": "https://github.com/marmelab/react-admin/issues" }, "homepage": "https://github.com/marmelab/react-admin#readme", - "gitHead": "8748248e40742bbd367338e0573a00213e17d3ab" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-language-french/package.json b/packages/ra-language-french/package.json index ff0e3ad1678..404b66ccbd8 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.9.3", + "version": "4.10.2", "description": "French messages for react-admin, the frontend framework for building admin applications on top of REST/GraphQL services", "repository": { "type": "git", @@ -16,7 +16,7 @@ "watch": "tsc --outDir dist/esm --module es2015 --watch" }, "dependencies": { - "ra-core": "^4.9.3" + "ra-core": "^4.10.2" }, "devDependencies": { "rimraf": "^3.0.2", @@ -34,5 +34,5 @@ "url": "https://github.com/marmelab/react-admin/issues" }, "homepage": "https://github.com/marmelab/react-admin#readme", - "gitHead": "8748248e40742bbd367338e0573a00213e17d3ab" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-no-code/package.json b/packages/ra-no-code/package.json index 2047d0eb852..fce36140104 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.9.4", + "version": "4.10.2", "description": "", "files": [ "*.md", @@ -48,10 +48,10 @@ "lodash": "~4.17.5", "papaparse": "^5.3.0", "prop-types": "^15.6.1", - "ra-data-local-storage": "^4.9.3", - "react-admin": "^4.9.4", + "ra-data-local-storage": "^4.10.2", + "react-admin": "^4.10.2", "react-dropzone": "^12.0.4", "react-query": "^3.32.1" }, - "gitHead": "6eb0f6fcbe3ba237b507f3506d230b3445c0a764" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-ui-materialui/package.json b/packages/ra-ui-materialui/package.json index a1e43c35adc..6682468cdda 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.9.4", + "version": "4.10.2", "description": "UI Components for react-admin with Material UI", "files": [ "*.md", @@ -34,9 +34,9 @@ "file-api": "~0.10.4", "history": "^5.1.0", "ignore-styles": "~5.0.1", - "ra-core": "^4.9.3", - "ra-i18n-polyglot": "^4.9.3", - "ra-language-english": "^4.9.3", + "ra-core": "^4.10.2", + "ra-i18n-polyglot": "^4.10.2", + "ra-language-english": "^4.10.2", "react": "^17.0.0", "react-dom": "^17.0.0", "react-hook-form": "^7.40.0", @@ -71,5 +71,5 @@ "react-query": "^3.32.1", "react-transition-group": "^4.4.1" }, - "gitHead": "6eb0f6fcbe3ba237b507f3506d230b3445c0a764" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/packages/ra-ui-materialui/src/field/ReferenceField.spec.tsx b/packages/ra-ui-materialui/src/field/ReferenceField.spec.tsx index 8d6157771d6..18807b33887 100644 --- a/packages/ra-ui-materialui/src/field/ReferenceField.spec.tsx +++ b/packages/ra-ui-materialui/src/field/ReferenceField.spec.tsx @@ -583,4 +583,33 @@ describe('', () => { expect(screen.findByText('Not found')).not.toBeNull(); }); + + it('should accept a queryOptions prop', async () => { + const dataProvider = testDataProvider({ + getMany: jest.fn().mockResolvedValue({ + data: [{ id: 123, title: 'foo' }], + }), + }); + render( + + + + + + + + ); + await waitFor(() => { + expect(dataProvider.getMany).toHaveBeenCalledWith('posts', { + ids: [123], + meta: { foo: 'bar' }, + }); + }); + }); }); diff --git a/packages/ra-ui-materialui/src/field/ReferenceField.tsx b/packages/ra-ui-materialui/src/field/ReferenceField.tsx index 2ea9283cab4..792ba12bab5 100644 --- a/packages/ra-ui-materialui/src/field/ReferenceField.tsx +++ b/packages/ra-ui-materialui/src/field/ReferenceField.tsx @@ -23,6 +23,7 @@ import { import { LinearProgress } from '../layout'; import { Link } from '../Link'; import { PublicFieldProps, fieldPropTypes, InjectedFieldProps } from './types'; +import { UseQueryOptions } from 'react-query'; /** * Fetch reference record, and render its representation, or delegate rendering to child component. @@ -106,6 +107,7 @@ export interface ReferenceFieldProps extends PublicFieldProps, InjectedFieldProps { children?: ReactNode; + queryOptions?: UseQueryOptions & { meta?: any }; reference: string; resource?: string; source: string; @@ -120,7 +122,7 @@ export interface ReferenceFieldProps */ export const NonEmptyReferenceField: FC< Omit & { id: Identifier } -> = ({ children, id, record, reference, link, ...props }) => { +> = ({ children, id, record, reference, link, queryOptions, ...props }) => { const createPath = useCreatePath(); const resourceDefinition = useResourceDefinition({ resource: reference }); @@ -146,6 +148,7 @@ export const NonEmptyReferenceField: FC< {...useReference({ reference, id, + options: queryOptions, })} resourceLinkPath={resourceLinkPath} > diff --git a/packages/react-admin/package.json b/packages/react-admin/package.json index ccb2408d538..f3ea10822ab 100644 --- a/packages/react-admin/package.json +++ b/packages/react-admin/package.json @@ -1,6 +1,6 @@ { "name": "react-admin", - "version": "4.9.4", + "version": "4.10.2", "description": "A frontend Framework for building admin applications on top of REST services, using ES6, React and Material UI", "files": [ "*.md", @@ -41,13 +41,13 @@ "@mui/icons-material": "^5.0.1", "@mui/material": "^5.0.2", "history": "^5.1.0", - "ra-core": "^4.9.3", - "ra-i18n-polyglot": "^4.9.3", - "ra-language-english": "^4.9.3", - "ra-ui-materialui": "^4.9.4", + "ra-core": "^4.10.2", + "ra-i18n-polyglot": "^4.10.2", + "ra-language-english": "^4.10.2", + "ra-ui-materialui": "^4.10.2", "react-hook-form": "^7.40.0", "react-router": "^6.1.0", "react-router-dom": "^6.1.0" }, - "gitHead": "6eb0f6fcbe3ba237b507f3506d230b3445c0a764" + "gitHead": "e936ff2c3f887d2e98ef136cf3b3f3d254725fc4" } diff --git a/yarn.lock b/yarn.lock index 6f7e936e9d7..e7bccad56c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9927,14 +9927,14 @@ __metadata: languageName: node linkType: hard -"data-generator-retail@^4.9.3, data-generator-retail@workspace:examples/data-generator": +"data-generator-retail@^4.10.2, 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.9.3 + ra-core: ^4.10.2 rimraf: ^3.0.2 typescript: ^4.4.0 peerDependencies: @@ -10161,7 +10161,7 @@ __metadata: "@types/recharts": ^1.8.10 "@vitejs/plugin-react": ^2.2.0 clsx: ^1.1.1 - data-generator-retail: ^4.9.3 + data-generator-retail: ^4.10.2 date-fns: ^2.19.0 fakerest: ^3.0.0 fetch-mock: ~9.11.0 @@ -10172,16 +10172,16 @@ __metadata: prop-types: ^15.6.1 proxy-polyfill: ^0.3.0 query-string: ^7.1.1 - ra-data-fakerest: ^4.9.3 - ra-data-graphql: ^4.9.4 - ra-data-graphql-simple: ^4.9.4 - ra-data-simple-rest: ^4.9.3 - ra-i18n-polyglot: ^4.9.3 - ra-input-rich-text: ^4.9.4 - ra-language-english: ^4.9.3 - ra-language-french: ^4.9.3 + ra-data-fakerest: ^4.10.2 + ra-data-graphql: ^4.10.1 + ra-data-graphql-simple: ^4.10.1 + ra-data-simple-rest: ^4.10.2 + ra-i18n-polyglot: ^4.10.2 + ra-input-rich-text: ^4.10.2 + ra-language-english: ^4.10.2 + ra-language-french: ^4.10.2 react: ^17.0.0 - react-admin: ^4.9.4 + react-admin: ^4.10.2 react-app-polyfill: ^2.0.0 react-dom: ^17.0.0 react-router: ^6.1.0 @@ -16794,10 +16794,10 @@ __metadata: dependencies: "@mui/material": ^5.0.2 "@vitejs/plugin-react": ^2.2.0 - ra-data-local-storage: ^4.9.3 - ra-no-code: ^4.9.4 + ra-data-local-storage: ^4.10.2 + ra-no-code: ^4.10.2 react: ^17.0.0 - react-admin: ^4.9.4 + react-admin: ^4.10.2 react-dom: ^17.0.0 typescript: ^4.4.0 vite: ^3.2.0 @@ -18870,7 +18870,7 @@ __metadata: languageName: node linkType: hard -"ra-core@^4.9.3, ra-core@workspace:packages/ra-core": +"ra-core@^4.10.2, ra-core@workspace:packages/ra-core": version: 0.0.0-use.local resolution: "ra-core@workspace:packages/ra-core" dependencies: @@ -18914,13 +18914,13 @@ __metadata: languageName: unknown linkType: soft -"ra-data-fakerest@^4.9.3, ra-data-fakerest@workspace:packages/ra-data-fakerest": +"ra-data-fakerest@^4.10.2, ra-data-fakerest@workspace:packages/ra-data-fakerest": version: 0.0.0-use.local resolution: "ra-data-fakerest@workspace:packages/ra-data-fakerest" dependencies: cross-env: ^5.2.0 fakerest: ^3.0.0 - ra-core: ^4.9.3 + ra-core: ^4.10.2 rimraf: ^3.0.2 typescript: ^4.4.0 peerDependencies: @@ -18928,7 +18928,7 @@ __metadata: languageName: unknown linkType: soft -"ra-data-graphql-simple@^4.9.4, ra-data-graphql-simple@workspace:packages/ra-data-graphql-simple": +"ra-data-graphql-simple@^4.10.1, ra-data-graphql-simple@workspace:packages/ra-data-graphql-simple": version: 0.0.0-use.local resolution: "ra-data-graphql-simple@workspace:packages/ra-data-graphql-simple" dependencies: @@ -18938,7 +18938,7 @@ __metadata: graphql-ast-types-browser: ~1.0.2 lodash: ~4.17.5 pluralize: ~7.0.0 - ra-data-graphql: ^4.9.4 + ra-data-graphql: ^4.10.1 rimraf: ^3.0.2 typescript: ^4.4.0 peerDependencies: @@ -18947,7 +18947,7 @@ __metadata: languageName: unknown linkType: soft -"ra-data-graphql@^4.9.4, ra-data-graphql@workspace:packages/ra-data-graphql": +"ra-data-graphql@^4.10.1, ra-data-graphql@workspace:packages/ra-data-graphql": version: 0.0.0-use.local resolution: "ra-data-graphql@workspace:packages/ra-data-graphql" dependencies: @@ -18964,13 +18964,13 @@ __metadata: languageName: unknown linkType: soft -"ra-data-json-server@^4.9.3, ra-data-json-server@workspace:packages/ra-data-json-server": +"ra-data-json-server@^4.10.2, ra-data-json-server@workspace:packages/ra-data-json-server": version: 0.0.0-use.local resolution: "ra-data-json-server@workspace:packages/ra-data-json-server" dependencies: cross-env: ^5.2.0 query-string: ^7.1.1 - ra-core: ^4.9.3 + ra-core: ^4.10.2 rimraf: ^3.0.2 typescript: ^4.4.0 languageName: unknown @@ -18983,7 +18983,7 @@ __metadata: cross-env: ^5.2.0 localforage: ^1.7.1 lodash: ~4.17.5 - ra-data-fakerest: ^4.9.3 + ra-data-fakerest: ^4.10.2 rimraf: ^3.0.2 typescript: ^4.4.0 peerDependencies: @@ -18991,13 +18991,13 @@ __metadata: languageName: unknown linkType: soft -"ra-data-local-storage@^4.9.3, ra-data-local-storage@workspace:packages/ra-data-localstorage": +"ra-data-local-storage@^4.10.2, 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.9.3 + ra-data-fakerest: ^4.10.2 rimraf: ^3.0.2 typescript: ^4.4.0 peerDependencies: @@ -19005,13 +19005,13 @@ __metadata: languageName: unknown linkType: soft -"ra-data-simple-rest@^4.9.3, ra-data-simple-rest@workspace:packages/ra-data-simple-rest": +"ra-data-simple-rest@^4.10.2, ra-data-simple-rest@workspace:packages/ra-data-simple-rest": version: 0.0.0-use.local resolution: "ra-data-simple-rest@workspace:packages/ra-data-simple-rest" dependencies: cross-env: ^5.2.0 query-string: ^7.1.1 - ra-core: ^4.9.3 + ra-core: ^4.10.2 rimraf: ^3.0.2 typescript: ^4.4.0 peerDependencies: @@ -19019,19 +19019,19 @@ __metadata: languageName: unknown linkType: soft -"ra-i18n-polyglot@^4.9.3, ra-i18n-polyglot@workspace:packages/ra-i18n-polyglot": +"ra-i18n-polyglot@^4.10.2, 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.9.3 + ra-core: ^4.10.2 rimraf: ^3.0.2 typescript: ^4.4.0 languageName: unknown linkType: soft -"ra-input-rich-text@^4.9.4, ra-input-rich-text@workspace:packages/ra-input-rich-text": +"ra-input-rich-text@^4.10.2, 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: @@ -19051,10 +19051,10 @@ __metadata: "@tiptap/react": ^2.0.0-beta.217 "@tiptap/starter-kit": ^2.0.0-beta.217 clsx: ^1.1.1 - data-generator-retail: ^4.9.3 - ra-core: ^4.9.3 - ra-data-fakerest: ^4.9.3 - ra-ui-materialui: ^4.9.4 + data-generator-retail: ^4.10.2 + ra-core: ^4.10.2 + ra-data-fakerest: ^4.10.2 + ra-ui-materialui: ^4.10.2 react: ^17.0.0 react-dom: ^17.0.0 react-hook-form: ^7.40.0 @@ -19070,27 +19070,27 @@ __metadata: languageName: unknown linkType: soft -"ra-language-english@^4.9.3, ra-language-english@workspace:packages/ra-language-english": +"ra-language-english@^4.10.2, 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.9.3 + ra-core: ^4.10.2 rimraf: ^3.0.2 typescript: ^4.4.0 languageName: unknown linkType: soft -"ra-language-french@^4.9.3, ra-language-french@workspace:packages/ra-language-french": +"ra-language-french@^4.10.2, 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.9.3 + ra-core: ^4.10.2 rimraf: ^3.0.2 typescript: ^4.4.0 languageName: unknown linkType: soft -"ra-no-code@^4.9.4, ra-no-code@workspace:packages/ra-no-code": +"ra-no-code@^4.10.2, ra-no-code@workspace:packages/ra-no-code": version: 0.0.0-use.local resolution: "ra-no-code@workspace:packages/ra-no-code" dependencies: @@ -19105,9 +19105,9 @@ __metadata: lodash: ~4.17.5 papaparse: ^5.3.0 prop-types: ^15.6.1 - ra-data-local-storage: ^4.9.3 + ra-data-local-storage: ^4.10.2 react: ^17.0.0 - react-admin: ^4.9.4 + react-admin: ^4.10.2 react-dom: ^17.0.0 react-dropzone: ^12.0.4 react-query: ^3.32.1 @@ -19121,7 +19121,7 @@ __metadata: languageName: unknown linkType: soft -"ra-ui-materialui@^4.9.4, ra-ui-materialui@workspace:packages/ra-ui-materialui": +"ra-ui-materialui@^4.10.2, ra-ui-materialui@workspace:packages/ra-ui-materialui": version: 0.0.0-use.local resolution: "ra-ui-materialui@workspace:packages/ra-ui-materialui" dependencies: @@ -19142,9 +19142,9 @@ __metadata: lodash: ~4.17.5 prop-types: ^15.7.0 query-string: ^7.1.1 - ra-core: ^4.9.3 - ra-i18n-polyglot: ^4.9.3 - ra-language-english: ^4.9.3 + ra-core: ^4.10.2 + ra-i18n-polyglot: ^4.10.2 + ra-language-english: ^4.10.2 react: ^17.0.0 react-dom: ^17.0.0 react-dropzone: ^12.0.4 @@ -19267,9 +19267,9 @@ __metadata: faker: ~5.4.0 lodash: ~4.17.5 prop-types: ^15.7.2 - ra-data-fakerest: ^4.9.3 + ra-data-fakerest: ^4.10.2 react: ^17.0.0 - react-admin: ^4.9.4 + react-admin: ^4.10.2 react-beautiful-dnd: ^13.0.0 react-dom: ^17.0.0 react-error-boundary: ^3.1.4 @@ -19329,7 +19329,7 @@ __metadata: languageName: unknown linkType: soft -"react-admin@^4.9.4, react-admin@workspace:packages/react-admin": +"react-admin@^4.10.2, react-admin@workspace:packages/react-admin": version: 0.0.0-use.local resolution: "react-admin@workspace:packages/react-admin" dependencies: @@ -19340,10 +19340,10 @@ __metadata: cross-env: ^5.2.0 expect: ^27.4.6 history: ^5.1.0 - ra-core: ^4.9.3 - ra-i18n-polyglot: ^4.9.3 - ra-language-english: ^4.9.3 - ra-ui-materialui: ^4.9.4 + ra-core: ^4.10.2 + ra-i18n-polyglot: ^4.10.2 + ra-language-english: ^4.10.2 + ra-ui-materialui: ^4.10.2 react-hook-form: ^7.40.0 react-router: ^6.1.0 react-router-dom: ^6.1.0 @@ -20980,13 +20980,13 @@ __metadata: lodash: ~4.17.5 prop-types: ^15.7.2 proxy-polyfill: ^0.3.0 - ra-data-fakerest: ^4.9.3 - ra-i18n-polyglot: ^4.9.3 - ra-input-rich-text: ^4.9.4 - ra-language-english: ^4.9.3 - ra-language-french: ^4.9.3 + ra-data-fakerest: ^4.10.2 + ra-i18n-polyglot: ^4.10.2 + ra-input-rich-text: ^4.10.2 + ra-language-english: ^4.10.2 + ra-language-french: ^4.10.2 react: ^17.0.0 - react-admin: ^4.9.4 + react-admin: ^4.10.2 react-app-polyfill: ^1.0.4 react-dom: ^17.0.0 react-hook-form: ^7.40.0 @@ -22317,9 +22317,9 @@ __metadata: "@types/react": ^18.0.22 "@types/react-dom": ^18.0.7 "@vitejs/plugin-react": ^2.2.0 - ra-data-json-server: ^4.9.3 + ra-data-json-server: ^4.10.2 react: ^18.2.0 - react-admin: ^4.9.4 + react-admin: ^4.10.2 react-dom: ^18.2.0 typescript: ^4.6.4 vite: ^3.2.0