diff --git a/ui/src/components/Card/index.tsx b/ui/src/components/Card/index.tsx index 496f4c6b..32eee662 100644 --- a/ui/src/components/Card/index.tsx +++ b/ui/src/components/Card/index.tsx @@ -29,7 +29,7 @@ const CardList = ({ project }: ProjectType) => { */ const onClickProject = (id: string) => { if (isEmptyString(id)) return; - navigate(`/projects/${id}/migration/steps/1`); + navigate(`/projects/${id}/migration/steps/${project?.current_step}`); }; const iconMapping: { [key: string]: string } = { diff --git a/ui/src/components/ContentMapper/index.scss b/ui/src/components/ContentMapper/index.scss index 6fe7d8cb..2c905b87 100644 --- a/ui/src/components/ContentMapper/index.scss +++ b/ui/src/components/ContentMapper/index.scss @@ -153,6 +153,10 @@ } .cms-field { text-transform: capitalize; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 445px; } .InstructionText { font-size: $size-font-small; diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 09931295..035a469a 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -206,11 +206,7 @@ const Fields: Mapping = { global_field: 'Global' }; -type ContentMapperComponentProps = { - projectData: MigrationResponse; -}; - -const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, ref: React.ForwardedRef) => { +const ContentMapper = forwardRef((props, ref: React.ForwardedRef) => { /** ALL CONTEXT HERE */ const migrationData = useSelector((state:RootState)=>state?.migration?.migrationData); @@ -358,23 +354,20 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re }, [contentTypeMapped, otherCmsTitle, contentModels]); - - useEffect(()=>{ - if(isContentDeleted){ + if(isContentDeleted) { setContentTypeMapped((prevState: ContentTypeMap) => { - const { [otherCmsTitle]: removed, ...newState } = prevState; + const { [otherCmsTitle]: removed, ...newState } = prevState; - return newState; - }); + return newState; + }); - setIsFieldDeleted(false); + setIsFieldDeleted(false); } - - },[isContentDeleted, contentModels, otherCmsTitle]) - + },[isContentDeleted, contentModels, otherCmsTitle]); + // useEffect for rendering mapped fields with existing stack useEffect(() => { if (contentTypeMapped[otherCmsTitle] === otherContentType?.label) { tableData?.forEach((row) => { @@ -387,18 +380,46 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re }; } + // 1st level group nesting if(schema?.schema) { schema?.schema?.forEach((childSchema) => { - if(row?.contentstackField === `${schema?.display_name} > ${childSchema?.display_name}`){ + if(row?.contentstackField === `${schema?.display_name} > ${childSchema?.display_name}`) { if(!isFieldDeleted) { - updatedExstingField[row?.uid] = { label: `${schema?.display_name} > ${childSchema?.display_name}`, value: childSchema } - } } + + // 2nd level group nesting + if (childSchema?.schema) { + // console.log("!!!!!!!!!!!!!!!!!!!", row, childSchema); + childSchema?.schema?.forEach((nestedSchema) => { + if (row?.contentstackField === `${schema?.display_name} > ${childSchema?.display_name} > ${nestedSchema?.display_name}`) { + if(!isFieldDeleted) { + updatedExstingField[row?.uid] = { + label: `${schema?.display_name} > ${childSchema?.display_name} > ${nestedSchema?.display_name}`, + value: nestedSchema + } + } + } + + // 3rd level group nesting + if (nestedSchema?.schema) { + nestedSchema?.schema?.forEach((nestedChild) => { + if (row?.contentstackField === `${schema?.display_name} > ${childSchema?.display_name} > ${nestedSchema?.display_name} > ${nestedChild?.display_name}`) { + if(!isFieldDeleted) { + updatedExstingField[row?.uid] = { + label: `${schema?.display_name} > ${childSchema?.display_name} > ${nestedSchema?.display_name} > ${nestedChild?.display_name}`, + value: nestedChild + } + } + } + }) + } + }) + } }) } }); @@ -693,7 +714,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re const accessorCall = (data: FieldMapType) => { return (
-
{data?.otherCmsField}
+
{data?.otherCmsField}
Type: {data?.otherCmsType}
@@ -1599,7 +1620,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re // Function to fetch single content type const handleFetchContentType = async () => { - const { data , status} = await fetchExistingContentType(projectId,'') ; + const { data } = await fetchExistingContentType(projectId,'') ; if(data?.contentTypes?.length <= 0){ Notification({ notificationContent: { text: "No content found in the stack" }, @@ -1620,7 +1641,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re setContentModels(data?.contentTypes); - const content_type = data?.contentTypes?.find((item:any)=>item?.title === otherContentType?.label); + const content_type = data?.contentTypes?.find((item: ContentTypeList)=>item?.title === otherContentType?.label); const contentTypeKey = Object.keys(contentTypeMapped).find(key => contentTypeMapped[key] === otherContentType?.label); @@ -1953,7 +1974,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re plural: `${totalCounts === 0 ? 'Count' : ''}` }} /> -
+
@@ -116,7 +66,7 @@ const MigrationFlowHeader = ({ handleOnClick, isLoading, isCompleted , legacyCMS aria-label='Save and Continue' isLoading={isLoading} > - {params?.stepId === '5' ? 'Start' : 'Save and Continue'} + {stepValue}
) diff --git a/ui/src/components/Modal/index.tsx b/ui/src/components/Modal/index.tsx index f5e369f1..3e76fbeb 100644 --- a/ui/src/components/Modal/index.tsx +++ b/ui/src/components/Modal/index.tsx @@ -15,7 +15,7 @@ import { import { Field as FinalField, Form as FinalForm } from 'react-final-form'; // Interface -import { ProjectModalProps } from './modal.interface'; +import { ProjectModalProps, FormData } from './modal.interface'; // Services import { useState } from 'react'; @@ -55,13 +55,7 @@ const Modal = (props: ProjectModalProps) => { }; const nameValidation = (value: string) => { - if (!value) { - setInputValue(false); - return 'Project name is required.'; - } else if (!/^[^\s].*$/.test(value)) { - setInputValue(false); - return 'Please enter project name.'; - } else if (value && value?.length > 200) { + if (value && value?.length > 200) { setInputValue(false); return 'Project Name should not be more than 200 chars'; } else { @@ -92,6 +86,16 @@ const Modal = (props: ProjectModalProps) => { { + const errors: any = {}; + if (!values.name || values.name === "") { + errors.name = 'Project name required'; + } else if (!/^[^\s].*$/.test(values.name)) { + errors.name = 'Please enter a valid project name.'; + } + return errors + }} render={({ handleSubmit }): JSX.Element => { return (
{ input.onChange(event); }} version="v2" - autoFocus={true} + // autoFocus={true} placeholder={namePlaceholder} data-testid="title-input" name="name" diff --git a/ui/src/components/Modal/modal.interface.ts b/ui/src/components/Modal/modal.interface.ts index 113f4434..643b196c 100644 --- a/ui/src/components/Modal/modal.interface.ts +++ b/ui/src/components/Modal/modal.interface.ts @@ -18,3 +18,7 @@ export interface SettingsModalProps { closeModal: () => void; navigate: (url: string) => void; } + +export interface FormData { + name?: string; +} diff --git a/ui/src/components/ProfileHeader/index.scss b/ui/src/components/ProfileHeader/index.scss index 26361a47..2552bd8b 100644 --- a/ui/src/components/ProfileHeader/index.scss +++ b/ui/src/components/ProfileHeader/index.scss @@ -3,7 +3,6 @@ .profile-card { width: 300px; padding: 11px 16px; - // background-color: #f8f9fa; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); text-align: center; } @@ -31,13 +30,15 @@ color: #6E6B86; font-size: $size-font-large; font-weight: $font-weight-semi-bold; + line-height: $line-height-default; margin-bottom: 5px; text-transform: capitalize; } .profile-card__email { - font-size: $size-font-small; color: #6E6B86; + font-size: $size-font-small; + line-height: $line-height-default; } .profile-card__logout { diff --git a/ui/src/components/TestMigration/index.tsx b/ui/src/components/TestMigration/index.tsx index a4bdf8b7..3671c760 100644 --- a/ui/src/components/TestMigration/index.tsx +++ b/ui/src/components/TestMigration/index.tsx @@ -1,7 +1,10 @@ import { useEffect, useState } from 'react'; -import { Field, FieldLabel, TextInput, Link, Icon, Tooltip } from '@contentstack/venus-components'; +import { Field, FieldLabel, TextInput, Link, Icon, Tooltip, Button } from '@contentstack/venus-components'; import { useSelector } from 'react-redux'; +// Redux files +import { RootState } from '../../store'; + // Services import { getCMSDataFromFile } from '../../cmsData/cmsSelector'; @@ -20,7 +23,7 @@ import './index.scss'; const TestMigration = () => { const [data, setData] = useState({}); - const newMigrationData = useSelector((state:any)=>state?.migration?.newMigrationData); + const newMigrationData = useSelector((state: RootState)=>state?.migration?.newMigrationData); /********** ALL USEEFFECT HERE *************/ @@ -39,40 +42,59 @@ const TestMigration = () => {
UID
-

Select your current Content Management system from the available options.

- Test Migration is a step where some content types are migrated in a test stack for review. A user can verify the stack and data. If the data is migrated properly then it can proceed with the final Migration Execution process.

+ + {(newMigrationData?.test_migration?.stack_api_key || newMigrationData?.test_migration?.stack_link) && + + + Test Stack + +
+ {newMigrationData?.test_migration?.stack_api_key && ( + + )} - {newMigrationData?.test_migration?.stack_link && ( - - - - - - )} -
-
+ {newMigrationData?.test_migration?.stack_link && ( + + + + + + )} + + +
+ + }
diff --git a/ui/src/components/layout/AppLayout/index.tsx b/ui/src/components/layout/AppLayout/index.tsx index 295985da..47a94058 100644 --- a/ui/src/components/layout/AppLayout/index.tsx +++ b/ui/src/components/layout/AppLayout/index.tsx @@ -25,8 +25,7 @@ const AppLayout: FC = ({ children }) => { useEffect(()=>{ dispatch(getUserDetails()); - - },[dispatch]); + },[]); useAuthCheck(); diff --git a/ui/src/pages/Login/index.tsx b/ui/src/pages/Login/index.tsx index b5e684ae..060ee5bd 100644 --- a/ui/src/pages/Login/index.tsx +++ b/ui/src/pages/Login/index.tsx @@ -3,7 +3,7 @@ import { FC,useEffect, useState } from 'react'; import { useNavigate, useLocation } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; -import { setAuthToken } from '../../store/slice/authSlice'; +import { getUserDetails, setAuthToken } from '../../store/slice/authSlice'; import { Button, Field, @@ -166,6 +166,9 @@ const Login: FC = () => { dispatch(setAuthToken(authenticationObj)); setLoginStates((prev) => ({ ...prev, submitted: true })); + + dispatch(getUserDetails()); + navigate(`/projects`, { replace: true }); } }; diff --git a/ui/src/pages/Migration/index.tsx b/ui/src/pages/Migration/index.tsx index 9ef616df..c43de92b 100644 --- a/ui/src/pages/Migration/index.tsx +++ b/ui/src/pages/Migration/index.tsx @@ -225,8 +225,7 @@ const Migration = () => { title:'Destination Stack' }, { - data: , + data: , id:'3', title:'Content Mapping' }, @@ -485,12 +484,14 @@ const Migration = () => {
- + {projectData && + <> +
- { projectData && - }
+ + }
diff --git a/ui/src/pages/MigrationEditor/index.scss b/ui/src/pages/MigrationEditor/index.scss deleted file mode 100644 index 3cc4e410..00000000 --- a/ui/src/pages/MigrationEditor/index.scss +++ /dev/null @@ -1,39 +0,0 @@ -@import '../../scss/variables'; -.migration-container { - #PageLayout__body { - //display: flex; - margin-left: 0; - width: 100% !important; - background: $color-base-white-10; - padding: 0; - overflow: hidden; - } - .PageTitle { - margin-left: 1rem; - font-weight: 700; - font-size: 18px; - font-family: Inter, sans-serif; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - line-height: normal; - } - .step-flow-wrapper-tree-area { - // border-right: 1px solid $color-base-gray-40; - display: flex; - max-width: 380px; - min-width: 378px; - max-height: 94vh; - min-height: calc(100vh - 115px); - } - .step-flow-wrapper-content-area { - display: flex; - flex-direction: column; - flex-grow: 1; - // justify-content: center; - // max-height: calc(100vh - 37px); - // overflow-y: auto; - // overflow-x: hidden; - width: calc(100% - 420px); - } -} diff --git a/ui/src/pages/MigrationEditor/index.tsx b/ui/src/pages/MigrationEditor/index.tsx deleted file mode 100644 index 69db889d..00000000 --- a/ui/src/pages/MigrationEditor/index.tsx +++ /dev/null @@ -1,72 +0,0 @@ -// Libraries -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 { DEFAULT_NEW_MIGRATION } from '../../context/app/app.interface'; - -// Service -import { getProject } from '../../services/api/project.service'; - -//Component -import NewMigrationWrapper from '../../components/Migrations/NewMigration/NewMigrationWrapper'; - -// Style -import './index.scss'; -import { updateNewMigrationData } from '../../store/slice/migrationDataSlice'; -import { RootState } from '../../store'; - -const MigrationEditor = () => { - const navigate = useNavigate(); - const params: Params = useParams(); - const dispatch = useDispatch(); - - - const selectedOrganisation = useSelector((state:RootState)=>state?.authentication?.selectedOrganisation); - - - const [projectName, setProjectName] = useState(''); - - const header = { - backNavigation: () => { - - dispatch(updateNewMigrationData(DEFAULT_NEW_MIGRATION)) - navigate(-1); - }, - component: - }; - - const bodyContent = { - component: - }; - /******** Function to get project ********/ - const fetchProject = async () => { - const response = await getProject(selectedOrganisation?.value || '', params?.projectId || ''); - - if (response?.status === 200) { - setProjectName(response?.data?.name); - - //Navigate to lastest or active Step - const url = `/projects/${params?.projectId}/migration/steps/${response?.data?.current_step}`; - navigate(url, { replace: true }); - } - }; - - // useEffect(() => { - // fetchProject(); - // }, []); - - useEffect(() => { - fetchProject(); - }, [selectedOrganisation?.value, params?.projectId]); - - return ( -
- -
- ); -}; - -export default MigrationEditor; diff --git a/ui/src/pages/Projects/index.tsx b/ui/src/pages/Projects/index.tsx index 0b031971..ebfc8d1f 100644 --- a/ui/src/pages/Projects/index.tsx +++ b/ui/src/pages/Projects/index.tsx @@ -6,6 +6,9 @@ import HTMLReactParser from 'html-react-parser'; import { useLocation } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; +// Redux +import { RootState } from '../../store'; +import useBlockNavigation from '../../hooks/userNavigation'; // Services import { getCMSDataFromFile } from '../../cmsData/cmsSelector'; @@ -31,10 +34,6 @@ import { NO_PROJECTS, NO_PROJECTS_SEARCH } from '../../common/assets'; // styles import './index.scss'; -import { getUserDetails } from '../../store/slice/authSlice'; -import useBlockNavigation from '../../hooks/userNavigation'; -import { RootState } from '../../store'; - const Projects = () => { const [data, setData] = useState({}); @@ -47,9 +46,7 @@ const Projects = () => { create_project_modal: createProjectModal } = data; - const dispatch = useDispatch(); const selectedOrganisation = useSelector((state:RootState)=>state?.authentication?.selectedOrganisation); - const outputIntro = HTMLReactParser(jsonToHtml(emptystate?.description ?? {})); @@ -62,10 +59,6 @@ const Projects = () => { const [searchText, setSearchText] = useState(search); const [isModalOpen, setIsModalOpen] = useState(false); - useEffect(()=>{ - dispatch(getUserDetails()); - },[]); - const fetchProjects = async () => { setLoadStatus(true); if (selectedOrganisation?.value) { @@ -88,10 +81,6 @@ const Projects = () => { }); }; - useEffect(()=>{ - dispatch(getUserDetails()); - },[dispatch]); - useEffect(() => { fetchData(); }, []); @@ -197,7 +186,7 @@ const Projects = () => {