fix(ui): prevents unwanted data overrides when bulk editing (#9842)
### What? It became possible for fields to reset to a defined `defaultValue` when bulk editing from the `edit-many` drawer. ### Why? The form-state of all fields were being considered during a bulk edit - this also meant using their initial states - this meant any fields with default values or nested fields (`arrays`) would be overwritten with their initial states I.e. empty values or default values. ### How? Now - we only send through the form data of the fields specifically being edited in the edit-many drawer and ignore all other fields. Leaving all other fields stay their current values. Fixes #9590 --------- Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
This commit is contained in:
@@ -103,16 +103,64 @@ export const Posts: CollectionConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'arrayOfFields',
|
||||
type: 'array',
|
||||
admin: {
|
||||
initCollapsed: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'optional',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'innerArrayOfFields',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'innerOptional',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'group',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'defaultValueField',
|
||||
type: 'text',
|
||||
defaultValue: 'testing',
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'someBlock',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'textBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'textFieldForBlock',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'defaultValueField',
|
||||
type: 'text',
|
||||
defaultValue: 'testing',
|
||||
},
|
||||
{
|
||||
name: 'relationship',
|
||||
type: 'relationship',
|
||||
|
||||
@@ -516,6 +516,68 @@ describe('admin3', () => {
|
||||
await expect(page.locator('.row-3 .cell-title')).toContainText(updatedPostTitle)
|
||||
})
|
||||
|
||||
test('should not override un-edited values in bulk edit if it has a defaultValue', async () => {
|
||||
await deleteAllPosts()
|
||||
const post1Title = 'Post'
|
||||
const postData = {
|
||||
title: 'Post',
|
||||
arrayOfFields: [
|
||||
{
|
||||
optional: 'some optional array field',
|
||||
innerArrayOfFields: [
|
||||
{
|
||||
innerOptional: 'some inner optional array field',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
group: {
|
||||
defaultValueField: 'not the group default value',
|
||||
title: 'some title',
|
||||
},
|
||||
someBlock: [
|
||||
{
|
||||
textFieldForBlock: 'some text for block text',
|
||||
blockType: 'textBlock',
|
||||
},
|
||||
],
|
||||
defaultValueField: 'not the default value',
|
||||
}
|
||||
const updatedPostTitle = `${post1Title} (Updated)`
|
||||
await Promise.all([createPost(postData)])
|
||||
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 titleOption = page.locator('.field-select .rs__option', {
|
||||
hasText: exactText('Title'),
|
||||
})
|
||||
|
||||
await expect(titleOption).toBeVisible()
|
||||
await titleOption.click()
|
||||
const titleInput = page.locator('#field-title')
|
||||
await expect(titleInput).toBeVisible()
|
||||
await titleInput.fill(updatedPostTitle)
|
||||
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,
|
||||
})
|
||||
|
||||
expect(updatedPost.docs[0].title).toBe(updatedPostTitle)
|
||||
expect(updatedPost.docs[0].arrayOfFields.length).toBe(1)
|
||||
expect(updatedPost.docs[0].arrayOfFields[0].optional).toBe('some optional array field')
|
||||
expect(updatedPost.docs[0].arrayOfFields[0].innerArrayOfFields.length).toBe(1)
|
||||
expect(updatedPost.docs[0].someBlock[0].textFieldForBlock).toBe('some text for block text')
|
||||
expect(updatedPost.docs[0].defaultValueField).toBe('not the default value')
|
||||
})
|
||||
|
||||
test('should bulk update with filters and across pages', async () => {
|
||||
// First, delete all posts created by the seed
|
||||
await deleteAllPosts()
|
||||
|
||||
@@ -138,9 +138,31 @@ export interface Post {
|
||||
[k: string]: unknown;
|
||||
}[]
|
||||
| null;
|
||||
arrayOfFields?:
|
||||
| {
|
||||
optional?: string | null;
|
||||
innerArrayOfFields?:
|
||||
| {
|
||||
innerOptional?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
group?: {
|
||||
defaultValueField?: string | null;
|
||||
title?: string | null;
|
||||
};
|
||||
someBlock?:
|
||||
| {
|
||||
textFieldForBlock?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'textBlock';
|
||||
}[]
|
||||
| null;
|
||||
defaultValueField?: string | null;
|
||||
relationship?: (string | null) | Post;
|
||||
customCell?: string | null;
|
||||
sidebarField?: string | null;
|
||||
@@ -484,11 +506,36 @@ export interface PostsSelect<T extends boolean = true> {
|
||||
description?: T;
|
||||
number?: T;
|
||||
richText?: T;
|
||||
arrayOfFields?:
|
||||
| T
|
||||
| {
|
||||
optional?: T;
|
||||
innerArrayOfFields?:
|
||||
| T
|
||||
| {
|
||||
innerOptional?: T;
|
||||
id?: T;
|
||||
};
|
||||
id?: T;
|
||||
};
|
||||
group?:
|
||||
| T
|
||||
| {
|
||||
defaultValueField?: T;
|
||||
title?: T;
|
||||
};
|
||||
someBlock?:
|
||||
| T
|
||||
| {
|
||||
textBlock?:
|
||||
| T
|
||||
| {
|
||||
textFieldForBlock?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
};
|
||||
defaultValueField?: T;
|
||||
relationship?: T;
|
||||
customCell?: T;
|
||||
sidebarField?: T;
|
||||
|
||||
Reference in New Issue
Block a user