2

I am setting up react-admin as a dashboard for a burger restaurant. Here is my My github repository.

I would like to apologize if any required troubleshooting information is missing. I am a bit out of my depth but I am having a go.

I have created two tables (three if you count contacts) to store the menu and the menu categories. I have tried to setup referential integrity. Immediately after doing this (and rebuilding the project with the new seed.sql file) I started getting the following after clicking on "menucategories" on the left-hand side:

enter image description here

Error: The dataProvider threw an error. It should return a rejected Promise instead.

   in List (at MenuCategory.js:5)
   in CatData (created by WithPermissions)
   in WithPermissions (created by Context.Consumer)
   in Route (created by ResourceRoutes)
   in Switch (created by ResourceRoutes)
   in ResourceRoutes (created by Resource)
   in Resource (at App.js:41)
   in Route (created by RoutesWithLayout)
   in Switch (created by RoutesWithLayout)
   in RoutesWithLayout (created by Context.Consumer)
   in div (created by Layout)
   in main (created by Layout)
   in div (created by Layout)
   in div (created by Layout)
   in Layout (created by WithStyles(Layout))
   in WithStyles(Layout) (created by Context.Consumer)
   in withRouter(WithStyles(Layout)) (created by ConnectFunction)
   in ConnectFunction (created by LayoutWithTheme)
   in ThemeProvider (created by LayoutWithTheme)
   in LayoutWithTheme (created by Context.Consumer)
   in Route (created by CoreAdminRouter)
   in Switch (created by CoreAdminRouter)
   in div (created by CoreAdminRouter)
   in CoreAdminRouter (created by Context.Consumer)
   in Route (created by CoreAdminUI)
   in Switch (created by CoreAdminUI)
   in CoreAdminUI (created by AdminUI)
   in AdminUI (created by Admin)
   in Router (created by ConnectedRouter)
   in ConnectedRouter (created by Context.Consumer)
   in ConnectedRouterWithContext (created by ConnectFunction)
   in ConnectFunction (created by CoreAdminContext)
   in TranslationProvider (created by CoreAdminContext)
   in Provider (created by CoreAdminContext)
   in CoreAdminContext (created by AdminContext)
   in AdminContext (created by Admin)
   in Admin (at App.js:25)
   in ReactAdminWrapper (at App.js:65)
   in ApolloProvider (at App.js:64)
   in App (at src/index.js:7)

The first lot of error information in the console is like this:

index.js:1 Warning: Failed prop type: The prop `children` is marked as required in `ForwardRef(Link)`, but its value is `null`.
   in ForwardRef(Link) (created by WithStyles(ForwardRef(Link)))
   in WithStyles(ForwardRef(Link))
   in Unknown
   in Unknown (at Contacts.js:13)
   in td (created by ForwardRef(TableCell))
   in ForwardRef(TableCell) (created by WithStyles(ForwardRef(TableCell)))
   in WithStyles(ForwardRef(TableCell)) (created by DatagridCell)
   in DatagridCell (created by DatagridRow)
   in tr (created by ForwardRef(TableRow))
   in ForwardRef(TableRow) (created by WithStyles(ForwardRef(TableRow)))
   in WithStyles(ForwardRef(TableRow)) (created by DatagridRow)
   in DatagridRow
   in tbody (created by ForwardRef(TableBody))
   in ForwardRef(TableBody) (created by WithStyles(ForwardRef(TableBody)))
   in WithStyles(ForwardRef(TableBody)) (created by DatagridBody)
   in DatagridBody (created by Datagrid)
   in table (created by ForwardRef(Table))
   in ForwardRef(Table) (created by WithStyles(ForwardRef(Table)))
   in WithStyles(ForwardRef(Table)) (created by Datagrid)
   in Datagrid (at Contacts.js:6)
   in div (created by ForwardRef(Paper))
   in ForwardRef(Paper) (created by WithStyles(ForwardRef(Paper)))
   in WithStyles(ForwardRef(Paper)) (created by ForwardRef(Card))
   in ForwardRef(Card) (created by WithStyles(ForwardRef(Card)))
   in WithStyles(ForwardRef(Card)) (created by ListView)
   in div (created by ListView)
   in div (created by ListView)
   in ListView (created by List)
   in List (at Contacts.js:5)
   in ContactList (created by WithPermissions)
   in WithPermissions (created by Context.Consumer)
   in Route (created by ResourceRoutes)
   in Switch (created by ResourceRoutes)
   in ResourceRoutes (created by Resource)
   in Resource (at App.js:26)
   in Route (created by RoutesWithLayout)
   in Switch (created by RoutesWithLayout)
   in RoutesWithLayout (created by Context.Consumer)
   in div (created by Layout)
   in main (created by Layout)
   in div (created by Layout)
   in div (created by Layout)
   in Layout (created by WithStyles(Layout))
   in WithStyles(Layout) (created by Context.Consumer)
   in withRouter(WithStyles(Layout)) (created by ConnectFunction)
   in ConnectFunction (created by LayoutWithTheme)
   in ThemeProvider (created by LayoutWithTheme)
   in LayoutWithTheme (created by Context.Consumer)
   in Route (created by CoreAdminRouter)
   in Switch (created by CoreAdminRouter)
   in div (created by CoreAdminRouter)
   in CoreAdminRouter (created by Context.Consumer)
   in Route (created by CoreAdminUI)
   in Switch (created by CoreAdminUI)
   in CoreAdminUI (created by AdminUI)
   in AdminUI (created by Admin)
   in Router (created by ConnectedRouter)
   in ConnectedRouter (created by Context.Consumer)
   in ConnectedRouterWithContext (created by ConnectFunction)
   in ConnectFunction (created by CoreAdminContext)
   in TranslationProvider (created by CoreAdminContext)
   in Provider (created by CoreAdminContext)
   in CoreAdminContext (created by AdminContext)
   in AdminContext (created by Admin)
   in Admin (at App.js:25)
   in ReactAdminWrapper (at App.js:65)
   in ApolloProvider (at App.js:64)
   in App (at src/index.js:7)

I was referring to the following tutorial when learning how to setup the referential integrity.

Please note the seed.sql file has has not been updated in the repo to the version I am working on (on my machine) which is as follows:


CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA public;

DROP TABLE IF EXISTS public.contacts CASCADE;

CREATE TABLE public.contacts (
    id             UUID PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
    email          VARCHAR(255) NOT NULL,
    firstname      VARCHAR(255),
    lastname       VARCHAR(255),
    website        VARCHAR(255),
    streetaddress  VARCHAR(255),
    phone          VARCHAR(255),
    companyname    VARCHAR(255),
    created_at     TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX contacts_email_index ON public.contacts (email);


DROP TABLE IF EXISTS public.menu CASCADE;

CREATE TABLE public.menu (
    id             SERIAL PRIMARY KEY,
    title          VARCHAR(255) NOT NULL,
    category_id    INT NOT NULL CONSTRAINT menu__ref_p REFERENCES menucategories,
    price          NUMERIC(8, 2),
    desc1          VARCHAR(255),
    isenabled      BOOLEAN NOT NULL DEFAULT TRUE,   
    created_at     TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);


DROP TABLE IF EXISTS public.menucategories CASCADE;

CREATE TABLE public.menucategories (
    category_id    SERIAL PRIMARY KEY,
    catname        VARCHAR(255) NOT NULL,
    created_at     TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);



SET client_min_messages = INFO;

Test data is prefilled into the database through the fixtures.sql file


INSERT INTO public.contacts
   (
       id,
       email,
       firstname,
       lastname
   )
   SELECT
       ('1de9c987-08ab-32fe-e218-89c124cd' || to_char(seqnum, 'FM0000'))::uuid,
       'firstname' || to_char(seqnum, 'FM0000') || '@example.com',
       'firstname' || to_char(seqnum, 'FM0000'),
       'lastname' || to_char(seqnum, 'FM0000')
   FROM 
       GENERATE_SERIES(1, 2) seqnum;

TRUNCATE public.menu CASCADE;

INSERT INTO public.menucategories
   (
       catname
   )
   SELECT
       ('category' || to_char(seqnum, 'FM0000'))
       
   FROM 
       GENERATE_SERIES(1, 3) seqnum;         

Here is the code in my App.js file:


import React, { useEffect, useState } from 'react'
import { ApolloProvider } from '@apollo/react-hooks';
import { Admin, Resource } from 'react-admin'
import { useApolloClient } from '@apollo/react-hooks'
import pgDataProvider from 'ra-postgraphile'
import { ContactList, ContactEdit, ContactCreate } from './Contacts'
import { MenuData, MenuEdit, CreateMenuItem } from './Menu'
import { CatData, CatEdit, CreateCatItem } from './MenuCategory'
import ApolloClient from './Apollo';
/* import { HttpError } from 'react-admin'; */

const ReactAdminWrapper = () => {
    const [dataProvider, setDataProvider] = useState(null);
    const client = useApolloClient();

    useEffect(() => {
        (async () => {
            const dataProvider = await pgDataProvider(client);
            setDataProvider(() => dataProvider);
        })()
    }, [client]);

    return (
        dataProvider && (
            <Admin dataProvider={dataProvider}>
                <Resource
                    name="contacts"
                    list={ContactList}
                    edit={ContactEdit}
                    create={ContactCreate}
                />

                <Resource 
                     name="menu"
                     list={MenuData}
                     edit={MenuEdit}
                     create={CreateMenuItem} 
                 
                />

              <Resource 
                     name="menucategories"
                     list={CatData}
                     edit={CatEdit}
                     create={CreateCatItem} 
                 
                />




            </Admin>
        )

        

     

    );
}

const App = () => {
    return (
        <ApolloProvider client={ApolloClient}>
            <ReactAdminWrapper />
        </ApolloProvider>
    );
}

export default App;

I am using AutocompleteInput to (hard-code) prefill the values but I need to change that to something like ReferenceField or ReferenceInput to pull the categories from the database. I am just not 100% sure on how to do this as I am new to react-admin. Any suggestions would be much appreciated.

My Menu.js file is as follows:

import React from 'react';
import { List, Datagrid, Edit, Create, SimpleForm, TextField, EditButton, TextInput, BooleanInput, BooleanField } from 'react-admin';
import { AutocompleteInput } from 'react-admin';

export const MenuData = (props) => (
    <List {...props}>
        <Datagrid>
            
            <TextField source="title" />
            <TextField source="category_id" />
            <TextField source="price" />
            <TextField source="desc1" />
            {/* <TextField source="image" /> */}
            <BooleanField label="enabled" source="isenabled" />
            
            <EditButton basePath="/menu" />
        </Datagrid>
    </List>
);

const MenuTitle = ({ record }) => {
    return <span>Menu {record ? `"${record.title}"` : ''}</span>;
};

export const MenuEdit = (props) => (
    <Edit title={<MenuTitle />} {...props}>
        <SimpleForm>
            <TextInput disabled source="id" />
            
            <TextInput source="title" />

{/* //These are currently hardcoded see: https://marmelab.com/react-admin/Inputs.html
//We want to grab the values from the database instead */}

    <AutocompleteInput source="category_id" choices={[
    { id: '1', name: 'category0001' },
    { id: '2', name: 'category0002' },
    { id: '3', name: 'category0003' },
   
]} />
            {/* <TextInput source="category_id" /> */}
            <TextInput source="price" />
            <TextInput disabledsource="image" />
            <TextInput source="desc1" />
            <BooleanInput label="Enabled" source="isenabled" />
            
        </SimpleForm>
    </Edit>
);

export const CreateMenuItem = (props) => (
    <Create title="Add a Menu Item" {...props}>
        <SimpleForm>
        <TextInput disabled source="id" />
            
            <TextInput source="title" />
           
            <AutocompleteInput source="category_id" choices={[
    { id: '1', name: 'category0001' },
    { id: '2', name: 'category0002' },
    { id: '3', name: 'category0003' },
   
]} />

            {/* <TextInput source="category_id" /> */}
            <TextInput source="price" />
          {/*   <TextInput disabledsource="image" /> */}
            <TextInput source="desc1" />
        </SimpleForm>
    </Create>
);

import React from 'react';
import { List, Datagrid, Edit, Create, SimpleForm, TextField, EditButton, TextInput } from 'react-admin';
//ReferenceField
export const CatData = (props) => (
    <List {...props}>
        <Datagrid>
            
            

            <TextField source="catname" />
         
       
            
            <EditButton basePath="/menucategories" />
        </Datagrid>
    </List>
);

const CatTitle = ({ record }) => {
    return <span>Category {record ? `"${record.title}"` : ''}</span>;
};

export const CatEdit = (props) => (
    <Edit title={<CatTitle />} {...props}>
        <SimpleForm>
            <TextInput disabled source="id" />
            <TextInput label="Category name" source="catname" />
         </SimpleForm>
    </Edit>
);

export const CreateCatItem = (props) => (
    <Create title="Add a Category" {...props}>
        <SimpleForm>
        <TextInput disabled source="id" />
        <TextInput label="Category name"  source="catname" />
          </SimpleForm>
    </Create>
);

Any help or assistance would be greatly appreciated.

caston
  • 159
  • 12
  • Seems like the data provider is broken and it throws an error. This could be due to misconfiguration on your side or a bug in the provider. I myself didn't have much luck with the official provider and I created my own. I published my work [here](https://gist.github.com/hendrikniemann/83648da05161a36e84c0ee4ab61ad605). – Herku Jul 01 '20 at 13:55
  • Thanks Herku, I will try that out. I am currently using [postgraphile client for react-admin](https://github.com/BowlingX/ra-postgraphile) I assume I would need to change this to use your solution instead. – caston Jul 01 '20 at 22:45
  • I just found the following: Different Primary Keys Sometimes the table you are querying might have a primary key other than id. react-admin enforces id to be returned in the response by the DataProvider. But you can configure a different primary key column for specific tables using the config object as below: const config = { 'primaryKey': { 'tableName': 'primaryKeyColumn', 'tableName2': 'primaryKeyColumn' } }; – caston Jul 06 '20 at 13:35

0 Answers0