Skip to content

Commit 99c22e9

Browse files
authored
Merge branch 'dev' into feat/add-unit-tests
2 parents 3802bd0 + 4aca51a commit 99c22e9

File tree

3 files changed

+84
-40
lines changed

3 files changed

+84
-40
lines changed

api/src/services/aem.service.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,15 +1355,20 @@ const createEntry = async ({
13551355
for await (const [locale, entries] of entriesLocale) {
13561356
for (const entry of entries) {
13571357
const flatData = deepFlattenObject(entry);
1358+
const km = keyMapper as Record<string, string> | undefined;
13581359
for (const [key, value] of Object.entries(flatData)) {
13591360
if (key.endsWith('._content_type_uid') && typeof value === 'string') {
13601361
const uidField = key?.replace('._content_type_uid', '');
1361-
const refs: string[] = entryMapping?.[value];
1362+
const mappedCtUid = km?.[value] && km[value] !== '' ? km[value] : value;
1363+
if (mappedCtUid !== value) {
1364+
_.set(entry, key, mappedCtUid);
1365+
}
1366+
const refs: string[] = entryMapping?.[mappedCtUid];
13621367

13631368
if (refs?.length) {
13641369
_.set(entry, `${uidField}.uid`, refs?.[0]);
13651370
} else {
1366-
console.info(`No entry found for content type: ${value}`);
1371+
console.info(`No entry found for content type: ${mappedCtUid}`);
13671372
}
13681373
}
13691374
}

api/src/utils/content-type-creator.utils.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,27 @@ const uidCorrector = ({ uid } : {uid : string}) => {
101101
return newUid;
102102
};
103103

104+
/**
105+
* Remap an array of reference UIDs using a mapping table.
106+
*
107+
* @param uids - The original reference UIDs.
108+
* @param keyMapper - A map from UID to new UID. Callers should prefer using
109+
* the *corrected* UID (i.e. the result of `uidCorrector({ uid })`) as the key.
110+
* For backward compatibility, this function also supports maps keyed by the
111+
* original UID, and will try both forms when looking up each entry.
112+
*
113+
* NOTE: Relying on mixed key styles (some original, some corrected) can hide
114+
* inconsistent UID formatting. When both key styles are present for the same
115+
* logical UID and map to different targets, a warning is logged so that such
116+
* issues do not go unnoticed.
117+
* @returns The remapped UIDs.
118+
*/
119+
function remapReferenceUids(uids: string[], keyMapper?: Record<string, string>): string[] {
120+
if (!keyMapper || !Object.keys(keyMapper).length) return uids;
121+
return uids.map(uid => keyMapper[uid] ?? keyMapper[uidCorrector({ uid })] ?? uid);
122+
}
104123

105-
function buildFieldSchema(item: any, marketPlacePath: string, parentUid = ''): any {
124+
function buildFieldSchema(item: any, marketPlacePath: string, parentUid = '', keyMapper?: Record<string, string>): any {
106125
if (item?.isDeleted === true) return null;
107126

108127
const getCleanUid = (uid: string): string => {
@@ -155,7 +174,7 @@ function buildFieldSchema(item: any, marketPlacePath: string, parentUid = ''): a
155174
const blockElements = blockItem?.schema || [];
156175
for (const element of blockElements) {
157176
if (element?.isDeleted === false) {
158-
const fieldSchema = buildFieldSchema(element, marketPlacePath, '');
177+
const fieldSchema = buildFieldSchema(element, marketPlacePath, '', keyMapper);
159178
if (fieldSchema) blockSchema.push(fieldSchema);
160179
}
161180
}
@@ -186,7 +205,7 @@ function buildFieldSchema(item: any, marketPlacePath: string, parentUid = ''): a
186205

187206
for (const element of elements) {
188207
if (element?.isDeleted === false) {
189-
const fieldSchema = buildFieldSchema(element, marketPlacePath, '');
208+
const fieldSchema = buildFieldSchema(element, marketPlacePath, '', keyMapper);
190209
if (fieldSchema) groupSchema.push(fieldSchema);
191210
}
192211
}
@@ -210,7 +229,8 @@ function buildFieldSchema(item: any, marketPlacePath: string, parentUid = ''): a
210229
title: item?.display_name || rawUid, // Keep original for display
211230
uid: itemUid // Snake case uid
212231
},
213-
marketPlacePath
232+
marketPlacePath,
233+
keyMapper
214234
});
215235
}
216236

@@ -470,10 +490,10 @@ export const convertToSchemaFormate = ({ field, advanced = false, marketPlacePat
470490
"error_messages": {
471491
"format": field?.advanced?.validationErrorMessage ?? '',
472492
},
473-
"reference_to": field?.advanced?.embedObjects?.length ? [
493+
"reference_to": field?.advanced?.embedObjects?.length ? remapReferenceUids([
474494
"sys_assets",
475495
...field?.advanced?.embedObjects?.map?.((item: any) => uidCorrector({ uid: item })) ?? [],
476-
] : [
496+
], keyMapper) : [
477497
"sys_assets"
478498
],
479499
"multiple": field?.advanced?.multiple ?? false,
@@ -736,7 +756,7 @@ export const convertToSchemaFormate = ({ field, advanced = false, marketPlacePat
736756
return {
737757
"data_type": "global_field",
738758
"display_name": field?.title,
739-
"reference_to": field?.refrenceTo ?? [],
759+
"reference_to": remapReferenceUids(field?.refrenceTo ?? [], keyMapper),
740760
"uid": cleanedUid,
741761
"mandatory": field?.advanced?.mandatory ?? false,
742762
"multiple": field?.advanced?.multiple ?? false,
@@ -748,7 +768,7 @@ export const convertToSchemaFormate = ({ field, advanced = false, marketPlacePat
748768
return {
749769
data_type: "reference",
750770
display_name: field?.title,
751-
reference_to: field?.refrenceTo ?? [],
771+
reference_to: remapReferenceUids(field?.refrenceTo ?? [], keyMapper),
752772
field_metadata: {
753773
ref_multiple: true,
754774
ref_multiple_content_types: true
@@ -816,7 +836,7 @@ export const convertToSchemaFormate = ({ field, advanced = false, marketPlacePat
816836
"mandatory": field?.advanced?.mandatory ?? false,
817837
"unique": field?.advanced?.unique ?? false,
818838
"non_localizable": field.advanced?.nonLocalizable ?? false,
819-
"reference_to": field?.advanced?.embedObjects?.length ? field?.advanced?.embedObjects?.map?.((item: any) => uidCorrector({ uid: item })) : []
839+
"reference_to": field?.advanced?.embedObjects?.length ? remapReferenceUids(field?.advanced?.embedObjects?.map?.((item: any) => uidCorrector({ uid: item })), keyMapper) : []
820840
}
821841
if ((field?.advanced?.embedObjects?.length === undefined) ||
822842
(field?.advanced?.embedObjects?.length === 0) ||
@@ -1177,7 +1197,7 @@ export const contenTypeMaker = async ({ contentType, destinationStackId, project
11771197
for (const item of ctData) {
11781198
if (item?.isDeleted === true) continue;
11791199

1180-
const fieldSchema = buildFieldSchema(item, marketPlacePath, '');
1200+
const fieldSchema = buildFieldSchema(item, marketPlacePath, '', keyMapper);
11811201
if (fieldSchema) {
11821202
ct?.schema.push(fieldSchema);
11831203
}

ui/src/components/ContentMapper/index.tsx

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,31 +1450,48 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref:
14501450
)
14511451

14521452
if (groupArray?.[0]?.child && previousSelectedValue !== selectedValue?.label && groupArray?.[0]?.uid === rowIndex) {
1453-
for (const item of groupArray?.[0]?.child ?? []) {
1454-
deletedExstingField[item?.backupFieldUid] = {
1455-
label: item?.uid,
1456-
value: existingField[item?.backupFieldUid]
1457-
1458-
}
1459-
setIsFieldDeleted(true);
1460-
const index = selectedOptions?.indexOf(existingField[item?.backupFieldUid]?.value?.label);
1461-
1462-
if (index > -1) {
1463-
selectedOptions?.splice(index, 1);
1464-
}
1465-
delete existingField[item?.backupFieldUid]
1466-
1467-
}
1453+
const collectAllDescendants = (
1454+
children: FieldMapType[],
1455+
visited: Set<FieldMapType> = new Set<FieldMapType>()
1456+
): FieldMapType[] => {
1457+
return children.flatMap((child) => {
1458+
if (!child || visited.has(child)) {
1459+
return [];
1460+
}
1461+
visited.add(child);
1462+
return [
1463+
child,
1464+
...collectAllDescendants(child?.child ?? [], visited)
1465+
];
1466+
});
1467+
};
1468+
1469+
const allDescendants = collectAllDescendants(groupArray[0].child);
1470+
const labelsToRemove = new Set<string>(
1471+
allDescendants
1472+
.map((item) => existingField[item?.backupFieldUid]?.label)
1473+
.filter(Boolean) as string[]
1474+
);
1475+
1476+
setExistingField((prev) => {
1477+
const next = { ...prev };
1478+
allDescendants.forEach((item) => delete next[item?.backupFieldUid]);
1479+
next[backupFieldUid] = { label: selectedValue?.label, value: selectedValue?.value };
1480+
return next;
1481+
});
1482+
1483+
setIsFieldDeleted(true);
1484+
1485+
setSelectedOptions((prev) => prev.filter((opt) => !labelsToRemove.has(opt)));
14681486
}
14691487
else {
14701488
setIsFieldDeleted(false);
1489+
setExistingField((prevOptions: ExistingFieldType) => ({
1490+
...prevOptions,
1491+
[backupFieldUid]: { label: selectedValue?.label, value: selectedValue?.value }
1492+
}));
14711493
}
14721494

1473-
setExistingField((prevOptions: ExistingFieldType) => ({
1474-
...prevOptions,
1475-
[backupFieldUid]: { label: selectedValue?.label, value: selectedValue?.value }
1476-
}));
1477-
14781495
//add selected option to array if it is not mapped to any other field
14791496
setSelectedOptions((prevSelected) => {
14801497
const newSelectedOptions = prevSelected?.filter(
@@ -2012,18 +2029,20 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref:
20122029
const OptionsForRow: OptionsType[] = [];
20132030

20142031
// If OtherContentType label and contentModels are present, set the contentTypeSchema
2032+
let resolvedSchema = contentTypeSchema;
20152033
if (otherContentType?.label && contentModels) {
20162034
const ContentType: ContentTypeList | undefined = contentModels?.find(
20172035
({ title }) => title === otherContentType?.label
20182036
);
2019-
setContentTypeSchema(ContentType?.schema);
2037+
resolvedSchema = ContentType?.schema;
2038+
setContentTypeSchema(resolvedSchema);
20202039
}
20212040

2022-
if (contentTypeSchema && validateArray(contentTypeSchema)) {
2041+
if (resolvedSchema && validateArray(resolvedSchema)) {
20232042
const fieldTypeToMatch = Fields[data?.backupFieldType as keyof Mapping]?.type;
20242043

20252044
// Check for UID match first
2026-
for (const value of contentTypeSchema) {
2045+
for (const value of resolvedSchema) {
20272046
if (data?.uid === value?.uid && data?.backupFieldType === value?.data_type && fieldTypeToMatch) {
20282047
OptionsForRow.push({ label: value?.display_name, value, isDisabled: false });
20292048
break;
@@ -2032,7 +2051,7 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref:
20322051

20332052
// If no exact match, process schema including modular blocks
20342053
if (OptionsForRow?.length === 0) {
2035-
for (const value of contentTypeSchema) {
2054+
for (const value of resolvedSchema) {
20362055
const groupArray = nestedList.filter(item =>
20372056
item?.child?.some(e => e?.id === data?.id)
20382057
);
@@ -2053,7 +2072,7 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref:
20532072
processSchema(value, data, array, groupArray, OptionsForRow, fieldsOfContentstack);
20542073
}
20552074
// Process leaf fields
2056-
else if (!array?.some(item => item?.id === data?.id) && checkConditions(fieldTypeToMatch, value, data) && !parentBlock) {
2075+
else if (!array?.some(item => item?.id === data?.id) && checkConditions(fieldTypeToMatch, value, data) && !parentBlock?.length) {
20572076
OptionsForRow.push(getMatchingOption(value, true, value?.display_name || '', value?.uid ?? ''));
20582077
}
20592078
}
@@ -2165,14 +2184,14 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref:
21652184
isDisabled: false
21662185
};
21672186

2168-
const adjustedOptions: OptionsType[] | OptionsType = (OptionsForRow.length === 0 && !contentTypeSchema) ? option :
2187+
const adjustedOptions: OptionsType[] | OptionsType = (OptionsForRow.length === 0 && !resolvedSchema) ? option :
21692188
(OptionsForRow?.length > 0 && OptionsForRow?.every((item) => item?.isDisabled) && OptionValue?.label === Fields[data?.contentstackFieldType]?.label) ? []
21702189
: OptionsForRow.map((option: OptionsType) => ({
21712190
...option,
21722191
isDisabled: selectedOptions?.includes?.(option?.label ?? '')
21732192
}));
21742193

2175-
const isTypeMatch = checkConditions(Fields[data?.contentstackFieldType]?.type?.toLowerCase(), existingField[data?.backupFieldUid]?.value, data);
2194+
const isTypeMatch = checkConditions(Fields[data?.contentstackFieldType]?.type, existingField[data?.backupFieldUid]?.value, data);
21762195

21772196
return (
21782197
<div className="table-row">
@@ -2213,7 +2232,7 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref:
22132232
>
22142233
<Button
22152234
buttonType="light"
2216-
disabled={(contentTypeSchema && existingField[data?.backupFieldUid]) || newMigrationData?.project_current_step > 4}
2235+
disabled={(resolvedSchema && existingField[data?.backupFieldUid]) || newMigrationData?.project_current_step > 4}
22172236
onClick={() => {
22182237
handleAdvancedSetting(initialOption?.label, data?.advanced || {}, data?.uid, data);
22192238
}}

0 commit comments

Comments
 (0)