Skip to content

Commit

Permalink
refactor(nested-updates): move depth handling around and decrease dep…
Browse files Browse the repository at this point in the history
…th for richtext
  • Loading branch information
chrishelgert committed Oct 27, 2023
1 parent 8e3daba commit a73451d
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 73 deletions.
1 change: 1 addition & 0 deletions packages/live-preview-sdk/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const TOOLTIP_HEIGHT = 32;
export const TOOLTIP_PADDING_LEFT = 5;

export const MAX_DEPTH = 10;
export const MAX_RTE_DEPTH = 2;

export const LIVE_PREVIEW_EDITOR_SOURCE = 'live-preview-editor' as const;
export const LIVE_PREVIEW_SDK_SOURCE = 'live-preview-sdk' as const;
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { SysProps, Entity, ContentType, GetStore } from '../../types';
import { updateEntry } from '../entries';
import defaultContentTypeJSON from './fixtures/contentType.json';
import entry from './fixtures/entry.json';
import { MAX_DEPTH } from '../../constants';

const EN = 'en-US';

Expand Down Expand Up @@ -58,7 +59,7 @@ describe('Update GraphQL Entry', () => {
updateFromEntryEditor: update,
locale,
getStore,
depth: 0,
maxDepth: MAX_DEPTH,
});
};

Expand Down
89 changes: 48 additions & 41 deletions packages/live-preview-sdk/src/graphql/entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
import { updateAsset } from './assets';
import { isRelevantField, updateAliasedInformation } from './queryUtils';
import { buildCollectionName, generateTypeName } from './utils';
import { MAX_DEPTH } from '../constants';
import { MAX_RTE_DEPTH } from '../constants';

/**
* Updates GraphQL response data based on CMA entry object
Expand All @@ -33,6 +33,7 @@ export async function updateEntry({
contentType,
dataFromPreviewApp,
updateFromEntryEditor,
maxDepth,
...props
}: UpdateEntryProps): Promise<Entity & { sys: SysProps }> {
if (dataFromPreviewApp.sys.id !== updateFromEntryEditor.sys.id) {
Expand All @@ -56,20 +57,23 @@ export async function updateEntry({
dataFromPreviewApp: copyOfDataFromPreviewApp,
updateFromEntryEditor,
name,
maxDepth: MAX_RTE_DEPTH,
});
} else if (field.type === 'Link') {
await updateSingleRefField({
...props,
dataFromPreviewApp: copyOfDataFromPreviewApp,
updateFromEntryEditor,
name,
maxDepth: maxDepth - 1,
});
} else if (field.type === 'Array' && field.items?.type === 'Link') {
await updateMultiRefField({
...props,
dataFromPreviewApp: copyOfDataFromPreviewApp,
updateFromEntryEditor,
name,
maxDepth: maxDepth - 1,
});
}
}
Expand Down Expand Up @@ -100,7 +104,7 @@ async function processNode({
locale: string;
getStore: GetStore;
gqlParams?: GraphQLParams;
depth: number;
maxDepth: number;
}) {
// Check if the node is an embedded entity
if (SUPPORTED_RICHTEXT_EMBEDS.includes(node.nodeType)) {
Expand Down Expand Up @@ -173,7 +177,7 @@ async function processRichTextField({
locale: string;
getStore: GetStore;
gqlParams?: GraphQLParams;
depth: number;
maxDepth: number;
}): Promise<{ entries: RichTextLink; assets: RichTextLink }> {
const entries: RichTextLink = { block: [], inline: [], hyperlink: [] };
const assets: RichTextLink = { block: [], inline: [], hyperlink: [] };
Expand Down Expand Up @@ -202,7 +206,7 @@ async function updateRichTextField({
locale,
gqlParams,
getStore,
depth,
maxDepth,
}: UpdateFieldProps) {
if (!dataFromPreviewApp[name]) {
dataFromPreviewApp[name] = {};
Expand All @@ -218,7 +222,7 @@ async function updateRichTextField({
locale,
getStore,
gqlParams,
depth,
maxDepth,
});
}

Expand Down Expand Up @@ -247,8 +251,24 @@ async function updateReferenceAssetField({
);
}

function isInDepthLimit(depth: number, gqlParams?: GraphQLParams): boolean {
return !!gqlParams || depth < MAX_DEPTH;
function isInDepthLimit(entityId: string, maxDepth: number, gqlParams?: GraphQLParams): boolean {
if (gqlParams) {
return true;
}

if (maxDepth > 0) {
return true;
}

debug.log(
'Max update depth is reached, please provide the GraphQL query if you need deeper nested information.',
{ entityId }
);
return false;
}

function getRichTextDepth(maxDepth: number) {
return Math.min(maxDepth - 1, MAX_RTE_DEPTH);
}

async function updateReferenceEntryField({
Expand All @@ -257,7 +277,7 @@ async function updateReferenceEntryField({
locale,
gqlParams,
getStore,
depth,
maxDepth,
}: SetOptional<Required<UpdateReferenceFieldProps>, 'gqlParams'>) {
const { reference, typeName } = await resolveReference({
referenceId: updatedReference.sys.id,
Expand Down Expand Up @@ -287,12 +307,12 @@ async function updateReferenceEntryField({
richTextNode: value,
locale,
gqlParams,
depth,
maxDepth: getRichTextDepth(maxDepth),
getStore,
});
}

if ('sys' in value && isInDepthLimit(depth, gqlParams)) {
if ('sys' in value && isInDepthLimit(updatedReference.sys.id, maxDepth, gqlParams)) {
// single reference
merged[key] = value;
await updateSingleRefField({
Expand All @@ -302,10 +322,14 @@ async function updateReferenceEntryField({
name: key,
gqlParams,
getStore,
depth: depth + 1,
maxDepth: maxDepth - 1,
});
}
} else if (Array.isArray(value) && value[0]?.sys && isInDepthLimit(depth, gqlParams)) {
} else if (
Array.isArray(value) &&
value[0]?.sys &&
isInDepthLimit(updatedReference.sys.id, maxDepth, gqlParams)
) {
// multi references
const name = buildCollectionName(key);
merged[name] = { items: value };
Expand All @@ -316,7 +340,7 @@ async function updateReferenceEntryField({
name: key,
gqlParams,
getStore,
depth: depth + 1,
maxDepth: maxDepth - 1,
});
} else {
// primitive fields
Expand All @@ -330,10 +354,7 @@ async function updateReferenceEntryField({
async function updateReferenceField({
referenceFromPreviewApp,
updatedReference,
locale,
gqlParams,
getStore,
depth,
...props
}: UpdateReferenceFieldProps) {
if (!updatedReference) {
return null;
Expand All @@ -350,55 +371,43 @@ async function updateReferenceField({

if (isAsset(updatedReference)) {
return updateReferenceAssetField({
...props,
referenceFromPreviewApp,
updatedReference,
locale,
gqlParams,
getStore,
depth,
});
}

return updateReferenceEntryField({
...props,
referenceFromPreviewApp,
updatedReference,
locale,
gqlParams,
getStore,
depth,
});
}

async function updateSingleRefField({
dataFromPreviewApp,
updateFromEntryEditor,
name,
locale,
gqlParams,
getStore,
depth,
maxDepth,
...props
}: UpdateFieldProps) {
const updatedReference = updateFromEntryEditor?.fields?.[name] as Asset | Entry | undefined;
dataFromPreviewApp[name] = await updateReferenceField({
...props,
referenceFromPreviewApp: dataFromPreviewApp[name] as Entry & {
__typename?: string;
},
updatedReference,
locale,
gqlParams,
getStore,
depth,
maxDepth: maxDepth - 1,
});
}

async function updateMultiRefField({
dataFromPreviewApp,
updateFromEntryEditor,
name,
locale,
gqlParams,
getStore,
depth,
maxDepth,
...props
}: UpdateFieldProps) {
const fieldName = buildCollectionName(name);

Expand All @@ -410,14 +419,12 @@ async function updateMultiRefField({
)?.items?.find((item) => item.sys.id === updatedItem.sys.id);

const result = await updateReferenceField({
...props,
referenceFromPreviewApp: itemFromPreviewApp as unknown as Entry & {
__typename?: string;
},
updatedReference: updatedItem,
locale,
gqlParams,
getStore,
depth,
maxDepth: maxDepth - 1,
});

return result;
Expand Down
6 changes: 4 additions & 2 deletions packages/live-preview-sdk/src/helpers/resolveReference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ export async function resolveReference({
locale: string;
getStore: GetStore;
}): Promise<{ reference: Entry | Asset; typeName: string }> {
const store = getStore(locale);

if (isAsset) {
const result = await getStore(locale).fetchAsset(referenceId);
const result = await store.fetchAsset(referenceId);
if (!result) {
throw new Error(`Unknown reference ${referenceId}`);
}
Expand All @@ -42,7 +44,7 @@ export async function resolveReference({
};
}

const result = await getStore(locale).fetchEntry(referenceId);
const result = await store.fetchEntry(referenceId);
if (!result) {
throw new Error(`Unknown reference ${referenceId}`);
}
Expand Down
8 changes: 4 additions & 4 deletions packages/live-preview-sdk/src/liveUpdates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
GraphQLParams,
} from './types';
import { EditorEntityStore } from '@contentful/visual-sdk';
import { MAX_DEPTH } from './constants';

interface MergeEntityProps {
dataFromPreviewApp: Entity;
Expand Down Expand Up @@ -54,6 +55,7 @@ export class LiveUpdates {
this.defaultLocale = locale;
this.sendMessage = (method, data) => sendMessageToEditor(method, data, targetOrigin);
this.storage = new StorageMap<Entity>('live-updates', new Map());
this.getStore = this.getStore.bind(this);
window.addEventListener('beforeunload', () => this.clearStorage());
}

Expand Down Expand Up @@ -97,8 +99,6 @@ export class LiveUpdates {
data: Entity;
updated: boolean;
}> {
const depth = 0;

if ('__typename' in dataFromPreviewApp) {
// GraphQL
const data = await (dataFromPreviewApp.__typename === 'Asset'
Expand All @@ -109,7 +109,7 @@ export class LiveUpdates {
updateFromEntryEditor: updateFromEntryEditor as Entry,
locale,
gqlParams,
depth,
maxDepth: MAX_DEPTH,
getStore: this.getStore,
}));

Expand All @@ -127,7 +127,7 @@ export class LiveUpdates {
dataFromPreviewApp as Entry,
updateFromEntryEditor as Entry,
locale,
depth,
MAX_DEPTH,
this.getStore
),
updated: true,
Expand Down
Loading

0 comments on commit a73451d

Please sign in to comment.