diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index c14b60ddc..49c06631d 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -51,7 +51,7 @@ const putTestData = async (req: Request) => { const id = field?.id?.replace(/[{}]/g, "")?.toLowerCase() || uuidv4(); field.id = id; fieldIds.push(id); - return { id, projectId, isDeleted: true, ...field }; + return { id, projectId, isDeleted: false, ...field }; }); FieldMapperModel.update((data: any) => { data.field_mapper = [...(data?.field_mapper ?? []), ...fields]; @@ -419,7 +419,7 @@ const updateContentType = async (req: Request) => { if (fieldIndex > -1 && field?.ContentstackFieldType !== "") { FieldMapperModel.update((data: any) => { data.field_mapper[fieldIndex] = field; - data.field_mapper[fieldIndex].isDeleted = false; + //data.field_mapper[fieldIndex].isDeleted = false; }); } }); diff --git a/ui/src/components/AdvancePropertise/advanceProperties.interface.ts b/ui/src/components/AdvancePropertise/advanceProperties.interface.ts index 0e5a15db0..e116709d9 100644 --- a/ui/src/components/AdvancePropertise/advanceProperties.interface.ts +++ b/ui/src/components/AdvancePropertise/advanceProperties.interface.ts @@ -116,6 +116,8 @@ export interface UpdatedSettings { * Indicates whether the component is non-localizable. */ NonLocalizable?: boolean; + + Multiple?: boolean } /** diff --git a/ui/src/components/AdvancePropertise/index.tsx b/ui/src/components/AdvancePropertise/index.tsx index 060d9f937..23b5a1e72 100644 --- a/ui/src/components/AdvancePropertise/index.tsx +++ b/ui/src/components/AdvancePropertise/index.tsx @@ -44,9 +44,11 @@ const AdvancePropertise = (props: SchemaProps) => { allowImagesOnly: props?.value?.AllowImagesOnly, nonLocalizable: props?.value?.NonLocalizable, embedObject: true, - embedAssests: true + embedAssests: true, + multiple: props?.value?.Multiple }); + // State for content types const [contentTypes, setContentTypes] = useState([]); const [ctValue, setCTValue] = useState(null); @@ -54,7 +56,6 @@ const AdvancePropertise = (props: SchemaProps) => { useEffect(() => { fetchContentTypes(''); }, []) - /** * Fetches the content types list. * @param searchText - The search text. @@ -77,16 +78,25 @@ const AdvancePropertise = (props: SchemaProps) => { [field]: (event.target as HTMLInputElement)?.value })); + const currentToggleStates = { + ...toggleStates, + [field]: (event.target as HTMLInputElement)?.value, + }; + props?.updateFieldSettings( props?.rowId, { + ...props?.value, [field?.charAt(0)?.toUpperCase() + field?.slice(1)]: (event.target as HTMLInputElement)?.value, validationRegex: '', - Mandatory: false, - Multiple: false, + MinChars: currentToggleStates?.minChars, + MaxChars:currentToggleStates?.maxChars, + Mandatory: currentToggleStates?.mandatory, + Multiple: currentToggleStates?.multiple, Unique: false, - NonLocalizable: false, - EmbedObject: false + NonLocalizable: currentToggleStates?.nonLocalizable, + EmbedObject: currentToggleStates?.embedObject, + EmbedObjects: ctValue, }, checkBoxChanged ); @@ -103,17 +113,22 @@ const AdvancePropertise = (props: SchemaProps) => { ...prevStates, [field]: value })); - + const currentToggleStates = { + ...toggleStates, + [field]: value, + }; + props?.updateFieldSettings( props?.rowId, { [field?.charAt(0)?.toUpperCase() + field?.slice(1)]: value, validationRegex: '', - Mandatory: false, - Multiple: false, + Mandatory: currentToggleStates?.mandatory, + Multiple: currentToggleStates?.multiple, Unique: false, - NonLocalizable: false, - EmbedObject: false + NonLocalizable: currentToggleStates?.nonLocalizable, + EmbedObject: currentToggleStates?.embedObject, + EmbedObjects : ctValue }, checkBoxChanged ); diff --git a/ui/src/components/ContentMapper/contentMapper.interface.ts b/ui/src/components/ContentMapper/contentMapper.interface.ts index 03b49061e..3373e6189 100644 --- a/ui/src/components/ContentMapper/contentMapper.interface.ts +++ b/ui/src/components/ContentMapper/contentMapper.interface.ts @@ -73,6 +73,9 @@ export interface Advanced { Unique?: boolean; NonLocalizable?: boolean; EmbedObject?: boolean; + EmbedObjects?:any; + MinChars?: string; + MaxChars?: number; } export interface ItemStatus { diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 8ba4b603a..34111075a 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -278,6 +278,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re let updatedRows: FieldMapType[] = tableData; let updatedExstingField: ExistingFieldType = existingField; const updatedSelectedOptions: string[] = selectedOptions; + const [initialRowSelectedData, setInitialRowSelectedData] = useState(); /** ALL HOOKS Here */ const { projectId = '' } = useParams(); @@ -348,7 +349,10 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re // To make all the fields checked useEffect(() => { const selectedId = tableData.reduce((acc, item) => { - acc[item?.id] = true; + if(! item?.isDeleted){ + acc[item?.id] = true; + + } return acc; }, {}); @@ -447,6 +451,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re setTableData(newTableData || []); setTotalCounts(data?.count); + setInitialRowSelectedData(newTableData.filter((item:any) => !item.isDeleted)) generateSourceGroupSchema(data?.fieldMapping); } catch (error) { @@ -579,30 +584,122 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re ); }; - // Function to handle selected fields const handleSelectedEntries = (singleSelectedRowIds: string[], selectedData: FieldMapType[]) => { const selectedObj: UidMap = {}; - + let Ischild = false; + singleSelectedRowIds.forEach((uid: string) => { - selectedObj[uid] = true; + const isId = selectedData?.some((item) => item?.id === uid); + if (isId) { + selectedObj[uid] = true; + } }); - + + // Iterate over each item in selectedData to handle group and child selection logic + selectedData?.forEach((item) => { + + // Extract the group UID if item is child of any group + const uidBeforeDot = item?.uid?.split('.')[0]; + const groupItem = tableData?.find((entry) => entry?.uid === uidBeforeDot); + + if (groupItem) { + // Mark the group item as selected if any child of group is selected + selectedObj[groupItem?.id] = true; + } + + // If the item is a group, handle its child items + if (item?.otherCmsType === 'Group') { + + // Get all child items of the group + const newEle = tableData?.filter((entry) => entry?.uid?.startsWith(item?.uid + '.')); + + if (newEle && validateArray(newEle)) { + + const allChildrenNotSelected = newEle.every(child => !selectedObj[child?.id || '']); + if (allChildrenNotSelected) { + + //if none of the child of group is selected then mark the child items as selected + newEle.forEach((child) => { + Ischild = true; + selectedObj[child?.id || ''] = true; + }); + } + } + } + else { + // If the item is not a group, mark it as selected in selectedObj + selectedObj[item?.id] = true; + } + }); + const uncheckedElements = findUncheckedElement(selectedData, tableData); + uncheckedElements && validateArray(uncheckedElements) && uncheckedElements?.forEach((field) => { if (field?.otherCmsType === "Group") { - const newEle = selectedData?.filter((entry) => entry?.uid?.startsWith(field?.uid + '.')) - newEle && validateArray(newEle) && newEle.forEach((child) => { - selectedObj[child?.id || ''] = false; - selectedData?.splice(selectedData?.indexOf(child), 1); - }) + // Get all child items of the unchecked group + const childItems = tableData?.filter((entry) => entry?.uid?.startsWith(field?.uid + '.')); + + if (childItems && validateArray(childItems)) { + + // Check if all children are selected + const allChildrenSelected = childItems.every(child => selectedObj[child?.id || '']); + + if (allChildrenSelected) { + childItems.forEach((child) => { + + // Remove each child item from selected + delete selectedObj[child?.id || '']; + + }); + delete selectedObj[field?.id || '']; + } + } + } + else { + + // Extract the group UID if item is child of any group + const uidBeforeDot = field?.uid?.split('.')[0]; + const groupItem = selectedData?.find((entry) => entry?.uid === uidBeforeDot); + const childItems = tableData?.filter((entry) => entry?.uid?.startsWith(groupItem?.uid + '.')); + + if (childItems && validateArray(childItems)) { + + // Check if all children are not selected of group + const allChildrenSelected = childItems.every(child => !selectedObj[child?.id || '']); + + if (allChildrenSelected) { + + childItems.forEach((child) => { + delete selectedObj[child?.id || '']; + + }); + delete selectedObj[groupItem?.id || '']; + } + } + + if (!Ischild) { + + delete selectedObj[field?.id || '']; + } } - }) + }); + const updatedTableData = tableData.map((tableItem) => { + const found = selectedData.some((selectedItem) => selectedItem.uid === tableItem.uid); + + // Mark the item as deleted if not found in selectedData + return { + ...tableItem, + isDeleted: !found ? true : false, + }; + }); + setRowIds(selectedObj); - setSelectedEntries(selectedData); + setSelectedEntries(updatedTableData); }; - + + // Function to find unchecked field const findUncheckedElement = (selectedData: FieldMapType[], tableData: FieldMapType[]) => { return tableData.filter((mainField: FieldMapType) => @@ -715,7 +812,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re icon="Sliders" size="small" onClick={() => - handleAdvancedSetting(fieldLabel, advancePropertise, data?.uid, data) + handleAdvancedSetting(fieldLabel, data?.advanced || {}, data?.uid, data) } /> @@ -727,7 +824,16 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re const handleFieldChange = (selectedValue: FieldTypes, rowIndex: string) => { setIsDropDownChanged(true); const previousSelectedValue = existingField[rowIndex]?.label; + const groupArray = nestedList.filter(item => + item?.child?.some(e => e?.id) + ) + if(groupArray[0].child && previousSelectedValue !== selectedValue?.label && groupArray[0]?.uid === rowIndex){ + for(const item of groupArray[0].child){ + delete existingField[item?.uid] + } + } + setExistingField((prevOptions) => ({ ...prevOptions, [rowIndex]: { label: selectedValue?.label, value: selectedValue?.value } @@ -770,7 +876,10 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re Mandatory: selectedValue?.value?.mandatory, Multiple: selectedValue?.value?.multiple, Unique: selectedValue?.value?.unique, - NonLocalizable: selectedValue?.value?.non_localizable + NonLocalizable: selectedValue?.value?.non_localizable, + MinChars: selectedValue?.value?.max, + MaxChars: selectedValue?.value?.min, + } }; } @@ -864,7 +973,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re currentDisplayName = '' ) => { // Update the current display name with the current value's display name - const updatedDisplayName = currentDisplayName ? `${currentDisplayName} '>' ${value?.display_name}` : value?.display_name; + const updatedDisplayName = currentDisplayName ? `${currentDisplayName} > ${value?.display_name}` : value?.display_name; if (value?.data_type === 'group') { @@ -1138,15 +1247,20 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re data?.otherCmsField === 'url' } > - + { - handleAdvancedSetting(initialOption?.label, advancePropertise, data?.uid, data); + handleAdvancedSetting(initialOption?.label, data?.advanced || {}, data?.uid, data); }} /> + + )} @@ -1553,7 +1667,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re tableHeight={tableHeight} equalWidthColumns={true} columnSelector={false} - initialRowSelectedData={tableData} + initialRowSelectedData={initialRowSelectedData} initialSelectedRowIds={rowIds} itemSize={80} withExportCta={{