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
23.28k stars 1.47k forks source link

type: row admin condition seems broken #5406

Open dacgray opened 5 months ago

dacgray commented 5 months ago

Link to reproduction

No response

Describe the Bug

                {
                    label: 'Items',
                    name: 'items',
                    type: 'array',
                    labels: {
                        singular: 'Item',
                        plural: 'Items',
                    },
                    admin: itemAdmin,
                    fields: [
                        {
                            label: 'Type',
                            name: 'type',
                            type: 'radio',
                            required: true,
                            options: [location, socialMedia, trustpilot],
                        },
                        {
                            label: 'Location',
                            type: 'group',
                            name: location.value,
                            admin: {
                                condition: (data, siblingData) =>
                                    siblingData.type === location.value,
                            },
                            fields: [
                                {
                                    label: 'Type',
                                    name: 'type',
                                    type: 'radio',
                                    required: true,
                                    options: [Fields.staticPage, Fields.link],
                                },
                                {
                                    admin: {
                                        condition: (data, siblingData) => {
                                            console.log('a', siblingData)
                                            return (
                                                siblingData.type ===
                                                Fields.staticPage.value
                                            )
                                        },
                                    },
                                    type: 'row',
                                    fields: [
                                        {
                                            label: 'Page Tag Filter',
                                            name: 'pageSelector',
                                            type: 'relationship',
                                            relationTo: 'page-tag-v1',
                                            admin: {
                                                width: '50%',
                                            },
                                        },
                                        {
                                            label: 'Target Url',
                                            name: 'staticPage',
                                            type: 'relationship',
                                            required: true,
                                            relationTo: 'static-page-v1',
                                            filterOptions: ({
                                                siblingData,
                                            }) => ({
                                                tags: {
                                                    equals: siblingData[
                                                        'pageSelector'
                                                    ],
                                                },
                                            }),
                                            admin: {
                                                width: '50%',
                                            },
                                        },
                                    ],
                                },

                                {
                                    admin: {
                                        condition: (data, siblingData) => {
                                            console.log('b', siblingData)
                                            return (
                                                siblingData.type ===
                                                Fields.link.value
                                            )
                                        },
                                    },
                                    label: 'External Link',
                                    name: 'link',
                                    type: 'relationship',
                                    required: true,
                                    relationTo: 'link-v1',
                                },
                            ],
                        },
                    ],
                },

If I place the condition on the row field sibling data is mixed between the item array object and the location group object:

image

If I place the condition on pageSelector and staticPage things work as expected:

{
                    label: 'Items',
                    name: 'items',
                    type: 'array',
                    labels: {
                        singular: 'Item',
                        plural: 'Items',
                    },
                    admin: itemAdmin,
                    fields: [
                        {
                            label: 'Type',
                            name: 'type',
                            type: 'radio',
                            required: true,
                            options: [location, socialMedia, trustpilot],
                        },
                        {
                            label: 'Location',
                            type: 'group',
                            name: location.value,
                            admin: {
                                condition: (data, siblingData) =>
                                    siblingData.type === location.value,
                            },
                            fields: [
                                {
                                    label: 'Type',
                                    name: 'type',
                                    type: 'radio',
                                    required: true,
                                    options: [Fields.staticPage, Fields.link],
                                },
                                {
                                    type: 'row',
                                    fields: [
                                        {
                                            label: 'Page Tag Filter',
                                            name: 'pageSelector',
                                            type: 'relationship',
                                            relationTo: 'page-tag-v1',
                                            admin: {
                                                condition: (
                                                    data,
                                                    siblingData
                                                ) => {
                                                    console.log(
                                                        'a',
                                                        siblingData
                                                    )
                                                    return (
                                                        siblingData.type ===
                                                        Fields.staticPage.value
                                                    )
                                                },
                                                width: '50%',
                                            },
                                        },
                                        {
                                            label: 'Target Url',
                                            name: 'staticPage',
                                            type: 'relationship',
                                            required: true,
                                            relationTo: 'static-page-v1',
                                            filterOptions: ({
                                                siblingData,
                                            }) => ({
                                                tags: {
                                                    equals: siblingData[
                                                        'pageSelector'
                                                    ],
                                                },
                                            }),
                                            admin: {
                                                condition: (
                                                    data,
                                                    siblingData
                                                ) => {
                                                    console.log(
                                                        'a',
                                                        siblingData
                                                    )
                                                    return (
                                                        siblingData.type ===
                                                        Fields.staticPage.value
                                                    )
                                                },
                                                width: '50%',
                                            },
                                        },
                                    ],
                                },

                                {
                                    admin: {
                                        condition: (data, siblingData) => {
                                            console.log('b', siblingData)
                                            return (
                                                siblingData.type ===
                                                Fields.link.value
                                            )
                                        },
                                    },
                                    label: 'External Link',
                                    name: 'link',
                                    type: 'relationship',
                                    required: true,
                                    relationTo: 'link-v1',
                                },
                            ],
                        },
                    ],
                },

image

To Reproduce

Above

Payload Version

2.11.2

Adapters and Plugins

"@payloadcms/bundler-webpack": "^1.0.6", "@payloadcms/db-mongodb": "^1.3.2", "@payloadcms/plugin-cloud-storage": "^1.1.1", "@payloadcms/plugin-sentry": "^0.0.6", "@payloadcms/richtext-slate": "^1.3.1",

SimYunSup commented 5 months ago

I think you have to define row's name if you want to use condition in row.

https://github.com/payloadcms/payload/blob/1c0d43c61a0e29bc9de50a4e608cb7dff9d5cd48/packages/payload/src/admin/components/forms/withCondition/WatchCondition.tsx#L44-L65

condition property needs path internally, but path is blank string if name is not exists.

https://github.com/payloadcms/payload/blob/1c0d43c61a0e29bc9de50a4e608cb7dff9d5cd48/packages/payload/src/admin/components/forms/RenderFields/index.tsx#L111

dacgray commented 5 months ago

Adding name to the row field causes a type error and kills the build:

image

image

SimYunSup commented 5 months ago

Oh, very sorry. I was mistaken. RowField is present-only, so name field is not exists in type. So that was bug.

It causes because of row's path is parent's path, so getSiblingData returns parent's siblingData.

getSiblingData code should add edge case for present-only fields, but I can't think how it changes to.

I'm sorry that I was mistaken.