Skip to content

Commit

Permalink
Add imports to guesser output
Browse files Browse the repository at this point in the history
  • Loading branch information
fzaninotto committed May 16, 2022
1 parent e0131ba commit ddd8449
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 49 deletions.
54 changes: 54 additions & 0 deletions packages/ra-ui-materialui/src/detail/EditGuesser.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import * as React from 'react';
import expect from 'expect';
import { render, screen, waitFor } from '@testing-library/react';
import { CoreAdminContext } from 'ra-core';

import { EditGuesser } from './EditGuesser';
import { ThemeProvider } from '../layout';

describe('<EditGuesser />', () => {
it('should log the guessed Edit view based on the fetched record', async () => {
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
const dataProvider = {
getOne: () =>
Promise.resolve({
data: {
id: 123,
author: 'john doe',
post_id: 6,
score: 3,
body:
"Queen, tossing her head through the wood. 'If it had lost something; and she felt sure it.",
created_at: new Date('2012-08-02'),
},
}),
getMany: () => Promise.resolve({ data: [] }),
};
render(
<ThemeProvider theme={{}}>
<CoreAdminContext dataProvider={dataProvider as any}>
<EditGuesser resource="comments" id={123} />
</CoreAdminContext>
</ThemeProvider>
);
await waitFor(() => {
screen.getByDisplayValue('john doe');
});
expect(logSpy).toHaveBeenCalledWith(`Guessed Edit:
import { DateInput, Edit, NumberInput, ReferenceInput, SelectInput, SimpleForm, TextInput } from 'react-admin';
export const CommentEdit = () => (
<Edit>
<SimpleForm>
<TextInput source="id" />
<TextInput source="author" />
<ReferenceInput source="post_id" reference="posts"><SelectInput optionText="id" /></ReferenceInput>
<NumberInput source="score" />
<TextInput source="body" />
<DateInput source="created_at" />
</SimpleForm>
</Edit>
);`);
});
});
74 changes: 54 additions & 20 deletions packages/ra-ui-materialui/src/detail/EditGuesser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import * as React from 'react';
import { useEffect, useState } from 'react';
import inflection from 'inflection';
import {
useEditController,
EditContextProvider,
EditBase,
InferredElement,
useResourceContext,
useEditContext,
Expand All @@ -14,6 +13,34 @@ import { EditProps } from '../types';
import { EditView } from './EditView';
import { editFieldTypes } from './editFieldTypes';

export const EditGuesser = (props: EditProps) => {
const {
resource,
id,
mutationMode,
mutationOptions,
queryOptions,
redirect,
transform,
disableAuthentication,
...rest
} = props;
return (
<EditBase
resource={resource}
id={id}
mutationMode={mutationMode}
mutationOptions={mutationOptions}
queryOptions={queryOptions}
redirect={redirect}
transform={transform}
disableAuthentication={disableAuthentication}
>
<EditViewGuesser {...rest} />
</EditBase>
);
};

const EditViewGuesser = props => {
const resource = useResourceContext(props);
const { record } = useEditContext();
Expand All @@ -29,34 +56,41 @@ const EditViewGuesser = props => {
null,
inferredElements
);
setInferredChild(inferredChild.getElement());

if (process.env.NODE_ENV === 'production') return;

const representation = inferredChild.getRepresentation();
const components = ['Edit']
.concat(
Array.from(
new Set(
Array.from(representation.matchAll(/<([^\/\s>]+)/g))
.map(match => match[1])
.filter(component => component !== 'span')
)
)
)
.sort();

process.env.NODE_ENV !== 'production' &&
// eslint-disable-next-line no-console
console.log(
`Guessed Edit:
// eslint-disable-next-line no-console
console.log(
`Guessed Edit:
import { ${components.join(', ')} } from 'react-admin';
export const ${inflection.capitalize(
inflection.singularize(resource)
)}Edit = () => (
inflection.singularize(resource)
)}Edit = () => (
<Edit>
${inferredChild.getRepresentation()}
${representation}
</Edit>
);`
);
setInferredChild(inferredChild.getElement());
);
}
}, [record, inferredChild, resource]);

return <EditView {...props}>{inferredChild}</EditView>;
};

EditViewGuesser.propTypes = EditView.propTypes;

export const EditGuesser = (props: EditProps) => {
const controllerProps = useEditController(props);
return (
<EditContextProvider value={controllerProps}>
<EditViewGuesser {...props} />
</EditContextProvider>
);
};
53 changes: 53 additions & 0 deletions packages/ra-ui-materialui/src/detail/ShowGuesser.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import * as React from 'react';
import expect from 'expect';
import { render, screen, waitFor } from '@testing-library/react';
import { CoreAdminContext } from 'ra-core';

import { ShowGuesser } from './ShowGuesser';
import { ThemeProvider } from '../layout';

describe('<ShowGuesser />', () => {
it('should log the guessed Show view based on the fetched record', async () => {
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
const dataProvider = {
getOne: () =>
Promise.resolve({
data: {
id: 123,
author: 'john doe',
post_id: 6,
score: 3,
body:
"Queen, tossing her head through the wood. 'If it had lost something; and she felt sure it.",
created_at: new Date('2012-08-02'),
},
}),
};
render(
<ThemeProvider theme={{}}>
<CoreAdminContext dataProvider={dataProvider as any}>
<ShowGuesser resource="comments" id={123} />
</CoreAdminContext>
</ThemeProvider>
);
await waitFor(() => {
screen.getByText('john doe');
});
expect(logSpy).toHaveBeenCalledWith(`Guessed Show:
import { DateField, NumberField, ReferenceField, Show, SimpleShowLayout, TextField } from 'react-admin';
export const CommentShow = () => (
<Show>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="author" />
<ReferenceField source="post_id" reference="posts"><TextField source="id" /></ReferenceField>
<NumberField source="score" />
<TextField source="body" />
<DateField source="created_at" />
</SimpleShowLayout>
</Show>
);`);
});
});
49 changes: 34 additions & 15 deletions packages/ra-ui-materialui/src/detail/ShowGuesser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ import { ShowProps } from '../types';
import { ShowView } from './ShowView';
import { showFieldTypes } from './showFieldTypes';

export const ShowGuesser = ({
id,
queryOptions,
resource,
...rest
}: Omit<ShowProps, 'children'>) => (
<ShowBase id={id} resource={resource} queryOptions={queryOptions}>
<ShowViewGuesser {...rest} />
</ShowBase>
);

const ShowViewGuesser = props => {
const resource = useResourceContext(props);
const { record } = useShowContext();
Expand All @@ -29,19 +40,35 @@ const ShowViewGuesser = props => {
inferredElements
);

process.env.NODE_ENV !== 'production' &&
// eslint-disable-next-line no-console
console.log(
`Guessed Show:
if (process.env.NODE_ENV === 'production') return;

const representation = inferredChild.getRepresentation();
const components = ['Show']
.concat(
Array.from(
new Set(
Array.from(representation.matchAll(/<([^\/\s>]+)/g))
.map(match => match[1])
.filter(component => component !== 'span')
)
)
)
.sort();

// eslint-disable-next-line no-console
console.log(
`Guessed Show:
import { ${components.join(', ')} } from 'react-admin';
export const ${inflection.capitalize(
inflection.singularize(resource)
)}Show = () => (
inflection.singularize(resource)
)}Show = () => (
<Show>
${inferredChild.getRepresentation()}
</Show>
);`
);
);
setInferredChild(inferredChild.getElement());
}
}, [record, inferredChild, resource]);
Expand All @@ -50,11 +77,3 @@ ${inferredChild.getRepresentation()}
};

ShowViewGuesser.propTypes = ShowView.propTypes;

export const ShowGuesser = ({ id, queryOptions, ...rest }: ShowProps) => (
<ShowBase id={id} queryOptions={queryOptions}>
<ShowViewGuesser {...rest} />
</ShowBase>
);

export default ShowGuesser;
56 changes: 56 additions & 0 deletions packages/ra-ui-materialui/src/list/ListGuesser.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import * as React from 'react';
import expect from 'expect';
import { render, screen, waitFor } from '@testing-library/react';
import { CoreAdminContext } from 'ra-core';

import { ListGuesser } from './ListGuesser';
import { ThemeProvider } from '../layout';

describe('<ListGuesser />', () => {
it('should log the guessed List view based on the fetched records', async () => {
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
const dataProvider = {
getList: () =>
Promise.resolve({
data: [
{
id: 123,
author: 'john doe',
post_id: 6,
score: 3,
body:
"Queen, tossing her head through the wood. 'If it had lost something; and she felt sure it.",
created_at: new Date('2012-08-02'),
},
],
total: 1,
}),
};
render(
<ThemeProvider theme={{}}>
<CoreAdminContext dataProvider={dataProvider as any}>
<ListGuesser resource="comments" />
</CoreAdminContext>
</ThemeProvider>
);
await waitFor(() => {
screen.getByText('john doe');
});
expect(logSpy).toHaveBeenCalledWith(`Guessed List:
import { Datagrid, DateField, List, NumberField, ReferenceField, TextField } from 'react-admin';
export const CommentList = () => (
<List>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="author" />
<ReferenceField source="post_id" reference="posts"><TextField source="id" /></ReferenceField>
<NumberField source="score" />
<TextField source="body" />
<DateField source="created_at" />
</Datagrid>
</List>
);`);
});
});
Loading

0 comments on commit ddd8449

Please sign in to comment.