MrHertal / react-admin-amplify

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

Can create a object but can't edit ReferenceInput input #41

Closed mgiorgi-github closed 3 years ago

mgiorgi-github commented 3 years ago

I've create a simple crud stack... i can create a Pill object but can't update, here is my code:

export const PillList = (props) => (
  <List {...props}>
    <Datagrid>
      <TextField source="title" />
      <TextField source="description" />
      <ReferenceField
        source="type.id"
        label="Type"
        reference="types"
        link="show"
      >
        <TextField source="title" />
      </ReferenceField>
      <EditButton />
      <DeleteButton />
    </Datagrid>
  </List>
);

export const PillCreate = (props) => (
  <Create {...props}>
    <SimpleForm>
      <TextInput source="title" />
      <TextInput multiline source="description" />
      <ReferenceInput label="Type" source="pillTypeId" reference="types">
        <SelectInput optionText="title" />
      </ReferenceInput>
    </SimpleForm>
  </Create>
);

export const PillEdit = (props) => (
  <Edit {...props}>
    <SimpleForm>
      <TextInput disabled label="Id" source="id" />
      <TextInput source="title" />
      <TextInput multiline source="description" />
      <ReferenceInput label="Type" source="type.id" reference="types">
        <SelectInput optionText="title" />
      </ReferenceInput>
    </SimpleForm>
  </Edit>
);

This is schema.grapql:

type Pill
  @model
  {
  id: ID!
  title: String
  description: String
  typeID: ID!
  type: Type @connection(fields: ["typeID"])
}

type Type
  @model
  {
  id: ID!
  title: String
}

If i use pillTypeId as source of ReferenceInput into Edit form (like Create form that work fine), when edit an item i can't see the value into select. If i use type.id as source of ReferenceInput into Edit form, when edit an item i can see the right value into select.

Both of cases i can't update the data and return this error:

"The variables input contains a field name 'type' that is not defined for input object type 'UpdatePillInput' "

Where is the problem? In my schema?

How can i do? Thanks

MrHertal commented 3 years ago

Hi @mgiorgi-github,

This is a tricky case that I stumbled upon myself too. There is nothing wrong with your schema nor your code.

As you described, the problem is that in the case of PillEdit, there are actually two sources:

First one is type.id - This is the right source for displaying PillEdit form, because the data provider is receiving a Pill resource of that shape.

Second one is pillTypeId - This is the right source when editing a Pill resource, because the mutation only accepts that field.

So the trick is to use type.id in order to display the form, and then transform the data when the form is submitted in order to use pillTypeId.

React Admin allows us to transform a record after the user has submitted the form but before the record is passed to the dataProvider.

So this would give something like this:

const editTransform = ({ type, ...data }) => ({
  ...data,
  pillTypeId: type.id,
});

export const PillEdit = (props) => (
  <Edit {...props} transform={editTransform}>
    <SimpleForm>
      <TextInput disabled label="Id" source="id" />
      <TextInput source="title" />
      <TextInput multiline source="description" />
      <ReferenceInput label="Type" source="type.id" reference="types">
        <SelectInput optionText="title" />
      </ReferenceInput>
    </SimpleForm>
  </Edit>
);
mgiorgi-github commented 3 years ago

Hi Grégoire, fantastic... l'll try, can you give me too an example for sort data in PillList (for type.id for example) and add a select field for filter this value? I would set a default value and change it by click on columns... i've tried but the sord don't change for any fields.. Thanks!

MrHertal commented 3 years ago

I invite you to read the filtering and sorting sections in the README.

If that's not enough, check the demo source code. It's full of filtering and sorting examples.

Thanks.

mgiorgi-github commented 3 years ago

I've seen this demo but there are not sort column.. into my example i've a numeric "order" field for Pills object, wich key i've to add to schema in order to sort data with react-admin-amplify?

This is my code:

@model
  @key(name: "byPillOrder", fields: ["order"], queryField: "pillByOrder")
  {
  id: ID!
  title: String
  description: String
  order: Int
  typeID: ID!
  type: Type @connection(fields: ["typeID"])
}

export const PillList = (props) => (
  <List {...props}>
    <Datagrid>
      <TextField source="title" />
      <TextField source="description" />
      <ReferenceField
        source="type.id"
        label="Type"
        reference="types"
        link="show"
      >
        <TextField source="title" />
      </ReferenceField>
      <TextField source="order" sortBy="pillByOrder" sortable={true} />
      <EditButton />
      <DeleteButton />
    </Datagrid>
  </List>
);

Thanks

MrHertal commented 3 years ago

Again as explained here, you cannot sort the default list. Sorting is only possible when a sort key is defined in your schema, so it must be something like:

@key(name: "byPillOrder", fields: ["ANOTHER_FIELD", "order"], queryField: "pillByOrder")

ANOTHER_FIELD being a hash key.

This is a limitation of Amplify, see here.

mgiorgi-github commented 3 years ago

I've follow your documentations and this is my new code but don't work fine... i see the column arrow asc and desc but the data are not sorted...

PS: I've tried with id instead of createdAt but amplify push return this error: One or more parameter values were invalid: Table KeySchema does not have a range key, which is required when specifying a LocalSecondaryIndex

type Pill
  @model
  @key(name: "byPillTitle", fields: ["createdAt", "title"], queryField: "pillByTitle")
  @auth(
    rules: [
      {
        allow: groups
        groups: ["Admin"]
        operations: [create, read, update, delete]
      }
      { allow: groups, groups: ["Client"], operations: [read] }
    ]
  ){
  id: ID!
  title: String
  description: String
  type: Type @connection(name: "PillType")
  createdAt: String
}

export const PillList = (props) => (
  <List {...props}>
    <Datagrid>
      <TextField source="title" sortBy="pillByTitle" sortable={true}/>
      <TextField source="description" />