fix(live-preview): populates rich text relationships
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type { fieldSchemaToJSON } from 'payload/utilities'
|
||||
|
||||
import { promise } from './promise'
|
||||
import { traverseRichText } from './traverseRichText'
|
||||
|
||||
export const traverseFields = <T>(args: {
|
||||
apiRoute?: string
|
||||
@@ -26,6 +27,18 @@ export const traverseFields = <T>(args: {
|
||||
const fieldName = fieldSchema.name
|
||||
|
||||
switch (fieldSchema.type) {
|
||||
case 'richText':
|
||||
result[fieldName] = traverseRichText({
|
||||
apiRoute,
|
||||
depth,
|
||||
incomingData: incomingData[fieldName],
|
||||
populationPromises,
|
||||
result: result[fieldName],
|
||||
serverURL,
|
||||
})
|
||||
|
||||
break
|
||||
|
||||
case 'array':
|
||||
if (Array.isArray(incomingData[fieldName])) {
|
||||
result[fieldName] = incomingData[fieldName].map((incomingRow, i) => {
|
||||
@@ -50,6 +63,7 @@ export const traverseFields = <T>(args: {
|
||||
return result[fieldName][i]
|
||||
})
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case 'blocks':
|
||||
|
||||
63
packages/live-preview/src/traverseRichText.ts
Normal file
63
packages/live-preview/src/traverseRichText.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { promise } from './promise'
|
||||
|
||||
export const traverseRichText = ({
|
||||
apiRoute,
|
||||
depth,
|
||||
incomingData,
|
||||
populationPromises,
|
||||
result,
|
||||
serverURL,
|
||||
}: {
|
||||
apiRoute: string
|
||||
depth: number
|
||||
incomingData: any
|
||||
populationPromises: Promise<void>[]
|
||||
result: any
|
||||
serverURL: string
|
||||
}): any => {
|
||||
if (Array.isArray(incomingData)) {
|
||||
result = incomingData.map((incomingRow) =>
|
||||
traverseRichText({
|
||||
apiRoute,
|
||||
depth,
|
||||
incomingData: incomingRow,
|
||||
populationPromises,
|
||||
result,
|
||||
serverURL,
|
||||
}),
|
||||
)
|
||||
} else if (typeof incomingData === 'object' && incomingData !== null) {
|
||||
result = incomingData
|
||||
|
||||
if ('relationTo' in incomingData && 'value' in incomingData && incomingData.value) {
|
||||
populationPromises.push(
|
||||
promise({
|
||||
id: typeof incomingData.value === 'object' ? incomingData.value.id : incomingData.value,
|
||||
accessor: 'value',
|
||||
apiRoute,
|
||||
collection: String(incomingData.relationTo),
|
||||
depth,
|
||||
ref: result,
|
||||
serverURL,
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
result = {}
|
||||
|
||||
Object.keys(incomingData).forEach((key) => {
|
||||
result[key] = traverseRichText({
|
||||
apiRoute,
|
||||
depth,
|
||||
incomingData: incomingData[key],
|
||||
populationPromises,
|
||||
result,
|
||||
serverURL,
|
||||
})
|
||||
})
|
||||
}
|
||||
} else {
|
||||
result = incomingData
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -384,6 +384,127 @@ describe('Collections - Live Preview', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('— relationships - populates within rich text', async () => {
|
||||
const initialData: Partial<Page> = {
|
||||
title: 'Test Page',
|
||||
}
|
||||
|
||||
// Add a relationship
|
||||
const merge1 = await mergeData({
|
||||
depth: 1,
|
||||
fieldSchema: schemaJSON,
|
||||
incomingData: {
|
||||
...initialData,
|
||||
relationshipInRichText: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
text: 'Paragraph 1',
|
||||
},
|
||||
{
|
||||
type: 'reference',
|
||||
reference: {
|
||||
relationTo: 'posts',
|
||||
value: testPost.id,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
initialData,
|
||||
serverURL,
|
||||
returnNumberOfRequests: true,
|
||||
})
|
||||
|
||||
expect(merge1._numberOfRequests).toEqual(1)
|
||||
expect(merge1.relationshipInRichText).toHaveLength(2)
|
||||
expect(merge1.relationshipInRichText[1].reference.value).toMatchObject(testPost)
|
||||
|
||||
// Remove the relationship
|
||||
const merge2 = await mergeData({
|
||||
depth: 1,
|
||||
fieldSchema: schemaJSON,
|
||||
incomingData: {
|
||||
...merge1,
|
||||
relationshipInRichText: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
text: 'Paragraph 1',
|
||||
},
|
||||
],
|
||||
},
|
||||
initialData,
|
||||
serverURL,
|
||||
returnNumberOfRequests: true,
|
||||
})
|
||||
|
||||
expect(merge2._numberOfRequests).toEqual(0)
|
||||
expect(merge2.relationshipInRichText).toHaveLength(1)
|
||||
expect(merge2.relationshipInRichText[0].type).toEqual('paragraph')
|
||||
})
|
||||
|
||||
it('— rich text - merges rich text', async () => {
|
||||
const initialData: Partial<Page> = {
|
||||
title: 'Test Page',
|
||||
}
|
||||
|
||||
// Add a relationship
|
||||
const merge1 = await mergeData({
|
||||
depth: 1,
|
||||
fieldSchema: schemaJSON,
|
||||
incomingData: {
|
||||
...initialData,
|
||||
hero: {
|
||||
type: 'lowImpact',
|
||||
richText: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text: 'Paragraph 1',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
initialData,
|
||||
serverURL,
|
||||
returnNumberOfRequests: true,
|
||||
})
|
||||
|
||||
expect(merge1._numberOfRequests).toEqual(0)
|
||||
expect(merge1.hero.richText).toHaveLength(1)
|
||||
expect(merge1.hero.richText[0].children[0].text).toEqual('Paragraph 1')
|
||||
|
||||
// Update the rich text
|
||||
const merge2 = await mergeData({
|
||||
depth: 1,
|
||||
fieldSchema: schemaJSON,
|
||||
incomingData: {
|
||||
...merge1,
|
||||
hero: {
|
||||
type: 'lowImpact',
|
||||
richText: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text: 'Paragraph 1 (Updated)',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
initialData,
|
||||
serverURL,
|
||||
returnNumberOfRequests: true,
|
||||
})
|
||||
|
||||
expect(merge2._numberOfRequests).toEqual(0)
|
||||
expect(merge2.hero.richText).toHaveLength(1)
|
||||
expect(merge2.hero.richText[0].children[0].text).toEqual('Paragraph 1 (Updated)')
|
||||
})
|
||||
|
||||
it('— relationships - populates within blocks', async () => {
|
||||
const block1 = (shallow?: boolean): Extract<Page['layout'][0], { blockType: 'cta' }> => ({
|
||||
blockType: 'cta',
|
||||
|
||||
@@ -21,88 +21,124 @@ export const RelationshipsBlock: React.FC<RelationshipsBlockProps> = (props) =>
|
||||
<p>
|
||||
This block is for testing purposes only. It renders every possible type of relationship.
|
||||
</p>
|
||||
<p>Upload:</p>
|
||||
{data?.relationshipAsUpload && (
|
||||
<p>
|
||||
<b>Rich Text:</b>
|
||||
</p>
|
||||
{data?.relationshipInRichText && <RichText content={data.relationshipInRichText} />}
|
||||
<p>
|
||||
<b>Upload:</b>
|
||||
</p>
|
||||
{data?.relationshipAsUpload ? (
|
||||
<div>
|
||||
{typeof data?.relationshipAsUpload === 'string'
|
||||
? data?.relationshipAsUpload
|
||||
: data?.relationshipAsUpload.filename}
|
||||
</div>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>Rich Text:</p>
|
||||
{data?.relationshipInRichText && <RichText content={data.relationshipInRichText} />}
|
||||
<p>Monomorphic Has One:</p>
|
||||
{data?.relationshipMonoHasOne && (
|
||||
<p>
|
||||
<b>Monomorphic Has One:</b>
|
||||
</p>
|
||||
{data?.relationshipMonoHasOne ? (
|
||||
<div>
|
||||
{typeof data?.relationshipMonoHasOne === 'string'
|
||||
? data?.relationshipMonoHasOne
|
||||
: data?.relationshipMonoHasOne.title}
|
||||
</div>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>Monomorphic Has Many:</p>
|
||||
{data?.relationshipMonoHasMany?.map(
|
||||
(item, index) =>
|
||||
item && <div key={index}>{typeof item === 'string' ? item : item.title}</div>,
|
||||
<p>
|
||||
<b>Monomorphic Has Many:</b>
|
||||
</p>
|
||||
{data?.relationshipMonoHasMany?.map((item, index) =>
|
||||
item ? <div key={index}>{typeof item === 'string' ? item : item.title}</div> : 'null',
|
||||
)}
|
||||
<p>Polymorphic Has One:</p>
|
||||
{data?.relationshipPolyHasOne && (
|
||||
<p>
|
||||
<b>Polymorphic Has One:</b>
|
||||
</p>
|
||||
{data?.relationshipPolyHasOne ? (
|
||||
<div>
|
||||
{typeof data?.relationshipPolyHasOne.value === 'string'
|
||||
? data?.relationshipPolyHasOne.value
|
||||
: data?.relationshipPolyHasOne.value.title}
|
||||
</div>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>Polymorphic Has Many:</p>
|
||||
{data?.relationshipPolyHasMany?.map(
|
||||
(item, index) =>
|
||||
item.value && (
|
||||
<div key={index}>
|
||||
{typeof item.value === 'string' ? item.value : item.value.title}
|
||||
</div>
|
||||
),
|
||||
<p>
|
||||
<b>Polymorphic Has Many:</b>
|
||||
</p>
|
||||
{data?.relationshipPolyHasMany?.map((item, index) =>
|
||||
item.value ? (
|
||||
<div key={index}>{typeof item.value === 'string' ? item.value : item.value.title}</div>
|
||||
) : (
|
||||
'null'
|
||||
),
|
||||
)}
|
||||
<p>Array of Relationships:</p>
|
||||
<p>
|
||||
<b>Array of Relationships:</b>
|
||||
</p>
|
||||
{data?.arrayOfRelationships?.map((item, index) => (
|
||||
<div className={classes.array} key={index}>
|
||||
<p>Upload:</p>
|
||||
{item?.uploadInArray && (
|
||||
<p>
|
||||
<b>Rich Text:</b>
|
||||
</p>
|
||||
{item?.richTextInArray && <RichText content={item.richTextInArray} />}
|
||||
<p>
|
||||
<b>Upload:</b>
|
||||
</p>
|
||||
{item?.uploadInArray ? (
|
||||
<div>
|
||||
{typeof item?.uploadInArray === 'string'
|
||||
? item?.uploadInArray
|
||||
: item?.uploadInArray.filename}
|
||||
</div>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>Rich Text:</p>
|
||||
{item?.richTextInArray && <RichText content={item.richTextInArray} />}
|
||||
<p>Monomorphic Has One:</p>
|
||||
{item?.relationshipInArrayMonoHasOne && (
|
||||
<p>
|
||||
<b>Monomorphic Has One:</b>
|
||||
</p>
|
||||
{item?.relationshipInArrayMonoHasOne ? (
|
||||
<div>
|
||||
{typeof item?.relationshipInArrayMonoHasOne === 'string'
|
||||
? item?.relationshipInArrayMonoHasOne
|
||||
: item?.relationshipInArrayMonoHasOne.title}
|
||||
</div>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>Monomorphic Has Many:</p>
|
||||
{item?.relationshipInArrayMonoHasMany?.map(
|
||||
(rel, relIndex) =>
|
||||
rel && <div key={relIndex}>{typeof rel === 'string' ? rel : rel.title}</div>,
|
||||
<p>
|
||||
<b>Monomorphic Has Many:</b>
|
||||
</p>
|
||||
{item?.relationshipInArrayMonoHasMany?.map((rel, relIndex) =>
|
||||
rel ? <div key={relIndex}>{typeof rel === 'string' ? rel : rel.title}</div> : 'null',
|
||||
)}
|
||||
<p>Polymorphic Has One:</p>
|
||||
{item?.relationshipInArrayPolyHasOne && (
|
||||
<p>
|
||||
<b>Polymorphic Has One:</b>
|
||||
</p>
|
||||
{item?.relationshipInArrayPolyHasOne ? (
|
||||
<div>
|
||||
{typeof item?.relationshipInArrayPolyHasOne.value === 'string'
|
||||
? item?.relationshipInArrayPolyHasOne.value
|
||||
: item?.relationshipInArrayPolyHasOne.value.title}
|
||||
</div>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>Polymorphic Has Many:</p>
|
||||
{item?.relationshipInArrayPolyHasMany?.map(
|
||||
(rel, relIndex) =>
|
||||
rel.value && (
|
||||
<div key={relIndex}>
|
||||
{typeof rel.value === 'string' ? rel.value : rel.value.title}
|
||||
</div>
|
||||
),
|
||||
<p>
|
||||
<b>Polymorphic Has Many:</b>
|
||||
</p>
|
||||
{item?.relationshipInArrayPolyHasMany?.map((rel, relIndex) =>
|
||||
rel.value ? (
|
||||
<div key={relIndex}>
|
||||
{typeof rel.value === 'string' ? rel.value : rel.value.title}
|
||||
</div>
|
||||
) : (
|
||||
'null'
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -78,7 +78,9 @@ const serialize = (children?: Children): React.ReactNode[] =>
|
||||
case 'relationship':
|
||||
return (
|
||||
<span key={i}>
|
||||
{node.value && typeof node.value === 'object' ? node.value.title : node.value}
|
||||
{node.value && typeof node.value === 'object'
|
||||
? node.value.title || node.value.id
|
||||
: node.value}
|
||||
</span>
|
||||
)
|
||||
case 'link':
|
||||
|
||||
Reference in New Issue
Block a user