From dfe6890f9145a470833cf1202a77114c001c6de1 Mon Sep 17 00:00:00 2001 From: Rohit Kini Date: Mon, 15 Jul 2024 21:26:07 +0530 Subject: [PATCH 01/17] aded type to distinguish content type and global field --- api/src/config/dev.config.ts | 2 +- .../projects.contentMapper.controller.ts | 9 ++++--- api/src/models/contentTypesMapper-lowdb.ts | 1 + api/src/server.ts | 2 +- api/src/services/contentMapper.service.ts | 27 ++++++++++--------- api/src/services/projects.service.ts | 13 ++++++--- uplaode-api/src/config/index.ts | 2 +- uplaode-api/src/controllers/sitecore/index.ts | 14 +++++++--- 8 files changed, 45 insertions(+), 25 deletions(-) diff --git a/api/src/config/dev.config.ts b/api/src/config/dev.config.ts index 00f69565a..cdd2363dc 100644 --- a/api/src/config/dev.config.ts +++ b/api/src/config/dev.config.ts @@ -12,4 +12,4 @@ export const devConfig = { }, LOG_FILE_PATH: process.platform === "win32" ? ".\\combine.log" : "./combine.log", // Replace with the actual path to your log file -}; \ No newline at end of file +}; diff --git a/api/src/controllers/projects.contentMapper.controller.ts b/api/src/controllers/projects.contentMapper.controller.ts index 6a22299c4..c0623d22d 100644 --- a/api/src/controllers/projects.contentMapper.controller.ts +++ b/api/src/controllers/projects.contentMapper.controller.ts @@ -37,10 +37,13 @@ const resetContentType = async (req: Request, res: Response): Promise => { // res.status(200).json(resp); // }; -const removeContentMapper = async (req: Request, res: Response): Promise => { +const removeContentMapper = async ( + req: Request, + res: Response +): Promise => { const resp = await contentMapperService.removeContentMapper(req); res.status(200).json(resp); -} +}; const getSingleContentTypes = async ( req: Request, @@ -59,5 +62,5 @@ export const contentMapperController = { resetContentType, // removeMapping, getSingleContentTypes, - removeContentMapper + removeContentMapper, }; diff --git a/api/src/models/contentTypesMapper-lowdb.ts b/api/src/models/contentTypesMapper-lowdb.ts index 77c3897a9..75bd77add 100644 --- a/api/src/models/contentTypesMapper-lowdb.ts +++ b/api/src/models/contentTypesMapper-lowdb.ts @@ -10,6 +10,7 @@ export interface ContentTypesMapper { contentstackTitle: string; contentstackUid: string; status: number; + type : string; fieldMapping: []; } diff --git a/api/src/server.ts b/api/src/server.ts index 7e9f0cf42..fbaf4cb60 100644 --- a/api/src/server.ts +++ b/api/src/server.ts @@ -103,4 +103,4 @@ try { } catch (e) { logger.error("Error while starting the server!"); logger.error(e); -} \ No newline at end of file +} diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index bd2151a07..0a155cb8a 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -26,7 +26,7 @@ import { ContentTypesMapper } from "../models/contentTypesMapper-lowdb.js"; // Developer service to create dummy contentmapping data const putTestData = async (req: Request) => { const projectId = req.params.projectId; - const contentTypes = req.body.contentTypes; + const contentTypes = req.body.contentTypes; await FieldMapperModel.read(); contentTypes.map((type: any, index: any) => { @@ -35,7 +35,7 @@ const putTestData = async (req: Request) => { const id = field?.id || uuidv4(); fieldIds.push(id); return { id, isDeleted: true, ...field }; - }); + }) ?? []; FieldMapperModel.update((data: any) => { data.field_mapper = [...(data?.field_mapper ?? []), ...fields]; }); @@ -45,7 +45,7 @@ const putTestData = async (req: Request) => { await ContentTypesMapperModelLowdb.read(); const contentIds: string[] = []; const contentType = contentTypes.map((item: any) => { - const id = item?.id || uuidv4(); + const id = item?.id || uuidv4(); contentIds.push(id); return { ...item, id }; }); @@ -532,7 +532,7 @@ const resetAllContentTypesMapping = async (projectId: string) => { try { const contentTypes = cData; for (const contentType of contentTypes) { - if (contentType && !isEmpty(contentType.fieldMapping)) { + if (contentType && !isEmpty(contentType.fieldMapping)) { for (const field of contentType.fieldMapping) { await FieldMapperModel.read(); const fieldData = FieldMapperModel.chain @@ -569,10 +569,8 @@ const resetAllContentTypesMapping = async (projectId: string) => { }); } } - } - return projectDetails; } catch (error: any) { logger.error( @@ -735,13 +733,16 @@ const removeContentMapper = async (req: Request) => { throw new BadRequestError(HTTP_TEXTS.PROJECT_NOT_FOUND); } await ContentTypesMapperModelLowdb.read(); - const cData: ContentTypesMapper[] = projectDetails?.content_mapper.map((cId: string) => { - const contentTypeData: ContentTypesMapper = ContentTypesMapperModelLowdb.chain - .get("ContentTypesMappers") - .find({ id: cId }) - .value(); - return contentTypeData; - }); + const cData: ContentTypesMapper[] = projectDetails?.content_mapper.map( + (cId: string) => { + const contentTypeData: ContentTypesMapper = + ContentTypesMapperModelLowdb.chain + .get("ContentTypesMappers") + .find({ id: cId }) + .value(); + return contentTypeData; + } + ); try { const contentTypes: ContentTypesMapper[] = cData; diff --git a/api/src/services/projects.service.ts b/api/src/services/projects.service.ts index f6cb13bb8..723a8fba6 100644 --- a/api/src/services/projects.service.ts +++ b/api/src/services/projects.service.ts @@ -27,8 +27,8 @@ const getAllProjects = async (req: Request) => { const orgId = req?.params?.orgId; const decodedToken = req.body.token_payload; - const { user_id = "", region = "" } = decodedToken; - + const { user_id = "", region = "" } = decodedToken; + await ProjectModelLowdb.read(); const projects = ProjectModelLowdb.chain .get("projects") @@ -354,7 +354,14 @@ const affixConfirmation = async (req: Request) => { const updateFileFormat = async (req: Request) => { const { orgId, projectId } = req.params; - const { token_payload, file_format,file_path,is_localPath,is_fileValid,awsDetails } = req.body; + const { + token_payload, + file_format, + file_path, + is_localPath, + is_fileValid, + awsDetails, + } = req.body; const srcFunc = "updateFileFormat"; const projectIndex = (await getProjectUtil( projectId, diff --git a/uplaode-api/src/config/index.ts b/uplaode-api/src/config/index.ts index d0722ca5a..95ea0bf7d 100644 --- a/uplaode-api/src/config/index.ts +++ b/uplaode-api/src/config/index.ts @@ -9,5 +9,5 @@ export default { bucketName: 'migartion-test', buketKey: 'project/package 45.zip' }, - localPath: '/Users/snehal.pimple/Desktop/package 45.zip' + localPath: '/Users/rohit/Desktop/package 45.zip' }; diff --git a/uplaode-api/src/controllers/sitecore/index.ts b/uplaode-api/src/controllers/sitecore/index.ts index 2ca0823d0..5b8c0549c 100644 --- a/uplaode-api/src/controllers/sitecore/index.ts +++ b/uplaode-api/src/controllers/sitecore/index.ts @@ -17,9 +17,17 @@ const createSitecoreMapper = async (filePath: string = "", projectId: string | s if (infoMap?.contentTypeUids?.length) { const fieldMapping: any = { contentTypes: [] }; for await (const contentType of infoMap?.contentTypeUids ?? []) { - fieldMapping?.contentTypes?.push( - JSON.parse(readFileSync(`${infoMap?.path}/content_types/${contentType}`, 'utf8')) - ); + const fileContent = readFileSync(`${infoMap?.path}/content_types/${contentType}`, 'utf8'); + const jsonfileContent = JSON.parse(fileContent); + jsonfileContent.type = "content_type"; + fieldMapping?.contentTypes?.push(jsonfileContent); + } + + for await (const contentType of infoMap?.globalFieldUids ?? []) { + const fileContent = readFileSync(`${infoMap?.path}/global_fields/${contentType}`, 'utf8'); + const jsonfileContent = JSON.parse(fileContent); + jsonfileContent.type = "global_field"; + fieldMapping?.contentTypes?.push(jsonfileContent); } const config = { method: 'post', From 4d72c20d8af65cab53abf1716b9445232dbf11d9 Mon Sep 17 00:00:00 2001 From: Rohit Kini Date: Mon, 15 Jul 2024 21:29:36 +0530 Subject: [PATCH 02/17] aded type to distinguish content type and global field --- api/src/models/contentTypesMapper-lowdb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/models/contentTypesMapper-lowdb.ts b/api/src/models/contentTypesMapper-lowdb.ts index 75bd77add..2ea7d3128 100644 --- a/api/src/models/contentTypesMapper-lowdb.ts +++ b/api/src/models/contentTypesMapper-lowdb.ts @@ -10,8 +10,8 @@ export interface ContentTypesMapper { contentstackTitle: string; contentstackUid: string; status: number; - type : string; fieldMapping: []; + type : string; } // interface ContentTypesMapper { From ca14e9752da2b86a871b0395b70ff74167daabb0 Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Tue, 16 Jul 2024 13:08:09 +0530 Subject: [PATCH 03/17] [CMG-244], [CMG-245] --- ui/src/components/ContentMapper/index.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 932ed5838..57948926e 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -85,7 +85,7 @@ const Fields: Mapping = { 'HTML Rich text Editor': 'JSON Rich Text Editor', 'JSON Rich Text Editor': 'JSON Rich Text Editor', // 'Multi line': - json: 'JSON Rich Text Editor', + json: ['HTML Rich text Editor', 'JSON Rich Text Editor'], URL: 'URL', file: 'File', number: 'Number', @@ -93,7 +93,7 @@ const Fields: Mapping = { boolean: 'Boolean', link: 'Link', reference: 'Reference', - dropdown: 'Select', + dropdown: 'dropdown', radio: 'Select', CheckBox: 'Select', global_field: 'Global' @@ -403,7 +403,7 @@ const ContentMapper = () => {
{data?.otherCmsField}
- Other CMS Type: {data?.otherCmsType} + Type: {data?.otherCmsType}
UID: {data?.uid}
@@ -796,6 +796,10 @@ const ContentMapper = () => { setisDropDownCHanged(false); setisContentTypeMapped(true); setisContentTypeSaved(true); + + setFilteredContentTypes(filteredContentTypes?.map(ct => + ct?.id === data?.updatedContentType?.id ? { ...ct, status: data?.updatedContentType?.status } : ct + )) } else { Notification({ notificationContent: { text: data?.error?.message }, From 2daecc239dda04b8c62cf6eca1c0f91ce19f39df Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Tue, 16 Jul 2024 13:17:24 +0530 Subject: [PATCH 04/17] [CMG-233] - Content Mapper | LHS | Icons of Content type and Global fields are missing --- ui/src/components/ContentMapper/index.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 89f5e7752..81ef07407 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -1112,17 +1112,14 @@ const ContentMapper = () => { >
- {content?.type === "Content Type" + {content?.type === "content_type" ? - : content?.type === "Global Field" - ? - : <> + : } {content?.otherCmsTitle && {content?.otherCmsTitle} }
-
{icon && ( From e61d772be470aff42599f31b892d5a0f93f648f8 Mon Sep 17 00:00:00 2001 From: Rohit Kini Date: Tue, 16 Jul 2024 14:44:26 +0530 Subject: [PATCH 05/17] type ans newstack flag and newstackId in DB --- api/src/models/project-lowdb.ts | 2 + api/src/services/projects.service.ts | 41 +++++++++++++++++++ uplaode-api/src/controllers/sitecore/index.ts | 15 ++++--- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/api/src/models/project-lowdb.ts b/api/src/models/project-lowdb.ts index 233e7f5d9..021c17b3b 100644 --- a/api/src/models/project-lowdb.ts +++ b/api/src/models/project-lowdb.ts @@ -50,6 +50,8 @@ interface Project { created_at: string; updated_at: string; isDeleted: boolean; + isNewStack: boolean; + newStackId: string; } interface ProjectDocument { diff --git a/api/src/services/projects.service.ts b/api/src/services/projects.service.ts index 723a8fba6..c8159b8e3 100644 --- a/api/src/services/projects.service.ts +++ b/api/src/services/projects.service.ts @@ -98,6 +98,8 @@ const createProject = async (req: Request) => { updated_at: new Date().toISOString(), created_at: new Date().toISOString(), isDeleted: false, + isNewStack: false, + newStackId: "", }; try { @@ -170,6 +172,10 @@ const updateProject = async (req: Request) => { ProjectModelLowdb.update((data: any) => { data.projects[projectIndex].name = updateData?.name; data.projects[projectIndex].description = updateData?.description; + if(data.projects[projectIndex].isNewStack === false && updateData?.isNewStack === true){ + data.projects[projectIndex].isNewStack = updateData?.isNewStack ; + data.projects[projectIndex].newStackId = updateData?.newStackId; + } data.projects[projectIndex].updated_by = user_id; data.projects[projectIndex].updated_at = new Date().toISOString(); project = data.projects[projectIndex]; @@ -352,6 +358,38 @@ const affixConfirmation = async (req: Request) => { }; }; +const updateNewStack = async (req: Request) => { + const srcFunc = "updateNewStack"; + const { orgId, projectId } = req.params; + const { token_payload } = req.body; + + await ProjectModelLowdb.read(); + const projectIndex = (await getProjectUtil( + projectId, + { + id: projectId, + org_id: orgId, + region: token_payload?.region, + owner: token_payload?.user_id, + }, + srcFunc, + true + )) as number; + + ProjectModelLowdb.update((data: any) => { + data.projects[projectIndex].isNewStack = true; + data.projects[projectIndex].updated_at = new Date().toISOString(); + }); + + return { + status: HTTP_CODES.OK, + data: { + message: HTTP_TEXTS.NEW_STACK_CREATED, + }, + }; +}; + + const updateFileFormat = async (req: Request) => { const { orgId, projectId } = req.params; const { @@ -813,6 +851,8 @@ const revertProject = async (req: Request) => { }; } }; + + export const projectService = { getAllProjects, getProject, @@ -821,6 +861,7 @@ export const projectService = { updateLegacyCMS, updateAffix, affixConfirmation, + updateNewStack, updateFileFormat, fileformatConfirmation, updateDestinationStack, diff --git a/uplaode-api/src/controllers/sitecore/index.ts b/uplaode-api/src/controllers/sitecore/index.ts index 5b8c0549c..7bac77c20 100644 --- a/uplaode-api/src/controllers/sitecore/index.ts +++ b/uplaode-api/src/controllers/sitecore/index.ts @@ -23,12 +23,17 @@ const createSitecoreMapper = async (filePath: string = "", projectId: string | s fieldMapping?.contentTypes?.push(jsonfileContent); } - for await (const contentType of infoMap?.globalFieldUids ?? []) { - const fileContent = readFileSync(`${infoMap?.path}/global_fields/${contentType}`, 'utf8'); - const jsonfileContent = JSON.parse(fileContent); - jsonfileContent.type = "global_field"; - fieldMapping?.contentTypes?.push(jsonfileContent); + + const fileContent = readFileSync(`${infoMap?.path}/global_fields/globalfields.json`, 'utf8'); + const jsonfileContent = JSON.parse(fileContent); + for (const key in jsonfileContent) { + if (jsonfileContent.hasOwnProperty(key)) { + const element = jsonfileContent[key]; + element.type = "global_field"; + } } + fieldMapping.contentTypes.push(jsonfileContent); + const config = { method: 'post', maxBodyLength: Infinity, From 360f69f9161b91d5f07d62fbebb1315f760497c1 Mon Sep 17 00:00:00 2001 From: Rohit Kini Date: Tue, 16 Jul 2024 15:39:32 +0530 Subject: [PATCH 06/17] added comments on api controllers,middlewares,models --- api/src/config/index.ts | 9 ++ api/src/controllers/auth.controller.ts | 12 +++ api/src/controllers/migration.controller.ts | 14 +++ api/src/controllers/org.controller.ts | 28 ++++++ .../projects.contentMapper.controller.ts | 56 ++++++++++++ api/src/controllers/projects.controller.ts | 90 +++++++++++++++++++ api/src/controllers/user.controller.ts | 7 ++ api/src/middlewares/auth.middleware.ts | 12 +++ .../auth.uploadService.middleware.ts | 10 +++ api/src/middlewares/error.middleware.ts | 7 ++ api/src/middlewares/logger.middleware.ts | 10 +++ api/src/middlewares/req-headers.middleware.ts | 8 ++ .../unmatched-routes.middleware.ts | 6 ++ api/src/models/FieldMapper.ts | 9 ++ api/src/models/authentication.ts | 6 ++ api/src/models/contentTypesMapper-lowdb.ts | 50 ++++++++++- api/src/models/project-lowdb.ts | 12 +++ api/src/models/types.ts | 20 +++++ 18 files changed, 365 insertions(+), 1 deletion(-) diff --git a/api/src/config/index.ts b/api/src/config/index.ts index 4f1523603..11f43c759 100644 --- a/api/src/config/index.ts +++ b/api/src/config/index.ts @@ -3,10 +3,16 @@ import path from "path"; import { prodConfig } from "./prod.config.js"; import { devConfig } from "./dev.config.js"; +/** + * Loads the environment variables from the .env file. + */ dotenv.config({ path: path.resolve(process.cwd(), `${process.env.NODE_ENV}.env`), }); +/** + * Configuration type for the application. + */ export type ConfigType = { APP_TOKEN_EXP: string; APP_TOKEN_KEY: string; @@ -28,6 +34,9 @@ export type ConfigType = { }; }; +/** + * Configuration object for the application. + */ export const config: ConfigType = { APP_TOKEN_EXP: "1d", PORT: process.env.PORT!, diff --git a/api/src/controllers/auth.controller.ts b/api/src/controllers/auth.controller.ts index 55e092e11..bdcbe1804 100644 --- a/api/src/controllers/auth.controller.ts +++ b/api/src/controllers/auth.controller.ts @@ -1,11 +1,23 @@ import { Request, Response } from "express"; import { authService } from "../services/auth.service.js"; +/** + * Handles the login request. + * + * @param req - The request object. + * @param res - The response object. + */ const login = async (req: Request, res: Response) => { const resp = await authService.login(req); res.status(resp?.status).json(resp?.data); }; +/** + * Handles the request for sending an SMS. + * + * @param req - The request object. + * @param res - The response object. + */ const RequestSms = async (req: Request, res: Response) => { const resp = await authService.requestSms(req); res.status(resp.status).json(resp.data); diff --git a/api/src/controllers/migration.controller.ts b/api/src/controllers/migration.controller.ts index 9816c5fe5..5d4d62498 100644 --- a/api/src/controllers/migration.controller.ts +++ b/api/src/controllers/migration.controller.ts @@ -1,11 +1,25 @@ import { Request, Response } from "express"; import { migrationService } from "../services/migration.service.js"; +/** + * Creates a test stack. + * + * @param req - The request object. + * @param res - The response object. + * @returns A promise that resolves to void. + */ const createTestStack = async (req: Request, res: Response): Promise => { const resp = await migrationService.createTestStack(req); res.status(200).json(resp); }; +/** + * Deletes the test stack. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A Promise that resolves when the stack is deleted. + */ const deleteTestStack = async (req: Request, res: Response): Promise => { const resp = await migrationService.deleteTestStack(req); res.status(200).json(resp); diff --git a/api/src/controllers/org.controller.ts b/api/src/controllers/org.controller.ts index a826ab489..8767f2b3b 100644 --- a/api/src/controllers/org.controller.ts +++ b/api/src/controllers/org.controller.ts @@ -1,21 +1,49 @@ import { Request, Response } from "express"; import { orgService } from "../services/org.service.js"; +/** + * Retrieves all stacks. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves when the operation is complete. + */ const getAllStacks = async (req: Request, res: Response) => { const resp = await orgService.getAllStacks(req); res.status(resp?.status).json(resp?.data); }; +/** + * Creates a stack. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves when the stack is created. + */ const createStack = async (req: Request, res: Response) => { const resp = await orgService.createStack(req); res.status(resp.status).json(resp.data); }; +/** + * Retrieves the locales for an organization. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves when the locales are retrieved. + */ const getLocales = async (req: Request, res: Response) => { const resp = await orgService.getLocales(req); res.status(resp.status).json(resp.data); }; +/** + * Retrieves the stack status. + * + * @param req - The request object. + * @param res - The response object. + * @returns A Promise that resolves to the stack status response. + */ const getStackStatus = async (req: Request, res: Response) => { const resp = await orgService.getStackStatus(req); res.status(resp.status).json(resp.data); diff --git a/api/src/controllers/projects.contentMapper.controller.ts b/api/src/controllers/projects.contentMapper.controller.ts index c0623d22d..d813ba0e0 100644 --- a/api/src/controllers/projects.contentMapper.controller.ts +++ b/api/src/controllers/projects.contentMapper.controller.ts @@ -1,18 +1,46 @@ import { Request, Response } from "express"; import { contentMapperService } from "../services/contentMapper.service.js"; +/** + * Handles the PUT request to update test data. + * + * @param req - The request object. + * @param res - The response object. + * @returns A Promise that resolves to void. + */ const putTestData = async (req: Request, res: Response): Promise => { const resp = await contentMapperService.putTestData(req); res.status(200).json(resp); }; +/** + * Retrieves the content types from the content mapper service and sends the response as JSON. + * + * @param req - The Express request object. + * @param res - The Express response object. + * @returns A Promise that resolves to void. + */ const getContentTypes = async (req: Request, res: Response): Promise => { const resp = await contentMapperService.getContentTypes(req); res.status(200).json(resp); }; +/** + * Retrieves the field mapping for a given request and sends the response as JSON. + * + * @param req - The request object. + * @param res - The response object. + * @returns A Promise that resolves to void. + */ const getFieldMapping = async (req: Request, res: Response): Promise => { const resp = await contentMapperService.getFieldMapping(req); res.status(200).json(resp); }; +/** + * Retrieves the existing content types. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves when the operation is complete. + */ const getExistingContentTypes = async ( req: Request, res: Response @@ -20,6 +48,13 @@ const getExistingContentTypes = async ( const resp = await contentMapperService.getExistingContentTypes(req); res.status(201).json(resp); }; +/** + * Updates the content type fields. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} A promise that resolves when the content type fields are updated. + */ const putContentTypeFields = async ( req: Request, res: Response @@ -27,6 +62,13 @@ const putContentTypeFields = async ( const resp = await contentMapperService.updateContentType(req); res.status(200).json(resp); }; +/** + * Resets the content type to its initial mapping. + * + * @param req - The request object. + * @param res - The response object. + * @returns A Promise that resolves to void. + */ const resetContentType = async (req: Request, res: Response): Promise => { const resp = await contentMapperService.resetToInitialMapping(req); res.status(200).json(resp); @@ -37,6 +79,13 @@ const resetContentType = async (req: Request, res: Response): Promise => { // res.status(200).json(resp); // }; +/** + * Removes a content mapper. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves when the content mapper is removed. + */ const removeContentMapper = async ( req: Request, res: Response @@ -45,6 +94,13 @@ const removeContentMapper = async ( res.status(200).json(resp); }; +/** + * Retrieves single content types. + * + * @param req - The request object. + * @param res - The response object. + * @returns A Promise that resolves to void. + */ const getSingleContentTypes = async ( req: Request, res: Response diff --git a/api/src/controllers/projects.controller.ts b/api/src/controllers/projects.controller.ts index dbe1abb97..a0ecdb2a9 100644 --- a/api/src/controllers/projects.controller.ts +++ b/api/src/controllers/projects.controller.ts @@ -1,64 +1,154 @@ import { Request, Response } from "express"; import { projectService } from "../services/projects.service.js"; +/** + * Retrieves all projects. + * + * @param req - The request object. + * @param res - The response object. + * @returns A promise that resolves to void. + */ const getAllProjects = async (req: Request, res: Response): Promise => { const allProjects = await projectService.getAllProjects(req); res.status(200).json(allProjects); }; +/** + * Retrieves a project based on the request. + * + * @param req - The request object. + * @param res - The response object. + * @returns A Promise that resolves to void. + */ const getProject = async (req: Request, res: Response): Promise => { const project = await projectService.getProject(req); res.status(200).json(project); }; +/** + * Creates a new project. + * + * @param req - The request object. + * @param res - The response object. + * @returns A Promise that resolves to void. + */ const createProject = async (req: Request, res: Response): Promise => { const project = await projectService.createProject(req); res.status(201).json(project); }; +/** + * Updates a project. + * + * @param req - The request object. + * @param res - The response object. + * @returns A Promise that resolves to void. + */ const updateProject = async (req: Request, res: Response): Promise => { const project = await projectService.updateProject(req); res.status(200).json(project); }; +/** + * Updates the legacy CMS for a project. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves when the update is complete. + */ const updateLegacyCMS = async (req: Request, res: Response) => { const resp = await projectService.updateLegacyCMS(req); res.status(resp.status).json(resp.data); }; +/** + * Updates the affix for a project. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves when the affix is updated. + */ const updateAffix = async (req: Request, res: Response) => { const resp = await projectService.updateAffix(req); res.status(resp.status).json(resp.data); }; +/** + * Handles the affix confirmation request. + * + * @param req - The request object. + * @param res - The response object. + * @returns A Promise that resolves to the response data. + */ const affixConfirmation = async (req: Request, res: Response) => { const resp = await projectService.affixConfirmation(req); res.status(resp.status).json(resp.data); }; +/** + * Updates the file format for a project. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves when the file format is updated. + */ const updateFileFormat = async (req: Request, res: Response) => { const resp = await projectService.updateFileFormat(req); res.status(resp.status).json(resp.data); }; +/** + * Handles the file format confirmation request. + * + * @param req - The request object. + * @param res - The response object. + */ const fileformatConfirmation = async (req: Request, res: Response) => { const resp = await projectService.fileformatConfirmation(req); res.status(resp.status).json(resp.data); }; +/** + * Updates the destination stack for a project. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves when the destination stack is updated. + */ const updateDestinationStack = async (req: Request, res: Response) => { const resp = await projectService.updateDestinationStack(req); res.status(resp.status).json(resp.data); }; +/** + * Updates the current step of a project. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves with the updated project. + */ const updateCurrentStep = async (req: Request, res: Response) => { const project = await projectService.updateCurrentStep(req); res.status(200).json(project); }; +/** + * Deletes a project. + * + * @param req - The request object. + * @param res - The response object. + * @returns A Promise that resolves to void. + */ const deleteProject = async (req: Request, res: Response): Promise => { const project = await projectService.deleteProject(req); res.status(200).json(project); }; +/** + * Reverts a project. + * + * @param req - The request object. + * @param res - The response object. + * @returns A Promise that resolves to void. + */ const revertProject = async (req: Request, res: Response): Promise => { const project = await projectService.revertProject(req); res.status(project.status).json(project); diff --git a/api/src/controllers/user.controller.ts b/api/src/controllers/user.controller.ts index d74936372..b0c883740 100644 --- a/api/src/controllers/user.controller.ts +++ b/api/src/controllers/user.controller.ts @@ -1,6 +1,13 @@ import { Request, Response } from "express"; import { userService } from "../services/user.service.js"; +/** + * Retrieves the user profile. + * + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves when the user profile is retrieved. + */ const getUserProfile = async (req: Request, res: Response) => { const resp = await userService.getUserProfile(req); res.status(resp?.status).json(resp?.data); diff --git a/api/src/middlewares/auth.middleware.ts b/api/src/middlewares/auth.middleware.ts index 17987a3eb..784202455 100644 --- a/api/src/middlewares/auth.middleware.ts +++ b/api/src/middlewares/auth.middleware.ts @@ -4,6 +4,13 @@ import jwt from "jsonwebtoken"; import { config } from "../config/index.js"; import { HTTP_CODES } from "../constants/index.js"; +/** + * Middleware function to authenticate the user. + * + * @param req - The Express request object. + * @param res - The Express response object. + * @param next - The next middleware function. + */ export const authenticateUser = ( req: Request, res: Response, @@ -17,6 +24,11 @@ export const authenticateUser = ( .status(status) .json({ status, message: "Unauthorized - Token missing" }); + /* this middleware function verifies the provided JWT token, + handles any errors that may occur during verification, + attaches the decoded token payload to the request object, + and then passes control to the next middleware or request handler. + */ jwt.verify(token, config.APP_TOKEN_KEY, (err, payload) => { if (err) return res diff --git a/api/src/middlewares/auth.uploadService.middleware.ts b/api/src/middlewares/auth.uploadService.middleware.ts index c23458493..cb1795302 100644 --- a/api/src/middlewares/auth.uploadService.middleware.ts +++ b/api/src/middlewares/auth.uploadService.middleware.ts @@ -2,6 +2,16 @@ import { Request, Response, NextFunction } from "express"; import { HTTP_CODES } from "../constants/index.js"; import { config } from "../config/index.js"; +/** + * Middleware function to authenticate the upload service. + * Checks if the provided secret key matches the configured file upload key. + * If the key is valid, the request is allowed to proceed to the next middleware or route handler. + * If the key is invalid, an unauthorized response is sent. + * + * @param req - The Express Request object. + * @param res - The Express Response object. + * @param next - The Express NextFunction to pass control to the next middleware or route handler. + */ export const authenticateUploadService = ( req: Request, res: Response, diff --git a/api/src/middlewares/error.middleware.ts b/api/src/middlewares/error.middleware.ts index 199152893..a2fb1138c 100644 --- a/api/src/middlewares/error.middleware.ts +++ b/api/src/middlewares/error.middleware.ts @@ -2,6 +2,13 @@ import { Request, Response, NextFunction } from "express"; import { AppError } from "../utils/custom-errors.utils.js"; import logger from "../utils/logger.js"; +/** + * Middleware function to handle errors in the application. + * @param err - The error object. + * @param req - The Express request object. + * @param res - The Express response object. + * @param next - The next middleware function. + */ export const errorMiddleware = ( err: Error, req: Request, diff --git a/api/src/middlewares/logger.middleware.ts b/api/src/middlewares/logger.middleware.ts index 0ccecbf70..df9568339 100644 --- a/api/src/middlewares/logger.middleware.ts +++ b/api/src/middlewares/logger.middleware.ts @@ -2,6 +2,16 @@ import expressWinston from "express-winston"; import logger from "../utils/logger.js"; //Logger Middleware to log every request +/** + * Express middleware for logging HTTP requests. + * + * @remarks + * This middleware uses `express-winston` to log HTTP requests with the specified options. + * + * @param req - The Express request object. + * @param res - The Express response object. + * @param next - The next middleware function. + */ const loggerMiddleware = expressWinston.logger({ level: "info", colorize: true, diff --git a/api/src/middlewares/req-headers.middleware.ts b/api/src/middlewares/req-headers.middleware.ts index 6a71f52b5..4e461839b 100644 --- a/api/src/middlewares/req-headers.middleware.ts +++ b/api/src/middlewares/req-headers.middleware.ts @@ -1,5 +1,13 @@ import { Request, Response, NextFunction } from "express"; +/** + * Middleware function to handle request headers. + * Adds necessary headers for CORS support and handles OPTIONS requests. + * + * @param req - The Express Request object. + * @param res - The Express Response object. + * @param next - The next middleware function. + */ export const requestHeadersMiddleware = ( req: Request, res: Response, diff --git a/api/src/middlewares/unmatched-routes.middleware.ts b/api/src/middlewares/unmatched-routes.middleware.ts index 02cd8530a..da305825e 100644 --- a/api/src/middlewares/unmatched-routes.middleware.ts +++ b/api/src/middlewares/unmatched-routes.middleware.ts @@ -1,6 +1,12 @@ import { Request, Response } from "express"; import { HTTP_CODES, HTTP_TEXTS } from "../constants/index.js"; +/** + * Middleware function to handle unmatched routes. + * + * @param req - The Express request object. + * @param res - The Express response object. + */ export const unmatchedRoutesMiddleware = (req: Request, res: Response) => { const status = HTTP_CODES.NOT_FOUND; res.status(status).json({ diff --git a/api/src/models/FieldMapper.ts b/api/src/models/FieldMapper.ts index f37f6bff4..3da4e6715 100644 --- a/api/src/models/FieldMapper.ts +++ b/api/src/models/FieldMapper.ts @@ -1,6 +1,9 @@ import { JSONFile } from "lowdb/node"; import LowWithLodash from "../utils/lowdb-lodash.utils.js"; +/** + * Represents the advanced configuration options for a field mapper. + */ interface Advanced { validationRegex: string; Mandatory: boolean; @@ -9,6 +12,9 @@ interface Advanced { NonLocalizable: boolean; } +/** + * Represents a field mapper object. + */ interface FieldMapper { field_mapper: { id: string; @@ -27,6 +33,9 @@ interface FieldMapper { const defaultData: FieldMapper = { field_mapper: [] }; +/** + * Represents the database instance for the FieldMapper model. + */ const db = new LowWithLodash( new JSONFile("database/field-mapper.json"), defaultData diff --git a/api/src/models/authentication.ts b/api/src/models/authentication.ts index 57bfd6f41..e50d8bbc5 100644 --- a/api/src/models/authentication.ts +++ b/api/src/models/authentication.ts @@ -1,6 +1,9 @@ // src/models/Authentication.ts import { JSONFile } from "lowdb/node"; import LowWithLodash from "../utils/lowdb-lodash.utils.js"; +/** + * Represents the authentication document. + */ interface AuthenticationDocument { users: { user_id: string; @@ -13,6 +16,9 @@ interface AuthenticationDocument { const defaultData: AuthenticationDocument = { users: [] }; +/** + * Represents the database instance for authentication data. + */ const db = new LowWithLodash( new JSONFile("database/authentication.json"), defaultData diff --git a/api/src/models/contentTypesMapper-lowdb.ts b/api/src/models/contentTypesMapper-lowdb.ts index 2ea7d3128..94de34f99 100644 --- a/api/src/models/contentTypesMapper-lowdb.ts +++ b/api/src/models/contentTypesMapper-lowdb.ts @@ -1,17 +1,59 @@ import { JSONFile } from "lowdb/node"; import LowWithLodash from "../utils/lowdb-lodash.utils.js"; +/** + * Represents a content type mapper. + */ export interface ContentTypesMapper { + /** + * The unique identifier of the content type mapper. + */ id: string; + + /** + * The title of the content type in the other CMS. + */ otherCmsTitle: string; + + /** + * The unique identifier of the content type in the other CMS. + */ otherCmsUid: string; + + /** + * Indicates whether the content type has been updated. + */ isUpdated: boolean; + + /** + * The date when the content type was last updated. + */ updateAt: Date; + + /** + * The title of the content type in Contentstack. + */ contentstackTitle: string; + + /** + * The unique identifier of the content type in Contentstack. + */ contentstackUid: string; + + /** + * The status of the content type. + */ status: number; + + /** + * The field mapping for the content type. + */ fieldMapping: []; - type : string; + + /** + * The type of the content type. + */ + type: string; } // interface ContentTypesMapper { @@ -20,12 +62,18 @@ export interface ContentTypesMapper { // contentTypes: [contentTypes]; // } +/** + * Represents a document containing content type mappers. + */ interface ContentTypeMapperDocument { ContentTypesMappers: ContentTypesMapper[]; } const defaultData: ContentTypeMapperDocument = { ContentTypesMappers: [] }; +/** + * Represents the database instance for the content types mapper. + */ const db = new LowWithLodash( new JSONFile("database/contentTypesMapper.json"), defaultData diff --git a/api/src/models/project-lowdb.ts b/api/src/models/project-lowdb.ts index 021c17b3b..74bfb6894 100644 --- a/api/src/models/project-lowdb.ts +++ b/api/src/models/project-lowdb.ts @@ -1,6 +1,9 @@ import { JSONFile } from "lowdb/node"; import LowWithLodash from "../utils/lowdb-lodash.utils.js"; +/** + * Represents the LegacyCMS object. + */ interface LegacyCMS { cms: string; affix: string; @@ -24,11 +27,17 @@ interface LegacyCMS { is_localPath: boolean; } +/** + * Represents an execution log. + */ interface ExecutionLog { log_url: string; date: Date; } +/** + * Represents a project. + */ interface Project { id: string; region: string; @@ -60,6 +69,9 @@ interface ProjectDocument { const defaultData: ProjectDocument = { projects: [] }; +/** + * Represents the database instance for the project. + */ const db = new LowWithLodash( new JSONFile("database/project.json"), defaultData diff --git a/api/src/models/types.ts b/api/src/models/types.ts index ed5d6d696..605c176ea 100644 --- a/api/src/models/types.ts +++ b/api/src/models/types.ts @@ -1,18 +1,38 @@ +/** + * Represents a user. + */ export interface User { + /** + * The email address of the user. + */ email: string; + + /** + * The password of the user. + */ password: string; } +/** + * Represents the payload of an application token. + */ export interface AppTokenPayload { region: string; user_id: string; } +/** + * Represents the LoginServiceType interface. + * @interface + */ export interface LoginServiceType { data: any; status: number; } +/** + * Represents the migration query type. + */ export interface MigrationQueryType { id: string; org_id: string; From bb3a7fa123551538817b5b1da38361835793d35c Mon Sep 17 00:00:00 2001 From: Rohit Kini Date: Tue, 16 Jul 2024 15:56:36 +0530 Subject: [PATCH 07/17] added comments on api controllers,middlewares,models --- uplaode-api/src/controllers/sitecore/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uplaode-api/src/controllers/sitecore/index.ts b/uplaode-api/src/controllers/sitecore/index.ts index 7bac77c20..b5f1e0625 100644 --- a/uplaode-api/src/controllers/sitecore/index.ts +++ b/uplaode-api/src/controllers/sitecore/index.ts @@ -30,9 +30,9 @@ const createSitecoreMapper = async (filePath: string = "", projectId: string | s if (jsonfileContent.hasOwnProperty(key)) { const element = jsonfileContent[key]; element.type = "global_field"; + fieldMapping.contentTypes.push(element); } } - fieldMapping.contentTypes.push(jsonfileContent); const config = { method: 'post', From 104cc06d7b42260398901ddf514eaba4cb5e6e27 Mon Sep 17 00:00:00 2001 From: Rohit Kini Date: Tue, 16 Jul 2024 18:22:30 +0530 Subject: [PATCH 08/17] added comments on api routes,services,utils --- api/src/routes/auth.routes.ts | 25 ++++- api/src/routes/contentMapper.routes.ts | 45 +++++++-- api/src/routes/migration.routes.ts | 22 +++- api/src/routes/org.routes.ts | 26 ++++- api/src/routes/projects.routes.ts | 3 + api/src/services/auth.service.ts | 24 +++++ api/src/services/contentMapper.service.ts | 83 +++++++++++++++ api/src/services/migration.service.ts | 12 +++ api/src/services/org.service.ts | 38 ++++++- api/src/services/projects.service.ts | 118 +++++++++++++++------- api/src/services/user.service.ts | 7 ++ api/src/utils/async-router.utils.ts | 5 + api/src/utils/auth.utils.ts | 7 ++ api/src/utils/custom-errors.utils.ts | 68 +++++++++++++ api/src/utils/get-project.utils.ts | 10 ++ api/src/utils/https.utils.ts | 9 ++ api/src/utils/index.ts | 25 +++++ api/src/utils/jwt.utils.ts | 6 ++ api/src/utils/logger.ts | 3 + api/src/utils/lowdb-lodash.utils.ts | 4 + 20 files changed, 486 insertions(+), 54 deletions(-) diff --git a/api/src/routes/auth.routes.ts b/api/src/routes/auth.routes.ts index 29608bca9..359b070c1 100644 --- a/api/src/routes/auth.routes.ts +++ b/api/src/routes/auth.routes.ts @@ -3,16 +3,37 @@ import { authController } from "../controllers/auth.controller.js"; import { asyncRouter } from "../utils/async-router.utils.js"; import validator from "../validators/index.js"; +/** + * Express router for handling authentication routes. + */ const router = express.Router(); -// Login route +/** + * Route for user login. + * + * @route POST /user-session + * @group Authentication + * @param {object} req.body - The request body containing user credentials. + * @returns {object} The response object containing user session information. + * @throws {ValidationError} If the request body fails validation. + * @throws {InternalServerError} If an error occurs while processing the request. + */ router.post( "/user-session", validator("auth"), asyncRouter(authController.login) ); -// SMS token route +/** + * Route for requesting SMS token. + * + * @route POST /request-token-sms + * @group Authentication + * @param {object} req.body - The request body containing user information. + * @returns {object} The response object containing the SMS token. + * @throws {ValidationError} If the request body fails validation. + * @throws {InternalServerError} If an error occurs while processing the request. + */ router.post( "/request-token-sms", validator("auth"), diff --git a/api/src/routes/contentMapper.routes.ts b/api/src/routes/contentMapper.routes.ts index a92401e68..90f6655a4 100644 --- a/api/src/routes/contentMapper.routes.ts +++ b/api/src/routes/contentMapper.routes.ts @@ -4,44 +4,73 @@ import { asyncRouter } from "../utils/async-router.utils.js"; const router = express.Router({ mergeParams: true }); -//Developer End Point to create dummy data +/** + * Developer End Point to create dummy data + * @route POST /createDummyData/:projectId + */ router.post( "/createDummyData/:projectId", asyncRouter(contentMapperController.putTestData) ); -//Get ContentTypes List +/** + * Get ContentTypes List + * @route GET /contentTypes/:projectId/:skip/:limit/:searchText? + */ router.get( "/contentTypes/:projectId/:skip/:limit/:searchText?", asyncRouter(contentMapperController.getContentTypes) ); -//Get FieldMapping List + +/** + * Get FieldMapping List + * @route GET /fieldMapping/:contentTypeId/:skip/:limit/:searchText? + */ router.get( "/fieldMapping/:contentTypeId/:skip/:limit/:searchText?", asyncRouter(contentMapperController.getFieldMapping) ); -//Get Existing ContentTypes List +/** + * Get Existing ContentTypes List + * @route GET /:projectId + */ router.get( "/:projectId", asyncRouter(contentMapperController.getExistingContentTypes) ); -//Update FieldMapping or contentType + +/** + * Update FieldMapping or contentType + * @route PUT /contentTypes/:orgId/:projectId/:contentTypeId + */ router.put( "/contentTypes/:orgId/:projectId/:contentTypeId", asyncRouter(contentMapperController.putContentTypeFields) ); -//Reset FieldMapping or contentType + +/** + * Reset FieldMapping or contentType + * @route PUT /resetFields/:orgId/:projectId/:contentTypeId + */ router.put( "/resetFields/:orgId/:projectId/:contentTypeId", asyncRouter(contentMapperController.resetContentType) ); -//get Single contenttype data + +/** + * Get Single contenttype data + * @route GET /:projectId/:contentTypeUid + */ router.get( "/:projectId/:contentTypeUid", asyncRouter(contentMapperController.getSingleContentTypes) ); -//remove content mapper + +/** + * Remove content mapper + * @route GET /:orgId/:projectId/content-mapper + */ router.get( "/:orgId/:projectId/content-mapper", asyncRouter(contentMapperController.removeContentMapper) diff --git a/api/src/routes/migration.routes.ts b/api/src/routes/migration.routes.ts index 3239ff985..1288b4e95 100644 --- a/api/src/routes/migration.routes.ts +++ b/api/src/routes/migration.routes.ts @@ -3,14 +3,34 @@ import express from "express"; import { asyncRouter } from "../utils/async-router.utils.js"; import { migrationController } from "../controllers/migration.controller.js"; +/** + * Express router for handling migration routes. + */ const router = express.Router({ mergeParams: true }); -// Create a new project route + +/** + * Route for creating a new test stack. + * @route POST /test-stack/:orgId/:projectId + * @group Migration + * @param {string} orgId - The ID of the organization. + * @param {string} projectId - The ID of the project. + * @returns {Promise} - A promise that resolves when the test stack is created. + */ router.post( "/test-stack/:orgId/:projectId", asyncRouter(migrationController.createTestStack) ); + +/** + * Route for deleting a test stack. + * @route POST /test-stack/:projectId + * @group Migration + * @param {string} projectId - The ID of the project. + * @returns {Promise} - A promise that resolves when the test stack is deleted. + */ router.post( "/test-stack/:projectId", asyncRouter(migrationController.deleteTestStack) ); + export default router; diff --git a/api/src/routes/org.routes.ts b/api/src/routes/org.routes.ts index 2e8a3c571..659861e07 100644 --- a/api/src/routes/org.routes.ts +++ b/api/src/routes/org.routes.ts @@ -3,22 +3,40 @@ import { orgController } from "../controllers/org.controller.js"; import { asyncRouter } from "../utils/async-router.utils.js"; import validator from "../validators/index.js"; +/** + * Express router for handling organization routes. + */ const router = express.Router({ mergeParams: true }); -// GET all org stacks route +/** + * GET all org stacks route. + * @param searchText - Optional parameter for searching stacks. + */ router.get("/stacks/:searchText?", asyncRouter(orgController.getAllStacks)); -// Create a new stack route +/** + * Create a new stack route. + * @param req - Express request object. + * @param res - Express response object. + */ router.post( "/stacks", validator("project"), asyncRouter(orgController.createStack) ); -// GET all contentstack locales route +/** + * GET all contentstack locales route. + * @param req - Express request object. + * @param res - Express response object. + */ router.get("/locales", asyncRouter(orgController.getLocales)); -// GET Content_types count +/** + * GET Content_types count. + * @param req - Express request object. + * @param res - Express response object. + */ router.post( "/stack_status", validator("destination_stack"), diff --git a/api/src/routes/projects.routes.ts b/api/src/routes/projects.routes.ts index 5c7a54099..b56a60c42 100644 --- a/api/src/routes/projects.routes.ts +++ b/api/src/routes/projects.routes.ts @@ -3,6 +3,9 @@ import { projectController } from "../controllers/projects.controller.js"; import { asyncRouter } from "../utils/async-router.utils.js"; import validator from "../validators/index.js"; +/** + * Express router for handling project routes. + */ const router = express.Router({ mergeParams: true }); // GET all projects route diff --git a/api/src/services/auth.service.ts b/api/src/services/auth.service.ts index 5e911d18b..7c79bc25e 100644 --- a/api/src/services/auth.service.ts +++ b/api/src/services/auth.service.ts @@ -13,9 +13,22 @@ import { import AuthenticationModel from "../models/authentication.js"; import logger from "../utils/logger.js"; +/** + * Logs in a user with the provided request data. + * + * @param req - The request object containing user data. + * @returns A promise that resolves to a LoginServiceType object. + * @throws ExceptionFunction if an error occurs during the login process. + */ const login = async (req: Request): Promise => { const srcFun = "Login"; + /* + handles user authentication by making a request to an API, + performing various checks and validations, + updating a model, and generating a JWT token. + It also handles potential errors and logs appropriate messages. + */ try { const userData = req?.body; @@ -115,9 +128,20 @@ const login = async (req: Request): Promise => { } }; +/** + * Sends a request for SMS login token. + * @param req - The request object. + * @returns A promise that resolves to a LoginServiceType object. + * @throws {InternalServerError} If an error occurs while sending the request. + */ const requestSms = async (req: Request): Promise => { const srcFun = "requestSms"; + /* + handles the authentication process by making an HTTP POST request to an API endpoint, + handling any errors that occur, and returning the appropriate response or error data. + It also includes logging functionality to track the execution and potential errors. + */ try { const userData = req?.body; const [err, res] = await safePromise( diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index 0a155cb8a..7ee2dfc87 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -24,11 +24,27 @@ import ContentTypesMapperModelLowdb from "../models/contentTypesMapper-lowdb.js" import { ContentTypesMapper } from "../models/contentTypesMapper-lowdb.js"; // Developer service to create dummy contentmapping data +/** + * Updates the test data for a given project. + * + * @param req - The request object containing the project ID and content types. + * @returns The updated project data. + */ const putTestData = async (req: Request) => { const projectId = req.params.projectId; const contentTypes = req.body.contentTypes; await FieldMapperModel.read(); + + /* + this code snippet iterates over an array of contentTypes and performs + some operations on each element. + It creates a new array called fields by mapping over the fieldMapping property of each type in contentTypes. + It generates a unique identifier for each field, pushes it into the fieldIds array, + and returns an object with additional properties. + It then updates the field_mapper property of a data object using the FieldMapperModel.update() function. + Finally, it updates the fieldMapping property of each type in the contentTypes array with the fieldIds array. + */ contentTypes.map((type: any, index: any) => { const fieldIds: string[] = []; const fields = type?.fieldMapping?.map?.((field: any) => { @@ -44,6 +60,13 @@ const putTestData = async (req: Request) => { await ContentTypesMapperModelLowdb.read(); const contentIds: string[] = []; + + /* + this code snippet is iterating over an array called contentTypes and + transforming each element by adding a unique identifier (id) if it doesn't already exist. + The transformed elements are then stored in the contentType variable, + and the generated id values are pushed into the contentIds array. + */ const contentType = contentTypes.map((item: any) => { const id = item?.id || uuidv4(); contentIds.push(id); @@ -53,6 +76,7 @@ const putTestData = async (req: Request) => { await ContentTypesMapperModelLowdb.update((data: any) => { data.ContentTypesMappers = contentType; }); + await ProjectModelLowdb.read(); const index = ProjectModelLowdb.chain .get("projects") @@ -72,6 +96,11 @@ const putTestData = async (req: Request) => { return pData; }; +/** + * Retrieves the content types based on the provided request parameters. + * @param req - The request object containing the parameters. + * @returns An object containing the total count and the array of content types. + */ const getContentTypes = async (req: Request) => { const sourceFn = "getContentTypes"; const projectId = req?.params?.projectId; @@ -134,6 +163,12 @@ const getContentTypes = async (req: Request) => { return { count: totalCount, contentTypes: result }; }; +/** + * Retrieves the field mapping for a given content type. + * @param req - The request object containing the content type ID, skip, limit, and search text. + * @returns An object containing the count of field mappings and the filtered/sliced field mappings. + * @throws BadRequestError if the content type is not found. + */ const getFieldMapping = async (req: Request) => { const srcFunc = "getFieldMapping"; const contentTypeId = req?.params?.contentTypeId; @@ -187,6 +222,11 @@ const getFieldMapping = async (req: Request) => { return { count: totalCount, fieldMapping: result }; }; +/** + * Retrieves existing content types for a given project. + * @param req - The request object containing the project ID and token payload. + * @returns An object containing the retrieved content types. + */ const getExistingContentTypes = async (req: Request) => { const projectId = req?.params?.projectId; @@ -232,6 +272,13 @@ const getExistingContentTypes = async (req: Request) => { //Add logic to get Project from DB return { contentTypes }; }; +/** + * Updates the content type based on the provided request. + * @param req - The request object containing the necessary parameters and data. + * @returns An object containing the updated content type. + * @throws BadRequestError if the request is invalid or the content type cannot be updated. + * @throws ExceptionFunction if an error occurs while updating the content type. + */ const updateContentType = async (req: Request) => { const srcFun = "udateContentType"; const { orgId, projectId, contentTypeId } = req.params; @@ -384,6 +431,15 @@ const updateContentType = async (req: Request) => { ); } }; +/** + * Resets the field mapping and content mapping for a specific content type in a project. + * + * @param req - The request object containing the parameters and body. + * @returns An object with a message indicating the success of the reset operation. + * @throws {BadRequestError} If the project status or current step is not valid for resetting the content mapping. + * @throws {BadRequestError} If the content type is not found or invalid. + * @throws {ExceptionFunction} If an error occurs while resetting the field mapping. + */ const resetToInitialMapping = async (req: Request) => { const srcFunc = "resetToInitialMapping"; const { orgId, projectId, contentTypeId } = req.params; @@ -492,6 +548,14 @@ const resetToInitialMapping = async (req: Request) => { ); } }; +/** + * Resets all the content types mapping for a specific project. + * + * @param projectId - The ID of the project. + * @returns The project details after resetting the content types mapping. + * @throws {BadRequestError} If the content mapper or project is not found. + * @throws {ExceptionFunction} If an error occurs while resetting the content types mapping. + */ const resetAllContentTypesMapping = async (projectId: string) => { const srcFunc = "resetAllContentTypesMapping"; @@ -587,6 +651,13 @@ const resetAllContentTypesMapping = async (projectId: string) => { ); } }; +/** + * Removes the content mapping for a project. + * @param projectId - The ID of the project. + * @returns The project details after removing the content mapping. + * @throws {BadRequestError} If the project is not found. + * @throws {ExceptionFunction} If an error occurs while removing the content mapping. + */ const removeMapping = async (projectId: string) => { const srcFunc = "removeMapping"; await ProjectModelLowdb.read(); @@ -673,6 +744,11 @@ const removeMapping = async (projectId: string) => { ); } }; +/** + * Retrieves a single content type from the specified project. + * @param req - The request object containing the project ID, content type UID, and token payload. + * @returns An object containing the title, UID, and schema of the content type, or an error object if an error occurs. + */ const getSingleContentTypes = async (req: Request) => { const projectId = req?.params?.projectId; const contentTypeUID = req?.params?.contentTypeUid; @@ -714,6 +790,13 @@ const getSingleContentTypes = async (req: Request) => { schema: res?.data?.content_type?.schema, }; }; +/** + * Removes the content mapping for a project. + * @param req - The request object containing the project ID. + * @returns The project details after removing the content mapping. + * @throws {BadRequestError} If the project is not found. + * @throws {ExceptionFunction} If an error occurs while removing the content mapping. + */ const removeContentMapper = async (req: Request) => { const projectId = req?.params?.projectId; const srcFunc = "removeMapping"; diff --git a/api/src/services/migration.service.ts b/api/src/services/migration.service.ts index 9c74fbf25..cdcad218b 100644 --- a/api/src/services/migration.service.ts +++ b/api/src/services/migration.service.ts @@ -9,6 +9,13 @@ import { HTTP_TEXTS, HTTP_CODES } from "../constants/index.js"; import { ExceptionFunction } from "../utils/custom-errors.utils.js"; import ProjectModelLowdb from "../models/project-lowdb.js"; +/** + * Creates a test stack. + * + * @param req - The request object containing the necessary parameters. + * @returns A promise that resolves to a LoginServiceType object. + * @throws ExceptionFunction if there is an error creating the stack. + */ const createTestStack = async (req: Request): Promise => { const srcFun = "createTestStack"; const orgId = req?.params?.orgId; @@ -99,6 +106,11 @@ const createTestStack = async (req: Request): Promise => { } }; +/** + * Deletes a test stack. + * @param req - The request object. + * @returns A promise that resolves to a LoginServiceType object. + */ const deleteTestStack = async (req: Request): Promise => { const srcFun = "deleteTestStack"; const projectId = req?.params?.projectId; diff --git a/api/src/services/org.service.ts b/api/src/services/org.service.ts index 90324fb39..29dcb21d5 100644 --- a/api/src/services/org.service.ts +++ b/api/src/services/org.service.ts @@ -9,6 +9,11 @@ import { HTTP_TEXTS, HTTP_CODES } from "../constants/index.js"; import { ExceptionFunction } from "../utils/custom-errors.utils.js"; import { BadRequestError } from "../utils/custom-errors.utils.js"; +/** + * Retrieves all stacks based on the provided request. + * @param req - The request object. + * @returns A promise that resolves to a LoginServiceType object. + */ const getAllStacks = async (req: Request): Promise => { const srcFun = "getAllStacks"; const orgId = req?.params?.orgId; @@ -82,6 +87,11 @@ const getAllStacks = async (req: Request): Promise => { } }; +/** + * Creates a stack. + * @param req - The request object. + * @returns A promise that resolves to a LoginServiceType object. + */ const createStack = async (req: Request): Promise => { const srcFun = "createStack"; const orgId = req?.params?.orgId; @@ -150,6 +160,12 @@ const createStack = async (req: Request): Promise => { } }; +/** + * Retrieves the locales from the CS API. + * @param req - The request object. + * @returns A promise that resolves to the response from the CS API. + * @throws {ExceptionFunction} If there is an error while retrieving the locales. + */ const getLocales = async (req: Request): Promise => { const srcFun = "getLocales"; const { token_payload } = req.body; @@ -204,6 +220,12 @@ const getLocales = async (req: Request): Promise => { } }; +/** + * Retrieves the status of a stack. + * @param req - The request object containing the orgId, token_payload, and stack_api_key. + * @returns An object containing the status and data of the stack. + * @throws ExceptionFunction if an error occurs while checking the status of the stack. + */ const getStackStatus = async (req: Request) => { const { orgId } = req.params; const { token_payload, stack_api_key } = req.body; @@ -286,15 +308,21 @@ const getStackStatus = async (req: Request) => { } }; //get all locals of particular stack +/** + * Retrieves stack local data. + * @param token_payload - The token payload. + * @param data - The data to process. + * @returns A promise that resolves with the stack local data. + */ const getStackLocal = async (token_payload: any, data: any) => { const srcFun = "getStackLocal"; - return new Promise(async (resolve, reject) => { + return new Promise( async (resolve) => { const authtoken = await getAuthtoken( token_payload?.region, token_payload?.user_id ); - let stacks = []; - for (let stack of data) { + const stacks = []; + for (const stack of data) { const [err, res] = await safePromise( https({ method: "GET", @@ -322,7 +350,7 @@ const getStackLocal = async (token_payload: any, data: any) => { status: err.response.status, }; } - let localesArr: any = []; + const localesArr: any = []; res?.data?.locales.map((lang: any) => { return localesArr.push({ code: lang.code, @@ -330,7 +358,7 @@ const getStackLocal = async (token_payload: any, data: any) => { }); }); - let obj = { + const obj = { name: stack.name, api_key: stack.api_key, master_locale: stack.master_locale, diff --git a/api/src/services/projects.service.ts b/api/src/services/projects.service.ts index c8159b8e3..6cff959ba 100644 --- a/api/src/services/projects.service.ts +++ b/api/src/services/projects.service.ts @@ -20,9 +20,16 @@ import getAuthtoken from "../utils/auth.utils.js"; import https from "../utils/https.utils.js"; import getProjectUtil from "../utils/get-project.utils.js"; import logger from "../utils/logger.js"; -import { contentMapperService } from "./contentMapper.service.js"; +// import { contentMapperService } from "./contentMapper.service.js"; import { v4 as uuidv4 } from "uuid"; +/** + * Retrieves all projects based on the provided request object. + * + * @param req - The request object containing the orgId and token_payload. + * @returns A Promise that resolves to an array of projects. + * @throws {NotFoundError} If no projects are found. + */ const getAllProjects = async (req: Request) => { const orgId = req?.params?.orgId; @@ -45,6 +52,11 @@ const getAllProjects = async (req: Request) => { return projects; }; +/** + * Retrieves a project based on the provided request. + * @param req - The request object containing the orgId, projectId, and token_payload. + * @returns A Promise that resolves to the retrieved project. + */ const getProject = async (req: Request) => { const orgId = req?.params?.orgId; const projectId = req?.params?.projectId; @@ -65,6 +77,12 @@ const getProject = async (req: Request) => { return project; }; +/** + * Creates a new project. + * @param req - The request object containing the project details. + * @returns An object with the status, message, and project details. + * @throws ExceptionFunction if there is an error creating the project. + */ const createProject = async (req: Request) => { const orgId = req?.params?.orgId; const { name, description } = req.body; @@ -145,6 +163,12 @@ const createProject = async (req: Request) => { } }; +/** + * Updates a project based on the provided request. + * @param req - The request object containing the necessary information. + * @returns An object with the updated project details. + * @throws ExceptionFunction if an error occurs while updating the project. + */ const updateProject = async (req: Request) => { const orgId = req?.params?.orgId; const projectId = req?.params?.projectId; @@ -217,6 +241,14 @@ const updateProject = async (req: Request) => { } }; +/** + * Updates the legacy CMS for a project. + * + * @param req - The request object containing the parameters and body. + * @returns An object with the status and data of the update operation. + * @throws BadRequestError if the project status is invalid. + * @throws ExceptionFunction if an error occurs during the update. + */ const updateLegacyCMS = async (req: Request) => { const { orgId, projectId } = req.params; const { token_payload, legacy_cms } = req.body; @@ -295,6 +327,12 @@ const updateLegacyCMS = async (req: Request) => { } }; +/** + * Updates the affix of a project. + * + * @param req - The request object containing the parameters and body. + * @returns An object with the status and data properties. + */ const updateAffix = async (req: Request) => { const srcFunc = "updateAffix"; const { orgId, projectId } = req.params; @@ -326,6 +364,12 @@ const updateAffix = async (req: Request) => { }; }; +/** + * Affixes the confirmation to a project in the database. + * + * @param req - The request object containing the parameters and body. + * @returns An object with the status and data properties. + */ const affixConfirmation = async (req: Request) => { const srcFunc = "affixConfirmation"; const { orgId, projectId } = req.params; @@ -358,38 +402,13 @@ const affixConfirmation = async (req: Request) => { }; }; -const updateNewStack = async (req: Request) => { - const srcFunc = "updateNewStack"; - const { orgId, projectId } = req.params; - const { token_payload } = req.body; - - await ProjectModelLowdb.read(); - const projectIndex = (await getProjectUtil( - projectId, - { - id: projectId, - org_id: orgId, - region: token_payload?.region, - owner: token_payload?.user_id, - }, - srcFunc, - true - )) as number; - - ProjectModelLowdb.update((data: any) => { - data.projects[projectIndex].isNewStack = true; - data.projects[projectIndex].updated_at = new Date().toISOString(); - }); - - return { - status: HTTP_CODES.OK, - data: { - message: HTTP_TEXTS.NEW_STACK_CREATED, - }, - }; -}; - - +/** + * Updates the file format for a project. + * @param req - The request object containing the parameters and body. + * @returns An object with the status and data properties. + * @throws BadRequestError if the project status is invalid. + * @throws ExceptionFunction if an error occurs while updating the file format. + */ const updateFileFormat = async (req: Request) => { const { orgId, projectId } = req.params; const { @@ -486,6 +505,11 @@ const updateFileFormat = async (req: Request) => { } }; +/** + * Updates the file format confirmation for a project. + * @param req - The request object containing the parameters and body. + * @returns An object with the status and data properties. + */ const fileformatConfirmation = async (req: Request) => { const srcFunc = "fileformat"; const { orgId, projectId } = req.params; @@ -518,6 +542,14 @@ const fileformatConfirmation = async (req: Request) => { }; }; +/** + * Updates the destination stack for a project. + * + * @param req - The request object containing the parameters and body. + * @returns An object with the status and data of the update operation. + * @throws BadRequestError if the project status is invalid or the destination stack is not found. + * @throws ExceptionFunction if an error occurs while updating the destination stack. + */ const updateDestinationStack = async (req: Request) => { const { orgId, projectId } = req.params; const { token_payload, stack_api_key } = req.body; @@ -629,6 +661,13 @@ const updateDestinationStack = async (req: Request) => { } }; +/** + * Updates the current step of a project based on the provided request. + * @param req - The request object containing the parameters and body. + * @returns The updated project object. + * @throws {BadRequestError} If the current step cannot be updated. + * @throws {ExceptionFunction} If an error occurs while updating the current step. + */ const updateCurrentStep = async (req: Request) => { const { orgId, projectId } = req.params; const token_payload = req.body.token_payload; @@ -724,6 +763,11 @@ const updateCurrentStep = async (req: Request) => { } }; +/** + * Deletes a project. + * @param req - The request object containing the project ID and organization ID. + * @returns An object with the status and data properties. + */ const deleteProject = async (req: Request) => { const { orgId, projectId } = req.params; const decodedToken = req.body.token_payload; @@ -809,6 +853,13 @@ const deleteProject = async (req: Request) => { }; }; +/** + * Reverts a project by setting its 'isDeleted' property to false. + * + * @param req - The request object containing the parameters and body. + * @returns An object with the status and data of the reverted project. + * @throws {NotFoundError} If the project is not found. + */ const revertProject = async (req: Request) => { const { orgId, projectId } = req.params; const decodedToken = req.body.token_payload; @@ -861,7 +912,6 @@ export const projectService = { updateLegacyCMS, updateAffix, affixConfirmation, - updateNewStack, updateFileFormat, fileformatConfirmation, updateDestinationStack, diff --git a/api/src/services/user.service.ts b/api/src/services/user.service.ts index 3d4d511a2..9c9a0467a 100644 --- a/api/src/services/user.service.ts +++ b/api/src/services/user.service.ts @@ -11,6 +11,13 @@ import AuthenticationModel from "../models/authentication.js"; import { safePromise, getLogMessage } from "../utils/index.js"; import logger from "../utils/logger.js"; +/** + * Retrieves the user profile based on the provided request. + * @param req - The request object containing the token payload. + * @returns A promise that resolves to the user profile. + * @throws {BadRequestError} If the user is not found. + * @throws {ExceptionFunction} If an error occurs while retrieving the user profile. + */ const getUserProfile = async (req: Request): Promise => { const srcFun = "getUserProfile"; const appTokenPayload: AppTokenPayload = req?.body?.token_payload; diff --git a/api/src/utils/async-router.utils.ts b/api/src/utils/async-router.utils.ts index 3ebb42336..712035973 100644 --- a/api/src/utils/async-router.utils.ts +++ b/api/src/utils/async-router.utils.ts @@ -1,5 +1,10 @@ import { Request, Response, NextFunction } from "express"; +/** + * Wraps an async function to handle errors and pass them to the Express error handler. + * @param fn - The async function to be wrapped. + * @returns A middleware function that handles async errors. + */ export const asyncRouter = (fn: any) => (req: Request, res: Response, next: NextFunction) => { Promise.resolve(fn(req, res, next)).catch(next); diff --git a/api/src/utils/auth.utils.ts b/api/src/utils/auth.utils.ts index 6ac51514a..30df20752 100644 --- a/api/src/utils/auth.utils.ts +++ b/api/src/utils/auth.utils.ts @@ -1,6 +1,13 @@ import AuthenticationModel from "../models/authentication.js"; import { UnauthorizedError } from "../utils/custom-errors.utils.js"; +/** + * Retrieves the authentication token for a given user in a specific region. + * @param region - The region of the user. + * @param userId - The ID of the user. + * @returns The authentication token for the user. + * @throws UnauthorizedError if the user is not found or the authentication token is missing. + */ export default async (region: string, userId: string) => { await AuthenticationModel.read(); const userIndex = AuthenticationModel.chain diff --git a/api/src/utils/custom-errors.utils.ts b/api/src/utils/custom-errors.utils.ts index 4b33d15f3..ee9204e84 100644 --- a/api/src/utils/custom-errors.utils.ts +++ b/api/src/utils/custom-errors.utils.ts @@ -1,55 +1,123 @@ import { HTTP_CODES, HTTP_TEXTS } from "../constants/index.js"; export class AppError extends Error { + /** + * Custom Error class for handling application errors. + */ constructor(public statusCode: number, message: string) { super(message); Object.setPrototypeOf(this, AppError.prototype); } } +/** + * Represents a custom error for a resource not found. + * Extends the base AppError class. + */ export class NotFoundError extends AppError { + /** + * Creates a new instance of NotFoundError. + * @param message - The error message. Defaults to "Not Found". + */ constructor(message: string = "Not Found") { super(HTTP_CODES.NOT_FOUND, message); } } +/** + * Represents a custom error for a bad request. + * Extends the base AppError class. + */ export class BadRequestError extends AppError { + /** + * Creates a new instance of the BadRequestError class. + * @param message The error message. + */ constructor(message: string = "Bad Request") { super(HTTP_CODES.BAD_REQUEST, message); } } +/** + * Represents a custom error related to database operations. + * Extends the base AppError class. + */ export class DatabaseError extends AppError { + /** + * Creates a new instance of the DatabaseError class. + * @param message The error message. + */ constructor(message: string = "DB error") { super(HTTP_CODES.SERVER_ERROR, message); } } +/** + * Represents a validation error that occurs during user validation. + * Extends the base AppError class. + */ export class ValidationError extends AppError { + /** + * Creates a new instance of the ValidationError class. + * @param message The error message associated with the validation error. Defaults to "User validation error". + */ constructor(message: string = "User validation error") { super(HTTP_CODES.UNPROCESSABLE_CONTENT, message); } } +/** + * Represents an Internal Server Error. + * This error is thrown when there is an internal server error in the application. + */ export class InternalServerError extends AppError { + /** + * Creates a new instance of the InternalServerError class. + * @param message The error message. + */ constructor(message: string = HTTP_TEXTS.INTERNAL_ERROR) { super(HTTP_CODES.SERVER_ERROR, message); } } +/** + * Represents an error that occurs when a user is unauthorized to access a resource. + * Extends the base AppError class. + */ export class UnauthorizedError extends AppError { + /** + * Creates a new instance of the UnauthorizedError class. + * @param message The error message. Defaults to the "Unauthorized" HTTP text. + */ constructor(message: string = HTTP_TEXTS.UNAUTHORIZED) { super(HTTP_CODES.UNAUTHORIZED, message); } } +/** + * Represents an error related to S3 operations. + * Extends the base AppError class. + */ export class S3Error extends AppError { + /** + * Creates a new instance of the S3Error class. + * @param message The error message. Defaults to HTTP_TEXTS.S3_ERROR. + */ constructor(message: string = HTTP_TEXTS.S3_ERROR) { super(HTTP_CODES.SERVER_ERROR, message); } } +/** + * Represents an ExceptionFunction class that extends the AppError class. + * This class is used to create custom exceptions with a specific HTTP status code. + */ export class ExceptionFunction extends AppError { + /** + * Creates a new instance of the ExceptionFunction class. + * @param message - The error message. + * @param httpStatus - The HTTP status code associated with the exception. + */ constructor(message: string, httpStatus: number) { super(httpStatus, message); } diff --git a/api/src/utils/get-project.utils.ts b/api/src/utils/get-project.utils.ts index 350cfd98c..cb32d8dc6 100644 --- a/api/src/utils/get-project.utils.ts +++ b/api/src/utils/get-project.utils.ts @@ -10,6 +10,16 @@ import { getLogMessage } from "../utils/index.js"; import logger from "./logger.js"; import { validate } from "uuid"; +/** + * Retrieves a project based on the provided project ID and query. + * @param projectId - The ID of the project to retrieve. + * @param query - The query to filter the projects. + * @param srcFunc - The source function name (optional). + * @param isIndex - Indicates whether to find the project by index (optional, default: false). + * @returns The retrieved project. + * @throws BadRequestError if the project ID is invalid or the project is not found. + * @throws ExceptionFunction if an error occurs during the retrieval process. + */ export default async ( projectId: string, query: MigrationQueryType, diff --git a/api/src/utils/https.utils.ts b/api/src/utils/https.utils.ts index 0ab6a892e..c878ee428 100644 --- a/api/src/utils/https.utils.ts +++ b/api/src/utils/https.utils.ts @@ -4,6 +4,9 @@ import { METHODS_TO_INCLUDE_DATA_IN_AXIOS, } from "../constants/index.js"; +/** + * Represents the HTTP request configuration. + */ type httpType = { url: string; method: string; @@ -11,6 +14,12 @@ type httpType = { data?: any; timeout?: number; }; +/** + * Sends an HTTP request using Axios. + * + * @param obj - The HTTP request object. + * @returns An object containing the response headers, status, and data. + */ export default async (obj: httpType) => { const { url, method, headers, data, timeout } = obj; const res = await axios(url, { diff --git a/api/src/utils/index.ts b/api/src/utils/index.ts index 40823eacc..15e6ea61d 100644 --- a/api/src/utils/index.ts +++ b/api/src/utils/index.ts @@ -1,17 +1,42 @@ +/** + * Throws an error with a custom message and status code. + * @param message - The error message. + * @param statusCode - The HTTP status code associated with the error. + * @throws {Error} - The error object with the specified message and status code. + */ export const throwError = (message: string, statusCode: number) => { throw Object.assign(new Error(message), { statusCode }); }; +/** + * Checks if a value is empty. + * @param val - The value to check. + * @returns `true` if the value is empty, `false` otherwise. + */ export const isEmpty = (val: unknown) => val === undefined || val === null || (typeof val === "object" && !Object.keys(val).length) || (typeof val === "string" && !val.trim().length); +/** + * Wraps a promise with error handling to ensure it always resolves with an array containing either an error or the result. + * @param promise - The promise to be wrapped. + * @returns A new promise that resolves with an array containing either an error or the result. + */ export const safePromise = (promise: Promise): Promise => promise.then((res) => [null, res]).catch((err) => [err]); //Generic method to get log message object +/** + * Returns a log message object. + * + * @param methodName - The name of the method. + * @param message - The log message. + * @param user - The user object. Defaults to an empty object. + * @param error - The error object. Optional. + * @returns The log message object. + */ export const getLogMessage = ( methodName: string, message: string, diff --git a/api/src/utils/jwt.utils.ts b/api/src/utils/jwt.utils.ts index d6f59aa7b..82e364bcd 100644 --- a/api/src/utils/jwt.utils.ts +++ b/api/src/utils/jwt.utils.ts @@ -4,6 +4,12 @@ import { AppTokenPayload } from "../models/types.js"; import { config } from "../config/index.js"; // @typescript-eslint/no-explicit-any +/** + * Generates a JWT token with the provided payload. + * + * @param payload - The payload to be included in the token. + * @returns The generated JWT token. + */ export const generateToken = (payload: AppTokenPayload): string => { return jwt.sign(payload, config.APP_TOKEN_KEY, { expiresIn: config.APP_TOKEN_EXP, diff --git a/api/src/utils/logger.ts b/api/src/utils/logger.ts index cbde4f7b0..b7baff0c3 100644 --- a/api/src/utils/logger.ts +++ b/api/src/utils/logger.ts @@ -1,6 +1,9 @@ import { createLogger, format, transports } from "winston"; //Logger for custom logs +/** + * The logger instance used for logging messages. + */ const logger = createLogger({ level: "info", format: format.combine(format.timestamp(), format.json()), diff --git a/api/src/utils/lowdb-lodash.utils.ts b/api/src/utils/lowdb-lodash.utils.ts index b87088a08..81bd511f8 100644 --- a/api/src/utils/lowdb-lodash.utils.ts +++ b/api/src/utils/lowdb-lodash.utils.ts @@ -1,6 +1,10 @@ import lodash from "lodash"; import { Low } from "lowdb"; +/** + * Represents a class that extends the Low class with Lodash functionality. + * @template T - The type of data stored in the LowWithLodash instance. + */ export default class LowWithLodash extends Low { chain: lodash.ExpChain = lodash.chain(this).get("data"); } From 4608251f3f1874f61911cfcb9c1ea62b54cbd25e Mon Sep 17 00:00:00 2001 From: Rohit Kini Date: Wed, 17 Jul 2024 12:18:00 +0530 Subject: [PATCH 09/17] added comments on validators --- api/src/database.ts | 6 ++++++ .../validators/affix-confirmation.validator.ts | 5 +++++ api/src/validators/affix.validator.ts | 5 +++++ api/src/validators/auth.validator.ts | 17 +++++++++++++++++ api/src/validators/cms.validator.ts | 5 +++++ .../validators/destination-stack.validator.ts | 5 +++++ api/src/validators/file-format.validator.ts | 5 +++++ .../fileformat-confirmation.validator.ts | 5 +++++ api/src/validators/index.ts | 5 +++++ api/src/validators/project.validator.ts | 5 +++++ 10 files changed, 63 insertions(+) diff --git a/api/src/database.ts b/api/src/database.ts index 859a3b0eb..8682aac4e 100644 --- a/api/src/database.ts +++ b/api/src/database.ts @@ -2,6 +2,12 @@ import logger from "./utils/logger.js"; import fs from "fs"; +/** + * Connects to the database. + * If the database folder does not exist, it creates it. + * @returns {Promise} A promise that resolves when the connection is successful. + * @throws {Error} If there is an error while connecting to the database. + */ const connectToDatabase = async () => { try { //check if the database folder exists diff --git a/api/src/validators/affix-confirmation.validator.ts b/api/src/validators/affix-confirmation.validator.ts index 5bbea21a7..837393dac 100644 --- a/api/src/validators/affix-confirmation.validator.ts +++ b/api/src/validators/affix-confirmation.validator.ts @@ -1,6 +1,11 @@ import { checkSchema } from "express-validator"; import { VALIDATION_ERRORS } from "../constants/index.js"; +/** + * Validates the affix_confirmation field in the request body. + * + * @returns {Object} The validation schema for the affix_confirmation field. + */ export default checkSchema({ affix_confirmation: { in: "body", diff --git a/api/src/validators/affix.validator.ts b/api/src/validators/affix.validator.ts index 62cf4af82..1dc70b5c0 100644 --- a/api/src/validators/affix.validator.ts +++ b/api/src/validators/affix.validator.ts @@ -1,6 +1,11 @@ import { checkSchema } from "express-validator"; import { VALIDATION_ERRORS, AFFIX_REGEX } from "../constants/index.js"; +/** + * Validates the 'affix' property in the request body. + * + * @returns {Object} The validation schema for the 'affix' property. + */ export default checkSchema({ affix: { in: "body", diff --git a/api/src/validators/auth.validator.ts b/api/src/validators/auth.validator.ts index 8ba097fe6..2148ae87d 100644 --- a/api/src/validators/auth.validator.ts +++ b/api/src/validators/auth.validator.ts @@ -1,7 +1,15 @@ import { checkSchema } from "express-validator"; import { VALIDATION_ERRORS, CS_REGIONS } from "../constants/index.js"; +/** + * Validates the authentication request body. + * + * @returns {Object} The validation schema for the authentication request body. + */ export default checkSchema({ + /** + * The email field in the request body. + */ email: { in: "body", isString: { @@ -22,6 +30,9 @@ export default checkSchema({ bail: true, }, }, + /** + * The password field in the request body. + */ password: { in: "body", isString: { @@ -30,6 +41,9 @@ export default checkSchema({ }, trim: true, }, + /** + * The region field in the request body. + */ region: { in: "body", isString: { @@ -43,6 +57,9 @@ export default checkSchema({ bail: true, }, }, + /** + * The 2FA token field in the request body. + */ tfa_token: { optional: true, in: "body", diff --git a/api/src/validators/cms.validator.ts b/api/src/validators/cms.validator.ts index 3b04f0625..7d391949e 100644 --- a/api/src/validators/cms.validator.ts +++ b/api/src/validators/cms.validator.ts @@ -1,6 +1,11 @@ import { checkSchema } from "express-validator"; import { VALIDATION_ERRORS } from "../constants/index.js"; +/** + * Validates the 'legacy_cms' field in the request body. + * + * @returns {Object} The validation schema for 'legacy_cms' field. + */ export default checkSchema({ legacy_cms: { in: "body", diff --git a/api/src/validators/destination-stack.validator.ts b/api/src/validators/destination-stack.validator.ts index 3c48f193c..e20439975 100644 --- a/api/src/validators/destination-stack.validator.ts +++ b/api/src/validators/destination-stack.validator.ts @@ -1,6 +1,11 @@ import { checkSchema } from "express-validator"; import { VALIDATION_ERRORS } from "../constants/index.js"; +/** + * Validates the destination stack API key. + * + * @returns {Object} The validation schema for the destination stack API key. + */ export default checkSchema({ stack_api_key: { in: "body", diff --git a/api/src/validators/file-format.validator.ts b/api/src/validators/file-format.validator.ts index 22aa06b1d..a8755511d 100644 --- a/api/src/validators/file-format.validator.ts +++ b/api/src/validators/file-format.validator.ts @@ -1,6 +1,11 @@ import { checkSchema } from "express-validator"; import { VALIDATION_ERRORS } from "../constants/index.js"; +/** + * Validates the file format. + * + * @returns {Object} The validation schema for the file format. + */ export default checkSchema({ file_format: { in: "body", diff --git a/api/src/validators/fileformat-confirmation.validator.ts b/api/src/validators/fileformat-confirmation.validator.ts index 199260966..4beb54b37 100644 --- a/api/src/validators/fileformat-confirmation.validator.ts +++ b/api/src/validators/fileformat-confirmation.validator.ts @@ -1,6 +1,11 @@ import { checkSchema } from "express-validator"; import { VALIDATION_ERRORS } from "../constants/index.js"; +/** + * Validates the file format confirmation field in the request body. + * + * @returns {Object} The validation schema for the file format confirmation field. + */ export default checkSchema({ fileformat_confirmation: { in: "body", diff --git a/api/src/validators/index.ts b/api/src/validators/index.ts index 269e5893e..1dd1e1549 100644 --- a/api/src/validators/index.ts +++ b/api/src/validators/index.ts @@ -10,6 +10,11 @@ import affixValidator from "./affix.validator.js"; import affixConfirmationValidator from "./affix-confirmation.validator.js"; import fileformatConfirmationValidator from "./fileformat-confirmation.validator.js"; +/** + * Middleware function that validates the request based on the specified route. + * @param route - The route to determine the validator to use. + * @returns The middleware function that performs the validation. + */ export default (route: string = "") => asyncRouter(async (req: Request, res: Response, next: NextFunction) => { const appValidators = { diff --git a/api/src/validators/project.validator.ts b/api/src/validators/project.validator.ts index d3e97973f..2df47ac1a 100644 --- a/api/src/validators/project.validator.ts +++ b/api/src/validators/project.validator.ts @@ -1,6 +1,11 @@ import { checkSchema } from "express-validator"; import { VALIDATION_ERRORS } from "../constants/index.js"; +/** + * Validates the project data. + * + * @returns {Object} The validation schema for the project data. + */ export default checkSchema({ name: { in: "body", From 46cdcb6207104e916d3d1a339563b46432af1529 Mon Sep 17 00:00:00 2001 From: AishDani Date: Wed, 17 Jul 2024 13:58:02 +0530 Subject: [PATCH 10/17] refactor:resolved content mapper bugs --- api/src/models/FieldMapper.ts | 1 + api/src/models/contentTypesMapper-lowdb.ts | 1 + api/src/routes/contentMapper.routes.ts | 2 +- api/src/services/contentMapper.service.ts | 43 +++++++++++----------- api/src/services/projects.service.ts | 6 +-- ui/src/cmsData/legacyCms.json | 2 +- ui/src/components/ContentMapper/index.scss | 4 ++ ui/src/components/ContentMapper/index.tsx | 28 ++++++++++---- ui/src/pages/Migration/index.tsx | 3 +- ui/src/services/api/migration.service.ts | 5 ++- 10 files changed, 59 insertions(+), 36 deletions(-) diff --git a/api/src/models/FieldMapper.ts b/api/src/models/FieldMapper.ts index f37f6bff4..2f1caf273 100644 --- a/api/src/models/FieldMapper.ts +++ b/api/src/models/FieldMapper.ts @@ -12,6 +12,7 @@ interface Advanced { interface FieldMapper { field_mapper: { id: string; + projectId: string; uid: string; otherCmsField: string; otherCmsType: string; diff --git a/api/src/models/contentTypesMapper-lowdb.ts b/api/src/models/contentTypesMapper-lowdb.ts index 77c3897a9..d394c5552 100644 --- a/api/src/models/contentTypesMapper-lowdb.ts +++ b/api/src/models/contentTypesMapper-lowdb.ts @@ -3,6 +3,7 @@ import LowWithLodash from "../utils/lowdb-lodash.utils.js"; export interface ContentTypesMapper { id: string; + projectId: string; otherCmsTitle: string; otherCmsUid: string; isUpdated: boolean; diff --git a/api/src/routes/contentMapper.routes.ts b/api/src/routes/contentMapper.routes.ts index a92401e68..5f563ba0a 100644 --- a/api/src/routes/contentMapper.routes.ts +++ b/api/src/routes/contentMapper.routes.ts @@ -17,7 +17,7 @@ router.get( ); //Get FieldMapping List router.get( - "/fieldMapping/:contentTypeId/:skip/:limit/:searchText?", + "/fieldMapping/:projectId/:contentTypeId/:skip/:limit/:searchText?", asyncRouter(contentMapperController.getFieldMapping) ); //Get Existing ContentTypes List diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index bd2151a07..63d63f340 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -34,7 +34,7 @@ const putTestData = async (req: Request) => { const fields = type?.fieldMapping?.map?.((field: any) => { const id = field?.id || uuidv4(); fieldIds.push(id); - return { id, isDeleted: true, ...field }; + return { id, projectId, isDeleted: true, ...field }; }); FieldMapperModel.update((data: any) => { data.field_mapper = [...(data?.field_mapper ?? []), ...fields]; @@ -47,11 +47,11 @@ const putTestData = async (req: Request) => { const contentType = contentTypes.map((item: any) => { const id = item?.id || uuidv4(); contentIds.push(id); - return { ...item, id }; + return { ...item, id, projectId }; }); await ContentTypesMapperModelLowdb.update((data: any) => { - data.ContentTypesMappers = contentType; + data.ContentTypesMappers = [...(data?.ContentTypesMappers ?? []), ...contentType]; }); await ProjectModelLowdb.read(); const index = ProjectModelLowdb.chain @@ -105,7 +105,7 @@ const getContentTypes = async (req: Request) => { contentMapperId.map((data: any) => { const contentMapperData = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .find({ id: data }) + .find({ id: data, projectId: projectId }) .value(); content_mapper.push(contentMapperData); }); @@ -137,6 +137,7 @@ const getContentTypes = async (req: Request) => { const getFieldMapping = async (req: Request) => { const srcFunc = "getFieldMapping"; const contentTypeId = req?.params?.contentTypeId; + const projectId = req?.params?.projectId; const skip: any = req?.params?.skip; const limit: any = req?.params?.limit; const search: string = req?.params?.searchText?.toLowerCase(); @@ -149,7 +150,7 @@ const getFieldMapping = async (req: Request) => { const contentType = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .find({ id: contentTypeId }) + .find({ id: contentTypeId, projectId: projectId }) .value(); if (isEmpty(contentType)) { @@ -165,11 +166,11 @@ const getFieldMapping = async (req: Request) => { const fieldData = contentType.fieldMapping.map((fields: any) => { const fieldMapper = FieldMapperModel.chain .get("field_mapper") - .find({ id: fields }) + .find({ id: fields, projectId: projectId}) .value(); + return fieldMapper; }); - const fieldMapping: any = fieldData; if (!isEmpty(fieldMapping)) { if (search) { @@ -315,7 +316,7 @@ const updateContentType = async (req: Request) => { const updateIndex = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .findIndex({ id: contentTypeId }) + .findIndex({ id: contentTypeId, projectId: projectId }) .value(); ContentTypesMapperModelLowdb.update((data: any) => { if (updateIndex >= 0) { @@ -366,7 +367,7 @@ const updateContentType = async (req: Request) => { await ContentTypesMapperModelLowdb.read(); const updatedContentType = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .find({ id: contentTypeId }) + .find({ id: contentTypeId, projectId: projectId }) .value(); return { updatedContentType }; @@ -425,14 +426,14 @@ const resetToInitialMapping = async (req: Request) => { await ContentTypesMapperModelLowdb.read(); const contentTypeData = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .find({ id: contentTypeId }) + .find({ id: contentTypeId,projectId: projectId }) .value(); await FieldMapperModel.read(); const fieldMappingData = contentTypeData.fieldMapping.map((itemId: any) => { const fieldData = FieldMapperModel.chain .get("field_mapper") - .find({ id: itemId }) + .find({ id: itemId, projectId: projectId }) .value(); return fieldData; }); @@ -524,7 +525,7 @@ const resetAllContentTypesMapping = async (projectId: string) => { const cData = contentMapperId.map((cId: any) => { const contentTypeData = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .find({ id: cId }) + .find({ id: cId, projectId: projectId }) .value(); return contentTypeData; }); @@ -537,11 +538,11 @@ const resetAllContentTypesMapping = async (projectId: string) => { await FieldMapperModel.read(); const fieldData = FieldMapperModel.chain .get("field_mapper") - .find({ id: field }) + .find({ id: field, projectId: projectId }) .value(); const fieldIndex = FieldMapperModel.chain .get("field_mapper") - .findIndex({ id: field }) + .findIndex({ id: field,projectId: projectId }) .value(); if (fieldIndex > -1) { @@ -560,7 +561,7 @@ const resetAllContentTypesMapping = async (projectId: string) => { if (!isEmpty(contentType?.id)) { const cIndex = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .findIndex({ id: contentType?.id }) + .findIndex({ id: contentType?.id , projectId: projectId}) .value(); if (cIndex > -1) { await ContentTypesMapperModelLowdb.update((data: any) => { @@ -610,7 +611,7 @@ const removeMapping = async (projectId: string) => { const cData = projectDetails?.content_mapper.map((cId: any) => { const contentTypeData = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .find({ id: cId }) + .find({ id: cId, projectId: projectId }) .value(); return contentTypeData; }); @@ -625,7 +626,7 @@ const removeMapping = async (projectId: string) => { await FieldMapperModel.read(); const fieldIndex = FieldMapperModel.chain .get("field_mapper") - .findIndex({ id: field }) + .findIndex({ id: field, projectId: projectId }) .value(); if (fieldIndex > -1) { await FieldMapperModel.update((fData: any) => { @@ -638,7 +639,7 @@ const removeMapping = async (projectId: string) => { if (!isEmpty(contentType?.id)) { const cIndex = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .findIndex({ id: contentType?.id }) + .findIndex({ id: contentType?.id, projectId: projectId}) .value(); if (cIndex > -1) { await ContentTypesMapperModelLowdb.update((data: any) => { @@ -738,7 +739,7 @@ const removeContentMapper = async (req: Request) => { const cData: ContentTypesMapper[] = projectDetails?.content_mapper.map((cId: string) => { const contentTypeData: ContentTypesMapper = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .find({ id: cId }) + .find({ id: cId, projectId:projectId }) .value(); return contentTypeData; }); @@ -753,7 +754,7 @@ const removeContentMapper = async (req: Request) => { await FieldMapperModel.read(); const fieldIndex = FieldMapperModel.chain .get("field_mapper") - .findIndex({ id: field }) + .findIndex({ id: field, projectId:projectId }) .value(); if (fieldIndex > -1) { await FieldMapperModel.update((fData: any) => { @@ -766,7 +767,7 @@ const removeContentMapper = async (req: Request) => { if (!isEmpty(contentType?.id)) { const cIndex = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .findIndex({ id: contentType?.id }) + .findIndex({ id: contentType?.id, projectId: projectId }) .value(); if (cIndex > -1) { await ContentTypesMapperModelLowdb.update((data: any) => { diff --git a/api/src/services/projects.service.ts b/api/src/services/projects.service.ts index f6cb13bb8..4e20691ed 100644 --- a/api/src/services/projects.service.ts +++ b/api/src/services/projects.service.ts @@ -710,7 +710,7 @@ const deleteProject = async (req: Request) => { content_mapper_id.map((item: any) => { const contentMapperData = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .find({ id: item }) + .find({ id: item, projectId:projectId }) .value(); const fieldMappingIds = contentMapperData?.fieldMapping; @@ -720,7 +720,7 @@ const deleteProject = async (req: Request) => { (fieldMappingIds || []).forEach((field: any) => { const fieldIndex = FieldMapperModel.chain .get("field_mapper") - .findIndex({ id: field }) + .findIndex({ id: field,projectId:projectId }) .value(); if (fieldIndex > -1) { FieldMapperModel.update((data: any) => { @@ -732,7 +732,7 @@ const deleteProject = async (req: Request) => { //delete all content Mapper which is related to Project const contentMapperID = ContentTypesMapperModelLowdb.chain .get("ContentTypesMappers") - .findIndex({ id: item }) + .findIndex({ id: item, projectId: projectId }) .value(); ContentTypesMapperModelLowdb.update((Cdata: any) => { delete Cdata.ContentTypesMappers[contentMapperID]; diff --git a/ui/src/cmsData/legacyCms.json b/ui/src/cmsData/legacyCms.json index 08ef2bfd7..dacef21ef 100644 --- a/ui/src/cmsData/legacyCms.json +++ b/ui/src/cmsData/legacyCms.json @@ -338,7 +338,7 @@ "uid": "cs6c761d71844ac800" }, "title": "Enter Affix", - "description": "Please enter the keyword to be affixed to the source. Minimum 2 characters, maximum 5 characters and should not start with numbers and not include special characters", + "description": "Please enter the keyword to be affixed to the source. Minimum 2 characters, maximum 5 characters and should not start with numbers and not include special characters.", "step_lock_text": "Editing this step is currently disabled. To make changes in Draft mode, please deactivate the migration.", "lock": false, "active": false, diff --git a/ui/src/components/ContentMapper/index.scss b/ui/src/components/ContentMapper/index.scss index cf03e88cb..3d635b4bd 100644 --- a/ui/src/components/ContentMapper/index.scss +++ b/ui/src/components/ContentMapper/index.scss @@ -270,3 +270,7 @@ div .table-row { padding: $px-12; text-align: center; } +.table-icons:hover { + background-color: $color-brand-fail-light; + cursor: pointer; +} \ No newline at end of file diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index d7ae14301..983da5f73 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -60,6 +60,7 @@ import AdvanceSettings from '../AdvancePropertise'; // Styles import './index.scss'; +import { MigrationResponse } from '../../services/api/service.interface'; const dummy_obj:any = { 'single_line_text':{ label : 'Single Line Textbox', @@ -178,7 +179,12 @@ const Fields: Mapping = { global_field: 'Global' }; -const ContentMapper = () => { +type ContentMapperComponentProps = { + projectData: MigrationResponse; + +}; + +const ContentMapper = ({projectData}:ContentMapperComponentProps) => { /** ALL CONTEXT HERE */ const migrationData = useSelector((state:RootState)=>state?.migration?.migrationData); @@ -337,8 +343,8 @@ const ContentMapper = () => { // Get the stack status if it is empty or not const stackStatus = async () => { const contentTypeCount = await getStackStatus( - newMigrationData?.destination_stack?.selectedOrg?.value, - newMigrationData?.destination_stack?.selectedStack?.value + projectData?.org_id, + projectData?.destination_stack_id ); if (contentTypeCount?.data?.contenttype_count > 0) { @@ -360,7 +366,7 @@ const ContentMapper = () => { // Method to get fieldmapping const fetchFields = async (contentTypeId: string, searchText: string) => { - const { data } = await getFieldMapping(contentTypeId || '', 0, 30, searchText || ''); + const { data } = await getFieldMapping(contentTypeId || '', 0, 30, searchText || '', projectId); try { const itemStatusMap: ItemStatusMapProp = {}; @@ -407,8 +413,8 @@ const ContentMapper = () => { updateItemStatusMap({ ...itemStatusMapCopy }); setLoading(true); - const { data } = await getFieldMapping(contentTypeUid || '', skip, limit, searchText || ''); - + const { data } = await getFieldMapping(contentTypeUid || '', skip, limit, searchText || '', projectId); + const updateditemStatusMapCopy: ItemStatusMapProp = { ...itemStatusMap }; for (let index = startIndex; index <= stopIndex; index++) { @@ -959,6 +965,13 @@ const ContentMapper = () => { }); } else { const { data } = await fetchExistingContentType(projectId, OtherContentType?.id || ''); + + const index = contentTypesList.findIndex(ct => ct?.uid === data?.uid); + if(index != -1){ + contentTypesList[index] = data; + } + + setContentTypesList(contentTypesList) setContentTypeSchema(data?.schema) } } @@ -1169,7 +1182,7 @@ const ContentMapper = () => {
{!IsEmptyStack && ( - + )} @@ -1179,6 +1192,7 @@ const ContentMapper = () => { size="small" version="v2" onClick={handleResetContentType} + hover={true} /> diff --git a/ui/src/pages/Migration/index.tsx b/ui/src/pages/Migration/index.tsx index 7fadece04..5e663e2f9 100644 --- a/ui/src/pages/Migration/index.tsx +++ b/ui/src/pages/Migration/index.tsx @@ -124,7 +124,8 @@ const Migration = () => { title:'Destination Stack' }, { - data: , + data: , id:'3', title:'Content Mapping' }, diff --git a/ui/src/services/api/migration.service.ts b/ui/src/services/api/migration.service.ts index e680370a2..833135f93 100644 --- a/ui/src/services/api/migration.service.ts +++ b/ui/src/services/api/migration.service.ts @@ -105,12 +105,13 @@ export const getFieldMapping = async ( contentTypeId: string, skip: number, limit: number, - searchText: string + searchText: string, + projectId:string ) => { try { const encodedSearchText = encodeURIComponent(searchText) ; return await getCall( - `${API_VERSION}/mapper/fieldMapping/${contentTypeId}/${skip}/${limit}/${encodedSearchText}?`, + `${API_VERSION}/mapper/fieldMapping/${projectId}/${contentTypeId}/${skip}/${limit}/${encodedSearchText}?`, options ); } catch (error: any) { From a1736c623974b7c254fc18f103669f8ec20e2dc0 Mon Sep 17 00:00:00 2001 From: Rohit Kini Date: Wed, 17 Jul 2024 14:04:49 +0530 Subject: [PATCH 11/17] components till DocLink --- api/src/controllers/org.controller.ts | 2 +- .../projects.contentMapper.controller.ts | 10 +- api/src/controllers/projects.controller.ts | 8 +- api/src/middlewares/auth.middleware.ts | 4 +- api/src/middlewares/req-headers.middleware.ts | 2 +- .../unmatched-routes.middleware.ts | 2 +- api/src/models/types.ts | 2 +- api/src/routes/auth.routes.ts | 4 +- api/src/services/contentMapper.service.ts | 15 +- api/src/services/org.service.ts | 2 +- api/src/services/projects.service.ts | 18 +-- api/src/validators/cms.validator.ts | 2 +- ui/src/common/assets/icons.tsx | 72 ++++++++-- .../AccountPage/accountPage.interface.ts | 3 + ui/src/components/AccountPage/index.scss | 17 +++ ui/src/components/AccountPage/index.tsx | 6 + .../advanceProperties.interface.ts | 115 +++++++++++++++ .../components/AdvancePropertise/index.scss | 31 ++++- ui/src/components/AdvancePropertise/index.tsx | 27 +++- ui/src/components/Card/card.interface.ts | 3 + ui/src/components/Card/card.scss | 101 +++++++++++--- ui/src/components/Card/index.tsx | 18 ++- .../Common/AddStack/addStack.interface.ts | 131 +++++++++++++++++- .../components/Common/AddStack/addStack.scss | 17 +++ .../components/Common/AddStack/addStack.tsx | 34 +++-- .../components/Common/Card/card.interface.ts | 25 ++++ ui/src/components/Common/Card/card.scss | 79 +++++++++++ ui/src/components/Common/Card/card.tsx | 12 ++ .../Common/DeleteProjectModal/index.tsx | 15 +- ui/src/components/Common/DocLink/DocLink.tsx | 31 +++++ 30 files changed, 722 insertions(+), 86 deletions(-) diff --git a/api/src/controllers/org.controller.ts b/api/src/controllers/org.controller.ts index 8767f2b3b..ac01c6964 100644 --- a/api/src/controllers/org.controller.ts +++ b/api/src/controllers/org.controller.ts @@ -3,7 +3,7 @@ import { orgService } from "../services/org.service.js"; /** * Retrieves all stacks. - * + * * @param {Request} req - The request object. * @param {Response} res - The response object. * @returns {Promise} - A promise that resolves when the operation is complete. diff --git a/api/src/controllers/projects.contentMapper.controller.ts b/api/src/controllers/projects.contentMapper.controller.ts index d813ba0e0..0839935fe 100644 --- a/api/src/controllers/projects.contentMapper.controller.ts +++ b/api/src/controllers/projects.contentMapper.controller.ts @@ -2,7 +2,7 @@ import { Request, Response } from "express"; import { contentMapperService } from "../services/contentMapper.service.js"; /** * Handles the PUT request to update test data. - * + * * @param req - The request object. * @param res - The response object. * @returns A Promise that resolves to void. @@ -14,7 +14,7 @@ const putTestData = async (req: Request, res: Response): Promise => { /** * Retrieves the content types from the content mapper service and sends the response as JSON. - * + * * @param req - The Express request object. * @param res - The Express response object. * @returns A Promise that resolves to void. @@ -25,7 +25,7 @@ const getContentTypes = async (req: Request, res: Response): Promise => { }; /** * Retrieves the field mapping for a given request and sends the response as JSON. - * + * * @param req - The request object. * @param res - The response object. * @returns A Promise that resolves to void. @@ -64,7 +64,7 @@ const putContentTypeFields = async ( }; /** * Resets the content type to its initial mapping. - * + * * @param req - The request object. * @param res - The response object. * @returns A Promise that resolves to void. @@ -96,7 +96,7 @@ const removeContentMapper = async ( /** * Retrieves single content types. - * + * * @param req - The request object. * @param res - The response object. * @returns A Promise that resolves to void. diff --git a/api/src/controllers/projects.controller.ts b/api/src/controllers/projects.controller.ts index a0ecdb2a9..3e7be0316 100644 --- a/api/src/controllers/projects.controller.ts +++ b/api/src/controllers/projects.controller.ts @@ -3,7 +3,7 @@ import { projectService } from "../services/projects.service.js"; /** * Retrieves all projects. - * + * * @param req - The request object. * @param res - The response object. * @returns A promise that resolves to void. @@ -27,7 +27,7 @@ const getProject = async (req: Request, res: Response): Promise => { /** * Creates a new project. - * + * * @param req - The request object. * @param res - The response object. * @returns A Promise that resolves to void. @@ -74,7 +74,7 @@ const updateAffix = async (req: Request, res: Response) => { /** * Handles the affix confirmation request. - * + * * @param req - The request object. * @param res - The response object. * @returns A Promise that resolves to the response data. @@ -132,7 +132,7 @@ const updateCurrentStep = async (req: Request, res: Response) => { /** * Deletes a project. - * + * * @param req - The request object. * @param res - The response object. * @returns A Promise that resolves to void. diff --git a/api/src/middlewares/auth.middleware.ts b/api/src/middlewares/auth.middleware.ts index 784202455..1e1499d28 100644 --- a/api/src/middlewares/auth.middleware.ts +++ b/api/src/middlewares/auth.middleware.ts @@ -6,7 +6,7 @@ import { HTTP_CODES } from "../constants/index.js"; /** * Middleware function to authenticate the user. - * + * * @param req - The Express request object. * @param res - The Express response object. * @param next - The next middleware function. @@ -24,7 +24,7 @@ export const authenticateUser = ( .status(status) .json({ status, message: "Unauthorized - Token missing" }); - /* this middleware function verifies the provided JWT token, + /* this middleware function verifies the provided JWT token, handles any errors that may occur during verification, attaches the decoded token payload to the request object, and then passes control to the next middleware or request handler. diff --git a/api/src/middlewares/req-headers.middleware.ts b/api/src/middlewares/req-headers.middleware.ts index 4e461839b..1c08008ab 100644 --- a/api/src/middlewares/req-headers.middleware.ts +++ b/api/src/middlewares/req-headers.middleware.ts @@ -3,7 +3,7 @@ import { Request, Response, NextFunction } from "express"; /** * Middleware function to handle request headers. * Adds necessary headers for CORS support and handles OPTIONS requests. - * + * * @param req - The Express Request object. * @param res - The Express Response object. * @param next - The next middleware function. diff --git a/api/src/middlewares/unmatched-routes.middleware.ts b/api/src/middlewares/unmatched-routes.middleware.ts index da305825e..cc6db151f 100644 --- a/api/src/middlewares/unmatched-routes.middleware.ts +++ b/api/src/middlewares/unmatched-routes.middleware.ts @@ -3,7 +3,7 @@ import { HTTP_CODES, HTTP_TEXTS } from "../constants/index.js"; /** * Middleware function to handle unmatched routes. - * + * * @param req - The Express request object. * @param res - The Express response object. */ diff --git a/api/src/models/types.ts b/api/src/models/types.ts index 605c176ea..41ad999de 100644 --- a/api/src/models/types.ts +++ b/api/src/models/types.ts @@ -6,7 +6,7 @@ export interface User { * The email address of the user. */ email: string; - + /** * The password of the user. */ diff --git a/api/src/routes/auth.routes.ts b/api/src/routes/auth.routes.ts index 359b070c1..60b1755b9 100644 --- a/api/src/routes/auth.routes.ts +++ b/api/src/routes/auth.routes.ts @@ -10,7 +10,7 @@ const router = express.Router(); /** * Route for user login. - * + * * @route POST /user-session * @group Authentication * @param {object} req.body - The request body containing user credentials. @@ -26,7 +26,7 @@ router.post( /** * Route for requesting SMS token. - * + * * @route POST /request-token-sms * @group Authentication * @param {object} req.body - The request body containing user information. diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index 7ee2dfc87..c717dc310 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -47,11 +47,12 @@ const putTestData = async (req: Request) => { */ contentTypes.map((type: any, index: any) => { const fieldIds: string[] = []; - const fields = type?.fieldMapping?.map?.((field: any) => { - const id = field?.id || uuidv4(); - fieldIds.push(id); - return { id, isDeleted: true, ...field }; - }) ?? []; + const fields = + type?.fieldMapping?.map?.((field: any) => { + const id = field?.id || uuidv4(); + fieldIds.push(id); + return { id, isDeleted: true, ...field }; + }) ?? []; FieldMapperModel.update((data: any) => { data.field_mapper = [...(data?.field_mapper ?? []), ...fields]; }); @@ -433,7 +434,7 @@ const updateContentType = async (req: Request) => { }; /** * Resets the field mapping and content mapping for a specific content type in a project. - * + * * @param req - The request object containing the parameters and body. * @returns An object with a message indicating the success of the reset operation. * @throws {BadRequestError} If the project status or current step is not valid for resetting the content mapping. @@ -550,7 +551,7 @@ const resetToInitialMapping = async (req: Request) => { }; /** * Resets all the content types mapping for a specific project. - * + * * @param projectId - The ID of the project. * @returns The project details after resetting the content types mapping. * @throws {BadRequestError} If the content mapper or project is not found. diff --git a/api/src/services/org.service.ts b/api/src/services/org.service.ts index 29dcb21d5..1719ce781 100644 --- a/api/src/services/org.service.ts +++ b/api/src/services/org.service.ts @@ -316,7 +316,7 @@ const getStackStatus = async (req: Request) => { */ const getStackLocal = async (token_payload: any, data: any) => { const srcFun = "getStackLocal"; - return new Promise( async (resolve) => { + return new Promise(async (resolve) => { const authtoken = await getAuthtoken( token_payload?.region, token_payload?.user_id diff --git a/api/src/services/projects.service.ts b/api/src/services/projects.service.ts index 6cff959ba..7fd806bed 100644 --- a/api/src/services/projects.service.ts +++ b/api/src/services/projects.service.ts @@ -196,8 +196,11 @@ const updateProject = async (req: Request) => { ProjectModelLowdb.update((data: any) => { data.projects[projectIndex].name = updateData?.name; data.projects[projectIndex].description = updateData?.description; - if(data.projects[projectIndex].isNewStack === false && updateData?.isNewStack === true){ - data.projects[projectIndex].isNewStack = updateData?.isNewStack ; + if ( + data.projects[projectIndex].isNewStack === false && + updateData?.isNewStack === true + ) { + data.projects[projectIndex].isNewStack = updateData?.isNewStack; data.projects[projectIndex].newStackId = updateData?.newStackId; } data.projects[projectIndex].updated_by = user_id; @@ -243,7 +246,7 @@ const updateProject = async (req: Request) => { /** * Updates the legacy CMS for a project. - * + * * @param req - The request object containing the parameters and body. * @returns An object with the status and data of the update operation. * @throws BadRequestError if the project status is invalid. @@ -329,7 +332,7 @@ const updateLegacyCMS = async (req: Request) => { /** * Updates the affix of a project. - * + * * @param req - The request object containing the parameters and body. * @returns An object with the status and data properties. */ @@ -366,7 +369,7 @@ const updateAffix = async (req: Request) => { /** * Affixes the confirmation to a project in the database. - * + * * @param req - The request object containing the parameters and body. * @returns An object with the status and data properties. */ @@ -544,7 +547,7 @@ const fileformatConfirmation = async (req: Request) => { /** * Updates the destination stack for a project. - * + * * @param req - The request object containing the parameters and body. * @returns An object with the status and data of the update operation. * @throws BadRequestError if the project status is invalid or the destination stack is not found. @@ -855,7 +858,7 @@ const deleteProject = async (req: Request) => { /** * Reverts a project by setting its 'isDeleted' property to false. - * + * * @param req - The request object containing the parameters and body. * @returns An object with the status and data of the reverted project. * @throws {NotFoundError} If the project is not found. @@ -903,7 +906,6 @@ const revertProject = async (req: Request) => { } }; - export const projectService = { getAllProjects, getProject, diff --git a/api/src/validators/cms.validator.ts b/api/src/validators/cms.validator.ts index 7d391949e..024726b5e 100644 --- a/api/src/validators/cms.validator.ts +++ b/api/src/validators/cms.validator.ts @@ -3,7 +3,7 @@ import { VALIDATION_ERRORS } from "../constants/index.js"; /** * Validates the 'legacy_cms' field in the request body. - * + * * @returns {Object} The validation schema for 'legacy_cms' field. */ export default checkSchema({ diff --git a/ui/src/common/assets/icons.tsx b/ui/src/common/assets/icons.tsx index 0b7f5d6c0..84ff957fa 100644 --- a/ui/src/common/assets/icons.tsx +++ b/ui/src/common/assets/icons.tsx @@ -1,3 +1,11 @@ +/** + * SVG component for the "NO_PROJECTS_SEARCH" icon. + * + * @remarks + * This SVG represents an icon used for indicating no search results in a project. + * + * @returns The SVG component. + */ export const NO_PROJECTS_SEARCH = ( ); +/** + * This file contains the definition of the NO_PROJECTS SVG icon. + * The icon represents a graphic illustration of a folder with no projects. + * It is used as a visual representation when there are no projects available. + */ export const NO_PROJECTS = ( ); +/** + * SVG icon component for a caret pointing right. + * + * @component + * @name CARET_RIGHT + */ export const CARET_RIGHT = ( ); +/** + * SVG icon component for the trash icon. + * @constant + */ export const TRASH = ( ); +/** + * SVG icon for search. + */ export const SEARCH_ICON = ( ); -export const LOG_OUT = ( - - - - +/** + * SVG icon for logging out. + */ +export const LOG_OUT = ( + + + + -); +); +/** + * SVG icon component for the magnify icon. + * + * @remarks + * This component renders an SVG icon for the magnify icon. + * + * @returns The SVG icon component. + */ export const MAGNIFY = ( - - - - + + + + ); +/** + * SVG icon component for DEMAGNIFY. + * + * @remarks + * This component renders an SVG icon for the DEMAGNIFY action. + * + * @returns The SVG icon component. + */ export const DEMAGNIFY = ( - - - - + + + ); diff --git a/ui/src/components/AccountPage/accountPage.interface.ts b/ui/src/components/AccountPage/accountPage.interface.ts index 761991296..a9e11bcc8 100644 --- a/ui/src/components/AccountPage/accountPage.interface.ts +++ b/ui/src/components/AccountPage/accountPage.interface.ts @@ -1,5 +1,8 @@ import { LoginType } from '../../pages/Login/login.interface'; +/** + * Represents an account object. + */ export interface AccountObj { children: React.ReactNode; data: LoginType; diff --git a/ui/src/components/AccountPage/index.scss b/ui/src/components/AccountPage/index.scss index 9af38e4f2..2de759609 100644 --- a/ui/src/components/AccountPage/index.scss +++ b/ui/src/components/AccountPage/index.scss @@ -1,5 +1,11 @@ @import '../../scss/variables'; +/** + * Styles for the AccountPage component. + * + * The AccountPage component is a container component that represents the account page of the application. + * It contains styles for the layout, logo, background image, action section, content, heading, and circles. + */ .AccountPage { align-items: stretch; display: flex; @@ -153,6 +159,17 @@ } } +/** + * Styles for the copyright text in the AccountPage component. + * + * CSS properties: + * - bottom: 1.5rem; + * - color: $color-font-base; + * - font-size: 0.75rem; + * - letter-spacing: 0.02em; + * - left: 2.5rem; + * - position: absolute; + */ .copyright_text { bottom: 1.5rem; color: $color-font-base; diff --git a/ui/src/components/AccountPage/index.tsx b/ui/src/components/AccountPage/index.tsx index 4b1316670..8809a70b8 100644 --- a/ui/src/components/AccountPage/index.tsx +++ b/ui/src/components/AccountPage/index.tsx @@ -4,6 +4,12 @@ import { AccountObj } from './accountPage.interface'; // Styles import './index.scss'; +/** + * Renders the AccountPage component. + * + * @param {AccountObj} props - The props object containing data for the component. + * @returns {JSX.Element} The rendered AccountPage component. + */ const AccountPage = (props: AccountObj): JSX.Element => { const { heading, copyrightText } = props.data; diff --git a/ui/src/components/AdvancePropertise/advanceProperties.interface.ts b/ui/src/components/AdvancePropertise/advanceProperties.interface.ts index 6ce7ae7f6..3c5be0314 100644 --- a/ui/src/components/AdvancePropertise/advanceProperties.interface.ts +++ b/ui/src/components/AdvancePropertise/advanceProperties.interface.ts @@ -1,36 +1,151 @@ import { Advanced, FieldMapType } from '../ContentMapper/contentMapper.interface'; +/** + * Represents the properties of a schema. + */ export interface SchemaProps { + /** + * The type of the field. + */ fieldtype: string; + + /** + * The updated settings for the field. + */ value: UpdatedSettings; + + /** + * The ID of the row. + */ rowId: string; + + /** + * A function to update the field settings. + * @param rowId - The ID of the row. + * @param value - The advanced settings. + * @param checkBoxChanged - Indicates whether the checkbox has changed. + */ updateFieldSettings: (rowId: string, value: Advanced, checkBoxChanged: boolean) => void; + + /** + * Indicates whether the field is localized. + */ isLocalised: boolean; + + /** + * A function to close the modal. + */ closeModal: () => void; + + /** + * The data for the field map. + */ data: FieldMapType; + + /** + * The ID of the project. + */ projectId?: string; } +/** + * Represents the updated settings for a component. + */ export interface UpdatedSettings { + /** + * The minimum number of characters allowed. + */ MinChars?: string; + + /** + * The maximum number of characters allowed. + */ MaxChars?: number; + + /** + * The minimum range allowed. + */ MinRange?: number; + + /** + * The maximum range allowed. + */ MaxRange?: number; + + /** + * The minimum size allowed. + */ minSize?: string; + + /** + * The maximum size allowed. + */ maxSize?: number; + + /** + * The default value for the component. + */ DefaultValue?: string; + + /** + * The regular expression used for validation. + */ ValidationRegex?: string; + + /** + * The title of the component. + */ title?: string; + + /** + * The URL associated with the component. + */ url?: string; + + /** + * Indicates whether the component is mandatory. + */ Mandatory?: boolean; + + /** + * Indicates whether only images are allowed. + */ AllowImagesOnly?: boolean; + + /** + * Indicates whether the component is non-localizable. + */ NonLocalizable?: boolean; } +/** + * Represents the props for the AdvanceProperties component. + */ export interface Props { + /** + * The data for the component. + */ data: SchemaProps; + + /** + * The optional states for the component. + */ states?: StateType; + + /** + * The callback function for handling changes in the component. + * @param field - The field that was changed. + * @param event - The event object associated with the change. + * @param checkBoxChanged - Indicates whether the change was triggered by a checkbox. + */ handleChange?: (field: string, event: any, checkBoxChanged: boolean) => void; + + /** + * The callback function for handling toggles in the component. + * @param field - The field that was toggled. + * @param value - The new value of the toggle. + * @param checkBoxChanged - Indicates whether the toggle was triggered by a checkbox. + */ handleToggle?: (field: string, value: boolean, checkBoxChanged: boolean) => void; } diff --git a/ui/src/components/AdvancePropertise/index.scss b/ui/src/components/AdvancePropertise/index.scss index 212c06f8b..ab126ed6e 100644 --- a/ui/src/components/AdvancePropertise/index.scss +++ b/ui/src/components/AdvancePropertise/index.scss @@ -1,6 +1,15 @@ @import '../../scss/variables'; .options-class { + /** + * Styles for the AdvancePropertise component. + * + * This SCSS file contains styles for the AdvancePropertise component, which is used to define + * advanced properties for a UI component. The styles include flexbox properties for layout, + * margin, grid template columns, and gap. + * + * @module components/AdvancePropertise + */ display: flex; flex-direction: column; justify-content: space-between; @@ -8,14 +17,34 @@ margin-bottom: 20px; grid-template-columns: 1fr; gap: 20px; -} + } +/** + * Styles for the option label in the AdvancePropertise component. + * + * @class option-label + * @memberof components.AdvancePropertise + * @cssprop {margin-bottom} margin-bottom - The margin bottom value for the option label. + */ .option-label { margin-bottom: $px-10; } +/** + * Styles for the non-localizable-message class. + */ .non-localizable-message { margin-top: 0; margin-left: 30px; } +/** + * + * This SCSS file contains styles for the AdvancePropertise component. + * + * The styles define various classes for different elements within the component, + * such as radio fields, labels, info styles, options, notes, toggles, fields, + * separators, and select menus. + * + * The classes are used to apply specific styling to these elements in the component. + */ .modal-data { padding: 0.75rem; .radio-field { diff --git a/ui/src/components/AdvancePropertise/index.tsx b/ui/src/components/AdvancePropertise/index.tsx index 373737a52..060d9f937 100644 --- a/ui/src/components/AdvancePropertise/index.tsx +++ b/ui/src/components/AdvancePropertise/index.tsx @@ -22,7 +22,13 @@ import { ContentType } from '../ContentMapper/contentMapper.interface'; // Styles import './index.scss'; +/** + * Component for displaying advanced properties. + * @param props - The schema properties. + * @returns The rendered component. + */ const AdvancePropertise = (props: SchemaProps) => { + // State for toggle states const [toggleStates, setToggleStates] = useState({ minChars: props?.value?.MinChars, maxChars: props?.value?.MaxChars, @@ -41,6 +47,7 @@ const AdvancePropertise = (props: SchemaProps) => { embedAssests: true }); + // State for content types const [contentTypes, setContentTypes] = useState([]); const [ctValue, setCTValue] = useState(null); @@ -48,13 +55,22 @@ const AdvancePropertise = (props: SchemaProps) => { fetchContentTypes(''); }, []) - // Fetch content types list + /** + * Fetches the content types list. + * @param searchText - The search text. + */ const fetchContentTypes = async (searchText: string) => { const { data } = await getContentTypes(props?.projectId ?? '', 0, 10, searchText || ''); //org id will always present setContentTypes(data?.contentTypes); }; + /** + * Handles the change event for input fields. + * @param field - The field name. + * @param event - The change event. + * @param checkBoxChanged - Indicates if the checkbox was changed. + */ const handleOnChange = (field: string, event: React.ChangeEvent, checkBoxChanged: boolean) => { setToggleStates((prevStates) => ({ ...prevStates, @@ -76,6 +92,12 @@ const AdvancePropertise = (props: SchemaProps) => { ); }; + /** + * Handles the toggle change event. + * @param field - The field name. + * @param value - The new value. + * @param checkBoxChanged - Indicates if the checkbox was changed. + */ const handleToggleChange = (field: string, value: boolean, checkBoxChanged: boolean) => { setToggleStates((prevStates) => ({ ...prevStates, @@ -97,13 +119,14 @@ const AdvancePropertise = (props: SchemaProps) => { ); }; + // Option for content types const option = Array.isArray(contentTypes) ? contentTypes.map((option) => ({ label: option?.otherCmsTitle, value: option?.otherCmsTitle })) : [{ label: contentTypes, value: contentTypes }]; return ( <> - +
{(props?.fieldtype === 'Single Line Textbox' || props?.fieldtype === 'Multi Line Textbox') && ( diff --git a/ui/src/components/Card/card.interface.ts b/ui/src/components/Card/card.interface.ts index 74c43df14..fe72a87b3 100644 --- a/ui/src/components/Card/card.interface.ts +++ b/ui/src/components/Card/card.interface.ts @@ -1,5 +1,8 @@ import { ProjectsObj } from '../../pages/Projects/projects.interface'; +/** + * Represents the project type. + */ export interface ProjectType { project?: ProjectsObj; } diff --git a/ui/src/components/Card/card.scss b/ui/src/components/Card/card.scss index 8a3917eaa..019a9875f 100644 --- a/ui/src/components/Card/card.scss +++ b/ui/src/components/Card/card.scss @@ -1,5 +1,8 @@ @import '../../scss/variables'; +/** + * Styles for the ProjectCard component. + */ .ProjectCard { background: $color-brand-white-base; border-radius: 0.6rem; @@ -7,14 +10,26 @@ transition: box-shadow 0.3s ease; width: 20rem; } + +/** + * Styles for the wrapper of the ProjectCard component. + */ .ProjectCardWrapper { padding: 18px; } + +/** + * Styles for the heading of the ProjectCard component. + */ .ProjectCard__heading { display: flex; margin-bottom: $px-20; padding: 0; } + +/** + * Styles for the title of the ProjectCard component. + */ .ProjectCard__title { color: $color-font-base; display: -webkit-box; @@ -28,6 +43,10 @@ -webkit-line-clamp: 2; -webkit-box-orient: vertical; } + +/** + * Styles for the footer of the ProjectCard component. + */ .ProjectCard__footer { display: flex; position: relative; @@ -39,27 +58,44 @@ padding: 0.9375rem 1.875rem; align-items: center; } + +/** + * Styles for the content of the ProjectCard component. + */ .ProjectCard__content { // margin: 0 1rem 2rem; padding: 0; text-align: center; } + +/** + * Styles for the status unit of the ProjectCard component. + */ .ProjectCard__Staus-unit { padding: 0 1em; } + +/** + * Styles for the unit of the ProjectCard component. + */ .ProjectCard__unit { border-left: 1px solid $color-brand-secondary-lightest; padding: 0 1em; } -.ProjectCard__unit:not(:last-child) { - border-right: 1px solid $color-base-gray-40; -} + +/** + * Styles for the stats of the ProjectCard component. + */ .ProjectCard__stats { display: flex; flex-wrap: nowrap; justify-content: center; padding-bottom: $px-10; } + +/** + * Styles for the stats category of the ProjectCard component. + */ .ProjectCard__stats-category { border: 1px solid $color-brand-secondary-lightest; border-radius: 8px; @@ -68,31 +104,56 @@ color: $color-font-base; padding: 4px 8px; text-transform: capitalize; - svg { - margin-right: 5px; - } - &.draft { - background-color: $color-base-white-10; - } - &.completed { - background-color: $color-brand-success-light; - } - &.failed { - background-color: $color-brand-fail-light; - } - &.pending { - background-color: $color-brand-attention-light; - } } + +/** + * Styles for the draft stats category of the ProjectCard component. + */ +.ProjectCard__stats-category.draft { + background-color: $color-base-white-10; +} + +/** + * Styles for the completed stats category of the ProjectCard component. + */ +.ProjectCard__stats-category.completed { + background-color: $color-brand-success-light; +} + +/** + * Styles for the failed stats category of the ProjectCard component. + */ +.ProjectCard__stats-category.failed { + background-color: $color-brand-fail-light; +} + +/** + * Styles for the pending stats category of the ProjectCard component. + */ +.ProjectCard__stats-category.pending { + background-color: $color-brand-attention-light; +} + +/** + * Styles for the stats title of the ProjectCard component. + */ .ProjectCard__stats-Title { color: $color-stepper-title; display: block; font-size: $size-font-small; margin-bottom: $space-4; } + +/** + * Styles for the validation color of the ProjectCard component. + */ .validation-color { color: $color-brand-warning-medium; } + +/** + * Styles for the CMS of the ProjectCard component. + */ .ProjectCard__cms { border: 1px solid $color-brand-secondary-lightest; border-radius: 8px; @@ -101,6 +162,10 @@ padding: 4px 8px; text-transform: capitalize; } + +/** + * Styles for the modified date of the ProjectCard component. + */ .ProjectCard__modified-date { color: $color-stepper-title; display: block; diff --git a/ui/src/components/Card/index.tsx b/ui/src/components/Card/index.tsx index 44bc169f1..ffd010899 100644 --- a/ui/src/components/Card/index.tsx +++ b/ui/src/components/Card/index.tsx @@ -12,16 +12,26 @@ import { getProject } from '../../services/api/project.service'; import './card.scss'; import { RootState } from '../../store'; +/** + * Renders a card component for a project in a list. + * @param project - The project object containing project details. + */ const CardList = ({ project }: ProjectType) => { const navigate = useNavigate(); - const selectedOrganisation = useSelector((state:RootState)=>state?.authentication?.selectedOrganisation); + const selectedOrganisation = useSelector((state: RootState) => state?.authentication?.selectedOrganisation); const [projectDetails, setprojectDetails] = useState(''); + /** + * Handles the click event when a project card is clicked. + * Navigates to the project migration steps page. + * @param id - The ID of the project. + */ const onClickProject = (id: string) => { if (isEmptyString(id)) return; navigate(`/projects/${id}/migration/steps/1`); }; + const iconMapping: { [key: string]: string } = { '0': 'Information', '1': 'Warning', @@ -31,6 +41,7 @@ const CardList = ({ project }: ProjectType) => { '5': 'CheckCircleDark', '6': 'Close', }; + const statusClassMapping: { [key: string]: string } = { '0': 'draft', '1': 'pending', @@ -40,6 +51,7 @@ const CardList = ({ project }: ProjectType) => { '5': 'completed', '6': 'failed', }; + const status = project?.status ?? '0'; const statusClass = statusClassMapping[status] || ''; const icon = iconMapping[status] || ''; @@ -56,7 +68,7 @@ const CardList = ({ project }: ProjectType) => { }; fetchProject(); }, [selectedOrganisation?.value, project?.id]); - + return (
onClickProject(project?.id || '')}> @@ -66,7 +78,7 @@ const CardList = ({ project }: ProjectType) => {
{project?.name &&

{project?.name}

}
- +
diff --git a/ui/src/components/Common/AddStack/addStack.interface.ts b/ui/src/components/Common/AddStack/addStack.interface.ts index da16ddc96..944c38fab 100644 --- a/ui/src/components/Common/AddStack/addStack.interface.ts +++ b/ui/src/components/Common/AddStack/addStack.interface.ts @@ -1,70 +1,199 @@ import { IDropDown } from '../../../context/app/app.interface'; +/** + * Represents the data structure for adding a stack in CMS. + */ export interface AddStackCMSData { + /** + * The primary call-to-action for the stack. + */ primary_cta: PrimaryCta; + + /** + * The secondary call-to-action for the stack. + */ secondary_cta: SecondaryCta; + + /** + * The description of the stack. + */ stack_description: string; + + /** + * The placeholder text for the stack description. + */ stack_description_placeholder: string; + + /** + * The localized description of the stack. + */ stack_locale_description: string; + + /** + * The locales supported by the stack. + */ stack_locales: string; + + /** + * The name of the stack. + */ stack_name: string; + + /** + * The placeholder text for the stack name. + */ stack_name_placeholder: string; + + /** + * The title of the stack. + */ title: string; } +/** + * Represents the primary call-to-action button for adding a stack. + */ export interface PrimaryCta { title: string; } +/** + * Represents the Secondary CTA interface. + */ export interface SecondaryCta { title: string; } +/** + * Interface representing the default data for AddStackCMSData. + */ export const defaultAddStackCMSData: AddStackCMSData = { + /** + * The title of the primary call-to-action button. + */ primary_cta: { title: '' }, + /** + * The title of the secondary call-to-action button. + */ secondary_cta: { title: '' }, + /** + * The description of the stack. + */ stack_description: '', + /** + * The placeholder for the stack description input field. + */ stack_description_placeholder: '', + /** + * The localized description of the stack. + */ stack_locale_description: '', + /** + * The locales supported by the stack. + */ stack_locales: '', + /** + * The name of the stack. + */ stack_name: '', + /** + * The placeholder for the stack name input field. + */ stack_name_placeholder: '', + /** + * The title of the stack. + */ title: '' }; +/** + * Represents the props for the AddStack component. + */ export interface AddStackProps { + /** + * The default values for the stack. + */ defaultValues: Stack; + + /** + * The locales for the dropdown. + */ locales: IDropDown[]; - onSubmit: (value: Stack) => {}; + + /** + * The function to be called when the form is submitted. + * @param value - The submitted stack value. + */ + onSubmit: (value: Stack) => void; + + /** + * The selected organisation. + */ selectedOrganisation: string; + + /** + * The function to close the modal. + */ closeModal: () => void; } +/** + * Represents a stack. + */ export interface Stack { + /** + * The name of the stack. + */ name: string; + + /** + * The description of the stack. + */ description: string; + + /** + * The locale of the stack. + */ locale: string; } +/** + * Represents the data structure for a stack. + */ export interface StackData { name: string; description: string; locale: Locale; } +/** + * Represents a locale. + */ interface Locale { value: string; } +/** + * Represents the response object returned by the server. + */ export interface Response { data: Data; } +/** + * Represents the data structure for the 'Data' interface. + */ interface Data { locales: LocaleType; } +/** + * Represents a type that defines a mapping of string keys to string values. + */ interface LocaleType { [key: string]: string; } +/** + * Represents the errors that can occur when adding a stack. + */ export interface Errors { name: string; locale: string; diff --git a/ui/src/components/Common/AddStack/addStack.scss b/ui/src/components/Common/AddStack/addStack.scss index 5a6647c80..d768305c2 100644 --- a/ui/src/components/Common/AddStack/addStack.scss +++ b/ui/src/components/Common/AddStack/addStack.scss @@ -1,11 +1,28 @@ +/** + * Styles for the ReactModal__add-stack class. + */ .ReactModal__add-stack { + /** + * Styles for the textarea inside the Description-field class. + * Disables the resizing of the textarea. + */ .Description-field > textarea { resize: none; } + + /** + * Styles for the single-value inside the Select__single-value class. + * Overrides the width to 200px. + */ .Select__single-value { width: 200px !important; } } + +/** + * Styles for the ReactModal__Overlay, ReactModal__Content, and ReactModal__Content__body.selectWrapperBody classes. + * Sets the overflow property to visible. + */ .ReactModal__Overlay .ReactModal__Content .ReactModal__Content__body.selectWrapperBody { overflow: visible; } diff --git a/ui/src/components/Common/AddStack/addStack.tsx b/ui/src/components/Common/AddStack/addStack.tsx index a8dc2ef24..9a6605c50 100644 --- a/ui/src/components/Common/AddStack/addStack.tsx +++ b/ui/src/components/Common/AddStack/addStack.tsx @@ -37,11 +37,22 @@ export interface Stack { locale: string; } +/** + * Renders the AddStack component. + * @param props - The component props. + * @returns The JSX element representing the AddStack component. + */ const AddStack = (props: any): JSX.Element => { + // State variables const [isProcessing, setIsProcessing] = useState(false); const [isLoading, setIsLoading] = useState(true); const [allLocales, setAllLocales] = useState([]); const [addStackCMSData, setAddStackCMSData] = useState(defaultAddStackCMSData); + + /** + * Handles the form submission. + * @param formData - The form data. + */ const onSubmit = async (formData: any) => { setIsProcessing(true); const resp = await props?.onSubmit({ @@ -63,10 +74,10 @@ const AddStack = (props: any): JSX.Element => { }; useEffect(() => { - //check if offline CMS data field is set to true, if then read data from cms data file. + // Check if offline CMS data field is set to true, if then read data from cms data file. getCMSDataFromFile(CS_ENTRIES?.ADD_STACK) .then((data: AddStackCMSData) => { - //Check for null + // Check for null if (!data) { setAddStackCMSData(defaultAddStackCMSData); setIsLoading(false); @@ -81,7 +92,7 @@ const AddStack = (props: any): JSX.Element => { setIsLoading(false); }); - //fetch all locales + // Fetch all locales getAllLocales(props?.selectedOrganisation) .then((response: any) => { const rawMappedLocalesMapped = @@ -100,7 +111,6 @@ const AddStack = (props: any): JSX.Element => { .catch((err: any) => { console.error(err); }); - //org id will always be there window.addEventListener('popstate', props?.closeModal); @@ -121,7 +131,7 @@ const AddStack = (props: any): JSX.Element => { { + validate={(values: any) => { const errors: any = {}; if (!values?.name || values?.name?.trim().length < 1) { errors.name = 'Stack name required'; @@ -213,13 +223,13 @@ const AddStack = (props: any): JSX.Element => { error={(meta?.error || meta?.submitError) && meta?.touched} /> {meta?.error && meta?.touched && ( - - {meta?.error} - - )} + + {meta?.error} + + )}
); diff --git a/ui/src/components/Common/Card/card.interface.ts b/ui/src/components/Common/Card/card.interface.ts index c48478488..db2068ec0 100644 --- a/ui/src/components/Common/Card/card.interface.ts +++ b/ui/src/components/Common/Card/card.interface.ts @@ -1,11 +1,36 @@ +/** + * Represents the interface for a card type. + */ export interface ICardType { + /** + * The title of the card. + */ title: string; + + /** + * The group name of the card. + */ group_name?: string; + + /** + * The description of the card. + */ description?: string; + + /** + * The CMS ID of the card. + */ cms_id?: string; + + /** + * The file format ID of the card. + */ fileformat_id?: string; } +/** + * Represents the default card type. + */ export const defaultCardType: ICardType = { title: '', group_name: '', diff --git a/ui/src/components/Common/Card/card.scss b/ui/src/components/Common/Card/card.scss index 6d90f2822..8b85919de 100644 --- a/ui/src/components/Common/Card/card.scss +++ b/ui/src/components/Common/Card/card.scss @@ -1,5 +1,11 @@ @import '../../../scss/variables'; +/** + * Styles for the service list container. + * + * @class service_list + * @memberof components.Common.Card + */ .service_list { text-align: center; display: flex; @@ -9,10 +15,18 @@ margin-bottom: 10px; } +/** + * Styles for the trigger_list class. + * This class sets the minimum width of 120px for the element. + */ .trigger_list { min-width: 120px !important; } +/** + * Styles for the connector list in the card component. + * Overrides the default styles of the tippy-box-light class. + */ .connector_list .tippy-box-light { max-width: $px-360 !important; padding: $px-15 !important; @@ -21,6 +35,9 @@ font-weight: $font-weight-regular; } +/** + * Styles for the connector list, action list, and trigger list components. + */ .connector_list, .action_list, .trigger_list { @@ -35,19 +52,61 @@ gap: 12px; } +/** + * Styles for the automation connectors help text within the connector list. + * + * Selectors: + * - .connector_list: The parent container for the connector list. + * - .tippy-box-light: The tooltip box with light theme. + * - #automationConnectorsHelpText: The help text element with the ID "automationConnectorsHelpText". + * + * CSS Properties: + * - cursor: Sets the cursor type to default. + * - color: Sets the text color to the base gray-20 color variable. + */ .connector_list .tippy-box-light #automationConnectorsHelpText { cursor: default; color: $color-base-gray-20; } +/** + * Applies a box shadow effect to the .connector_list element when hovered. + * + * @hover + * @cssproperty box-shadow - The box shadow effect to apply. + * @cssvalue 0 3px $px-5 $px-2 rgb(215 215 215) - The specific box shadow values. + */ .connector_list:hover { box-shadow: 0 3px $px-5 $px-2 rgb(215 215 215); } +/** + * Styles for the service icon in the card component. + * + * @class service_icon + * @memberof components.Common.Card + * + * @cssprop {padding} padding - The padding of the service icon. + */ .service_icon { padding: $space-20 0; } +/** + * Styles for the service title in the card component. + * + * @class .service_title + * @memberof components.Common.Card + * + * @cssprop {padding} padding - The padding of the service title. + * @cssprop {min-height} min-height - The minimum height of the service title. + * @cssprop {max-height} max-height - The maximum height of the service title. + * @cssprop {overflow-y} overflow-y - The overflow behavior for the service title. + * @cssprop {font-weight} font-weight - The font weight of the service title. + * @cssprop {font-size} font-size - The font size of the service title. + * @cssprop {border-radius} border-radius - The border radius of the service title. + * @cssprop {background} background - The background color of the service title. + */ .service_title { padding: $px-5 $px-5; min-height: $px-40; @@ -59,6 +118,19 @@ background: $color-base-white-10; } +/** + * Styles for the header of the full-screen page layout. + * + * @class .PageLayout--full-screen .PageLayout__head + * @memberof components.Common.Card + * + * @cssprop {position} position - The position of the header. + * @cssprop {border} border-bottom - The bottom border of the header. + * @cssprop {box-shadow} box-shadow - The shadow of the header. + * @cssprop {border} border - The border of the header. + * @cssprop {margin} margin-top - The top margin of the header. + * @cssprop {z-index} z-index - The stacking order of the header. + */ .PageLayout--full-screen .PageLayout__head { position: relative; border-bottom: 1px solid rgb(226, 235, 248); @@ -67,6 +139,13 @@ margin-top: 3.5rem; z-index: 8; } +/** + * CSS class for a centered card title. + * Adds a margin of 10px to the title. + */ +.centered-card-title { + margin: 10px; +} .centered-card-title{ margin: 10px; } diff --git a/ui/src/components/Common/Card/card.tsx b/ui/src/components/Common/Card/card.tsx index fc0a9b7e1..2d2d081fe 100644 --- a/ui/src/components/Common/Card/card.tsx +++ b/ui/src/components/Common/Card/card.tsx @@ -5,6 +5,9 @@ import { addDomainInPath } from '../../../utilities/functions'; import './card.scss'; +/** + * Props for the Card component. + */ type CardProps = { data: any; idField?: string; @@ -13,6 +16,15 @@ type CardProps = { cardType?: string; }; +/** + * Renders a card component. + * + * @param data - The data object for the card. + * @param selectedCard - The currently selected card. + * @param onCardClick - The callback function to handle card click event. + * @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 imgStyle = { width: cardType === 'legacyCMS' ? '60px' : '46px', diff --git a/ui/src/components/Common/DeleteProjectModal/index.tsx b/ui/src/components/Common/DeleteProjectModal/index.tsx index d5abbf786..b175dfadb 100644 --- a/ui/src/components/Common/DeleteProjectModal/index.tsx +++ b/ui/src/components/Common/DeleteProjectModal/index.tsx @@ -15,6 +15,12 @@ import { deleteProject } from '../../../services/api/project.service'; // Interfaces import { SettingsModalProps } from '../../../components/Modal/modal.interface'; +/** + * Renders a modal component for deleting a project. + * + * @param {SettingsModalProps} props - The component props. + * @returns {JSX.Element} The rendered DeleteProjectModal component. + */ const DeleteProjectModal = (props: SettingsModalProps) => { const { closeModal, @@ -24,7 +30,13 @@ const DeleteProjectModal = (props: SettingsModalProps) => { selectedOrg } = props; - const handleDeleteProject = async (closeModal: () => void) => { + /** + * Handles the deletion of the project. + * + * @param {() => void} closeModal - A function to close the modal. + * @returns {Promise} A promise that resolves when the project is deleted. + */ + const handleDeleteProject = async (closeModal: () => void): Promise => { const response = await deleteProject(selectedOrg?.value || '', projectId ?? '',); if (response?.status === 200) { @@ -44,6 +56,7 @@ const DeleteProjectModal = (props: SettingsModalProps) => { }, 1200) } } + return ( <> ) => void; } +/** + * Renders a component that displays a link and a checkbox. + * + * @component + * @example + * // Usage: + * { + * console.log('Checkbox changed:', e.target.checked); + * }} + * /> + * + * @param {Object} props - The component props. + * @param {Object} props.cta - The link details. + * @param {string} props.cta.href - The URL of the link. + * @param {string} props.cta.title - The title of the link. + * @param {boolean} props.isCheckedBoxChecked - Indicates whether the checkbox is checked. + * @param {boolean} props.isDisable - Indicates whether the component is disabled. + * @param {string} props.label - The label for the checkbox. + * @param {boolean} props.isLabelFullWidth - Indicates whether the label should take full width. + * @param {function} props.onChange - The event handler for the checkbox change event. + * @returns {JSX.Element} The rendered component. + */ const DocLink = ({ cta, isCheckedBoxChecked, From 613f7d56d1a66e9ea8e25354fedeae475815a55a Mon Sep 17 00:00:00 2001 From: AishDani Date: Wed, 17 Jul 2024 14:32:47 +0530 Subject: [PATCH 12/17] refactor:added regex for id of fieldmapper --- api/src/services/contentMapper.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index c9ca50a58..3d2373fd2 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -48,7 +48,7 @@ const putTestData = async (req: Request) => { contentTypes.map((type: any, index: any) => { const fieldIds: string[] = []; const fields = type?.fieldMapping?.map?.((field: any) => { - const id = field?.id || uuidv4(); + const id = field?.id.replace(/[{}-]/g, '').toLowerCase() || uuidv4(); fieldIds.push(id); return { id, projectId, isDeleted: true, ...field }; }); @@ -68,7 +68,7 @@ const putTestData = async (req: Request) => { and the generated id values are pushed into the contentIds array. */ const contentType = contentTypes.map((item: any) => { - const id = item?.id || uuidv4(); + const id = item?.id.replace(/[{}-]/g, '').toLowerCase() || uuidv4(); contentIds.push(id); return { ...item, id, projectId }; }); From ce819816acface1e59a3bf7f249ebba3ac22c8cc Mon Sep 17 00:00:00 2001 From: Rohit Kini Date: Wed, 17 Jul 2024 17:58:26 +0530 Subject: [PATCH 13/17] added comments till Content mapper --- .../Common/FileUpload/fileupload.scss | 30 ++++ ui/src/components/Common/FileUpload/index.tsx | 40 ++++++ .../components/Common/FileUpload/upload.scss | 96 +++++++++++++ .../components/Common/FileUpload/upload.tsx | 22 +++ .../Common/Modal/FilterModal/FilterModal.scss | 129 ++++++++++++++++++ .../Common/Modal/FilterModal/FilterModal.tsx | 3 + .../FilterModal/filterModal.interface.ts | 4 + .../Common/NotificationModal/index.tsx | 50 ++++--- .../Common/ProgressBar/progressBar.scss | 9 ++ .../components/Common/Settings/Settings.scss | 11 ++ ui/src/components/Common/Settings/index.tsx | 4 + .../Common/Settings/setting.interface.ts | 9 ++ .../Common/WordWrapper/WordWrapper.tsx | 6 + ui/src/components/Common/private-route.tsx | 11 ++ ui/src/components/Common/router.tsx | 4 + 15 files changed, 409 insertions(+), 19 deletions(-) diff --git a/ui/src/components/Common/FileUpload/fileupload.scss b/ui/src/components/Common/FileUpload/fileupload.scss index 6a2e32bda..44476f91f 100644 --- a/ui/src/components/Common/FileUpload/fileupload.scss +++ b/ui/src/components/Common/FileUpload/fileupload.scss @@ -1,4 +1,7 @@ @import '../../../scss/variables'; +/** + * Styles for the file upload container. + */ .file-upload-container { display: flex; height: 21.25rem; @@ -10,6 +13,9 @@ border-radius: 0.25rem; border: 0.125rem dashed $color-base-gray-40; + /** + * Styles for the file upload element. + */ .file-upload { display: flex; height: 4.5rem; @@ -20,6 +26,9 @@ flex-shrink: 0; } + /** + * Styles for the text inside the file upload element. + */ .file-upload-text { text-align: center; font-family: Inter; @@ -30,6 +39,9 @@ letter-spacing: 0.16px; } + /** + * Styles for the image inside the file upload container. + */ .file-upload-image { width: 15rem; height: 15rem; @@ -37,14 +49,32 @@ } } +/** + * Adds a hover effect to the element, displaying a dashed border in the base purple color. + * + * @class hover + */ .hover { border: 0.125rem dashed $color-base-purple; } +/** + * This SCSS file contains styles for the FileUpload component. + */ + .hidden { display: none; } +/** + * Styles for the validation container component. + * + * The validation container is a flex container that displays a validation message + * for a file upload component. It has a white background color, a fixed height, + * and a border. The container is centered vertically and has no padding. + * + * @class validation-container + */ .validation-container { display: flex; background-color: $color-base-white-5; diff --git a/ui/src/components/Common/FileUpload/index.tsx b/ui/src/components/Common/FileUpload/index.tsx index 1945e9955..73958cd4f 100644 --- a/ui/src/components/Common/FileUpload/index.tsx +++ b/ui/src/components/Common/FileUpload/index.tsx @@ -11,16 +11,30 @@ type FileUploadProps = { projectId: string; }; +/** + * FileUpload component for uploading files. + * + * @param {FileUploadProps} props - The props for the FileUpload component. + * @returns {JSX.Element} The rendered FileUpload component. + */ const FileUpload = (props: FileUploadProps) => { const [isDragOver, setIsDragOver] = useState(false); const fileInputRef = useRef(null); const targetRef = useRef(null); + /** + * Empty method to handle setting upload modal to false. + */ const handleSetUploadModalFalse = (): any => { // Empty Method }; + /** + * Reads the files and opens the upload modal. + * + * @param {FileList | null} filesList - The list of files to be uploaded. + */ const readFiles = (filesList: FileList | null) => { //handle Null check if (!filesList) return; @@ -49,6 +63,11 @@ const FileUpload = (props: FileUploadProps) => { setIsDragOver(false); }; + /** + * Handles the drop event when files are dropped onto the component. + * + * @param {DragEvent} e - The drop event. + */ const handleDrop = (e: DragEvent) => { e.preventDefault(); e.stopPropagation(); @@ -57,22 +76,43 @@ const FileUpload = (props: FileUploadProps) => { e.dataTransfer.clearData(); }; + /** + * Handles the drag toggle event when dragging files over the component. + * + * @param {boolean} flag - The flag indicating whether the files are being dragged over the component. + * @returns {Function} The event handler function. + */ const handleDragToggle = (flag: boolean) => (e: DragEvent) => { e.preventDefault(); setIsDragOver(flag); }; + /** + * Handles the file change event when a file is selected using the file input. + * + * @param {ChangeEvent} e - The file change event. + */ const handleFileChange = (e: ChangeEvent) => { e.preventDefault(); readFiles(e?.target?.files); }; + /** + * Handles the file select event when the "Choose file" link is clicked. + * + * @param {any} e - The file select event. + */ const handleFileSelect = (e: any) => { e.preventDefault(); fileInputRef?.current?.click(); }; + /** + * Handles the onClose event after the files are uploaded. + * + * @param {IFile[]} files - The uploaded files. + */ const onCloseAfterUpload = (files: IFile[]) => { props.handleOnFileUpload(files); }; diff --git a/ui/src/components/Common/FileUpload/upload.scss b/ui/src/components/Common/FileUpload/upload.scss index b6b680fb9..13ab47b9c 100644 --- a/ui/src/components/Common/FileUpload/upload.scss +++ b/ui/src/components/Common/FileUpload/upload.scss @@ -1,11 +1,21 @@ @import '../../../scss/variables'; /* Asset upload window css */ +/** + * Styles for the asset upload component. + * + * @class .asset-upload + */ .asset-upload { background: $color-brand-white-base; box-shadow: 0 $space-4 $space-30 rgba(0, 0, 0, 0.25); width: 31.25rem; + /** + * Styles for the heading section of the asset upload component. + * + * @class .asset-upload__heading + */ &__heading { align-items: center; border-radius: $radii-4; @@ -14,26 +24,58 @@ justify-content: space-between; padding: 0 calc(var(--space-22) + 0.063rem); + /** + * Styles for the in-progress state of the heading section. + * + * @class .in-progress + */ &.in-progress { background-color: $color-brand-primary-base; } + /** + * Styles for the success state of the heading section. + * + * @class .success + */ &.success { background-color: $color-brand-success-base; } + /** + * Styles for the attention state of the heading section. + * + * @class .attention + */ &.attention { background-color: $color-brand-attention-base; } + /** + * Styles for the warning state of the heading section. + * + * @class .warning + */ &.warning { background-color: #ffab00 !important; } + /** + * Styles for the actions section of the heading. + * + * @class .asset-upload-actions + */ .asset-upload-actions { justify-content: space-between; width: 4.375rem; + /** + * Styles for the cancel, minimize, and maximize buttons in the actions section. + * + * @class .asset-upload__cancel + * @class .asset-upload__minimize + * @class .asset-upload__maximize + */ &__cancel, &__minimize, &__maximize { @@ -45,20 +87,34 @@ justify-content: center; width: $space-30; + /** + * Styles for the hover state of the cancel, minimize, and maximize buttons. + */ &:hover { background: rgba(34, 34, 34, 0.2); } + /** + * Styles for the SVG icons in the cancel, minimize, and maximize buttons. + */ & > svg { cursor: pointer; } } + /** + * Styles for the SVG icons in the actions section. + */ & > svg { cursor: pointer; } } + /** + * Styles for the count section in the heading. + * + * @class .asset-upload__count + */ .asset-upload__count { color: $color-font-white; font-size: $size-font-xl; @@ -67,17 +123,32 @@ } } + /** + * Styles for the body section of the asset upload component. + * + * @class .asset-upload__body + */ &__body { height: 19.06rem; margin-right: $space-15; overflow-y: auto; + /** + * Styles for each file in the body section. + * + * @class .asset-upload__file + */ .asset-upload__file { display: flex; height: 3.75rem; justify-content: space-between; padding: $space-15; + /** + * Styles for the name section of each file. + * + * @class .asset-upload__name + */ &__name { color: $color-font-black; font-size: $size-font-medium; @@ -87,17 +158,37 @@ // @include text-wrapper; } + /** + * Styles for the actions section of each file. + * + * @class .asset-upload__actions + */ &__actions { display: flex; + /** + * Styles for the progress section in the actions section. + * + * @class .asset-upload__progress + */ &__progress { margin-right: $space-34; + /** + * Styles for the file loaded count in the progress section. + * + * @class .file-loaded + */ .file-loaded { color: $color-font-base; font-size: $size-font-medium; } + /** + * Styles for the total size count in the progress section. + * + * @class .total-size + */ .total-size { color: $color-font-base; font-size: $size-font-medium; @@ -105,6 +196,11 @@ } } + /** + * Styles for the cancel upload button in the actions section. + * + * @class .cancel-upload + */ .cancel-upload { cursor: pointer; margin-top: calc(var(--space-2) + 0.063rem); diff --git a/ui/src/components/Common/FileUpload/upload.tsx b/ui/src/components/Common/FileUpload/upload.tsx index fcae15a4e..748f47799 100644 --- a/ui/src/components/Common/FileUpload/upload.tsx +++ b/ui/src/components/Common/FileUpload/upload.tsx @@ -19,6 +19,14 @@ import { returnFileSize, shortName } from '../../../utilities/functions'; import { UPLOAD_FILE_URL } from '../../../utilities/constants'; import './upload.scss'; +/** + * Renders a file component. + * + * @param {Object} props - The component props. + * @param {Object} props.file - The file object. + * @param {Function} props.handleRemove - The function to handle file removal. + * @returns {JSX.Element} The file component. + */ const File = ({ file, handleRemove }: any) => { return (
@@ -43,6 +51,12 @@ const File = ({ file, handleRemove }: any) => { ); }; +/** + * Renders an error file component. + * @param file - The file object. + * @param handleRemove - The function to handle file removal. + * @returns The JSX element representing the error file component. + */ const ErrorFile = ({ file, handleRemove }: any) => { return (
@@ -62,6 +76,11 @@ const ErrorFile = ({ file, handleRemove }: any) => { ); }; +/** + * Renders a component for interrupting the file upload process. + * @param props - The component props. + * @returns The rendered InterruptUpload component. + */ const InterruptUpload = (props: any) => { const handleProceed = () => { props.closeModal({ cancelUpload: true }); @@ -100,6 +119,9 @@ const InterruptUpload = (props: any) => { ); }; +/** + * Component for handling file uploads. + */ class Upload extends Component { state = { fileList: this.props.fileList, diff --git a/ui/src/components/Common/Modal/FilterModal/FilterModal.scss b/ui/src/components/Common/Modal/FilterModal/FilterModal.scss index a39ada6aa..65731c96f 100644 --- a/ui/src/components/Common/Modal/FilterModal/FilterModal.scss +++ b/ui/src/components/Common/Modal/FilterModal/FilterModal.scss @@ -1,5 +1,10 @@ @import '../../../../scss/variables'; +/** + * Styles for the FilterModal component. + * + * @class Filter__modal + */ .Filter__modal { width: $px-400; z-index: 40; @@ -9,29 +14,78 @@ border-radius: $px-10; } +/** + * Styles for the checkbox input and tick in the FilterModal component. + * + * The styles target the checkbox input element when it is checked, as well as the checkbox box element. + * The margin-top property sets the top margin of the checkbox tick. + * The font-size property sets the font size of the checkbox input. + */ .Filter__modal .Checkbox input:checked ~ .Checkbox__tick, .Filter__modal .Checkbox .Checkbox__box { margin-top: $px-4; font-size: $px-16; } +/** + * Styles for the FilterModal component. + * + * @class FilterModal + * @memberof components.Common.Modal + * + * @cssprop {string} cursor - Specifies the type of cursor to be displayed when hovering over the Filter__item. + * @cssprop {string} padding - Specifies the padding of the Filter__item. + */ .Filter__modal .Filter__item { cursor: pointer; padding: $px-10 $px-20; } +/** + * Styles for the hover effect on the FilterModal item. + * + * This selector targets the FilterModal item when it is being hovered over by the user. + * It sets the background color to a lightened version of the base white color. + */ .Filter__modal .Filter__item:hover { background-color: $color-base-white-10; } +/** + * Applies a specific color to the WordWrapper element when the Filter__item is being hovered over. + * + * @selector .Filter__modal .Filter__item:hover .WordWrapper + * @property color - The color to apply to the WordWrapper element. + * @value $color-brand-primary-base - The base color of the brand primary. + */ .Filter__modal .Filter__item:hover .WordWrapper { color: $color-brand-primary-base; } +/** + * Styles for the hover effect on the Checkbox__box element within the Filter__item element + * in the Filter__modal component. + * + * When the Filter__item element is hovered over, the Checkbox__box element will have a border + * with a thickness of 1.5 pixels and a color of $color-brand-primary-base. + */ .Filter__modal .Filter__item:hover .Checkbox__box { border: 1.5px solid $color-brand-primary-base; } +/** + * Styles for the header of the filter modal. + * + * @class .Filter__modal-header + * @memberof components.Common.Modal.FilterModal + * + * @property {string} background - The background color of the header. + * @property {string} border-bottom - The bottom border of the header. + * @property {string} font-size - The font size of the header. + * @property {string} height - The height of the header. + * @property {string} justify-content - The alignment of the content within the header. + * @property {string} padding - The padding of the header. + */ .Filter__modal-header { background: $color-base-white-10; border-bottom: 1px solid $color-brand-secondary-lightest; @@ -41,6 +95,20 @@ padding: $px-14 $px-16; } +/** + * Styles for the header container of the filter modal. + * + * @class .Filter__modal-header .Filter__modal-header-container + * @memberOf components.Common.Modal.FilterModal.FilterModal.scss + * + * @property {string} align-items - Specifies the alignment of the items inside the container. + * @property {string} display - Specifies the display behavior of the container. + * @property {string} color - Specifies the color of the text inside the container. + * @property {string} font-size - Specifies the font size of the text inside the container. + * @property {string} height - Specifies the height of the container. + * @property {string} line-height - Specifies the line height of the text inside the container. + * @property {string} font-weight - Specifies the font weight of the text inside the container. + */ .Filter__modal-header .Filter__modal-header-container { align-items: center; display: flex; @@ -53,10 +121,19 @@ font-weight: 600; } +/** + * Styles for the title element in the header of the filter modal. + */ .Filter__modal-header .Filter__modal-header-container .Filter__modal-header-title { font-weight: 600; } +/** + * Styles for the counter element in the filter modal header. + * + * This selector targets the counter element within the header container of the filter modal. + * It applies styles such as border, border radius, color, font size, font weight, etc. + */ .Filter__modal-header .Filter__modal-header-container .Filter__modal-header-counter { border: 1px solid $color-brand-secondary-lightest; border-radius: 1rem; @@ -74,30 +151,61 @@ width: fit-content; } +/** + * Styles for the search input inside the FilterModal component. + * + * @class .Filter__searchbox .Search--primary .Search__input + * @memberof components.Common.Modal.FilterModal + * + * @cssprop {number} height - The height of the search input in pixels. + */ .Filter__searchbox .Search--primary .Search__input { height: $px-35; } +/** + * Styles for the FilterModal component's modal content. + */ .Filter__modal-content { overflow: scroll; max-height: $px-250; overflow-x: hidden; } +/** + * Styles for the Filter__icon class. + * + * This class is used to style the filter icon in the modal. + * It sets the cursor to pointer, adds padding, and sets the border-radius to 10%. + */ .Filter__icon { cursor: pointer !important; padding: $px-5; border-radius: 10%; } +/** + * Styles for the hover effect on the Filter__icon element. + */ .Filter__icon:hover { background-color: rgba(108, 92, 231, 0.1); } +/** + * Sets the background color for the filter icon. + * + * @class .Filter__icon_bg_color + * @memberof components.Common.Modal.FilterModal + * + * @cssprop {Color} background-color - The background color of the filter icon. + */ .Filter__icon_bg_color { background-color: rgba(108, 92, 231, 0.1); } +/** + * Styles for the cancel button in the filter modal header. + */ .Filter__modal-header-cancel { border-radius: 25%; cursor: pointer; @@ -105,10 +213,24 @@ width: $px-24; } +/** + * Styles for the hover state of the cancel button in the filter modal header. + * + * @class .Filter__modal-header-cancel:hover + * @memberof components.Common.Modal.FilterModal.FilterModal.scss + * + * @cssprop {Color} background-color - The background color of the cancel button when hovered. + */ .Filter__modal-header-cancel:hover { background-color: $color-brand-secondary-lightest; } +/** + * Styles for the footer of the filter modal. + * + * @class .Filter__modal-footer + * @memberof components.Common.Modal.FilterModal + */ .Filter__modal-footer { display: flex; border-top: 1px solid $color-brand-secondary-lightest; @@ -117,6 +239,13 @@ padding: $px-20; } +/** + * Styles for the ".Filter__no-found" class. + * + * This class is used to style the text when no results are found in the filter modal. + * It sets the text alignment to center, vertical alignment to middle, line height to $px-50, + * font weight to 600, and font size to $px-14. + */ .Filter__no-found { text-align: center; vertical-align: middle; diff --git a/ui/src/components/Common/Modal/FilterModal/FilterModal.tsx b/ui/src/components/Common/Modal/FilterModal/FilterModal.tsx index 56b3e5d20..403f30cd6 100644 --- a/ui/src/components/Common/Modal/FilterModal/FilterModal.tsx +++ b/ui/src/components/Common/Modal/FilterModal/FilterModal.tsx @@ -5,6 +5,9 @@ import WordWrapper from '../../WordWrapper/WordWrapper'; import { IFilterStatusType, IFilterType } from './filterModal.interface'; import './FilterModal.scss'; +/** + * Props for the FilterModal component. + */ type Props = { title: string; list: IFilterType[]; diff --git a/ui/src/components/Common/Modal/FilterModal/filterModal.interface.ts b/ui/src/components/Common/Modal/FilterModal/filterModal.interface.ts index 311d0aab3..c36a49a87 100644 --- a/ui/src/components/Common/Modal/FilterModal/filterModal.interface.ts +++ b/ui/src/components/Common/Modal/FilterModal/filterModal.interface.ts @@ -4,6 +4,10 @@ export interface IFilterType { isChecked: boolean; } +/** + * Represents the interface for the filter status type. + * It is a key-value pair where the key is a string and the value is a boolean. + */ export interface IFilterStatusType { [key: string]: boolean; } diff --git a/ui/src/components/Common/NotificationModal/index.tsx b/ui/src/components/Common/NotificationModal/index.tsx index 8467cd796..382155925 100644 --- a/ui/src/components/Common/NotificationModal/index.tsx +++ b/ui/src/components/Common/NotificationModal/index.tsx @@ -14,26 +14,38 @@ interface Props { isopen: any; } -const NotificationModal = (props:Props) => { - return( - <> - {props?.closeModal(),props.isopen(false)}} className="text-capitalize" /> - -
- -
-
- +/** + * Renders a notification modal component. + * + * @param props - The component props. + * @returns The rendered notification modal component. + */ +const NotificationModal = (props: Props) => { + return ( + <> + { + props?.closeModal(); + props.isopen(false); + }} + className="text-capitalize" + /> + +
+ +
+
+ - - - - - - ) - + + + +
+ + ); } export default NotificationModal; \ No newline at end of file diff --git a/ui/src/components/Common/ProgressBar/progressBar.scss b/ui/src/components/Common/ProgressBar/progressBar.scss index fc0310e27..2e304456f 100644 --- a/ui/src/components/Common/ProgressBar/progressBar.scss +++ b/ui/src/components/Common/ProgressBar/progressBar.scss @@ -1,5 +1,14 @@ @import '../../../scss//variables'; +/** + * Styles for the ProgressBar component. + * + * The ProgressBar component displays a progress bar with a customizable bar and circle. + * + * @class ProgressBar + * @memberof components.Common + * + */ .ProgressBar { border-radius: $space-4; diff --git a/ui/src/components/Common/Settings/Settings.scss b/ui/src/components/Common/Settings/Settings.scss index 4c6377a39..5d7787582 100644 --- a/ui/src/components/Common/Settings/Settings.scss +++ b/ui/src/components/Common/Settings/Settings.scss @@ -34,13 +34,24 @@ } } +/** + * Styles for the Settings component. + */ + .Field { margin-bottom: $px-40; } + +/** + * Styles for hiding the left sidebar in the PageLayout component. + */ .PageLayout__leftSidebar--hide { display: none; } +/** + * Styles for the left sidebar. + */ .leftsidebar { margin-top: 0 !important; } diff --git a/ui/src/components/Common/Settings/index.tsx b/ui/src/components/Common/Settings/index.tsx index 7103fb796..4f9d0d982 100644 --- a/ui/src/components/Common/Settings/index.tsx +++ b/ui/src/components/Common/Settings/index.tsx @@ -34,6 +34,10 @@ import DeleteProjectModal from '../DeleteProjectModal'; import './Settings.scss'; import { RootState } from '../../../store'; +/** + * Renders the Settings component. + * This component is responsible for displaying and updating project settings. + */ const Settings = () => { const params: Params = useParams(); diff --git a/ui/src/components/Common/Settings/setting.interface.ts b/ui/src/components/Common/Settings/setting.interface.ts index f0abcc5e4..183b80b84 100644 --- a/ui/src/components/Common/Settings/setting.interface.ts +++ b/ui/src/components/Common/Settings/setting.interface.ts @@ -1,3 +1,6 @@ +/** + * Represents a project. + */ interface IProject { title: string; name: string; @@ -7,6 +10,9 @@ interface IProject { save_project: CTA; email: string; } +/** + * Represents a Call to Action (CTA) object. + */ interface CTA { open_in_new_tab: boolean; theme: string; @@ -18,6 +24,9 @@ interface IExecutionLogs { title: string; } +/** + * Represents a setting object. + */ export interface Setting { project?: IProject; execution_logs?: IExecutionLogs; diff --git a/ui/src/components/Common/WordWrapper/WordWrapper.tsx b/ui/src/components/Common/WordWrapper/WordWrapper.tsx index f9ca62381..9b86a8e31 100644 --- a/ui/src/components/Common/WordWrapper/WordWrapper.tsx +++ b/ui/src/components/Common/WordWrapper/WordWrapper.tsx @@ -10,6 +10,12 @@ type Props = { position?: string; }; +/** + * Renders a component that wraps text and provides a tooltip if the text exceeds a maximum length. + * + * @param {Props} props - The component props. + * @returns {JSX.Element} The rendered WordWrapper component. + */ function WordWrapper(props: Props) { const { maxLength, tooltipcontent, position = 'right' } = props; const text = props.text || ''; diff --git a/ui/src/components/Common/private-route.tsx b/ui/src/components/Common/private-route.tsx index 3ba2ce342..b7fa4da40 100644 --- a/ui/src/components/Common/private-route.tsx +++ b/ui/src/components/Common/private-route.tsx @@ -2,11 +2,22 @@ import { FC, ReactNode } from 'react'; import { Navigate, Outlet, useLocation } from 'react-router'; import { getDataFromLocalStorage } from '../../utilities/functions'; +/** + * Props for the PrivateRoute component. + */ type IProps = { children?: ReactNode; redirectTo: string; }; +/** + * Renders a private route component that checks if the user is authenticated. + * If the user is authenticated, it renders the child components. + * If the user is not authenticated, it redirects to the specified route. + * + * @param redirectTo - The route to redirect to if the user is not authenticated. + * @returns The private route component. + */ const PrivateRoute: FC = ({ redirectTo }: IProps) => { const isAuthenticated = !!getDataFromLocalStorage('app_token'); diff --git a/ui/src/components/Common/router.tsx b/ui/src/components/Common/router.tsx index 6df9932c2..0fffa4a2f 100644 --- a/ui/src/components/Common/router.tsx +++ b/ui/src/components/Common/router.tsx @@ -19,6 +19,10 @@ const MigrationLazyLoad = lazy(() => import('../../pages/Migration')); const ProjectsLazyLoad = lazy(() => import('../../pages/Projects')); const SettingsLazyLoad = lazy(() => import ('../Common/Settings')) +/** + * Renders the application router. + * @returns The application router component. + */ const AppRouter = () => { return ( From 35ffe90561d320205295c47c59c7c4e4b3de0789 Mon Sep 17 00:00:00 2001 From: AishDani Date: Wed, 17 Jul 2024 18:51:24 +0530 Subject: [PATCH 14/17] refactor:changed uid of title and url to lowercase --- api/src/services/contentMapper.service.ts | 4 ++-- uplaode-api/migration-sitecore/libs/contenttypes.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index 47c8a92e6..298e37743 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -48,7 +48,7 @@ const putTestData = async (req: Request) => { contentTypes.map((type: any, index: any) => { const fieldIds: string[] = []; const fields = type?.fieldMapping?.map?.((field: any) => { - const id = field?.id.replace(/[{}-]/g, '').toLowerCase() || uuidv4(); + const id = field?.id?.replace(/[{}]/g, '')?.toLowerCase() || uuidv4(); fieldIds.push(id); return { id, projectId, isDeleted: true, ...field }; }); @@ -68,7 +68,7 @@ const putTestData = async (req: Request) => { and the generated id values are pushed into the contentIds array. */ const contentType = contentTypes.map((item: any) => { - const id = item?.id.replace(/[{}-]/g, '').toLowerCase() || uuidv4(); + const id = item?.id?.replace(/[{}]/g, '')?.toLowerCase() || uuidv4(); contentIds.push(id); return { ...item, id, projectId }; }); diff --git a/uplaode-api/migration-sitecore/libs/contenttypes.js b/uplaode-api/migration-sitecore/libs/contenttypes.js index 570384ecc..dbfd138b4 100644 --- a/uplaode-api/migration-sitecore/libs/contenttypes.js +++ b/uplaode-api/migration-sitecore/libs/contenttypes.js @@ -464,7 +464,7 @@ const contentTypeMapper = ({ components, standardValues, content_type, basePath, if (isUrlfound === undefined) { mainSchema?.unshift( { - uid: "Url", + uid: "url", "otherCmsField": "url", "otherCmsType": "text", "contentstackField": "Url", @@ -478,7 +478,7 @@ const contentTypeMapper = ({ components, standardValues, content_type, basePath, ) if (isPresent === undefined) { mainSchema.unshift({ - uid: "Title", + uid: "title", "otherCmsField": "title", "otherCmsType": "text", "contentstackField": "Title", From a2188e75bc161f5ae29c92b682bbf638ee2f2521 Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Thu, 18 Jul 2024 13:24:39 +0530 Subject: [PATCH 15/17] [CMG-247] - debugging --- ui/src/components/ContentMapper/index.tsx | 81 ++++++++++++++++++++--- 1 file changed, 71 insertions(+), 10 deletions(-) diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 81ef07407..9703c209e 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -48,7 +48,8 @@ import { optionsType, UidMap, ContentTypeMap, - Advanced + Advanced, + SavedContentType } from './contentMapper.interface'; import { ItemStatusMapProp } from '@contentstack/venus-components/build/components/Table/types'; import { ModalObj } from '../Modal/modal.interface'; @@ -57,6 +58,7 @@ import { UpdatedSettings } from '../AdvancePropertise/advanceProperties.interfac // Components import SchemaModal from '../SchemaModal'; import AdvanceSettings from '../AdvancePropertise'; +import SaveChangesModal from '../Common/SaveChangesModal'; // Styles import './index.scss'; @@ -425,19 +427,71 @@ const ContentMapper = () => { } }; + const [isModalOpen, setIsModalOpen] = useState(false); + + + const [currentCt, setCurrentCt] = useState(contentTypes[0]?.otherCmsTitle); + const [savedContentType, setSavedContentType] = useState({'col1': true, 'col2': false}); + console.log("savedContentType", savedContentType); + + + // Method to change the content type const openContentType = (i: number) => { - setActive(i); + // console.log("savedContentType[i - 1]", i, savedContentType[i - 1]); + + if (i > -1 && 1 < filteredContentTypes?.length) { + + // filteredContentTypes?.forEach((ct: ContentType) => { + // ct.otherCmsTitle = true + // }) - const otherTitle = contentTypes?.[i]?.otherCmsTitle; - setOtherCmsTitle(otherTitle); - const option = contentTypeMapped?.[otherTitle] ?? 'Select Content Type'; - setOtherContentType({ label: option, value: option }); - setContentTypeUid(contentTypes?.[i]?.id ?? ''); - fetchFields(contentTypes?.[i]?.id ?? '', searchText || ''); - setotherCmsUid(contentTypes?.[i]?.otherCmsUid); - setSelectedContentType(contentTypes?.[i]); + // setCurrentCt(otherTitle); + const updatedCT = {} + // updatedCT.contentTypes.[i].otherCmsTitle = true + // contentTypes.[i].otherCmsTitle = true + setSavedContentType(updatedCT) + + + + + + // console.log("isContentTypeSaved", savedContentType[i - 1]?.otherCmsTitle, savedContentType[i]?.otherCmsTitle); + + // savedCTArray.push({contentTypes?.[i]?.otherCmsTitle : true}); + } + + // console.log("savedCTArray", contentTypes?.[i]?.otherCmsTitle, i); + if (isDropDownChanged) { + console.log("otherCmsTitle", otherCmsTitle); + + setIsModalOpen(true); + return cbModal({ + component: (props: ModalObj) => ( + + ), + modalProps: { + size: 'xsmall', + shouldCloseOnOverlayClick: false + } + }); + } else { + setActive(i); + const otherTitle = contentTypes?.[i]?.otherCmsTitle; + setOtherCmsTitle(otherTitle); + const option = contentTypeMapped?.[otherTitle] ?? 'Select Content Type'; + setOtherContentType({ label: option, value: option }); + + setContentTypeUid(contentTypes?.[i]?.id ?? ''); + fetchFields(contentTypes?.[i]?.id ?? '', searchText || ''); + setotherCmsUid(contentTypes?.[i]?.otherCmsUid); + setSelectedContentType(contentTypes?.[i]); + } }; // Function to get exisiting content types list @@ -525,6 +579,8 @@ const ContentMapper = () => { // Method for change select value const handleValueChange = (value: FieldTypes, rowIndex: string) => { + console.log("setisDropDownCHanged", value, rowIndex); + setisDropDownCHanged(true); setFieldValue(value); const updatedRows = tableData?.map((row) => { @@ -893,6 +949,11 @@ const ContentMapper = () => { setisContentTypeMapped(true); setisContentTypeSaved(true); + // const savedCTArray: SavedContentType = {} + // data.updatedContentType.otherCmsTitle = true + // // savedCTArray = data?.updatedContentType; + // setSavedContentType(data?.updatedContentType?.otherCmsTitle) + setFilteredContentTypes(filteredContentTypes?.map(ct => ct?.id === data?.updatedContentType?.id ? { ...ct, status: data?.updatedContentType?.status } : ct )) From dd15779539ebde8eeadb5f0edd00baa2dc3a8549 Mon Sep 17 00:00:00 2001 From: AishDani Date: Thu, 18 Jul 2024 15:18:37 +0530 Subject: [PATCH 16/17] refactor:resolved undefined error --- api/src/services/contentMapper.service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index 298e37743..4949216c6 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -49,6 +49,7 @@ const putTestData = async (req: Request) => { const fieldIds: string[] = []; const fields = type?.fieldMapping?.map?.((field: any) => { const id = field?.id?.replace(/[{}]/g, '')?.toLowerCase() || uuidv4(); + field.id = id; fieldIds.push(id); return { id, projectId, isDeleted: true, ...field }; }); @@ -68,7 +69,8 @@ const putTestData = async (req: Request) => { and the generated id values are pushed into the contentIds array. */ const contentType = contentTypes.map((item: any) => { - const id = item?.id?.replace(/[{}]/g, '')?.toLowerCase() || uuidv4(); + const id = item?.id.replace(/[{}]/g, '')?.toLowerCase() || uuidv4(); + item.id = id; contentIds.push(id); return { ...item, id, projectId }; }); From 85e8c88041df796d63dcd81a7aa877fb0585418d Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Thu, 18 Jul 2024 17:32:34 +0530 Subject: [PATCH 17/17] [CMG-247], [CMG-256] --- .../Common/SaveChangesModal/index.tsx | 41 +++++++ ui/src/components/ContentMapper/index.tsx | 100 ++++++------------ 2 files changed, 76 insertions(+), 65 deletions(-) create mode 100644 ui/src/components/Common/SaveChangesModal/index.tsx diff --git a/ui/src/components/Common/SaveChangesModal/index.tsx b/ui/src/components/Common/SaveChangesModal/index.tsx new file mode 100644 index 000000000..1086c4b6e --- /dev/null +++ b/ui/src/components/Common/SaveChangesModal/index.tsx @@ -0,0 +1,41 @@ + +import { + ModalBody, + ModalHeader, + ModalFooter, + ButtonGroup, + Button, + Paragraph +} from '@contentstack/venus-components'; + +interface Props { + closeModal: () => void; + isopen: any; + otherCmsTitle?: string; + saveContentType: () => void; + openContentType: () => void; +} + +const SaveChangesModal = (props:Props) => { + return( + <> + {props?.closeModal(),props.isopen(false)}} className="text-capitalize" /> + +
+ +
+
+ + + + + + + + ) + +} + +export default SaveChangesModal; \ No newline at end of file diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 0bc73b380..291427249 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -49,7 +49,6 @@ import { UidMap, ContentTypeMap, Advanced, - SavedContentType } from './contentMapper.interface'; import { ItemStatusMapProp } from '@contentstack/venus-components/build/components/Table/types'; import { ModalObj } from '../Modal/modal.interface'; @@ -435,50 +434,18 @@ const ContentMapper = ({projectData}:ContentMapperComponentProps) => { const [isModalOpen, setIsModalOpen] = useState(false); - - const [currentCt, setCurrentCt] = useState(contentTypes[0]?.otherCmsTitle); - const [savedContentType, setSavedContentType] = useState({'col1': true, 'col2': false}); - console.log("savedContentType", savedContentType); - - - // Method to change the content type - const openContentType = (i: number) => { - // console.log("savedContentType[i - 1]", i, savedContentType[i - 1]); - - if (i > -1 && 1 < filteredContentTypes?.length) { - - // filteredContentTypes?.forEach((ct: ContentType) => { - // ct.otherCmsTitle = true - // }) - - - // setCurrentCt(otherTitle); - const updatedCT = {} - // updatedCT.contentTypes.[i].otherCmsTitle = true - // contentTypes.[i].otherCmsTitle = true - setSavedContentType(updatedCT) - - - - - - // console.log("isContentTypeSaved", savedContentType[i - 1]?.otherCmsTitle, savedContentType[i]?.otherCmsTitle); - - // savedCTArray.push({contentTypes?.[i]?.otherCmsTitle : true}); - } - - // console.log("savedCTArray", contentTypes?.[i]?.otherCmsTitle, i); + const handleOpenContentType = (i: number) => { if (isDropDownChanged) { - console.log("otherCmsTitle", otherCmsTitle); - setIsModalOpen(true); return cbModal({ component: (props: ModalObj) => ( openContentType(i)} /> ), modalProps: { @@ -487,19 +454,23 @@ const ContentMapper = ({projectData}:ContentMapperComponentProps) => { } }); } else { - setActive(i); - const otherTitle = contentTypes?.[i]?.otherCmsTitle; - setOtherCmsTitle(otherTitle); - const option = contentTypeMapped?.[otherTitle] ?? 'Select Content Type'; - setOtherContentType({ label: option, value: option }); - - setContentTypeUid(contentTypes?.[i]?.id ?? ''); - fetchFields(contentTypes?.[i]?.id ?? '', searchText || ''); - setotherCmsUid(contentTypes?.[i]?.otherCmsUid); - setSelectedContentType(contentTypes?.[i]); + openContentType(i); } }; + const openContentType = (i: number) => { + setActive(i); + const otherTitle = contentTypes?.[i]?.otherCmsTitle; + setOtherCmsTitle(otherTitle); + const option = contentTypeMapped?.[otherTitle] ?? 'Select Content Type'; + setOtherContentType({ label: option, value: option }); + + setContentTypeUid(contentTypes?.[i]?.id ?? ''); + fetchFields(contentTypes?.[i]?.id ?? '', searchText || ''); + setotherCmsUid(contentTypes?.[i]?.otherCmsUid); + setSelectedContentType(contentTypes?.[i]); + } + // Function to get exisiting content types list const fetchExistingContentTypes = async () => { const { data, status } = await getExistingContentTypes(projectId); @@ -585,8 +556,6 @@ const ContentMapper = ({projectData}:ContentMapperComponentProps) => { // Method for change select value const handleValueChange = (value: FieldTypes, rowIndex: string) => { - console.log("setisDropDownCHanged", value, rowIndex); - setisDropDownCHanged(true); setFieldValue(value); const updatedRows = tableData?.map((row) => { @@ -622,15 +591,15 @@ const ContentMapper = ({projectData}:ContentMapperComponentProps) => { } }); }; + const SelectAccessor = (data: FieldMapType) => { - //const OptionsForRow = Fields[data?.backupFieldType as keyof Mapping]; const OptionsForRow = dummy_obj?.[data?.backupFieldType]?.options ; const initialOption = { label: dummy_obj?.[data?.ContentstackFieldType]?.label, value: dummy_obj?.[data?.ContentstackFieldType]?.label, }; - let option:any; + let option: FieldTypes[]; if (Array.isArray(OptionsForRow)) { option = OptionsForRow.map((option) => ({ label: option, @@ -641,12 +610,18 @@ const ContentMapper = ({projectData}:ContentMapperComponentProps) => { label, value, })); - }else{ + + if (option?.length === 1 && option?.[0]?.label === initialOption?.label) { + option = [{ label: "No option available", value: "No option available" }]; + } + + } else { option = [{ label: OptionsForRow, value: OptionsForRow }] } - const fieldLabel = data?.ContentstackFieldType === 'url' || data?.ContentstackFieldType === 'group' - ? data?.ContentstackFieldType : option?.[0]?.label + const fieldLabel = data?.ContentstackFieldType === 'url' || data?.ContentstackFieldType === 'group' + ? data?.ContentstackFieldType : option?.[0]?.label + return (
@@ -947,7 +922,7 @@ const ContentMapper = ({projectData}:ContentMapperComponentProps) => { notificationContent: { text: 'Content type saved successfully' }, notificationProps: { position: 'bottom-center', - hideProgressBar: false + hideProgressBar: true }, type: 'success' }); @@ -955,11 +930,6 @@ const ContentMapper = ({projectData}:ContentMapperComponentProps) => { setisContentTypeMapped(true); setisContentTypeSaved(true); - // const savedCTArray: SavedContentType = {} - // data.updatedContentType.otherCmsTitle = true - // // savedCTArray = data?.updatedContentType; - // setSavedContentType(data?.updatedContentType?.otherCmsTitle) - setFilteredContentTypes(filteredContentTypes?.map(ct => ct?.id === data?.updatedContentType?.id ? { ...ct, status: data?.updatedContentType?.status } : ct )) @@ -968,7 +938,7 @@ const ContentMapper = ({projectData}:ContentMapperComponentProps) => { notificationContent: { text: data?.error?.message }, notificationProps: { position: 'bottom-center', - hideProgressBar: false + hideProgressBar: true }, type: 'error' }); @@ -1181,8 +1151,8 @@ const ContentMapper = ({projectData}:ContentMapperComponentProps) => {
  • openContentType(index)} - onKeyDown={() => openContentType(index)} + onClick={() => handleOpenContentType(index)} + onKeyDown={() => handleOpenContentType(index)} >