Skip to content
Merged

Dev #295

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ui/src/components/Card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 } = {
Expand Down
4 changes: 4 additions & 0 deletions ui/src/components/ContentMapper/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
65 changes: 43 additions & 22 deletions ui/src/components/ContentMapper/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,7 @@ const Fields: Mapping = {
global_field: 'Global'
};

type ContentMapperComponentProps = {
projectData: MigrationResponse;
};

const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, ref: React.ForwardedRef<ContentTypeSaveHandles>) => {
const ContentMapper = forwardRef((props, ref: React.ForwardedRef<ContentTypeSaveHandles>) => {
/** ALL CONTEXT HERE */

const migrationData = useSelector((state:RootState)=>state?.migration?.migrationData);
Expand Down Expand Up @@ -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) => {
Expand All @@ -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
}
}
}
})
}
})
}
})
}
});
Expand Down Expand Up @@ -693,7 +714,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re
const accessorCall = (data: FieldMapType) => {
return (
<div>
<div className="cms-field">{data?.otherCmsField}</div>
<Tooltip content={data?.otherCmsField} position='bottom'><div className="cms-field">{data?.otherCmsField}</div></Tooltip>
<InstructionText>
Type: {data?.otherCmsType}
<br />
Expand Down Expand Up @@ -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" },
Expand All @@ -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);


Expand Down Expand Up @@ -1953,7 +1974,7 @@ const ContentMapper = forwardRef(({projectData}: ContentMapperComponentProps, re
plural: `${totalCounts === 0 ? 'Count' : ''}`
}}
/>
<div className='text-end my-3 mx-3 px-1'>
<div className='text-end my-2 mx-3 px-1 py-1'>
<Button
className="saveButton"
onClick={handleSaveContentType}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/LegacyCms/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const LegacyCMSComponent = forwardRef(({ legacyCMSData, isCompleted, handleOnAll

useEffect(() => {
const fetchCMSData = async () => {
setIsLoading(true);
//setIsLoading(true);

//check if offline CMS data field is set to true, if then read data from cms data file.
const data = await getCMSDataFromFile(CS_ENTRIES.LEGACY_CMS);
Expand Down
1 change: 1 addition & 0 deletions ui/src/components/MainHeader/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
color: $color-font-base;
font-weight: $font-weight-bold;
height: $px-32;
line-height: 1.35;
width: $px-32;
&:hover {
border-color: $color-brand-primary-base;
Expand Down
7 changes: 4 additions & 3 deletions ui/src/components/MainHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const MainHeader = () => {
const newMigrationData = useSelector((state:RootState)=> state?.migration?.newMigrationData);

const [data, setData] = useState<MainHeaderType>({});
const [orgsList, setOrgsList] = useState<IDropDown[]>([]);
const [orgsList, setOrgsList] = useState<IDropDown[]>(organisationsList ?? []);
const [isModalOpen, setIsModalOpen] = useState(false);


Expand All @@ -51,9 +51,10 @@ const MainHeader = () => {

const { logo, organization_label: organizationLabel } = data;

const name = `${user?.first_name?.charAt(0)}${user?.last_name?.charAt(0)}`.toUpperCase() ?? '';
const name = user ? `${user?.first_name?.charAt(0)}${user?.last_name?.charAt(0)}`.toUpperCase() ?? '' : '';

const updateOrganisationListState = () => {

if (organisationsList) {
//set selected org as default
const list = organisationsList.map((org: IDropDown) => ({
Expand Down Expand Up @@ -87,7 +88,7 @@ const MainHeader = () => {

useEffect(() => {
updateOrganisationListState();
}, [selectedOrganisation]);
}, [selectedOrganisation,organisationsList]);

const handleOnDropDownChange = (data: IDropDown) => {
if (data.value === selectedOrganisation.value) return;
Expand Down
92 changes: 21 additions & 71 deletions ui/src/components/MigrationFlowHeader/index.tsx
Original file line number Diff line number Diff line change
@@ -1,110 +1,60 @@
// Libraries
import { useEffect, useRef, useState } from 'react';
import { Button, cbModal } from '@contentstack/venus-components';
import { useDispatch, useSelector } from 'react-redux';
import { useEffect, useState } from 'react';
import { Button } from '@contentstack/venus-components';
import { useSelector } from 'react-redux';
import { Params, useNavigate, useParams } from 'react-router';

// Redux files
import { updateNewMigrationData } from '../../store/slice/migrationDataSlice';

// Service
import { getProject } from '../../services/api/project.service';
import { RootState } from '../../store';

// Interfaces
import { DEFAULT_NEW_MIGRATION } from '../../context/app/app.interface';
import { ModalObj } from '../Modal/modal.interface';
import { MigrationResponse } from '../../services/api/service.interface';

// CSS
import './index.scss';
import NotificationModal from '../Common/NotificationModal';
import { isEmptyString } from '../../utilities/functions';
import { RootState } from '../../store';

type MigrationFlowHeaderProps = {
handleOnClick: (event: MouseEvent, handleStepChange: (currentStep: number) => void) => void;
isLoading: boolean;
isCompleted: boolean;
legacyCMSRef: React.MutableRefObject<any>;
projectData:MigrationResponse
};

const MigrationFlowHeader = ({ handleOnClick, isLoading, isCompleted , legacyCMSRef}: MigrationFlowHeaderProps) => {
const MigrationFlowHeader = ({projectData, handleOnClick, isLoading }: MigrationFlowHeaderProps) => {
const [projectName, setProjectName] = useState('');
const [currentStep, setCurrentStep] = useState<number>(0);

const navigate = useNavigate();
const params: Params<string> = useParams();
const dispatch = useDispatch();

const selectedOrganisation = useSelector((state:any)=>state?.authentication?.selectedOrganisation);
const newMigrationData = useSelector((state:RootState)=> state?.migration?.newMigrationData);

//const legacyCMSRef = useRef<any>(null);
const selectedOrganisation = useSelector((state: RootState)=>state?.authentication?.selectedOrganisation);

useEffect(() => {
fetchProject();
}, [selectedOrganisation?.value, params?.projectId]);

/******** Function to get project ********/
const fetchProject = async () => {
const response = await getProject(selectedOrganisation?.value || '', params?.projectId || '');
setProjectName(projectData?.name);
setCurrentStep(projectData?.current_step);

if (response?.status === 200) {
setProjectName(response?.data?.name);
setCurrentStep(response?.data?.current_step);

//Navigate to lastest or active Step
const url = `/projects/${params?.projectId}/migration/steps/${response?.data?.current_step}`;
navigate(url, { replace: true });
}
//Navigate to lastest or active Step
const url = `/projects/${params?.projectId}/migration/steps/${projectData?.current_step}`;
navigate(url, { replace: true });
};

const backNavigation = () => {

const goback = () => {
dispatch(updateNewMigrationData(DEFAULT_NEW_MIGRATION))
navigate(-1);
}


if (legacyCMSRef.current) {
const currentIndex = legacyCMSRef.current.getInternalActiveStepIndex() + 1 ;

if(-1 < currentIndex && currentIndex < 4 && ( !isEmptyString(newMigrationData?.legacy_cms?.selectedCms?.cms_id) || !isEmptyString(newMigrationData?.legacy_cms?.affix) )&& currentStep === 1
){
return cbModal({
component: (props: ModalObj) => (
<NotificationModal
goBack={goback}
{...props}
isopen={false}
/>
),
modalProps: {
size: 'xsmall',
shouldCloseOnOverlayClick: false
}
});
}
}

dispatch(updateNewMigrationData(DEFAULT_NEW_MIGRATION))
navigate(-1);
let stepValue;
if (params?.stepId === '3' || params?.stepId === '4') {
stepValue = 'Continue';
} else if (params?.stepId === '5') {
stepValue = 'Start';
} else {
stepValue = 'Save and Continue';
}

return (
<div className='d-flex align-items-center justify-content-between migration-flow-header'>
<div className='d-flex align-items-center'>
{/* <Button
aria-label='Go back'
buttonType="secondary"
icon="v2-LeftArrow"
iconAlignment="left"
size="large"
version="v2"
className="back-btn"
onlyIconHoverColor="secondary"
onClick={backNavigation}
/> */}
{ projectName && <h1>{projectName}</h1> }
</div>

Expand All @@ -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}
</Button>
</div>
)
Expand Down
22 changes: 13 additions & 9 deletions ui/src/components/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -92,6 +86,16 @@ const Modal = (props: ProjectModalProps) => {
<FinalForm
className="customForm"
onSubmit={handleSubmit}
keepDirtyOnReinitialize={true}
validate={(values): any => {
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 (
<form
Expand Down Expand Up @@ -134,7 +138,7 @@ const Modal = (props: ProjectModalProps) => {
input.onChange(event);
}}
version="v2"
autoFocus={true}
// autoFocus={true}
placeholder={namePlaceholder}
data-testid="title-input"
name="name"
Expand Down
4 changes: 4 additions & 0 deletions ui/src/components/Modal/modal.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ export interface SettingsModalProps {
closeModal: () => void;
navigate: (url: string) => void;
}

export interface FormData {
name?: string;
}
Loading