fix(live-preview): populates localized relationships in client-side live preview (#9617)

Fixes #5026. When using client-side Live Preview, switching locale would
not populate relationships in that locale, and would use the default
locale instead. This was because locale was simply not being handled.
Now, we pass the locale through the event, and use it to make localized
queries when populating those relationships.
This commit is contained in:
Jacob Fletcher
2024-11-29 15:41:39 -05:00
committed by GitHub
parent 9892303f1f
commit 3d1a0656d2
12 changed files with 200 additions and 93 deletions

View File

@@ -43,6 +43,7 @@ export const handleMessage = async <T>(args: {
fieldSchema: payloadLivePreviewFieldSchema,
incomingData: data,
initialData: payloadLivePreviewPreviousData || initialData,
locale: event.data.locale,
serverURL,
})

View File

@@ -15,6 +15,11 @@ const defaultRequestHandler = ({ apiPath, endpoint, serverURL }) => {
})
}
// Relationships are only updated when their `id` or `relationTo` changes, by comparing the old and new values
// This needs to also happen when locale changes, except this is not not part of the API response
// Instead, we keep track of the old locale ourselves and trigger a re-population when it changes
let prevLocale: string | undefined
export const mergeData = async <T>(args: {
apiRoute?: string
collectionPopulationRequestHandler?: ({
@@ -31,6 +36,7 @@ export const mergeData = async <T>(args: {
fieldSchema: ReturnType<typeof fieldSchemaToJSON>
incomingData: Partial<T>
initialData: T
locale?: string
returnNumberOfRequests?: boolean
serverURL: string
}): Promise<
@@ -45,6 +51,7 @@ export const mergeData = async <T>(args: {
fieldSchema,
incomingData,
initialData,
locale,
returnNumberOfRequests,
serverURL,
} = args
@@ -57,6 +64,7 @@ export const mergeData = async <T>(args: {
externallyUpdatedRelationship,
fieldSchema,
incomingData,
localeChanged: prevLocale !== locale,
populationsByCollection,
result,
})
@@ -72,7 +80,7 @@ export const mergeData = async <T>(args: {
res = await requestHandler({
apiPath: apiRoute || '/api',
endpoint: encodeURI(
`${collection}?depth=${depth}&where[id][in]=${Array.from(ids).join(',')}`,
`${collection}?depth=${depth}&where[id][in]=${Array.from(ids).join(',')}${locale ? `&locale=${locale}` : ''}`,
),
serverURL,
}).then((res) => res.json())
@@ -92,6 +100,8 @@ export const mergeData = async <T>(args: {
}),
)
prevLocale = locale
return {
...result,
...(returnNumberOfRequests

View File

@@ -6,7 +6,7 @@ export const subscribe = <T>(args: {
depth?: number
initialData: T
serverURL: string
}): ((event: MessageEvent) => void) => {
}): ((event: MessageEvent) => Promise<void> | void) => {
const { apiRoute, callback, depth, initialData, serverURL } = args
const onMessage = async (event: MessageEvent) => {

View File

@@ -8,6 +8,7 @@ export const traverseFields = <T>(args: {
externallyUpdatedRelationship?: UpdatedDocument
fieldSchema: ReturnType<typeof fieldSchemaToJSON>
incomingData: T
localeChanged: boolean
populationsByCollection: PopulationsByCollection
result: T
}): void => {
@@ -15,6 +16,7 @@ export const traverseFields = <T>(args: {
externallyUpdatedRelationship,
fieldSchema: fieldSchemas,
incomingData,
localeChanged,
populationsByCollection,
result,
} = args
@@ -47,6 +49,7 @@ export const traverseFields = <T>(args: {
externallyUpdatedRelationship,
fieldSchema: fieldSchema.fields,
incomingData: incomingRow,
localeChanged,
populationsByCollection,
result: result[fieldName][i],
})
@@ -80,6 +83,7 @@ export const traverseFields = <T>(args: {
externallyUpdatedRelationship,
fieldSchema: incomingBlockJSON.fields,
incomingData: incomingBlock,
localeChanged,
populationsByCollection,
result: result[fieldName][i],
})
@@ -103,6 +107,7 @@ export const traverseFields = <T>(args: {
externallyUpdatedRelationship,
fieldSchema: fieldSchema.fields,
incomingData: incomingData[fieldName] || {},
localeChanged,
populationsByCollection,
result: result[fieldName],
})
@@ -135,11 +140,12 @@ export const traverseFields = <T>(args: {
const newRelation = incomingRelation.relationTo
const hasChanged = newID !== oldID || newRelation !== oldRelation
const hasUpdated =
newRelation === externallyUpdatedRelationship?.entitySlug &&
newID === externallyUpdatedRelationship?.id
if (hasChanged || hasUpdated) {
if (hasChanged || hasUpdated || localeChanged) {
if (!populationsByCollection[newRelation]) {
populationsByCollection[newRelation] = []
}
@@ -153,11 +159,12 @@ export const traverseFields = <T>(args: {
} else {
// Handle `hasMany` monomorphic
const hasChanged = incomingRelation !== result[fieldName][i]?.id
const hasUpdated =
fieldSchema.relationTo === externallyUpdatedRelationship?.entitySlug &&
incomingRelation === externallyUpdatedRelationship?.id
if (hasChanged || hasUpdated) {
if (hasChanged || hasUpdated || localeChanged) {
if (!populationsByCollection[fieldSchema.relationTo]) {
populationsByCollection[fieldSchema.relationTo] = []
}
@@ -207,13 +214,14 @@ export const traverseFields = <T>(args: {
const oldRelation = hasOldValue ? result[fieldName].relationTo : ''
const hasChanged = newID !== oldID || newRelation !== oldRelation
const hasUpdated =
newRelation === externallyUpdatedRelationship?.entitySlug &&
newID === externallyUpdatedRelationship?.id
// if the new value/relation is different from the old value/relation
// populate the new value, otherwise leave it alone
if (hasChanged || hasUpdated) {
if (hasChanged || hasUpdated || localeChanged) {
// if the new value is not empty, populate it
// otherwise set the value to null
if (newID) {
@@ -245,13 +253,14 @@ export const traverseFields = <T>(args: {
result[fieldName]
const hasChanged = newID !== oldID
const hasUpdated =
fieldSchema.relationTo === externallyUpdatedRelationship?.entitySlug &&
newID === externallyUpdatedRelationship?.id
// if the new value is different from the old value
// populate the new value, otherwise leave it alone
if (hasChanged || hasUpdated) {
if (hasChanged || hasUpdated || localeChanged) {
// if the new value is not empty, populate it
// otherwise set the value to null
if (newID) {

View File

@@ -2,7 +2,7 @@
import type { EditViewProps } from 'payload'
import { ShimmerEffect, useAllFormFields, useDocumentEvents } from '@payloadcms/ui'
import { ShimmerEffect, useAllFormFields, useDocumentEvents, useLocale } from '@payloadcms/ui'
import { reduceFieldsToValues } from 'payload/shared'
import React, { useEffect } from 'react'
@@ -25,6 +25,8 @@ export const LivePreview: React.FC<EditViewProps> = (props) => {
url,
} = useLivePreviewContext()
const locale = useLocale()
const { mostRecentUpdate } = useDocumentEvents()
const { breakpoint, fieldSchemaJSON } = useLivePreviewContext()
@@ -57,6 +59,7 @@ export const LivePreview: React.FC<EditViewProps> = (props) => {
data: values,
externallyUpdatedRelationship: mostRecentUpdate,
fieldSchemaJSON: shouldSendSchema ? fieldSchemaJSON : undefined,
locale: locale.code,
}
// Post message to external popup window
@@ -80,6 +83,7 @@ export const LivePreview: React.FC<EditViewProps> = (props) => {
setIframeHasLoaded,
fieldSchemaJSON,
mostRecentUpdate,
locale,
])
// To support SSR, we transmit a `window.postMessage` event without a payload

View File

@@ -38,6 +38,9 @@ export const PageClient: React.FC<{
/>
<Gutter>
<div id={renderedPageTitleID}>{`For Testing: ${data.title}`}</div>
<div id={renderedPageTitleID}>
{`For Testing (Localized): ${typeof data.relationToLocalized === 'string' ? data.relationToLocalized : data.relationToLocalized?.localizedTitle}`}
</div>
</Gutter>
</React.Fragment>
)

View File

@@ -75,6 +75,16 @@ export const Pages: CollectionConfig = {
{
label: 'Test',
fields: [
{
name: 'localizedTitle',
type: 'text',
localized: true,
},
{
name: 'relationToLocalized',
type: 'relationship',
relationTo: postsSlug,
},
{
label: 'Rich Text — Slate',
type: 'richText',

View File

@@ -71,6 +71,16 @@ export const Posts: CollectionConfig = {
},
],
},
{
label: 'Test',
fields: [
{
name: 'localizedTitle',
type: 'text',
localized: true,
},
],
},
],
},
{

View File

@@ -25,6 +25,10 @@ import {
import { formatLivePreviewURL } from './utilities/formatLivePreviewURL.js'
export default buildConfigWithDefaults({
localization: {
defaultLocale: 'en',
locales: ['en', 'es'],
},
admin: {
importMap: {
baseDir: path.resolve(dirname),

View File

@@ -51,6 +51,7 @@ describe('Collections - Live Preview', () => {
slug: 'post-1',
title: 'Test Post',
tenant: tenant.id,
localizedTitle: 'Test Post',
},
})
@@ -60,6 +61,7 @@ describe('Collections - Live Preview', () => {
slug: 'post-2',
title: 'Test Post 2',
tenant: tenant.id,
localizedTitle: 'Test Post 2',
},
})
@@ -1135,6 +1137,54 @@ describe('Collections - Live Preview', () => {
])
})
it('— relationships - populates localized relationships', async () => {
const post = await payload.create({
collection: postsSlug,
data: {
title: 'Test Post',
slug: 'test-post',
hero: {
type: 'highImpact',
media: media.id,
},
localizedTitle: 'Test Post Spanish',
},
locale: 'es',
})
await payload.update({
id: post.id,
locale: 'en',
collection: postsSlug,
data: {
localizedTitle: 'Test Post English',
},
})
const initialData: Partial<Page> = {
title: 'Test Page',
relationToLocalized: post.id,
}
// Populate the relationships
const merge1 = await mergeData({
depth: 1,
fieldSchema: schemaJSON,
incomingData: {
...initialData,
relationToLocalized: post.id,
},
initialData,
serverURL,
returnNumberOfRequests: true,
collectionPopulationRequestHandler,
locale: 'es',
})
expect(merge1._numberOfRequests).toEqual(1)
expect(merge1.relationToLocalized).toHaveProperty('localizedTitle', 'Test Post Spanish')
})
it('— rich text - merges text changes', async () => {
// Add a relationship
const merge1 = await traverseRichText({

View File

@@ -38,7 +38,7 @@ export interface Config {
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
};
db: {
defaultIDType: string;
defaultIDType: number;
};
globals: {
header: Header;
@@ -48,7 +48,7 @@ export interface Config {
header: HeaderSelect<false> | HeaderSelect<true>;
footer: FooterSelect<false> | FooterSelect<true>;
};
locale: null;
locale: 'en' | 'es';
user: User & {
collection: 'users';
};
@@ -80,7 +80,7 @@ export interface UserAuthOperations {
* via the `definition` "users".
*/
export interface User {
id: string;
id: number;
updatedAt: string;
createdAt: string;
email: string;
@@ -97,9 +97,9 @@ export interface User {
* via the `definition` "pages".
*/
export interface Page {
id: string;
id: number;
slug: string;
tenant?: (string | null) | Tenant;
tenant?: (number | null) | Tenant;
title: string;
hero: {
type: 'none' | 'highImpact' | 'lowImpact';
@@ -108,7 +108,7 @@ export interface Page {
[k: string]: unknown;
}[]
| null;
media?: (string | null) | Media;
media?: (number | null) | Media;
};
layout?:
| (
@@ -127,11 +127,11 @@ export interface Page {
reference?:
| ({
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null)
| ({
relationTo: 'pages';
value: string | Page;
value: number | Page;
} | null);
url?: string | null;
label: string;
@@ -161,11 +161,11 @@ export interface Page {
reference?:
| ({
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null)
| ({
relationTo: 'pages';
value: string | Page;
value: number | Page;
} | null);
url?: string | null;
label: string;
@@ -181,7 +181,7 @@ export interface Page {
| {
invertBackground?: boolean | null;
position?: ('default' | 'fullscreen') | null;
media: string | Media;
media: number | Media;
id?: string | null;
blockName?: string | null;
blockType: 'mediaBlock';
@@ -194,18 +194,18 @@ export interface Page {
| null;
populateBy?: ('collection' | 'selection') | null;
relationTo?: 'posts' | null;
categories?: (string | Category)[] | null;
categories?: (number | Category)[] | null;
limit?: number | null;
selectedDocs?:
| {
relationTo: 'posts';
value: string | Post;
value: number | Post;
}[]
| null;
populatedDocs?:
| {
relationTo: 'posts';
value: string | Post;
value: number | Post;
}[]
| null;
populatedDocsTotal?: number | null;
@@ -215,6 +215,8 @@ export interface Page {
}
)[]
| null;
localizedTitle?: string | null;
relationToLocalized?: (number | null) | Post;
richTextSlate?:
| {
[k: string]: unknown;
@@ -235,22 +237,22 @@ export interface Page {
};
[k: string]: unknown;
} | null;
relationshipAsUpload?: (string | null) | Media;
relationshipMonoHasOne?: (string | null) | Post;
relationshipMonoHasMany?: (string | Post)[] | null;
relationshipAsUpload?: (number | null) | Media;
relationshipMonoHasOne?: (number | null) | Post;
relationshipMonoHasMany?: (number | Post)[] | null;
relationshipPolyHasOne?: {
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null;
relationshipPolyHasMany?:
| {
relationTo: 'posts';
value: string | Post;
value: number | Post;
}[]
| null;
arrayOfRelationships?:
| {
uploadInArray?: (string | null) | Media;
uploadInArray?: (number | null) | Media;
richTextInArray?: {
root: {
type: string;
@@ -266,28 +268,28 @@ export interface Page {
};
[k: string]: unknown;
} | null;
relationshipInArrayMonoHasOne?: (string | null) | Post;
relationshipInArrayMonoHasMany?: (string | Post)[] | null;
relationshipInArrayMonoHasOne?: (number | null) | Post;
relationshipInArrayMonoHasMany?: (number | Post)[] | null;
relationshipInArrayPolyHasOne?: {
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null;
relationshipInArrayPolyHasMany?:
| {
relationTo: 'posts';
value: string | Post;
value: number | Post;
}[]
| null;
id?: string | null;
}[]
| null;
tab?: {
relationshipInTab?: (string | null) | Post;
relationshipInTab?: (number | null) | Post;
};
meta?: {
title?: string | null;
description?: string | null;
image?: (string | null) | Media;
image?: (number | null) | Media;
};
updatedAt: string;
createdAt: string;
@@ -297,7 +299,7 @@ export interface Page {
* via the `definition` "tenants".
*/
export interface Tenant {
id: string;
id: number;
title: string;
clientURL: string;
updatedAt: string;
@@ -308,7 +310,7 @@ export interface Tenant {
* via the `definition` "media".
*/
export interface Media {
id: string;
id: number;
alt: string;
updatedAt: string;
createdAt: string;
@@ -327,9 +329,9 @@ export interface Media {
* via the `definition` "posts".
*/
export interface Post {
id: string;
id: number;
slug: string;
tenant?: (string | null) | Tenant;
tenant?: (number | null) | Tenant;
title: string;
hero: {
type: 'none' | 'highImpact' | 'lowImpact';
@@ -338,7 +340,7 @@ export interface Post {
[k: string]: unknown;
}[]
| null;
media?: (string | null) | Media;
media?: (number | null) | Media;
};
layout?:
| (
@@ -357,11 +359,11 @@ export interface Post {
reference?:
| ({
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null)
| ({
relationTo: 'pages';
value: string | Page;
value: number | Page;
} | null);
url?: string | null;
label: string;
@@ -391,11 +393,11 @@ export interface Post {
reference?:
| ({
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null)
| ({
relationTo: 'pages';
value: string | Page;
value: number | Page;
} | null);
url?: string | null;
label: string;
@@ -411,7 +413,7 @@ export interface Post {
| {
invertBackground?: boolean | null;
position?: ('default' | 'fullscreen') | null;
media: string | Media;
media: number | Media;
id?: string | null;
blockName?: string | null;
blockType: 'mediaBlock';
@@ -424,18 +426,18 @@ export interface Post {
| null;
populateBy?: ('collection' | 'selection') | null;
relationTo?: 'posts' | null;
categories?: (string | Category)[] | null;
categories?: (number | Category)[] | null;
limit?: number | null;
selectedDocs?:
| {
relationTo: 'posts';
value: string | Post;
value: number | Post;
}[]
| null;
populatedDocs?:
| {
relationTo: 'posts';
value: string | Post;
value: number | Post;
}[]
| null;
populatedDocsTotal?: number | null;
@@ -445,11 +447,12 @@ export interface Post {
}
)[]
| null;
relatedPosts?: (string | Post)[] | null;
relatedPosts?: (number | Post)[] | null;
localizedTitle?: string | null;
meta?: {
title?: string | null;
description?: string | null;
image?: (string | null) | Media;
image?: (number | null) | Media;
};
updatedAt: string;
createdAt: string;
@@ -459,7 +462,7 @@ export interface Post {
* via the `definition` "categories".
*/
export interface Category {
id: string;
id: number;
title?: string | null;
updatedAt: string;
createdAt: string;
@@ -469,9 +472,9 @@ export interface Category {
* via the `definition` "ssr".
*/
export interface Ssr {
id: string;
id: number;
slug: string;
tenant?: (string | null) | Tenant;
tenant?: (number | null) | Tenant;
title: string;
hero: {
type: 'none' | 'highImpact' | 'lowImpact';
@@ -480,7 +483,7 @@ export interface Ssr {
[k: string]: unknown;
}[]
| null;
media?: (string | null) | Media;
media?: (number | null) | Media;
};
layout?:
| (
@@ -499,11 +502,11 @@ export interface Ssr {
reference?:
| ({
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null)
| ({
relationTo: 'pages';
value: string | Page;
value: number | Page;
} | null);
url?: string | null;
label: string;
@@ -533,11 +536,11 @@ export interface Ssr {
reference?:
| ({
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null)
| ({
relationTo: 'pages';
value: string | Page;
value: number | Page;
} | null);
url?: string | null;
label: string;
@@ -553,7 +556,7 @@ export interface Ssr {
| {
invertBackground?: boolean | null;
position?: ('default' | 'fullscreen') | null;
media: string | Media;
media: number | Media;
id?: string | null;
blockName?: string | null;
blockType: 'mediaBlock';
@@ -566,18 +569,18 @@ export interface Ssr {
| null;
populateBy?: ('collection' | 'selection') | null;
relationTo?: 'posts' | null;
categories?: (string | Category)[] | null;
categories?: (number | Category)[] | null;
limit?: number | null;
selectedDocs?:
| {
relationTo: 'posts';
value: string | Post;
value: number | Post;
}[]
| null;
populatedDocs?:
| {
relationTo: 'posts';
value: string | Post;
value: number | Post;
}[]
| null;
populatedDocsTotal?: number | null;
@@ -590,7 +593,7 @@ export interface Ssr {
meta?: {
title?: string | null;
description?: string | null;
image?: (string | null) | Media;
image?: (number | null) | Media;
};
updatedAt: string;
createdAt: string;
@@ -600,9 +603,9 @@ export interface Ssr {
* via the `definition` "ssr-autosave".
*/
export interface SsrAutosave {
id: string;
id: number;
slug: string;
tenant?: (string | null) | Tenant;
tenant?: (number | null) | Tenant;
title: string;
hero: {
type: 'none' | 'highImpact' | 'lowImpact';
@@ -611,7 +614,7 @@ export interface SsrAutosave {
[k: string]: unknown;
}[]
| null;
media?: (string | null) | Media;
media?: (number | null) | Media;
};
layout?:
| (
@@ -630,11 +633,11 @@ export interface SsrAutosave {
reference?:
| ({
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null)
| ({
relationTo: 'pages';
value: string | Page;
value: number | Page;
} | null);
url?: string | null;
label: string;
@@ -664,11 +667,11 @@ export interface SsrAutosave {
reference?:
| ({
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null)
| ({
relationTo: 'pages';
value: string | Page;
value: number | Page;
} | null);
url?: string | null;
label: string;
@@ -684,7 +687,7 @@ export interface SsrAutosave {
| {
invertBackground?: boolean | null;
position?: ('default' | 'fullscreen') | null;
media: string | Media;
media: number | Media;
id?: string | null;
blockName?: string | null;
blockType: 'mediaBlock';
@@ -697,18 +700,18 @@ export interface SsrAutosave {
| null;
populateBy?: ('collection' | 'selection') | null;
relationTo?: 'posts' | null;
categories?: (string | Category)[] | null;
categories?: (number | Category)[] | null;
limit?: number | null;
selectedDocs?:
| {
relationTo: 'posts';
value: string | Post;
value: number | Post;
}[]
| null;
populatedDocs?:
| {
relationTo: 'posts';
value: string | Post;
value: number | Post;
}[]
| null;
populatedDocsTotal?: number | null;
@@ -721,7 +724,7 @@ export interface SsrAutosave {
meta?: {
title?: string | null;
description?: string | null;
image?: (string | null) | Media;
image?: (number | null) | Media;
};
updatedAt: string;
createdAt: string;
@@ -732,44 +735,44 @@ export interface SsrAutosave {
* via the `definition` "payload-locked-documents".
*/
export interface PayloadLockedDocument {
id: string;
id: number;
document?:
| ({
relationTo: 'users';
value: string | User;
value: number | User;
} | null)
| ({
relationTo: 'pages';
value: string | Page;
value: number | Page;
} | null)
| ({
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null)
| ({
relationTo: 'ssr';
value: string | Ssr;
value: number | Ssr;
} | null)
| ({
relationTo: 'ssr-autosave';
value: string | SsrAutosave;
value: number | SsrAutosave;
} | null)
| ({
relationTo: 'tenants';
value: string | Tenant;
value: number | Tenant;
} | null)
| ({
relationTo: 'categories';
value: string | Category;
value: number | Category;
} | null)
| ({
relationTo: 'media';
value: string | Media;
value: number | Media;
} | null);
globalSlug?: string | null;
user: {
relationTo: 'users';
value: string | User;
value: number | User;
};
updatedAt: string;
createdAt: string;
@@ -779,10 +782,10 @@ export interface PayloadLockedDocument {
* via the `definition` "payload-preferences".
*/
export interface PayloadPreference {
id: string;
id: number;
user: {
relationTo: 'users';
value: string | User;
value: number | User;
};
key?: string | null;
value?:
@@ -802,7 +805,7 @@ export interface PayloadPreference {
* via the `definition` "payload-migrations".
*/
export interface PayloadMigration {
id: string;
id: number;
name?: string | null;
batch?: number | null;
updatedAt: string;
@@ -913,6 +916,8 @@ export interface PagesSelect<T extends boolean = true> {
blockName?: T;
};
};
localizedTitle?: T;
relationToLocalized?: T;
richTextSlate?: T;
richTextLexical?: T;
relationshipAsUpload?: T;
@@ -1037,6 +1042,7 @@ export interface PostsSelect<T extends boolean = true> {
};
};
relatedPosts?: T;
localizedTitle?: T;
meta?:
| T
| {
@@ -1322,7 +1328,7 @@ export interface PayloadMigrationsSelect<T extends boolean = true> {
* via the `definition` "header".
*/
export interface Header {
id: string;
id: number;
navItems?:
| {
link: {
@@ -1331,11 +1337,11 @@ export interface Header {
reference?:
| ({
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null)
| ({
relationTo: 'pages';
value: string | Page;
value: number | Page;
} | null);
url?: string | null;
label: string;
@@ -1352,7 +1358,7 @@ export interface Header {
* via the `definition` "footer".
*/
export interface Footer {
id: string;
id: number;
navItems?:
| {
link: {
@@ -1361,11 +1367,11 @@ export interface Footer {
reference?:
| ({
relationTo: 'posts';
value: string | Post;
value: number | Post;
} | null)
| ({
relationTo: 'pages';
value: string | Page;
value: number | Page;
} | null);
url?: string | null;
label: string;

View File

@@ -37,7 +37,7 @@
],
"paths": {
"@payload-config": [
"./test/_community/config.ts"
"./test/live-preview/config.ts"
],
"@payloadcms/live-preview": [
"./packages/live-preview/src"