diff --git a/next-env.d.ts b/next-env.d.ts
index 1b3be0840f..830fb594ca 100644
--- a/next-env.d.ts
+++ b/next-env.d.ts
@@ -1,5 +1,6 @@
///
///
+///
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/packages/plugin-nested-docs/src/utilities/formatBreadcrumb.ts b/packages/plugin-nested-docs/src/utilities/formatBreadcrumb.ts
index 13702b38c4..de98d49409 100644
--- a/packages/plugin-nested-docs/src/utilities/formatBreadcrumb.ts
+++ b/packages/plugin-nested-docs/src/utilities/formatBreadcrumb.ts
@@ -3,12 +3,19 @@ import type { SanitizedCollectionConfig } from 'payload'
import type { Breadcrumb, GenerateLabel, GenerateURL } from '../types.js'
type Args = {
+ /**
+ * Existing breadcrumb, if any, to base the new breadcrumb on.
+ * This ensures that row IDs are maintained across updates, etc.
+ */
+ breadcrumb?: Breadcrumb
collection: SanitizedCollectionConfig
docs: Record[]
generateLabel?: GenerateLabel
generateURL?: GenerateURL
}
+
export const formatBreadcrumb = ({
+ breadcrumb,
collection,
docs,
generateLabel,
@@ -32,6 +39,7 @@ export const formatBreadcrumb = ({
}
return {
+ ...(breadcrumb || {}),
doc: lastDoc.id as string,
label,
url,
diff --git a/packages/plugin-nested-docs/src/utilities/populateBreadcrumbs.ts b/packages/plugin-nested-docs/src/utilities/populateBreadcrumbs.ts
index 86b1431269..782957085d 100644
--- a/packages/plugin-nested-docs/src/utilities/populateBreadcrumbs.ts
+++ b/packages/plugin-nested-docs/src/utilities/populateBreadcrumbs.ts
@@ -26,10 +26,13 @@ export const populateBreadcrumbs = async ({
req,
}: Args): Promise => {
const newData = data
+
const currentDocument = {
...originalDoc,
...data,
+ id: originalDoc?.id ?? data?.id,
}
+
const allParentDocuments: Document[] = await getAllParentDocuments(
req,
{
@@ -41,14 +44,11 @@ export const populateBreadcrumbs = async ({
currentDocument,
)
- if (originalDoc?.id) {
- currentDocument.id = originalDoc?.id
- }
-
allParentDocuments.push(currentDocument)
const breadcrumbs = allParentDocuments.map((_, i) =>
formatBreadcrumb({
+ breadcrumb: currentDocument[breadcrumbsFieldName]?.[i],
collection,
docs: allParentDocuments.slice(0, i + 1),
generateLabel,
diff --git a/test/form-state/collections/Posts/index.ts b/test/form-state/collections/Posts/index.ts
index 07a5e8231d..a28b5f8838 100644
--- a/test/form-state/collections/Posts/index.ts
+++ b/test/form-state/collections/Posts/index.ts
@@ -76,24 +76,10 @@ export const PostsCollection: CollectionConfig = {
name: 'array',
type: 'array',
admin: {
- description: 'If there is no value, a default row will be added by a beforeChange hook',
components: {
RowLabel: './collections/Posts/ArrayRowLabel.js#ArrayRowLabel',
},
},
- hooks: {
- beforeChange: [
- ({ value }) =>
- !value?.length
- ? [
- {
- defaultTextField: 'This is a computed value.',
- customTextField: 'This is a computed value.',
- },
- ]
- : value,
- ],
- },
fields: [
{
name: 'customTextField',
@@ -111,5 +97,31 @@ export const PostsCollection: CollectionConfig = {
},
],
},
+ {
+ name: 'computedArray',
+ type: 'array',
+ admin: {
+ description:
+ 'If there is no value, a default row will be added by a beforeChange hook. Otherwise, modifies the rows on save.',
+ },
+ hooks: {
+ beforeChange: [
+ ({ value }) =>
+ !value?.length
+ ? [
+ {
+ text: 'This is a computed value.',
+ },
+ ]
+ : value,
+ ],
+ },
+ fields: [
+ {
+ name: 'text',
+ type: 'text',
+ },
+ ],
+ },
],
}
diff --git a/test/form-state/e2e.spec.ts b/test/form-state/e2e.spec.ts
index cb0ec2ca0f..27fb396099 100644
--- a/test/form-state/e2e.spec.ts
+++ b/test/form-state/e2e.spec.ts
@@ -312,22 +312,18 @@ test.describe('Form State', () => {
// Now test array rows, as their merge logic is different
- await page.locator('#field-array #array-row-0').isVisible()
+ await page.locator('#field-computedArray #computedArray-row-0').isVisible()
- await removeArrayRow(page, { fieldName: 'array' })
+ await removeArrayRow(page, { fieldName: 'computedArray' })
- await page.locator('#field-array .array-row-0').isHidden()
+ await page.locator('#field-computedArray #computedArray-row-0').isHidden()
await saveDocAndAssert(page)
- await expect(page.locator('#field-array #array-row-0')).toBeVisible()
+ await expect(page.locator('#field-computedArray #computedArray-row-0')).toBeVisible()
await expect(
- page.locator('#field-array #array-row-0 #field-array__0__customTextField'),
- ).toHaveValue('This is a computed value.')
-
- await expect(
- page.locator('#field-array #array-row-0 #field-array__0__defaultTextField'),
+ page.locator('#field-computedArray #computedArray-row-0 #field-computedArray__0__text'),
).toHaveValue('This is a computed value.')
})
diff --git a/test/form-state/payload-types.ts b/test/form-state/payload-types.ts
index 165bedbee0..179343a2bb 100644
--- a/test/form-state/payload-types.ts
+++ b/test/form-state/payload-types.ts
@@ -144,9 +144,6 @@ export interface Post {
}
)[]
| null;
- /**
- * If there is no value, a default row will be added by a beforeChange hook
- */
array?:
| {
customTextField?: string | null;
@@ -154,6 +151,15 @@ export interface Post {
id?: string | null;
}[]
| null;
+ /**
+ * If there is no value, a default row will be added by a beforeChange hook. Otherwise, modifies the rows on save.
+ */
+ computedArray?:
+ | {
+ text?: string | null;
+ id?: string | null;
+ }[]
+ | null;
updatedAt: string;
createdAt: string;
}
@@ -288,6 +294,12 @@ export interface PostsSelect {
defaultTextField?: T;
id?: T;
};
+ computedArray?:
+ | T
+ | {
+ text?: T;
+ id?: T;
+ };
updatedAt?: T;
createdAt?: T;
}
diff --git a/test/plugin-nested-docs/payload-types.ts b/test/plugin-nested-docs/payload-types.ts
index de28d82c89..3079834d06 100644
--- a/test/plugin-nested-docs/payload-types.ts
+++ b/test/plugin-nested-docs/payload-types.ts
@@ -178,6 +178,13 @@ export interface User {
hash?: string | null;
loginAttempts?: number | null;
lockUntil?: string | null;
+ sessions?:
+ | {
+ id: string;
+ createdAt?: string | null;
+ expiresAt: string;
+ }[]
+ | null;
password?: string | null;
}
/**
@@ -295,6 +302,13 @@ export interface UsersSelect {
hash?: T;
loginAttempts?: T;
lockUntil?: T;
+ sessions?:
+ | T
+ | {
+ id?: T;
+ createdAt?: T;
+ expiresAt?: T;
+ };
}
/**
* This interface was referenced by `Config`'s JSON-Schema