fix: incorrect duplication of data in admin ui (#3907)

This commit is contained in:
Jarrod Flesch
2023-10-27 22:41:33 -04:00
committed by GitHub
parent 237eebdf87
commit 46fc41cbd9
5 changed files with 155 additions and 74 deletions

7
.vscode/launch.json vendored
View File

@@ -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}",

View File

@@ -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
} }

View File

@@ -83,6 +83,11 @@ export default buildConfigWithDefaults({
name: 'description', name: 'description',
type: 'text', type: 'text',
}, },
{
name: 'localizedCheckbox',
type: 'checkbox',
localized: true,
},
], ],
}, },
ArrayCollection, ArrayCollection,

View File

@@ -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()
}) })
}) })
}) })

View File

@@ -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 {}
} }