fix(live-preview): populates rich text relationships

This commit is contained in:
Jacob Fletcher
2023-11-22 11:37:00 -05:00
parent 8a7b41721a
commit 24dacd6712
5 changed files with 278 additions and 42 deletions

View File

@@ -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':

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

View File

@@ -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',

View File

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

View File

@@ -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':