From 2e638438faa0df6cb541575fb5616ddb98966c87 Mon Sep 17 00:00:00 2001 From: AishDani Date: Wed, 31 Jul 2024 10:56:55 +0530 Subject: [PATCH 01/13] refactor:resolved eslint any warnings --- ui/src/components/Card/index.tsx | 2 +- ui/src/context/app/app.interface.ts | 14 ++- ui/src/pages/Login/index.tsx | 8 +- ui/src/pages/Migration/index.tsx | 19 +++- ui/src/pages/MigrationEditor/index.tsx | 6 +- ui/src/pages/Projects/index.tsx | 5 +- ui/src/services/api/login.service.ts | 16 +++- ui/src/services/api/migration.service.ts | 117 ++++++++++++++++------- ui/src/services/api/project.service.ts | 45 ++++++--- ui/src/services/api/stacks.service.ts | 16 +++- ui/src/services/api/upload.service.ts | 19 ++-- ui/src/services/api/user.service.ts | 16 +++- ui/src/utilities/constants.interface.ts | 6 +- ui/src/utilities/functions.ts | 16 +++- 14 files changed, 217 insertions(+), 88 deletions(-) diff --git a/ui/src/components/Card/index.tsx b/ui/src/components/Card/index.tsx index ffd01089..752187f8 100644 --- a/ui/src/components/Card/index.tsx +++ b/ui/src/components/Card/index.tsx @@ -102,7 +102,7 @@ const CardList = ({ project }: ProjectType) => {
- {getDays(project?.updated_at)} + {project?.updated_at && getDays(project?.updated_at)}
diff --git a/ui/src/context/app/app.interface.ts b/ui/src/context/app/app.interface.ts index 01192dea..f041d293 100644 --- a/ui/src/context/app/app.interface.ts +++ b/ui/src/context/app/app.interface.ts @@ -10,6 +10,16 @@ export interface ICTA { href: string; } +export type DataProps = { + stepComponentProps: ()=>{}; + currentStep: number; + handleStepChange: (step: number) => void; +}; + +export type SummaryProps = { + stepData: IStep; + stepComponentProps: ()=>{}; +}; interface ContentTypeMap { [key: string]: string; } @@ -70,8 +80,8 @@ export interface IStep { status?: string; lock: boolean; active?: boolean; - data?: (props: any) => JSX.Element; - summery?: (props: any) => JSX.Element; + data?: (props:DataProps) => JSX.Element; + summery?: (props: SummaryProps) => JSX.Element; empty_step_placeholder?: string; } diff --git a/ui/src/pages/Login/index.tsx b/ui/src/pages/Login/index.tsx index 0f343717..f87da3b7 100644 --- a/ui/src/pages/Login/index.tsx +++ b/ui/src/pages/Login/index.tsx @@ -1,9 +1,9 @@ // Libraries -import { FC, useContext, useEffect, useState } from 'react'; +import { FC,useEffect, useState } from 'react'; import { useNavigate, useLocation } from 'react-router-dom'; -import { useDispatch, useSelector } from 'react-redux'; +import { useDispatch } from 'react-redux'; -import { getUserDetails, setAuthToken } from '../../store/slice/authSlice'; +import { setAuthToken } from '../../store/slice/authSlice'; import { Button, Field, @@ -37,8 +37,6 @@ import AccountPage from '../../components/AccountPage'; // Styles import './index.scss'; -import { AppContext } from '../../context/app/app.context'; - const Login: FC = () => { const [data, setData] = useState({}); diff --git a/ui/src/pages/Migration/index.tsx b/ui/src/pages/Migration/index.tsx index 8b65bc9c..5af1b1fc 100644 --- a/ui/src/pages/Migration/index.tsx +++ b/ui/src/pages/Migration/index.tsx @@ -36,6 +36,14 @@ import TestMigration from '../../components/TestMigration'; import MigrationExecution from '../../components/MigrationExecution'; import { Notification } from '@contentstack/venus-components'; +type StepperComponentRef = { + handleStepChange: (step: number) => void; +}; +type LegacyCmsRef = { + getInternalActiveStepIndex: () => number; +}; + + const Migration = () => { const [projectData, setProjectData] = useState(); const [isLoading, setIsLoading] = useState(false); @@ -46,8 +54,8 @@ const Migration = () => { const { projectId = '' } = useParams(); const navigate = useNavigate(); const dispatch = useDispatch(); - const stepperRef = useRef(null); - const legacyCMSRef = useRef(null); + const stepperRef = useRef(null); + const legacyCMSRef = useRef(null); const selectedOrganisation = useSelector((state: RootState)=>state?.authentication?.selectedOrganisation); const newMigrationData = useSelector((state:RootState)=> state?.migration?.newMigrationData); @@ -217,7 +225,7 @@ const Migration = () => { result = 'Imported File'; break; } - if (currentIndex !== 3 || currentIndex !== 4) { + if (currentIndex !== 3) { Notification({ notificationContent: { text: `Please complete ${result} step` }, type: 'warning' @@ -314,7 +322,10 @@ const Migration = () => { dispatch(updateNewMigrationData((newMigrationDataObj))); } - + useEffect(() => { + console.log('Migration component rendered'); + }, []); + return (
diff --git a/ui/src/pages/MigrationEditor/index.tsx b/ui/src/pages/MigrationEditor/index.tsx index 9fbceeee..69db889d 100644 --- a/ui/src/pages/MigrationEditor/index.tsx +++ b/ui/src/pages/MigrationEditor/index.tsx @@ -1,11 +1,10 @@ // Libraries -import { useContext, useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { PageHeader, PageLayout } from '@contentstack/venus-components'; import { Params, useNavigate, useParams } from 'react-router'; import { useDispatch, useSelector } from 'react-redux'; // Context -import { AppContext } from '../../context/app/app.context'; import { DEFAULT_NEW_MIGRATION } from '../../context/app/app.interface'; // Service @@ -17,6 +16,7 @@ import NewMigrationWrapper from '../../components/Migrations/NewMigration/NewMig // Style import './index.scss'; import { updateNewMigrationData } from '../../store/slice/migrationDataSlice'; +import { RootState } from '../../store'; const MigrationEditor = () => { const navigate = useNavigate(); @@ -24,7 +24,7 @@ const MigrationEditor = () => { const dispatch = useDispatch(); - const selectedOrganisation = useSelector((state:any)=>state?.authentication?.selectedOrganisation); + const selectedOrganisation = useSelector((state:RootState)=>state?.authentication?.selectedOrganisation); const [projectName, setProjectName] = useState(''); diff --git a/ui/src/pages/Projects/index.tsx b/ui/src/pages/Projects/index.tsx index 2ba3960b..66e5dc54 100644 --- a/ui/src/pages/Projects/index.tsx +++ b/ui/src/pages/Projects/index.tsx @@ -20,8 +20,6 @@ import { ProjectsType, ProjectsObj } from './projects.interface'; import { ModalObj } from '../../components/Modal/modal.interface'; import { CTA } from '../Home/home.interface'; -// Context -import { AppContext } from '../../context/app/app.context'; // Components import ProjectsHeader from '../../components/ProjectsHeader'; @@ -35,6 +33,7 @@ import { NO_PROJECTS, NO_PROJECTS_SEARCH } from '../../common/assets'; import './index.scss'; import { getUserDetails } from '../../store/slice/authSlice'; import useBlockNavigation from '../../hooks/userNavigation'; +import { RootState } from '../../store'; const Projects = () => { @@ -49,7 +48,7 @@ const Projects = () => { } = data; const dispatch = useDispatch(); - const selectedOrganisation = useSelector((state:any)=>state?.authentication?.selectedOrganisation); + const selectedOrganisation = useSelector((state:RootState)=>state?.authentication?.selectedOrganisation); const outputIntro = HTMLReactParser(jsonToHtml(emptystate?.description ?? {})); diff --git a/ui/src/services/api/login.service.ts b/ui/src/services/api/login.service.ts index 69ee0dc4..acf3300a 100644 --- a/ui/src/services/api/login.service.ts +++ b/ui/src/services/api/login.service.ts @@ -6,15 +6,23 @@ import { postCall } from './service'; export const userSession = (data: User) => { try { return postCall(`${AUTH_ROUTES}/user-session`, data); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in userSession: ${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } } }; export const requestSMSToken = (data: SmsToken) => { try { return postCall(`${AUTH_ROUTES}/request-token-sms`, data); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in requestSMSToken: ${error.message}`); + } else { + throw new Error('Unknown error in requestSMSToken'); + } } }; diff --git a/ui/src/services/api/migration.service.ts b/ui/src/services/api/migration.service.ts index 833135f9..485bf034 100644 --- a/ui/src/services/api/migration.service.ts +++ b/ui/src/services/api/migration.service.ts @@ -1,3 +1,4 @@ +import { ObjectType } from '../../utilities/constants.interface'; import { API_VERSION } from '../../utilities/constants'; import { getDataFromLocalStorage } from '../../utilities/functions'; import { getCall, postCall, putCall } from './service'; @@ -11,56 +12,80 @@ const options = { export const getMigrationData = (orgId: string, projectId: string) => { try { return getCall(`${API_VERSION}/org/${orgId}/project/${projectId}/`, options); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in getting migrationData: ${error.message}`); + } else { + throw new Error('Unknown error in getting migrationData'); + } } }; -export const updateLegacyCMSData = (orgId: string, projectId: string, data: any) => { +export const updateLegacyCMSData = (orgId: string, projectId: string, data: ObjectType) => { try { return putCall(`${API_VERSION}/org/${orgId}/project/${projectId}/legacy-cms`, data, options); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error'); + } } }; -export const updateAffixData = (orgId: string, projectId: string, data: any) => { +export const updateAffixData = (orgId: string, projectId: string, data: ObjectType) => { try { return putCall(`${API_VERSION}/org/${orgId}/project/${projectId}/affix`, data, options); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error'); + } } }; -export const updateFileFormatData = (orgId: string, projectId: string, data: any) => { +export const updateFileFormatData = (orgId: string, projectId: string, data: ObjectType) => { try { return putCall(`${API_VERSION}/org/${orgId}/project/${projectId}/file-format`, data, options); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error'); + } } }; -export const updateDestinationStack = (orgId: string, projectId: string, data: any) => { +export const updateDestinationStack = (orgId: string, projectId: string, data: ObjectType) => { try { return putCall( `${API_VERSION}/org/${orgId}/project/${projectId}/destination-stack`, data, options ); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error'); + } } }; -export const updateCurrentStepData = (orgId: string, projectId: string, data: any = {}) => { +export const updateCurrentStepData = (orgId: string, projectId: string, data: ObjectType = {}) => { try { return putCall(`${API_VERSION}/org/${orgId}/project/${projectId}/current-step`, data, options); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error'); + } } }; -export const affixConfirmation = (orgId: string, projectId: string, data: any = {}) => { +export const affixConfirmation = (orgId: string, projectId: string, data: ObjectType = {}) => { try { return putCall( `${API_VERSION}/org/${orgId}/project/${projectId}/affix_confirmation`, @@ -72,7 +97,7 @@ export const affixConfirmation = (orgId: string, projectId: string, data: any = } }; -export const fileformatConfirmation = (orgId: string, projectId: string, data: any = {}) => { +export const fileformatConfirmation = (orgId: string, projectId: string, data: ObjectType = {}) => { try { return putCall( `${API_VERSION}/org/${orgId}/project/${projectId}/fileformat_confirmation`, @@ -96,8 +121,12 @@ export const getContentTypes = ( `${API_VERSION}/mapper/contentTypes/${projectId}/${skip}/${limit}/${encodedSearchText}?`, options ); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error'); + } } }; @@ -114,16 +143,24 @@ export const getFieldMapping = async ( `${API_VERSION}/mapper/fieldMapping/${projectId}/${contentTypeId}/${skip}/${limit}/${encodedSearchText}?`, options ); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error'); + } } }; export const getExistingContentTypes = async (projectId: string) => { try { return await getCall(`${API_VERSION}/mapper/${projectId}`, options); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error'); + } } }; @@ -131,7 +168,7 @@ export const updateContentType = async ( orgId: string, projectId: string, contentTypeId: string, - data: any + data: ObjectType ) => { try { return await putCall( @@ -139,8 +176,12 @@ export const updateContentType = async ( data, options ); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error'); + } } }; @@ -148,7 +189,7 @@ export const resetToInitialMapping = async ( orgId: string, projectId: string, contentTypeId: string, - data: any + data: ObjectType ) => { try { return await putCall( @@ -156,12 +197,16 @@ export const resetToInitialMapping = async ( data, options ); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error'); + } } }; -export const createTestStack = async (orgId: string, projectId: string, data: any) => { +export const createTestStack = async (orgId: string, projectId: string, data: ObjectType) => { try { return await postCall( `${API_VERSION}/migration/test-stack/${orgId}/${projectId}`, @@ -176,8 +221,12 @@ export const createTestStack = async (orgId: string, projectId: string, data: an export const fetchExistingContentType = async (projectId: string, contentTypeUid: string) => { try { return await getCall(`${API_VERSION}/mapper/${projectId}/${contentTypeUid}`, options); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error'); + } } } diff --git a/ui/src/services/api/project.service.ts b/ui/src/services/api/project.service.ts index dfc36891..118e1b84 100644 --- a/ui/src/services/api/project.service.ts +++ b/ui/src/services/api/project.service.ts @@ -1,3 +1,4 @@ +import { ObjectType } from '../../utilities/constants.interface'; import { API_VERSION } from '../../utilities/constants'; import { getDataFromLocalStorage } from '../../utilities/functions'; import { getCall, postCall, putCall, deleteCall } from './service'; @@ -11,39 +12,59 @@ const options = () => ({ export const getAllProjects = async (orgId: string) => { try { return await getCall(`${API_VERSION}/org/${orgId}/project`, options()); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in userSession: ${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } } }; export const getProject = async (orgId: string, projectId: string) => { try { return await getCall(`${API_VERSION}/org/${orgId}/project/${projectId}`, options()); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in userSession: ${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } } }; -export const createProject = async (orgId: string, data: any) => { +export const createProject = async (orgId: string, data: ObjectType) => { try { return await postCall(`${API_VERSION}/org/${orgId}/project/`, data, options()); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in userSession: ${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } } }; -export const updateProject = async (orgId: string, projectId: string, data: any) => { +export const updateProject = async (orgId: string, projectId: string, data: ObjectType) => { try { return await putCall(`${API_VERSION}/org/${orgId}/project/${projectId}`, data, options()); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in userSession: ${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } } }; export const deleteProject = async (orgId: string, projectId: string) => { try { return await deleteCall(`${API_VERSION}/org/${orgId}/project/${projectId}`, options()); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in userSession: ${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } } }; diff --git a/ui/src/services/api/stacks.service.ts b/ui/src/services/api/stacks.service.ts index 334b2b7a..4d8143db 100644 --- a/ui/src/services/api/stacks.service.ts +++ b/ui/src/services/api/stacks.service.ts @@ -19,8 +19,12 @@ export const getAllStacksInOrg = async (orgId: string,searchText: string) => { export const createStacksInOrg = async (orgId: string, data: any) => { try { return await postCall(`${API_VERSION}/org/${orgId}/stacks`, data, options); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in userSession: ${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } } }; @@ -30,7 +34,11 @@ export const getStackStatus = async (orgId: string, data: string) => { stack_api_key: data }; return await postCall(`${API_VERSION}/org/${orgId}/stack_status`, stack_api, options); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in userSession: ${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } } }; diff --git a/ui/src/services/api/upload.service.ts b/ui/src/services/api/upload.service.ts index ead7f3f2..65437123 100644 --- a/ui/src/services/api/upload.service.ts +++ b/ui/src/services/api/upload.service.ts @@ -1,7 +1,6 @@ import axios from 'axios'; import { UPLOAD_FILE_RELATIVE_URL } from '../../utilities/constants'; -import { User, SmsToken } from '../../pages/Login/login.interface'; -import { API_VERSION } from '../../utilities/constants'; +import { User } from '../../pages/Login/login.interface'; import { getDataFromLocalStorage } from '../../utilities/functions'; //Axios Calls for Upload server @@ -9,8 +8,12 @@ export const getCall = async (url: string, options?: any) => { try { const response = await axios.get(url, { ...options }); return response; - } catch (err: any) { - return err.response; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } } }; @@ -18,8 +21,12 @@ export const postCall = async (url: string, data: User, options?: any) => { try { const response = await axios.post(url, data, options); return response; - } catch (err: any) { - return err.response; + } catch (error) { + if (error instanceof Error) { + throw new Error(`${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } } }; diff --git a/ui/src/services/api/user.service.ts b/ui/src/services/api/user.service.ts index f9668f6b..c19cf14f 100644 --- a/ui/src/services/api/user.service.ts +++ b/ui/src/services/api/user.service.ts @@ -11,8 +11,12 @@ export const getUser = async () => { try { return await getCall(`${API_VERSION}/user/profile`, options); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in userSession: ${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } } }; @@ -25,7 +29,11 @@ export const getAllLocales = async (orgId: string) => { try { return await getCall(`${API_VERSION}/org/${orgId}/locales`, options); - } catch (error: any) { - return error; + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in userSession: ${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } } }; diff --git a/ui/src/utilities/constants.interface.ts b/ui/src/utilities/constants.interface.ts index 0089b499..deaf0d82 100644 --- a/ui/src/utilities/constants.interface.ts +++ b/ui/src/utilities/constants.interface.ts @@ -1,3 +1,7 @@ export interface ObjectType { - [key: string]: string; + [key: string]: any; } + +export interface Image { + url?: string; +} \ No newline at end of file diff --git a/ui/src/utilities/functions.ts b/ui/src/utilities/functions.ts index 7035f1e3..bcb47920 100644 --- a/ui/src/utilities/functions.ts +++ b/ui/src/utilities/functions.ts @@ -1,5 +1,6 @@ import { Notification } from '@contentstack/venus-components'; import { WEBSITE_BASE_URL } from './constants'; +import { Image, ObjectType } from './constants.interface'; export const Locales = { en: 'en-us', @@ -17,16 +18,16 @@ export const getLocaleCode = (loc = 'en') => { }; // Validate object whether empty or not -export const validateObject = (obj: any) => +export const validateObject = (obj: ObjectType) => Object.keys(obj).length !== 0 && obj.constructor === Object; // Array validation - pass array in and check for length to be more than 0. export const validateArray = (array: T[]) => Array.isArray(array) && array.length > 0; // Use: validateSingleImage(image) -export const validateImage = (image: any) => image && image?.url; +export const validateImage = (image: Image) => image && image?.url; -export const validateLink = (link: any) => link && link?.url; +export const validateLink = (link: Image) => link && link?.url; export const imageWithSiteDomainUrl = (url: string) => { if (WEBSITE_BASE_URL && url?.indexOf('https://images.contentstack.io') > -1) { @@ -68,7 +69,12 @@ export const clearMeasures = (measreName: string, clearAll?: boolean) => { export const extractWindowObj = (str: string): string | null => { const re = /]*>([\s\S]*?)<\/script>/g; - const matches: any = str.match(re); + const matches = str.match(re); + + if (!matches) { + return null; + } + for (const matchStr of matches) { if (matchStr.includes('window.sso')) { return matchStr.replace('', ''); @@ -100,7 +106,7 @@ export const setDataInLocalStorage = (key: string, data: any) => { return true; }; -export const getDays = (day: any) => { +export const getDays = (day: string | number | Date) => { const presentDay = new Date().getTime(); const projectDate = new Date(day).getTime(); const time = presentDay - projectDate; From 9ac0dd8415f917803ca0645b3562c491d377f592 Mon Sep 17 00:00:00 2001 From: AishDani Date: Wed, 31 Jul 2024 11:01:53 +0530 Subject: [PATCH 02/13] refactor:removed console --- ui/src/pages/Migration/index.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/ui/src/pages/Migration/index.tsx b/ui/src/pages/Migration/index.tsx index 5af1b1fc..88e90960 100644 --- a/ui/src/pages/Migration/index.tsx +++ b/ui/src/pages/Migration/index.tsx @@ -322,9 +322,6 @@ const Migration = () => { dispatch(updateNewMigrationData((newMigrationDataObj))); } - useEffect(() => { - console.log('Migration component rendered'); - }, []); return (
From 419bd9e51a4c67f49b3358338471e16eaaaa974e Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Wed, 31 Jul 2024 15:19:18 +0530 Subject: [PATCH 03/13] Added clearable option feature in the field dropdown for Existing stack --- ui/src/components/ContentMapper/index.tsx | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 2030ef4b..67bfcc0a 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -910,8 +910,6 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re return OptionsForRow; }; - - const SelectAccessorOfColumn = (data: FieldMapType) => { // Fetch options for the current row from dummy_obj based on backupFieldType( empty stack options) @@ -1042,17 +1040,17 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re }; const adjustedOptions = (OptionsForRow.length === 0 && !contentTypeSchema) ? option : - (OptionsForRow.length > 0 && OptionsForRow.every((item)=>item.isDisabled) && OptionValue.label === dummy_obj[data?.ContentstackFieldType]?.label) ? [] + (OptionsForRow.length > 0 && OptionsForRow.every((item)=>item.isDisabled) && OptionValue.label === dummy_obj[data?.ContentstackFieldType]?.label) ? [] : OptionsForRow.map((option: optionsType) => ({ ...option, isDisabled: selectedOptions.includes(option?.label ?? '') })); - + return (
; className?: string; emptyStateMsg?: string | JSX.Element; - stepComponentProps?: any; hideTabView?: boolean; stepContentClassName?: string; stepTitleClassName?: string; testId?: string; - handleSaveCT: () => {}; + handleSaveCT?: () => void; changeDropdownState: () => void; }; @@ -42,7 +51,7 @@ export type HorizontalStepperHandles = { const HorizontalStepper = forwardRef( (props: stepperProps, ref: React.ForwardedRef) => { - const { steps, className, emptyStateMsg, stepComponentProps, hideTabView, testId } = props; + const { steps, className, emptyStateMsg, hideTabView, testId } = props; const [showStep, setShowStep] = useState(0); const [stepsCompleted, setStepsCompleted] = useState([]); const [isModalOpen, setIsModalOpen] = useState(false); @@ -121,6 +130,9 @@ const HorizontalStepper = forwardRef( navigate(url, { replace: true }); } } + + //variable for button component in table + const onlyIcon= true; const StepsTitleCreator: React.FC = () => (
@@ -133,7 +145,6 @@ const HorizontalStepper = forwardRef( !stepsCompleted.includes(idx) && idx !== showStep && !stepsCompleted?.includes(idx - 1) ? 'disableEvents' : ''; - return (
@@ -145,7 +156,8 @@ const HorizontalStepper = forwardRef(
{completedClass ? (
- + {/* */} +
) : ( <>{idx + 1} diff --git a/ui/src/pages/Migration/index.tsx b/ui/src/pages/Migration/index.tsx index 88e90960..b0e0423d 100644 --- a/ui/src/pages/Migration/index.tsx +++ b/ui/src/pages/Migration/index.tsx @@ -24,6 +24,7 @@ import { IFlowStep } from '../../components/Stepper/FlowStepper/flowStep.interface'; import { INewMigration } from '../../context/app/app.interface'; +import { ContentTypeSaveHandles } from '../../components/ContentMapper/contentMapper.interface'; // Components @@ -43,7 +44,6 @@ type LegacyCmsRef = { getInternalActiveStepIndex: () => number; }; - const Migration = () => { const [projectData, setProjectData] = useState(); const [isLoading, setIsLoading] = useState(false); @@ -60,7 +60,7 @@ const Migration = () => { const selectedOrganisation = useSelector((state: RootState)=>state?.authentication?.selectedOrganisation); const newMigrationData = useSelector((state:RootState)=> state?.migration?.newMigrationData); - const saveRef = useRef(null); + const saveRef = useRef(null); useEffect(() => { fetchData(); @@ -148,9 +148,7 @@ const Migration = () => { data: , id:'5', title:'Migration Execution' - }, - - + } ] return steps; } From 14084f9671a1e7fc3e72ebe3712e77e46b09dd5c Mon Sep 17 00:00:00 2001 From: AishDani Date: Mon, 5 Aug 2024 16:54:11 +0530 Subject: [PATCH 05/13] refactor:When multiple groups are present and you select group 1 then below all the fields from group 1 should display --- ui/src/components/ContentMapper/index.tsx | 138 ++++++++++++++---- .../HorizontalStepper/HorizontalStepper.tsx | 36 ++++- 2 files changed, 145 insertions(+), 29 deletions(-) diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index af6462cf..dac1c1c2 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -271,6 +271,10 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re const [isModalOpen, setIsModalOpen] = useState(false); const [nestedList, setNestedList] = useState([]); const [disabledOptions, setDisabledOptions] = useState>(new Set()); + const [isUpdated, setIsUpdated] = useState(false); + let updatedRows: FieldMapType[] = tableData; + let updatedExstingField: ExistingFieldType = exstingField; + const updatedSelectedOptions :string[] = selectedOptions; /** ALL HOOKS Here */ const { projectId = '' } = useParams(); @@ -303,7 +307,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re field._canSelect = true; } }); - }); + },[]); useEffect(() => { if (contentTypeMapped && otherCmsTitle) { @@ -847,6 +851,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re value: any, data: any, array: any, + groupArray:any[], OptionsForRow: any[], fieldsOfContentstack: any, currentDisplayName = '' @@ -861,30 +866,46 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re OptionsForRow.push(getMatchingOption(value, true, updatedDisplayName)); - // Process nested groups within this group - for (const key of value.schema || []) { - if (key?.data_type === 'group') { - processSchema(key, data, array, OptionsForRow, fieldsOfContentstack, updatedDisplayName); - } - } } - // Process nested schemas within the current group - for (const item of array) { - const fieldTypeToMatch = fieldsOfContentstack[item?.otherCmsType as keyof Mapping]; - if (item.id === data?.id) { - for (const key of value.schema || []) { - if (checkConditions(fieldTypeToMatch, key, item)) { - OptionsForRow.push(getMatchingOption(key, true, `${updatedDisplayName} > ${key.display_name}` || '')); - } - - // Recursively process nested groups - if (key?.data_type === 'group') { - processSchema(key, data, array, OptionsForRow, fieldsOfContentstack, updatedDisplayName); + + const existingLabel = exstingField[groupArray[0]?.uid]?.label || ''; + const lastLabelSegment = existingLabel.includes('>') + ? existingLabel?.split('>')?.pop()?.trim() + : existingLabel; + + if(value.display_name === lastLabelSegment) + { + // Process nested schemas within the current group + for (const item of array) { + const fieldTypeToMatch = fieldsOfContentstack[item?.otherCmsType as keyof Mapping]; + if (item.id === data?.id) { + for (const key of exstingField[groupArray[0]?.uid]?.value.schema || []) { + + if (checkConditions(fieldTypeToMatch, key, item)) { + OptionsForRow.push(getMatchingOption(key, true, `${updatedDisplayName} > ${key.display_name}` || '')); + break; + } + + // Recursively process nested groups + if (key?.data_type === 'group') { + processSchema(key, data, array, groupArray,OptionsForRow, fieldsOfContentstack, updatedDisplayName); + } + } } } - } + } - } else { + else{ + for (const key of value.schema || []) { + if (key?.data_type === 'group') { + processSchema(key, data, array, groupArray, OptionsForRow, fieldsOfContentstack, updatedDisplayName); + } + } + + } + + } + else { const fieldTypeToMatch = fieldsOfContentstack[data?.otherCmsType as keyof Mapping]; if (!array.some((item :any)=> item.id === data?.id) && checkConditions(fieldTypeToMatch, value, data)) { @@ -901,7 +922,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re // Recursively process nested groups if (key?.data_type === 'group') { - processSchema(key, data, array, OptionsForRow, fieldsOfContentstack, updatedDisplayName); + processSchema(key, data, array,groupArray, OptionsForRow, fieldsOfContentstack, updatedDisplayName); } } } @@ -976,7 +997,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re const array = groupArray[0]?.child || [] if(value.data_type === 'group'){ - processSchema(value, data, array, OptionsForRow, fieldsOfContentstack) + processSchema(value, data, array,groupArray, OptionsForRow, fieldsOfContentstack) } else if (!array.some(item => item.id === data?.id) && checkConditions(fieldTypeToMatch, value, data)) { @@ -988,7 +1009,55 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re } const selectedOption = OptionsForRow.length; - + + // Handle case where there is exactly one match and it is auto-mapped + if(OptionsForRow.length === 1 && + (OptionsForRow[0]?.value?.uid === 'url' || OptionsForRow[0]?.value?.uid === 'title' || OptionsForRow[0]?.value?.data_type === 'group' || OptionsForRow[0]?.value?.data_type === 'reference')) + { + updatedRows = updatedRows.map((row) => { + if (row?.uid === data?.uid) { + return { + ...row, + contentstackField: OptionsForRow[0]?.value?.display_name, + advanced: { + validationRegex: OptionsForRow[0]?.value?.format, + Mandatory: OptionsForRow[0]?.value?.mandatory, + Multiple: OptionsForRow[0]?.value?.multiple, + Unique: OptionsForRow[0]?.value?.unique, + NonLocalizable: OptionsForRow[0]?.value?.non_localizable, + }, + }; + } + return row; + }); + + // Disable option if it's not already in exstingField + if (!exstingField[data?.uid] && OptionsForRow[0]) { + OptionsForRow[0].isDisabled = true; + } + const newLabel = OptionsForRow[0]?.value?.display_name; + const newvalue = OptionsForRow[0]?.value; + + // Check if there's already a matching entry in updatedExstingField + const hasMatchingEntry = Object.values(updatedExstingField).some( + (entry) =>{ return entry?.label === newLabel } + ); + + if (!hasMatchingEntry) { + updatedExstingField = { + ...updatedExstingField, + [data?.uid]: { label: newLabel, value: newvalue } + }; + } + + const newValue = OptionsForRow[0]?.value?.display_name; + if (!updatedSelectedOptions[newValue]) { + updatedSelectedOptions.push(newValue); + } + setIsUpdated(true); + + } + let option: any; if (Array.isArray(OptionsForEachRow)) { option = OptionsForEachRow.map((option) => ({ @@ -1007,9 +1076,9 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re } else { option = [{ label: OptionsForEachRow, value: OptionsForEachRow }]; } - + const OptionValue: any = - OptionsForRow.length === 1 && + OptionsForRow.length === 1 && (exstingField[data?.uid] || updatedExstingField[data?.uid] ) && (OptionsForRow[0]?.value?.uid === 'url' || OptionsForRow[0]?.value?.uid === 'title' || OptionsForRow[0]?.value?.data_type === 'group' || OptionsForRow[0]?.value?.data_type === 'reference') ? { label: OptionsForRow[0]?.value?.display_name, @@ -1017,7 +1086,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re isDisabled: true } : (OptionsForRow.length === 0 || (OptionsForRow.length > 0 && OptionsForRow.every((item)=>item.isDisabled) - && ! exstingField[data?.uid] )) + && (!exstingField[data?.uid] || ! updatedExstingField[data?.uid] ) )) ? { label: dummy_obj[data?.ContentstackFieldType]?.label, value: dummy_obj[data?.ContentstackFieldType]?.label, @@ -1073,6 +1142,21 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re ); }; + + useEffect(() => { + if (isUpdated) { + setTableData(updatedRows as FieldMapType[]); + setexsitingField(updatedExstingField); + setSelectedOptions(updatedSelectedOptions); + setIsUpdated(false); + } + else{ + setexsitingField({}); + setSelectedOptions([]); + + } + }, [isUpdated, OtherContentType]); + const handleSaveContentType = async () => { const orgId = selectedOrganisation?.uid; const projectID = projectId; diff --git a/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.tsx b/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.tsx index c37037bd..49c6981e 100644 --- a/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.tsx +++ b/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.tsx @@ -1,7 +1,9 @@ // Libraries import React, { useState, useImperativeHandle, forwardRef, useEffect } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import { cbModal, Button } from '@contentstack/venus-components'; +import './HorizontalStepper.scss'; +import { Icon, cbModal, Notification,Button } from '@contentstack/venus-components'; + import { useSelector } from 'react-redux'; // Redux @@ -49,6 +51,31 @@ export type HorizontalStepperHandles = { handleStepChange: (currentStep: number) => void; }; +const showNotification = (currentIndex:number) =>{ + console.log("current Index ===> ", currentIndex); + + let result; + switch (currentIndex ) { + case 0: + result = 'CMS'; + break; + case 1: + result = 'Enter Affix'; + break; + case 2: + result = 'Imported File'; + break; + + } + return( + currentIndex !== 3 && currentIndex !== 4 && + Notification({ + notificationContent: { text: `Please complete ${result} step` }, + type: 'warning' + }) + + ) +} const HorizontalStepper = forwardRef( (props: stepperProps, ref: React.ForwardedRef) => { const { steps, className, emptyStateMsg, hideTabView, testId } = props; @@ -118,7 +145,12 @@ const HorizontalStepper = forwardRef( shouldCloseOnOverlayClick: false } }); - } else { + } + else if(-1 < newMigrationData?.legacy_cms?.currentStep && + newMigrationData?.legacy_cms?.currentStep < 2){ + showNotification(newMigrationData?.legacy_cms?.currentStep + 1); + } + else { setTabStep(idx); } }; From 8df5fa42886f0f11d87c08792bf0191933a89eed Mon Sep 17 00:00:00 2001 From: AishDani Date: Mon, 5 Aug 2024 16:59:27 +0530 Subject: [PATCH 06/13] refactore:removed api call to send new created stack details to backend --- ui/src/components/DestinationStack/Actions/LoadStacks.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ui/src/components/DestinationStack/Actions/LoadStacks.tsx b/ui/src/components/DestinationStack/Actions/LoadStacks.tsx index 19032ace..a04c876e 100644 --- a/ui/src/components/DestinationStack/Actions/LoadStacks.tsx +++ b/ui/src/components/DestinationStack/Actions/LoadStacks.tsx @@ -125,13 +125,6 @@ const LoadStacks = (props: LoadFileFormatProps) => { // console.log("Updating newMigrationData:", newMigrationDataObj); dispatch(updateNewMigrationData(newMigrationDataObj)); - // API call for saving selected CMS - if (resp?.data?.stack?.api_key) { - updateDestinationStack(selectedOrganisation?.value, projectId, { - stack_api_key: resp?.data?.stack?.api_key - }); - } - // call for Step Change props.handleStepChange(props?.currentStep, true); From c0f9228c0c114f8b07ed807f4daaba52343ac718 Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Tue, 6 Aug 2024 12:38:17 +0530 Subject: [PATCH 07/13] SNYK errors resolved --- .../components/DestinationStack/Actions/LoadStacks.tsx | 10 ++++++---- ui/src/components/Modal/index.tsx | 5 ++++- .../Stepper/HorizontalStepper/HorizontalStepper.tsx | 10 ++++++---- ui/src/context/app/app.interface.ts | 2 +- ui/src/reportWebVitals.js | 3 +++ uplaode-api/package.json | 4 ++-- uplaode-api/src/services/fileProcessing.ts | 4 ++-- uplaode-api/tsconfig.json | 4 ++-- 8 files changed, 26 insertions(+), 16 deletions(-) diff --git a/ui/src/components/DestinationStack/Actions/LoadStacks.tsx b/ui/src/components/DestinationStack/Actions/LoadStacks.tsx index a04c876e..a0936a02 100644 --- a/ui/src/components/DestinationStack/Actions/LoadStacks.tsx +++ b/ui/src/components/DestinationStack/Actions/LoadStacks.tsx @@ -74,12 +74,12 @@ const LoadStacks = (props: LoadFileFormatProps) => { //Handle new stack details const handleOnSave = async (data: Stack) => { - if (isSaving) return false; + // if (isSaving) return false; setIsSaving(true); if (isEmptyString(data?.name) || isEmptyString(data?.locale)) { setIsSaving(false); - return false; + // return false; } // Post data to backend @@ -129,8 +129,10 @@ const LoadStacks = (props: LoadFileFormatProps) => { props.handleStepChange(props?.currentStep, true); return true; - } - return false; + } + // else { + // return false; + // } }; /**** ALL METHODS HERE ****/ diff --git a/ui/src/components/Modal/index.tsx b/ui/src/components/Modal/index.tsx index 5144e6f8..cdc8d317 100644 --- a/ui/src/components/Modal/index.tsx +++ b/ui/src/components/Modal/index.tsx @@ -44,11 +44,14 @@ const Modal = (props: ProjectModalProps) => { // const payload = {name: values?.name, description: values?.description || ''} const res = await createProject(selectedOrg?.uid || '', values); + if (res?.error) { + return res?.error; + } if (res?.status === 201) { const projectId = res?.data?.project?.id window.location.href = `/projects/${projectId}/migration/steps/1`; } - return res?.error ? false : res; + return res; }; const nameValidation = (value: string) => { diff --git a/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.tsx b/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.tsx index 49c6981e..d1d68f47 100644 --- a/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.tsx +++ b/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.tsx @@ -2,7 +2,7 @@ import React, { useState, useImperativeHandle, forwardRef, useEffect } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import './HorizontalStepper.scss'; -import { Icon, cbModal, Notification,Button } from '@contentstack/venus-components'; +import { cbModal, Notification,Button } from '@contentstack/venus-components'; import { useSelector } from 'react-redux'; @@ -83,7 +83,7 @@ const HorizontalStepper = forwardRef( const [stepsCompleted, setStepsCompleted] = useState([]); const [isModalOpen, setIsModalOpen] = useState(false); - const { stepId } = useParams<{ stepId: any }>(); + const { stepId } = useParams<{ stepId: string }>(); const navigate = useNavigate(); const { projectId = '' } = useParams(); @@ -95,8 +95,9 @@ const HorizontalStepper = forwardRef( useBlockNavigation(isModalOpen); useEffect(() => { - const stepIndex = parseInt(stepId, 10) - 1; - if (!isNaN(stepIndex) && stepIndex >= 0 && stepIndex < steps?.length) { + const stepIndex = parseInt(stepId || '', 10) - 1; + + if (!Number.isNaN(stepIndex) && stepIndex >= 0 && stepIndex < steps?.length) { setShowStep(stepIndex); setStepsCompleted(prev => { const updatedStepsCompleted = [...prev]; @@ -222,5 +223,6 @@ const HorizontalStepper = forwardRef( ); } ); + HorizontalStepper.displayName = 'HorizontalStepper'; export default HorizontalStepper; diff --git a/ui/src/context/app/app.interface.ts b/ui/src/context/app/app.interface.ts index f041d293..749bbbf3 100644 --- a/ui/src/context/app/app.interface.ts +++ b/ui/src/context/app/app.interface.ts @@ -190,7 +190,7 @@ export interface IMigrationData { testmigrationData: ITestMigration; } -export interface IDropDown { +export interface IDropDown { uid?: string; label: string; value: string; diff --git a/ui/src/reportWebVitals.js b/ui/src/reportWebVitals.js index 532f29b0..cf1a2121 100644 --- a/ui/src/reportWebVitals.js +++ b/ui/src/reportWebVitals.js @@ -6,6 +6,9 @@ const reportWebVitals = (onPerfEntry) => { getFCP(onPerfEntry); getLCP(onPerfEntry); getTTFB(onPerfEntry); + }) + .catch(error => { + console.error('Error:', error); }); } }; diff --git a/uplaode-api/package.json b/uplaode-api/package.json index 382b021b..17a4b39f 100644 --- a/uplaode-api/package.json +++ b/uplaode-api/package.json @@ -31,7 +31,7 @@ "typescript": "^5.3.3" }, "dependencies": { - "@aws-sdk/client-s3": "^3.490.0", + "@aws-sdk/client-s3": "^3.529.0", "@contentstack/cli-utilities": "^1.5.12", "@typescript-eslint/parser": "^7.7.1", "axios": "^1.6.8", @@ -52,4 +52,4 @@ "node-fetch": "^2.7.0", "prettier": "^2.7.1" } -} \ No newline at end of file +} diff --git a/uplaode-api/src/services/fileProcessing.ts b/uplaode-api/src/services/fileProcessing.ts index 4a92b700..5df0fe6b 100644 --- a/uplaode-api/src/services/fileProcessing.ts +++ b/uplaode-api/src/services/fileProcessing.ts @@ -10,7 +10,7 @@ const handleFileProcessing = async (fileExt: string, zipBuffer: any, cmsType: st if (fileExt === 'zip') { const zip = new JSZip(); await zip.loadAsync(zipBuffer); - if (await validator({ data: zip, type: cmsType, extension: fileExt })) { + if (validator({ data: zip, type: cmsType, extension: fileExt })) { const isSaved = await saveZip(zip); if (isSaved) { logger.info('Validation success:', { @@ -38,7 +38,7 @@ const handleFileProcessing = async (fileExt: string, zipBuffer: any, cmsType: st // if file is not zip // Convert the buffer to a string assuming it's UTF-8 encoded const jsonString = Buffer?.from?.(zipBuffer)?.toString?.('utf8'); - if (await validator({ data: jsonString, type: cmsType, extension: fileExt })) { + if (validator({ data: jsonString, type: cmsType, extension: fileExt })) { logger.info('Validation success:', { status: HTTP_CODES?.OK, message: HTTP_TEXTS?.VALIDATION_SUCCESSFULL, diff --git a/uplaode-api/tsconfig.json b/uplaode-api/tsconfig.json index 51793fe2..dbb6d8bb 100644 --- a/uplaode-api/tsconfig.json +++ b/uplaode-api/tsconfig.json @@ -32,7 +32,7 @@ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + "typeRoots": ["./node_modules/@types", "./expree.d.ts"], /* Specify multiple folders that act like './node_modules/@types'. */ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ @@ -107,6 +107,6 @@ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, - "include": ["src/**/*.ts"], + "include": ["src/**/*.ts", "express.d.ts"], "exclude": ["node_modules", "build"] } From a569671172603703e99fad927cc8ec2b27d6cead Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Tue, 6 Aug 2024 12:41:47 +0530 Subject: [PATCH 08/13] [CMG-281] - Content Mapper | When an existing stack is chosen or a new stack is selected, the changes do not appear on the content mapper page until you refresh it. --- ui/src/components/ContentMapper/index.tsx | 25 ++++++++--------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index dac1c1c2..f806f9a2 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -296,10 +296,16 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re .catch((err) => { console.error(err); }); - stackStatus(); + fetchExistingContentTypes(); }, []); + useEffect(() => { + if (newMigrationData?.destination_stack?.selectedStack?.value || projectData?.destination_stack_id) { + stackStatus(); + } + }, [newMigrationData?.destination_stack?.selectedStack?.value || projectData?.destination_stack_id]) + // Make title and url field non editable useEffect(() => { tableData?.forEach((field) => { @@ -390,7 +396,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re const stackStatus = async () => { const contentTypeCount = await getStackStatus( projectData?.org_id || selectedOrganisation?.value, - projectData?.destination_stack_id || newMigrationData?.destination_stack?.selectedStack?.value + newMigrationData?.destination_stack?.selectedStack?.value || projectData?.destination_stack_id ); if (contentTypeCount?.data?.contenttype_count > 0) { @@ -1142,21 +1148,6 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re ); }; - - useEffect(() => { - if (isUpdated) { - setTableData(updatedRows as FieldMapType[]); - setexsitingField(updatedExstingField); - setSelectedOptions(updatedSelectedOptions); - setIsUpdated(false); - } - else{ - setexsitingField({}); - setSelectedOptions([]); - - } - }, [isUpdated, OtherContentType]); - const handleSaveContentType = async () => { const orgId = selectedOrganisation?.uid; const projectID = projectId; From be715099dd8a269e5044b6afec3d2ad804032e79 Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Tue, 6 Aug 2024 14:57:50 +0530 Subject: [PATCH 09/13] [CMG-282] - Content Mapper | LHS | On hover of Content type and Global fields icon, it shows 'content_type' and 'global_field instead of 'Content type' and 'Global field' --- .../ContentMapper/contentMapper.interface.ts | 1 + ui/src/components/ContentMapper/index.scss | 66 +++++++------ ui/src/components/ContentMapper/index.tsx | 94 +++++++++++-------- ui/src/scss/App.scss | 3 + 4 files changed, 96 insertions(+), 68 deletions(-) diff --git a/ui/src/components/ContentMapper/contentMapper.interface.ts b/ui/src/components/ContentMapper/contentMapper.interface.ts index e28d77e9..e8ec2c26 100644 --- a/ui/src/components/ContentMapper/contentMapper.interface.ts +++ b/ui/src/components/ContentMapper/contentMapper.interface.ts @@ -138,5 +138,6 @@ export interface ContentTypeMap { export interface ContentTypeSaveHandles { handleSaveContentType: () => void; } +export type MouseOrKeyboardEvent = React.MouseEvent | React.KeyboardEvent; diff --git a/ui/src/components/ContentMapper/index.scss b/ui/src/components/ContentMapper/index.scss index 3d635b4b..4949e199 100644 --- a/ui/src/components/ContentMapper/index.scss +++ b/ui/src/components/ContentMapper/index.scss @@ -63,43 +63,47 @@ list-style-type: none; padding: 15px 0 15px 0; li { - align-items: center; - cursor: pointer; - display: flex; - font-size: $size-font-xl; - justify-content: space-between; - line-height: normal; - min-height: 42px; - padding: $px-8 $px-10 $px-8 $px-12; - &:hover, &.active-ct { - background-color: $color-brand-white-base; - .cms-title { - span { - color: $color-brand-primary-base; - } - } - } - .cms-title { + .list-button { align-items: center; + background: none; + cursor: pointer; display: flex; - margin-right: $px-12; - max-height: 24px; - white-space: nowrap; - width: 80%; - .tippy-wrapper { + font-size: $size-font-xl; + justify-content: space-between; + line-height: normal; + min-height: 42px; + padding: $px-8 $px-10 $px-8 $px-12; + width: 100%; + &:hover, &.active-ct { + background-color: $color-brand-white-base; + .cms-title { + span { + color: $color-brand-primary-base; + } + } + } + .cms-title { + align-items: center; display: flex; + margin-right: $px-12; + max-height: 24px; + white-space: nowrap; + width: 70%; + .tippy-wrapper { + display: flex; + } + span { + color: $color-font-base; + margin-left: $px-10; + overflow: hidden; + text-overflow: ellipsis; + } } - span { - color: $color-font-base; - margin-left: $px-10; - overflow: hidden; - text-overflow: ellipsis; + .ct-options { + justify-content: flex-end; } } - .ct-options { - justify-content: flex-end; - } - } + } } .mapped-icon { circle { diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index f806f9a2..a02a2ae3 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -49,7 +49,8 @@ import { UidMap, ContentTypeMap, Advanced, - ContentTypeSaveHandles + ContentTypeSaveHandles, + MouseOrKeyboardEvent } from './contentMapper.interface'; import { ItemStatusMapProp } from '@contentstack/venus-components/build/components/Table/types'; import { ModalObj } from '../Modal/modal.interface'; @@ -1355,7 +1356,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re } // Function to filter content types as per the status - const handleContentTypeFilter = (value: string, e: React.MouseEvent) => { + const handleContentTypeFilter = (value: string, e: MouseOrKeyboardEvent) => { const li_list = document.querySelectorAll('.filter-wrapper li'); if(li_list) { li_list.forEach((ele) => { @@ -1425,12 +1426,18 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re
    {Object.keys(CONTENT_MAPPING_STATUS).map((key, keyInd) => ( - <> -
  • handleContentTypeFilter(CONTENT_MAPPING_STATUS[key], e)}> - {CONTENT_MAPPING_STATUS[key] && {CONTENT_MAPPING_STATUS[key]} } - {STATUS_ICON_Mapping[key] && } -
  • - +
  • + +
  • ))}
@@ -1443,38 +1450,51 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re
    {filteredContentTypes?.map((content: ContentType, index: number) => { const icon = STATUS_ICON_Mapping[content?.status] || ''; - + + const format = (str: string) => { + const frags = str.split('_'); + for (let i = 0; i < frags?.length; i++) { + frags[i] = frags[i].charAt(0).toUpperCase() + frags[i].slice(1); + } + return frags.join(' '); + } return ( -
  • handleOpenContentType(index)} - onKeyDown={() => handleOpenContentType(index)} - > -
    - - {content?.type === "content_type" - ? - : +
  • +
+ }} + > +
+ + {content?.type === "content_type" + ? + : + } + + {content?.otherCmsTitle && {content?.otherCmsTitle} } +
-
- - {icon && ( - - +
+ + {icon && ( + + + + )} + + + + handleSchemaPreview(content?.otherCmsTitle)} /> - )} - - - - handleSchemaPreview(content?.otherCmsTitle)} /> - - -
+
+
+ ) })} @@ -1492,7 +1512,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re canSearch={true} data={tableData?.length ? [...tableData] : []} columns={columns} - uniqueKey={'id' || ''} + uniqueKey={'id'} isRowSelect // fullRowSelect itemStatusMap={itemStatusMap} diff --git a/ui/src/scss/App.scss b/ui/src/scss/App.scss index 4e749a23..4dc2f6cc 100644 --- a/ui/src/scss/App.scss +++ b/ui/src/scss/App.scss @@ -419,6 +419,9 @@ h2 { border-top: 1px solid $color-brand-secondary-lightest; } } +.list-button { + border: 0 none; +} ::-webkit-input-placeholder { color: $color-stepper-title !important; } From 6f900ef56e3dd0c05dc91e294cd55550eb3acd44 Mon Sep 17 00:00:00 2001 From: AishDani Date: Tue, 6 Aug 2024 16:43:51 +0530 Subject: [PATCH 10/13] refactor:content mapper bugs --- api/src/services/contentMapper.service.ts | 72 ++++++++++++------- ui/src/components/ContentMapper/index.tsx | 3 +- .../migration-sitecore/libs/reference.js | 2 +- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index 94a1f4b8..c14b60dd 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -286,13 +286,12 @@ const getExistingContentTypes = async (req: Request) => { * @throws ExceptionFunction if an error occurs while updating the content type. */ const updateContentType = async (req: Request) => { - const srcFun = "udateContentType"; + const srcFun = "updateContentType"; const { orgId, projectId, contentTypeId } = req.params; const { contentTypeData, token_payload } = req.body; const fieldMapping = contentTypeData?.fieldMapping; - // const updatedContentType: any = {}; - + // Read project data await ProjectModelLowdb.read(); const projectIndex = (await getProjectUtil( projectId, @@ -307,6 +306,7 @@ const updateContentType = async (req: Request) => { )) as number; const project = ProjectModelLowdb.data.projects[projectIndex]; + // Check project status if ( [NEW_PROJECT_STATUS[5], NEW_PROJECT_STATUS[4]].includes(project.status) || project.current_step < STEPPER_STEPS.CONTENT_MAPPING @@ -318,9 +318,13 @@ const updateContentType = async (req: Request) => { token_payload ) ); - throw new BadRequestError(HTTP_TEXTS.CANNOT_UPDATE_CONTENT_MAPPING); + return { + status: 400, + message: HTTP_TEXTS.CANNOT_UPDATE_CONTENT_MAPPING + }; } + // Validate contentTypeData if (isEmpty(contentTypeData)) { logger.error( getLogMessage( @@ -328,14 +332,21 @@ const updateContentType = async (req: Request) => { `${HTTP_TEXTS.INVALID_CONTENT_TYPE} Id: ${contentTypeId}` ) ); - throw new BadRequestError(HTTP_TEXTS.INVALID_CONTENT_TYPE); + return { + status: 400, + message: HTTP_TEXTS.INVALID_CONTENT_TYPE + }; } try { await ContentTypesMapperModelLowdb.read(); + const updateIndex = ContentTypesMapperModelLowdb.chain + .get("ContentTypesMappers") + .findIndex({ id: contentTypeId, projectId: projectId }) + .value(); if (fieldMapping) { - fieldMapping.forEach(async (field: any) => { + for (const field of fieldMapping) { if ( !field.ContentstackFieldType || field.ContentstackFieldType === "" || @@ -351,25 +362,24 @@ const updateContentType = async (req: Request) => { )}` ) ); - await ContentTypesMapperModelLowdb.read(); - ContentTypesMapperModelLowdb.update((data: any) => { - data.ContentTypesMappers[updateIndex].status = - CONTENT_TYPE_STATUS[3]; + await ContentTypesMapperModelLowdb.update((data: any) => { + data.ContentTypesMappers[updateIndex].status = CONTENT_TYPE_STATUS[3]; }); - throw new BadRequestError( - `${VALIDATION_ERRORS.STRING_REQUIRED.replace( + return { + status: 400, + message: `${VALIDATION_ERRORS.STRING_REQUIRED.replace( "$", "ContentstackFieldType or contentstackFieldUid" )}` - ); + }; } - }); + } } - const updateIndex = ContentTypesMapperModelLowdb.chain - .get("ContentTypesMappers") - .findIndex({ id: contentTypeId, projectId: projectId }) - .value(); + // const updateIndex = ContentTypesMapperModelLowdb.chain + // .get("ContentTypesMappers") + // .findIndex({ id: contentTypeId, projectId: projectId }) + // .value(); ContentTypesMapperModelLowdb.update((data: any) => { if (updateIndex >= 0) { data.ContentTypesMappers[updateIndex].otherCmsTitle = @@ -394,12 +404,15 @@ const updateContentType = async (req: Request) => { `${HTTP_TEXTS.CONTENT_TYPE_NOT_FOUND} Id: ${contentTypeId}` ) ); - throw new BadRequestError(HTTP_TEXTS.CONTENT_TYPE_NOT_FOUND); + return { + status: 404, + message: HTTP_TEXTS.CONTENT_TYPE_NOT_FOUND + }; } if (!isEmpty(fieldMapping)) { await FieldMapperModel.read(); - (fieldMapping || []).forEach((field: any) => { + fieldMapping.forEach((field: any) => { const fieldIndex = FieldMapperModel.data.field_mapper.findIndex( (f: any) => f?.id === field?.id ); @@ -411,18 +424,22 @@ const updateContentType = async (req: Request) => { } }); } - await ContentTypesMapperModelLowdb.read(); await ContentTypesMapperModelLowdb.update((data: any) => { data.ContentTypesMappers[updateIndex].status = CONTENT_TYPE_STATUS[2]; }); - // fetch updated data to return in response + + // Fetch and return updated content type await ContentTypesMapperModelLowdb.read(); const updatedContentType = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") .find({ id: contentTypeId, projectId: projectId }) .value(); - return { updatedContentType }; + return { + status: 200, + data: { updatedContentType } + }; + } catch (error: any) { logger.error( getLogMessage( @@ -431,12 +448,13 @@ const updateContentType = async (req: Request) => { error ) ); - throw new ExceptionFunction( - error?.message || HTTP_TEXTS.INTERNAL_ERROR, - error?.status || HTTP_CODES.SERVER_ERROR - ); + return { + status: error?.status || 500, + message: error?.message || HTTP_TEXTS.INTERNAL_ERROR + }; } }; + /** * Resets the field mapping and content mapping for a specific content type in a project. * diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index dac1c1c2..ccbe6d42 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -1148,6 +1148,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re setTableData(updatedRows as FieldMapType[]); setexsitingField(updatedExstingField); setSelectedOptions(updatedSelectedOptions); + setSelectedEntries(updatedRows); setIsUpdated(false); } else{ @@ -1224,7 +1225,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re )); } else { Notification({ - notificationContent: { text: data?.error?.message }, + notificationContent: { text: data?.message }, notificationProps: { position: 'bottom-center', hideProgressBar: true diff --git a/uplaode-api/migration-sitecore/libs/reference.js b/uplaode-api/migration-sitecore/libs/reference.js index d4f3ba13..31bafd40 100644 --- a/uplaode-api/migration-sitecore/libs/reference.js +++ b/uplaode-api/migration-sitecore/libs/reference.js @@ -96,7 +96,7 @@ function ExtractRef() { otherCmsType: "reference", contentstackField: newKey, contentstackFieldUid: uidCorrector({ uid: newKey }), - ContentstackFieldType: "refernce", + ContentstackFieldType: "reference", isDeleted: false, backupFieldType: "reference", refrenceTo: key, From b82bfa5be2dd3dd911b35301d9d71bc5f2fc34d7 Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Tue, 6 Aug 2024 17:24:23 +0530 Subject: [PATCH 11/13] [CMG-283], [CMG-284] --- ui/src/components/ContentMapper/index.scss | 36 ++++++++++++---------- ui/src/components/ContentMapper/index.tsx | 15 +++++++-- ui/src/scss/App.scss | 2 ++ 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/ui/src/components/ContentMapper/index.scss b/ui/src/components/ContentMapper/index.scss index 4949e199..612843a8 100644 --- a/ui/src/components/ContentMapper/index.scss +++ b/ui/src/components/ContentMapper/index.scss @@ -65,23 +65,13 @@ li { .list-button { align-items: center; - background: none; - cursor: pointer; display: flex; font-size: $size-font-xl; justify-content: space-between; line-height: normal; min-height: 42px; padding: $px-8 $px-10 $px-8 $px-12; - width: 100%; - &:hover, &.active-ct { - background-color: $color-brand-white-base; - .cms-title { - span { - color: $color-brand-primary-base; - } - } - } + .cms-title { align-items: center; display: flex; @@ -103,6 +93,16 @@ justify-content: flex-end; } } + &:hover, &.active-ct { + button { + background-color: $color-brand-white-base; + } + .cms-title { + span { + color: $color-brand-primary-base; + } + } + } } } .mapped-icon { @@ -247,12 +247,14 @@ div .table-row { top: $px-50; z-index: 1; li { - align-items: center; - cursor: pointer; - display: flex; - font-size: $size-font-medium; - justify-content: space-between; - padding: $px-8 $px-12; + button { + align-items: center; + display: flex; + justify-content: space-between; + font-size: $size-font-medium; + padding: $px-8 $px-12; + } + &:hover { background-color: $color-base-white-10; color: $color-brand-primary-base; diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index a02a2ae3..838940c5 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -1211,9 +1211,12 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re setisContentTypeMapped(true); setisContentTypeSaved(true); - setFilteredContentTypes(filteredContentTypes?.map(ct => + const savedCT = filteredContentTypes?.map(ct => ct?.id === data?.updatedContentType?.id ? { ...ct, status: data?.updatedContentType?.status } : ct - )); + ); + + setFilteredContentTypes(savedCT); + setContentTypes(savedCT); } else { Notification({ notificationContent: { text: data?.error?.message }, @@ -1365,8 +1368,8 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re } (e?.target as HTMLElement)?.closest('li')?.classList?.add('active-filter'); - const filteredCT = contentTypes?.filter((ct) => {return CONTENT_MAPPING_STATUS[ct?.status] === value}); + const filteredCT = contentTypes?.filter((ct) => {return CONTENT_MAPPING_STATUS[ct?.status] === value}); if (value !== 'All') { setFilteredContentTypes(filteredCT); setCount(filteredCT?.length); @@ -1428,6 +1431,8 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re {Object.keys(CONTENT_MAPPING_STATUS).map((key, keyInd) => (