fix(ui): populate nested fields for enableListViewSelectAPI (#13827)

Fixes an issue with the new experimental `enableListViewSelectAPI`
config option.

Group fields were not populating properly in the list view

### Before (incorrect)
```ts
{
  group.field: true
}
```

### After (correct)
```ts
{
  group: {
    field: true
  }
}
```
This commit is contained in:
Jarrod Flesch
2025-09-16 17:23:08 -04:00
committed by GitHub
parent a9553925f6
commit dc732b8f52
7 changed files with 142 additions and 54 deletions

View File

@@ -1,9 +1,14 @@
import type { ColumnPreference, SelectType } from 'payload'
export const transformColumnsToSelect = (columns: ColumnPreference[]): SelectType =>
columns.reduce((acc, column) => {
import { unflatten } from 'payload/shared'
export const transformColumnsToSelect = (columns: ColumnPreference[]): SelectType => {
const columnsSelect = columns.reduce((acc, column) => {
if (column.active) {
acc[column.accessor] = true
}
return acc
}, {} as SelectType)
return unflatten(columnsSelect)
}

View File

@@ -21,5 +21,15 @@ export const ListViewSelectAPI: CollectionConfig = {
name: 'description',
type: 'text',
},
{
name: 'group',
type: 'group',
fields: [
{
name: 'groupNameField',
type: 'text',
},
],
},
],
}

View File

@@ -36,6 +36,7 @@ let payload: PayloadTestSDK<Config>
import { listViewSelectAPISlug } from 'admin/collections/ListViewSelectAPI/index.js'
import { devUser } from 'credentials.js'
import { getRowByCellValueAndAssert } from 'helpers/e2e/getRowByCellValueAndAssert.js'
import {
openListColumns,
reorderColumns,
@@ -993,7 +994,8 @@ describe('List View', () => {
await toggleColumn(page, { columnLabel: 'ID', columnName: 'id', targetState: 'off' })
})
test('should use select API in the list view when `enableListViewSelectAPI` is true', async () => {
describe('enableListViewSelectAPI', () => {
test('`id` should always be selected even when toggled off', async () => {
const doc = await payload.create({
collection: listViewSelectAPISlug,
data: {
@@ -1047,6 +1049,48 @@ describe('List View', () => {
.toBeTruthy()
})
test('group fields should populate with the select API', async () => {
const doc = await payload.create({
collection: listViewSelectAPISlug,
data: {
title: 'This is a test title',
description: 'This is a test description',
group: {
groupNameField: 'Select Nested Field',
},
},
})
const selectAPIUrl = new AdminUrlUtil(serverURL, listViewSelectAPISlug)
await page.goto(selectAPIUrl.list)
await toggleColumn(page, {
columnLabel: 'Group > Group Name Field',
columnName: 'group.groupNameField',
targetState: 'off',
})
await toggleColumn(page, {
columnLabel: 'Group > Group Name Field',
columnName: 'group.groupNameField',
targetState: 'on',
})
await getRowByCellValueAndAssert({
cellClass: `.cell-group__groupNameField`,
page,
textToMatch: 'Select Nested Field',
})
// cleanup after run
await payload.delete({
id: doc.id,
collection: listViewSelectAPISlug,
})
})
})
test('should toggle columns and save to preferences', async () => {
const tableHeaders = 'table > thead > tr > th'
const numberOfColumns = await page.locator(tableHeaders).count()

View File

@@ -594,6 +594,9 @@ export interface ListViewSelectApi {
id: string;
title?: string | null;
description?: string | null;
group?: {
groupNameField?: string | null;
};
updatedAt: string;
createdAt: string;
}
@@ -1153,6 +1156,11 @@ export interface CustomListDrawerSelect<T extends boolean = true> {
export interface ListViewSelectApiSelect<T extends boolean = true> {
title?: T;
description?: T;
group?:
| T
| {
groupNameField?: T;
};
updatedAt?: T;
createdAt?: T;
}

View File

@@ -76,6 +76,7 @@ export const testEslintConfig = [
'createFolderFromDoc',
'assertURLParams',
'uploadImage',
'getRowByCellValueAndAssert',
],
},
],

View File

@@ -0,0 +1,23 @@
import type { Locator, Page } from '@playwright/test'
import { expect } from '@playwright/test'
export async function getRowByCellValueAndAssert({
page,
textToMatch,
cellClass,
}: {
cellClass: `.cell-${string}`
page: Page
textToMatch: string
}): Promise<Locator> {
const row = page
.locator(`.collection-list .table tr`)
.filter({
has: page.locator(`${cellClass}`, { hasText: textToMatch }),
})
.first()
await expect(row).toBeVisible()
return row
}

View File

@@ -2,6 +2,8 @@ import type { Page } from '@playwright/test'
import type { AdminUrlUtil } from '../../helpers/adminUrlUtil.js'
import { getRowByCellValueAndAssert } from './getRowByCellValueAndAssert.js'
export async function goToListDoc({
page,
cellClass,
@@ -14,12 +16,7 @@ export async function goToListDoc({
urlUtil: AdminUrlUtil
}) {
await page.goto(urlUtil.list)
const row = page
.locator(`.collection-list .table tr`)
.filter({
has: page.locator(`${cellClass}`, { hasText: textToMatch }),
})
.first()
const row = await getRowByCellValueAndAssert({ page, textToMatch, cellClass })
const cellLink = row.locator(`td a`).first()
const linkURL = await cellLink.getAttribute('href')
await page.goto(`${urlUtil.serverURL}${linkURL}`)