MrHertal / react-admin-amplify

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

Sort list and filter by connection field #43

Closed mgiorgi-github closed 3 years ago

mgiorgi-github commented 3 years ago

Hi, excuse me for opened a new issue but i can't enable sorting... i've follow 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... I've to display a list of data (Pill items in my case), enable sort column by delay field (a numeric field) and add a simple filter by type (type is a connection, not a real field)... can you give me an functional example for do it? I think this can bu usefull for other people...

Thanks

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

type Type
  @model{
  id: ID!
  title: String
  pills: [Pill] @connection(name: "PillType")
}

export const PillList = (props) => (
  <List {...props}>
    <Datagrid>
      <TextField source="title" sortBy="pillByTitle" sortable={true}/>
      <TextField source="description" />
mgiorgi-github commented 3 years ago

I've create a new project and follow all steps of documentations... i can filter but can't sort my PillList for title and delay... what is wrong?

I've installed the demo but i've not seen a sorting example


type Type
  @model
  @key(name: "byTitle", fields: ["title", "id"], queryField: "typesByTitle") 
{
  id: ID!
  title: String
  order: Int!
}

type Pill
  @model
  @key(name: "byType", fields: ["typeID", "id"], queryField: "pillsByType")
  @key(name: "byDelay", fields: ["delay", "id"], queryField: "pillsByDelay")
  @key(name: "byTitle", fields: ["title", "id"], queryField: "pillsByTitle")
{
  id: ID!
  title: String
  description: String
  text: String
  typeID: ID!
  delay: Int!
}

const PillFilter = (props) => (
  <AmplifyFilter {...props}>
  <ReferenceInput
    source="pillsByType.typeID"
    reference="types"
    label="Tipologia di utente"
    filterToQuery={(searchText) => ({
      typesByTitle: { title: searchText },
    })}
    alwaysOn
  >
    <AutocompleteInput optionText="title" alwaysOn resettable />
  </ReferenceInput>
  </AmplifyFilter>
);

export const PillList = (props) => (
  <List {...props} filters={<PillFilter />}>
    <Datagrid>
      <TextField source="title" sortBy="pillsByTitle" sortable={true}/>
      <TextField source="description" />
      <ReferenceField
        source="typeID"
        label="Type"
        reference="types"
        link="show"
      >
        <TextField source="title"/>
      </ReferenceField>
      <TextField source="delay" sortBy="pillsByDelay" sortable={true}/>
      <EditButton />
      <DeleteButton />
    </Datagrid>
  </List>
);```
MrHertal commented 3 years ago

In order to sort by title or delay, you need to define sort keys:

type Pill
  @model
  @key(name: "byType", fields: ["typeID", "id"], queryField: "pillsByType")
  @key(name: "byFooByTitle", fields: ["foo", "title"], queryField: "pillsByFooByTitle")
  @key(name: "byFooByDelay", fields: ["foo", "delay"], queryField: "pillsByFooByDelay")
{
  id: ID!
  foo: String!
  title: String
  description: String
  text: String
  typeID: ID!
  delay: Int!
}

foo field must always be the same value, something like PILL.

Then configure the filter:

const defaultQuery = "listPills";

const PillFilter = (props) => (
  <AmplifyFilter {...props} defaultQuery={defaultQuery}>
    <QuickFilter
      source="pillsByFooByTitle.foo"
      label="Title"
      defaultValue="PILL"
    />
    <TextInput
      source="pillsByFooByTitle.title.beginsWith"
      label="Title"
      alwaysOn
      resettable
    />
    <QuickFilter
      source="pillsByFooByDelay.foo"
      label="Delay"
      defaultValue="PILL"
    />
    <TextInput
      source="pillsByFooByDelay.delay.beginsWith"
      label="Delay"
      alwaysOn
      resettable
    />
  </AmplifyFilter>
);

export const PillList = (props) => {
  const [query, setQuery] = React.useState(defaultQuery);

  return (
    <List
      {...props}
      filters={<PillFilter setQuery={setQuery} />}
    >
      <Datagrid>
        <TextField source="title" sortBy={query} />
        <TextField source="delay" sortBy={query} />
      </Datagrid>
    </List>
  );
};
mgiorgi-github commented 3 years ago

Hi Grégoire, thanks for reply... for every tables i've to add a field only for sorting ( like "foo") with even the same value for each row ( like "PILL")? Is right? In your documentation you've usato productID and customerID but this fields have got a different value for orders rows... i can't use in both filter typeID?

type Pill
  @model
  @key(name: "byType", fields: ["typeID", "id"], queryField: "pillsByType")
  @key(name: "byTypeByTitle", fields: ["typeID", "title"], queryField: "pillsByTypeByTitle")
  @key(name: "byTypeByDelay", fields: ["typeID", "delay"], queryField: "pillsByTypeByDelay")
{
  id: ID!
  title: String
  description: String
  text: String
  typeID: ID!
  delay: Int!
}
MrHertal commented 3 years ago

Yes this is the only way if you want to sort ALL pills by title or delay.

@key(name: "byTypeByTitle", fields: ["typeID", "title"], queryField: "pillsByTypeByTitle")

doing like this, you will only be able to sort by title the pills of a specific type.

mgiorgi-github commented 3 years ago

I've tried a lot of times but i can't sort... i've added this keys but the rows order remain even self, certificationID in my case have even the same value, i'm desperated :-(

type Pill
  @model
  @key(name: "byDelay", fields: ["certificationID", "delay"], queryField: "pillsByDelay")
  @auth(
    rules: [
      {
        allow: groups
        groups: ["Admin"]
        operations: [create, read, update, delete]
      }
      { allow: groups, groups: ["Client"], operations: [read] }
    ]
  ){
  id: ID!
  title: String
  delay: Int!
  typeID: ID!
  certificationID: ID!
}

export const PillList = (props) => (
  <List {...props}>
    <Datagrid>
      <TextField source="id" sortable={false}/>
      <TextField source="title" sortable={false}/>
      <TextField source="certificationID" sortable={false}/>
      <ReferenceField
        source="typeID"
        label="Type"
        reference="types"
        link="show"
      >
        <TextField source="title"/>
      </ReferenceField>
      <TextField source="delay" sortBy="pillsByDelay" sortable={true}/>
      <EditButton />
      <DeleteButton />
    </Datagrid>
  </List>
);
MrHertal commented 3 years ago

It looks correct now but you need to put the filter:

    <List
      {...props}
      filters={<PillFilter setQuery={setQuery} />}
    >

Then once you filter by certificationID, you should be able to sort by delay.

mgiorgi-github commented 3 years ago

Ok now it work fine! Is possibile enable a default filter in order to show all data already sorted? In my case i've certificationID whit the same value and for enable sort before i've to filter (for only one exist value of certificationID) and then see the rows sorted

MrHertal commented 3 years ago

OK good news.

II don't know if it's possible to put a default value, have you tried this?

Otherwise in your case you could simply replace the listPills query in queries.js by the pillsByDelay query. With the certificationID value hardcoded. You wouldn't even need to set a filter.

mgiorgi-github commented 3 years ago

I've tried to add filterDefaultValues but don't work fine... Last question: is possible manually trigger change event of filter and force the default value (into PillList component where query="listPills")? Thanks for support

MrHertal commented 3 years ago

It should be possible but I've never tried.