From 09e9bf6c4ee555f9a5e2dadffdaac3a6546f7ac3 Mon Sep 17 00:00:00 2001 From: fzaninotto Date: Mon, 16 May 2022 22:08:50 +0200 Subject: [PATCH 1/5] Add imports to guesser output --- .../src/detail/EditGuesser.spec.tsx | 54 ++++++++++++++ .../src/detail/EditGuesser.tsx | 74 ++++++++++++++----- .../src/detail/ShowGuesser.spec.tsx | 53 +++++++++++++ .../src/detail/ShowGuesser.tsx | 49 ++++++++---- .../src/list/ListGuesser.spec.tsx | 56 ++++++++++++++ .../ra-ui-materialui/src/list/ListGuesser.tsx | 71 ++++++++++++++---- 6 files changed, 306 insertions(+), 51 deletions(-) create mode 100644 packages/ra-ui-materialui/src/detail/EditGuesser.spec.tsx create mode 100644 packages/ra-ui-materialui/src/detail/ShowGuesser.spec.tsx create mode 100644 packages/ra-ui-materialui/src/list/ListGuesser.spec.tsx diff --git a/packages/ra-ui-materialui/src/detail/EditGuesser.spec.tsx b/packages/ra-ui-materialui/src/detail/EditGuesser.spec.tsx new file mode 100644 index 00000000000..c30a0d7e620 --- /dev/null +++ b/packages/ra-ui-materialui/src/detail/EditGuesser.spec.tsx @@ -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('', () => { + 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( + + + + + + ); + 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 = () => ( + + + + + + + + + + +);`); + }); +}); diff --git a/packages/ra-ui-materialui/src/detail/EditGuesser.tsx b/packages/ra-ui-materialui/src/detail/EditGuesser.tsx index dba8ae09122..57004506ab4 100644 --- a/packages/ra-ui-materialui/src/detail/EditGuesser.tsx +++ b/packages/ra-ui-materialui/src/detail/EditGuesser.tsx @@ -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, @@ -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 ( + + + + ); +}; + const EditViewGuesser = props => { const resource = useResourceContext(props); const { record } = useEditContext(); @@ -29,21 +56,37 @@ 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 = () => ( -${inferredChild.getRepresentation()} +${representation} );` - ); - setInferredChild(inferredChild.getElement()); + ); } }, [record, inferredChild, resource]); @@ -51,12 +94,3 @@ ${inferredChild.getRepresentation()} }; EditViewGuesser.propTypes = EditView.propTypes; - -export const EditGuesser = (props: EditProps) => { - const controllerProps = useEditController(props); - return ( - - - - ); -}; diff --git a/packages/ra-ui-materialui/src/detail/ShowGuesser.spec.tsx b/packages/ra-ui-materialui/src/detail/ShowGuesser.spec.tsx new file mode 100644 index 00000000000..e23492afdee --- /dev/null +++ b/packages/ra-ui-materialui/src/detail/ShowGuesser.spec.tsx @@ -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('', () => { + 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( + + + + + + ); + await waitFor(() => { + screen.getByText('john doe'); + }); + expect(logSpy).toHaveBeenCalledWith(`Guessed Show: + +import { DateField, NumberField, ReferenceField, Show, SimpleShowLayout, TextField } from 'react-admin'; + +export const CommentShow = () => ( + + + + + + + + + + +);`); + }); +}); diff --git a/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx b/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx index ddc0d0dd9c9..2016a29612d 100644 --- a/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx +++ b/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx @@ -13,6 +13,17 @@ import { ShowProps } from '../types'; import { ShowView } from './ShowView'; import { showFieldTypes } from './showFieldTypes'; +export const ShowGuesser = ({ + id, + queryOptions, + resource, + ...rest +}: Omit) => ( + + + +); + const ShowViewGuesser = props => { const resource = useResourceContext(props); const { record } = useShowContext(); @@ -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 = () => ( ${inferredChild.getRepresentation()} );` - ); + ); setInferredChild(inferredChild.getElement()); } }, [record, inferredChild, resource]); @@ -50,11 +77,3 @@ ${inferredChild.getRepresentation()} }; ShowViewGuesser.propTypes = ShowView.propTypes; - -export const ShowGuesser = ({ id, queryOptions, ...rest }: ShowProps) => ( - - - -); - -export default ShowGuesser; diff --git a/packages/ra-ui-materialui/src/list/ListGuesser.spec.tsx b/packages/ra-ui-materialui/src/list/ListGuesser.spec.tsx new file mode 100644 index 00000000000..03fc6669e02 --- /dev/null +++ b/packages/ra-ui-materialui/src/list/ListGuesser.spec.tsx @@ -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('', () => { + 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( + + + + + + ); + await waitFor(() => { + screen.getByText('john doe'); + }); + expect(logSpy).toHaveBeenCalledWith(`Guessed List: + +import { Datagrid, DateField, List, NumberField, ReferenceField, TextField } from 'react-admin'; + +export const CommentList = () => ( + + + + + + + + + + +);`); + }); +}); diff --git a/packages/ra-ui-materialui/src/list/ListGuesser.tsx b/packages/ra-ui-materialui/src/list/ListGuesser.tsx index bd131d287b1..0732004edaf 100644 --- a/packages/ra-ui-materialui/src/list/ListGuesser.tsx +++ b/packages/ra-ui-materialui/src/list/ListGuesser.tsx @@ -2,15 +2,15 @@ import * as React from 'react'; import { useState, useEffect } from 'react'; import inflection from 'inflection'; import { - useListController, + ListBase, getElementsFromRecords, InferredElement, - ListContextProvider, useListContext, useResourceContext, RaRecord, } from 'ra-core'; +import { ListProps } from './List'; import { ListView, ListViewProps } from './ListView'; import { listFieldTypes } from './listFieldTypes'; @@ -34,14 +34,37 @@ import { listFieldTypes } from './listFieldTypes'; * * ); */ -export const ListGuesser = () => { - const controllerProps = useListController({ - queryOptions: { keepPreviousData: false }, - }); +export const ListGuesser = ( + props: Omit +) => { + const { + debounce, + disableAuthentication, + disableSyncWithLocation, + exporter, + filter, + filterDefaultValues, + perPage, + queryOptions, + resource, + sort, + ...rest + } = props; return ( - - - + + debounce={debounce} + disableAuthentication={disableAuthentication} + disableSyncWithLocation={disableSyncWithLocation} + exporter={exporter} + filter={filter} + filterDefaultValues={filterDefaultValues} + perPage={perPage} + queryOptions={{ keepPreviousData: false }} + resource={resource} + sort={sort} + > + + ); }; @@ -66,19 +89,35 @@ const ListViewGuesser = (props: Omit) => { inferredElements ); - process.env.NODE_ENV !== 'production' && - // eslint-disable-next-line no-console - console.log( - `Guessed List: + if (process.env.NODE_ENV === 'production') return; + + const representation = inferredChild.getRepresentation(); + const components = ['List'] + .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 List: + +import { ${components.join(', ')} } from 'react-admin'; export const ${inflection.capitalize( - inflection.singularize(resource) - )}List = () => ( + inflection.singularize(resource) + )}List = () => ( ${inferredChild.getRepresentation()} );` - ); + ); setInferredChild(inferredChild.getElement()); } }, [data, inferredChild, resource]); From 21419396f7f642cef7521052d0f00b565135835b Mon Sep 17 00:00:00 2001 From: fzaninotto Date: Mon, 16 May 2022 22:14:17 +0200 Subject: [PATCH 2/5] Fix order --- packages/ra-ui-materialui/src/detail/ShowGuesser.tsx | 2 +- packages/ra-ui-materialui/src/list/ListGuesser.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx b/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx index 2016a29612d..ee6ce7babba 100644 --- a/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx +++ b/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx @@ -39,6 +39,7 @@ const ShowViewGuesser = props => { null, inferredElements ); + setInferredChild(inferredChild.getElement()); if (process.env.NODE_ENV === 'production') return; @@ -69,7 +70,6 @@ ${inferredChild.getRepresentation()} );` ); - setInferredChild(inferredChild.getElement()); } }, [record, inferredChild, resource]); diff --git a/packages/ra-ui-materialui/src/list/ListGuesser.tsx b/packages/ra-ui-materialui/src/list/ListGuesser.tsx index 0732004edaf..dee9054e4f2 100644 --- a/packages/ra-ui-materialui/src/list/ListGuesser.tsx +++ b/packages/ra-ui-materialui/src/list/ListGuesser.tsx @@ -88,6 +88,7 @@ const ListViewGuesser = (props: Omit) => { null, inferredElements ); + setInferredChild(inferredChild.getElement()); if (process.env.NODE_ENV === 'production') return; @@ -118,7 +119,6 @@ ${inferredChild.getRepresentation()} );` ); - setInferredChild(inferredChild.getElement()); } }, [data, inferredChild, resource]); From 650a15ef5bd69574cfc2f67797ca95ab37fc36b7 Mon Sep 17 00:00:00 2001 From: fzaninotto Date: Mon, 16 May 2022 22:25:10 +0200 Subject: [PATCH 3/5] Change syntax --- .../ra-ui-materialui/src/detail/EditGuesser.tsx | 13 +++++++------ .../ra-ui-materialui/src/detail/ShowGuesser.tsx | 12 ++++++------ packages/ra-ui-materialui/src/list/ListGuesser.tsx | 12 ++++++------ 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/packages/ra-ui-materialui/src/detail/EditGuesser.tsx b/packages/ra-ui-materialui/src/detail/EditGuesser.tsx index 57004506ab4..9a518482a2d 100644 --- a/packages/ra-ui-materialui/src/detail/EditGuesser.tsx +++ b/packages/ra-ui-materialui/src/detail/EditGuesser.tsx @@ -44,9 +44,9 @@ export const EditGuesser = (props: EditProps) => { const EditViewGuesser = props => { const resource = useResourceContext(props); const { record } = useEditContext(); - const [inferredChild, setInferredChild] = useState(null); + const [child, setChild] = useState(null); useEffect(() => { - if (record && !inferredChild) { + if (record && !child) { const inferredElements = getElementsFromRecords( [record], editFieldTypes @@ -56,16 +56,17 @@ const EditViewGuesser = props => { null, inferredElements ); - setInferredChild(inferredChild.getElement()); + setChild(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)) + Array.from(representation.matchAll(/<([^/\s>]+)/g)) .map(match => match[1]) .filter(component => component !== 'span') ) @@ -88,9 +89,9 @@ ${representation} );` ); } - }, [record, inferredChild, resource]); + }, [record, child, resource]); - return {inferredChild}; + return {child}; }; EditViewGuesser.propTypes = EditView.propTypes; diff --git a/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx b/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx index ee6ce7babba..eb0c74f37d4 100644 --- a/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx +++ b/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx @@ -27,9 +27,9 @@ export const ShowGuesser = ({ const ShowViewGuesser = props => { const resource = useResourceContext(props); const { record } = useShowContext(); - const [inferredChild, setInferredChild] = useState(null); + const [child, setChild] = useState(null); useEffect(() => { - if (record && !inferredChild) { + if (record && !child) { const inferredElements = getElementsFromRecords( [record], showFieldTypes @@ -39,7 +39,7 @@ const ShowViewGuesser = props => { null, inferredElements ); - setInferredChild(inferredChild.getElement()); + setChild(inferredChild.getElement()); if (process.env.NODE_ENV === 'production') return; @@ -48,7 +48,7 @@ const ShowViewGuesser = props => { .concat( Array.from( new Set( - Array.from(representation.matchAll(/<([^\/\s>]+)/g)) + Array.from(representation.matchAll(/<([^/\s>]+)/g)) .map(match => match[1]) .filter(component => component !== 'span') ) @@ -71,9 +71,9 @@ ${inferredChild.getRepresentation()} );` ); } - }, [record, inferredChild, resource]); + }, [record, child, resource]); - return {inferredChild}; + return {child}; }; ShowViewGuesser.propTypes = ShowView.propTypes; diff --git a/packages/ra-ui-materialui/src/list/ListGuesser.tsx b/packages/ra-ui-materialui/src/list/ListGuesser.tsx index dee9054e4f2..6b595f6d683 100644 --- a/packages/ra-ui-materialui/src/list/ListGuesser.tsx +++ b/packages/ra-ui-materialui/src/list/ListGuesser.tsx @@ -71,14 +71,14 @@ export const ListGuesser = ( const ListViewGuesser = (props: Omit) => { const { data } = useListContext(props); const resource = useResourceContext(); - const [inferredChild, setInferredChild] = useState(null); + const [child, setChild] = useState(null); useEffect(() => { - setInferredChild(null); + setChild(null); }, [resource]); useEffect(() => { - if (data && data.length > 0 && !inferredChild) { + if (data && data.length > 0 && !child) { const inferredElements = getElementsFromRecords( data, listFieldTypes @@ -88,7 +88,7 @@ const ListViewGuesser = (props: Omit) => { null, inferredElements ); - setInferredChild(inferredChild.getElement()); + setChild(inferredChild.getElement()); if (process.env.NODE_ENV === 'production') return; @@ -120,9 +120,9 @@ ${inferredChild.getRepresentation()} );` ); } - }, [data, inferredChild, resource]); + }, [data, child, resource]); - return {inferredChild}; + return {child}; }; ListViewGuesser.propTypes = ListView.propTypes; From d4fc4986b3bc394ed84998df82e5cad32ec33368 Mon Sep 17 00:00:00 2001 From: fzaninotto Date: Mon, 16 May 2022 22:41:41 +0200 Subject: [PATCH 4/5] Fix missing resource change effect --- packages/ra-ui-materialui/src/detail/EditGuesser.tsx | 5 +++++ packages/ra-ui-materialui/src/detail/ShowGuesser.tsx | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/packages/ra-ui-materialui/src/detail/EditGuesser.tsx b/packages/ra-ui-materialui/src/detail/EditGuesser.tsx index 9a518482a2d..c7efb51dc3f 100644 --- a/packages/ra-ui-materialui/src/detail/EditGuesser.tsx +++ b/packages/ra-ui-materialui/src/detail/EditGuesser.tsx @@ -45,6 +45,11 @@ const EditViewGuesser = props => { const resource = useResourceContext(props); const { record } = useEditContext(); const [child, setChild] = useState(null); + + useEffect(() => { + setChild(null); + }, [resource]); + useEffect(() => { if (record && !child) { const inferredElements = getElementsFromRecords( diff --git a/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx b/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx index eb0c74f37d4..f4b1525952f 100644 --- a/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx +++ b/packages/ra-ui-materialui/src/detail/ShowGuesser.tsx @@ -28,6 +28,11 @@ const ShowViewGuesser = props => { const resource = useResourceContext(props); const { record } = useShowContext(); const [child, setChild] = useState(null); + + useEffect(() => { + setChild(null); + }, [resource]); + useEffect(() => { if (record && !child) { const inferredElements = getElementsFromRecords( From 9d36311d7a829d3922e53e4ff215b1eb02412c67 Mon Sep 17 00:00:00 2001 From: fzaninotto Date: Tue, 17 May 2022 16:18:55 +0200 Subject: [PATCH 5/5] Fix linter warnings --- packages/ra-ui-materialui/src/list/ListGuesser.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ra-ui-materialui/src/list/ListGuesser.tsx b/packages/ra-ui-materialui/src/list/ListGuesser.tsx index 6b595f6d683..14e8872c528 100644 --- a/packages/ra-ui-materialui/src/list/ListGuesser.tsx +++ b/packages/ra-ui-materialui/src/list/ListGuesser.tsx @@ -97,7 +97,7 @@ const ListViewGuesser = (props: Omit) => { .concat( Array.from( new Set( - Array.from(representation.matchAll(/<([^\/\s>]+)/g)) + Array.from(representation.matchAll(/<([^/\s>]+)/g)) .map(match => match[1]) .filter(component => component !== 'span') )