fix(live-preview): populates rte uploads and relationships (#4379)

This commit is contained in:
Jacob Fletcher
2023-12-05 00:53:11 -05:00
committed by GitHub
parent 290e9d8238
commit 4090aebb0e
11 changed files with 677 additions and 77 deletions

View File

@@ -53,13 +53,20 @@ export const traverseRichText = ({
? Array.isArray(incomingData[key]) ? Array.isArray(incomingData[key])
? [] ? []
: {} : {}
: incomingData[key] : undefined
} }
const isRelationship = key === 'value' && 'relationTo' in incomingData const isRelationship = key === 'value' && 'relationTo' in incomingData
if (isRelationship) { if (isRelationship) {
const needsPopulation = !result.value || typeof result.value !== 'object' // or if there are no keys besides id
const needsPopulation =
!result.value ||
typeof result.value !== 'object' ||
(typeof result.value === 'object' &&
Object.keys(result.value).length === 1 &&
'id' in result.value)
const hasChanged = const hasChanged =
result && result &&
typeof result === 'object' && typeof result === 'object' &&
@@ -71,7 +78,10 @@ export const traverseRichText = ({
} }
populationsByCollection[incomingData.relationTo].push({ populationsByCollection[incomingData.relationTo].push({
id: incomingData[key], id:
incomingData[key] && typeof incomingData[key] === 'object'
? incomingData[key].id
: incomingData[key],
accessor: 'value', accessor: 'value',
ref: result, ref: result,
}) })

View File

@@ -1,5 +1,6 @@
import type { CollectionConfig } from '../../../packages/payload/src/collections/config/types' import type { CollectionConfig } from '../../../packages/payload/src/collections/config/types'
import { lexicalEditor } from '../../../packages/richtext-lexical/src'
import { Archive } from '../blocks/ArchiveBlock' import { Archive } from '../blocks/ArchiveBlock'
import { CallToAction } from '../blocks/CallToAction' import { CallToAction } from '../blocks/CallToAction'
import { Content } from '../blocks/Content' import { Content } from '../blocks/Content'
@@ -62,8 +63,15 @@ export const Pages: CollectionConfig = {
label: 'Test', label: 'Test',
fields: [ fields: [
{ {
name: 'relationshipInRichText', label: 'Rich Text — Slate',
type: 'richText', type: 'richText',
name: 'richTextSlate',
},
{
label: 'Rich Text — Lexical',
type: 'richText',
name: 'richTextLexical',
editor: lexicalEditor({}),
}, },
{ {
name: 'relationshipAsUpload', name: 'relationshipAsUpload',

View File

@@ -154,10 +154,7 @@ describe('Collections - Live Preview', () => {
expect(mergedData._numberOfRequests).toEqual(0) expect(mergedData._numberOfRequests).toEqual(0)
}) })
// TODO: this test is not working in Postgres it('— uploads - adds and removes media', async () => {
// This is because of how relationships are handled in `mergeData`
// This test passes in MongoDB, though
it.skip('— uploads - adds and removes media', async () => {
const initialData: Partial<Page> = { const initialData: Partial<Page> = {
title: 'Test Page', title: 'Test Page',
} }
@@ -198,6 +195,166 @@ describe('Collections - Live Preview', () => {
expect(mergedDataWithoutUpload.hero.media).toBeFalsy() expect(mergedDataWithoutUpload.hero.media).toBeFalsy()
}) })
it('— uploads - populates within Slate rich text editor', async () => {
const initialData: Partial<Page> = {
title: 'Test Page',
}
// Add upload
const merge1 = await mergeData({
depth: 1,
fieldSchema: schemaJSON,
incomingData: {
...initialData,
richTextSlate: [
{
type: 'upload',
relationTo: 'media',
value: media.id,
},
],
},
initialData,
serverURL,
returnNumberOfRequests: true,
})
expect(merge1.richTextSlate).toHaveLength(1)
expect(merge1.richTextSlate[0].value).toMatchObject(media)
expect(merge1._numberOfRequests).toEqual(1)
// Remove upload
const merge2 = await mergeData({
depth: 1,
fieldSchema: schemaJSON,
incomingData: {
...merge1,
richTextSlate: [
{
type: 'paragraph',
children: [
{
text: 'Hello, world!',
},
],
},
],
},
initialData,
serverURL,
returnNumberOfRequests: true,
})
expect(merge2.richTextSlate).toHaveLength(1)
expect(merge2.richTextSlate[0].value).toBeFalsy()
expect(merge2.richTextSlate[0].type).toEqual('paragraph')
expect(merge2._numberOfRequests).toEqual(0)
})
it('— uploads - populates within Lexical rich text editor', async () => {
const initialData: Partial<Page> = {
title: 'Test Page',
}
// Add upload
const merge1 = await mergeData({
depth: 1,
fieldSchema: schemaJSON,
incomingData: {
...initialData,
richTextLexical: {
root: {
type: 'root',
format: '',
indent: 0,
version: 1,
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'Hello, world!',
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1,
},
{
format: '',
type: 'upload',
relationTo: 'media',
version: 1,
value: media.id,
},
],
direction: 'ltr',
},
},
},
initialData,
serverURL,
returnNumberOfRequests: true,
})
expect(merge1.richTextLexical.root.children).toHaveLength(2)
expect(merge1.richTextLexical.root.children[1].value).toMatchObject(media)
expect(merge1._numberOfRequests).toEqual(1)
// Remove upload
const merge2 = await mergeData({
depth: 1,
fieldSchema: schemaJSON,
incomingData: {
...merge1,
richTextLexical: {
root: {
type: 'root',
format: '',
indent: 0,
version: 1,
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'Hello, world!',
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1,
},
],
direction: 'ltr',
},
},
},
initialData,
serverURL,
returnNumberOfRequests: true,
})
expect(merge2.richTextLexical.root.children).toHaveLength(1)
expect(merge2.richTextLexical.root.children[0].value).toBeFalsy()
expect(merge2.richTextLexical.root.children[0].type).toEqual('paragraph')
})
it('— relationships - populates monomorphic has one relationships', async () => { it('— relationships - populates monomorphic has one relationships', async () => {
const initialData: Partial<Page> = { const initialData: Partial<Page> = {
title: 'Test Page', title: 'Test Page',
@@ -422,7 +579,7 @@ describe('Collections - Live Preview', () => {
}, },
], ],
}, },
initialData, initialData: merge1,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
}) })
@@ -451,7 +608,130 @@ describe('Collections - Live Preview', () => {
]) ])
}) })
it('— relationships - populates within rich text', async () => { it('— relationships - populates within Slate rich text editor', async () => {
const initialData: Partial<Page> = {
title: 'Test Page',
}
// Add a relationship and an upload
const merge1 = await mergeData({
depth: 1,
fieldSchema: schemaJSON,
incomingData: {
...initialData,
richTextSlate: [
{
children: [
{
text: ' ',
},
],
relationTo: 'posts',
type: 'relationship',
value: {
id: testPost.id,
},
},
{
type: 'paragraph',
children: [
{
text: '',
},
],
},
{
children: [
{
text: '',
},
],
relationTo: 'media',
type: 'upload',
value: {
id: media.id,
},
},
],
},
initialData,
serverURL,
returnNumberOfRequests: true,
})
expect(merge1._numberOfRequests).toEqual(2)
expect(merge1.richTextSlate).toHaveLength(3)
expect(merge1.richTextSlate[0].type).toEqual('relationship')
expect(merge1.richTextSlate[0].value).toMatchObject(testPost)
expect(merge1.richTextSlate[1].type).toEqual('paragraph')
expect(merge1.richTextSlate[2].type).toEqual('upload')
expect(merge1.richTextSlate[2].value).toMatchObject(media)
// Add a new node between the relationship and the upload
const merge2 = await mergeData({
depth: 1,
fieldSchema: schemaJSON,
incomingData: {
...merge1,
richTextSlate: [
{
children: [
{
text: ' ',
},
],
relationTo: 'posts',
type: 'relationship',
value: {
id: testPost.id,
},
},
{
type: 'paragraph',
children: [
{
text: '',
},
],
},
{
type: 'paragraph',
children: [
{
text: '',
},
],
},
{
children: [
{
text: '',
},
],
relationTo: 'media',
type: 'upload',
value: {
id: media.id,
},
},
],
},
initialData: merge1,
serverURL,
returnNumberOfRequests: true,
})
expect(merge2._numberOfRequests).toEqual(1)
expect(merge2.richTextSlate).toHaveLength(4)
expect(merge2.richTextSlate[0].type).toEqual('relationship')
expect(merge2.richTextSlate[0].value).toMatchObject(testPost)
expect(merge2.richTextSlate[1].type).toEqual('paragraph')
expect(merge2.richTextSlate[2].type).toEqual('paragraph')
expect(merge2.richTextSlate[3].type).toEqual('upload')
expect(merge2.richTextSlate[3].value).toMatchObject(media)
})
it('— relationships - populates within Lexical rich text editor', async () => {
const initialData: Partial<Page> = { const initialData: Partial<Page> = {
title: 'Test Page', title: 'Test Page',
} }
@@ -462,56 +742,130 @@ describe('Collections - Live Preview', () => {
fieldSchema: schemaJSON, fieldSchema: schemaJSON,
incomingData: { incomingData: {
...initialData, ...initialData,
relationshipInRichText: [ richTextLexical: {
{ root: {
type: 'paragraph', type: 'root',
text: 'Paragraph 1', format: '',
indent: 0,
version: 1,
children: [
{
format: '',
type: 'relationship',
version: 1,
relationTo: 'posts',
value: {
id: testPost.id,
},
},
{
children: [],
direction: null,
format: '',
indent: 0,
type: 'paragraph',
version: 1,
},
{
format: '',
type: 'upload',
version: 1,
fields: null,
relationTo: 'media',
value: {
id: media.id,
},
},
],
direction: null,
}, },
{ },
type: 'reference',
reference: {
relationTo: 'posts',
value: testPost.id,
},
},
],
}, },
initialData, initialData,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
}) })
expect(merge1._numberOfRequests).toEqual(1) expect(merge1._numberOfRequests).toEqual(2)
expect(merge1.relationshipInRichText).toHaveLength(2) expect(merge1.richTextLexical.root.children).toHaveLength(3)
expect(merge1.relationshipInRichText[1].reference.value).toMatchObject(testPost) expect(merge1.richTextLexical.root.children[0].type).toEqual('relationship')
expect(merge1.richTextLexical.root.children[0].value).toMatchObject(testPost)
expect(merge1.richTextLexical.root.children[1].type).toEqual('paragraph')
expect(merge1.richTextLexical.root.children[2].type).toEqual('upload')
expect(merge1.richTextLexical.root.children[2].value).toMatchObject(media)
// Remove the relationship // Add a node before the populated one
const merge2 = await mergeData({ const merge2 = await mergeData({
depth: 1, depth: 1,
fieldSchema: schemaJSON, fieldSchema: schemaJSON,
incomingData: { incomingData: {
...merge1, ...merge1,
relationshipInRichText: [ richTextLexical: {
{ root: {
type: 'paragraph', type: 'root',
text: 'Paragraph 1', format: '',
indent: 0,
version: 1,
children: [
{
format: '',
type: 'relationship',
version: 1,
relationTo: 'posts',
value: {
id: testPost.id,
},
},
{
children: [],
direction: null,
format: '',
indent: 0,
type: 'paragraph',
version: 1,
},
{
children: [],
direction: null,
format: '',
indent: 0,
type: 'paragraph',
version: 1,
},
{
format: '',
type: 'upload',
version: 1,
fields: null,
relationTo: 'media',
value: {
id: media.id,
},
},
],
direction: null,
}, },
], },
}, },
initialData, initialData: merge1,
serverURL, serverURL,
returnNumberOfRequests: true, returnNumberOfRequests: true,
}) })
expect(merge2._numberOfRequests).toEqual(0) expect(merge2._numberOfRequests).toEqual(1)
expect(merge2.relationshipInRichText).toHaveLength(1) expect(merge2.richTextLexical.root.children).toHaveLength(4)
expect(merge2.relationshipInRichText[0].type).toEqual('paragraph') expect(merge2.richTextLexical.root.children[0].type).toEqual('relationship')
expect(merge2.richTextLexical.root.children[0].value).toMatchObject(testPost)
expect(merge2.richTextLexical.root.children[1].type).toEqual('paragraph')
expect(merge2.richTextLexical.root.children[2].type).toEqual('paragraph')
expect(merge2.richTextLexical.root.children[3].type).toEqual('upload')
expect(merge2.richTextLexical.root.children[3].value).toMatchObject(media)
}) })
it('— relationships - does not re-populate existing rich text relationships', async () => { it('— relationships - does not re-populate existing rich text relationships', async () => {
const initialData: Partial<Page> = { const initialData: Partial<Page> = {
title: 'Test Page', title: 'Test Page',
relationshipInRichText: [ richTextSlate: [
{ {
type: 'paragraph', type: 'paragraph',
text: 'Paragraph 1', text: 'Paragraph 1',
@@ -532,7 +886,7 @@ describe('Collections - Live Preview', () => {
fieldSchema: schemaJSON, fieldSchema: schemaJSON,
incomingData: { incomingData: {
...initialData, ...initialData,
relationshipInRichText: [ richTextSlate: [
{ {
type: 'paragraph', type: 'paragraph',
text: 'Paragraph 1 (Updated)', text: 'Paragraph 1 (Updated)',
@@ -552,9 +906,9 @@ describe('Collections - Live Preview', () => {
}) })
expect(merge1._numberOfRequests).toEqual(0) expect(merge1._numberOfRequests).toEqual(0)
expect(merge1.relationshipInRichText).toHaveLength(2) expect(merge1.richTextSlate).toHaveLength(2)
expect(merge1.relationshipInRichText[0].text).toEqual('Paragraph 1 (Updated)') expect(merge1.richTextSlate[0].text).toEqual('Paragraph 1 (Updated)')
expect(merge1.relationshipInRichText[1].reference.value).toMatchObject(testPost) expect(merge1.richTextSlate[1].reference.value).toMatchObject(testPost)
}) })
it('— relationships - populates within blocks', async () => { it('— relationships - populates within blocks', async () => {

View File

@@ -6,7 +6,6 @@ import React from 'react'
import { PAYLOAD_SERVER_URL } from '@/app/_api/serverURL' import { PAYLOAD_SERVER_URL } from '@/app/_api/serverURL'
import { Hero } from '@/app/_components/Hero' import { Hero } from '@/app/_components/Hero'
import { Blocks } from '@/app/_components/Blocks' import { Blocks } from '@/app/_components/Blocks'
import { RelationshipsBlock } from '@/app/_blocks/Relationships'
export const PageClient: React.FC<{ export const PageClient: React.FC<{
page: PageType page: PageType

View File

@@ -22,9 +22,15 @@ export const RelationshipsBlock: React.FC<RelationshipsBlockProps> = (props) =>
This block is for testing purposes only. It renders every possible type of relationship. This block is for testing purposes only. It renders every possible type of relationship.
</p> </p>
<p> <p>
<b>Rich Text:</b> <b>Rich Text Slate:</b>
</p> </p>
{data?.relationshipInRichText && <RichText content={data.relationshipInRichText} />} {data?.richTextSlate && <RichText content={data.richTextSlate} renderUploadFilenameOnly />}
<p>
<b>Rich Text Lexical:</b>
</p>
{data?.richTextLexical && (
<RichText serializer="lexical" content={data.richTextLexical} renderUploadFilenameOnly />
)}
<p> <p>
<b>Upload:</b> <b>Upload:</b>
</p> </p>

View File

@@ -1,17 +1,25 @@
import React from 'react' import React from 'react'
import serialize from './serialize' import serializeSlate from './serializeSlate'
import serializeLexical from './serializeLexical'
import classes from './index.module.scss' import classes from './index.module.scss'
const RichText: React.FC<{ className?: string; content: any }> = ({ className, content }) => { const RichText: React.FC<{
className?: string
content: any
renderUploadFilenameOnly?: boolean
serializer?: 'lexical' | 'slate'
}> = ({ className, content, renderUploadFilenameOnly, serializer = 'slate' }) => {
if (!content) { if (!content) {
return null return null
} }
return ( return (
<div className={[classes.richText, className].filter(Boolean).join(' ')}> <div className={[classes.richText, className].filter(Boolean).join(' ')}>
{serialize(content)} {serializer === 'slate'
? serializeSlate(content, renderUploadFilenameOnly)
: serializeLexical(content, renderUploadFilenameOnly)}
</div> </div>
) )
} }

View File

@@ -0,0 +1,89 @@
import type { SerializedEditorState } from 'lexical'
import { CMSLink } from '../Link'
import { Media } from '../Media'
const serializer = (
content?: SerializedEditorState['root']['children'],
renderUploadFilenameOnly?: boolean,
): React.ReactNode | React.ReactNode[] =>
content?.map((node, i) => {
switch (node.type) {
case 'h1':
return <h1 key={i}>{serializeLexical(node?.children, renderUploadFilenameOnly)}</h1>
case 'h2':
return <h2 key={i}>{serializeLexical(node?.children, renderUploadFilenameOnly)}</h2>
case 'h3':
return <h3 key={i}>{serializeLexical(node?.children, renderUploadFilenameOnly)}</h3>
case 'h4':
return <h4 key={i}>{serializeLexical(node?.children, renderUploadFilenameOnly)}</h4>
case 'h5':
return <h5 key={i}>{serializeLexical(node?.children, renderUploadFilenameOnly)}</h5>
case 'h6':
return <h6 key={i}>{serializeLexical(node?.children, renderUploadFilenameOnly)}</h6>
case 'quote':
return (
<blockquote key={i}>
{serializeLexical(node?.children, renderUploadFilenameOnly)}
</blockquote>
)
case 'ul':
return <ul key={i}>{serializeLexical(node?.children, renderUploadFilenameOnly)}</ul>
case 'ol':
return <ol key={i}>{serializeLexical(node.children, renderUploadFilenameOnly)}</ol>
case 'li':
return <li key={i}>{serializeLexical(node.children, renderUploadFilenameOnly)}</li>
case 'relationship':
return (
<span key={i}>
{node.value && typeof node.value === 'object'
? node.value.title || node.value.id
: node.value}
</span>
)
case 'link':
return (
<CMSLink
key={i}
type={node.linkType === 'internal' ? 'reference' : 'custom'}
url={node.url}
reference={node.doc as any}
newTab={Boolean(node?.newTab)}
>
{serializer(node?.children, renderUploadFilenameOnly)}
</CMSLink>
)
case 'upload':
if (renderUploadFilenameOnly) {
return <span key={i}>{node.value.filename}</span>
}
return <Media key={i} resource={node?.value} />
case 'paragraph':
return <p key={i}>{serializer(node?.children, renderUploadFilenameOnly)}</p>
case 'text':
return <span key={i}>{node.text}</span>
}
})
const serializeLexical = (
content?: SerializedEditorState,
renderUploadFilenameOnly?: boolean,
): React.ReactNode | React.ReactNode[] => {
return serializer(content?.root?.children, renderUploadFilenameOnly)
}
export default serializeLexical

View File

@@ -1,8 +1,8 @@
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
import escapeHTML from 'escape-html' import escapeHTML from 'escape-html'
import Link from 'next/link'
import { Text } from 'slate' import { Text } from 'slate'
import { CMSLink } from '../Link' import { CMSLink } from '../Link'
import { Media } from '../Media'
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
type Children = Leaf[] type Children = Leaf[]
@@ -15,7 +15,10 @@ type Leaf = {
[key: string]: unknown [key: string]: unknown
} }
const serialize = (children?: Children): React.ReactNode[] => const serializeSlate = (
children?: Children,
renderUploadFilenameOnly?: boolean,
): React.ReactNode[] =>
children?.map((node, i) => { children?.map((node, i) => {
if (Text.isText(node)) { if (Text.isText(node)) {
let text = <span dangerouslySetInnerHTML={{ __html: escapeHTML(node.text) }} /> let text = <span dangerouslySetInnerHTML={{ __html: escapeHTML(node.text) }} />
@@ -57,25 +60,39 @@ const serialize = (children?: Children): React.ReactNode[] =>
switch (node.type) { switch (node.type) {
case 'h1': case 'h1':
return <h1 key={i}>{serialize(node?.children)}</h1> return <h1 key={i}>{serializeSlate(node?.children, renderUploadFilenameOnly)}</h1>
case 'h2': case 'h2':
return <h2 key={i}>{serialize(node?.children)}</h2> return <h2 key={i}>{serializeSlate(node?.children, renderUploadFilenameOnly)}</h2>
case 'h3': case 'h3':
return <h3 key={i}>{serialize(node?.children)}</h3> return <h3 key={i}>{serializeSlate(node?.children, renderUploadFilenameOnly)}</h3>
case 'h4': case 'h4':
return <h4 key={i}>{serialize(node?.children)}</h4> return <h4 key={i}>{serializeSlate(node?.children, renderUploadFilenameOnly)}</h4>
case 'h5': case 'h5':
return <h5 key={i}>{serialize(node?.children)}</h5> return <h5 key={i}>{serializeSlate(node?.children, renderUploadFilenameOnly)}</h5>
case 'h6': case 'h6':
return <h6 key={i}>{serialize(node?.children)}</h6> return <h6 key={i}>{serializeSlate(node?.children, renderUploadFilenameOnly)}</h6>
case 'quote': case 'quote':
return <blockquote key={i}>{serialize(node?.children)}</blockquote> return (
<blockquote key={i}>
{serializeSlate(node?.children, renderUploadFilenameOnly)}
</blockquote>
)
case 'ul': case 'ul':
return <ul key={i}>{serialize(node?.children)}</ul> return <ul key={i}>{serializeSlate(node?.children, renderUploadFilenameOnly)}</ul>
case 'ol': case 'ol':
return <ol key={i}>{serialize(node.children)}</ol> return <ol key={i}>{serializeSlate(node.children, renderUploadFilenameOnly)}</ol>
case 'li': case 'li':
return <li key={i}>{serialize(node.children)}</li> return <li key={i}>{serializeSlate(node.children, renderUploadFilenameOnly)}</li>
case 'relationship': case 'relationship':
return ( return (
<span key={i}> <span key={i}>
@@ -84,6 +101,7 @@ const serialize = (children?: Children): React.ReactNode[] =>
: node.value} : node.value}
</span> </span>
) )
case 'link': case 'link':
return ( return (
<CMSLink <CMSLink
@@ -93,13 +111,20 @@ const serialize = (children?: Children): React.ReactNode[] =>
reference={node.doc as any} reference={node.doc as any}
newTab={Boolean(node?.newTab)} newTab={Boolean(node?.newTab)}
> >
{serialize(node?.children)} {serializeSlate(node?.children, renderUploadFilenameOnly)}
</CMSLink> </CMSLink>
) )
case 'upload':
if (renderUploadFilenameOnly) {
return <span key={i}>{node.value.filename}</span>
}
return <Media key={i} resource={node?.value} />
default: default:
return <p key={i}>{serialize(node?.children)}</p> return <p key={i}>{serializeSlate(node?.children, renderUploadFilenameOnly)}</p>
} }
}) || [] }) || []
export default serialize export default serializeSlate

View File

@@ -11,6 +11,7 @@ export interface Config {
users: User users: User
pages: Page pages: Page
posts: Post posts: Post
tenants: Tenant
categories: Category categories: Category
media: Media media: Media
'payload-preferences': PayloadPreference 'payload-preferences': PayloadPreference
@@ -37,6 +38,7 @@ export interface User {
export interface Page { export interface Page {
id: string id: string
slug: string slug: string
tenant?: (string | null) | Tenant
title: string title: string
hero: { hero: {
type: 'none' | 'highImpact' | 'lowImpact' type: 'none' | 'highImpact' | 'lowImpact'
@@ -152,16 +154,6 @@ export interface Page {
} }
)[] )[]
| null | null
meta?: {
title?: string | null
description?: string | null
image?: string | Media | null
}
relationshipInRichText?:
| {
[k: string]: unknown
}[]
| null
relationshipAsUpload?: string | Media | null relationshipAsUpload?: string | Media | null
relationshipMonoHasOne?: (string | null) | Post relationshipMonoHasOne?: (string | null) | Post
relationshipMonoHasMany?: (string | Post)[] | null relationshipMonoHasMany?: (string | Post)[] | null
@@ -198,6 +190,41 @@ export interface Page {
id?: string | null id?: string | null
}[] }[]
| null | null
richTextSlate?:
| {
[k: string]: unknown
}[]
| null
richTextLexical?: {
root: {
children: {
type: string
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
type: string
version: number
}
[k: string]: unknown
} | null
tab: {
relationshipInTab?: (string | null) | Post
}
meta?: {
title?: string | null
description?: string | null
image?: string | Media | null
}
updatedAt: string
createdAt: string
}
export interface Tenant {
id: string
title: string
clientURL: string
updatedAt: string updatedAt: string
createdAt: string createdAt: string
} }
@@ -221,6 +248,7 @@ export interface Media {
export interface Post { export interface Post {
id: string id: string
slug: string slug: string
tenant?: (string | null) | Tenant
title: string title: string
hero: { hero: {
type: 'none' | 'highImpact' | 'lowImpact' type: 'none' | 'highImpact' | 'lowImpact'

View File

@@ -154,11 +154,6 @@ export interface Page {
} }
)[] )[]
| null | null
relationshipInRichText?:
| {
[k: string]: unknown
}[]
| null
relationshipAsUpload?: string | Media | null relationshipAsUpload?: string | Media | null
relationshipMonoHasOne?: (string | null) | Post relationshipMonoHasOne?: (string | null) | Post
relationshipMonoHasMany?: (string | Post)[] | null relationshipMonoHasMany?: (string | Post)[] | null
@@ -195,6 +190,26 @@ export interface Page {
id?: string | null id?: string | null
}[] }[]
| null | null
richTextSlate?:
| {
[k: string]: unknown
}[]
| null
richTextLexical?: {
root: {
children: {
type: string
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
type: string
version: number
}
[k: string]: unknown
} | null
tab: { tab: {
relationshipInTab?: (string | null) | Post relationshipInTab?: (string | null) | Post
} }

View File

@@ -95,7 +95,7 @@ export const home: Omit<Page, 'createdAt' | 'id' | 'updatedAt'> = {
}, },
], ],
relationshipAsUpload: '{{MEDIA_ID}}', relationshipAsUpload: '{{MEDIA_ID}}',
relationshipInRichText: [ richTextSlate: [
{ {
children: [ children: [
{ {
@@ -108,7 +108,65 @@ export const home: Omit<Page, 'createdAt' | 'id' | 'updatedAt'> = {
id: '{{POST_1_ID}}', id: '{{POST_1_ID}}',
}, },
}, },
{
type: 'paragraph',
children: [
{
text: '',
},
],
},
{
children: [
{
text: '',
},
],
relationTo: 'media',
type: 'upload',
value: {
id: '{{MEDIA_ID}}',
},
},
], ],
richTextLexical: {
root: {
type: 'root',
format: '',
indent: 0,
version: 1,
children: [
{
format: '',
type: 'relationship',
version: 1,
relationTo: 'posts',
value: {
id: '{{POST_1_ID}}',
},
},
{
children: [],
direction: null,
format: '',
indent: 0,
type: 'paragraph',
version: 1,
},
{
format: '',
type: 'upload',
version: 1,
fields: null,
relationTo: 'media',
value: {
id: '{{MEDIA_ID}}',
},
},
],
direction: null,
},
},
relationshipMonoHasMany: ['{{POST_1_ID}}'], relationshipMonoHasMany: ['{{POST_1_ID}}'],
relationshipMonoHasOne: '{{POST_1_ID}}', relationshipMonoHasOne: '{{POST_1_ID}}',
relationshipPolyHasMany: [{ relationTo: 'posts', value: '{{POST_1_ID}}' }], relationshipPolyHasMany: [{ relationTo: 'posts', value: '{{POST_1_ID}}' }],