MrHertal / react-admin-amplify

AWS Amplify data provider for react-admin.
MIT License
159 stars 42 forks source link

Graphql pluralization for Edit: useGetOne() relies on the Redux store #59

Closed bjacog closed 3 years ago

bjacog commented 3 years ago

I have an AWS Amplify graphql api model:

type Category @model {
  id: ID!
  name: String!
  colour: String!
  careers: [Career] @connection(keyName: "byCategory", fields: ["id"])
  questions: [Question] @connection(keyName: "byCategory", fields: ["id"])
}

My list component works 100% out of the box using what ListGuesser provides.

For Create, using a very basic Create form:

const CreateCategory = (props) => (
  <Create
    {...props}
  >
    <SimpleForm>
      <TextInput source="name" />
      <TextInput source="colour" />
    </SimpleForm>
  </Create>
);

When I try to save the form data, it. produces an error:

Could not find query createCategorie

Seems like a classic error in pluralization, but. inspecting the code of this lib or the graphql lib used yielded no information to me. I updated the Create:

const CreateCategory = (props) => (
  <Create
    // eslint-disable-next-line react/jsx-props-no-spreading
    {...props}
    /* this is weird, but I think translation is messing with us.
    * Since the lib was trying to hit createCategorie
    * (mis-singularization of categories -> category.)
    * when I passed "category" as the resource, it incorrectly dropped the y at the end.
    */
    resource="categoryy"
  >
    <SimpleForm>
      <TextInput source="name" />
      <TextInput source="colour" />
    </SimpleForm>
  </Create>
);

And it worked. Moving on I expected the same to be required for Edit but alas it did not work. My Edit component:

const EditCategory = (props) => (
  <Edit
    {...props}
  >
    <SimpleForm>
      <TextInput source="name" />
      <TextInput source="colour" />
    </SimpleForm>
  </Edit>
);

This produces the some message that Create produced:

Could not find query getCategorie

So I added the resource, first just with one y:

const EditCategory = (props) => (
  <Edit
    // eslint-disable-next-line react/jsx-props-no-spreading
    {...props}
    /* this is weird, but I think translation is messing with us.
    * Since the lib was trying to hit createCategorie
    * (mis-singularization of categories -> category.)
    * when I passed "category" as the resource, it incorrectly dropped the y at the end.
    */
    resource="category"
  >
    <SimpleForm>
      <TextInput source="name" />
      <TextInput source="colour" />
    </SimpleForm>
  </Edit>
);

Which yields:

useGetOne.js:43 Uncaught Error: No <Resource> defined for "category". useGetOne() relies on the Redux store, so it cannot work if you don't include a <Resource>.

Adding another y to the resource in an attempt to hack it:

const EditCategory = (props) => (
  <Edit
    // eslint-disable-next-line react/jsx-props-no-spreading
    {...props}
    /* this is weird, but I think translation is messing with us.
    * Since the lib was trying to hit createCategorie
    * (mis-singularization of categories -> category.)
    * when I passed "category" as the resource, it incorrectly dropped the y at the end.
    */
    resource="categoryy"
  >
    <SimpleForm>
      <TextInput source="name" />
      <TextInput source="colour" />
    </SimpleForm>
  </Edit>
);

Which produces the same error for the updated resource name:

useGetOne.js:43 Uncaught Error: No <Resource> defined for "categoryy". useGetOne() relies on the Redux store, so it cannot work if you don't include a <Resource>.

Any help would be greatly appreciated.

MrHertal commented 3 years ago

Hi,

What is the name of the resource in App.js?

The pluralization is dumb, so if your model is Category, resource name should be: categorys

You can then change the label like:

<Resource name="categorys" options={{ label: "Categories" }} />
bjacog commented 3 years ago

@MrHertal Thank you that pointed me in the right direction.

Your solution works but another issue in react-admin causes the dataprovider to pass relations as fields to amplify. So I had to implement custom graphql mutations for updates anyway. So I ended up customizing the graphql queries for the model with the name "fixed" to Categorie and right now that seems like the solution with the cleanest implementation without having to have resources with funny names.