payloadcms / payload

Payload is the open-source, fullstack Next.js framework, giving you instant backend superpowers. Get a full TypeScript backend and admin panel instantly. Use Payload as a headless CMS or for building powerful applications.
https://payloadcms.com
MIT License
25.77k stars 1.64k forks source link

defaultSort (dev and cloud) and defaultColumns (only cloud) not respected for a certain collection #8265

Closed Because789 closed 2 months ago

Because789 commented 2 months ago

Link to reproduction

https://github.com/Because789/payload/tree/defaultsort-test/test/_community/collections

Environment Info

Binaries:
  Node: 20.17.0
  npm: 10.8.2
  Yarn: N/A
  pnpm: 9.10.0
Relevant Packages:
  payload: 3.0.0-beta.107
  next: 15.0.0-canary.104
  @payloadcms/db-mongodb: 3.0.0-beta.107
  @payloadcms/email-nodemailer: 3.0.0-beta.107
  @payloadcms/graphql: 3.0.0-beta.107
  @payloadcms/next/utilities: 3.0.0-beta.107
  @payloadcms/plugin-cloud: 3.0.0-beta.107
  @payloadcms/plugin-nested-docs: 3.0.0-beta.107
  @payloadcms/richtext-lexical: 3.0.0-beta.107
  @payloadcms/translations: 3.0.0-beta.107
  @payloadcms/ui/shared: 3.0.0-beta.107
  react: 19.0.0-rc-06d0b89e-20240801
  react-dom: 19.0.0-rc-06d0b89e-20240801

Describe the Bug

I have this collection:

import { Image } from '@/blocks/image/config'
import { Connections } from '@/blocks/connections/config'
import { InspirationalQuote } from '@/blocks/inspirational-quote/config'
import { ConflictQuote } from '@/blocks/conflict-quote/config'
import { SolutionQuote } from '@/blocks/solution-quote/config'
import { Keywords } from '@/blocks/keywords/config'
import type { CollectionConfig } from 'payload'

export const Stories: CollectionConfig = {
    slug: 'stories',
    access: {
        read: () => true,
    },
    admin: {
        group: 'Content',
        useAsTitle: 'title',
        description: 'Hier werden die Geschichten verwaltet',
        defaultColumns: ['title', 'content', 'pub_date', 'storyteller', '_status'],
        pagination: {
            limits: [10, 20, 50, 100],
        },
    },
    defaultSort: '-title',
    fields: [
        {
            name: 'title',
            label: 'Title',
            type: 'text',
            required: true,
        },
        {
            type: 'tabs',
            tabs: [
                {
                    label: 'Main', // required
                    description: 'Edit content here',
                    fields: [
                        {
                            name: 'main_image',
                            label: 'Main Image',
                            type: 'upload',
                            relationTo: 'media',
                            required: true,
                        },
                        {
                            name: 'content',
                            label: 'Content',
                            type: 'richText',
                            localized: true,
                            // Pass the Lexical editor here and override base settings as necessary
                            // editor: lexicalEditor(),
                        },
                    ]
                },
                {
                    label: 'Blocks', // required
                    description: 'Edit blocks here',
                    fields: [
                        {
                            // Optionale Features gehören hier hin
                            name: 'layout',
                            label: 'Layout',
                            type: 'blocks',
                            blocks: [
                                Image,
                                Connections,
                                InspirationalQuote,
                                ConflictQuote,
                                SolutionQuote,
                                Keywords,
                            ],
                            localized: true,
                        },
                    ]
                },
                {
                    label: 'Meta',
                    description: 'Edit meta data here',
                    fields: [
                        {
                            name: 'series',
                            label: 'Series',
                            type: 'relationship',
                            relationTo: 'series',
                            required: true,
                        },
                        {
                            name: 'storyteller',
                            label: 'Storyteller',
                            type: 'relationship',
                            relationTo: 'users',
                            required: true,
                        },
                        {
                            name: 'storywriter',
                            label: 'Storywriter',
                            type: 'relationship',
                            relationTo: 'users',
                            required: true,
                        },
                        {
                            name: 'interview_language',
                            label: 'Interview Language',
                            type: 'text',
                        },
                        {
                            name: 'interview_place',
                            label: 'Interview Place',
                            type: 'text',
                        },
                        {
                            name: 'country',
                            type: 'text',
                            admin: {
                                components: {
                                    Field: '/components/SelectCountry.tsx#SelectCountry',
                                },
                            },
                        },
                    ]
                },
            ],
        },
        {
            name: 'slug',
            label: 'Slug',
            type: 'text',
            required: true,
            admin: {
                position: 'sidebar',
                description: 'URL of the story: yyyy-mm-dd-title',
            }
        },
        {
            name: 'pub_date',
            label: 'Publication Date',
            type: 'date',
            required: true,
            admin: {
                date: {
                    displayFormat: 'd. MMMM yyyy',
                },
                position: 'sidebar',
            }
        },
        {
            name: 'categories',
            label: 'Categories',
            type: 'relationship',
            relationTo: 'categories',
            hasMany: true,
            required: true,
            admin: {
                position: 'sidebar',
            }
        },
    ],
    versions: {
        drafts: {
            // // Uncomment to enable autosave for drafts
            // autosave: {
            //     interval: 800, // In milliseconds
            // },
        },
        maxPerDoc: 10,
    },
}

In my dev environment, defaultColumns works, but defaultSort defaults to &sort=author, although there is not a single field named author in the whole project:

Stories-Dev

On my cloud instance, defaultColumns doesn't work and defaultSort defaults to &sort=-categories:

Stories-Cloud

Since other collections don't show this issues, I assume the problem is the nesting in this collection with tabs and/or blocks? I tried commenting out the tab with the blocks (see below), but that didn't change anything. I'm new to payload, so it's unclear to me, if there is an issue with my collection configuration or if that's a bug.

Reproduction Steps

This shorter version shows the same behavior in my dev environment (didn't test it in cloud):

import type { CollectionConfig } from 'payload'

export const Stories: CollectionConfig = {
    slug: 'stories',
    access: {
        read: () => true,
    },
    admin: {
        group: 'Content',
        useAsTitle: 'title',
        description: 'Hier werden die Geschichten verwaltet',
        defaultColumns: ['title', 'content', 'pub_date', 'storyteller', '_status'],
        pagination: {
            limits: [10, 20, 50, 100],
        },
    },
    defaultSort: '-title',
    fields: [
        {
            name: 'title',
            label: 'Title',
            type: 'text',
            required: true,
        },
        {
            type: 'tabs',
            tabs: [
                {
                    label: 'Main', // required
                    description: 'Edit content here',
                    fields: [
                        {
                            name: 'main_image',
                            label: 'Main Image',
                            type: 'upload',
                            relationTo: 'media',
                            required: true,
                        },
                        {
                            name: 'content',
                            label: 'Content',
                            type: 'richText',
                            localized: true,
                        },
                    ]
                },
                {
                    label: 'Meta',
                    description: 'Edit meta data here',
                    fields: [
                        {
                            name: 'storyteller',
                            label: 'Storyteller',
                            type: 'relationship',
                            relationTo: 'users',
                            required: true,
                        },
                        {
                            name: 'storywriter',
                            label: 'Storywriter',
                            type: 'relationship',
                            relationTo: 'users',
                            required: true,
                        },
                        {
                            name: 'interview_language',
                            label: 'Interview Language',
                            type: 'text',
                        },
                        {
                            name: 'interview_place',
                            label: 'Interview Place',
                            type: 'text',
                        },
                        {
                            name: 'country',
                            type: 'text',
                            admin: {
                                components: {
                                    Field: '/components/SelectCountry.tsx#SelectCountry',
                                },
                            },
                        },
                    ]
                },
            ],
        },
        {
            name: 'slug',
            label: 'Slug',
            type: 'text',
            required: true,
            admin: {
                position: 'sidebar',
                description: 'URL of the story: yyyy-mm-dd-title',
            }
        },
        {
            name: 'pub_date',
            label: 'Publication Date',
            type: 'date',
            required: true,
            admin: {
                date: {
                    displayFormat: 'd. MMMM yyyy',
                },
                position: 'sidebar',
            }
        },
    ],
    versions: {
        drafts: {
            // // Uncomment to enable autosave for drafts
            // autosave: {
            //     interval: 800, // In milliseconds
            // },
        },
        maxPerDoc: 10,
    },
}

I added it to test/_community/collections, but didn't understand how to get it running (got a Mongo DB connection error).

Adapters and Plugins

No response

paulpopus commented 2 months ago

Can you test this behaviour in a fresh browser and with a new user please?

Reason being that we actually store user preferences for certain things in the admin panel, so if you've clicked around and customised columns for example it will be stored and then re-used every time. The configuration is only respected if you have no preferences, as in a fresh user.

Because789 commented 2 months ago

Oh well, that simple, yeah that was it. Same user in fresh browser didn't help. New user in fresh browser did help. For the old user in the cloud I had to trigger another sorting, and just like that the defaultColumns were right.

But isn't that an issue? Shouldn't a new deployment trigger the deletion of this user settings, at least of those that get changed? defaultSort isn't such an issue, but at least a change in defaultColumns should delete this specific user setting, don't you think so?

paulpopus commented 2 months ago

Nice glad it's solved!

But isn't that an issue?

It's hard to actually know if the user's columns don't match default columns due to updated preferences or deployments without storing more data on them.

One thing you can do if this becomes a regular problem is to just delete user preferences from the database or using the local API in onInit or via a custom endpoint.

As a feature we've had the idea to add a button on the user account so each user can reset their own preferences if needed.

Because789 commented 2 months ago

+1 for that feature.

Thanks for the help!

github-actions[bot] commented 2 months ago

This issue has been automatically locked. Please open a new issue if this issue persists with any additional detail.