diff --git a/.circleci/config.yml b/.circleci/config.yml index a9892239..9f5e6be9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,6 +32,7 @@ jobs: - checkout - yarn_install - run: yarn lint + - run: yarn tsc - run: yarn build unit-tests: executor: linux-node diff --git a/packages/live-preview-sdk/src/__tests__/inspectorMode.spec.ts b/packages/live-preview-sdk/src/__tests__/inspectorMode.spec.ts index 9ac06daf..5b708f7b 100644 --- a/packages/live-preview-sdk/src/__tests__/inspectorMode.spec.ts +++ b/packages/live-preview-sdk/src/__tests__/inspectorMode.spec.ts @@ -9,9 +9,10 @@ const locale = 'en-US'; describe('InspectorMode', () => { let inspectorMode: InspectorMode; + const targetOrigin = ['https://app.contentful.com']; beforeEach(() => { - inspectorMode = new InspectorMode({ locale }); + inspectorMode = new InspectorMode({ locale, targetOrigin }); }); afterEach(() => { diff --git a/packages/live-preview-sdk/src/__tests__/react.spec.tsx b/packages/live-preview-sdk/src/__tests__/react.spec.tsx index 380c0a68..e34937c1 100644 --- a/packages/live-preview-sdk/src/__tests__/react.spec.tsx +++ b/packages/live-preview-sdk/src/__tests__/react.spec.tsx @@ -64,7 +64,7 @@ describe('useContentfulLiveUpdates', () => { }); expect(subscribe).toHaveBeenCalledTimes(1); - expect(subscribe).toHaveBeenCalledWith({ + expect(subscribe).toHaveBeenCalledWith('edit', { data: initialData, locale, callback: expect.any(Function), @@ -108,7 +108,7 @@ describe('useContentfulLiveUpdates', () => { const updatedData1 = createData('4', 'Hello World'); act(() => { - subscribe.mock.calls[0][0].callback(updatedData1); + subscribe.mock.calls[0][1].callback(updatedData1); vi.advanceTimersToNextTimer(); }); @@ -116,7 +116,7 @@ describe('useContentfulLiveUpdates', () => { const updatedData2 = createData('4', 'Hello World!'); act(() => { - subscribe.mock.calls[0][0].callback(updatedData2); + subscribe.mock.calls[0][1].callback(updatedData2); vi.advanceTimersToNextTimer(); }); @@ -142,11 +142,11 @@ describe('useContentfulLiveUpdates', () => { const updatedData = createData('5', 'Hello World'); act(() => { - subscribe.mock.calls[0][0].callback(createData('5', 'Hello W')); - subscribe.mock.calls[0][0].callback(createData('5', 'Hello Wo')); - subscribe.mock.calls[0][0].callback(createData('5', 'Hello Wor')); - subscribe.mock.calls[0][0].callback(createData('5', 'Hello Worl')); - subscribe.mock.calls[0][0].callback(updatedData); + subscribe.mock.calls[0][1].callback(createData('5', 'Hello W')); + subscribe.mock.calls[0][1].callback(createData('5', 'Hello Wo')); + subscribe.mock.calls[0][1].callback(createData('5', 'Hello Wor')); + subscribe.mock.calls[0][1].callback(createData('5', 'Hello Worl')); + subscribe.mock.calls[0][1].callback(updatedData); vi.advanceTimersToNextTimer(); }); diff --git a/packages/live-preview-sdk/src/__tests__/resolveReference.spec.ts b/packages/live-preview-sdk/src/__tests__/resolveReference.spec.ts index b2add673..8229137a 100644 --- a/packages/live-preview-sdk/src/__tests__/resolveReference.spec.ts +++ b/packages/live-preview-sdk/src/__tests__/resolveReference.spec.ts @@ -11,6 +11,7 @@ vi.mock('@contentful/visual-sdk'); describe('resolveReference', () => { const locale = 'en-US'; + const sendMessage = vi.fn(); beforeEach(() => { (EditorEntityStore as Mock).mockImplementation(() => ({ @@ -51,6 +52,7 @@ describe('resolveReference', () => { entityReferenceMap: new Map([['1', asset]]), referenceId: '1', locale, + sendMessage, }); expect(result).toEqual(expected); @@ -62,6 +64,7 @@ describe('resolveReference', () => { referenceId: cdaAsset.sys.id, isAsset: true, locale, + sendMessage, }); expect(result.typeName).toBe('Asset'); @@ -102,6 +105,7 @@ describe('resolveReference', () => { entityReferenceMap: new Map([['1', entry]]), referenceId: '1', locale, + sendMessage, }); expect(result).toEqual(expected); @@ -112,6 +116,7 @@ describe('resolveReference', () => { entityReferenceMap: new Map(), referenceId: cdaEntry.sys.id, locale, + sendMessage, }); expect(result.typeName).toBe('TopicProductFeature'); diff --git a/packages/live-preview-sdk/src/graphql/__tests__/entries.test.ts b/packages/live-preview-sdk/src/graphql/__tests__/entries.test.ts index c9f79dd5..3d62d36d 100644 --- a/packages/live-preview-sdk/src/graphql/__tests__/entries.test.ts +++ b/packages/live-preview-sdk/src/graphql/__tests__/entries.test.ts @@ -19,6 +19,7 @@ const defaultContentType = defaultContentTypeJSON as ContentTypeProps; // Note: we can get rid of expect.objectContaining, if we iterate over the provided data instead of the ContentType.fields describe('Update GraphQL Entry', () => { const testReferenceId = '18kDTlnJNnDIJf6PsXE5Mr'; + const sendMessage = vi.fn(); beforeEach(() => { (resolveReference as Mock).mockResolvedValue({ @@ -59,6 +60,7 @@ describe('Update GraphQL Entry', () => { updateFromEntryEditor: update, locale, entityReferenceMap, + sendMessage, }); }; diff --git a/packages/live-preview-sdk/src/graphql/entries.ts b/packages/live-preview-sdk/src/graphql/entries.ts index 2c711167..35d6188a 100644 --- a/packages/live-preview-sdk/src/graphql/entries.ts +++ b/packages/live-preview-sdk/src/graphql/entries.ts @@ -2,7 +2,14 @@ import { BLOCKS, INLINES } from '@contentful/rich-text-types'; import { Asset, Entry } from 'contentful'; import type { SetOptional } from 'type-fest'; -import { isPrimitiveField, updatePrimitiveField, resolveReference, clone, debug } from '../helpers'; +import { + isPrimitiveField, + updatePrimitiveField, + resolveReference, + clone, + debug, + SendMessage, +} from '../helpers'; import { SUPPORTED_RICHTEXT_EMBEDS, isAsset, isRichText } from '../helpers/entities'; import { CollectionItem, @@ -35,6 +42,7 @@ export async function updateEntry({ locale, entityReferenceMap, gqlParams, + sendMessage, }: UpdateEntryProps): Promise { if (dataFromPreviewApp.sys.id !== updateFromEntryEditor.sys.id) { return dataFromPreviewApp; @@ -59,6 +67,7 @@ export async function updateEntry({ name, locale, gqlParams, + sendMessage, }); } else if (field.type === 'Link') { await updateSingleRefField({ @@ -68,6 +77,7 @@ export async function updateEntry({ locale, entityReferenceMap, gqlParams, + sendMessage, }); } else if (field.type === 'Array' && field.items?.type === 'Link') { await updateMultiRefField({ @@ -77,6 +87,7 @@ export async function updateEntry({ locale, entityReferenceMap, gqlParams, + sendMessage, }); } } @@ -101,6 +112,7 @@ async function processNode( assets: RichTextLink, entityReferenceMap: EntityReferenceMap, locale: string, + sendMessage: SendMessage, gqlParams?: GraphQLParams ) { // Check if the node is an embedded entity @@ -119,6 +131,7 @@ async function processNode( entityReferenceMap, locale, gqlParams, + sendMessage, }); } else if (node.data.target.sys.linkType === 'Asset') { ref = await updateReferenceAssetField({ @@ -127,6 +140,7 @@ async function processNode( entityReferenceMap, locale, gqlParams, + sendMessage, }); } @@ -160,7 +174,15 @@ async function processNode( // since embedded entries can be part of other rich text content (e.g. embedded inline entries) // we need to recursively check for these entries to display them for (const contentNode of node.content) { - await processNode(contentNode, entries, assets, entityReferenceMap, locale, gqlParams); + await processNode( + contentNode, + entries, + assets, + entityReferenceMap, + locale, + sendMessage, + gqlParams + ); } } } @@ -169,6 +191,7 @@ async function processRichTextField( richTextNode: any | null, entityReferenceMap: EntityReferenceMap, locale: string, + sendMessage: SendMessage, gqlParams?: GraphQLParams ): Promise<{ entries: RichTextLink; assets: RichTextLink }> { const entries: RichTextLink = { block: [], inline: [], hyperlink: [] }; @@ -176,7 +199,7 @@ async function processRichTextField( if (richTextNode) { for (const node of richTextNode.content) { - await processNode(node, entries, assets, entityReferenceMap, locale, gqlParams); + await processNode(node, entries, assets, entityReferenceMap, locale, sendMessage, gqlParams); } } @@ -193,6 +216,7 @@ async function updateRichTextField({ locale, entityReferenceMap, gqlParams, + sendMessage, }: UpdateFieldProps) { if (!dataFromPreviewApp[name]) { dataFromPreviewApp[name] = {}; @@ -207,6 +231,7 @@ async function updateRichTextField({ dataFromPreviewApp[name].json, entityReferenceMap, locale, + sendMessage, gqlParams ); } @@ -217,12 +242,14 @@ async function updateReferenceAssetField({ entityReferenceMap, locale, gqlParams, + sendMessage, }: SetOptional, 'gqlParams'>) { const { reference } = await resolveReference({ entityReferenceMap, referenceId: updatedReference.sys.id, isAsset: true, locale, + sendMessage, }); return updateAsset( @@ -242,11 +269,13 @@ async function updateReferenceEntryField({ entityReferenceMap, locale, gqlParams, + sendMessage, }: SetOptional, 'gqlParams'>) { const { reference, typeName } = await resolveReference({ entityReferenceMap, referenceId: updatedReference.sys.id, locale, + sendMessage, }); // If we have the typename of the updated reference, we can work with it @@ -267,7 +296,13 @@ async function updateReferenceEntryField({ if (isRichText(value)) { // richtext merged[key] = { json: value }; - merged[key].links = await processRichTextField(value, entityReferenceMap, locale); + merged[key].links = await processRichTextField( + value, + entityReferenceMap, + locale, + sendMessage, + gqlParams + ); } if ('sys' in value) { @@ -280,6 +315,7 @@ async function updateReferenceEntryField({ entityReferenceMap, name: key, gqlParams, + sendMessage, }); } } else if (Array.isArray(value) && value[0]?.sys) { @@ -293,6 +329,7 @@ async function updateReferenceEntryField({ entityReferenceMap, name: key, gqlParams, + sendMessage, }); } else { // primitive fields @@ -309,6 +346,7 @@ async function updateReferenceField({ entityReferenceMap, locale, gqlParams, + sendMessage, }: UpdateReferenceFieldProps) { if (!updatedReference) { return null; @@ -330,6 +368,7 @@ async function updateReferenceField({ entityReferenceMap, locale, gqlParams, + sendMessage, }); } @@ -339,6 +378,7 @@ async function updateReferenceField({ entityReferenceMap, locale, gqlParams, + sendMessage, }); } @@ -349,6 +389,7 @@ async function updateSingleRefField({ locale, entityReferenceMap, gqlParams, + sendMessage, }: UpdateFieldProps) { const updatedReference = updateFromEntryEditor?.fields?.[name] as Asset | Entry | undefined; dataFromPreviewApp[name] = await updateReferenceField({ @@ -359,6 +400,7 @@ async function updateSingleRefField({ entityReferenceMap: entityReferenceMap as EntityReferenceMap, locale, gqlParams, + sendMessage, }); } @@ -369,6 +411,7 @@ async function updateMultiRefField({ locale, entityReferenceMap, gqlParams, + sendMessage, }: UpdateFieldProps) { const fieldName = buildCollectionName(name); @@ -387,6 +430,7 @@ async function updateMultiRefField({ entityReferenceMap: entityReferenceMap as EntityReferenceMap, locale, gqlParams, + sendMessage, }); return result; diff --git a/packages/live-preview-sdk/src/helpers/resolveReference.ts b/packages/live-preview-sdk/src/helpers/resolveReference.ts index 10fd489e..ebb034bb 100644 --- a/packages/live-preview-sdk/src/helpers/resolveReference.ts +++ b/packages/live-preview-sdk/src/helpers/resolveReference.ts @@ -1,4 +1,9 @@ -import { EditorEntityStore, RequestedEntitiesMessage } from '@contentful/visual-sdk'; +import { + EditorEntityStore, + PostMessageMethods, + RequestEntitiesMessage, + RequestedEntitiesMessage, +} from '@contentful/visual-sdk'; import type { Asset, Entry } from 'contentful'; import { generateTypeName } from '../graphql/utils'; @@ -6,10 +11,9 @@ import { ASSET_TYPENAME, EntityReferenceMap } from '../types'; const store: Record = {}; -function getStore( - locale: string, - sendMessage: EditorEntityStore['sendMessage'] -): EditorEntityStore { +export type SendMessage = (method: PostMessageMethods, params: RequestEntitiesMessage) => void; + +function getStore(locale: string, sendMessage: SendMessage): EditorEntityStore { if (!store[locale]) { store[locale] = new EditorEntityStore({ entities: [], @@ -41,12 +45,14 @@ export async function resolveReference(info: { entityReferenceMap: EntityReferenceMap; referenceId: string; locale: string; + sendMessage: SendMessage; }): Promise<{ reference: Entry; typeName: string }>; export async function resolveReference(info: { entityReferenceMap: EntityReferenceMap; referenceId: string; isAsset: true; locale: string; + sendMessage: SendMessage; }): Promise<{ reference: Asset; typeName: string }>; /** * Returns the requested reference from @@ -64,7 +70,7 @@ export async function resolveReference({ referenceId: string; isAsset?: boolean; locale: string; - sendMessage: EditorEntityStore['sendMessage']; + sendMessage: SendMessage; }): Promise<{ reference: Entry | Asset; typeName: string }> { const reference = entityReferenceMap.get(referenceId); diff --git a/packages/live-preview-sdk/src/index.ts b/packages/live-preview-sdk/src/index.ts index f4ce24f0..fd1c7f31 100644 --- a/packages/live-preview-sdk/src/index.ts +++ b/packages/live-preview-sdk/src/index.ts @@ -16,8 +16,10 @@ import { InspectorMode } from './inspectorMode'; import { LiveUpdates } from './liveUpdates'; import { ConnectedMessage, + EditorMessage, LivePreviewPostMessageMethods, MessageFromEditor, + PostMessageMethods, UrlChangedMessage, openEntryInEditorUtility, } from './messages'; @@ -61,6 +63,7 @@ export class ContentfulLivePreview { static inspectorModeEnabled = true; static liveUpdatesEnabled = true; static locale: string; + static sendMessage: (method: PostMessageMethods, data: EditorMessage) => void; static targetOrigin: string[]; // Static method to initialize the LivePreview SDK @@ -113,11 +116,11 @@ export class ContentfulLivePreview { // setup the live preview plugins (inspectorMode and liveUpdates) if (this.inspectorModeEnabled) { - this.inspectorMode = new InspectorMode({ locale }); + this.inspectorMode = new InspectorMode({ locale, targetOrigin: this.targetOrigin }); } if (this.liveUpdatesEnabled) { - this.liveUpdates = new LiveUpdates({ locale, origins: this.targetOrigin }); + this.liveUpdates = new LiveUpdates({ locale, targetOrigin: this.targetOrigin }); this.saveEvent = new SaveEvent({ locale }); } diff --git a/packages/live-preview-sdk/src/inspectorMode.ts b/packages/live-preview-sdk/src/inspectorMode.ts index 65b39b80..87b161bf 100644 --- a/packages/live-preview-sdk/src/inspectorMode.ts +++ b/packages/live-preview-sdk/src/inspectorMode.ts @@ -18,11 +18,13 @@ export class InspectorMode { private tooltip: HTMLButtonElement | null = null; // this tooltip scrolls to the correct field in the entry editor private currentElementBesideTooltip: HTMLElement | null = null; // this element helps to position the tooltip private defaultLocale: string; + private targetOrigin: string[]; - constructor({ locale }: { locale: string }) { + constructor({ locale, targetOrigin }: { locale: string; targetOrigin: string[] }) { this.tooltip = null; this.currentElementBesideTooltip = null; this.defaultLocale = locale; + this.targetOrigin = targetOrigin; this.updateTooltipPosition = this.updateTooltipPosition.bind(this); this.addTooltipOnHover = this.addTooltipOnHover.bind(this); @@ -120,7 +122,7 @@ export class InspectorMode { const locale = this.tooltip?.getAttribute(DATA_CURR_LOCALE) || this.defaultLocale; if (fieldId && entryId && locale) { - openEntryInEditorUtility(fieldId, entryId, locale); + openEntryInEditorUtility(fieldId, entryId, locale, this.targetOrigin); } } } diff --git a/packages/live-preview-sdk/src/liveUpdates.ts b/packages/live-preview-sdk/src/liveUpdates.ts index ed96f773..2a66c21a 100644 --- a/packages/live-preview-sdk/src/liveUpdates.ts +++ b/packages/live-preview-sdk/src/liveUpdates.ts @@ -2,9 +2,11 @@ import type { Asset, Entry } from 'contentful'; import type { ContentfulSubscribeConfig, + EditorMessage, EntryUpdatedMessage, ErrorMessage, MessageFromEditor, + PostMessageMethods, SubscribedMessage, } from '.'; import * as gql from './graphql'; @@ -45,11 +47,11 @@ export class LiveUpdates { private subscriptions = new Map(); private storage: StorageMap; private defaultLocale: string; - private targetOrigin: string[]; + private sendMessage: (method: PostMessageMethods, data: EditorMessage) => void; constructor({ locale, targetOrigin }: { locale: string; targetOrigin: string[] }) { this.defaultLocale = locale; - this.targetOrigin = targetOrigin; + this.sendMessage = (method, data) => sendMessageToEditor(method, data, targetOrigin); this.storage = new StorageMap('live-updates', new Map()); window.addEventListener('beforeunload', () => this.clearStorage()); } @@ -78,6 +80,7 @@ export class LiveUpdates { locale, entityReferenceMap, gqlParams, + sendMessage: this.sendMessage, })); return { @@ -98,7 +101,8 @@ export class LiveUpdates { locale, entityReferenceMap, depth, - visitedReferenceMap + visitedReferenceMap, + this.sendMessage ), updated: true, }; @@ -271,7 +275,7 @@ export class LiveUpdates { } private sendErrorMessage(error: ErrorMessage): void { - sendMessageToEditor(LivePreviewPostMessageMethods.ERROR, error, this.targetOrigin); + this.sendMessage(LivePreviewPostMessageMethods.ERROR, error); } /** @@ -311,17 +315,13 @@ export class LiveUpdates { // Tell the editor that there is a subscription // It's possible that the `type` is not 100% accurate as we don't know how it will be merged in the future. - sendMessageToEditor( - LivePreviewPostMessageMethods.SUBSCRIBED, - { - action: LivePreviewPostMessageMethods.SUBSCRIBED, - type: isGQL ? 'GQL' : 'REST', - locale, - entryId: sysId, - event: 'edit', - } as SubscribedMessage, - this.targetOrigin - ); + this.sendMessage(LivePreviewPostMessageMethods.SUBSCRIBED, { + action: LivePreviewPostMessageMethods.SUBSCRIBED, + type: isGQL ? 'GQL' : 'REST', + locale, + entryId: sysId, + event: 'edit', + } as SubscribedMessage); return () => { this.subscriptions.delete(id); diff --git a/packages/live-preview-sdk/src/react.tsx b/packages/live-preview-sdk/src/react.tsx index 0c7489f5..e9cf7622 100644 --- a/packages/live-preview-sdk/src/react.tsx +++ b/packages/live-preview-sdk/src/react.tsx @@ -55,6 +55,7 @@ export function ContentfulLivePreviewProvider({ debugMode = false, enableInspectorMode = true, enableLiveUpdates = true, + targetOrigin, }: PropsWithChildren): ReactElement { if (!locale) { throw new Error( @@ -62,11 +63,17 @@ export function ContentfulLivePreviewProvider({ ); } - ContentfulLivePreview.init({ locale, debugMode, enableInspectorMode, enableLiveUpdates }); + ContentfulLivePreview.init({ + locale, + debugMode, + enableInspectorMode, + enableLiveUpdates, + targetOrigin, + }); const props = useMemo( - () => ({ locale, debugMode, enableInspectorMode, enableLiveUpdates }), - [locale, debugMode, enableInspectorMode, enableLiveUpdates] + () => ({ locale, debugMode, enableInspectorMode, enableLiveUpdates, targetOrigin }), + [locale, debugMode, enableInspectorMode, enableLiveUpdates, targetOrigin] ); return ( @@ -148,7 +155,7 @@ export function useContentfulLiveUpdates( } // or update content through live updates - return ContentfulLivePreview.subscribe({ + return ContentfulLivePreview.subscribe('edit', { data: data as Argument, locale: options.locale, query: options.query, diff --git a/packages/live-preview-sdk/src/rest/__tests__/entities.test.ts b/packages/live-preview-sdk/src/rest/__tests__/entities.test.ts index b4656e90..f3e940bd 100644 --- a/packages/live-preview-sdk/src/rest/__tests__/entities.test.ts +++ b/packages/live-preview-sdk/src/rest/__tests__/entities.test.ts @@ -31,6 +31,7 @@ const asset = assetJSON as unknown as Asset; const dataFromPreviewApp = dataFromPreviewAppJSON as unknown as Entry; describe('Update REST entry', () => { + const sendMessage = vi.fn(); const defaultEntityReferenceMap = new Map([ [newEntryReference.sys.id, newEntryReference], [newAssetReference.sys.id, newAssetReference], @@ -44,6 +45,7 @@ describe('Update REST entry', () => { } as unknown as Entry, ], ]); + beforeEach(() => { (resolveReference as Mock).mockImplementation(async ({ referenceId }) => { return { reference: defaultEntityReferenceMap.get(referenceId) }; @@ -76,7 +78,8 @@ describe('Update REST entry', () => { locale, entityReferenceMap, 0, - visitedReferences + visitedReferences, + sendMessage ); }; diff --git a/packages/live-preview-sdk/src/rest/entities.ts b/packages/live-preview-sdk/src/rest/entities.ts index 88b11559..e6adc5de 100644 --- a/packages/live-preview-sdk/src/rest/entities.ts +++ b/packages/live-preview-sdk/src/rest/entities.ts @@ -2,7 +2,14 @@ import { Asset, Entry } from 'contentful'; import type { WithResourceName } from 'contentful-management'; import { MAX_DEPTH } from '../constants'; -import { debug, clone, isPrimitiveField, resolveReference, updatePrimitiveField } from '../helpers'; +import { + debug, + clone, + isPrimitiveField, + resolveReference, + updatePrimitiveField, + SendMessage, +} from '../helpers'; import { SUPPORTED_RICHTEXT_EMBEDS, isAsset, @@ -36,7 +43,8 @@ async function updateRef( locale: string, entityReferenceMap: EntityReferenceMap, depth: number, - visitedReferenceMap: Map + visitedReferenceMap: Map, + sendMessage: SendMessage ): Promise { let reference; const id = @@ -54,6 +62,7 @@ async function updateRef( referenceId: updateFromEntryEditor.sys.id, ...(isAsset(updateFromEntryEditor) ? { isAsset: true } : undefined), locale, + sendMessage, }); reference = resolvedReference; visitedReferenceMap.set(id, resolvedReference); @@ -79,7 +88,8 @@ async function updateRef( key as keyof Reference['fields'], entityReferenceMap, depth + 1, - visitedReferenceMap + visitedReferenceMap, + sendMessage ); // multi ref fields } else if (Array.isArray(value) && isEntityLink(value[0]) && depth < MAX_DEPTH) { @@ -90,7 +100,8 @@ async function updateRef( key as keyof Reference['fields'], entityReferenceMap, depth + 1, - visitedReferenceMap + visitedReferenceMap, + sendMessage ); // rich text fields } else if (isRichText(value)) { @@ -101,7 +112,8 @@ async function updateRef( locale, entityReferenceMap, depth + 1, - visitedReferenceMap + visitedReferenceMap, + sendMessage ); // single and multi resource link fields } else if (isResourceLink(value) || (Array.isArray(value) && isResourceLink(value[0]))) { @@ -129,7 +141,8 @@ async function updateMultiRefField( name: keyof Reference['fields'], entityReferenceMap: EntityReferenceMap, depth: number, - visitedReferenceMap: Map + visitedReferenceMap: Map, + sendMessage: SendMessage ) { if (!updateFromEntryEditor.fields?.[name]) { delete dataFromPreviewApp.fields[name]; @@ -145,7 +158,8 @@ async function updateMultiRefField( locale, entityReferenceMap, depth + 1, - visitedReferenceMap + visitedReferenceMap, + sendMessage ) ) ).then((list) => list.filter(Boolean))) as Reference[]; @@ -161,7 +175,8 @@ async function updateSingleRefField( name: keyof Reference['fields'], entityReferenceMap: EntityReferenceMap, depth: number, - visitedReferenceMap: Map + visitedReferenceMap: Map, + sendMessage: SendMessage ) { const matchUpdateFromEntryEditor = updateFromEntryEditor?.fields?.[name] as Reference | undefined; @@ -178,7 +193,8 @@ async function updateSingleRefField( locale, entityReferenceMap, depth + 1, - visitedReferenceMap + visitedReferenceMap, + sendMessage ); return dataFromPreviewApp; @@ -189,7 +205,8 @@ async function resolveRichTextLinks( entityReferenceMap: EntityReferenceMap, locale: string, depth: number, - visitedReferenceMap: Map + visitedReferenceMap: Map, + sendMessage: SendMessage ) { if (SUPPORTED_RICHTEXT_EMBEDS.includes(node.nodeType)) { if (node.data && node.data.target && node.data.target.sys) { @@ -205,7 +222,8 @@ async function resolveRichTextLinks( locale, entityReferenceMap, depth + 1, - visitedReferenceMap + visitedReferenceMap, + sendMessage ); } } @@ -218,7 +236,8 @@ async function resolveRichTextLinks( entityReferenceMap, locale, depth + 1, - visitedReferenceMap +visitedReferenceMap, + sendMessage ); } } @@ -231,7 +250,8 @@ async function updateRichTextField( locale: string, entityReferenceMap: EntityReferenceMap, depth: number, - visitedReferenceMap: Map + visitedReferenceMap: Map, + sendMessage: SendMessage ) { const richText = updateFromEntryEditor.fields?.[name]; @@ -240,7 +260,14 @@ async function updateRichTextField( dataFromPreviewApp.fields[name] = richText; // Resolve the linked entries or assets within the rich text field for (const node of richText.content) { - await resolveRichTextLinks(node, entityReferenceMap, locale, depth, visitedReferenceMap); + await resolveRichTextLinks( + node, + entityReferenceMap, + locale, + depth, + visitedReferenceMap, + sendMessage + ); } } } @@ -261,7 +288,8 @@ export async function updateEntity( locale: string, entityReferenceMap: EntityReferenceMap, depth: number, - visitedReferenceMap: Map + visitedReferenceMap: Map, + sendMessage: SendMessage ): Promise { if (dataFromPreviewApp.sys.id !== updateFromEntryEditor.sys.id) { return dataFromPreviewApp; @@ -284,7 +312,8 @@ export async function updateEntity( name as keyof Reference['fields'], entityReferenceMap, depth + 1, - visitedReferenceMap + visitedReferenceMap, + sendMessage ); } else if (field.type === 'Array' && field.items?.type === 'Link' && depth < MAX_DEPTH) { await updateMultiRefField( @@ -294,7 +323,8 @@ export async function updateEntity( name as keyof Reference['fields'], entityReferenceMap, depth + 1, - visitedReferenceMap + visitedReferenceMap, + sendMessage ); } else if (field.type === 'RichText') { await updateRichTextField( @@ -304,7 +334,8 @@ export async function updateEntity( locale, entityReferenceMap, depth, - visitedReferenceMap + visitedReferenceMap, + sendMessage ); } else if (field.type === 'ResourceLink') { //@TODO -- add live updates for resource links diff --git a/packages/live-preview-sdk/src/types.ts b/packages/live-preview-sdk/src/types.ts index 95b5de50..8da34e43 100644 --- a/packages/live-preview-sdk/src/types.ts +++ b/packages/live-preview-sdk/src/types.ts @@ -1,6 +1,8 @@ import type { Asset, Entry } from 'contentful'; import type { ContentTypeProps } from 'contentful-management'; +import { SendMessage } from './helpers'; + export type ContentType = ContentTypeProps; export const ASSET_TYPENAME = 'Asset'; @@ -63,6 +65,7 @@ export type UpdateEntryProps = { locale: string; entityReferenceMap: EntityReferenceMap; gqlParams?: GraphQLParams; + sendMessage: SendMessage; }; export type UpdateFieldProps = { @@ -72,6 +75,7 @@ export type UpdateFieldProps = { locale: string; entityReferenceMap: EntityReferenceMap; gqlParams?: GraphQLParams; + sendMessage: SendMessage; }; export type UpdateReferenceFieldProps = { @@ -80,6 +84,7 @@ export type UpdateReferenceFieldProps = { entityReferenceMap: EntityReferenceMap; locale: string; gqlParams?: GraphQLParams; + sendMessage: SendMessage; }; /**