From a79926b3ccf09e5d686de7d85aa1b8b3f54771d9 Mon Sep 17 00:00:00 2001 From: GaurishN Date: Mon, 9 Dec 2024 12:07:42 +0530 Subject: [PATCH 1/4] fixed selection deselection issue --- ui/src/components/ContentMapper/index.tsx | 340 ++++++++++++++++------ 1 file changed, 255 insertions(+), 85 deletions(-) diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 5d9d9690..620974b8 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -69,6 +69,8 @@ import SaveChangesModal from '../Common/SaveChangesModal'; import './index.scss'; import { NoDataFound, SCHEMA_PREVIEW } from '../../common/assets'; +const rowHistoryObj: any = {} + const Fields: MappingFields = { 'single_line_text':{ label : 'Single Line Textbox', @@ -733,9 +735,60 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R ); }; + // add row ids with their data to rowHistoryObj + useEffect(() => { + Object.keys(rowHistoryObj).forEach(key => delete rowHistoryObj[key]); + tableData.forEach(i => rowHistoryObj[i.id] = [{checked: true, at: Date.now(), ...modifiedObj(i)}]) + }, [tableData]); + + function getParentId(uid: string){ + return tableData.find(i => i.uid === uid)?.id ?? null + } + + function modifiedObj (obj: FieldMapType) { + const {otherCmsType, uid, id} = obj + const excludeArr = ["group"] + return { + id, + otherCmsType, + uid, + parentId : excludeArr.includes(otherCmsType.toLowerCase()) ? null : getParentId(uid?.split('.')[0]) + } + } + + // Get the last action of each row + function getLastElements(obj: any) { + const result: any = {}; + for (const key in obj) { + if (Array.isArray(obj[key]) && obj[key].length > 0) { + // Get the last element of the array + result[key] = obj[key][obj[key].length - 1]; + } + } + return result; + } + + // Get the latest action performed on table + function findLatest(obj: any) { + let latestItem = null; + + for (const key in obj) { + if (Array.isArray(obj[key]) && obj[key].length > 0) { + // Get the last element of the array + const lastElement = obj[key][obj[key].length - 1]; + + // Compare the 'at' property + if (!latestItem || lastElement.at > latestItem.at) { + latestItem = lastElement; + } + } + } + + return latestItem; + } + const handleSelectedEntries = (singleSelectedRowIds: string[], selectedData: FieldMapType[]) => { const selectedObj: UidMap = {}; - let Ischild = false; singleSelectedRowIds.forEach((uid: string) => { const isId = selectedData?.some((item) => item?.id === uid); @@ -743,119 +796,236 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R 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; + const updateRowHistoryObj = (key: string, checked: boolean) => { + const obj = tableData.find(i => i.id === key); + if (obj) { + rowHistoryObj[key].push({ + checked, + at: Date.now(), + ...modifiedObj(obj), + }); } - - // 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; - }); - } + // updates rowHistoryObj based on selectedObj + for (const key in rowHistoryObj) { + if (Object.prototype.hasOwnProperty.call(selectedObj, key)) { + if(!rowHistoryObj[key][rowHistoryObj[key].length - 1].checked){ + updateRowHistoryObj(key, true); + } + }else{ + if(rowHistoryObj[key][rowHistoryObj[key].length - 1].checked){ + updateRowHistoryObj(key, false); } - } - 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") { + } - // Get all child items of the unchecked group - const childItems = tableData?.filter((entry) => entry?.uid?.startsWith(field?.uid + '.')); - - if (childItems && validateArray(childItems)) { + // Get the latest action performed row + const latestRow = findLatest(rowHistoryObj) + + if(latestRow.otherCmsType.toLowerCase() === "group" && latestRow.parentId === null){ + // get all child rows of group + const childItems = tableData?.filter((entry) => entry?.uid?.startsWith(latestRow?.uid + '.')); + if (childItems && validateArray(childItems)) { + if(latestRow.checked){ + const lastEle = getLastElements(rowHistoryObj) + let isChildChecked = false + childItems.forEach((child) => { + if(lastEle[child.id].checked){ + isChildChecked = true + } + }) - // Check if all children are selected - const allChildrenSelected = childItems.every(child => selectedObj[child?.id || '']); - - if (allChildrenSelected) { + if(isChildChecked) { + if(!selectedObj[latestRow?.id]){ + selectedObj[latestRow?.id] = true + } + } else{ childItems.forEach((child) => { - - // Remove each child item from selected - delete selectedObj[child?.id || '']; - - }); - delete selectedObj[field?.id || '']; + if(!selectedObj[child?.id]){ + selectedObj[child?.id] = true + } + }) } - } - } - 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)) { + }else{ + childItems.forEach((child) => { + delete selectedObj[child?.id || '']; + }) + } + } + } else if(latestRow.parentId && !["title", "url"].includes(latestRow.uid.toLowerCase())){ + // Extract the group UID if item is child of any group + const uidBeforeDot = latestRow?.uid?.split('.')[0]; + const groupItem = tableData?.find((entry) => entry?.uid === uidBeforeDot); + const childItems = tableData?.filter((entry) => entry?.uid?.startsWith(groupItem?.uid + '.')); - // 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(latestRow.checked){ + if(!selectedObj[latestRow.parentId]){ + selectedObj[latestRow.parentId] = true } - - if (!Ischild) { + if(!selectedObj[latestRow.id]){ + selectedObj[latestRow.id] = true + } + }else{ + const lastEle = getLastElements(rowHistoryObj) - delete selectedObj[field?.id || '']; + let allChildFalse = 0 + childItems.forEach((child) => { + if(!lastEle[child.id].checked){ + allChildFalse ++ + } + }) + if(childItems.length === allChildFalse){ + if(selectedObj[latestRow.parentId]){ + delete selectedObj[latestRow.parentId] + } + }else{ + if(selectedObj[latestRow.id]){ + delete selectedObj[latestRow.id] + } } } - }); + } + const updatedTableData = tableData.map((tableItem) => { - const found = selectedData.some((selectedItem) => selectedItem.uid === tableItem.uid); + // 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, + isDeleted: selectedObj[tableItem.id] ?? false//!found ? true : false, }; - }); - + }); setRowIds(selectedObj); setSelectedEntries(updatedTableData); }; + + // const handleSelectedEntries2 = (singleSelectedRowIds: string[], selectedData: FieldMapType[]) => { + // const selectedObj: UidMap = {}; + // let Ischild = false; + + // singleSelectedRowIds.forEach((uid: string) => { + // 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") { + + // // 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(updatedTableData); + // }; // Function to find unchecked field - const findUncheckedElement = (selectedData: FieldMapType[], tableData: FieldMapType[]) => { - return tableData.filter((mainField: FieldMapType) => - !selectedData.some((selectedField:FieldMapType) => selectedField?.otherCmsField === mainField?.otherCmsField) - ); - } + // const findUncheckedElement = (selectedData: FieldMapType[], tableData: FieldMapType[]) => { + // return tableData.filter((mainField: FieldMapType) => + // !selectedData.some((selectedField:FieldMapType) => selectedField?.otherCmsField === mainField?.otherCmsField) + // ); + // } // Method for change select value const handleValueChange = (value: FieldTypes, rowIndex: string) => { From 78ac9245b15d71f4918570ec02071011ab50ecb6 Mon Sep 17 00:00:00 2001 From: AishDani Date: Wed, 22 Jan 2025 15:27:27 +0530 Subject: [PATCH 2/4] refactor:update current-step after migration from api side and stack-name of testStack in UI --- api/src/services/runCli.service.ts | 2 ++ .../LogScreen/MigrationLogViewer.tsx | 2 +- ui/src/pages/Migration/index.tsx | 20 ++++++++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/api/src/services/runCli.service.ts b/api/src/services/runCli.service.ts index e3730301..a3daa489 100644 --- a/api/src/services/runCli.service.ts +++ b/api/src/services/runCli.service.ts @@ -63,6 +63,8 @@ export const runCli = async (rg: string, user_id: string, stack_uid: any, projec !isTest && ProjectModelLowdb.update((data: any) => { data.projects[projectIndex].isMigrationCompleted = true; data.projects[projectIndex].isMigrationStarted = false; + data.projects[projectIndex].current_step = 5; + data.projects[projectIndex].status = 5; }) } }); diff --git a/ui/src/components/LogScreen/MigrationLogViewer.tsx b/ui/src/components/LogScreen/MigrationLogViewer.tsx index 5cfe82e4..c413b494 100644 --- a/ui/src/components/LogScreen/MigrationLogViewer.tsx +++ b/ui/src/components/LogScreen/MigrationLogViewer.tsx @@ -193,7 +193,7 @@ const MigrationLogViewer = ({ serverPath }: LogsType) => { /** * Updates the Migration excution step as completed in backend if migration completes. */ - updateCurrentStepData(selectedOrganisation.value, projectId); + //await updateCurrentStepData(selectedOrganisation.value, projectId); return cbModal({ component: (props: ModalObj) => ( diff --git a/ui/src/pages/Migration/index.tsx b/ui/src/pages/Migration/index.tsx index 783657a1..ef1bf575 100644 --- a/ui/src/pages/Migration/index.tsx +++ b/ui/src/pages/Migration/index.tsx @@ -23,7 +23,7 @@ import { DEFAULT_IFLOWSTEP, IFlowStep } from '../../components/Stepper/FlowStepper/flowStep.interface'; -import { IDropDown, INewMigration, ICMSType, ILegacyCMSComponent, DEFAULT_CMS_TYPE } from '../../context/app/app.interface'; +import { IDropDown, INewMigration, ICMSType, ILegacyCMSComponent, DEFAULT_CMS_TYPE, TestStacks } from '../../context/app/app.interface'; import { ContentTypeSaveHandles } from '../../components/ContentMapper/contentMapper.interface'; import { ICardType } from "../../components/Common/Card/card.interface"; import { ModalObj } from '../../components/Modal/modal.interface'; @@ -203,6 +203,7 @@ const Migration = () => { const existingGlobalFields = await fetchExistingGlobalFields(); const stackLink = `${CS_URL[projectData?.region]}/stack/${projectData?.current_test_stack_id}/dashboard`; + const stackName = projectData?.test_stacks?.find((stack:TestStacks)=> stack?.stackUid === projectData?.current_test_stack_id)?.stackName; const projectMapper = { ...newMigrationData, @@ -245,7 +246,8 @@ const Migration = () => { stack_link: stackLink, stack_api_key: projectData?.current_test_stack_id, isMigrationStarted: newMigrationData?.test_migration?.isMigrationStarted || false, - isMigrationComplete: newMigrationData?.test_migration?.isMigrationStarted || false + isMigrationComplete: newMigrationData?.test_migration?.isMigrationStarted || false, + stack_name: stackName, }, migration_execution: { migrationStarted: projectData?.isMigrationStarted, @@ -361,8 +363,9 @@ const Migration = () => { } }); const res = await updateCurrentStepData(selectedOrganisation.value, projectId); + handleStepChange(1); - if (res) { + if (res?.status === 200) { setIsLoading(false); const url = `/projects/${projectId}/migration/steps/2`; @@ -418,9 +421,9 @@ const Migration = () => { created_at:newMigrationData?.destination_stack?.selectedStack?.created_at, isNewStack: newMigrationData?.destination_stack?.selectedStack?.isNewStack }) - handleStepChange(2); const res = await updateCurrentStepData(selectedOrganisation?.value, projectId); - if (res) { + if (res?.status === 200) { + handleStepChange(2); setIsLoading(false); const url = `/projects/${projectId}/migration/steps/3`; navigate(url, { replace: true }); @@ -486,8 +489,11 @@ const Migration = () => { await updateMigrationKey(selectedOrganisation.value, projectId); - await updateCurrentStepData(selectedOrganisation.value, projectId); - handleStepChange(4); + const res = await updateCurrentStepData(selectedOrganisation.value, projectId); + if(res?.status === 200){ + handleStepChange(4); + } + } /** From 95e49f65b10b86508795f06f22ffb90c1364391c Mon Sep 17 00:00:00 2001 From: Arpit1119 Date: Tue, 28 Jan 2025 15:06:17 +0530 Subject: [PATCH 3/4] fix: Test migration Logs issue fixed --- api/src/server.ts | 2 +- api/src/services/contentful.service.ts | 33 +++++++++++--------------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/api/src/server.ts b/api/src/server.ts index 157dd0e9..0280e9cc 100644 --- a/api/src/server.ts +++ b/api/src/server.ts @@ -26,7 +26,7 @@ const watcher = chokidar.watch(config.LOG_FILE_PATH, { usePolling: true, // Enables polling to detect changes in all environments interval: 1, // Poll every 100ms (you can adjust this if needed) awaitWriteFinish: { // Wait for file to finish being written before triggering - stabilityThreshold: 1, // Time to wait before considering the file stable + stabilityThreshold: 10, // Time to wait before considering the file stable pollInterval: 1, // Interval at which to poll for file stability }, persistent: true, // Keeps watching the file even after initial change diff --git a/api/src/services/contentful.service.ts b/api/src/services/contentful.service.ts index 3f6a9cf7..f73aaac0 100644 --- a/api/src/services/contentful.service.ts +++ b/api/src/services/contentful.service.ts @@ -5,7 +5,7 @@ import { v4 as uuidv4 } from "uuid"; import _ from "lodash"; import axios from "axios"; import jsonpath from "jsonpath"; -// import pLimit from 'p-limit'; +import pLimit from 'p-limit'; import {CHUNK_SIZE, MIGRATION_DATA_CONFIG } from "../constants/index.js"; @@ -408,24 +408,17 @@ const createAssets = async (packagePath: any, destination_stack_id:string, proje const assets = JSON.parse(data)?.assets; if (assets && assets.length > 0) { - const tasks = assets.map( - async (asset: any, index: any) => - saveAsset(asset, failedJSON, assetData, metadata, projectId, destination_stack_id, 0) + const limit = pLimit(10); // Limit concurrent operations to 10 + const tasks = assets.map((asset: any) => + limit(() => saveAsset(asset, failedJSON, assetData, metadata, projectId, destination_stack_id, 0)) ); -// This code is intentionally commented out -// for testing purposes. - - // const limit = pLimit(10); // Limit concurrent operations to 10 - // const tasks = assets.map((asset: any) => - // limit(() => saveAsset(asset, failedJSON, assetData, metadata, projectId, destination_stack_id, 0)) - // ); - // await Promise.all(tasks); - await Promise.all(tasks); const assetMasterFolderPath = path.join(assetsSave, ASSETS_FAILED_FILE); await writeOneFile(path.join(assetsSave, ASSETS_SCHEMA_FILE), assetData); + // This code is intentionally commented out + // const chunks: { [key: string]: any } = makeChunks(assetData); // const refs: any = {}; @@ -653,12 +646,6 @@ const createEntry = async (packagePath: any, destination_stack_id:string, projec entryData[name][locale][id][formattedKey] = value; } ); - const message = getLogMessage( - srcFunc, - `Entry title "${entryData[name][locale][id]?.title}"(${name}) in the ${locale} locale has been successfully transformed.`, - {} - ) - customLogger(projectId, destination_stack_id, 'info', message) }); }); @@ -673,6 +660,14 @@ const createEntry = async (packagePath: any, destination_stack_id:string, projec values as { [key: string]: any } )) { const chunks = await makeChunks(localeValues); + for (const [entryKey, entryValue] of Object.entries(localeValues)){ + const message = getLogMessage( + srcFunc, + `Entry title "${(entryValue as { title: string })?.title}"(${key}) in the ${localeKey} locale has been successfully transformed.`, + {} + ); + await customLogger(projectId, destination_stack_id, "info", message); + } const refs: { [key: string]: any } = {}; let chunkIndex = 1; const filePath = path.join( From 7cef91c1e44c69cb2b0066754fce40f0fd682256 Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Tue, 28 Jan 2025 19:04:35 +0530 Subject: [PATCH 4/4] [CMG-466] - Handle Undefined type use case in content mapping --- .../ContentMapper/contentMapper.interface.ts | 18 ++ ui/src/components/ContentMapper/index.tsx | 297 ++++++------------ 2 files changed, 111 insertions(+), 204 deletions(-) diff --git a/ui/src/components/ContentMapper/contentMapper.interface.ts b/ui/src/components/ContentMapper/contentMapper.interface.ts index 63dacafd..2cea8fad 100644 --- a/ui/src/components/ContentMapper/contentMapper.interface.ts +++ b/ui/src/components/ContentMapper/contentMapper.interface.ts @@ -65,6 +65,7 @@ export interface FieldMapType { _canSelect?: boolean; advanced?: Advanced; contentstackUid: string; + _invalid?: boolean; } export interface Advanced { @@ -174,4 +175,21 @@ export interface MappingObj { options: Mapping; } +export interface FieldHistoryObj { + [key: string]: ModifiedField[]; +} + +export interface FieldObj { + [key: string]: ModifiedField; +} + +export interface ModifiedField { + at: number; + checked: boolean; + id: string; + otherCmsType: string; + parentId: string; + uid: string; +} + diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 8f6da408..5ab3747b 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -54,7 +54,9 @@ import { Advanced, ContentTypeSaveHandles, MouseOrKeyboardEvent, - MappingFields + MappingFields, + FieldHistoryObj, + FieldObj } from './contentMapper.interface'; import { ItemStatusMapProp } from '@contentstack/venus-components/build/components/Table/types'; import { ModalObj } from '../Modal/modal.interface'; @@ -69,7 +71,7 @@ import SaveChangesModal from '../Common/SaveChangesModal'; import './index.scss'; import { NoDataFound, SCHEMA_PREVIEW } from '../../common/assets'; -const rowHistoryObj: any = {} +const rowHistoryObj: FieldHistoryObj = {} const Fields: MappingFields = { 'single_line_text':{ @@ -286,7 +288,16 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R if (field?.otherCmsField !== 'title' && field?.otherCmsField !== 'url') { field._canSelect = true; } + + if (field?.otherCmsType === undefined) { + field._invalid = true; + } else { + field._invalid = false; + } }); + + const validatedData = tableData?.filter((data) => !data?._invalid); + setSelectedEntries(validatedData); },[tableData]); useEffect(() => { @@ -403,7 +414,7 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R // To make all the fields checked useEffect(() => { const selectedId = tableData.reduce((acc, item) => { - if(! item?.isDeleted){ + if(! item?.isDeleted && !item?._invalid) { acc[item?.id] = true; } @@ -749,101 +760,101 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R // add row ids with their data to rowHistoryObj useEffect(() => { Object.keys(rowHistoryObj).forEach(key => delete rowHistoryObj[key]); - tableData.forEach(i => rowHistoryObj[i.id] = [{checked: true, at: Date.now(), ...modifiedObj(i)}]) + tableData?.forEach(item => { + rowHistoryObj[item?.id] = [{checked: true, at: Date.now(), ...modifiedObj(item)}] + }); }, [tableData]); - function getParentId(uid: string){ - return tableData.find(i => i.uid === uid)?.id ?? null + const getParentId = (uid: string) => { + return tableData?.find(i => i?.uid === uid)?.id ?? '' } - function modifiedObj (obj: FieldMapType) { + const modifiedObj = (obj: FieldMapType) => { const {otherCmsType, uid, id} = obj const excludeArr = ["group"] return { id, otherCmsType, uid, - parentId : excludeArr.includes(otherCmsType.toLowerCase()) ? null : getParentId(uid?.split('.')[0]) + parentId : excludeArr?.includes(otherCmsType?.toLowerCase()) ? '' : getParentId(uid?.split('.')[0]) } } // Get the last action of each row - function getLastElements(obj: any) { - const result: any = {}; + const getLastElements = (obj: FieldHistoryObj) => { + const result: FieldObj = {}; for (const key in obj) { - if (Array.isArray(obj[key]) && obj[key].length > 0) { - // Get the last element of the array - result[key] = obj[key][obj[key].length - 1]; - } + if (Array.isArray(obj[key]) && obj[key]?.length > 0) { + // Get the last element of the array + result[key] = obj[key][obj[key]?.length - 1]; + } } return result; } // Get the latest action performed on table - function findLatest(obj: any) { + const findLatest = (obj: FieldHistoryObj) => { let latestItem = null; for (const key in obj) { - if (Array.isArray(obj[key]) && obj[key].length > 0) { - // Get the last element of the array - const lastElement = obj[key][obj[key].length - 1]; + if (Array.isArray(obj[key]) && obj[key]?.length > 0) { + // Get the last element of the array + const lastElement = obj[key][obj[key]?.length - 1]; - // Compare the 'at' property - if (!latestItem || lastElement.at > latestItem.at) { - latestItem = lastElement; - } + // Compare the 'at' property + if (!latestItem || lastElement?.at > latestItem?.at) { + latestItem = lastElement; } + } } - return latestItem; } + + // Update the object on selection or deselection + const updateRowHistoryObj = (key: string, checked: boolean) => { + const obj = tableData?.find(i => i?.id === key); + if (obj) { + rowHistoryObj[key].push({ + checked, + at: Date.now(), + ...modifiedObj(obj), + }); + } + }; - const handleSelectedEntries = (singleSelectedRowIds: string[], selectedData: FieldMapType[]) => { + const handleSelectedEntries = (singleSelectedRowIds: string[]) => { const selectedObj: UidMap = {}; singleSelectedRowIds.forEach((uid: string) => { - const isId = selectedData?.some((item) => item?.id === uid); + const isId = selectedEntries?.some((item) => item?.id === uid); if (isId) { selectedObj[uid] = true; } }); - const updateRowHistoryObj = (key: string, checked: boolean) => { - const obj = tableData.find(i => i.id === key); - if (obj) { - rowHistoryObj[key].push({ - checked, - at: Date.now(), - ...modifiedObj(obj), - }); - } - }; - // updates rowHistoryObj based on selectedObj for (const key in rowHistoryObj) { - if (Object.prototype.hasOwnProperty.call(selectedObj, key)) { - if(!rowHistoryObj[key][rowHistoryObj[key].length - 1].checked){ + if (Object.hasOwn(selectedObj, key)) { + if(!rowHistoryObj[key][rowHistoryObj[key]?.length - 1]?.checked){ updateRowHistoryObj(key, true); } - }else{ - if(rowHistoryObj[key][rowHistoryObj[key].length - 1].checked){ - updateRowHistoryObj(key, false); - } + } else if(rowHistoryObj[key][rowHistoryObj[key]?.length - 1]?.checked){ + updateRowHistoryObj(key, false); } } // Get the latest action performed row - const latestRow = findLatest(rowHistoryObj) + const latestRow = findLatest(rowHistoryObj); - if(latestRow.otherCmsType.toLowerCase() === "group" && latestRow.parentId === null){ + if(latestRow?.otherCmsType?.toLowerCase() === "group" && latestRow?.parentId === '') { // get all child rows of group - const childItems = tableData?.filter((entry) => entry?.uid?.startsWith(latestRow?.uid + '.')); + const childItems = selectedEntries?.filter((entry) => entry?.uid?.startsWith(latestRow?.uid + '.')); if (childItems && validateArray(childItems)) { if(latestRow.checked){ const lastEle = getLastElements(rowHistoryObj) let isChildChecked = false childItems.forEach((child) => { - if(lastEle[child.id].checked){ + if(lastEle[child?.id]?.checked){ isChildChecked = true } }) @@ -852,7 +863,7 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R if(!selectedObj[latestRow?.id]){ selectedObj[latestRow?.id] = true } - } else{ + } else { childItems.forEach((child) => { if(!selectedObj[child?.id]){ selectedObj[child?.id] = true @@ -860,53 +871,49 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R }) } - }else{ - childItems.forEach((child) => { + } else { + childItems?.forEach((child) => { delete selectedObj[child?.id || '']; }) } } - } else if(latestRow.parentId && !["title", "url"].includes(latestRow.uid.toLowerCase())){ + } else if(latestRow?.parentId && !["title", "url"].includes(latestRow?.uid?.toLowerCase())){ // Extract the group UID if item is child of any group const uidBeforeDot = latestRow?.uid?.split('.')[0]; - const groupItem = tableData?.find((entry) => entry?.uid === uidBeforeDot); - const childItems = tableData?.filter((entry) => entry?.uid?.startsWith(groupItem?.uid + '.')); + const groupItem = selectedEntries?.find((entry) => entry?.uid === uidBeforeDot); + const childItems = selectedEntries?.filter((entry) => entry?.uid?.startsWith(groupItem?.uid + '.')); if(latestRow.checked){ - if(!selectedObj[latestRow.parentId]){ - selectedObj[latestRow.parentId] = true + if(!selectedObj[latestRow?.parentId]){ + selectedObj[latestRow?.parentId] = true } - if(!selectedObj[latestRow.id]){ - selectedObj[latestRow.id] = true + if(!selectedObj[latestRow?.id]){ + selectedObj[latestRow?.id] = true } }else{ const lastEle = getLastElements(rowHistoryObj) let allChildFalse = 0 - childItems.forEach((child) => { - if(!lastEle[child.id].checked){ + childItems?.forEach((child) => { + if(!lastEle[child?.id]?.checked){ allChildFalse ++ } }) - if(childItems.length === allChildFalse){ - if(selectedObj[latestRow.parentId]){ - delete selectedObj[latestRow.parentId] + if(childItems?.length === allChildFalse){ + if(selectedObj[latestRow?.parentId]){ + delete selectedObj[latestRow?.parentId] } - }else{ - if(selectedObj[latestRow.id]){ - delete selectedObj[latestRow.id] - } - } + }else if (selectedObj[latestRow?.id]){ + delete selectedObj[latestRow?.id] + } } } - const updatedTableData = tableData.map((tableItem) => { - // const found = selectedData.some((selectedItem) => selectedItem.uid === tableItem.uid); - + const updatedTableData = selectedEntries.map((tableItem) => { // Mark the item as deleted if not found in selectedData return { ...tableItem, - isDeleted: selectedObj[tableItem.id] ?? false//!found ? true : false, + isDeleted: !selectedObj[tableItem?.id] && !tableItem?._invalid //!found ? true : false, }; }); @@ -914,130 +921,6 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R setSelectedEntries(updatedTableData); }; - // const handleSelectedEntries2 = (singleSelectedRowIds: string[], selectedData: FieldMapType[]) => { - // const selectedObj: UidMap = {}; - // let Ischild = false; - - // singleSelectedRowIds.forEach((uid: string) => { - // 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") { - - // // 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(updatedTableData); - // }; - - - - // Function to find unchecked field - // const findUncheckedElement = (selectedData: FieldMapType[], tableData: FieldMapType[]) => { - // return tableData.filter((mainField: FieldMapType) => - // !selectedData.some((selectedField:FieldMapType) => selectedField?.otherCmsField === mainField?.otherCmsField) - // ); - // } - // Method for change select value const handleValueChange = (value: FieldTypes, rowIndex: string) => { setIsDropDownChanged(true); @@ -1092,8 +975,8 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R //const OptionsForRow = Fields[data?.backupFieldType as keyof Mapping]; const OptionsForRow = Fields?.[data?.backupFieldType]?.options ; const initialOption = { - label: Fields?.[data?.contentstackFieldType]?.label, - value: Fields?.[data?.contentstackFieldType]?.label, + label: Fields?.[data?.contentstackFieldType]?.label ?? 'No Option', + value: Fields?.[data?.contentstackFieldType]?.label ?? 'No Option', }; let option: FieldTypes[]; if (Array.isArray(OptionsForRow)) { @@ -1134,8 +1017,9 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R data?.otherCmsType === "Group" || data?.otherCmsField === 'title' || data?.otherCmsField === 'url' || - data?.otherCmsField === 'reference'|| + data?.otherCmsType === 'reference'|| data?.contentstackFieldType === "global_field" || + data?.otherCmsType === undefined || newMigrationData?.project_current_step > 4 } /> @@ -1145,7 +1029,8 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R data?.otherCmsField === 'title' || data?.otherCmsField === 'url' || data?.otherCmsType === 'reference' || - data?.contentstackFieldType === 'global_field' + data?.contentstackFieldType === 'global_field' || + data?.otherCmsType === undefined ) && ( 0 && OptionsForRow.every((item)=>item.isDisabled) && (!existingField[data?.uid] || ! updatedExstingField[data?.uid] ) ) || (OptionsForRow.length > 0 && data?.contentstackFieldType === "dropdown")) ? { - label: Fields[data?.contentstackFieldType]?.label, - value: Fields[data?.contentstackFieldType]?.label, + label: Fields[data?.contentstackFieldType]?.label ?? 'No Option', + value: Fields[data?.contentstackFieldType]?.label ?? 'No Option', isDisabled: data?.contentstackFieldType === 'text' || data?.contentstackFieldType === 'group' || data?.contentstackFieldType === 'url' || data?.otherCmsType === "reference" || data?.contentstackFieldType === "global_field" || - data?.contentstackFieldType === "dropdown" - + data?.contentstackFieldType === "dropdown" || + data?.otherCmsType === undefined } : { label: `${selectedOption} matches`, @@ -2004,7 +1892,7 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R type: 'error' }); } - if(otherContentType?.id && data?.contentTypes?.every((item: any) => item?.uid !== otherContentType?.id)){ + if(otherContentType?.id && data?.contentTypes?.every((item: FieldMapType) => item?.uid !== otherContentType?.id)){ await handleCTDeleted(isContentType, data?.contentTypes); } } catch (error) { @@ -2055,7 +1943,7 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R type: 'error' }); } - if(otherContentType?.id && data?.globalFields?.every((item: any) => item?.uid !== otherContentType?.id)){ + if(otherContentType?.id && data?.globalFields?.every((item: FieldMapType) => item?.uid !== otherContentType?.id)){ await handleCTDeleted(isContentType, data?.globalFields); } } catch (error) { @@ -2393,6 +2281,7 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R singular: '', plural: `${totalCounts === 0 ? 'Count' : ''}` }} + rowDisableProp={{ key: '_invalid', value: true }} />