Skip to content

Commit b7ad7b3

Browse files
authored
Merge pull request #7699 from marmelab/guessers-with-import
Add imports to guesser output
2 parents 89700e3 + 9d36311 commit b7ad7b3

File tree

6 files changed

+332
-66
lines changed

6 files changed

+332
-66
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import * as React from 'react';
2+
import expect from 'expect';
3+
import { render, screen, waitFor } from '@testing-library/react';
4+
import { CoreAdminContext } from 'ra-core';
5+
6+
import { EditGuesser } from './EditGuesser';
7+
import { ThemeProvider } from '../layout';
8+
9+
describe('<EditGuesser />', () => {
10+
it('should log the guessed Edit view based on the fetched record', async () => {
11+
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
12+
const dataProvider = {
13+
getOne: () =>
14+
Promise.resolve({
15+
data: {
16+
id: 123,
17+
author: 'john doe',
18+
post_id: 6,
19+
score: 3,
20+
body:
21+
"Queen, tossing her head through the wood. 'If it had lost something; and she felt sure it.",
22+
created_at: new Date('2012-08-02'),
23+
},
24+
}),
25+
getMany: () => Promise.resolve({ data: [] }),
26+
};
27+
render(
28+
<ThemeProvider theme={{}}>
29+
<CoreAdminContext dataProvider={dataProvider as any}>
30+
<EditGuesser resource="comments" id={123} />
31+
</CoreAdminContext>
32+
</ThemeProvider>
33+
);
34+
await waitFor(() => {
35+
screen.getByDisplayValue('john doe');
36+
});
37+
expect(logSpy).toHaveBeenCalledWith(`Guessed Edit:
38+
39+
import { DateInput, Edit, NumberInput, ReferenceInput, SelectInput, SimpleForm, TextInput } from 'react-admin';
40+
41+
export const CommentEdit = () => (
42+
<Edit>
43+
<SimpleForm>
44+
<TextInput source="id" />
45+
<TextInput source="author" />
46+
<ReferenceInput source="post_id" reference="posts"><SelectInput optionText="id" /></ReferenceInput>
47+
<NumberInput source="score" />
48+
<TextInput source="body" />
49+
<DateInput source="created_at" />
50+
</SimpleForm>
51+
</Edit>
52+
);`);
53+
});
54+
});

packages/ra-ui-materialui/src/detail/EditGuesser.tsx

+64-24
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import * as React from 'react';
22
import { useEffect, useState } from 'react';
33
import inflection from 'inflection';
44
import {
5-
useEditController,
6-
EditContextProvider,
5+
EditBase,
76
InferredElement,
87
useResourceContext,
98
useEditContext,
@@ -14,12 +13,45 @@ import { EditProps } from '../types';
1413
import { EditView } from './EditView';
1514
import { editFieldTypes } from './editFieldTypes';
1615

16+
export const EditGuesser = (props: EditProps) => {
17+
const {
18+
resource,
19+
id,
20+
mutationMode,
21+
mutationOptions,
22+
queryOptions,
23+
redirect,
24+
transform,
25+
disableAuthentication,
26+
...rest
27+
} = props;
28+
return (
29+
<EditBase
30+
resource={resource}
31+
id={id}
32+
mutationMode={mutationMode}
33+
mutationOptions={mutationOptions}
34+
queryOptions={queryOptions}
35+
redirect={redirect}
36+
transform={transform}
37+
disableAuthentication={disableAuthentication}
38+
>
39+
<EditViewGuesser {...rest} />
40+
</EditBase>
41+
);
42+
};
43+
1744
const EditViewGuesser = props => {
1845
const resource = useResourceContext(props);
1946
const { record } = useEditContext();
20-
const [inferredChild, setInferredChild] = useState(null);
47+
const [child, setChild] = useState(null);
48+
49+
useEffect(() => {
50+
setChild(null);
51+
}, [resource]);
52+
2153
useEffect(() => {
22-
if (record && !inferredChild) {
54+
if (record && !child) {
2355
const inferredElements = getElementsFromRecords(
2456
[record],
2557
editFieldTypes
@@ -29,34 +61,42 @@ const EditViewGuesser = props => {
2961
null,
3062
inferredElements
3163
);
64+
setChild(inferredChild.getElement());
65+
66+
if (process.env.NODE_ENV === 'production') return;
3267

33-
process.env.NODE_ENV !== 'production' &&
34-
// eslint-disable-next-line no-console
35-
console.log(
36-
`Guessed Edit:
68+
const representation = inferredChild.getRepresentation();
69+
70+
const components = ['Edit']
71+
.concat(
72+
Array.from(
73+
new Set(
74+
Array.from(representation.matchAll(/<([^/\s>]+)/g))
75+
.map(match => match[1])
76+
.filter(component => component !== 'span')
77+
)
78+
)
79+
)
80+
.sort();
81+
82+
// eslint-disable-next-line no-console
83+
console.log(
84+
`Guessed Edit:
85+
86+
import { ${components.join(', ')} } from 'react-admin';
3787
3888
export const ${inflection.capitalize(
39-
inflection.singularize(resource)
40-
)}Edit = () => (
89+
inflection.singularize(resource)
90+
)}Edit = () => (
4191
<Edit>
42-
${inferredChild.getRepresentation()}
92+
${representation}
4393
</Edit>
4494
);`
45-
);
46-
setInferredChild(inferredChild.getElement());
95+
);
4796
}
48-
}, [record, inferredChild, resource]);
97+
}, [record, child, resource]);
4998

50-
return <EditView {...props}>{inferredChild}</EditView>;
99+
return <EditView {...props}>{child}</EditView>;
51100
};
52101

53102
EditViewGuesser.propTypes = EditView.propTypes;
54-
55-
export const EditGuesser = (props: EditProps) => {
56-
const controllerProps = useEditController(props);
57-
return (
58-
<EditContextProvider value={controllerProps}>
59-
<EditViewGuesser {...props} />
60-
</EditContextProvider>
61-
);
62-
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import * as React from 'react';
2+
import expect from 'expect';
3+
import { render, screen, waitFor } from '@testing-library/react';
4+
import { CoreAdminContext } from 'ra-core';
5+
6+
import { ShowGuesser } from './ShowGuesser';
7+
import { ThemeProvider } from '../layout';
8+
9+
describe('<ShowGuesser />', () => {
10+
it('should log the guessed Show view based on the fetched record', async () => {
11+
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
12+
const dataProvider = {
13+
getOne: () =>
14+
Promise.resolve({
15+
data: {
16+
id: 123,
17+
author: 'john doe',
18+
post_id: 6,
19+
score: 3,
20+
body:
21+
"Queen, tossing her head through the wood. 'If it had lost something; and she felt sure it.",
22+
created_at: new Date('2012-08-02'),
23+
},
24+
}),
25+
};
26+
render(
27+
<ThemeProvider theme={{}}>
28+
<CoreAdminContext dataProvider={dataProvider as any}>
29+
<ShowGuesser resource="comments" id={123} />
30+
</CoreAdminContext>
31+
</ThemeProvider>
32+
);
33+
await waitFor(() => {
34+
screen.getByText('john doe');
35+
});
36+
expect(logSpy).toHaveBeenCalledWith(`Guessed Show:
37+
38+
import { DateField, NumberField, ReferenceField, Show, SimpleShowLayout, TextField } from 'react-admin';
39+
40+
export const CommentShow = () => (
41+
<Show>
42+
<SimpleShowLayout>
43+
<TextField source="id" />
44+
<TextField source="author" />
45+
<ReferenceField source="post_id" reference="posts"><TextField source="id" /></ReferenceField>
46+
<NumberField source="score" />
47+
<TextField source="body" />
48+
<DateField source="created_at" />
49+
</SimpleShowLayout>
50+
</Show>
51+
);`);
52+
});
53+
});

packages/ra-ui-materialui/src/detail/ShowGuesser.tsx

+44-20
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,28 @@ import { ShowProps } from '../types';
1313
import { ShowView } from './ShowView';
1414
import { showFieldTypes } from './showFieldTypes';
1515

16+
export const ShowGuesser = ({
17+
id,
18+
queryOptions,
19+
resource,
20+
...rest
21+
}: Omit<ShowProps, 'children'>) => (
22+
<ShowBase id={id} resource={resource} queryOptions={queryOptions}>
23+
<ShowViewGuesser {...rest} />
24+
</ShowBase>
25+
);
26+
1627
const ShowViewGuesser = props => {
1728
const resource = useResourceContext(props);
1829
const { record } = useShowContext();
19-
const [inferredChild, setInferredChild] = useState(null);
30+
const [child, setChild] = useState(null);
31+
32+
useEffect(() => {
33+
setChild(null);
34+
}, [resource]);
35+
2036
useEffect(() => {
21-
if (record && !inferredChild) {
37+
if (record && !child) {
2238
const inferredElements = getElementsFromRecords(
2339
[record],
2440
showFieldTypes
@@ -28,33 +44,41 @@ const ShowViewGuesser = props => {
2844
null,
2945
inferredElements
3046
);
47+
setChild(inferredChild.getElement());
48+
49+
if (process.env.NODE_ENV === 'production') return;
3150

32-
process.env.NODE_ENV !== 'production' &&
33-
// eslint-disable-next-line no-console
34-
console.log(
35-
`Guessed Show:
51+
const representation = inferredChild.getRepresentation();
52+
const components = ['Show']
53+
.concat(
54+
Array.from(
55+
new Set(
56+
Array.from(representation.matchAll(/<([^/\s>]+)/g))
57+
.map(match => match[1])
58+
.filter(component => component !== 'span')
59+
)
60+
)
61+
)
62+
.sort();
63+
64+
// eslint-disable-next-line no-console
65+
console.log(
66+
`Guessed Show:
67+
68+
import { ${components.join(', ')} } from 'react-admin';
3669
3770
export const ${inflection.capitalize(
38-
inflection.singularize(resource)
39-
)}Show = () => (
71+
inflection.singularize(resource)
72+
)}Show = () => (
4073
<Show>
4174
${inferredChild.getRepresentation()}
4275
</Show>
4376
);`
44-
);
45-
setInferredChild(inferredChild.getElement());
77+
);
4678
}
47-
}, [record, inferredChild, resource]);
79+
}, [record, child, resource]);
4880

49-
return <ShowView {...props}>{inferredChild}</ShowView>;
81+
return <ShowView {...props}>{child}</ShowView>;
5082
};
5183

5284
ShowViewGuesser.propTypes = ShowView.propTypes;
53-
54-
export const ShowGuesser = ({ id, queryOptions, ...rest }: ShowProps) => (
55-
<ShowBase id={id} queryOptions={queryOptions}>
56-
<ShowViewGuesser {...rest} />
57-
</ShowBase>
58-
);
59-
60-
export default ShowGuesser;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import * as React from 'react';
2+
import expect from 'expect';
3+
import { render, screen, waitFor } from '@testing-library/react';
4+
import { CoreAdminContext } from 'ra-core';
5+
6+
import { ListGuesser } from './ListGuesser';
7+
import { ThemeProvider } from '../layout';
8+
9+
describe('<ListGuesser />', () => {
10+
it('should log the guessed List view based on the fetched records', async () => {
11+
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
12+
const dataProvider = {
13+
getList: () =>
14+
Promise.resolve({
15+
data: [
16+
{
17+
id: 123,
18+
author: 'john doe',
19+
post_id: 6,
20+
score: 3,
21+
body:
22+
"Queen, tossing her head through the wood. 'If it had lost something; and she felt sure it.",
23+
created_at: new Date('2012-08-02'),
24+
},
25+
],
26+
total: 1,
27+
}),
28+
};
29+
render(
30+
<ThemeProvider theme={{}}>
31+
<CoreAdminContext dataProvider={dataProvider as any}>
32+
<ListGuesser resource="comments" />
33+
</CoreAdminContext>
34+
</ThemeProvider>
35+
);
36+
await waitFor(() => {
37+
screen.getByText('john doe');
38+
});
39+
expect(logSpy).toHaveBeenCalledWith(`Guessed List:
40+
41+
import { Datagrid, DateField, List, NumberField, ReferenceField, TextField } from 'react-admin';
42+
43+
export const CommentList = () => (
44+
<List>
45+
<Datagrid rowClick="edit">
46+
<TextField source="id" />
47+
<TextField source="author" />
48+
<ReferenceField source="post_id" reference="posts"><TextField source="id" /></ReferenceField>
49+
<NumberField source="score" />
50+
<TextField source="body" />
51+
<DateField source="created_at" />
52+
</Datagrid>
53+
</List>
54+
);`);
55+
});
56+
});

0 commit comments

Comments
 (0)