fix: incorrect duplication of data in admin ui (#3907)
This commit is contained in:
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -40,6 +40,13 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "node-terminal"
|
"type": "node-terminal"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "pnpm run dev localization",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"name": "Run Dev Localization",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "node-terminal"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "PAYLOAD_BUNDLER=vite pnpm run dev fields",
|
"command": "PAYLOAD_BUNDLER=vite pnpm run dev fields",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ const Duplicate: React.FC<Props> = ({ id, collection, slug }) => {
|
|||||||
|
|
||||||
const saveDocument = async ({
|
const saveDocument = async ({
|
||||||
id,
|
id,
|
||||||
locale = '',
|
|
||||||
duplicateID = '',
|
duplicateID = '',
|
||||||
|
locale = '',
|
||||||
}): Promise<null | string> => {
|
}): Promise<null | string> => {
|
||||||
const response = await requests.get(`${serverURL}${api}/${slug}/${id}`, {
|
const response = await requests.get(`${serverURL}${api}/${slug}/${id}`, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -56,6 +56,7 @@ const Duplicate: React.FC<Props> = ({ id, collection, slug }) => {
|
|||||||
params: {
|
params: {
|
||||||
depth: 0,
|
depth: 0,
|
||||||
draft: true,
|
draft: true,
|
||||||
|
'fallback-locale': 'none',
|
||||||
locale,
|
locale,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -75,7 +76,7 @@ const Duplicate: React.FC<Props> = ({ id, collection, slug }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await requests[duplicateID ? 'patch' : 'post'](
|
const result = await requests[duplicateID ? 'patch' : 'post'](
|
||||||
`${serverURL}${api}/${slug}/${duplicateID}?locale=${locale}`,
|
`${serverURL}${api}/${slug}/${duplicateID}?locale=${locale}&fallback-locale=none`,
|
||||||
{
|
{
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
headers: {
|
headers: {
|
||||||
@@ -100,7 +101,7 @@ const Duplicate: React.FC<Props> = ({ id, collection, slug }) => {
|
|||||||
await localization.localeCodes.reduce(async (priorLocalePatch, locale) => {
|
await localization.localeCodes.reduce(async (priorLocalePatch, locale) => {
|
||||||
await priorLocalePatch
|
await priorLocalePatch
|
||||||
if (abort) return
|
if (abort) return
|
||||||
duplicateID = await saveDocument({ locale, id, duplicateID })
|
duplicateID = await saveDocument({ id, duplicateID, locale })
|
||||||
if (!duplicateID) {
|
if (!duplicateID) {
|
||||||
abort = true
|
abort = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,11 @@ export default buildConfigWithDefaults({
|
|||||||
name: 'description',
|
name: 'description',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'localizedCheckbox',
|
||||||
|
type: 'checkbox',
|
||||||
|
localized: true,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
ArrayCollection,
|
ArrayCollection,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { expect, test } from '@playwright/test'
|
|||||||
import type { LocalizedPost } from './payload-types'
|
import type { LocalizedPost } from './payload-types'
|
||||||
|
|
||||||
import payload from '../../packages/payload/src'
|
import payload from '../../packages/payload/src'
|
||||||
|
import wait from '../../packages/payload/src/utilities/wait'
|
||||||
import { changeLocale, openDocControls, saveDocAndAssert } from '../helpers'
|
import { changeLocale, openDocControls, saveDocAndAssert } from '../helpers'
|
||||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil'
|
import { AdminUrlUtil } from '../helpers/adminUrlUtil'
|
||||||
import { initPayloadTest } from '../helpers/configHelpers'
|
import { initPayloadTest } from '../helpers/configHelpers'
|
||||||
@@ -131,7 +132,9 @@ describe('Localization', () => {
|
|||||||
collection: localizedPostsSlug,
|
collection: localizedPostsSlug,
|
||||||
data: {
|
data: {
|
||||||
title: englishTitle,
|
title: englishTitle,
|
||||||
|
localizedCheckbox: true,
|
||||||
},
|
},
|
||||||
|
locale: defaultLocale,
|
||||||
})
|
})
|
||||||
|
|
||||||
const id = localizedPost.id.toString()
|
const id = localizedPost.id.toString()
|
||||||
@@ -147,11 +150,46 @@ describe('Localization', () => {
|
|||||||
|
|
||||||
await page.goto(url.edit(id))
|
await page.goto(url.edit(id))
|
||||||
await openDocControls(page)
|
await openDocControls(page)
|
||||||
|
|
||||||
|
// duplicate document
|
||||||
await page.locator('#action-duplicate').click()
|
await page.locator('#action-duplicate').click()
|
||||||
await expect(page.locator('.Toastify')).toContainText('successfully')
|
await expect(page.locator('.Toastify')).toContainText('successfully')
|
||||||
|
|
||||||
|
// check fields
|
||||||
await expect(page.locator('#field-title')).toHaveValue(englishTitle)
|
await expect(page.locator('#field-title')).toHaveValue(englishTitle)
|
||||||
await changeLocale(page, spanishLocale)
|
await changeLocale(page, spanishLocale)
|
||||||
await expect(page.locator('#field-title')).toHaveValue(spanishTitle)
|
await expect(page.locator('#field-title')).toHaveValue(spanishTitle)
|
||||||
|
|
||||||
|
// click checkbox manually
|
||||||
|
await page.locator('#field-localizedCheckbox').click()
|
||||||
|
await expect(page.locator('#field-localizedCheckbox')).not.toBeChecked()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should duplicate localized checkbox correctly', async () => {
|
||||||
|
await page.goto(url.create)
|
||||||
|
await changeLocale(page, defaultLocale)
|
||||||
|
await fillValues({ title: englishTitle, description })
|
||||||
|
await page.locator('#field-localizedCheckbox').click()
|
||||||
|
|
||||||
|
await page.locator('#action-save').click()
|
||||||
|
// wait for navigation to update route
|
||||||
|
await wait(500)
|
||||||
|
|
||||||
|
// ensure spanish is not checked
|
||||||
|
await changeLocale(page, spanishLocale)
|
||||||
|
await expect(page.locator('#field-localizedCheckbox')).not.toBeChecked()
|
||||||
|
|
||||||
|
// duplicate doc
|
||||||
|
await changeLocale(page, defaultLocale)
|
||||||
|
await openDocControls(page)
|
||||||
|
await page.locator('#action-duplicate').click()
|
||||||
|
|
||||||
|
// wait for navigation to update route
|
||||||
|
await wait(500)
|
||||||
|
|
||||||
|
// finally change locale to spanish
|
||||||
|
await changeLocale(page, spanishLocale)
|
||||||
|
await expect(page.locator('#field-localizedCheckbox')).not.toBeChecked()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
/**
|
/**
|
||||||
* This file was automatically generated by Payload.
|
* This file was automatically generated by Payload.
|
||||||
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
||||||
@@ -14,6 +15,8 @@ export interface Config {
|
|||||||
'with-localized-relationship': WithLocalizedRelationship
|
'with-localized-relationship': WithLocalizedRelationship
|
||||||
'relationship-localized': RelationshipLocalized
|
'relationship-localized': RelationshipLocalized
|
||||||
dummy: Dummy
|
dummy: Dummy
|
||||||
|
'payload-preferences': PayloadPreference
|
||||||
|
'payload-migrations': PayloadMigration
|
||||||
}
|
}
|
||||||
globals: {
|
globals: {
|
||||||
'global-array': GlobalArray
|
'global-array': GlobalArray
|
||||||
@@ -21,136 +24,163 @@ export interface Config {
|
|||||||
}
|
}
|
||||||
export interface User {
|
export interface User {
|
||||||
id: string
|
id: string
|
||||||
relation?: string | LocalizedPost
|
relation?: (string | null) | LocalizedPost
|
||||||
email?: string
|
|
||||||
resetPasswordToken?: string
|
|
||||||
resetPasswordExpiration?: string
|
|
||||||
loginAttempts?: number
|
|
||||||
lockUntil?: string
|
|
||||||
createdAt: string
|
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
password?: string
|
createdAt: string
|
||||||
|
email: string
|
||||||
|
resetPasswordToken?: string | null
|
||||||
|
resetPasswordExpiration?: string | null
|
||||||
|
salt?: string | null
|
||||||
|
hash?: string | null
|
||||||
|
loginAttempts?: number | null
|
||||||
|
lockUntil?: string | null
|
||||||
|
password: string | null
|
||||||
}
|
}
|
||||||
export interface LocalizedPost {
|
export interface LocalizedPost {
|
||||||
id: string
|
id: string
|
||||||
title?: string
|
title?: string | null
|
||||||
description?: string
|
description?: string | null
|
||||||
createdAt: string
|
localizedCheckbox?: boolean | null
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
}
|
}
|
||||||
export interface ArrayField {
|
export interface ArrayField {
|
||||||
id: string
|
id: string
|
||||||
items?: {
|
items?:
|
||||||
text: string
|
| {
|
||||||
id?: string
|
text: string
|
||||||
}[]
|
id?: string | null
|
||||||
createdAt: string
|
}[]
|
||||||
|
| null
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
}
|
}
|
||||||
export interface LocalizedRequired {
|
export interface LocalizedRequired {
|
||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
layout: (
|
layout: (
|
||||||
| {
|
| {
|
||||||
text?: string
|
text?: string | null
|
||||||
id?: string
|
id?: string | null
|
||||||
blockName?: string
|
blockName?: string | null
|
||||||
blockType: 'text'
|
blockType: 'text'
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
number?: number
|
number?: number | null
|
||||||
id?: string
|
id?: string | null
|
||||||
blockName?: string
|
blockName?: string | null
|
||||||
blockType: 'number'
|
blockType: 'number'
|
||||||
}
|
}
|
||||||
)[]
|
)[]
|
||||||
createdAt: string
|
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
}
|
}
|
||||||
export interface WithLocalizedRelationship {
|
export interface WithLocalizedRelationship {
|
||||||
id: string
|
id: string
|
||||||
localizedRelationship?: string | LocalizedPost
|
localizedRelationship?: (string | null) | LocalizedPost
|
||||||
localizedRelationHasManyField?: string[] | LocalizedPost[]
|
localizedRelationHasManyField?: (string | LocalizedPost)[] | null
|
||||||
localizedRelationMultiRelationTo?:
|
localizedRelationMultiRelationTo?:
|
||||||
| {
|
| ({
|
||||||
value: string | LocalizedPost
|
|
||||||
relationTo: 'localized-posts'
|
relationTo: 'localized-posts'
|
||||||
}
|
value: string | LocalizedPost
|
||||||
| {
|
} | null)
|
||||||
value: string | Dummy
|
| ({
|
||||||
relationTo: 'dummy'
|
relationTo: 'dummy'
|
||||||
}
|
value: string | Dummy
|
||||||
|
} | null)
|
||||||
localizedRelationMultiRelationToHasMany?:
|
localizedRelationMultiRelationToHasMany?:
|
||||||
| (
|
| (
|
||||||
| {
|
| {
|
||||||
value: string
|
|
||||||
relationTo: 'localized-posts'
|
relationTo: 'localized-posts'
|
||||||
|
value: string | LocalizedPost
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
value: string
|
|
||||||
relationTo: 'dummy'
|
relationTo: 'dummy'
|
||||||
|
value: string | Dummy
|
||||||
}
|
}
|
||||||
)[]
|
)[]
|
||||||
| (
|
| null
|
||||||
| {
|
|
||||||
value: LocalizedPost
|
|
||||||
relationTo: 'localized-posts'
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
value: Dummy
|
|
||||||
relationTo: 'dummy'
|
|
||||||
}
|
|
||||||
)[]
|
|
||||||
createdAt: string
|
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
}
|
}
|
||||||
export interface Dummy {
|
export interface Dummy {
|
||||||
id: string
|
id: string
|
||||||
name?: string
|
name?: string | null
|
||||||
createdAt: string
|
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
}
|
}
|
||||||
export interface RelationshipLocalized {
|
export interface RelationshipLocalized {
|
||||||
id: string
|
id: string
|
||||||
relationship?: string | LocalizedPost
|
relationship?: (string | null) | LocalizedPost
|
||||||
relationshipHasMany?: string[] | LocalizedPost[]
|
relationshipHasMany?: (string | LocalizedPost)[] | null
|
||||||
relationMultiRelationTo?:
|
relationMultiRelationTo?:
|
||||||
| {
|
| ({
|
||||||
value: string | LocalizedPost
|
|
||||||
relationTo: 'localized-posts'
|
relationTo: 'localized-posts'
|
||||||
}
|
value: string | LocalizedPost
|
||||||
| {
|
} | null)
|
||||||
value: string | Dummy
|
| ({
|
||||||
relationTo: 'dummy'
|
relationTo: 'dummy'
|
||||||
}
|
value: string | Dummy
|
||||||
|
} | null)
|
||||||
relationMultiRelationToHasMany?:
|
relationMultiRelationToHasMany?:
|
||||||
| (
|
| (
|
||||||
| {
|
| {
|
||||||
value: string
|
|
||||||
relationTo: 'localized-posts'
|
relationTo: 'localized-posts'
|
||||||
|
value: string | LocalizedPost
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
value: string
|
|
||||||
relationTo: 'dummy'
|
relationTo: 'dummy'
|
||||||
|
value: string | Dummy
|
||||||
}
|
}
|
||||||
)[]
|
)[]
|
||||||
| (
|
| null
|
||||||
| {
|
arrayField?:
|
||||||
value: LocalizedPost
|
| {
|
||||||
relationTo: 'localized-posts'
|
nestedRelation?: (string | null) | LocalizedPost
|
||||||
}
|
id?: string | null
|
||||||
| {
|
}[]
|
||||||
value: Dummy
|
| null
|
||||||
relationTo: 'dummy'
|
|
||||||
}
|
|
||||||
)[]
|
|
||||||
createdAt: string
|
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
|
}
|
||||||
|
export interface PayloadPreference {
|
||||||
|
id: string
|
||||||
|
user: {
|
||||||
|
relationTo: 'users'
|
||||||
|
value: string | User
|
||||||
|
}
|
||||||
|
key?: string | null
|
||||||
|
value?:
|
||||||
|
| {
|
||||||
|
[k: string]: unknown
|
||||||
|
}
|
||||||
|
| unknown[]
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| null
|
||||||
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
|
}
|
||||||
|
export interface PayloadMigration {
|
||||||
|
id: string
|
||||||
|
name?: string | null
|
||||||
|
batch?: number | null
|
||||||
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
}
|
}
|
||||||
export interface GlobalArray {
|
export interface GlobalArray {
|
||||||
id: string
|
id: string
|
||||||
array?: {
|
array?:
|
||||||
text?: string
|
| {
|
||||||
id?: string
|
text?: string | null
|
||||||
}[]
|
id?: string | null
|
||||||
|
}[]
|
||||||
|
| null
|
||||||
|
updatedAt?: string | null
|
||||||
|
createdAt?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'payload' {
|
||||||
|
export interface GeneratedTypes extends Config {}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user