Search code examples
admin-on-rest

Adding multiple list views to same resource - Admin-On-Rest


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.


Solution

  • 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.