From bc2f0077a09c4949cbd75428580315132cfedf46 Mon Sep 17 00:00:00 2001 From: AishDani Date: Fri, 3 Jan 2025 13:52:30 +0530 Subject: [PATCH 1/3] refactor:[CMG-439] --- ui/src/components/Modal/index.tsx | 2 +- ui/src/components/ProjectsHeader/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/components/Modal/index.tsx b/ui/src/components/Modal/index.tsx index dc40ae702..f0db50817 100644 --- a/ui/src/components/Modal/index.tsx +++ b/ui/src/components/Modal/index.tsx @@ -60,7 +60,7 @@ const Modal = (props: ProjectModalProps) => { return 'Project name is required.'; } else if (!/^[^\s].*$/.test(value)) { setInputValue(false); - return 'Please enter a valid project name.'; + //return 'Please enter a valid project name.'; } else { setInputValue(true); } diff --git a/ui/src/components/ProjectsHeader/index.tsx b/ui/src/components/ProjectsHeader/index.tsx index efb61e1fe..f7ba3aa56 100644 --- a/ui/src/components/ProjectsHeader/index.tsx +++ b/ui/src/components/ProjectsHeader/index.tsx @@ -28,7 +28,7 @@ const ProjectsHeader = ({ placeholder={searchPlaceholder} type="secondary" onChange={(search: string) =>{ - setSearchText(search)} + search.trim()?.length > 0 ? setSearchText(search?.trim()) : setSearchText(search)} } width="large" onClear={true} From d73ae7daa6ae82c28820f329d01bbae28177aa05 Mon Sep 17 00:00:00 2001 From: AishDani Date: Fri, 3 Jan 2025 14:15:43 +0530 Subject: [PATCH 2/3] refactor:[CMG-452]:After saving the changes and returning to the same module, the CMS field should remain disabled --- ui/src/components/Common/Card/card.scss | 4 ++++ ui/src/components/Common/Card/card.tsx | 7 ++++--- ui/src/components/LegacyCms/Actions/LoadSelectCms.tsx | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ui/src/components/Common/Card/card.scss b/ui/src/components/Common/Card/card.scss index e3dcbd605..1aab90f44 100644 --- a/ui/src/components/Common/Card/card.scss +++ b/ui/src/components/Common/Card/card.scss @@ -148,4 +148,8 @@ p { color: $color-stepper-title; } +} +.Card__disabled{ + cursor: not-allowed; + opacity: .5; } \ No newline at end of file diff --git a/ui/src/components/Common/Card/card.tsx b/ui/src/components/Common/Card/card.tsx index 0be5b932b..f857903b2 100644 --- a/ui/src/components/Common/Card/card.tsx +++ b/ui/src/components/Common/Card/card.tsx @@ -14,6 +14,7 @@ type CardProps = { onCardClick?: (T: any) => unknown; selectedCard: any; cardType?: string; + disabled: boolean; }; /** @@ -25,7 +26,7 @@ type CardProps = { * @param cardType - The type of the card. * @param idField - The field name for the card's ID. Defaults to 'id'. */ -const Card = ({ data, selectedCard, onCardClick, cardType, idField = 'id' }: CardProps) => { +const Card = ({ data, selectedCard, onCardClick, cardType, idField = 'id',disabled }: CardProps) => { const imgStyle = { width: cardType === 'legacyCMS' ? '60px' : '46px', height: cardType === 'legacyCMS' ? '60px' : '46px' @@ -51,9 +52,9 @@ const Card = ({ data, selectedCard, onCardClick, cardType, idField = 'id' }: Car
{data.description && (
diff --git a/ui/src/components/LegacyCms/Actions/LoadSelectCms.tsx b/ui/src/components/LegacyCms/Actions/LoadSelectCms.tsx index e571f02d2..0d676c5bb 100644 --- a/ui/src/components/LegacyCms/Actions/LoadSelectCms.tsx +++ b/ui/src/components/LegacyCms/Actions/LoadSelectCms.tsx @@ -106,7 +106,7 @@ const LoadSelectCms = (props: LoadSelectCmsProps) => { } }; - dispatch(updateNewMigrationData(newMigrationDataObj)); + //dispatch(updateNewMigrationData(newMigrationDataObj)); setCmsData(filteredCmsData) @@ -205,6 +205,7 @@ const LoadSelectCms = (props: LoadSelectCmsProps) => { onCardClick={data?.cms_id !== selectedCard?.cms_id ? handleCardClick : undefined} selectedCard={selectedCard} idField="cms_id" + disabled={newMigrationData?.project_current_step > 1} /> ))}
)) From 3ed2ded1d09fb8b1b9e3326ed326ec37a2db5052 Mon Sep 17 00:00:00 2001 From: AishDani Date: Mon, 6 Jan 2025 17:34:49 +0530 Subject: [PATCH 3/3] refactor:[CMG-430]:When migration of project is done in stack 1, then user should not be able to do same project's migration in stack 1 --- api/src/controllers/projects.controller.ts | 6 +++ api/src/routes/projects.routes.ts | 2 + api/src/services/projects.service.ts | 48 ++++++++++++++++++- .../DestinationStack/Actions/LoadStacks.tsx | 12 +++-- .../LogScreen/MigrationLogViewer.tsx | 5 ++ .../components/MigrationFlowHeader/index.tsx | 4 +- ui/src/context/app/app.interface.ts | 7 ++- ui/src/pages/Migration/index.tsx | 6 ++- ui/src/services/api/project.service.ts | 12 +++++ 9 files changed, 94 insertions(+), 8 deletions(-) diff --git a/api/src/controllers/projects.controller.ts b/api/src/controllers/projects.controller.ts index d05e0867d..b97d82c88 100644 --- a/api/src/controllers/projects.controller.ts +++ b/api/src/controllers/projects.controller.ts @@ -171,6 +171,11 @@ const updateMigrationExecution = async (req: Request, res: Response): Promise => { + const project = await projectService.getMigratedStacks(req); + res.status(project.status).json(project); +} + export const projectController = { getAllProjects, getProject, @@ -187,4 +192,5 @@ export const projectController = { revertProject, updateStackDetails, updateMigrationExecution, + getMigratedStacks, }; diff --git a/api/src/routes/projects.routes.ts b/api/src/routes/projects.routes.ts index 00a0fed81..72f65457d 100644 --- a/api/src/routes/projects.routes.ts +++ b/api/src/routes/projects.routes.ts @@ -80,4 +80,6 @@ router.patch("/:projectId/stack-details", asyncRouter(projectController.updateSt //update migration execution key router.put("/:projectId/migration-excution",asyncRouter(projectController.updateMigrationExecution)); +router.get("/:projectId/get-migrated-stacks", asyncRouter(projectController.getMigratedStacks)) + export default router; diff --git a/api/src/services/projects.service.ts b/api/src/services/projects.service.ts index f684c90d7..945408a50 100644 --- a/api/src/services/projects.service.ts +++ b/api/src/services/projects.service.ts @@ -1212,6 +1212,51 @@ const updateMigrationExecution = async (req: Request) => { }; +/** + * get the destination_stack_id of completed projects. + * + * @param req - The request object containing the parameters and body. + * @returns An object with the status and data of the update operation. + * @throws ExceptionFunction if an error occurs during the process. + */ +const getMigratedStacks = async(req: Request) => { + + const { token_payload } = req.body; + const srcFunc = "getMigratedStacks"; + + try { + await ProjectModelLowdb.read(); + const projects = ProjectModelLowdb.data?.projects || []; + + // Map through projects to extract `destinationstack` key + const destinationStacks = projects.filter((project: any) => project?.status === 5 && project.current_step === 5) + .map((project: any) => project.destination_stack_id); + + return { + status: HTTP_CODES.OK, + destinationStacks + }; + + } catch (error:any) { + // Log error message + logger.error( + getLogMessage( + srcFunc, + "Error occurred while while getting all destinationstack id's of projects", + token_payload, + error + ) + ); + + // Throw a custom exception with the error details + throw new ExceptionFunction( + error?.message || HTTP_TEXTS.INTERNAL_ERROR, + error?.statusCode || error?.status || HTTP_CODES.SERVER_ERROR + ); + + } + +} export const projectService = { getAllProjects, @@ -1229,5 +1274,6 @@ export const projectService = { revertProject, updateStackDetails, updateContentMapper, - updateMigrationExecution + updateMigrationExecution, + getMigratedStacks }; diff --git a/ui/src/components/DestinationStack/Actions/LoadStacks.tsx b/ui/src/components/DestinationStack/Actions/LoadStacks.tsx index eb618dca6..fd9ef8105 100644 --- a/ui/src/components/DestinationStack/Actions/LoadStacks.tsx +++ b/ui/src/components/DestinationStack/Actions/LoadStacks.tsx @@ -38,6 +38,7 @@ const LoadStacks = (props: LoadFileFormatProps) => { const newMigrationData = useSelector((state:RootState)=>state?.migration?.newMigrationData); const selectedOrganisation = useSelector((state:RootState)=>state?.authentication?.selectedOrganisation); const dispatch = useDispatch(); + /**** ALL UseStates HERE ****/ const [selectedStack, setSelectedStack] = useState( null @@ -61,7 +62,8 @@ const LoadStacks = (props: LoadFileFormatProps) => { default: false, master_locale: '', locales: [], - created_at: '' + created_at: '', + disabled: false, } ]; const [allStack, setAllStack] = useState(newMigrationData?.destination_stack?.stackArray); @@ -106,7 +108,8 @@ const LoadStacks = (props: LoadFileFormatProps) => { locales: resp?.data?.stack?.locales, created_at: resp?.data?.stack?.created_at, uid: resp?.data?.stack?.api_key, - isNewStack: true + isNewStack: true, + isDisabled: false, }; setSelectedStack(newCreatedStack); @@ -183,7 +186,7 @@ const LoadStacks = (props: LoadFileFormatProps) => { if (allStack?.length <= 0) { setAllStack(loadingOption); const stackData = await getAllStacksInOrg(selectedOrganisation?.value, ''); // org id will always be there - + const stackArray = validateArray(stackData?.data?.stacks) ? stackData?.data?.stacks?.map((stack: StackResponse) => ({ label: stack?.name, @@ -192,7 +195,8 @@ const LoadStacks = (props: LoadFileFormatProps) => { master_locale: stack?.master_locale, locales: stack?.locales, created_at: stack?.created_at, - isNewStack: newStackCreated + isNewStack: newStackCreated, + isDisabled: newMigrationDataRef?.current?.destination_stack?.migratedStacks?.includes(stack?.api_key), })) : []; diff --git a/ui/src/components/LogScreen/MigrationLogViewer.tsx b/ui/src/components/LogScreen/MigrationLogViewer.tsx index 75c082b54..89fabf83c 100644 --- a/ui/src/components/LogScreen/MigrationLogViewer.tsx +++ b/ui/src/components/LogScreen/MigrationLogViewer.tsx @@ -218,6 +218,11 @@ const MigrationLogViewer = ({ serverPath }: LogsType) => { const message = logObject.message; return ( + newMigrationData?.destination_stack?.migratedStacks?.includes(newMigrationData?.destination_stack?.selectedStack?.value) ? +
+
Migration has already done in selected stack. Please create a new project.
+
+ : message === "Migration logs will appear here once the process begins." ?
{message}
diff --git a/ui/src/components/MigrationFlowHeader/index.tsx b/ui/src/components/MigrationFlowHeader/index.tsx index 4c224f157..32bb5ebb0 100644 --- a/ui/src/components/MigrationFlowHeader/index.tsx +++ b/ui/src/components/MigrationFlowHeader/index.tsx @@ -80,6 +80,8 @@ const MigrationFlowHeader = ({projectData, handleOnClick, isLoading, finalExecut finalExecutionStarted || newMigrationData?.migration_execution?.migrationStarted || newMigrationData?.migration_execution?.migrationCompleted; + const destinationStackMigrated = params?.stepId === '5' && newMigrationData?.destination_stack?.migratedStacks?.includes(newMigrationData?.destination_stack?.selectedStack?.value); + return (
@@ -96,7 +98,7 @@ const MigrationFlowHeader = ({projectData, handleOnClick, isLoading, finalExecut version="v2" aria-label='Save and Continue' isLoading={isLoading || newMigrationData?.isprojectMapped} - disabled={isStep4AndNotMigrated || isStepInvalid || isExecutionStarted} + disabled={isStep4AndNotMigrated || isStepInvalid || isExecutionStarted || destinationStackMigrated} > {stepValue} diff --git a/ui/src/context/app/app.interface.ts b/ui/src/context/app/app.interface.ts index 9d392989e..72bce29f7 100644 --- a/ui/src/context/app/app.interface.ts +++ b/ui/src/context/app/app.interface.ts @@ -171,6 +171,8 @@ export interface IDestinationStack { selectedOrg: IDropDown; selectedStack: IDropDown; stackArray: IDropDown[]; + migratedStacks: string[]; + } export interface IContentMapper { existingGlobal: ContentTypeList[] | (() => ContentTypeList[]); @@ -220,6 +222,7 @@ export interface IDropDown { locales: locales[]; created_at: string; isNewStack?: boolean; + isDisabled?:boolean; } export interface ITestMigration { stack_link: string; @@ -258,7 +261,8 @@ export const DEFAULT_DROPDOWN: IDropDown = { master_locale: '', locales: [], created_at: '', - isNewStack: false + isNewStack: false, + isDisabled: false, }; export const DEFAULT_ORGANISATION: Organization = { @@ -330,6 +334,7 @@ export const DEFAULT_DESTINATION_STACK: IDestinationStack = { selectedOrg: DEFAULT_DROPDOWN, selectedStack: DEFAULT_DROPDOWN, stackArray: [], + migratedStacks: [], }; export const DEFAULT_CONTENT_MAPPER: IContentMapper = { diff --git a/ui/src/pages/Migration/index.tsx b/ui/src/pages/Migration/index.tsx index ef463ba15..783657a10 100644 --- a/ui/src/pages/Migration/index.tsx +++ b/ui/src/pages/Migration/index.tsx @@ -37,6 +37,7 @@ import ContentMapper from '../../components/ContentMapper'; import TestMigration from '../../components/TestMigration'; import MigrationExecution from '../../components/MigrationExecution'; import SaveChangesModal from '../../components/Common/SaveChangesModal'; +import { getMigratedStacks } from '../../services/api/project.service'; type StepperComponentRef = { handleStepChange: (step: number) => void; @@ -161,6 +162,8 @@ const Migration = () => { if (isEmptyString(selectedOrganisation?.value) || isEmptyString(params?.projectId)) return; const data = await getMigrationData(selectedOrganisation?.value, params?.projectId ?? ''); + const migratedstacks = await getMigratedStacks(selectedOrganisation?.value, projectId ); + if (data) { setIsLoading(false); setProjectData(data?.data); @@ -229,7 +232,8 @@ const Migration = () => { destination_stack: { selectedOrg: selectedOrganisationData, selectedStack: selectedStackData, - stackArray:[] + stackArray:[], + migratedStacks: migratedstacks?.data?.destinationStacks, }, content_mapping: { isDropDownChanged: false, diff --git a/ui/src/services/api/project.service.ts b/ui/src/services/api/project.service.ts index 118e1b843..3d33e4f3e 100644 --- a/ui/src/services/api/project.service.ts +++ b/ui/src/services/api/project.service.ts @@ -68,3 +68,15 @@ export const deleteProject = async (orgId: string, projectId: string) => { } } }; + +export const getMigratedStacks = async (orgId: string, projectId: string) => { + try { + return await getCall(`${API_VERSION}/org/${orgId}/project/${projectId}/get-migrated-stacks`, options()); + } catch (error) { + if (error instanceof Error) { + throw new Error(`Error in userSession: ${error.message}`); + } else { + throw new Error('Unknown error in userSession'); + } + } +};