Error trying to reorder items within another list in Keystone 6

321 Views Asked by At

I'm using KeystoneJS v6. I'm trying to enable functionality which allow me to reorder the placement of images when used in another list. Currently i'm setting up the image list below, however I'm unable to set the defaultIsOrderable to true due to the error pasted.

KeystoneJS list:

  Image: list({
    fields: {
      title: text({
        validation: { isRequired: true },
        isIndexed: 'unique',
        isFilterable: true,
        isOrderable: true,
      }),
      images: cloudinaryImage({
        cloudinary: {
          cloudName: process.env.CLOUDINARY_CLOUD_NAME,
          apiKey: process.env.CLOUDINARY_API_KEY,
          apiSecret: process.env.CLOUDINARY_API_SECRET,
          folder: process.env.CLOUDINARY_API_FOLDER,
        },
      }),
    },
    defaultIsOrderable: true
  }),

Error message:

The expected type comes from property 'defaultIsOrderable' which is declared here on type 'ListConfig<BaseListTypeInfo, BaseFields<BaseListTypeInfo>>'

Peeking at the definition of the field shows

defaultIsOrderable?: false | ((args: FilterOrderArgs<ListTypeInfo>) => MaybePromise<boolean>);
1

There are 1 best solutions below

0
On

Looking at the schema API docs, the defaultIsOrderable lets you set:

[...] the default value to use for isOrderable for fields on this list.

You're trying to set this to true but, according to the relevant section of the field docs, the isOrderable field option already defaults to true. I believe this is why the defaultIsOrderable type doesn't allow you to supply the true literal – doing so would be redundant.

So that explains the specific error your getting but I think you also may have misunderstood the purpose of the orderBy option.

The OrderBy Option

The field docs mention the two effects the field OrderBy option has:

If true (default), the GraphQL API and Admin UI will support ordering by this field.

Take, for example, your Image list above. As the title field is "orderable", it is included in the list's orderBy GraphQL type (ImageOrderByInput). When querying the list, you can order the results by the values in this field, like this:

query {
  images (orderBy: [{ title: desc }]) {
    id
    title
    images { publicUrl }
  }
}

The GraphQL API docs have some details on this.

You can also use the field to order items when listing them in the Admin UI, either by clicking the column heading or selecting the field from the "sort" dropdown:

Keystone list view ordering options

Note though, these features order items at runtime, by the values stored in orderable fields. They don't allow an admin to "re-order" items in the Admin UI (unless you did so by changing the image titles in this case).

Specifying an Order

If you want to set the order of items within a list you'd need to store separate values in, for example, a displayOrder field like this:

  Image: list({
    fields: {
      title: text({
        validation: { isRequired: true },
        isIndexed: 'unique',
        isFilterable: true,
      }),
      displayOrder: integer(),
      // ...
    },
  }),

Unfortunately Keystone doesn't yet give you a great way to manage this the Admin UI (ie. you can't "drag and drop" in the list view or anything like that). You need to edit each item individually to set the displayOrder values.

Ordering Within a Relationship

I notice your question says you're trying to "reorder the placement of images when used in another list" (emphasis mine). In this case you're talking about relationships, which changes the problem somewhat. Some approaches are..

  • If the relationship is one-to-many, you can use the displayOrder: integer() solution shown above but the UX is worse again. You're still setting the order values against each item but not in the context of the relationship. However, querying based on these order values and setting them via the GraphQL API should be fairly straight forward.
  • If the relationship is many-to-many, it's similar but you can't store the "displayOrder" value in the Image list as any one image may be linked to multiple other items. You need to store the order info "with" the relationship itself. It's not trivial but my recent answer on storing additional values on a many-to-many relationship may point you in the right direction.
  • A third option is to not use the relationship field at all but to link items using the inline relationships functionality of the document field. This is a bit different to work with - easier to manage from the Admin UI but less powerful in GraphQL as you can't traverse the relationship as easily. However it does give you a way to manage a small, ordered set of related items in a many-to-many relationship.
  • You can save an ordered set of ids to a json field. This is similar to using a document field but a more manual.

Hopefully that clears up what's possible with the current "orderBy" functionality and relationship options. Which of these solutions is most appropriate depends heavily on the specifics of your project and use case.

Note too, there are plans to extend Keystone's functionality for sorting and reordering lists from both the DX and UX perspectives. See "Sortable lists" on the Keystone roadmap.