From 2ec4d0c2efe58e989cf4c4eae545eb45a0c0daf4 Mon Sep 17 00:00:00 2001 From: Dan Ribbens Date: Sat, 14 Dec 2024 22:31:31 -0500 Subject: [PATCH] feat: join field admin.defaultColumns (#9982) Add the ability to specify which columns should appear in the relationship table of a join fields The new property is in the Join field `admin.defaultColumns` and can be set to an array of strings containing the field names in the desired order. --- docs/fields/join.mdx | 9 +++--- packages/payload/src/admin/functions/index.ts | 2 +- packages/payload/src/fields/config/types.ts | 4 ++- .../src/elements/RelationshipTable/index.tsx | 12 +++++++- test/joins/collections/Categories.ts | 3 ++ test/joins/e2e.spec.ts | 28 +++++++++++++------ 6 files changed, 42 insertions(+), 16 deletions(-) diff --git a/docs/fields/join.mdx b/docs/fields/join.mdx index 7c4adedc6c..14627a6dc4 100644 --- a/docs/fields/join.mdx +++ b/docs/fields/join.mdx @@ -145,10 +145,11 @@ _\* An asterisk denotes that a property is required._ You can control the user experience of the join field using the `admin` config properties. The following options are supported: -| Option | Description | -|------------------------|----------------------------------------------------------------------------------------| -| **`allowCreate`** | Set to `false` to remove the controls for making new related documents from this field. | -| **`components.Label`** | Override the default Label of the Field Component. [More details](../admin/fields#label) | +| Option | Description | +|------------------------|---------------------------------------------------------------------------------------------------------------------------| +| **`defaultColumns`** | Array of field names that correspond to which columns to show in the relationship table. Default is the collection config. | +| **`allowCreate`** | Set to `false` to remove the controls for making new related documents from this field. | +| **`components.Label`** | Override the default Label of the Field Component. [More details](../admin/fields#label) | ## Join Field Data diff --git a/packages/payload/src/admin/functions/index.ts b/packages/payload/src/admin/functions/index.ts index 980e4767b4..a2bcc33a96 100644 --- a/packages/payload/src/admin/functions/index.ts +++ b/packages/payload/src/admin/functions/index.ts @@ -49,7 +49,7 @@ export type ListQuery = { export type BuildTableStateArgs = { collectionSlug: string - columns?: any[] // TODO: type this (comes from ui pkg) + columns?: { accessor: string; active: boolean }[] docs?: PaginatedDocs['docs'] enableRowSelections?: boolean query?: ListQuery diff --git a/packages/payload/src/fields/config/types.ts b/packages/payload/src/fields/config/types.ts index 4d2f9aa56e..2821602983 100644 --- a/packages/payload/src/fields/config/types.ts +++ b/packages/payload/src/fields/config/types.ts @@ -1390,6 +1390,7 @@ export type JoinField = { Error?: CustomComponent Label?: CustomComponent } & Admin['components'] + defaultColumns?: string[] disableBulkEdit?: never readOnly?: never } & Admin @@ -1422,7 +1423,8 @@ export type JoinField = { FieldGraphQLType export type JoinFieldClient = { - admin?: AdminClient & Pick + admin?: AdminClient & + Pick } & FieldBaseClient & Pick< JoinField, diff --git a/packages/ui/src/elements/RelationshipTable/index.tsx b/packages/ui/src/elements/RelationshipTable/index.tsx index 3d15b4af47..2d00b244e6 100644 --- a/packages/ui/src/elements/RelationshipTable/index.tsx +++ b/packages/ui/src/elements/RelationshipTable/index.tsx @@ -115,12 +115,21 @@ export const RelationshipTable: React.FC = (pro newQuery.where = hoistQueryParamsToAnd(newQuery.where, filterOptions) } + // map columns from string[] to ColumnPreferences + const defaultColumns = field.admin.defaultColumns + ? field.admin.defaultColumns.map((accessor) => ({ + accessor, + active: true, + })) + : undefined + const { data: newData, state: newColumnState, Table: NewTable, } = await getTableState({ collectionSlug: relationTo, + columns: defaultColumns, docs, enableRowSelections: false, query: newQuery, @@ -134,11 +143,12 @@ export const RelationshipTable: React.FC = (pro setIsLoadingTable(false) }, [ - query, field.defaultLimit, field.defaultSort, + field.admin.defaultColumns, collectionConfig.admin.pagination.defaultLimit, collectionConfig.defaultSort, + query, filterOptions, getTableState, relationTo, diff --git a/test/joins/collections/Categories.ts b/test/joins/collections/Categories.ts index 8b3a896ba6..4d031f39ba 100644 --- a/test/joins/collections/Categories.ts +++ b/test/joins/collections/Categories.ts @@ -91,6 +91,9 @@ export const Categories: CollectionConfig = { type: 'join', collection: postsSlug, on: 'group.category', + admin: { + defaultColumns: ['id', 'createdAt', 'title'], + }, }, { name: 'camelCasePosts', diff --git a/test/joins/e2e.spec.ts b/test/joins/e2e.spec.ts index 9d0d509f2b..f32386f315 100644 --- a/test/joins/e2e.spec.ts +++ b/test/joins/e2e.spec.ts @@ -218,16 +218,28 @@ test.describe('Join Field', () => { const titleAscButton = titleColumn.locator('button.sort-column__asc') await expect(titleAscButton).toBeVisible() await titleAscButton.click() - await expect(joinField.locator('tbody tr:first-child td:nth-child(2)')).toHaveText( - 'Test Post 1', - ) + await expect(joinField.locator('tbody .row-1')).toContainText('Test Post 1') const titleDescButton = titleColumn.locator('button.sort-column__desc') await expect(titleDescButton).toBeVisible() await titleDescButton.click() - await expect(joinField.locator('tbody tr:first-child td:nth-child(2)')).toHaveText( - 'Test Post 3', - ) + await expect(joinField.locator('tbody .row-1')).toContainText('Test Post 3') + }) + + test('should display relationship table with columns from admin.defaultColumns', async () => { + await page.goto(categoriesURL.edit(categoryID)) + const joinField = page.locator('#field-group__relatedPosts.field-type.join') + const thead = joinField.locator('.relationship-table thead') + await expect(thead).toContainText('ID') + await expect(thead).toContainText('Created At') + await expect(thead).toContainText('Title') + const innerText = await thead.innerText() + + // expect the order of columns to be 'ID', 'Created At', 'Title' + // eslint-disable-next-line payload/no-flaky-assertions + expect(innerText.indexOf('ID')).toBeLessThan(innerText.indexOf('Created At')) + // eslint-disable-next-line payload/no-flaky-assertions + expect(innerText.indexOf('Created At')).toBeLessThan(innerText.indexOf('Title')) }) test('should update relationship table when new document is created', async () => { @@ -276,9 +288,7 @@ test.describe('Join Field', () => { await titleField.fill('Test Post 1 Updated') await drawer.locator('button[id="action-save"]').click() await expect(drawer).toBeHidden() - await expect(joinField.locator('tbody tr:first-child td:nth-child(2)')).toHaveText( - 'Test Post 1 Updated', - ) + await expect(joinField.locator('tbody .row-1')).toContainText('Test Post 1 Updated') }) test('should render empty relationship table when creating new document', async () => {