fix(ui): bulk edit subfields (#10035)

Fixes #10019. When bulk editing subfields, such as a field within a
group, changes are not persisted to the database. Not only this, but
nested fields with the same name as another selected field are
controlled by the same input. E.g. typing into one fields changes the
value of both.

The root problem is that field paths are incorrect.

When opening the bulk edit drawer, fields are flattened into options for
the field selector. This is so that fields in a tab, for example, aren't
hidden behind their tab when bulk editing. The problem is that
`RenderFields` is not set up to receive pre-determined field paths. It
attempts to build up its own field paths, but are never correct because
`getFieldPaths` receives the wrong arguments.

The fix is to just render the top-level fields directly, bypassing
`RenderFields` altogether.

Fields with subfields will still recurse through this function, but at
the top-level, fields can be sent directly to `RenderField` (singular)
since their paths have already been already formatted in the flattening
step.
This commit is contained in:
Jacob Fletcher
2025-03-19 17:01:59 -04:00
committed by GitHub
parent a02e4762d0
commit b5fc8c6573
10 changed files with 199 additions and 118 deletions

View File

@@ -423,6 +423,41 @@ test.describe('Bulk Edit', () => {
title: updatedPostTitle,
})
})
test('should bulk edit fields with subfields', async () => {
await deleteAllPosts()
const { id: docID } = await createPost()
await page.goto(postsUrl.list)
await page.locator('input#select-all').check()
await page.locator('.edit-many__toggle').click()
await page.locator('.field-select .rs__control').click()
const bulkEditModal = page.locator('#edit-posts')
const titleOption = bulkEditModal.locator('.field-select .rs__option', {
hasText: exactText('Group > Title'),
})
await titleOption.click()
const titleInput = bulkEditModal.locator('#field-group__title')
await titleInput.fill('New Group Title')
await page.locator('.form-submit button[type="submit"].edit-many__publish').click()
await expect(page.locator('.payload-toast-container .toast-success')).toContainText(
'Updated 1 Post successfully.',
)
const updatedPost = await payload
.find({
collection: 'posts',
limit: 1,
})
?.then((res) => res.docs[0])
expect(updatedPost?.group?.title).toBe('New Group Title')
})
})
async function deleteAllPosts() {