Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7271d36
update SavedQueryFilterListItem to update listContext stateinstead of…
ThieryMichel Feb 26, 2026
6c50a2c
add test
ThieryMichel Feb 26, 2026
3d3c0eb
Merge pull request #11173 from marmelab/saved-queries-disableSyncWith…
WiXSL Mar 2, 2026
b4c2d43
fix(ListButtons): fix nested list toggling in rich text editor
frlruehle Mar 3, 2026
5a90dde
Merge pull request #11179 from frlruehle/fix-allow-nesting-different-…
slax57 Mar 4, 2026
f41cba3
Bump dompurify and @types/dompurify
dependabot[bot] Mar 4, 2026
65fb7e8
Merge pull request #11180 from marmelab/dependabot/npm_and_yarn/multi…
slax57 Mar 5, 2026
4dc47cd
docs: use splat route for TanStack Start setup
WiXSL Mar 5, 2026
76e18e4
docs: simplify TanStack Start postgrest setup
WiXSL Mar 5, 2026
ba218f6
Merge pull request #11182 from marmelab/doc-tanstack-start-splat-route
ThieryMichel Mar 6, 2026
9de7480
update deps to fix vulnerabilities
ThieryMichel Mar 9, 2026
00c18b6
Merge pull request #11183 from marmelab/fix-dependabot-alert
fzaninotto Mar 9, 2026
319ece6
Bump dompurify from 3.3.1 to 3.3.2
dependabot[bot] Mar 9, 2026
54daad9
Bump js-yaml from 3.14.1 to 3.14.2
dependabot[bot] Mar 9, 2026
a2d8eeb
Merge pull request #11184 from marmelab/dependabot/npm_and_yarn/dompu…
fzaninotto Mar 9, 2026
289889c
Merge pull request #11185 from marmelab/dependabot/npm_and_yarn/js-ya…
fzaninotto Mar 9, 2026
4bd6d4a
Fix compatibility with latest version of `@hookform/resolvers`
slax57 Mar 10, 2026
9455780
fix tests
slax57 Mar 10, 2026
6bb138d
Merge pull request #11186 from marmelab/fix-@hookform/resolvers-compat
ThieryMichel Mar 10, 2026
6d4a767
v5.14.4
slax57 Mar 10, 2026
fbb97ae
Update changelog for version 5.14.4
slax57 Mar 10, 2026
faa3d60
Merge remote-tracking branch 'origin/master' into merge-master-5.14.4
slax57 Mar 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## 5.14.4

* Fix SavedQuery when `disableSyncWithLocation` is set ([#11173](https://github.com/marmelab/react-admin/pull/11173)) ([ThieryMichel](https://github.com/ThieryMichel))
* Fix `RichTextInput` does not allow nesting unordered and ordered lists ([#11179](https://github.com/marmelab/react-admin/pull/11179)) ([frlruehle](https://github.com/frlruehle))
* Fix compatibility with latest version of `@hookform/resolvers` ([#11186](https://github.com/marmelab/react-admin/pull/11186)) ([slax57](https://github.com/slax57))
* [Doc] Use splat route for TanStack Start setup ([#11182](https://github.com/marmelab/react-admin/pull/11182)) ([WiXSL](https://github.com/WiXSL))
* Fix security warnings due to outdated dependencies ([#11183](https://github.com/marmelab/react-admin/pull/11183)) ([ThieryMichel](https://github.com/ThieryMichel))
* Bump js-yaml from 3.14.1 to 3.14.2 ([#11185](https://github.com/marmelab/react-admin/pull/11185)) ([dependabot[bot]](https://github.com/apps/dependabot))
* Bump dompurify from 3.3.1 to 3.3.2 ([#11184](https://github.com/marmelab/react-admin/pull/11184)) ([dependabot[bot]](https://github.com/apps/dependabot))
* Bump dompurify and @types/dompurify ([#11180](https://github.com/marmelab/react-admin/pull/11180)) ([dependabot[bot]](https://github.com/apps/dependabot))

## 5.14.3

* Add default empty component and i18n messages to `ListGuesser` ([#11165](https://github.com/marmelab/react-admin/pull/11165)) ([WiXSL](https://github.com/WiXSL))
Expand Down
30 changes: 7 additions & 23 deletions docs/TanStackStart.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ yarn add react-admin ra-router-tanstack ra-data-json-server

## Adding React-Admin In A Sub Route

TanStack Start uses file-based routing. React-admin generates dynamic routes for each resource (e.g. `/admin/users`, `/admin/users/:id`). To avoid “Not Found” pages, we create explicit routes for the resource paths and render the same admin component in each route.
TanStack Start uses file-based routing. React-admin generates dynamic routes for each resource (e.g. `/admin/users`, `/admin/users/:id`). To avoid creating one TanStack route per react-admin page, use a single splat route.

First, create the admin route at `src/routes/admin.tsx`:
First, create the admin route at `src/routes/admin.$.tsx`:

```tsx
// in src/routes/admin.tsx
// in src/routes/admin.$.tsx
import { createFileRoute } from '@tanstack/react-router';
import {
Admin,
Expand All @@ -71,7 +71,7 @@ import jsonServerProvider from 'ra-data-json-server';
import { tanStackRouterProvider } from 'ra-router-tanstack';

const dataProvider = jsonServerProvider('https://jsonplaceholder.typicode.com');
export const Route = createFileRoute('/admin')({ component: App });
export const Route = createFileRoute('/admin/$')({ component: App });

function App() {
return (
Expand All @@ -92,7 +92,7 @@ function App() {
export default App;
```

Then create the routes for the resource and its dynamic paths:
Then keep the root route as a simple link to the admin:

```tsx
// in src/routes/index.tsx
Expand All @@ -112,22 +112,6 @@ function Home() {
export const Route = createFileRoute('/')({ component: Home });
```

```tsx
// in src/routes/admin.users.tsx
import { createFileRoute } from '@tanstack/react-router';
import App from './admin';

export const Route = createFileRoute('/admin/users')({ component: App });
```

```tsx
// in src/routes/admin.users.$id.tsx
import { createFileRoute } from '@tanstack/react-router';
import App from './admin';

export const Route = createFileRoute('/admin/users/$id')({ component: App });
```


You can now start the app in `development` mode:

Expand All @@ -141,7 +125,7 @@ The admin should render at `/admin` on your dev server.

![TanStack Start admin screen](./img/tanstack-admin.png)

**Tip**: If you add more resources, create matching file-based routes for each resource list and edit path under `/admin` and point them to the same `App` component.
**Tip**: With the `/admin/$` route, you don't need to create one TanStack Start route file per react-admin page.

## Removing The TanStack Header

Expand Down Expand Up @@ -229,7 +213,7 @@ yarn add @raphiniert/ra-data-postgrest
Finally, update your Admin dataProvider:

```tsx
// in src/routes/admin.tsx
// in src/routes/admin.$.tsx
import { Admin, Resource, ListGuesser, fetchUtils } from 'react-admin';
import postgrestRestProvider from '@raphiniert/ra-data-postgrest';
import { tanStackRouterProvider } from 'ra-router-tanstack';
Expand Down
4 changes: 2 additions & 2 deletions examples/data-generator/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "data-generator-retail",
"version": "5.14.3",
"version": "5.14.4",
"homepage": "https://github.com/marmelab/react-admin/tree/master/examples/data-generator",
"bugs": "https://github.com/marmelab/react-admin/issues",
"license": "MIT",
Expand All @@ -17,7 +17,7 @@
"date-fns": "^3.6.0"
},
"devDependencies": {
"ra-core": "^5.14.3",
"ra-core": "^5.14.4",
"typescript": "^5.1.3",
"zshy": "^0.5.0"
},
Expand Down
14 changes: 7 additions & 7 deletions examples/simple/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "simple",
"version": "5.14.3",
"version": "5.14.4",
"private": true,
"type": "module",
"scripts": {
Expand All @@ -17,13 +17,13 @@
"fakerest": "^4.1.3",
"jsonexport": "^3.2.0",
"lodash": "~4.17.5",
"ra-data-fakerest": "^5.14.3",
"ra-i18n-polyglot": "^5.14.3",
"ra-input-rich-text": "^5.14.3",
"ra-language-english": "^5.14.3",
"ra-language-french": "^5.14.3",
"ra-data-fakerest": "^5.14.4",
"ra-i18n-polyglot": "^5.14.4",
"ra-input-rich-text": "^5.14.4",
"ra-language-english": "^5.14.4",
"ra-language-french": "^5.14.4",
"react": "^18.3.1",
"react-admin": "^5.14.3",
"react-admin": "^5.14.4",
"react-dom": "^18.3.1",
"react-hook-form": "^7.65.0",
"react-router": "^6.28.1",
Expand Down
6 changes: 3 additions & 3 deletions lerna.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"lerna": "2.5.1",
"packages": ["examples/data-generator", "examples/simple", "packages/*"],
"version": "5.14.3",
"npmClient": "yarn"
"version": "5.14.4",
"npmClient": "yarn",
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@
"globals": "^16.0.0",
"husky": "^2.3.0",
"jest": "^29.5.0",
"jest-circus": "29.5.0",
"jest-circus": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"jest-resolve": "29.5.0",
"jest-resolve": "^29.5.0",
"jest-watch-typeahead": "2.2.2",
"lerna": "~7.1.3",
"lerna": "^9.0.5",
"lint-staged": "^13.0.3",
"lodash": "^4.17.21",
"lolex": "~2.3.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/create-react-admin/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "create-react-admin",
"description": "A CLI to quickly start a new react-admin project",
"version": "5.14.3",
"version": "5.14.4",
"license": "MIT",
"bin": "lib/cli.js",
"type": "module",
Expand Down
6 changes: 3 additions & 3 deletions packages/ra-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ra-core",
"version": "5.14.3",
"version": "5.14.4",
"description": "Core components of react-admin, a frontend Framework for building admin applications on top of REST services, using ES6, React",
"files": [
"*.md",
Expand Down Expand Up @@ -38,7 +38,7 @@
"build": "zshy --silent"
},
"devDependencies": {
"@hookform/resolvers": "^3.2.0",
"@hookform/resolvers": "^5.2.2",
"@tanstack/react-query": "^5.90.2",
"@tanstack/react-query-devtools": "^5.90.2",
"@testing-library/react": "^15.0.7",
Expand All @@ -58,7 +58,7 @@
"react-router-dom": "^6.28.1",
"typescript": "^5.1.3",
"yup": "^0.32.11",
"zod": "^3.22.1",
"zod": "^4.3.6",
"zshy": "^0.5.0"
},
"peerDependencies": {
Expand Down
4 changes: 3 additions & 1 deletion packages/ra-core/src/form/Form.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,9 @@ describe('Form', () => {
const translate = jest.spyOn(i18nProvider, 'translate');
render(<ZodResolver i18nProvider={i18nProvider} />);
fireEvent.click(screen.getByText('Submit'));
await screen.findByText('Required');
await screen.findByText(
'Invalid input: expected string, received undefined'
);
await screen.findByText('This field is required');
await screen.findByText('This field must be provided');
await screen.findByText('app.validation.missing');
Expand Down
73 changes: 66 additions & 7 deletions packages/ra-core/src/form/Form.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
} from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
import polyglotI18nProvider from 'ra-i18n-polyglot';
import englishMessages from 'ra-language-english';
import {
Expand Down Expand Up @@ -273,14 +275,10 @@ export const InputLevelValidation = ({

const zodSchema = z.object({
defaultMessage: z.string(), //.min(1),
customMessage: z.string({
required_error: 'This field is required',
}),
customMessageTranslationKey: z.string({
required_error: 'app.validation.required',
}),
customMessage: z.string({ error: 'This field is required' }),
customMessageTranslationKey: z.string({ error: 'app.validation.required' }),
missingCustomMessageTranslationKey: z.string({
required_error: 'app.validation.missing',
error: 'app.validation.missing',
}),
});

Expand Down Expand Up @@ -308,6 +306,67 @@ export const ZodResolver = ({
);
};

type Schema = z.infer<typeof zodSchema>;

export const ZodResolverWithSchema = ({
i18nProvider = defaultI18nProvider,
}: {
i18nProvider?: I18nProvider;
}) => {
const [result, setResult] = React.useState<any>();
return (
<CoreAdminContext i18nProvider={i18nProvider}>
<Form<Schema>
record={{}}
onSubmit={data => setResult(data)}
resolver={zodResolver(zodSchema)}
>
<Input source="defaultMessage" />
<Input source="customMessage" />
<Input source="customMessageTranslationKey" />
<Input source="missingCustomMessageTranslationKey" />
<button type="submit">Submit</button>
</Form>
<pre>{JSON.stringify(result, null, 2)}</pre>
</CoreAdminContext>
);
};

const yupSchema = yup.object({
defaultMessage: yup.string().required(),
customMessage: yup.string().required('This field is required'),
customMessageTranslationKey: yup
.string()
.required('app.validation.required'),
missingCustomMessageTranslationKey: yup
.string()
.required('app.validation.missing'),
});

export const YupResolver = ({
i18nProvider = defaultI18nProvider,
}: {
i18nProvider?: I18nProvider;
}) => {
const [result, setResult] = React.useState<any>();
return (
<CoreAdminContext i18nProvider={i18nProvider}>
<Form
record={{}}
onSubmit={data => setResult(data)}
resolver={yupResolver(yupSchema)}
>
<Input source="defaultMessage" />
<Input source="customMessage" />
<Input source="customMessageTranslationKey" />
<Input source="missingCustomMessageTranslationKey" />
<button type="submit">Submit</button>
</Form>
<pre>{JSON.stringify(result, null, 2)}</pre>
</CoreAdminContext>
);
};

const FormUnderTest = () => {
const navigate = useNavigate();
return (
Expand Down
7 changes: 5 additions & 2 deletions packages/ra-core/src/form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export function Form<RecordType = any>(props: FormProps<RecordType>) {
} = props;
const record = useRecordContext(props);
const resource = useResourceContext(props);
const { form, formHandleSubmit } = useAugmentedForm(props);
const { form, formHandleSubmit } = useAugmentedForm<RecordType>(props);
const sourceContext = React.useMemo<SourceContextValue>(
() => ({
getSource: (source: string) => source,
Expand Down Expand Up @@ -113,7 +113,10 @@ export function Form<RecordType = any>(props: FormProps<RecordType>) {
}

export type FormProps<RecordType = any> = FormOwnProps<RecordType> &
Omit<UseFormProps, 'onSubmit'> & {
Omit<
UseFormProps<RecordType extends FieldValues ? RecordType : FieldValues>,
'onSubmit'
> & {
validate?: ValidateForm;
noValidate?: boolean;
WarnWhenUnsavedChangesComponent?: React.ComponentType<{
Expand Down
7 changes: 6 additions & 1 deletion packages/ra-core/src/form/useAugmentedForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,12 @@ export const useAugmentedForm = <RecordType = any>(

export type UseAugmentedFormProps<RecordType = any> =
UseFormOwnProps<RecordType> &
Omit<UseFormProps, 'onSubmit'> & {
Omit<
UseFormProps<
RecordType extends FieldValues ? RecordType : FieldValues
>,
'onSubmit'
> & {
validate?: ValidateForm;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FieldValues } from 'react-hook-form';
import { FieldValues, Resolver } from 'react-hook-form';

/**
* Convert a simple validation function that returns an object matching the form shape with errors
Expand All @@ -25,7 +25,7 @@ import { FieldValues } from 'react-hook-form';
export const getSimpleValidationResolver =
<TFieldValues extends FieldValues = FieldValues>(
validate: ValidateForm<TFieldValues>
) =>
): Resolver<TFieldValues> =>
async (data: TFieldValues) => {
const errors = await validate(data);

Expand Down
4 changes: 2 additions & 2 deletions packages/ra-data-fakerest/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ra-data-fakerest",
"version": "5.14.3",
"version": "5.14.4",
"description": "JSON Server data provider for react-admin",
"zshy": "./src/index.ts",
"main": "./dist/index.cjs",
Expand Down Expand Up @@ -41,7 +41,7 @@
"devDependencies": {
"@types/jest": "^29.5.2",
"expect": "^27.4.6",
"ra-core": "^5.14.3",
"ra-core": "^5.14.4",
"typescript": "^5.1.3",
"zshy": "^0.5.0"
},
Expand Down
4 changes: 2 additions & 2 deletions packages/ra-data-graphql-simple/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ra-data-graphql-simple",
"version": "5.14.3",
"version": "5.14.4",
"description": "A GraphQL simple data provider for react-admin",
"zshy": "./src/index.ts",
"main": "./dist/index.cjs",
Expand Down Expand Up @@ -36,7 +36,7 @@
"graphql-ast-types-browser": "~1.0.2",
"lodash": "~4.17.5",
"pluralize": "~7.0.0",
"ra-data-graphql": "^5.14.3"
"ra-data-graphql": "^5.14.4"
},
"peerDependencies": {
"graphql": "^15.6.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/ra-data-graphql/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ra-data-graphql",
"version": "5.14.3",
"version": "5.14.4",
"description": "A GraphQL data provider for react-admin",
"zshy": "./src/index.ts",
"main": "./dist/index.cjs",
Expand Down
Loading
Loading