From 2962f6f98cb36c2dff408244f7ce78308e58f4c1 Mon Sep 17 00:00:00 2001 From: fzaninotto <fzaninotto@gmail.com> Date: Thu, 1 Apr 2021 22:05:09 +0200 Subject: [PATCH] Fix customRoutes aren't used when the resources are empty Closes #6079 --- examples/simple/src/index.tsx | 4 +- .../ra-core/src/core/CoreAdminRouter.spec.tsx | 52 +++++++++++++++++-- packages/ra-core/src/core/CoreAdminRouter.tsx | 49 ++++++++++------- packages/ra-core/src/types.ts | 1 + 4 files changed, 80 insertions(+), 26 deletions(-) diff --git a/examples/simple/src/index.tsx b/examples/simple/src/index.tsx index 6acc3c35cbd..d7d9ad5da49 100644 --- a/examples/simple/src/index.tsx +++ b/examples/simple/src/index.tsx @@ -1,6 +1,6 @@ /* eslint react/jsx-key: off */ import * as React from 'react'; -import { Admin, Resource } from 'react-admin'; // eslint-disable-line import/no-unresolved +import { Admin, Resource, CustomRoute } from 'react-admin'; // eslint-disable-line import/no-unresolved import { render } from 'react-dom'; import { Route } from 'react-router-dom'; @@ -23,7 +23,7 @@ render( title="Example Admin" layout={Layout} customRoutes={[ - <Route + <Route<CustomRoute> exact path="/custom" component={props => <CustomRouteNoLayout {...props} />} diff --git a/packages/ra-core/src/core/CoreAdminRouter.spec.tsx b/packages/ra-core/src/core/CoreAdminRouter.spec.tsx index b0f617343a6..0d237becec7 100644 --- a/packages/ra-core/src/core/CoreAdminRouter.spec.tsx +++ b/packages/ra-core/src/core/CoreAdminRouter.spec.tsx @@ -81,10 +81,10 @@ describe('<CoreAdminRouter>', () => { getPermissions: jest.fn().mockResolvedValue(''), }; - const { getByText } = renderWithRedux( + const { queryByText } = renderWithRedux( <AuthContext.Provider value={authProvider}> <Router history={history}> - <CoreAdminRouter {...defaultProps} layout={Layout}> + <CoreAdminRouter layout={Layout}> {() => [ <Resource key="posts" @@ -104,12 +104,54 @@ describe('<CoreAdminRouter>', () => { ); // Timeout needed because of the authProvider call await waitFor(() => { - expect(getByText('Layout')).not.toBeNull(); + expect(queryByText('Layout')).not.toBeNull(); }); history.push('/posts'); - expect(getByText('PostList')).not.toBeNull(); + expect(queryByText('PostList')).not.toBeNull(); history.push('/comments'); - expect(getByText('CommentList')).not.toBeNull(); + expect(queryByText('CommentList')).not.toBeNull(); + }); + + it('should return loading while the resources are not resolved', async () => { + const history = createMemoryHistory(); + const authProvider = { + login: jest.fn().mockResolvedValue(''), + logout: jest.fn().mockResolvedValue(''), + checkAuth: jest.fn().mockResolvedValue(''), + checkError: jest.fn().mockResolvedValue(''), + getPermissions: jest.fn().mockResolvedValue(''), + }; + const Loading = () => <>Loading</>; + const Custom = () => <>Custom</>; + + const { queryByText } = renderWithRedux( + <AuthContext.Provider value={authProvider}> + <Router history={history}> + <CoreAdminRouter + {...defaultProps} + layout={Layout} + loading={Loading} + customRoutes={[ + <Route + key="foo" + noLayout + path="/foo" + component={Custom} + />, + ]} + > + {() => new Promise(() => {})} + </CoreAdminRouter> + </Router> + </AuthContext.Provider> + ); + // Timeout needed because of the authProvider call + await new Promise(resolve => setTimeout(resolve, 1010)); + history.push('/posts'); + expect(queryByText('Loading')).not.toBeNull(); + history.push('/foo'); + expect(queryByText('Loading')).toBeNull(); + expect(queryByText('Custom')).not.toBeNull(); }); }); diff --git a/packages/ra-core/src/core/CoreAdminRouter.tsx b/packages/ra-core/src/core/CoreAdminRouter.tsx index 25f8302386e..11396c5b561 100644 --- a/packages/ra-core/src/core/CoreAdminRouter.tsx +++ b/packages/ra-core/src/core/CoreAdminRouter.tsx @@ -107,33 +107,43 @@ const CoreAdminRouter: FunctionComponent<AdminRouterProps> = props => { loading: LoadingPage, logout, menu, - ready, + ready: Ready, theme, title, } = props; - if ( - (typeof children !== 'function' && !children) || - (Array.isArray(children) && children.length === 0) - ) { - return createElement(ready); + if (typeof children !== 'function' && !children) { + return <Ready />; } if ( - typeof children === 'function' && - (!computedChildren || computedChildren.length === 0) + (typeof children === 'function' && + (!computedChildren || computedChildren.length === 0)) || + (Array.isArray(children) && children.length === 0) ) { - if (oneSecondHasPassed) { - return ( - <Route - path="/" - key="loading" - render={() => <LoadingPage theme={theme} />} - /> - ); - } else { - return null; - } + return ( + <Switch> + {customRoutes + .filter(route => route.props.noLayout) + .map((route, key) => + cloneElement(route, { + key, + render: routeProps => + renderCustomRoutesWithoutLayout( + route, + routeProps + ), + component: undefined, + }) + )} + {oneSecondHasPassed && ( + <Route + key="loading" + render={() => <LoadingPage theme={theme} />} + /> + )} + </Switch> + ); } const childrenToRender = (typeof children === 'function' @@ -167,6 +177,7 @@ const CoreAdminRouter: FunctionComponent<AdminRouterProps> = props => { route, routeProps ), + component: undefined, }) )} <Route diff --git a/packages/ra-core/src/types.ts b/packages/ra-core/src/types.ts index 44f174d9b59..5fd27bff7cc 100644 --- a/packages/ra-core/src/types.ts +++ b/packages/ra-core/src/types.ts @@ -389,6 +389,7 @@ export type AdminChildren = RenderResourcesFunction | ReactNode; export interface CustomRoute extends RouteProps { noLayout?: boolean; + [key: string]: any; } export type CustomRoutes = Array<ReactElement<CustomRoute>>;