Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix TabbedForm with uri encoded identifiers #10021

Merged
merged 1 commit into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions packages/ra-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.52.0",
"react-router": "^6.22.0",
"react-router-dom": "^6.22.0",
"react-router": "^6.25.1",
"react-router-dom": "^6.25.1",
"react-test-renderer": "^18.2.0",
"recharts": "^2.1.15",
"rimraf": "^3.0.2",
Expand Down
4 changes: 2 additions & 2 deletions packages/ra-ui-materialui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
"react-dom": "^18.3.1",
"react-hook-form": "^7.52.0",
"react-is": "^18.2.0",
"react-router": "^6.22.0",
"react-router-dom": "^6.22.0",
"react-router": "^6.25.1",
"react-router-dom": "^6.25.1",
"react-test-renderer": "^18.2.0",
"rimraf": "^3.0.2",
"typescript": "^5.1.3"
Expand Down
9 changes: 9 additions & 0 deletions packages/ra-ui-materialui/src/form/TabbedForm.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { AdminContext } from '../AdminContext';
import { TabbedForm } from './TabbedForm';
import { TabbedFormClasses } from './TabbedFormView';
import { TextInput } from '../input';
import { EncodedPaths } from './TabbedForm.stories';

describe('<TabbedForm />', () => {
it('should display the tabs', () => {
Expand All @@ -38,6 +39,14 @@ describe('<TabbedForm />', () => {
expect(tabs.length).toEqual(2);
});

it('should display the tabs contents with encoded complex record identifiers', async () => {
render(<EncodedPaths />);

const tabs = await screen.findAllByRole('tab');
expect(tabs.length).toEqual(2);
await screen.findByLabelText('Title');
});

it('should set the style of an inactive Tab button with errors', async () => {
render(
<TestMemoryRouter initialEntries={['/1']}>
Expand Down
78 changes: 60 additions & 18 deletions packages/ra-ui-materialui/src/form/TabbedForm.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import * as React from 'react';
import { ResourceContextProvider, testDataProvider } from 'ra-core';
import {
RaRecord,
ResourceContextProvider,
testDataProvider,
TestMemoryRouter,
} from 'ra-core';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';

Expand All @@ -8,6 +13,7 @@ import { Edit } from '../detail';
import { NumberInput, TextInput } from '../input';
import { TabbedForm } from './TabbedForm';
import { Stack } from '@mui/material';
import { Route, Routes } from 'react-router';

export default { title: 'ra-ui-materialui/forms/TabbedForm' };

Expand All @@ -19,24 +25,38 @@ const data = {
year: 1869,
};

const Wrapper = ({ children }) => (
<AdminContext
i18nProvider={{
translate: (x, options) => options?._ ?? x,
changeLocale: () => Promise.resolve(),
getLocale: () => 'en',
}}
dataProvider={testDataProvider({
getOne: () => Promise.resolve({ data }),
})}
defaultTheme="light"
const Wrapper = ({
children,
record = data,
}: {
children: React.ReactNode;
record?: RaRecord;
}) => (
<TestMemoryRouter
initialEntries={[`/books/${encodeURIComponent(record.id)}`]}
>
<ResourceContextProvider value="books">
<Edit id={1} sx={{ width: 600 }}>
{children}
</Edit>
</ResourceContextProvider>
</AdminContext>
<AdminContext
i18nProvider={{
translate: (x, options) => options?._ ?? x,
changeLocale: () => Promise.resolve(),
getLocale: () => 'en',
}}
dataProvider={testDataProvider({
// @ts-ignore
getOne: () => Promise.resolve({ data: record }),
})}
defaultTheme="light"
>
<ResourceContextProvider value="books">
<Routes>
<Route
path="/books/:id/*"
element={<Edit sx={{ width: 600 }}>{children}</Edit>}
/>
</Routes>
</ResourceContextProvider>
</AdminContext>
</TestMemoryRouter>
);

export const Basic = () => (
Expand Down Expand Up @@ -142,3 +162,25 @@ export const Resolver = () => (
</TabbedForm>
</Wrapper>
);

const dataWithEncodedId = {
id: '1:prod:resource1',
title: 'War and Peace',
author: 'Leo Tolstoy',
bio: 'Leo Tolstoy (1828-1910) was a Russian writer who is regarded as one of the greatest authors of all time. He received nominations for the Nobel Prize in Literature every year from 1902 to 1906 and for the Nobel Peace Prize in 1901, 1902, and 1909.',
year: 1869,
};
export const EncodedPaths = () => (
<Wrapper record={dataWithEncodedId}>
<TabbedForm>
<TabbedForm.Tab label="main">
<TextInput source="title" />
<TextInput source="author" />
<NumberInput source="year" />
</TabbedForm.Tab>
<TabbedForm.Tab label="details">
<TextInput multiline source="bio" />
</TabbedForm.Tab>
</TabbedForm>
</Wrapper>
);
10 changes: 9 additions & 1 deletion packages/ra-ui-materialui/src/form/TabbedFormView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ export const TabbedFormView = (props: TabbedFormViewProps): ReactElement => {
const hidden = syncWithLocation
? !matchPath(
`${resolvedPath.pathname}/${tabPath}`,
location.pathname
// The current location might have encoded segments (e.g. the record id) but resolvedPath.pathname doesn't
// and the match would fail.
getDecodedPathname(location.pathname)
)
: tabValue !== index;

Expand All @@ -102,6 +104,12 @@ export const TabbedFormView = (props: TabbedFormViewProps): ReactElement => {
);
};

/**
* Returns the pathname with each segment decoded
*/
const getDecodedPathname = (pathname: string) =>
pathname.split('/').map(decodeURIComponent).join('/');

const DefaultTabs = <TabbedFormTabs />;
const DefaultComponent = ({ children }) => (
<CardContent>{children}</CardContent>
Expand Down
38 changes: 19 additions & 19 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4143,10 +4143,10 @@ __metadata:
languageName: node
linkType: hard

"@remix-run/router@npm:1.15.0":
version: 1.15.0
resolution: "@remix-run/router@npm:1.15.0"
checksum: 4805b5761ccbce3a522d3313c74ece7d4a411f02fd6d495d20f4352dcc87d8899f1b79a4c172a130e0f7a73b5f63a29177d8860131c35e3388552b1bd38a97f2
"@remix-run/router@npm:1.18.0":
version: 1.18.0
resolution: "@remix-run/router@npm:1.18.0"
checksum: 3ec7e441a0e54932a3d3bf932432094420f2c117715d80a5454bc7e55d13b91250749942aab032cd07aee191f1c1de33fede8682025bfd3a453dd207c016e140
languageName: node
linkType: hard

Expand Down Expand Up @@ -17694,8 +17694,8 @@ __metadata:
react-error-boundary: "npm:^4.0.13"
react-hook-form: "npm:^7.52.0"
react-is: "npm:^18.2.0"
react-router: "npm:^6.22.0"
react-router-dom: "npm:^6.22.0"
react-router: "npm:^6.25.1"
react-router-dom: "npm:^6.25.1"
react-test-renderer: "npm:^18.2.0"
recharts: "npm:^2.1.15"
rimraf: "npm:^3.0.2"
Expand Down Expand Up @@ -17971,8 +17971,8 @@ __metadata:
react-error-boundary: "npm:^4.0.13"
react-hook-form: "npm:^7.52.0"
react-is: "npm:^18.2.0"
react-router: "npm:^6.22.0"
react-router-dom: "npm:^6.22.0"
react-router: "npm:^6.25.1"
react-router-dom: "npm:^6.25.1"
react-test-renderer: "npm:^18.2.0"
react-transition-group: "npm:^4.4.5"
rimraf: "npm:^3.0.2"
Expand Down Expand Up @@ -18413,27 +18413,27 @@ __metadata:
languageName: node
linkType: hard

"react-router-dom@npm:^6.22.0":
version: 6.22.0
resolution: "react-router-dom@npm:6.22.0"
"react-router-dom@npm:^6.22.0, react-router-dom@npm:^6.25.1":
version: 6.25.1
resolution: "react-router-dom@npm:6.25.1"
dependencies:
"@remix-run/router": "npm:1.15.0"
react-router: "npm:6.22.0"
"@remix-run/router": "npm:1.18.0"
react-router: "npm:6.25.1"
peerDependencies:
react: ">=16.8"
react-dom: ">=16.8"
checksum: f1c338d6a37ee331f141d683a9139bc397128f6c15ef796589894ba29de1101eeeab7c4bf26429632c86bbca7376a9d900a6bfbd351ac5c9e1e231ac1b05fe5d
checksum: 15e2b5bf89a26db9a108d19a4e0e2054180bfb1f5f62662dd93ad697ee1bdc91a8041efd762d552c95e65fc06ca0cb0c1e88acdeeaf03aba37f7a29e470c7cc4
languageName: node
linkType: hard

"react-router@npm:6.22.0, react-router@npm:^6.22.0":
version: 6.22.0
resolution: "react-router@npm:6.22.0"
"react-router@npm:6.25.1, react-router@npm:^6.22.0, react-router@npm:^6.25.1":
version: 6.25.1
resolution: "react-router@npm:6.25.1"
dependencies:
"@remix-run/router": "npm:1.15.0"
"@remix-run/router": "npm:1.18.0"
peerDependencies:
react: ">=16.8"
checksum: aa3878321797e526e4f3a57f97e8dd06f7cf6d7b9f95db39ea5d74259a2058404a04af0f852296ba6f09f9cecd7ca5f67125b9853ceb7fe6a852ffa5e3369dca
checksum: a7e824c1f6d9641beabc23111865ddd2525b3794403e07b297fc2bdd4cddec93e166aacdb9d2602768864d70f3bf490f59eeab8474a04ae1f13a832f305eeec3
languageName: node
linkType: hard

Expand Down
Loading