React-admin: [RFC] Adding path props to Resources because declareResources action doesn't work with <Admin />

Created on 4 Oct 2017  路  3Comments  路  Source: marmelab/react-admin

Due to #1120 issue, we had to use <Admin /> in order to get started with admin on rest.

We have the requirement to secure our routes under services: /foobar-service/users

Resource does not offer any way to customize the client path, and as soon as you declare a <Resource /> under <Admin /> a route is being created so we had to use declareResources action to declare our resources.

This is how we use <Admin />

export default class App extends React.PureComponent {
  render() {
    return (
        <Admin
          theme={getMuiTheme(darkBaseTheme)}
          locale={DEFAULT_LOCALE}
          messages={fromReactIntl(this.props.messages)}
          menu={Menu}
          loginPage={compose(
            withSagaLogout,
            withLanguageProvider(this.props.messages),
          )(LoginPage)}
          dashboard={DashboardPage}
          appLayout={compose(
            withSagaLogout,
            withLanguageProvider(this.props.messages),
          )(Layout)}
          customRoutes={customRoutes}
          authClient={authClient}
          restClient={restClient}
          history={createBrowserHistory()}
        />
    );
  }
}

And this is how we created the customRoutes:

export default [
  <Route exact path={pages.platform.childRoutes.halBrowser.path} component={HalBrowserPage} />,
  <Route exact path={pages.userManagement.childRoutes.userList.path} render={(routeProps) => <UserList hasCreate resource="users" {...routeProps} />} />,
];

Note: because declareResources needs the store to exist, it is not possible to call the declareResources action outside <Admin /> which is responsible of creating the store.

We have tried to do that task using an appLayout HoC but some mapStateToProps call in List.js was failing after the 3rd mapStateToProps call to list.

We then tweaker our own <Admin /> to do the action call inside and it look like this :

  sagaMiddleware.run(saga);
  store.dispatch(declareResources([
    {
      name: 'users',
    },
    {
      name: 'roles',
    },
    {
      name: 'oAuthClients',
    }
  ])); // <== added this in Admin.js
  const logout = authClient ? createElement(logoutButton || Logout) : null;

What you were expecting:

it should have prepare the resources state.

What happened instead:

In all our test, using declareResources in addition of <Admin /> throw an error after because something reset the state (certainly <Admin />).

/home/dka/out.gif

Steps to reproduce:

Use in combinaison <Admin /> and declareResources.

Environment

  • Admin-on-rest version: 1.3.2
  • React version: 16
  • Stack trace (in case of a JS error):
connectAdvanced.js:251 Uncaught TypeError: Cannot read property 'list' of undefined
    at Function.mapStateToProps [as mapToProps] (List.js:442)
    at mapToPropsProxy (wrapMapToProps.js:48)
    at handleNewPropsAndNewState (selectorFactory.js:39)
    at handleSubsequentCalls (selectorFactory.js:72)
    at pureFinalPropsSelector (selectorFactory.js:79)
    at Object.runComponentSelector [as run] (connectAdvanced.js:36)
    at Connect.componentWillReceiveProps (connectAdvanced.js:160)
    at callComponentWillReceiveProps (react-dom.development.js:9795)
    at updateClassInstance (react-dom.development.js:9974)
    at updateClassComponent (react-dom.development.js:10224)

We finally manage to customize the route paths by not using declareResources and by creating our own Layout, AdminRoutes and CrudRoutes components.

I've edited them in a way <Resource /> can receive a path props.

Is the pull request request welcome ?

All 3 comments

A custom path on resources was something existing in ng-admin.
We faced a similar issue and got around it by coding the logic inside our own RestClient and customising the url in convertRESTRequestToHTTP using a static mapping of resourceName => Path

import resourceMappings from '../modules/resourceMappings.json';

export const convertRESTRequestToHTTP = ( type, resource, params ) => {
    const controllerUrl = `/controller/${resourceMappings[resource]}`;
    let url = '';
    const options = {};
    switch ( type ) {
        case GET_LIST: {
            const { page, perPage } = params.pagination;
            const { field, order } = params.sort;
            const query = {
                sort: JSON.stringify( [[field, order === 'ASC' ? 1 : -1]] ),
                page: page,
                limit: perPage,
            };
            url = `${controllerUrl}/${resource}?${queryParameters( query )}`;
            break;
...

Ability of doing this on the Resource declaration sounds neater to me though

No, we don't want to go that way. Resource names are used by the app for the Redux store and routing. If you need something more sophisticated, the mapping must be done in the REST client, as @Phocea pointed.

Interesting. We needed to display to the user the path including the service.

I managed to do it by customizing my own AdminRoutes.js#L64:

        {resources.map(resource => (
          <Route
            path={resource.path || resource.name}
            key={resource.name}
            render={() => (
              <CrudRoute
                path={resource.path}
                resource={resource.name}
                list={resource.list}
                create={resource.create}
                edit={resource.edit}
                show={resource.show}
                remove={resource.remove}
                options={resource.options}
              />
            )}
          />
        ))}

@fzaninotto you pointed out that resource names are used by the app for the Redux store and routing

So far, I haven't seen any side effect and this implementation would not modify the resource name either.

Can you please confirm that there is a risk of side effect ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kdabir picture kdabir  路  3Comments

aserrallerios picture aserrallerios  路  3Comments

marknelissen picture marknelissen  路  3Comments

mbj36 picture mbj36  路  3Comments

Dragomir-Ivanov picture Dragomir-Ivanov  路  3Comments