Skip to content
Merged

Dev #980

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions api/src/services/aem.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1355,15 +1355,20 @@ const createEntry = async ({
for await (const [locale, entries] of entriesLocale) {
for (const entry of entries) {
const flatData = deepFlattenObject(entry);
const km = keyMapper as Record<string, string> | undefined;
for (const [key, value] of Object.entries(flatData)) {
if (key.endsWith('._content_type_uid') && typeof value === 'string') {
const uidField = key?.replace('._content_type_uid', '');
const refs: string[] = entryMapping?.[value];
const mappedCtUid = km?.[value] && km[value] !== '' ? km[value] : value;
if (mappedCtUid !== value) {
_.set(entry, key, mappedCtUid);
}
const refs: string[] = entryMapping?.[mappedCtUid];

if (refs?.length) {
_.set(entry, `${uidField}.uid`, refs?.[0]);
} else {
console.info(`No entry found for content type: ${value}`);
console.info(`No entry found for content type: ${mappedCtUid}`);
}
}
}
Expand Down
40 changes: 30 additions & 10 deletions api/src/utils/content-type-creator.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,27 @@ const uidCorrector = ({ uid } : {uid : string}) => {
return newUid;
};

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

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

const getCleanUid = (uid: string): string => {
Expand Down Expand Up @@ -155,7 +174,7 @@ function buildFieldSchema(item: any, marketPlacePath: string, parentUid = ''): a
const blockElements = blockItem?.schema || [];
for (const element of blockElements) {
if (element?.isDeleted === false) {
const fieldSchema = buildFieldSchema(element, marketPlacePath, '');
const fieldSchema = buildFieldSchema(element, marketPlacePath, '', keyMapper);
if (fieldSchema) blockSchema.push(fieldSchema);
}
}
Expand Down Expand Up @@ -186,7 +205,7 @@ function buildFieldSchema(item: any, marketPlacePath: string, parentUid = ''): a

for (const element of elements) {
if (element?.isDeleted === false) {
const fieldSchema = buildFieldSchema(element, marketPlacePath, '');
const fieldSchema = buildFieldSchema(element, marketPlacePath, '', keyMapper);
if (fieldSchema) groupSchema.push(fieldSchema);
}
}
Expand All @@ -210,7 +229,8 @@ function buildFieldSchema(item: any, marketPlacePath: string, parentUid = ''): a
title: item?.display_name || rawUid, // Keep original for display
uid: itemUid // Snake case uid
},
marketPlacePath
marketPlacePath,
keyMapper
});
}

Expand Down Expand Up @@ -470,10 +490,10 @@ export const convertToSchemaFormate = ({ field, advanced = false, marketPlacePat
"error_messages": {
"format": field?.advanced?.validationErrorMessage ?? '',
},
"reference_to": field?.advanced?.embedObjects?.length ? [
"reference_to": field?.advanced?.embedObjects?.length ? remapReferenceUids([
"sys_assets",
...field?.advanced?.embedObjects?.map?.((item: any) => uidCorrector({ uid: item })) ?? [],
] : [
], keyMapper) : [
"sys_assets"
],
"multiple": field?.advanced?.multiple ?? false,
Expand Down Expand Up @@ -736,7 +756,7 @@ export const convertToSchemaFormate = ({ field, advanced = false, marketPlacePat
return {
"data_type": "global_field",
"display_name": field?.title,
"reference_to": field?.refrenceTo ?? [],
"reference_to": remapReferenceUids(field?.refrenceTo ?? [], keyMapper),
"uid": cleanedUid,
"mandatory": field?.advanced?.mandatory ?? false,
"multiple": field?.advanced?.multiple ?? false,
Expand All @@ -748,7 +768,7 @@ export const convertToSchemaFormate = ({ field, advanced = false, marketPlacePat
return {
data_type: "reference",
display_name: field?.title,
reference_to: field?.refrenceTo ?? [],
reference_to: remapReferenceUids(field?.refrenceTo ?? [], keyMapper),
field_metadata: {
ref_multiple: true,
ref_multiple_content_types: true
Expand Down Expand Up @@ -816,7 +836,7 @@ export const convertToSchemaFormate = ({ field, advanced = false, marketPlacePat
"mandatory": field?.advanced?.mandatory ?? false,
"unique": field?.advanced?.unique ?? false,
"non_localizable": field.advanced?.nonLocalizable ?? false,
"reference_to": field?.advanced?.embedObjects?.length ? field?.advanced?.embedObjects?.map?.((item: any) => uidCorrector({ uid: item })) : []
"reference_to": field?.advanced?.embedObjects?.length ? remapReferenceUids(field?.advanced?.embedObjects?.map?.((item: any) => uidCorrector({ uid: item })), keyMapper) : []
}
if ((field?.advanced?.embedObjects?.length === undefined) ||
(field?.advanced?.embedObjects?.length === 0) ||
Expand Down Expand Up @@ -1177,7 +1197,7 @@ export const contenTypeMaker = async ({ contentType, destinationStackId, project
for (const item of ctData) {
if (item?.isDeleted === true) continue;

const fieldSchema = buildFieldSchema(item, marketPlacePath, '');
const fieldSchema = buildFieldSchema(item, marketPlacePath, '', keyMapper);
if (fieldSchema) {
ct?.schema.push(fieldSchema);
}
Expand Down
73 changes: 46 additions & 27 deletions ui/src/components/ContentMapper/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1450,31 +1450,48 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref:
)

if (groupArray?.[0]?.child && previousSelectedValue !== selectedValue?.label && groupArray?.[0]?.uid === rowIndex) {
for (const item of groupArray?.[0]?.child ?? []) {
deletedExstingField[item?.backupFieldUid] = {
label: item?.uid,
value: existingField[item?.backupFieldUid]

}
setIsFieldDeleted(true);
const index = selectedOptions?.indexOf(existingField[item?.backupFieldUid]?.value?.label);

if (index > -1) {
selectedOptions?.splice(index, 1);
}
delete existingField[item?.backupFieldUid]

}
const collectAllDescendants = (
children: FieldMapType[],
visited: Set<FieldMapType> = new Set<FieldMapType>()
): FieldMapType[] => {
return children.flatMap((child) => {
if (!child || visited.has(child)) {
return [];
}
visited.add(child);
return [
child,
...collectAllDescendants(child?.child ?? [], visited)
];
});
};

const allDescendants = collectAllDescendants(groupArray[0].child);
const labelsToRemove = new Set<string>(
allDescendants
.map((item) => existingField[item?.backupFieldUid]?.label)
.filter(Boolean) as string[]
);

setExistingField((prev) => {
const next = { ...prev };
allDescendants.forEach((item) => delete next[item?.backupFieldUid]);
next[backupFieldUid] = { label: selectedValue?.label, value: selectedValue?.value };
return next;
});

setIsFieldDeleted(true);

setSelectedOptions((prev) => prev.filter((opt) => !labelsToRemove.has(opt)));
}
else {
setIsFieldDeleted(false);
setExistingField((prevOptions: ExistingFieldType) => ({
...prevOptions,
[backupFieldUid]: { label: selectedValue?.label, value: selectedValue?.value }
}));
}

setExistingField((prevOptions: ExistingFieldType) => ({
...prevOptions,
[backupFieldUid]: { label: selectedValue?.label, value: selectedValue?.value }
}));

//add selected option to array if it is not mapped to any other field
setSelectedOptions((prevSelected) => {
const newSelectedOptions = prevSelected?.filter(
Expand Down Expand Up @@ -2012,18 +2029,20 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref:
const OptionsForRow: OptionsType[] = [];

// If OtherContentType label and contentModels are present, set the contentTypeSchema
let resolvedSchema = contentTypeSchema;
if (otherContentType?.label && contentModels) {
const ContentType: ContentTypeList | undefined = contentModels?.find(
({ title }) => title === otherContentType?.label
);
setContentTypeSchema(ContentType?.schema);
resolvedSchema = ContentType?.schema;
setContentTypeSchema(resolvedSchema);
}

if (contentTypeSchema && validateArray(contentTypeSchema)) {
if (resolvedSchema && validateArray(resolvedSchema)) {
const fieldTypeToMatch = Fields[data?.backupFieldType as keyof Mapping]?.type;

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

// If no exact match, process schema including modular blocks
if (OptionsForRow?.length === 0) {
for (const value of contentTypeSchema) {
for (const value of resolvedSchema) {
const groupArray = nestedList.filter(item =>
item?.child?.some(e => e?.id === data?.id)
);
Expand All @@ -2053,7 +2072,7 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref:
processSchema(value, data, array, groupArray, OptionsForRow, fieldsOfContentstack);
}
// Process leaf fields
else if (!array?.some(item => item?.id === data?.id) && checkConditions(fieldTypeToMatch, value, data) && !parentBlock) {
else if (!array?.some(item => item?.id === data?.id) && checkConditions(fieldTypeToMatch, value, data) && !parentBlock?.length) {
OptionsForRow.push(getMatchingOption(value, true, value?.display_name || '', value?.uid ?? ''));
}
}
Expand Down Expand Up @@ -2165,7 +2184,7 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref:
isDisabled: false
};

const adjustedOptions: OptionsType[] | OptionsType = (OptionsForRow.length === 0 && !contentTypeSchema) ? option :
const adjustedOptions: OptionsType[] | OptionsType = (OptionsForRow.length === 0 && !resolvedSchema) ? option :
(OptionsForRow?.length > 0 && OptionsForRow?.every((item) => item?.isDisabled) && OptionValue?.label === Fields[data?.contentstackFieldType]?.label) ? []
: OptionsForRow.map((option: OptionsType) => ({
...option,
Expand Down Expand Up @@ -2213,7 +2232,7 @@ const ContentMapper = forwardRef(({ handleStepChange }: contentMapperProps, ref:
>
<Button
buttonType="light"
disabled={(contentTypeSchema && existingField[data?.backupFieldUid]) || newMigrationData?.project_current_step > 4}
disabled={(resolvedSchema && existingField[data?.backupFieldUid]) || newMigrationData?.project_current_step > 4}
onClick={() => {
handleAdvancedSetting(initialOption?.label, data?.advanced || {}, data?.uid, data);
}}
Expand Down