fix: clone embedded Rich Text entries [] - #10765
Conversation
There was a problem hiding this comment.
Pull request overview
Updates the deep-clone app to correctly deep-clone and rewrite embedded Entry references inside Rich Text fields, and adds configurability to the closest-preview app for which field id identifies “previewable” (page/root) entries.
Changes:
- Deep Clone: traverse Rich Text node trees to discover embedded entry links and rewrite them to cloned targets during the update pass.
- Deep Clone: add unit coverage for embedded-entry-block and embedded-entry-inline cloning (while leaving embedded assets unchanged).
- Closest Preview: introduce an installation parameter (
slugFieldId) to configure the “preview field”, and thread it through content-type filtering + root-entry detection with updated tests/mocks.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| apps/deep-clone/src/utils/EntryCloner.ts | Adds Rich Text traversal + embedded entry target rewriting during clone/update passes. |
| apps/deep-clone/test/utils/EntryCloner.spec.ts | Adds unit test ensuring embedded entry links in Rich Text are cloned/rewritten and assets are left unchanged. |
| apps/closest-preview/src/types.ts | Adds installation parameter typing and a default slug field constant. |
| apps/closest-preview/src/utils/livePreviewUtils.ts | Makes “slug field” configurable in filtering and live preview detection; reads from installation parameters. |
| apps/closest-preview/src/locations/ConfigScreen.tsx | Adds UI + persistence for configuring the preview field id. |
| apps/closest-preview/src/components/ContentTypeMultiSelect.tsx | Threads slugFieldId into content type filtering and stabilizes default excluded list. |
| apps/closest-preview/test/mocks/mockSdk.ts | Extends SDK mock to include installation parameters. |
| apps/closest-preview/test/mocks/mockCma.ts | Extends CMA mock content types/entries with a url field used by new tests. |
| apps/closest-preview/test/locations/Sidebar.spec.tsx | Adds coverage that configured preview field id is honored when finding root entries. |
| apps/closest-preview/test/locations/ConfigScreen.spec.tsx | Adds coverage for loading/saving custom preview field id and failure-to-load behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (Array.isArray(fieldValue)) { | ||
| await Promise.all( | ||
| fieldValue.map((f: any) => { | ||
| return this.inspectField(f); | ||
| fieldValue.map((nestedValue) => { | ||
| return this.inspectField(nestedValue); | ||
| }) | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| if (this.isReference(fieldValue)) { | ||
| await this.findReferences(fieldValue.sys.id); | ||
| return; | ||
| } | ||
|
|
||
| if (this.isRichTextNode(fieldValue)) { | ||
| const embeddedEntryTarget = this.getEmbeddedEntryTarget(fieldValue); | ||
| if (embeddedEntryTarget) { | ||
| await this.findReferences(embeddedEntryTarget.sys.id); | ||
| } | ||
|
|
||
| if (Array.isArray(fieldValue.content)) { | ||
| await Promise.all( | ||
| fieldValue.content.map((nestedValue) => { | ||
| return this.inspectField(nestedValue); | ||
| }) | ||
| ); | ||
| } |
There was a problem hiding this comment.
inspectField now traverses all arrays (including rich text content) using Promise.all, which can fan out into a large number of concurrent findReferences calls (and thus CMA entry.get requests) for Rich Text-heavy entries. Consider limiting concurrency (e.g., a queue/p-limit) or switching these deep traversals to a sequential for...of to reduce the risk of rate limiting/timeouts when cloning large documents.
There was a problem hiding this comment.
Fixed. Rich Text traversal now walks arrays and rich-text content sequentially instead of fanning out nested Promise.all calls, and I added regression coverage that fails if embedded-entry fetches overlap.
| export interface AppInstallationParameters { | ||
| slugFieldId?: string; | ||
| } | ||
|
|
||
| export const DEFAULT_SLUG_FIELD_ID = 'slug'; |
There was a problem hiding this comment.
PR description notes updates only in apps/deep-clone, but this PR also changes apps/closest-preview (new installation parameter + filtering logic + tests). Please either update the PR description/title/scope to reflect Closest Preview changes, or split these into a separate PR to keep review and release impact clear.
There was a problem hiding this comment.
This one is valid and I am not treating it as ignorable. The PR currently mixes Deep Clone and Closest Preview changes, so before merge it should either be split into focused PRs or have its title/description updated to reflect the full scope.
Support Deep Clone traversing embedded entry references inside Rich Text so cloned documents point at cloned entries instead of the originals.
b1904fd to
adaf5b3
Compare
Summary
Deep Clone currently skips embedded entry references inside Rich Text fields, which leaves cloned documents pointing at the original embedded entries. This change teaches the cloner to traverse Rich Text nodes so embedded entry blocks and inline embedded entries are discovered, cloned, and rewritten to the cloned targets.
Changes
Notes
This came out of a support-thread investigation where the current behavior looked surprising for customers using Deep Clone on Rich Text-heavy models.
Updated in: