2

I have a tale Resource that I want to display in different ways for the same user, depending on the tale status

Tale with status = NEW should be shown with List1

Tales with status = APPROVED etc need to be shown as List2 (I need to display different properties of the tale)

How to achieve this using Admin-On-Rest?

On Adding the same resource twice (as below) and allocating different List Views to both is only causing the first to be displayed and the second is ignored

<Resource name="tales" list={EditorAssignedList} edit={EditTale} options={{ label: 'Assigned Tales' }}/>
<Resource name="tales" list={EditorTaleTrack} options={{ label: 'Your Tales' }}/>

The following error is logged.

flattenChildren(...): Encountered two children with the same key, `1:$tales`. Child keys must be unique;

Any strategies on how to inject unique key into the resource.

kunal pareek
  • 1,285
  • 10
  • 21

3 Answers3

2

The above answer is not really that useful if you also want to add CRUD capabilities to the same route but through different List Menus. If you have 2 list views List1 and List2 with CRUD components. Enter edit (for example) from List2 and hit save you will be redirect to List1

A more broad solution is to create a custom wrapper to your REST Client. Inspiration from below. https://marmelab.com/admin-on-rest/RestClients.html#decorating-your-rest-client-example-of-file-upload

for my case it looked like this.

I created a dummy resource 'trackTale' in App.js. The in restWrapper.js

const RESTWrapper = requestHandler => (type, resource, params) => {

      if (type === 'GET_LIST' && resource === 'trackTale') {
        const page =  params.pagination.page
        const perPage = params.pagination.perPage
        const {field, order} = params.sort
        const query = {}
        query['where'] = {...params.filter}
        if (field) {query['order'] = [field + ' ' + order]}
        if (perPage > 0) {
            query['limit'] = perPage;
            if (page >= 0) {
                query['skip'] = (page - 1) * perPage
            }
        }
        //Key part here hardcoding the tales route to trackTale

const url = config.host + '/' + 'tales?' +  queryParameters({filter: JSON.stringify(query)})
        const options = {};
        options.user = {authenticated: true}
        options.user.token = localStorage.getItem('token');
        options.method = 'GET';
        return fetchUtils.fetchJson(url, options)
          .then((response) => {
            const {headers, json} = response;
            //admin on rest needs the {data} key
            return {data: json,
                    total: parseInt(headers.get('x-total-count').split('/').pop(), 10)}
        })
    }
}


//below function is very very specific to how loopback.js expects to recieve REST queries. Please customize it for your API needs
const queryParameters = data => Object.keys(data)
    .map(key => [key, data[key]].map(encodeURIComponent).join('='))
    .join('&');

This will work for all cases. Can still create a custom Menu if your different routes do not have CRUD.

kunal pareek
  • 1,285
  • 10
  • 21
  • What are `config` and `queryParameters` in your code? I assume `fetchUtils` are from admin-on-rest? – quicklikerabbit Sep 13 '17 at 23:44
  • Config is my local config and queryParameters is a function I forgot to include in the above. Am adding it now. fetchUtils is imported from AOR. – kunal pareek Sep 14 '17 at 05:01
1

Keep only one resource. Create a custom menu with 2 entries which pass your filters to the url parameters.

Then in a TalesList component, display the correct edition components depending on your parameter

Gildas Garcia
  • 6,966
  • 3
  • 15
  • 29
  • Have created a menu element as suggested in docs. However need clarity on both the points you have mentioned. 1) How to pass filter parameters from the menu component to the resource? 2) How to access the menu item being clicked from the list view (basically how can I access which link has been tapped and thus which view to display) – kunal pareek May 24 '17 at 11:07
  • 1) Look at the url of a normal list view page with filters set. That should give you the name of the parameters you need. Then just follow the react router documentation on the `Link` component 2) Maybe the [aor-dependent-input](https://github.com/marmelab/aor-dependent-input) addon can help you with that. I haven't tested it on views. If that doesn't work, I'll see how we can upgrade it to support views. – Gildas Garcia May 25 '17 at 17:13
  • Ok. Will get on this and tell you. – kunal pareek May 26 '17 at 06:38
0

Solved with great and amazing help by @Gildas

This was solved by

1) Create a custom menu component

const linkData = {
  pathname: "/tales",
  hash: "trackTales"
}

export default ({ resources, onMenuTap, logout }) => {
  return (
    <div>
      <MenuItem containerElement={<Link to="/tales" />} primaryText="Tales For Edit" onTouchTap={onMenuTap} />
      <MenuItem containerElement={<Link to={ linkData } />} primaryText="Track Tales" onTouchTap={onMenuTap} />
      {logout}
    </div>
  )
}

React Router's Link Component accepts objects as parameters. These are passed as props to the downstream component.

export const EditorAssignedList = (props) => {
  return taleViewJuggler(props)
}

The juggler function reads the props and creates custom views based on props. Link component was passing data to the 'location' key in the props.

const taleViewJuggler = (props) => {
  let viewName = props.location.hash
  let component;
  switch (viewName) {
    case "case1":
      component = (
        <ListView1 />
      )
      break;
    case "#case2":
      component = ( < ListView2 /> )
      break;
  }
  return component
}
kunal pareek
  • 1,285
  • 10
  • 21
  • Great :) I assume the dependent-input addon did not work for views then ? – Gildas Garcia May 29 '17 at 07:13
  • I didn't try it TBH. I had a sense of what you were suggesting initially, but was struggling to find a way to pass custom props from menu to the switch component above. Thanks again for everything. Also thanks a lot for Admin on Rest. I would very much like to sponsor a beer for you guys at the team after I finish my project and get paid :) – kunal pareek May 29 '17 at 09:26
  • Ok :) FYI, I just released a new version of the [aor-dependent-input](https://github.com/marmelab/aor-dependent-input) addon which now provides an `DependentField` component for views – Gildas Garcia May 30 '17 at 10:06