Skip to content

Commit

Permalink
Fix TabbedForm with uri encoded identifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
djhi committed Jul 19, 2024
1 parent c4547b1 commit a94172a
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 42 deletions.
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

0 comments on commit a94172a

Please sign in to comment.