diff --git a/api/src/config/dev.config.ts b/api/src/config/dev.config.ts index 86cf81918..cdd2363dc 100644 --- a/api/src/config/dev.config.ts +++ b/api/src/config/dev.config.ts @@ -10,4 +10,6 @@ export const devConfig = { AZURE_NA: "https://azure-na-app.contentstack.com/#!", AZURE_EU: "https://azure-eu-app.contentstack.com/#!", }, + LOG_FILE_PATH: + process.platform === "win32" ? ".\\combine.log" : "./combine.log", // Replace with the actual path to your log file }; diff --git a/api/src/config/index.ts b/api/src/config/index.ts index 4f1523603..f714b3806 100644 --- a/api/src/config/index.ts +++ b/api/src/config/index.ts @@ -7,6 +7,9 @@ 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; @@ -14,6 +17,7 @@ export type ConfigType = { PORT: string; APP_ENV: string; MONGODB_URI: string; + LOG_FILE_PATH: string; CS_API: { NA: string; EU: string; @@ -28,12 +32,35 @@ export type ConfigType = { }; }; +/** + * Loads the configuration from environment variables and returns the configuration object. + * @returns The configuration object. + */ export const config: ConfigType = { + /** + * Expiration time for the application token. + */ APP_TOKEN_EXP: "1d", - PORT: process.env.PORT!, - APP_ENV: process.env.NODE_ENV!, + /** + * Key used to sign the application token. + */ APP_TOKEN_KEY: process.env.APP_TOKEN_KEY!, + /** + * Key used for file uploads. + */ FILE_UPLOAD_KEY: process.env.FILE_UPLOAD_KEY!, + /** + * Port on which the server will listen. + */ + PORT: process.env.PORT!, + /** + * Environment in which the application is running. + */ + APP_ENV: process.env.NODE_ENV!, + /** + * MongoDB connection URI. + */ MONGODB_URI: process.env.MONGODB_URI!, + ...(process.env.NODE_ENV === "production" ? prodConfig : devConfig), }; diff --git a/api/src/config/prod.config.ts b/api/src/config/prod.config.ts index 2a124479d..7a49fdbd9 100644 --- a/api/src/config/prod.config.ts +++ b/api/src/config/prod.config.ts @@ -11,4 +11,6 @@ export const prodConfig = { AZURE_NA: "https://azure-na-app.contentstack.com/#!", AZURE_EU: "https://azure-eu-app.contentstack.com/#!", }, + LOG_FILE_PATH: + process.platform === "win32" ? ".\\combine.log" : "./combine.log", // Replace with the actual path to your log file }; diff --git a/api/src/controllers/auth.controller.ts b/api/src/controllers/auth.controller.ts index 55e092e11..8c72d70c3 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..d779bf442 100644 --- a/api/src/controllers/migration.controller.ts +++ b/api/src/controllers/migration.controller.ts @@ -1,11 +1,23 @@ import { Request, Response } from "express"; import { migrationService } from "../services/migration.service.js"; +/** + * Creates a test stack. + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves when the operation is complete. + */ const createTestStack = async (req: Request, res: Response): Promise => { const resp = await migrationService.createTestStack(req); res.status(200).json(resp); }; +/** + * Deletes a test stack. + * @param {Request} req - The request object. + * @param {Response} res - The response object. + * @returns {Promise} - A promise that resolves when the operation is complete. + */ 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..c07b3773d 100644 --- a/api/src/controllers/org.controller.ts +++ b/api/src/controllers/org.controller.ts @@ -1,21 +1,41 @@ import { Request, Response } from "express"; import { orgService } from "../services/org.service.js"; +/** + * Get all stacks + * @param req - Express request object + * @param res - Express response object + */ const getAllStacks = async (req: Request, res: Response) => { const resp = await orgService.getAllStacks(req); res.status(resp?.status).json(resp?.data); }; +/** + * Create a new stack + * @param req - Express request object + * @param res - Express response object + */ const createStack = async (req: Request, res: Response) => { const resp = await orgService.createStack(req); res.status(resp.status).json(resp.data); }; +/** + * Get all locales + * @param req - Express request object + * @param res - Express response object + */ const getLocales = async (req: Request, res: Response) => { const resp = await orgService.getLocales(req); res.status(resp.status).json(resp.data); }; +/** + * Get stack status + * @param req - Express request object + * @param res - Express response object + */ 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 6a22299c4..9ed85f852 100644 --- a/api/src/controllers/projects.contentMapper.controller.ts +++ b/api/src/controllers/projects.contentMapper.controller.ts @@ -1,18 +1,45 @@ import { Request, Response } from "express"; import { contentMapperService } from "../services/contentMapper.service.js"; + +/** + * Puts test data. + * @param req - The request object. + * @param res - The response object. + * @returns Promise + */ const putTestData = async (req: Request, res: Response): Promise => { const resp = await contentMapperService.putTestData(req); res.status(200).json(resp); }; +/** + * Gets content types. + * @param req - The request object. + * @param res - The response object. + * @returns Promise + */ const getContentTypes = async (req: Request, res: Response): Promise => { const resp = await contentMapperService.getContentTypes(req); res.status(200).json(resp); }; + +/** + * Gets field mapping. + * @param req - The request object. + * @param res - The response object. + * @returns Promise + */ const getFieldMapping = async (req: Request, res: Response): Promise => { const resp = await contentMapperService.getFieldMapping(req); res.status(200).json(resp); }; + +/** + * Gets existing content types. + * @param req - The request object. + * @param res - The response object. + * @returns Promise + */ const getExistingContentTypes = async ( req: Request, res: Response @@ -20,6 +47,13 @@ const getExistingContentTypes = async ( const resp = await contentMapperService.getExistingContentTypes(req); res.status(201).json(resp); }; + +/** + * Puts content type fields. + * @param req - The request object. + * @param res - The response object. + * @returns Promise + */ const putContentTypeFields = async ( req: Request, res: Response @@ -27,21 +61,38 @@ const putContentTypeFields = async ( const resp = await contentMapperService.updateContentType(req); res.status(200).json(resp); }; + +/** + * Resets content type. + * @param req - The request object. + * @param res - The response object. + * @returns Promise + */ const resetContentType = async (req: Request, res: Response): Promise => { const resp = await contentMapperService.resetToInitialMapping(req); res.status(200).json(resp); }; -// TODO Will remove if not required -// const removeMapping = async (req: Request, res: Response): Promise => { -// const resp = await contentMapperService.removeMapping(req); -// res.status(200).json(resp); -// }; -const removeContentMapper = async (req: Request, res: Response): Promise => { +/** + * Removes content mapper. + * @param req - The request object. + * @param res - The response object. + * @returns Promise + */ +const removeContentMapper = async ( + req: Request, + res: Response +): Promise => { const resp = await contentMapperService.removeContentMapper(req); res.status(200).json(resp); -} +}; +/** + * Gets single content types. + * @param req - The request object. + * @param res - The response object. + * @returns Promise + */ const getSingleContentTypes = async ( req: Request, res: Response @@ -50,6 +101,17 @@ const getSingleContentTypes = async ( res.status(201).json(resp); }; +/** + * Removes mapping. + * @param req - The request object. + * @param res - The response object. + * @returns Promise + */ +// const removeMapping = async (req: Request, res: Response): Promise => { +// const resp = await contentMapperService.removeMapping(req); +// res.status(200).json(resp); +// }; + export const contentMapperController = { getContentTypes, getFieldMapping, @@ -59,5 +121,5 @@ export const contentMapperController = { resetContentType, // removeMapping, getSingleContentTypes, - removeContentMapper + removeContentMapper, }; diff --git a/api/src/controllers/projects.controller.ts b/api/src/controllers/projects.controller.ts index dbe1abb97..684ae5a3e 100644 --- a/api/src/controllers/projects.controller.ts +++ b/api/src/controllers/projects.controller.ts @@ -1,64 +1,157 @@ 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. + * + * @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 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 a legacy CMS. + * + * @param req - The request object. + * @param res - The response object. + * @returns A promise that resolves to void. + */ const updateLegacyCMS = async (req: Request, res: Response) => { const resp = await projectService.updateLegacyCMS(req); res.status(resp.status).json(resp.data); }; +/** + * Updates an affix. + * + * @param req - The request object. + * @param res - The response object. + * @returns A promise that resolves to void. + */ const updateAffix = async (req: Request, res: Response) => { const resp = await projectService.updateAffix(req); res.status(resp.status).json(resp.data); }; +/** + * Affix confirmation. + * + * @param req - The request object. + * @param res - The response object. + * @returns A promise that resolves to void. + */ const affixConfirmation = async (req: Request, res: Response) => { const resp = await projectService.affixConfirmation(req); res.status(resp.status).json(resp.data); }; +/** + * Updates a file format. + * + * @param req - The request object. + * @param res - The response object. + * @returns A promise that resolves to void. + */ const updateFileFormat = async (req: Request, res: Response) => { const resp = await projectService.updateFileFormat(req); res.status(resp.status).json(resp.data); }; +/** + * File format confirmation. + * + * @param req - The request object. + * @param res - The response object. + * @returns A promise that resolves to void. + */ const fileformatConfirmation = async (req: Request, res: Response) => { const resp = await projectService.fileformatConfirmation(req); res.status(resp.status).json(resp.data); }; +/** + * Updates a destination stack. + * + * @param req - The request object. + * @param res - The response object. + * @returns A promise that resolves to void. + */ 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 req - The request object. + * @param res - The response object. + * @returns A promise that resolves to void. + */ 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..9c3f1d651 100644 --- a/api/src/controllers/user.controller.ts +++ b/api/src/controllers/user.controller.ts @@ -1,6 +1,12 @@ import { Request, Response } from "express"; import { userService } from "../services/user.service.js"; +/** + * Retrieves the user profile. + * + * @param req - The request object. + * @param res - The response object. + */ 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/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/middlewares/auth.middleware.ts b/api/src/middlewares/auth.middleware.ts index 17987a3eb..94cc63d5b 100644 --- a/api/src/middlewares/auth.middleware.ts +++ b/api/src/middlewares/auth.middleware.ts @@ -4,6 +4,12 @@ import jwt from "jsonwebtoken"; import { config } from "../config/index.js"; import { HTTP_CODES } from "../constants/index.js"; +/** + * Authenticates the user. + * @param req - Express request object. + * @param res - Express response object. + * @param next - Express next function. + */ export const authenticateUser = ( req: Request, res: Response, diff --git a/api/src/middlewares/auth.uploadService.middleware.ts b/api/src/middlewares/auth.uploadService.middleware.ts index c23458493..8af2c00dd 100644 --- a/api/src/middlewares/auth.uploadService.middleware.ts +++ b/api/src/middlewares/auth.uploadService.middleware.ts @@ -2,6 +2,12 @@ import { Request, Response, NextFunction } from "express"; import { HTTP_CODES } from "../constants/index.js"; import { config } from "../config/index.js"; +/** + * Authenticates the upload service. + * @param req - Express request object. + * @param res - Express response object. + * @param next - Express next function. + */ 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..5cf7b23e7 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"; +/** + * Error middleware + * @param err - Error object + * @param req - Express request object + * @param res - Express response object + * @param next - Express next 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..a7a34af1b 100644 --- a/api/src/middlewares/logger.middleware.ts +++ b/api/src/middlewares/logger.middleware.ts @@ -1,7 +1,9 @@ import expressWinston from "express-winston"; import logger from "../utils/logger.js"; -//Logger Middleware to log every request +/** + * Logger middleware to log all incoming requests. + */ 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..aa1f425ea 100644 --- a/api/src/middlewares/req-headers.middleware.ts +++ b/api/src/middlewares/req-headers.middleware.ts @@ -1,5 +1,12 @@ import { Request, Response, NextFunction } from "express"; +/** + * Middleware to set the request headers. + * + * @param req The request object. + * @param res The response object. + * @param next The next 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..79a67de3e 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"; +/** + * Handles the unmatched routes. + * + * @param req The request object. + * @param res The 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..e31820ac5 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 field mapper. + */ 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..ac0388312 100644 --- a/api/src/models/authentication.ts +++ b/api/src/models/authentication.ts @@ -1,6 +1,11 @@ // src/models/Authentication.ts + import { JSONFile } from "lowdb/node"; import LowWithLodash from "../utils/lowdb-lodash.utils.js"; + +/** + * Represents the structure of the authentication document. + */ interface AuthenticationDocument { users: { user_id: string; @@ -11,8 +16,14 @@ interface AuthenticationDocument { }[]; } +/** + * Represents the default data for the authentication document. + */ const defaultData: AuthenticationDocument = { users: [] }; +/** + * Represents the database instance for the authentication document. + */ 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 77c3897a9..ee56688e5 100644 --- a/api/src/models/contentTypesMapper-lowdb.ts +++ b/api/src/models/contentTypesMapper-lowdb.ts @@ -1,6 +1,9 @@ import { JSONFile } from "lowdb/node"; import LowWithLodash from "../utils/lowdb-lodash.utils.js"; +/** + * Represents a content type mapper. + */ export interface ContentTypesMapper { id: string; otherCmsTitle: string; @@ -19,12 +22,21 @@ export interface ContentTypesMapper { // contentTypes: [contentTypes]; // } +/** + * Represents a content type mapper document. + */ interface ContentTypeMapperDocument { ContentTypesMappers: ContentTypesMapper[]; } +/** + * Default data for the ContentTypeMapperDocument. + */ 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 233e7f5d9..a6b8b5eaf 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 ExecutionLog object. + */ interface ExecutionLog { log_url: string; date: Date; } +/** + * Represents a Project object. + */ interface Project { id: string; region: string; @@ -52,12 +61,21 @@ interface Project { isDeleted: boolean; } +/** + * Represents a Project Document. + */ interface ProjectDocument { projects: Project[]; } +/** + * Represents the default data for the project document. + */ const defaultData: ProjectDocument = { projects: [] }; +/** + * Represents the database instance for the project document. + */ 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..6febaaf90 100644 --- a/api/src/models/types.ts +++ b/api/src/models/types.ts @@ -1,21 +1,33 @@ +/** + * Represents a user. + */ export interface User { - email: string; - password: string; + email: string; // The email of the user. + password: string; // The password of the user. } +/** + * Represents the payload of an app token. + */ export interface AppTokenPayload { - region: string; - user_id: string; + region: string; // The region of the app token. + user_id: string; // The user ID associated with the app token. } +/** + * Represents the response from a login service. + */ export interface LoginServiceType { - data: any; - status: number; + data: any; // The data returned by the login service. + status: number; // The status code of the response. } +/** + * Represents a migration query. + */ export interface MigrationQueryType { - id: string; - org_id: string; - region: string; - owner: string; + id: string; // The ID of the migration query. + org_id: string; // The organization ID associated with the migration query. + region: string; // The region of the migration query. + owner: string; // The owner of the migration query. } diff --git a/api/src/routes/auth.routes.ts b/api/src/routes/auth.routes.ts index 29608bca9..9b080a42e 100644 --- a/api/src/routes/auth.routes.ts +++ b/api/src/routes/auth.routes.ts @@ -3,9 +3,12 @@ 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 +// User session route router.post( "/user-session", validator("auth"), diff --git a/api/src/routes/contentMapper.routes.ts b/api/src/routes/contentMapper.routes.ts index a92401e68..b3c98f8a7 100644 --- a/api/src/routes/contentMapper.routes.ts +++ b/api/src/routes/contentMapper.routes.ts @@ -15,32 +15,37 @@ router.get( "/contentTypes/:projectId/:skip/:limit/:searchText?", asyncRouter(contentMapperController.getContentTypes) ); + //Get FieldMapping List router.get( "/fieldMapping/:contentTypeId/:skip/:limit/:searchText?", asyncRouter(contentMapperController.getFieldMapping) ); -//Get Existing ContentTypes List +//Get Existing ContentTypes List router.get( "/:projectId", asyncRouter(contentMapperController.getExistingContentTypes) ); + //Update FieldMapping or contentType router.put( "/contentTypes/:orgId/:projectId/:contentTypeId", asyncRouter(contentMapperController.putContentTypeFields) ); + //Reset FieldMapping or contentType router.put( "/resetFields/:orgId/:projectId/:contentTypeId", asyncRouter(contentMapperController.resetContentType) ); + //get Single contenttype data router.get( "/:projectId/:contentTypeUid", asyncRouter(contentMapperController.getSingleContentTypes) ); + //remove content mapper router.get( "/:orgId/:projectId/content-mapper", 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..340240a85 100644 --- a/api/src/routes/org.routes.ts +++ b/api/src/routes/org.routes.ts @@ -5,20 +5,39 @@ import validator from "../validators/index.js"; const router = express.Router({ mergeParams: true }); -// GET all org stacks route +/** + * GET all org stacks route + * @route GET /stacks/:searchText? + * @param {string} searchText - Optional search text + * @returns {Promise} + */ router.get("/stacks/:searchText?", asyncRouter(orgController.getAllStacks)); -// Create a new stack route +/** + * Create a new stack route + * @route POST /stacks + * @param {object} project - The project data + * @returns {Promise} + */ router.post( "/stacks", validator("project"), asyncRouter(orgController.createStack) ); -// GET all contentstack locales route +/** + * GET all contentstack locales route + * @route GET /locales + * @returns {Promise} + */ router.get("/locales", asyncRouter(orgController.getLocales)); -// GET Content_types count +/** + * GET Content_types count + * @route POST /stack_status + * @param {object} destination_stack - The destination stack data + * @returns {Promise} + */ 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..2846d496b 100644 --- a/api/src/routes/projects.routes.ts +++ b/api/src/routes/projects.routes.ts @@ -5,70 +5,120 @@ import validator from "../validators/index.js"; const router = express.Router({ mergeParams: true }); -// GET all projects route +/** + * GET all projects route + * @route GET /projects + */ router.get("/", asyncRouter(projectController.getAllProjects)); -// GET a single project route +/** + * GET a single project route + * @route GET /projects/:projectId + * @param {string} projectId - The ID of the project + */ router.get("/:projectId", asyncRouter(projectController.getProject)); -// Create a new project route +/** + * Create a new project route + * @route POST /projects + */ router.post("/", asyncRouter(projectController.createProject)); -// Update a project route +/** + * Update a project route + * @route PUT /projects/:projectId + * @param {string} projectId - The ID of the project + */ router.put("/:projectId", asyncRouter(projectController.updateProject)); -// Update project's legacy-cms +/** + * Update project's legacy-cms + * @route PUT /projects/:projectId/legacy-cms + * @param {string} projectId - The ID of the project + */ router.put( "/:projectId/legacy-cms", validator("cms"), asyncRouter(projectController.updateLegacyCMS) ); -// Update project's Affix +/** + * Update project's Affix + * @route PUT /projects/:projectId/affix + * @param {string} projectId - The ID of the project + */ router.put( "/:projectId/affix", validator("affix"), asyncRouter(projectController.updateAffix) ); -// Update project's Affix confirmation +/** + * Update project's Affix confirmation + * @route PUT /projects/:projectId/affix_confirmation + * @param {string} projectId - The ID of the project + */ router.put( "/:projectId/affix_confirmation", validator("affix_confirmation_validator"), asyncRouter(projectController.affixConfirmation) ); -// Update project's file format +/** + * Update project's file format + * @route PUT /projects/:projectId/file-format + * @param {string} projectId - The ID of the project + */ router.put( "/:projectId/file-format", validator("file_format"), asyncRouter(projectController.updateFileFormat) ); -// Update project's fileformat confirmation +/** + * Update project's fileformat confirmation + * @route PUT /projects/:projectId/fileformat_confirmation + * @param {string} projectId - The ID of the project + */ router.put( "/:projectId/fileformat_confirmation", validator("fileformat_confirmation_validator"), asyncRouter(projectController.fileformatConfirmation) ); -// Update project's destination-cms +/** + * Update project's destination-cms + * @route PUT /projects/:projectId/destination-stack + * @param {string} projectId - The ID of the project + */ router.put( "/:projectId/destination-stack", validator("destination_stack"), asyncRouter(projectController.updateDestinationStack) ); -// Update project's current step +/** + * Update project's current step + * @route PUT /projects/:projectId/current-step + * @param {string} projectId - The ID of the project + */ router.put( "/:projectId/current-step", asyncRouter(projectController.updateCurrentStep) ); -// Delete a project route +/** + * Delete a project route + * @route DELETE /projects/:projectId + * @param {string} projectId - The ID of the project + */ router.delete("/:projectId", asyncRouter(projectController.deleteProject)); -//revert Project Route +/** + * Revert Project Route + * @route PATCH /projects/:projectId + * @param {string} projectId - The ID of the project + */ router.patch("/:projectId", asyncRouter(projectController.revertProject)); export default router; diff --git a/api/src/routes/user.routes.ts b/api/src/routes/user.routes.ts index 6e4e0bd48..bc1659c6c 100644 --- a/api/src/routes/user.routes.ts +++ b/api/src/routes/user.routes.ts @@ -4,7 +4,12 @@ import { asyncRouter } from "../utils/async-router.utils.js"; const router = express.Router(); -// Profile route +/** + * Route for getting user profile. + * @route GET /profile + * @group User + * @returns {Promise} - A promise that resolves when the user profile is retrieved. + */ router.get("/profile", asyncRouter(userController.getUserProfile)); export default router; diff --git a/api/src/server.ts b/api/src/server.ts index 678121afd..fbaf4cb60 100644 --- a/api/src/server.ts +++ b/api/src/server.ts @@ -20,6 +20,7 @@ import chokidar from "chokidar"; import { Server } from "socket.io"; import http from "http"; import fs from "fs"; + try { const app = express(); app.use( @@ -55,9 +56,17 @@ try { logger.info(`Server listening at port ${config.PORT}`) ); // Chokidar - Watch for log file changes - const logFilePath = "/Users/sayali.joshi/Projects/migration-v2-node-server/api/combine.log"; // Replace with the actual path to your log file + const logFilePath = config.LOG_FILE_PATH; const watcher = chokidar.watch(logFilePath); // Socket.IO - Send logs to client + /** + * The Socket.IO server instance. + * + * @remarks + * This server instance is responsible for handling real-time communication between the client and the server using the Socket.IO library. + * + * @type {Server} + */ const io = new Server( server, (http, diff --git a/api/src/services/auth.service.ts b/api/src/services/auth.service.ts index 5e911d18b..c46900d0a 100644 --- a/api/src/services/auth.service.ts +++ b/api/src/services/auth.service.ts @@ -13,12 +13,26 @@ import { import AuthenticationModel from "../models/authentication.js"; import logger from "../utils/logger.js"; +/** + * Logs in a user with the provided credentials. + * + * @param req - The request object containing user data. + * @returns A promise that resolves to the login service response. + * @throws ExceptionFunction if an error occurs during the login process. + */ const login = async (req: Request): Promise => { const srcFun = "Login"; try { const userData = req?.body; + /** + * Authenticates the user by making a POST request to the user-session endpoint. + * Includes the user's organizations and roles in the response. + * + * @param userData - The user data object containing email, password, and optional tfa_token. + * @returns A Promise that resolves to an array containing an error object and the response object. + */ const [err, res] = await safePromise( https({ method: "POST", @@ -115,6 +129,13 @@ const login = async (req: Request): Promise => { } }; +/** + * Requests an SMS token for the user. + * + * @param req - The request object containing user data. + * @returns A promise that resolves to the login service response. + * @throws InternalServerError if an error occurs during the requestSms process. + */ const requestSms = async (req: Request): Promise => { const srcFun = "requestSms"; diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index bd2151a07..e5731e9ce 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -23,10 +23,15 @@ import { v4 as uuidv4 } from "uuid"; 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; + const contentTypes = req.body.contentTypes; await FieldMapperModel.read(); contentTypes.map((type: any, index: any) => { @@ -45,7 +50,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 }; }); @@ -72,6 +77,12 @@ const putTestData = async (req: Request) => { return pData; }; +/** + * Retrieves the content types for a given project. + * + * @param req - The request object containing the project ID. + * @returns The content types for the project. + */ const getContentTypes = async (req: Request) => { const sourceFn = "getContentTypes"; const projectId = req?.params?.projectId; @@ -134,6 +145,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. + * @returns The field mapping for the content type. + */ const getFieldMapping = async (req: Request) => { const srcFunc = "getFieldMapping"; const contentTypeId = req?.params?.contentTypeId; @@ -187,6 +204,12 @@ const getFieldMapping = async (req: Request) => { return { count: totalCount, fieldMapping: result }; }; +/** + * Retrieves the existing content types for a given project. + * + * @param req - The request object containing the project ID. + * @returns The existing content types for the project. + */ const getExistingContentTypes = async (req: Request) => { const projectId = req?.params?.projectId; @@ -232,6 +255,13 @@ const getExistingContentTypes = async (req: Request) => { //Add logic to get Project from DB return { contentTypes }; }; + +/** + * Updates the content type for a given project. + * + * @param req - The request object containing the project ID and content type data. + * @returns The updated content type data. + */ const updateContentType = async (req: Request) => { const srcFun = "udateContentType"; const { orgId, projectId, contentTypeId } = req.params; @@ -384,6 +414,13 @@ const updateContentType = async (req: Request) => { ); } }; + +/** + * Resets the field mapping to the initial mapping for a given content type. + * + * @param req - The request object containing the project ID, content type ID, and user token. + * @returns The message indicating the reset of the field mapping. + */ const resetToInitialMapping = async (req: Request) => { const srcFunc = "resetToInitialMapping"; const { orgId, projectId, contentTypeId } = req.params; @@ -492,6 +529,13 @@ const resetToInitialMapping = async (req: Request) => { ); } }; + +/** + * Resets all the content types mapping for a given project. + * + * @param projectId - The project ID. + * @returns The project details. + */ const resetAllContentTypesMapping = async (projectId: string) => { const srcFunc = "resetAllContentTypesMapping"; @@ -532,7 +576,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 +613,8 @@ const resetAllContentTypesMapping = async (projectId: string) => { }); } } - } - return projectDetails; } catch (error: any) { logger.error( @@ -589,6 +631,13 @@ const resetAllContentTypesMapping = async (projectId: string) => { ); } }; + +/** + * Removes the content mapping for a given project. + * + * @param projectId - The project ID. + * @returns The project details. + */ const removeMapping = async (projectId: string) => { const srcFunc = "removeMapping"; await ProjectModelLowdb.read(); @@ -675,6 +724,13 @@ const removeMapping = async (projectId: string) => { ); } }; + +/** + * Retrieves the content type for a given project. + * + * @param req - The request object containing the project ID and content type UID. + * @returns The content type data. + */ const getSingleContentTypes = async (req: Request) => { const projectId = req?.params?.projectId; const contentTypeUID = req?.params?.contentTypeUid; @@ -716,6 +772,13 @@ const getSingleContentTypes = async (req: Request) => { schema: res?.data?.content_type?.schema, }; }; + +/** + * Removes the content mapping for a given project. + * + * @param req - The request object containing the project ID. + * @returns The project details. + */ const removeContentMapper = async (req: Request) => { const projectId = req?.params?.projectId; const srcFunc = "removeMapping"; @@ -735,13 +798,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/migration.service.ts b/api/src/services/migration.service.ts index 9c74fbf25..bbccaa127 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 new test stack. + * + * @param req - The request object containing the project data. + * @returns A promise that resolves to the login service response. + * @throws ExceptionFunction if an error occurs during the stack creation process. + */ const createTestStack = async (req: Request): Promise => { const srcFun = "createTestStack"; const orgId = req?.params?.orgId; @@ -99,6 +106,13 @@ const createTestStack = async (req: Request): Promise => { } }; +/** + * Deletes a test stack. + * + * @param req - The request object containing the project data. + * @returns A promise that resolves to the login service response. + * @throws ExceptionFunction if an error occurs during the stack deletion process. + */ 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..d43294387 100644 --- a/api/src/services/org.service.ts +++ b/api/src/services/org.service.ts @@ -9,6 +9,13 @@ 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"; +/** + * Gets all stacks of an organization. + * + * @param req - The request object containing the organization ID. + * @returns A promise that resolves to the login service response. + * @throws ExceptionFunction if an error occurs during the stack retrieval process. + */ const getAllStacks = async (req: Request): Promise => { const srcFun = "getAllStacks"; const orgId = req?.params?.orgId; @@ -82,6 +89,13 @@ const getAllStacks = async (req: Request): Promise => { } }; +/** + * Creates a new stack. + * + * @param req - The request object containing the organization ID, stack name, description, and master locale. + * @returns A promise that resolves to the login service response. + * @throws ExceptionFunction if an error occurs during the stack creation process. + */ const createStack = async (req: Request): Promise => { const srcFun = "createStack"; const orgId = req?.params?.orgId; @@ -150,6 +164,13 @@ const createStack = async (req: Request): Promise => { } }; +/** + * Gets all locales. + * + * @param req - The request object containing the organization ID. + * @returns A promise that resolves to the login service response. + * @throws ExceptionFunction if an error occurs during the locale retrieval process. + */ const getLocales = async (req: Request): Promise => { const srcFun = "getLocales"; const { token_payload } = req.body; @@ -204,6 +225,13 @@ const getLocales = async (req: Request): Promise => { } }; +/** + * Gets the status of a stack. + * + * @param req - The request object containing the organization ID and stack API key. + * @returns A promise that resolves to the login service response. + * @throws ExceptionFunction if an error occurs during the stack status retrieval process. + */ const getStackStatus = async (req: Request) => { const { orgId } = req.params; const { token_payload, stack_api_key } = req.body; @@ -285,16 +313,23 @@ const getStackStatus = async (req: Request) => { ); } }; -//get all locals of particular stack + +/** + * Gets the locales of a stack. + * + * @param token_payload - The token payload containing the region and user ID. + * @param data - The stack data. + * @returns A promise that resolves to the stack locales. + */ 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 +357,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 +365,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 f6cb13bb8..37a81d035 100644 --- a/api/src/services/projects.service.ts +++ b/api/src/services/projects.service.ts @@ -20,15 +20,22 @@ 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; 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") @@ -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; @@ -143,6 +161,12 @@ const createProject = async (req: Request) => { } }; +/** + * Updates an existing project. + * @param req - The request object containing the orgId, projectId, and updateData. + * @returns An object with the status, message, and updated project details. + * @throws ExceptionFunction if there is an error updating the project. + */ const updateProject = async (req: Request) => { const orgId = req?.params?.orgId; const projectId = req?.params?.projectId; @@ -211,6 +235,12 @@ const updateProject = async (req: Request) => { } }; +/** + * Updates the legacy CMS details for a project. + * @param req - The request object containing the orgId, projectId, and legacy_cms. + * @returns An object with the status and message. + * @throws ExceptionFunction if there is an error updating the legacy CMS. + */ const updateLegacyCMS = async (req: Request) => { const { orgId, projectId } = req.params; const { token_payload, legacy_cms } = req.body; @@ -289,6 +319,12 @@ const updateLegacyCMS = async (req: Request) => { } }; +/** + * Updates the affix for a project. + * @param req - The request object containing the orgId, projectId, and affix. + * @returns An object with the status and message. + * @throws ExceptionFunction if there is an error updating the affix. + */ const updateAffix = async (req: Request) => { const srcFunc = "updateAffix"; const { orgId, projectId } = req.params; @@ -320,6 +356,12 @@ const updateAffix = async (req: Request) => { }; }; +/** + * Updates the affix confirmation for a project. + * @param req - The request object containing the orgId, projectId, and affix_confirmation. + * @returns An object with the status and message. + * @throws ExceptionFunction if there is an error updating the affix confirmation. + */ const affixConfirmation = async (req: Request) => { const srcFunc = "affixConfirmation"; const { orgId, projectId } = req.params; @@ -352,9 +394,22 @@ const affixConfirmation = async (req: Request) => { }; }; +/** + * Updates the file format for a project. + * @param req - The request object containing the orgId, projectId, and file_format. + * @returns An object with the status and message. + * @throws ExceptionFunction if there is an error updating the file format. + */ 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, @@ -441,6 +496,12 @@ const updateFileFormat = async (req: Request) => { } }; +/** + * Updates the file format confirmation for a project. + * @param req - The request object containing the orgId, projectId, and fileformat_confirmation. + * @returns An object with the status and message. + * @throws ExceptionFunction if there is an error updating the file format confirmation. + */ const fileformatConfirmation = async (req: Request) => { const srcFunc = "fileformat"; const { orgId, projectId } = req.params; @@ -473,6 +534,12 @@ const fileformatConfirmation = async (req: Request) => { }; }; +/** + * Updates the destination stack for a project. + * @param req - The request object containing the orgId, projectId, and stack_api_key. + * @returns An object with the status and message. + * @throws ExceptionFunction if there is an error updating the destination stack. + */ const updateDestinationStack = async (req: Request) => { const { orgId, projectId } = req.params; const { token_payload, stack_api_key } = req.body; @@ -584,6 +651,12 @@ const updateDestinationStack = async (req: Request) => { } }; +/** + * Updates the current step for a project. + * @param req - The request object containing the orgId and projectId. + * @returns The updated project. + * @throws ExceptionFunction if there is an error updating the current step. + */ const updateCurrentStep = async (req: Request) => { const { orgId, projectId } = req.params; const token_payload = req.body.token_payload; @@ -679,6 +752,12 @@ const updateCurrentStep = async (req: Request) => { } }; +/** + * Deletes a project. + * @param req - The request object containing the orgId and projectId. + * @returns An object with the status and message. + * @throws ExceptionFunction if there is an error deleting the project. + */ const deleteProject = async (req: Request) => { const { orgId, projectId } = req.params; const decodedToken = req.body.token_payload; @@ -764,6 +843,12 @@ const deleteProject = async (req: Request) => { }; }; +/** + * Reverts a project. + * @param req - The request object containing the orgId and projectId. + * @returns An object with the status, message, and project details. + * @throws NotFoundError if the project is not found. + */ const revertProject = async (req: Request) => { const { orgId, projectId } = req.params; const decodedToken = req.body.token_payload; @@ -806,6 +891,7 @@ const revertProject = async (req: Request) => { }; } }; + export const projectService = { getAllProjects, getProject, 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..921a45935 100644 --- a/api/src/utils/async-router.utils.ts +++ b/api/src/utils/async-router.utils.ts @@ -1,5 +1,11 @@ import { Request, Response, NextFunction } from "express"; +/** + * Wraps an asynchronous route handler function with error handling middleware. + * + * @param fn - The asynchronous route handler function. + * @returns A middleware function that handles asynchronous 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..b66b86104 100644 --- a/api/src/utils/custom-errors.utils.ts +++ b/api/src/utils/custom-errors.utils.ts @@ -1,5 +1,9 @@ import { HTTP_CODES, HTTP_TEXTS } from "../constants/index.js"; +/** + * Represents an application error. + * Extends the base AppError class. + */ export class AppError extends Error { constructor(public statusCode: number, message: string) { super(message); @@ -7,48 +11,80 @@ export class AppError extends Error { } } +/** + * Represents a custom error for a resource not found. + * Extends the base AppError class. + */ export class NotFoundError extends AppError { 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 { constructor(message: string = "Bad Request") { super(HTTP_CODES.BAD_REQUEST, message); } } +/** + * Represents a custom error for a database error. + * Extends the base AppError class. + */ export class DatabaseError extends AppError { constructor(message: string = "DB error") { super(HTTP_CODES.SERVER_ERROR, message); } } +/** + * Represents a custom error for a validation error. + * Extends the base AppError class. + */ export class ValidationError extends AppError { constructor(message: string = "User validation error") { super(HTTP_CODES.UNPROCESSABLE_CONTENT, message); } } +/** + * Represents a custom error for an internal server error. + * Extends the base AppError class + */ export class InternalServerError extends AppError { constructor(message: string = HTTP_TEXTS.INTERNAL_ERROR) { super(HTTP_CODES.SERVER_ERROR, message); } } +/** + * Represents a custom error for an unauthorized request. + * Extends the base AppError class + */ export class UnauthorizedError extends AppError { constructor(message: string = HTTP_TEXTS.UNAUTHORIZED) { super(HTTP_CODES.UNAUTHORIZED, message); } } +/** + * Represents a custom error for an S3 error. + * Extends the base AppError class + */ export class S3Error extends AppError { constructor(message: string = HTTP_TEXTS.S3_ERROR) { super(HTTP_CODES.SERVER_ERROR, message); } } +/** + * Represents a custom error for a function exception. + * Extends the base AppError class + */ export class ExceptionFunction extends AppError { 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..543b720fb 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 projectId 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 search by index (optional). + * @returns The project that matches the provided projectId and query. + * @throws BadRequestError if the projectId 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..1f12a5520 100644 --- a/api/src/utils/https.utils.ts +++ b/api/src/utils/https.utils.ts @@ -11,6 +11,13 @@ 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..9f5bee738 100644 --- a/api/src/utils/index.ts +++ b/api/src/utils/index.ts @@ -1,17 +1,40 @@ +/** + * 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. + * @param promise - The promise to wrap. + * @returns A new promise that resolves with an array containing the error (if any) and the result of the original promise. + */ export const safePromise = (promise: Promise): Promise => promise.then((res) => [null, res]).catch((err) => [err]); -//Generic method to get log message object +/** + * Creates a log message object. + * @param methodName - The name of the method. + * @param message - The log message. + * @param user - The user object (optional). + * @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..c903692cc 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 for logging messages. + * Logger for custom logs + */ 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"); } diff --git a/api/src/validators/affix-confirmation.validator.ts b/api/src/validators/affix-confirmation.validator.ts index 5bbea21a7..aea82e472 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 property in the request body. + * + * @returns {Object} The validation schema for affix_confirmation. + */ 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..53c3cf000 100644 --- a/api/src/validators/auth.validator.ts +++ b/api/src/validators/auth.validator.ts @@ -1,6 +1,11 @@ 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({ email: { in: "body", diff --git a/api/src/validators/cms.validator.ts b/api/src/validators/cms.validator.ts index 3b04f0625..b0ddc2d97 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' property in the request body. + * + * @returns {Object} The validation schema for the 'legacy_cms' property. + */ 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..d39dc64c6 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 'stack_api_key' property in the request body. + * + * @returns {Object} The validation schema for the 'stack_api_key' property. + */ 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..7ff351efc 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' property in the request body. + * + * @returns {Object} The validation schema for the 'file_format' property. + */ 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..1607f9081 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 'fileformat_confirmation' property in the request body. + * + * @returns {Object} The validation schema for the 'fileformat_confirmation' property. + */ export default checkSchema({ fileformat_confirmation: { in: "body", diff --git a/api/src/validators/index.ts b/api/src/validators/index.ts index 269e5893e..fdd4b3f89 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 async middleware function. + */ 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", diff --git a/ui/src/common/assets/icons.tsx b/ui/src/common/assets/icons.tsx index 179668e2e..e7a7b67e3 100644 --- a/ui/src/common/assets/icons.tsx +++ b/ui/src/common/assets/icons.tsx @@ -1,3 +1,6 @@ +/** + * This file contains the definition of the SVG icon component. + */ export const NO_PROJECTS_SEARCH = ( ); + export const NO_PROJECTS = ( { 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..dac129eb6 100644 --- a/ui/src/components/AdvancePropertise/advanceProperties.interface.ts +++ b/ui/src/components/AdvancePropertise/advanceProperties.interface.ts @@ -1,5 +1,8 @@ import { Advanced, FieldMapType } from '../ContentMapper/contentMapper.interface'; +/** + * Represents the schema properties. + */ export interface SchemaProps { fieldtype: string; value: UpdatedSettings; @@ -11,6 +14,9 @@ export interface SchemaProps { projectId?: string; } +/** + * Represents the updated settings. + */ export interface UpdatedSettings { MinChars?: string; MaxChars?: number; @@ -27,6 +33,9 @@ export interface UpdatedSettings { NonLocalizable?: boolean; } +/** + * Represents the props. + */ export interface Props { data: SchemaProps; states?: StateType; @@ -34,20 +43,82 @@ export interface Props { handleToggle?: (field: string, value: boolean, checkBoxChanged: boolean) => void; } +/** + * Represents the state type for advanced properties. + */ export interface StateType { + /** + * 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. + */ defaultValue?: string; + + /** + * The validation regular expression. + */ validationRegex?: string; + + /** + * The title. + */ title?: string; + + /** + * The URL. + */ url?: string; + + /** + * Indicates if the field is mandatory. + */ mandatory?: boolean; + + /** + * Indicates if only images are allowed. + */ allowImagesOnly?: boolean; + + /** + * Indicates if the field is non-localizable. + */ nonLocalizable?: boolean; + + /** + * Indicates if the object should be embedded. + */ embedObject?: boolean; + + /** + * Indicates if the assets should be embedded. + */ embedAssests?: boolean; } \ No newline at end of file diff --git a/ui/src/components/AdvancePropertise/index.scss b/ui/src/components/AdvancePropertise/index.scss index 212c06f8b..5fa6c7eff 100644 --- a/ui/src/components/AdvancePropertise/index.scss +++ b/ui/src/components/AdvancePropertise/index.scss @@ -1,3 +1,7 @@ +/** + * Styles for the AdvancePropertise component. + */ + @import '../../scss/variables'; .options-class { @@ -9,36 +13,46 @@ grid-template-columns: 1fr; gap: 20px; } + .option-label { margin-bottom: $px-10; } + .non-localizable-message { margin-top: 0; margin-left: 30px; } + .modal-data { padding: 0.75rem; + .radio-field { margin-bottom: 0.75rem; } + .Radio { width: calc(33.33333% - .66667rem); padding: .5rem; margin: 0 !important; } + .FieldLabel { margin-bottom: $px-8; } + .info-style { margin-top: .75rem; margin-bottom: 1.5rem; + .Info__border { border-left-color: #0469e3; } } + .options-class { line-height: $line-height-reset; } + .nl-note { color: $color-font-base; font-size: $size-font-large; @@ -46,17 +60,21 @@ margin-left: 2.75rem; margin-top: -.25rem !important; } + .ToggleWrap { margin-top: 0.5rem; - padding: 0 0.5rem + padding: 0 0.5rem; } + .Field { margin-bottom: $px-24; } + .fields-group-separator { color: $color-base-black-base; margin: 0 16px; } + .Select { .Select__menu { .Select__menu-list { @@ -65,20 +83,23 @@ align-items: center; display: flex; } + .Checkbox__label { height: auto; } - } + } } - } - } + } + } + .Select__menu { position: relative; z-index: 10000; } + .Select__control--menu-is-open { position: relative; border: 2px solid red; z-index: 10000; - } + } } 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..a186d11a3 100644 --- a/ui/src/components/Card/card.scss +++ b/ui/src/components/Card/card.scss @@ -1,5 +1,7 @@ @import '../../scss/variables'; - +/** + * Styles for the ProjectCard component. + */ .ProjectCard { background: $color-brand-white-base; border-radius: 0.6rem; @@ -7,14 +9,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 +42,10 @@ -webkit-line-clamp: 2; -webkit-box-orient: vertical; } + +/** + * Styles for the footer of the ProjectCard component. + */ .ProjectCard__footer { display: flex; position: relative; @@ -39,14 +57,26 @@ 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; @@ -60,6 +90,10 @@ 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; @@ -84,15 +118,55 @@ 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 +175,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..09e1c6231 100644 --- a/ui/src/components/Card/index.tsx +++ b/ui/src/components/Card/index.tsx @@ -12,6 +12,12 @@ 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 {ProjectType} project - The project object. + * @returns {JSX.Element} The card component. + */ + const CardList = ({ project }: ProjectType) => { const navigate = useNavigate(); diff --git a/ui/src/components/Common/AddStack/addStack.interface.ts b/ui/src/components/Common/AddStack/addStack.interface.ts index da16ddc96..325d385c5 100644 --- a/ui/src/components/Common/AddStack/addStack.interface.ts +++ b/ui/src/components/Common/AddStack/addStack.interface.ts @@ -1,13 +1,51 @@ 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 input field. + */ 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 input field. + */ stack_name_placeholder: string; + + /** + * The title of the stack. + */ title: string; } @@ -19,19 +57,49 @@ 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. + */ stack_description_placeholder: '', + /** + * The locale-specific 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. + */ stack_name_placeholder: '', + /** + * The title of the stack. + */ title: '' }; diff --git a/ui/src/components/Common/AddStack/addStack.scss b/ui/src/components/Common/AddStack/addStack.scss index 5a6647c80..a146ab6b9 100644 --- a/ui/src/components/Common/AddStack/addStack.scss +++ b/ui/src/components/Common/AddStack/addStack.scss @@ -1,3 +1,16 @@ +/** + * Styles for the AddStack component. + * Styles for the ReactModal component used in the AddStack component. + * + * .ReactModal__add-stack - Styles for the parent container of the ReactModal component in the AddStack component. + * .Description-field > textarea - Styles for the textarea element inside the .Description-field class. + * resize: none; - Disables the ability to resize the textarea. + * .Select__single-value - Styles for the single-value element inside the .Select class. + * width: 200px !important; - Sets the width of the single-value element to 200 pixels, overriding any other styles. + * + * .ReactModal__Overlay .ReactModal__Content .ReactModal__Content__body.selectWrapperBody - Styles for the selectWrapperBody element inside the ReactModal component. + * overflow: visible; - Sets the overflow property of the selectWrapperBody element to visible. + */ .ReactModal__add-stack { .Description-field > textarea { resize: none; diff --git a/ui/src/components/Common/AddStack/addStack.tsx b/ui/src/components/Common/AddStack/addStack.tsx index a8dc2ef24..7f355f891 100644 --- a/ui/src/components/Common/AddStack/addStack.tsx +++ b/ui/src/components/Common/AddStack/addStack.tsx @@ -37,6 +37,13 @@ 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 => { const [isProcessing, setIsProcessing] = useState(false); const [isLoading, setIsLoading] = useState(true); 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..c69f942dd 100644 --- a/ui/src/components/Common/Card/card.scss +++ b/ui/src/components/Common/Card/card.scss @@ -1,5 +1,9 @@ @import '../../../scss/variables'; +/** + * Styles for the card component. + */ +// Styles for the service list container .service_list { text-align: center; display: flex; @@ -9,21 +13,33 @@ margin-bottom: 10px; } +// Styles for the trigger list container .trigger_list { min-width: 120px !important; } -.connector_list .tippy-box-light { - max-width: $px-360 !important; - padding: $px-15 !important; - line-height: 130%; - font-size: $px-12; - font-weight: $font-weight-regular; +// Styles for the connector list container +.connector_list { + // Styles for the tooltip box within the connector list + .tippy-box-light { + max-width: $px-360 !important; + padding: $px-15 !important; + line-height: 130%; + font-size: $px-12; + font-weight: $font-weight-regular; + } + + // Styles for the help text within the connector list tooltip box + .tippy-box-light #automationConnectorsHelpText { + cursor: default; + color: $color-base-gray-20; + } } -.connector_list, +// Styles for the action list and trigger list containers .action_list, .trigger_list { + // Styles for the container border //border: 1px solid $color-base-gray-40; border: 1px solid #6C5CE766; border-radius: $px-6; @@ -35,19 +51,17 @@ gap: 12px; } -.connector_list .tippy-box-light #automationConnectorsHelpText { - cursor: default; - color: $color-base-gray-20; -} - +// Styles for the connector list container on hover .connector_list:hover { box-shadow: 0 3px $px-5 $px-2 rgb(215 215 215); } +// Styles for the service icon .service_icon { padding: $space-20 0; } +// Styles for the service title .service_title { padding: $px-5 $px-5; min-height: $px-40; @@ -59,6 +73,7 @@ background: $color-base-white-10; } +// Styles for the full-screen page layout head .PageLayout--full-screen .PageLayout__head { position: relative; border-bottom: 1px solid rgb(226, 235, 248); @@ -67,6 +82,8 @@ margin-top: 3.5rem; z-index: 8; } -.centered-card-title{ + +// Styles for the centered card title +.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..8cbd82b5b 100644 --- a/ui/src/components/Common/Card/card.tsx +++ b/ui/src/components/Common/Card/card.tsx @@ -13,7 +13,13 @@ type CardProps = { cardType?: string; }; -const Card = ({ data, selectedCard, onCardClick, cardType, idField = 'id' }: CardProps) => { +/** + * Represents a card component. + * + * @param {CardProps} props - The props for the card component. + * @returns {JSX.Element} The rendered card component. + */ +const Card = ({ data, selectedCard, onCardClick, cardType, idField = 'id' }: CardProps): JSX.Element => { const imgStyle = { width: cardType === 'legacyCMS' ? '60px' : '46px', height: cardType === 'legacyCMS' ? '60px' : '46px' diff --git a/ui/src/components/Common/DeleteProjectModal/index.tsx b/ui/src/components/Common/DeleteProjectModal/index.tsx index d5abbf786..b4d63a43b 100644 --- a/ui/src/components/Common/DeleteProjectModal/index.tsx +++ b/ui/src/components/Common/DeleteProjectModal/index.tsx @@ -15,6 +15,13 @@ import { deleteProject } from '../../../services/api/project.service'; // Interfaces import { SettingsModalProps } from '../../../components/Modal/modal.interface'; +/** + * Component for the Delete Project Modal. + * + * @component + * @param {SettingsModalProps} props - The props for the DeleteProjectModal component. + * @returns {JSX.Element} The JSX element representing the DeleteProjectModal component. + */ const DeleteProjectModal = (props: SettingsModalProps) => { const { closeModal, @@ -24,7 +31,13 @@ const DeleteProjectModal = (props: SettingsModalProps) => { selectedOrg } = props; - const handleDeleteProject = async (closeModal: () => void) => { + /** + * Handles the deletion of the project. + * + * @param {() => void} closeModal - The 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 +57,7 @@ const DeleteProjectModal = (props: SettingsModalProps) => { }, 1200) } } + return ( <> ) => void; } +/** + * Renders a component that displays a link and a checkbox. + * + * @component + * @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 up the full width. + * @param {function} props.onChange - The callback function to be called when the checkbox value changes. + * @returns {JSX.Element} The rendered component. + */ const DocLink = ({ cta, isCheckedBoxChecked, diff --git a/ui/src/components/Common/FileUpload/fileupload.scss b/ui/src/components/Common/FileUpload/fileupload.scss index 6a2e32bda..00eea59cb 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,23 @@ } } +/** + * Styles for the hover effect on the file upload container. + */ .hover { border: 0.125rem dashed $color-base-purple; } +/** + * Styles for hiding an element. + */ .hidden { display: none; } +/** + * Styles for the 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..184bb1bb0 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 selected for upload. + * + * @param {FileList | null} filesList - The list of files selected for upload. + */ 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 files are 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 file upload. + * + * @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..8d5e49a3e 100644 --- a/ui/src/components/Common/FileUpload/upload.scss +++ b/ui/src/components/Common/FileUpload/upload.scss @@ -1,3 +1,36 @@ +/** + * Styles for the asset upload component. + * + * This SCSS file contains styles for the asset upload window component. + * It includes styles for the heading, body, and various elements within the component. + * The component is used for uploading files and displaying their progress. + * CSS classes: + * - .asset-upload - The main container for the asset upload component. + * - .asset-upload__heading - The heading section of the asset upload component. + * - .asset-upload__heading.in-progress - Applied when the upload is in progress. + * - .asset-upload__heading.success - Applied when the upload is successful. + * - .asset-upload__heading.attention - Applied when attention is required. + * - .asset-upload__heading.warning - Applied when there is a warning. + * - .asset-upload__actions - Container for the upload actions. + * - .asset-upload__actions__cancel - Cancel upload action button. + * - .asset-upload__actions__minimize - Minimize upload action button. + * - .asset-upload__actions__maximize - Maximize upload action button. + * - .asset-upload__count - Displays the count of uploaded files. + * - .asset-upload__body - The body section of the asset upload component. + * - .asset-upload__file - Container for each uploaded file. + * - .asset-upload__file__name - Displays the name of the uploaded file. + * - .asset-upload__file__actions - Container for file actions. + * - .asset-upload__file__actions__progress - Container for file upload progress. + * - .asset-upload__file__actions__progress .file-loaded - Displays the loaded file size. + * - .asset-upload__file__actions__progress .total-size - Displays the total file size. + * - .asset-upload__file__actions .cancel-upload - Cancel upload action button for a file. + * + * @example + *
+ *
...
+ *
...
+ *
+ */ @import '../../../scss/variables'; /* Asset upload window css */ diff --git a/ui/src/components/Common/FileUpload/upload.tsx b/ui/src/components/Common/FileUpload/upload.tsx index fcae15a4e..e6f5bcbba 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,12 @@ const ErrorFile = ({ file, handleRemove }: any) => { ); }; +/** + * Renders a component for interrupting the file upload process. + * + * @param props - The component props. + * @returns The rendered component. + */ const InterruptUpload = (props: any) => { const handleProceed = () => { props.closeModal({ cancelUpload: true }); @@ -100,6 +120,10 @@ 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..f304bf2d8 100644 --- a/ui/src/components/Common/Modal/FilterModal/FilterModal.scss +++ b/ui/src/components/Common/Modal/FilterModal/FilterModal.scss @@ -1,6 +1,8 @@ @import '../../../../scss/variables'; - -.Filter__modal { +/** + * Styles for the FilterModal component. + */ + .Filter__modal { width: $px-400; z-index: 40; position: absolute; @@ -9,30 +11,48 @@ border-radius: $px-10; } -.Filter__modal .Checkbox input:checked ~ .Checkbox__tick, -.Filter__modal .Checkbox .Checkbox__box { - margin-top: $px-4; - font-size: $px-16; -} +/** + * Styles for the checkboxes inside the FilterModal component. + */ + .Filter__modal .Checkbox input:checked ~ .Checkbox__tick, + .Filter__modal .Checkbox .Checkbox__box { + margin-top: $px-4; + font-size: $px-16; + } -.Filter__modal .Filter__item { +/** + * Styles for each filter item inside the FilterModal component. + */ + .Filter__modal .Filter__item { cursor: pointer; padding: $px-10 $px-20; } -.Filter__modal .Filter__item:hover { +/** + * Styles for the filter item when hovered inside the FilterModal component. + */ + .Filter__modal .Filter__item:hover { background-color: $color-base-white-10; } -.Filter__modal .Filter__item:hover .WordWrapper { +/** + * Styles for the WordWrapper element when the filter item is hovered inside the FilterModal component. + */ + .Filter__modal .Filter__item:hover .WordWrapper { color: $color-brand-primary-base; } -.Filter__modal .Filter__item:hover .Checkbox__box { +/** + * Styles for the Checkbox__box element when the filter item is hovered inside the FilterModal component. + */ + .Filter__modal .Filter__item:hover .Checkbox__box { border: 1.5px solid $color-brand-primary-base; } -.Filter__modal-header { +/** + * Styles for the header of the FilterModal component. + */ + .Filter__modal-header { background: $color-base-white-10; border-bottom: 1px solid $color-brand-secondary-lightest; font-size: $px-20; @@ -41,7 +61,10 @@ padding: $px-14 $px-16; } -.Filter__modal-header .Filter__modal-header-container { +/** + * Styles for the container of the header in the FilterModal component. + */ + .Filter__modal-header .Filter__modal-header-container { align-items: center; display: flex; color: #222; @@ -53,11 +76,17 @@ font-weight: 600; } -.Filter__modal-header .Filter__modal-header-container .Filter__modal-header-title { +/** + * Styles for the title in the header of the FilterModal component. + */ + .Filter__modal-header .Filter__modal-header-container .Filter__modal-header-title { font-weight: 600; } -.Filter__modal-header .Filter__modal-header-container .Filter__modal-header-counter { +/** + * Styles for the counter in the header of the FilterModal component. + */ + .Filter__modal-header .Filter__modal-header-container .Filter__modal-header-counter { border: 1px solid $color-brand-secondary-lightest; border-radius: 1rem; color: $color-stepper-title; @@ -74,26 +103,44 @@ width: fit-content; } -.Filter__searchbox .Search--primary .Search__input { +/** + * Styles for the search box inside the FilterModal component. + */ + .Filter__searchbox .Search--primary .Search__input { height: $px-35; } -.Filter__modal-content { +/** + * Styles for the content area of the FilterModal component. + */ + .Filter__modal-content { overflow: scroll; max-height: $px-250; overflow-x: hidden; } -.Filter__icon { +/** + * Styles for the filter icon in the FilterModal component. + */ + .Filter__icon { cursor: pointer !important; padding: $px-5; border-radius: 10%; } -.Filter__icon:hover { +/** + * Styles for the background color of the filter icon in the FilterModal component. + */ + .Filter__icon:hover { background-color: rgba(108, 92, 231, 0.1); } +/** + * Styles for the cancel button in the header of the FilterModal component. + */ + .Filter__icon_bg_color { + background-color: rgba(108, 92, 231, 0.1); +} .Filter__icon_bg_color { background-color: rgba(108, 92, 231, 0.1); } @@ -108,8 +155,10 @@ .Filter__modal-header-cancel:hover { background-color: $color-brand-secondary-lightest; } - -.Filter__modal-footer { +/** + * Styles for the footer of the FilterModal component. + */ + .Filter__modal-footer { display: flex; border-top: 1px solid $color-brand-secondary-lightest; height: $px-70; @@ -117,7 +166,10 @@ padding: $px-20; } -.Filter__no-found { +/** + * Styles for the "no results found" message in the FilterModal component. + */ + .Filter__no-found { text-align: center; vertical-align: middle; line-height: $px-50; diff --git a/ui/src/components/Common/Modal/FilterModal/FilterModal.tsx b/ui/src/components/Common/Modal/FilterModal/FilterModal.tsx index 56b3e5d20..336690287 100644 --- a/ui/src/components/Common/Modal/FilterModal/FilterModal.tsx +++ b/ui/src/components/Common/Modal/FilterModal/FilterModal.tsx @@ -20,6 +20,14 @@ type Props = { iconSize?: 'original' | 'tiny' | 'mini' | 'small' | 'large' | 'medium' | 'extraSmall'; }; +/** + * Represents a filter modal component. + * + * @component + * @param {Props} props - The props for the FilterModal component. + * @returns {JSX.Element} The rendered FilterModal component. + */ + export const FilterModal = (props: Props) => { const { title, diff --git a/ui/src/components/Common/Modal/FilterModal/filterModal.interface.ts b/ui/src/components/Common/Modal/FilterModal/filterModal.interface.ts index 311d0aab3..f5c43b553 100644 --- a/ui/src/components/Common/Modal/FilterModal/filterModal.interface.ts +++ b/ui/src/components/Common/Modal/FilterModal/filterModal.interface.ts @@ -1,3 +1,6 @@ +/** + * Represents the interface for a filter type. + */ export interface IFilterType { value: string; label: string; diff --git a/ui/src/components/Common/ProgressBar/index.tsx b/ui/src/components/Common/ProgressBar/index.tsx index f15ae7d4b..81260efcc 100644 --- a/ui/src/components/Common/ProgressBar/index.tsx +++ b/ui/src/components/Common/ProgressBar/index.tsx @@ -24,6 +24,13 @@ type IStyle = { [key: string]: string } +/** + * Renders a progress bar component. + * + * @component + * @param {ProgressBarProps} props - The props for the ProgressBar component. + * @returns {JSX.Element} - The rendered ProgressBar component. + */ const ProgressBar = (props: ProgressBarProps) => { const { percentage, color, height, borderRadius, type, radius, stroke, bgColor } = props diff --git a/ui/src/components/Common/ProgressBar/progressBar.scss b/ui/src/components/Common/ProgressBar/progressBar.scss index fc0310e27..3ffaabe07 100644 --- a/ui/src/components/Common/ProgressBar/progressBar.scss +++ b/ui/src/components/Common/ProgressBar/progressBar.scss @@ -1,16 +1,31 @@ @import '../../../scss//variables'; - +/** + * Styles for the ProgressBar component. + * + * @class ProgressBar + */ .ProgressBar { border-radius: $space-4; overflow: hidden; + + /** + * Styles for the progress bar element. + * + * @class ProgressBar__bar + */ &__bar { - border-radius: inherit; height: inherit; transition: width 100ms linear; } - &__circle{ + + /** + * Styles for the progress circle element. + * + * @class ProgressBar__circle + */ + &__circle { stroke-width: 5%; transform: rotate(-90deg); transform-origin: 50% 50%; diff --git a/ui/src/components/Common/Settings/Settings.scss b/ui/src/components/Common/Settings/Settings.scss index 4c6377a39..c5875a943 100644 --- a/ui/src/components/Common/Settings/Settings.scss +++ b/ui/src/components/Common/Settings/Settings.scss @@ -1,19 +1,40 @@ +/** + * This SCSS file contains styles for the Settings component. + */ + @import '../../../scss/variables'; #setting-page { display: flex; width: 100%; + + /** + * Styles for the section header. + */ .SectionHeader { color: $color-stepper-title; font-weight: $font-weight-semi-bold; margin-bottom: 2rem; } + + /** + * Styles for the page layout. + */ .PageLayout { width: 100%; } - .PageLayout__head, .PageLayout__leftSidebar { + + /** + * Styles for the page layout's head and left sidebar. + */ + .PageLayout__head, + .PageLayout__leftSidebar { border-top: 0 none; } + + /** + * Styles for the primary page layout. + */ .PageLayout--primary { .PageLayout__content { .PageLayout__body { @@ -21,12 +42,20 @@ margin-left: 15rem; padding-top: $px-8; } - } - } + } + } + + /** + * Styles for the action component title. + */ .action-component-title { justify-content: space-between; width: calc(100vw - 326px); } + + /** + * Styles for the content block. + */ .content-block { margin-right: 0; padding: 1.5rem; @@ -34,28 +63,30 @@ } } +/** + * Styles for the field. + */ .Field { margin-bottom: $px-40; } + +/** + * Styles for hiding the left sidebar. + */ .PageLayout__leftSidebar--hide { display: none; } +/** + * Styles for the left sidebar. + */ .leftsidebar { margin-top: 0 !important; } -// .content-body .white-box-container { -// background-color: $color-brand-white-base; -// padding: 20px; -// margin-top: 50px !important; -// margin-left: 240px; -// margin-right: auto; -// position: relative; -// z-index: 10; -// height: 600px; -// } - +/** + * Styles for the stack settings heading. + */ .stack-settings__heading { color: $color-base-black-base; font-size: 0.875rem; @@ -65,26 +96,16 @@ margin-bottom: $px-20; } -// .toggle-class { -// width: calc(100% - 18.4375rem) !important; -// } -// .layout-container.specific-context .PageLayout__head { -// z-index: 10 !important; -// margin-left: 240px; -// width: 100% !important; -// } -// .SaveButton { -// padding: 30px 10px; -// } - -// .layout-container.content-body .PageLayout__body { -// margin-top: 90px !important; -// margin-left: 227px !important; -// } - +/** + * Styles for the page layout's left sidebar. + */ .PageLayout__leftSidebar { background-color: #f7f9fc !important; } + +/** + * Styles for the active list row. + */ .ListRowV2--active { background-color: #fff; border-left: 0.125rem solid; diff --git a/ui/src/components/Common/Settings/setting.interface.ts b/ui/src/components/Common/Settings/setting.interface.ts index f0abcc5e4..0d6a420ea 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; 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..11ff6d635 100644 --- a/ui/src/components/Common/private-route.tsx +++ b/ui/src/components/Common/private-route.tsx @@ -7,6 +7,14 @@ type IProps = { 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 ( diff --git a/ui/src/components/ContentMapper/contentMapper.interface.ts b/ui/src/components/ContentMapper/contentMapper.interface.ts index a247930a8..00b750556 100644 --- a/ui/src/components/ContentMapper/contentMapper.interface.ts +++ b/ui/src/components/ContentMapper/contentMapper.interface.ts @@ -50,19 +50,35 @@ export interface ContentType { fieldMapping?: FieldMapType[] | []; } +/** + * Represents the field mapping type for ContentMapper. + */ export interface FieldMapType { + /** The Contentstack field type. */ ContentstackFieldType: string; + /** The child field mappings. */ child?: FieldMapType[] | undefined; + /** The backup field type. */ backupFieldType: string; + /** The Contentstack field name. */ contentstackField: string; + /** The Contentstack field UID. */ contentstackFieldUid: string; + /** Indicates if the field is deleted. */ isDeleted: boolean; + /** The field name in another CMS. */ otherCmsField: string; + /** The field type in another CMS. */ otherCmsType: string; + /** The UID of the field mapping. */ uid: string; + /** The ID of the field mapping. */ id: string; + /** Indicates if the field can be selected. */ _canSelect?: boolean; + /** Advanced field options. */ advanced?: Advanced; + /** The Contentstack UID. */ contentstackUid: string; } diff --git a/ui/src/components/ContentMapper/index.scss b/ui/src/components/ContentMapper/index.scss index cf03e88cb..3ad57d742 100644 --- a/ui/src/components/ContentMapper/index.scss +++ b/ui/src/components/ContentMapper/index.scss @@ -1,3 +1,34 @@ +/** + * + * This SCSS file contains styles for the ContentMapper component. + * The ContentMapper component is responsible for mapping content types and fields. + * It includes styles for the content types list, search bar, list items, options, table, and other UI elements. + * + * Styles are organized into different sections: + * - .content-types-list-wrapper: Styles for the wrapper of the content types list. + * - .content-types-list-header: Styles for the header of the content types list. + * - .ct-search-wrapper: Styles for the search bar wrapper. + * - .ct-list-wrapper: Styles for the wrapper of the content types list. + * - .ct-list: Styles for the content types list. + * - .mapped-icon: Styles for the mapped icon. + * - .dropdown-align: Styles for aligning the dropdown menu. + * - .content-type-list: Styles for the content type list. + * - .content-types-fields-wrapper: Styles for the wrapper of the content types fields. + * - .cta-wrapper: Styles for the call-to-action wrapper. + * - .table-container: Styles for the table container. + * - .table-wrapper: Styles for the table wrapper. + * - .disabled-field: Styles for disabled fields. + * - .action-btn-wrapper: Styles for the action button wrapper. + * - .action-component-body: Styles for the action component body. + * - .step-container: Styles for the step container. + * - .saveButton: Styles for the save button. + * - .btnWrapper: Styles for the button wrapper. + * - div .select: Styles for the select dropdown. + * - div .table-row: Styles for the table row. + * - .status-wrapper: Styles for the status wrapper. + * - .filter-wrapper: Styles for the filter wrapper. + * - .no-content: Styles for the no content message. + */ @import '../../scss/App.scss'; @import '../../scss/variables'; diff --git a/ui/src/components/ContentMapper/index.tsx b/ui/src/components/ContentMapper/index.tsx index 932ed5838..7e365ae6a 100644 --- a/ui/src/components/ContentMapper/index.tsx +++ b/ui/src/components/ContentMapper/index.tsx @@ -99,6 +99,10 @@ const Fields: Mapping = { global_field: 'Global' }; +/** + * Component for mapping content types. + */ + const ContentMapper = () => { /** ALL CONTEXT HERE */ diff --git a/ui/src/components/DestinationStack/Actions/LoadOrganisation.tsx b/ui/src/components/DestinationStack/Actions/LoadOrganisation.tsx index fc33d2c4b..a78ab6c26 100644 --- a/ui/src/components/DestinationStack/Actions/LoadOrganisation.tsx +++ b/ui/src/components/DestinationStack/Actions/LoadOrganisation.tsx @@ -1,41 +1,51 @@ -import { ChangeEvent, useEffect, useState } from 'react'; +// Importing necessary React hooks and Redux functions for state management. +import { useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; + +// Importing type definitions for dropdown and migration data structures. import { IDropDown, INewMigration } from '../../../context/app/app.interface'; + +// Importing UI components from @contentstack/venus-components. import { TextInput } from '@contentstack/venus-components'; +// Importing stylesheet for the DestinationStack component. import '../DestinationStack.scss'; + +// Utility function to check for empty strings. import { isEmptyString } from '../../../utilities/functions'; + +// RootState type for accessing the Redux store's state. import { RootState } from '../../../store'; + +// Action creator for updating migration data in the Redux store. import { updateNewMigrationData } from '../../../store/slice/migrationDataSlice'; +// Interface defining the props expected by the LoadOrganisation component. interface LoadOrganisationProps { - stepComponentProps: any; - currentStep: number; - handleStepChange: (stepIndex: number, closeStep?: boolean) => void; + stepComponentProps: any; // Props for the step component, type not specified. + currentStep: number; // The current step in a multi-step process. + handleStepChange: (stepIndex: number, closeStep?: boolean) => void; // Function to handle step changes. } +// The LoadOrganisation component is responsible for loading and displaying the selected organisation. const LoadOrganisation = (props: LoadOrganisationProps) => { - /**** ALL HOOKS HERE ****/ - - const newMigrationData = useSelector((state:RootState)=>state?.migration?.newMigrationData); - const selectedOrganisation = useSelector((state:RootState)=>state?.authentication?.selectedOrganisation); - + // State and dispatch hooks for interacting with the Redux store. + const newMigrationData = useSelector((state: RootState) => state?.migration?.newMigrationData); + const selectedOrganisation = useSelector((state: RootState) => state?.authentication?.selectedOrganisation); const dispatch = useDispatch(); + // Local state for tracking the selected organisation. const [selectedOrg, setSelectedOrg] = useState(); - /**** ALL METHODS HERE ****/ - //update new Migration Data + // Function to update the new migration data in the Redux store. const setNewMigrationData = (data: INewMigration) => { - dispatch(updateNewMigrationData((data))); + dispatch(updateNewMigrationData(data)); }; - - - /**** ALL USEEffects HERE ****/ + // Effect hook to initialize the selected organisation based on the Redux store or local state. useEffect(() => { const org = !isEmptyString(newMigrationData.destination_stack.selectedOrg.label) - ? newMigrationData?.destination_stack?.selectedOrg + ? newMigrationData.destination_stack.selectedOrg : selectedOrganisation; setSelectedOrg(org as any); @@ -48,7 +58,8 @@ const LoadOrganisation = (props: LoadOrganisationProps) => { } }); }, []); - + + // Render function for the LoadOrganisation component. return (
{ ); }; -export default LoadOrganisation; +// Exporting the LoadOrganisation component as the default export. +export default LoadOrganisation; \ No newline at end of file diff --git a/ui/src/components/DestinationStack/Actions/LoadStacks.tsx b/ui/src/components/DestinationStack/Actions/LoadStacks.tsx index a7d41d94f..bef438cca 100644 --- a/ui/src/components/DestinationStack/Actions/LoadStacks.tsx +++ b/ui/src/components/DestinationStack/Actions/LoadStacks.tsx @@ -27,6 +27,11 @@ const defaultStack = { name: '' }; +/** + * Component for loading stacks. + * @param props - The component props. + * @returns The LoadStacks component. + */ const LoadStacks = (props: LoadFileFormatProps) => { const ref = useRef(null); /**** ALL HOOKS HERE ****/ diff --git a/ui/src/components/DestinationStack/DestinationStack.scss b/ui/src/components/DestinationStack/DestinationStack.scss index 3a6abb716..224fb5bb8 100644 --- a/ui/src/components/DestinationStack/DestinationStack.scss +++ b/ui/src/components/DestinationStack/DestinationStack.scss @@ -1,13 +1,24 @@ @import '../../scss/variables'; +/** + * Styles for the service list container. + * + * The service list container is used to display a list of services. + * It aligns the text to the left, uses flexbox to wrap the items, + * sets a gap of 12px between the items, and applies a margin of + * 0 0 20px 10px to the container. + */ .service_list { text-align: left; display: flex; flex-wrap: wrap; gap: 12px; - margin: 0 0 20px 10px !important + margin: 0 0 20px 10px !important; } +/** + * Styles for the DestinationStack component. + */ .title { margin: 20px 0 5px; padding: 0 8px; @@ -16,32 +27,59 @@ font-weight: $font-weight-semi-bold; line-height: 21px; } + +/** + * Styles for the stackTitle class. + */ .stackTitle { color: $color-black-2121; font-size: $size-font-large; font-weight: $font-weight-semi-bold; padding-bottom: 20px; } + +/** + * Styles for the pl-40 class. + */ .pl-40 { padding-left: $px-40; } + +/** + * Styles for the Dropdown-wrapper class. + */ .Dropdown-wrapper { + /** + * Styles for the css-b8ldur-Input class. + */ .css-b8ldur-Input { - margin: 0; - padding: 0; + margin: 0; + padding: 0; } .Select__v2 .Select__menu .Select__menu-list { padding: 1px; } } + +/** + * Styles for the stackselect class. + */ .stackselect { min-width: 600px !important; max-width: 600px !important; border: 1px solid $color-brand-secondary-lightest; border-radius: 4px; } + +/** + * Styles for the destination-stack-container class. + */ .destination-stack-container { padding: 20px; + + /** + * Styles for the migration-vertical-stepper class. + */ .migration-vertical-stepper { padding: 24px 30px; border: 1px solid $color-brand-secondary-lightest; @@ -57,6 +95,10 @@ border: 0 none; border-radius: 0; } + + /** + * Styles for the stepper-title class. + */ .stepper-title { margin: 20px 0 5px; padding: 0 8px; @@ -78,17 +120,28 @@ box-shadow: none; border: 0 none; border-radius: 0; - padding:0 !important; + padding: 0 !important; } + + /** + * Styles for the migration-vertical-stepper-container class. + */ .migration-vertical-stepper-container { border-bottom: 0 none; } + + /** + * Styles for the orgInput class. + */ .orgInput { max-width: 600px; width: 100%; } + + /** + * Styles for the Select__menu class. + */ .Select__menu { - // max-width: 430px; width: 100%; margin: 0; padding: 0; @@ -118,12 +171,21 @@ color: $color-brand-primary-base; } } - .Select .Select__control .Select__value-container input, .Select__single-value input[text]{ + + /** + * Styles for the Select__value-container class. + */ + .Select .Select__control .Select__value-container input, + .Select__single-value input[text] { font-size: 16px !important; line-height: 24px !important; color: $color-placeholder !important; width: 100% !important; } + + /** + * Styles for the Select__option class. + */ .Select__option { position: relative; } @@ -132,22 +194,38 @@ .TextInput--disabled .TextInput__v2 { background-color: #F9F8FF !important; } + + /** + * Styles for the #Step2 ID. + */ #Step2 { + /** + * Styles for the action-summary-wrapper class. + */ .action-summary-wrapper { background-color: $color-brand-white-base; margin-left: 2px; padding: 0 !important; } } + + /** + * Styles for the errorMessage class. + */ .errorMessage { color: $color-brand-warning-medium; font-size: $size-font-small; } - - } } + +/** + * Styles for the action-summary-wrapper class. + */ .action-summary-wrapper { + /** + * Styles for the Select__value-container class. + */ .Select .Select__control .Select__value-container.Select__value-container--has-value .Select__single-value input { width: 100% !important; background-color: $color-brand-white-base; @@ -156,13 +234,19 @@ font-weight: $font-weight-regular; line-height: 24px; } + + /** + * Styles for the TextInput--disabled class. + */ .TextInput--disabled .TextInput__v2 { background-color: $color-base-white-5 !important; color: $color-black-2121; } } - +/** + * Styles for the locale-container class. + */ .locale-container { display: flex; background-color: $color-base-white-5; diff --git a/ui/src/components/DestinationStack/StepperSteps.ts b/ui/src/components/DestinationStack/StepperSteps.ts index 76e2db96a..af174b7fa 100644 --- a/ui/src/components/DestinationStack/StepperSteps.ts +++ b/ui/src/components/DestinationStack/StepperSteps.ts @@ -6,6 +6,15 @@ import OrganisationSummary from './Summary/OrganisationSummary'; import StacksSummary from './Summary/StacksSummary'; import { IStep } from '../../context/app/app.interface'; +/** + * Returns an updated step object based on the provided parameters. + * + * @param step - The original step object. + * @param isCompleted - A boolean indicating whether the step is completed. + * @param isMigrationLocked - A boolean indicating whether the migration is locked. + * @param isPrevStepLocked - A boolean indicating whether the previous step is locked. Default is false. + * @returns The updated step object. + */ const getComponentObject = ( step: IStep, isCompleted: boolean, @@ -47,6 +56,14 @@ const getComponentObject = ( return updatedStep; }; +/** + * Returns an array of component objects representing the steps in the destination stack. + * + * @param isCompleted - A boolean indicating whether the migration is completed. + * @param isMigrationLocked - A boolean indicating whether the migration is locked. + * @param allSteps - An array of IStep objects representing all the steps in the destination stack. + * @returns An array of component objects representing the steps in the destination stack. + */ export const getDestinationStackSteps = ( isCompleted: boolean, isMigrationLocked: boolean, diff --git a/ui/src/components/DestinationStack/Summary/OrganisationSummary.tsx b/ui/src/components/DestinationStack/Summary/OrganisationSummary.tsx index 56d0a3845..04bcbb78d 100644 --- a/ui/src/components/DestinationStack/Summary/OrganisationSummary.tsx +++ b/ui/src/components/DestinationStack/Summary/OrganisationSummary.tsx @@ -6,10 +6,20 @@ import { IStep } from '../../../context/app/app.interface'; import './summary.scss'; import { RootState } from '../../../store'; +/** + * Props for the OrganisationSummary component. + */ interface OrganisationSummaryProps { stepData: IStep; } +/** + * Renders the summary of the selected organization in the destination stack. + * + * @component + * @param {OrganisationSummaryProps} props - The props for the OrganisationSummary component. + * @returns {JSX.Element} The rendered OrganisationSummary component. + */ const OrganisationSummary = (props: OrganisationSummaryProps): JSX.Element => { const newMigrationData = useSelector((state:RootState)=>state?.migration?.newMigrationData); diff --git a/ui/src/components/DestinationStack/Summary/StacksSummary.tsx b/ui/src/components/DestinationStack/Summary/StacksSummary.tsx index e5082ad63..a751fc4e0 100644 --- a/ui/src/components/DestinationStack/Summary/StacksSummary.tsx +++ b/ui/src/components/DestinationStack/Summary/StacksSummary.tsx @@ -14,6 +14,12 @@ interface StacksSummaryProps { stepData: IStep; } +/** + * Renders the summary of stacks in the destination stack component. + * + * @param {StacksSummaryProps} props - The props for the StacksSummary component. + * @returns {JSX.Element} The rendered StacksSummary component. + */ const StacksSummary = (props: StacksSummaryProps): JSX.Element => { const newMigrationData = useSelector((state:RootState)=>state?.migration?.newMigrationData); diff --git a/ui/src/components/DestinationStack/Summary/summary.scss b/ui/src/components/DestinationStack/Summary/summary.scss index 43f3cb926..7875eccd0 100644 --- a/ui/src/components/DestinationStack/Summary/summary.scss +++ b/ui/src/components/DestinationStack/Summary/summary.scss @@ -1,5 +1,8 @@ @import '../../../scss/variables'; +/** + * Styles for the summary title. + */ .summary-title { font-family: $font-family-primary; font-style: normal; @@ -11,6 +14,9 @@ margin-top: 3px; } +/** + * Styles for the action summary wrapper in Step 2. + */ #Step2 .action-summary-wrapper { background-color: rgb(247, 249, 252); border: none; @@ -20,10 +26,16 @@ top: 50%; } +/** + * Styles for the step in the StepperWrapper in Step 2. + */ #Step2 .StepperWrapper__step { padding: 0 !important; } +/** + * Styles for the col-12 class. + */ .col-12 { text-align: left; padding: 0; diff --git a/ui/src/components/DestinationStack/index.tsx b/ui/src/components/DestinationStack/index.tsx index 81c411022..a36be6259 100644 --- a/ui/src/components/DestinationStack/index.tsx +++ b/ui/src/components/DestinationStack/index.tsx @@ -18,63 +18,100 @@ import { getCMSDataFromFile } from '../../cmsData/cmsSelector'; import { RootState } from '../../store'; import { updateMigrationData, updateNewMigrationData } from '../../store/slice/migrationDataSlice'; +/** + * Props for the DestinationStackComponent. + */ type DestinationStackComponentProps = { destination_stack: string; org_id: string; isCompleted: boolean; projectData: MigrationResponse; handleStepChange: (currentStep: number) => void; - handleOnAllStepsComplete:(flag : boolean)=>void; + handleOnAllStepsComplete: (flag: boolean) => void; }; +/** + * Renders the DestinationStackComponent. + * @param destination_stack - The destination stack value. + * @param org_id - The organization ID. + * @param projectData - The project data. + * @param isCompleted - Flag indicating if the component is completed. + * @param handleOnAllStepsComplete - Callback function for handling all steps completion. + */ const DestinationStackComponent = ({ destination_stack, org_id, projectData, isCompleted, - // handleStepChange, handleOnAllStepsComplete, }: DestinationStackComponentProps) => { /** ALL HOOKS HERE */ + + /** + * Flag indicating if the component is loading. + */ const [isLoading, setIsLoading] = useState(true); - // const [isCompleted, setIsCompleted] = useState(false); + + /** + * Flag indicating if the component is migration locked. + */ const [isMigrationLocked, setIsMigrationLocked] = useState(false); + + /** + * The key for the stepper component. + */ const [stepperKey, setStepperKey] = useState('v-mig-destination-step'); + + /** + * The internal active step index. + */ const [internalActiveStepIndex, setInternalActiveStepIndex] = useState(-1); + /** + * Reference to the autoVerticalStepperComponent. + */ const autoVerticalStepperComponent = useRef(null); /** ALL CONTEXT HERE */ - const migrationData = useSelector((state:RootState)=>state?.migration?.migrationData); - const newMigrationData = useSelector((state:RootState)=>state?.migration?.newMigrationData); - const selectedOrganisation = useSelector((state:RootState)=>state?.authentication?.selectedOrganisation); - const organisationsList = useSelector((state:RootState)=>state?.authentication?.organisationsList); - const dispatch = useDispatch(); - // const { projectId = '' } = useParams(); + /** + * The migration data from the Redux store. + */ + const migrationData = useSelector((state: RootState) => state?.migration?.migrationData); + + /** + * The new migration data from the Redux store. + */ + const newMigrationData = useSelector((state: RootState) => state?.migration?.newMigrationData); + + /** + * The selected organization from the Redux store. + */ + const selectedOrganisation = useSelector((state: RootState) => state?.authentication?.selectedOrganisation); + + /** + * The list of organizations from the Redux store. + */ + const organisationsList = useSelector((state: RootState) => state?.authentication?.organisationsList); - // const navigate = useNavigate(); + /** + * The Redux dispatch function. + */ + const dispatch = useDispatch(); + /** + * Handles all steps completion. + * @param flag - Flag indicating if all steps are completed. + */ const handleAllStepsComplete = (flag = false) => { handleOnAllStepsComplete(flag); }; - // const handleOnClick = async (event: MouseEvent) => { - // event?.preventDefault(); - // //Update Data in backend - // await updateDestinationStack(selectedOrganisation?.value, projectId, { - // stack_api_key: newMigrationData?.destination_stack?.selectedStack?.value - // }); - // handleStepChange(2); - // const res = await updateCurrentStepData(selectedOrganisation?.value, projectId); - // if (res) { - // const url = `/projects/${projectId}/migration/steps/3`; - // navigate(url, { replace: true }); - // } - // }; - + /** + * Updates the destination stack data. + */ const updateDestinationStackData = async () => { - //Update New Migration data + // Update New Migration data const selectedOrganisationData = validateArray(organisationsList) ? organisationsList?.find((org: IDropDown) => org?.value === org_id) @@ -85,20 +122,19 @@ const DestinationStackComponent = ({ label: '', master_locale: '', locales: [], - created_at: '' + created_at: '', }; - //If stack is already selected and exist in backend, then fetch all stack list and filter selected stack. + // If stack is already selected and exist in backend, then fetch all stack list and filter selected stack. if (!isEmptyString(destination_stack)) { const stackData: any = await getAllStacksInOrg( - selectedOrganisationData?.value || selectedOrganisation?.value,'' + selectedOrganisationData?.value || selectedOrganisation?.value, + '' ); const stack = validateArray(stackData?.data?.stacks) && - stackData?.data?.stacks?.find( - (stack: StackResponse) => stack?.api_key === destination_stack - ); + stackData?.data?.stacks?.find((stack: StackResponse) => stack?.api_key === destination_stack); if (stack) { selectedStackData = { @@ -106,45 +142,45 @@ const DestinationStackComponent = ({ value: stack?.api_key, master_locale: stack?.master_locale, locales: stack?.locales, - created_at: stack?.created_at + created_at: stack?.created_at, }; } } - //Make First Step Complete + // Make First Step Complete if (!isEmptyString(selectedOrganisationData?.value)) { setInternalActiveStepIndex(0); } - //Complete step if all step are selected. + // Complete step if all step are selected. if ( !isEmptyString(selectedOrganisationData?.value) && !isEmptyString(selectedStackData?.value) ) { setInternalActiveStepIndex(1); - // setIsCompleted(true); } - //Update newMigration Data for destination stack + // Update newMigration Data for destination stack const newMigData: IDestinationStack = { ...newMigrationData?.destination_stack, selectedOrg: selectedOrganisationData || selectedOrganisation, - selectedStack: selectedStackData + selectedStack: selectedStackData, }; dispatch(updateNewMigrationData({ destination_stack: newMigData })); }; /********** ALL USEEFFECT HERE *************/ + useEffect(() => { + /** + * Fetches the CMS data and updates the component state. + */ const fetchCMSData = async () => { - //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. const data = await getCMSDataFromFile(CS_ENTRIES?.DESTINATION_STACK); - //fetch Legacy CMS Component Data from Contentstack CMS - //const data = await getEntries({ contentType: CS_ENTRIES.DESTINATION_STACK }) - - //Check for null + // Check for null if (!data) { dispatch(updateMigrationData({ destinationStackData: DEFAULT_DESTINATION_STACK_DATA })); setIsLoading(false); @@ -153,19 +189,18 @@ const DestinationStackComponent = ({ const destinationStackDataMapped: IDestinationStackComponent = { ...data, - all_steps: getDestinationStackSteps(isCompleted, isMigrationLocked, data?.all_steps) + all_steps: getDestinationStackSteps(isCompleted, isMigrationLocked, data?.all_steps), }; - //updateDestinationStackData(); - dispatch(updateMigrationData({ destinationStackData: destinationStackDataMapped })); setIsLoading(false); - //Check for migration Status and lock. + // Check for migration Status and lock. // Status where Migration is to be Locked: setIsMigrationLocked(projectData?.status === 2 || projectData?.status === 5); }; + fetchCMSData(); }, []); @@ -193,7 +228,11 @@ const DestinationStackComponent = ({ ); } } - }, [internalActiveStepIndex]); + }, [internalActiveStepIndex]); + + /** + * Renders the DestinationStackComponent. + */ return ( <> {isLoading ? ( @@ -204,7 +243,7 @@ const DestinationStackComponent = ({
) : (
-
{migrationData?.destinationStackData?.title}
+
{migrationData?.destinationStackData?.title}
{ public state: State = { hasError: false diff --git a/ui/src/components/ImageTag/index.tsx b/ui/src/components/ImageTag/index.tsx index 75854d970..8ee40846a 100644 --- a/ui/src/components/ImageTag/index.tsx +++ b/ui/src/components/ImageTag/index.tsx @@ -8,6 +8,16 @@ interface ImageType { noWebP?: boolean; } +/** + * Renders an image tag with optional webP format support. + * + * @param classes - The CSS classes to apply to the image tag. + * @param image - The image object containing the URL and title. + * @param imageUrl - The URL of the image. + * @param alt - The alternative text for the image. + * @param noWebP - A flag indicating whether to disable webP format. + * @returns The rendered image tag. + */ const ImageTag = ({ classes, image, imageUrl, alt = '', noWebP = false }: ImageType) => { let imageLink = image?.url ? image.url : imageUrl; const altText = alt ? alt : image?.title; @@ -17,4 +27,5 @@ const ImageTag = ({ classes, image, imageUrl, alt = '', noWebP = false }: ImageT } return {altText}; }; + export default ImageTag; diff --git a/ui/src/components/LegacyCms/Actions/LoadFileFormat.tsx b/ui/src/components/LegacyCms/Actions/LoadFileFormat.tsx index 78b6091dd..2d6d06bed 100644 --- a/ui/src/components/LegacyCms/Actions/LoadFileFormat.tsx +++ b/ui/src/components/LegacyCms/Actions/LoadFileFormat.tsx @@ -27,8 +27,14 @@ interface LoadFileFormatProps { handleStepChange: (stepIndex: number, closeStep?: boolean) => void; } +/** + * Component for loading file format. + * @param {LoadFileFormatProps} props - The component props. + * @returns {JSX.Element} The rendered component. + */ const LoadFileFormat = (props: LoadFileFormatProps) => { + // State variables const newMigrationData = useSelector((state:RootState)=>state?.migration?.newMigrationData); const selectedOrganisation = useSelector((state:RootState)=>state?.authentication?.selectedOrganisation); const migrationData = useSelector((state:RootState)=>state?.migration?.migrationData); @@ -43,99 +49,9 @@ const LoadFileFormat = (props: LoadFileFormatProps) => { const [fileIcon, setFileIcon] = useState(newMigrationData?.legacy_cms?.selectedFileFormat?.title); const [isError, setIsError] = useState(false); const [error, setError] = useState(''); - - const { projectId = '' } = useParams(); + // Other code... - /**** ALL METHODS HERE ****/ - - const handleBtnClick = async () => { - - if (!isEmptyString(selectedCard?.fileformat_id) && isCheckedBoxChecked) { - dispatch(updateNewMigrationData({ - ...newMigrationData, - legacy_cms: { - ...newMigrationData?.legacy_cms, - isFileFormatCheckboxChecked: isCheckedBoxChecked - } - })); - await fileformatConfirmation(selectedOrganisation?.value, projectId, { - fileformat_confirmation: true - }); - - //call for Step Change - props.handleStepChange(props?.currentStep); - } - }; - - // Toggles checkbox selection - const handleCheckBoxChange = (e: ChangeEvent) => { - const { checked } = e.target; - setIsCheckedBoxChecked(checked); - }; - - const getFileExtension = (filePath: string): string => { - const ext = filePath.split('.').pop(); - return ext ? `${ext}` : 'zip'; - }; - - const handleFileFormat = async() =>{ - const apiRes: any = await getConfig(); - const cmsType = !isEmptyString(newMigrationData?.legacy_cms?.selectedCms?.parent) ? newMigrationData?.legacy_cms?.selectedCms?.parent : apiRes?.data?.cmsType?.toLowerCase(); - const filePath = apiRes?.data?.localPath?.toLowerCase(); - const fileFormat = getFileExtension(filePath); - if(! isEmptyString(selectedCard?.fileformat_id)){ - setFileIcon(selectedCard?.title); - } - else{ - const { all_cms = [] } = migrationData?.legacyCMSData || {}; - let filteredCmsData:any = all_cms; - if (cmsType) { - filteredCmsData = all_cms?.filter((cms: any) => cms?.parent?.toLowerCase() === cmsType?.toLowerCase()); - } - - const isFormatValid = filteredCmsData[0]?.allowed_file_formats?.find((format:any)=>{ - const isValid = format?.fileformat_id?.toLowerCase() === fileFormat?.toLowerCase(); - return isValid; - }); - - if(! isFormatValid){ - setIsError(true); - setError('File format does not support, please add the correct file format.'); - } - - const selectedFileFormatObj = { - description: "", - fileformat_id: fileFormat, - group_name: fileFormat, - isactive: true, - title: fileFormat === 'zip' ? fileFormat?.charAt(0)?.toUpperCase() + fileFormat?.slice(1) : fileFormat?.toUpperCase() - } - - - const newMigrationDataObj = { - ...newMigrationData, - legacy_cms: { - ...newMigrationData?.legacy_cms, - selectedFileFormat: selectedFileFormatObj - } - }; - - setFileIcon(fileFormat === 'zip' ? fileFormat?.charAt(0).toUpperCase() + fileFormat.slice(1) : fileFormat?.toUpperCase()); - dispatch(updateNewMigrationData(newMigrationDataObj)); - - } - - - } - - /**** ALL USEEffects HERE ****/ - useEffect(()=>{ - handleFileFormat(); - handleBtnClick(); - },[]); - - return (
diff --git a/ui/src/components/LegacyCms/Actions/LoadPrefix.tsx b/ui/src/components/LegacyCms/Actions/LoadPrefix.tsx index af7c68a3a..b5d0cd4c9 100644 --- a/ui/src/components/LegacyCms/Actions/LoadPrefix.tsx +++ b/ui/src/components/LegacyCms/Actions/LoadPrefix.tsx @@ -29,6 +29,12 @@ interface LoadSelectCmsProps { handleStepChange: (stepIndex: number, closeStep?: boolean) => void; } +/** + * Component for loading and handling the prefix in the Legacy CMS. + * @param {LoadSelectCmsProps} props - The component props. + * @returns {JSX.Element} The rendered component. + */ + const LoadPreFix = (props: LoadSelectCmsProps) => { /**** ALL HOOKS HERE ****/ const newMigrationData = useSelector((state:RootState)=>state?.migration?.newMigrationData); diff --git a/ui/src/components/LegacyCms/Actions/LoadSelectCms.tsx b/ui/src/components/LegacyCms/Actions/LoadSelectCms.tsx index 3c9ea52d5..960ead8dc 100644 --- a/ui/src/components/LegacyCms/Actions/LoadSelectCms.tsx +++ b/ui/src/components/LegacyCms/Actions/LoadSelectCms.tsx @@ -33,6 +33,13 @@ interface LoadSelectCmsProps { handleStepChange: (stepIndex: number, closeStep?: boolean) => void; } +/** + * Component for loading and selecting CMS data. + * + * @component + * @param {LoadSelectCmsProps} props - The component props. + * @returns {JSX.Element} The rendered component. + */ const LoadSelectCms = (props: LoadSelectCmsProps) => { /**** ALL HOOKS HERE ****/ const migrationData = useSelector((state:RootState)=>state?.migration?.migrationData); diff --git a/ui/src/components/LegacyCms/Actions/LoadUploadFile.tsx b/ui/src/components/LegacyCms/Actions/LoadUploadFile.tsx index ba112b787..aa3c62d8a 100644 --- a/ui/src/components/LegacyCms/Actions/LoadUploadFile.tsx +++ b/ui/src/components/LegacyCms/Actions/LoadUploadFile.tsx @@ -21,6 +21,11 @@ interface Props { fileDetails: FileDetails; } +/** + * Renders the file component based on the file details. + * @param {Props} fileDetails - The file details object. + * @returns {JSX.Element} The rendered file component. + */ const FileComponent = ({fileDetails}:Props ) => { return ( @@ -41,15 +46,32 @@ const FileComponent = ({fileDetails}:Props ) => { ); }; -const saveStateToLocalStorage = (state:any, projectId : string) => { +/** + * Saves the state to the local storage. + * @param state - The state object to be saved. + * @param projectId - The ID of the project. + */ +const saveStateToLocalStorage = (state: any, projectId: string) => { sessionStorage.setItem(`uploadProgressState_${projectId}`, JSON.stringify(state)); }; -const getStateFromLocalStorage = (projectId : string) => { +/** + * Retrieves the upload progress state from the session storage for a specific project. + * @param projectId - The ID of the project. + * @returns The upload progress state if found, otherwise null. + */ +const getStateFromLocalStorage = (projectId: string) => { const state = sessionStorage.getItem(`uploadProgressState_${projectId}`); return state ? JSON.parse(state) : null; }; +/** + * Component for loading and uploading a file. + * + * @component + * @param {LoadUploadFileProps} props - The component props. + * @returns {JSX.Element} The rendered component. + */ const LoadUploadFile = (props: LoadUploadFileProps) => { /**** ALL HOOKS HERE ****/ diff --git a/ui/src/components/LegacyCms/StepperSteps.ts b/ui/src/components/LegacyCms/StepperSteps.ts index 423bc0ce4..0dd02b51f 100644 --- a/ui/src/components/LegacyCms/StepperSteps.ts +++ b/ui/src/components/LegacyCms/StepperSteps.ts @@ -10,6 +10,14 @@ import UploadFileSummary from './Summary/UploadFileSummary'; import LoadPreFix from './Actions/LoadPrefix'; import PreFixSummary from './Summary/PreFixSummary'; +/** + * Returns an updated step object based on the provided parameters. + * + * @param step - The original step object. + * @param isCompleted - A boolean indicating whether the step is completed. + * @param isMigrationLocked - A boolean indicating whether the migration is locked. + * @returns The updated step object. + */ const getComponentObject = ( step: IStep, isCompleted: boolean, @@ -70,6 +78,14 @@ const getComponentObject = ( return updatedStep; }; +/** + * Retrieves the legacy CMS steps based on the provided parameters. + * + * @param isCompleted - A boolean indicating whether the steps are completed. + * @param isMigrationLocked - A boolean indicating whether the migration is locked. + * @param allSteps - An array of IStep objects representing all the steps. + * @returns An array of component objects representing the legacy CMS steps. + */ export const getLegacyCMSSteps = ( isCompleted: boolean, isMigrationLocked: boolean, diff --git a/ui/src/components/LegacyCms/Summary/FileFormatSummary.tsx b/ui/src/components/LegacyCms/Summary/FileFormatSummary.tsx index fe7311c22..3e63a1e41 100644 --- a/ui/src/components/LegacyCms/Summary/FileFormatSummary.tsx +++ b/ui/src/components/LegacyCms/Summary/FileFormatSummary.tsx @@ -14,6 +14,12 @@ interface FileFormatSummaryProps { stepData: IStep; } +/** + * Renders the file format summary component. + * + * @param {FileFormatSummaryProps} props - The component props. + * @returns {JSX.Element} The file format summary component. + */ const FileFormatSummary = ({ stepData }: FileFormatSummaryProps): JSX.Element => { const newMigrationData = useSelector((state:RootState)=>state?.migration?.newMigrationData); diff --git a/ui/src/components/LegacyCms/Summary/PreFixSummary.tsx b/ui/src/components/LegacyCms/Summary/PreFixSummary.tsx index de15eebe2..1d8da2970 100644 --- a/ui/src/components/LegacyCms/Summary/PreFixSummary.tsx +++ b/ui/src/components/LegacyCms/Summary/PreFixSummary.tsx @@ -13,6 +13,12 @@ interface PreFixSummaryProps { stepData: IStep; } +/** + * Renders the PreFixSummary component. + * + * @param {PreFixSummaryProps} props - The component props. + * @returns {JSX.Element} The rendered PreFixSummary component. + */ const PreFixSummary = (props: PreFixSummaryProps): JSX.Element => { const newMigrationData = useSelector((state:RootState)=>state?.migration?.newMigrationData); diff --git a/ui/src/components/LegacyCms/Summary/SelectCmsSummary.tsx b/ui/src/components/LegacyCms/Summary/SelectCmsSummary.tsx index 9d8d4beb5..bbb0dcc7d 100644 --- a/ui/src/components/LegacyCms/Summary/SelectCmsSummary.tsx +++ b/ui/src/components/LegacyCms/Summary/SelectCmsSummary.tsx @@ -12,6 +12,12 @@ interface SelectCmsSummaryProps { stepData: IStep; } +/** + * Renders the summary component for selecting CMS. + * + * @param {SelectCmsSummaryProps} props - The component props. + * @returns {JSX.Element} The rendered component. + */ const SelectCmsSummary = (props: SelectCmsSummaryProps): JSX.Element => { const newMigrationData = useSelector((state:RootState)=>state?.migration?.newMigrationData); diff --git a/ui/src/components/LegacyCms/Summary/UploadFileSummary.tsx b/ui/src/components/LegacyCms/Summary/UploadFileSummary.tsx index 11a160359..ff1f63ecc 100644 --- a/ui/src/components/LegacyCms/Summary/UploadFileSummary.tsx +++ b/ui/src/components/LegacyCms/Summary/UploadFileSummary.tsx @@ -18,6 +18,13 @@ interface Props { fileDetails: FileDetails; } +/** + * Renders the file component based on the provided file details. + * + * @param {Props} props - The component props. + * @param {FileDetails} props.fileDetails - The details of the file. + * @returns {React.ReactElement} The rendered file component. + */ export const FileComponent: React.FC = ({ fileDetails }) => { return ( @@ -38,13 +45,20 @@ export const FileComponent: React.FC = ({ fileDetails }) => { ); }; +/** + * Renders the summary component for uploading a file. + * + * @param {UploadFileSummaryProps} props - The component props. + * @returns {JSX.Element} The rendered component. + */ const UploadFileSummary = ({ stepComponentProps, stepData }: UploadFileSummaryProps): JSX.Element => { const newMigrationData = useSelector((state:RootState)=>state?.migration?.newMigrationData); - const [isLoading, setIsLoading] = useState(false); + const [isLoading, setIsLoading] = useState(false); + return (
{!isEmptyString(newMigrationData?.legacy_cms?.uploadedFile?.name) ? ( diff --git a/ui/src/components/LegacyCms/Summary/summary.scss b/ui/src/components/LegacyCms/Summary/summary.scss index bb9cb6e94..eccce6ada 100644 --- a/ui/src/components/LegacyCms/Summary/summary.scss +++ b/ui/src/components/LegacyCms/Summary/summary.scss @@ -1,4 +1,7 @@ @import '../../../scss/variables'; +/** + * Styles for the summary title. + */ .summary-title { //font-family: $font-family-primary; font-style: normal; @@ -10,30 +13,61 @@ margin-top: 3px; } +/** + * Styles for the disabled checkbox label. + */ .Checkbox input:disabled ~ .Checkbox__label { opacity: 1; } + +/** + * Styles for the checked checkbox. + */ .Checkbox.Checkbox--state-checked { display: flex; } + +/** + * Styles for the checkbox tick SVG. + */ .Checkbox .Checkbox__tick svg { display: block; } + +/** + * Styles for the checked and disabled checkbox. + */ .Checkbox.Checkbox--state-checked.Checkbox--state-disabled { color: #212121; opacity: 1; } + +/** + * Styles for the checkbox wrapper. + */ .Checkbox-wrapper .Checkbox { display: flex; } + +/** + * Styles for the checkbox label within the checkbox wrapper. + */ .Checkbox-wrapper .Checkbox .Checkbox__label { margin-top: -2px; } + +/** + * Styles for the disabled and checked checkbox label. + */ .Checkbox input:disabled:checked ~ .Checkbox__label, .Checkbox input:disabled:indeterminate ~ .Checkbox__label { color: #212121; opacity: 1; } + +/** + * Styles for the affix container. + */ .affix-container { display: flex; background-color: $color-base-white-5; diff --git a/ui/src/components/LegacyCms/index.tsx b/ui/src/components/LegacyCms/index.tsx index bea44d7fb..af8e1cb5a 100644 --- a/ui/src/components/LegacyCms/index.tsx +++ b/ui/src/components/LegacyCms/index.tsx @@ -33,6 +33,15 @@ type LegacyCMSComponentProps = { handleOnAllStepsComplete:(flag : boolean)=>void; }; +/** + * Represents the LegacyCMSComponent. + * @param legacyCMSData - The legacy CMS data. + * @param projectData - The project data. + * @param isCompleted - Indicates if the migration is completed. + * @param handleOnAllStepsComplete - The callback function for handling all steps completion. + * @param ref - The ref object. + * @returns The LegacyCMSComponent. + */ const LegacyCMSComponent = forwardRef(({ legacyCMSData, projectData, isCompleted, handleOnAllStepsComplete, }: LegacyCMSComponentProps, ref) => { //react-redux apis const migrationData = useSelector((state:RootState)=>state?.migration?.migrationData); diff --git a/ui/src/components/LegacyCms/legacyCms.scss b/ui/src/components/LegacyCms/legacyCms.scss index 647dfcd09..f01ece1ef 100644 --- a/ui/src/components/LegacyCms/legacyCms.scss +++ b/ui/src/components/LegacyCms/legacyCms.scss @@ -1,4 +1,8 @@ @import '../../scss/variables'; +/** + * Styles for the legacy CMS component. + */ + .service_list_legacy { text-align: center; display: flex; @@ -7,67 +11,105 @@ margin: 20px 20px ; } +/** + * Adds left padding of 40 pixels. + */ .pl-40 { padding-left: $px-40; } +/** + * Centers the element vertically. + */ .center-align { margin-top: calc(100vh - 65%); } +/** + * Styles for a small circular loader. + */ .CircularLoader--size-small { width: $px-80 !important; height: $px-80 !important; } +/** + * Styles for a circular loader. + */ .CircularLoader { display: inline-block !important; border-top: $px-5 solid $color-brand-primary-base !important; } -.legacy-cms-container { +/** + * Styles for the legacy CMS container. + */ +.legacy-cms-container { padding-left: 25px !important; padding-top: 26px; padding-right: 30px; - overflow-y: auto; overflow-x: hidden; max-height: 70vh; background-color: $color-base-white-10; - } +/** + * Styles for the search section in the legacy CMS. + */ .service_list_search { display: flex; margin: $space-15; } +/** + * Styles for the search bar in the legacy CMS. + */ .service_list_search_bar { flex: 15; margin-right: $px-15; height: $px-35; } +/** + * Styles for the search input in the search bar. + */ .service_list_search_bar .Search-input-show { width: 100%; } +/** + * Styles for the search button in the legacy CMS. + */ .service_list_search_button { flex: 1; } +/** + * Styles for the filter modal in the search button. + */ .service_list_search_button .Filter__modal { right: $px-15; } +/** + * Styles for the filter wrapper in the search button. + */ .service_list_search_button .Filter__wrapper { position: absolute; } +/** + * Styles for the filter icon in the search button. + */ .service_list_search_button .Filter__icon { min-height: $px-40; top: -8px; } + +/** + * Styles for the validation container. + */ .validation-container { display: flex; flex-direction: column; @@ -78,13 +120,20 @@ margin-left: 20px !important; border: 1px solid $color-brand-secondary-lightest; border-radius: var(--TermCount, 5px); - } + +/** + * Styles for the elements inside the validation container. + */ .validation-container > * { margin-right: 10px; margin-left: 15px; } -.error-container{ + +/** + * Styles for the error container. + */ +.error-container { display: flex; background-color: $color-base-white-5; height: 72px; @@ -95,27 +144,50 @@ border: 1px solid $color-brand-fail-base; border-radius: var(--TermCount, 5px); } + +/** + * Styles for the elements inside the error container. + */ .error-container > * { margin-left: 10px; margin-top: 5px; } +/** + * Styles for the error message. + */ .errorMessage { color: $color-brand-warning-medium; font-size: 12px; } -.validation-cta{ + +/** + * Styles for the validation call-to-action. + */ +.validation-cta { margin: $space-24 $space-20 0; line-height: 24px; } -.success{ + +/** + * Styles for the success message. + */ +.success { color: $color-brand-success-base; margin-top: 5px; } -.error{ + +/** + * Styles for the error message. + */ +.error { color: $color-brand-fail-base; } -.link-discription{ + +/** + * Styles for the link description. + */ +.link-discription { font-family: $font-family-primary; font-style: normal; font-weight: $font-weight-regular; @@ -125,27 +197,41 @@ margin-bottom: $space-10; margin-top: $space-10; } -.bar-container{ + +/** + * Styles for the bar container. + */ +.bar-container { height: 10px; width: 592px; align-items: center; margin-left: 20px !important; margin-top: 10px; } -.file-icon-group{ - display:flex; + +/** + * Styles for the file icon group. + */ +.file-icon-group { + display: flex; flex-direction: row; gap: 30px; } -.loader{ + +/** + * Styles for the loader. + */ +.loader { margin-left: 20px; - .CircularLoader--size-small{ + .CircularLoader--size-small { width: 2rem !important; height: 2rem !important; } - } -.processing-test{ +/** + * Styles for the processing test. + */ +.processing-test { margin-top: 5px; } \ No newline at end of file diff --git a/ui/src/components/LogScreen/index.scss b/ui/src/components/LogScreen/index.scss index 479c674b6..8efb6746a 100644 --- a/ui/src/components/LogScreen/index.scss +++ b/ui/src/components/LogScreen/index.scss @@ -1,4 +1,7 @@ @import '../../scss/variables'; +/** + * Styles for the LogScreen component. + */ .logs-container { font-family: Arial, sans-serif; @@ -8,8 +11,13 @@ margin: 0 $px-24 $px-24; position: relative; } + .logs-wrapper { position: relative; + + /** + * Styles for the action items within the LogScreen component. + */ .action-items { position: absolute; right: 48px; @@ -17,13 +25,16 @@ } } - +/** + * Styles for each log entry within the LogScreen component. + */ .log-entry { align-items: center; background-color: $color-base-white-10; display: flex; padding: 5px 0; position: relative; + &::before { background-color: $color-base-white-5; border-right: 1px solid $color-brand-secondary-lightest; @@ -36,30 +47,33 @@ width: 50px; } - .log-number, .log-time, .log-message { + /** + * Styles for the log number within each log entry. + */ + .log-number { + text-align: center; + min-width: 50px; + color: $color-font-active; + position: relative; + } + + /** + * Styles for the log time within each log entry. + */ + .log-time { + color: $color-font-active; font-family: "IBM Plex Mono", monospace; font-size: $size-font-medium; font-weight: $font-weight-medium; + padding: 0 $px-16; + } + + /** + * Styles for the log message within each log entry. + */ + .log-message { + color: $color-black-222; + flex-grow: 1; + padding: 0 $px-16; } -} - -.log-number { - text-align: center; - min-width: 50px; - color: $color-font-active; - position: relative; -} - -.log-time { - color: $color-font-active; - font-family: "IBM Plex Mono", monospace; - font-size: $size-font-medium; - font-weight: $font-weight-medium; - padding: 0 $px-16; -} - -.log-message { - color: $color-black-222; - flex-grow: 1; - padding: 0 $px-16; } diff --git a/ui/src/components/LogScreen/index.tsx b/ui/src/components/LogScreen/index.tsx index 81a601603..ad0dbae5f 100644 --- a/ui/src/components/LogScreen/index.tsx +++ b/ui/src/components/LogScreen/index.tsx @@ -1,5 +1,5 @@ // Libraries -import React, { useEffect, useState, useRef } from 'react'; +import React, { useEffect, useState } from 'react'; import { Icon } from '@contentstack/venus-components'; import io from 'socket.io-client'; @@ -17,61 +17,127 @@ type LogsType = { serverPath: string; } -const LogViewer = ({serverPath}: LogsType) => { +/** + * LogViewer component displays logs received from the server. + * @param {string} serverPath - The path of the server to connect to. + */ +const LogViewer = ({ serverPath }: LogsType) => { const [logs, setLogs] = useState(["Loading logs..."]); useEffect(() => { const socket = io(serverPath || ''); // Connect to the server + + /** + * Event listener for 'logUpdate' event. + * @param {string} newLogs - The new logs received from the server. + */ socket.on('logUpdate', (newLogs: string) => { - console.log("new logs", newLogs); - + // console.log("new logs", newLogs); const logArray = newLogs.split('\n'); - console.log(logArray); + // console.log(logArray); setLogs(logArray); - }); - + return () => { socket.disconnect(); // Cleanup on component unmount }; }, []); - - //SCROLL LISTENER - useEffect(() => { - window.addEventListener("scroll", handleScrollToTop); - }); - const refScrollUp = useRef(null); + /** + * Scrolls to the top of the logs container. + */ const handleScrollToTop = () => { - console.log("=============", refScrollUp, refScrollUp?.current); - - refScrollUp?.current?.scrollIntoView({ behavior: "smooth" }); + const logsContainer = document.querySelector('.logs-container'); + if (logsContainer) { + logsContainer.scrollTo({ + top: 0, + behavior: 'smooth', + }); + } + } + + /** + * Scrolls to the bottom of the logs container. + */ + const handleScrollToBottom = () => { + const logsContainer = document.querySelector('.logs-container'); + if (logsContainer) { + logsContainer.scrollTo({ + top: logsContainer.scrollHeight, + behavior: 'smooth', + }); + } } + + /** + * Copies the logs to the clipboard. + */ + const handleCopyLogs = () => { + const logsContainer = document.querySelector('.logs-container'); + if (logsContainer) { + const range = document.createRange(); + range.selectNode(logsContainer); + window.getSelection()?.removeAllRanges(); + window.getSelection()?.addRange(range); + navigator.clipboard.writeText(logsContainer.textContent || ''); + window.getSelection()?.removeAllRanges(); + } + } + + const [zoomLevel, setZoomLevel] = useState(1); + + /** + * Zooms in the logs container. + */ + const handleZoomIn = () => { + const logsContainer = document.querySelector('.logs-magnify') as HTMLElement; + if (logsContainer) { + setZoomLevel(prevZoomLevel => prevZoomLevel + 0.1); + logsContainer.style.transform = `scale(${zoomLevel})`; + } + }; + + /** + * Zooms out the logs container. + */ + const handleZoomOut = () => { + const logsContainer = document.querySelector('.logs-magnify') as HTMLElement; + if (logsContainer) { + setZoomLevel(prevZoomLevel => prevZoomLevel - 0.1); + logsContainer.style.transform = `scale(${zoomLevel})`; + } + }; + return (
- {logs?.map((log, index) => { - console.log(log); - try { - const logObject = JSON.parse(log); - const level = logObject.level; - const timestamp = logObject.timestamp; - const message = logObject.message; - return ( -
-
{index}
-
{new Date(timestamp).toTimeString().split(' ')[0]}
-
{message}
-
- ); - } catch (error) { - console.error('Invalid JSON string', error); - } - })} - +
+ {logs?.map((log, index) => { + // console.log(log); + try { + const logObject = JSON.parse(log); + const level = logObject.level; + const timestamp = logObject.timestamp; + const message = logObject.message; + return ( +
+
{index}
+
{new Date(timestamp).toTimeString().split(' ')[0]}
+
{message}
+
+ ); + } catch (error) { + console.error('Invalid JSON string', error); + } + })} +
+ + + +
); diff --git a/ui/src/components/MainHeader/index.scss b/ui/src/components/MainHeader/index.scss index 14a769e90..cc0cef2ac 100644 --- a/ui/src/components/MainHeader/index.scss +++ b/ui/src/components/MainHeader/index.scss @@ -1,5 +1,16 @@ @import '../../scss/variables'; +/** + * + * This SCSS file contains styles for the MainHeader component. + * The MainHeader component is a fixed header that appears at the top of the page. + * It includes a logo, organization wrapper, and dropdown menu. + * + * The styles in this file define the layout, colors, and behavior of the MainHeader component. + * It also includes styles for the dropdown menu items and the logo. + * + * The MainHeader component is used in the UI of the application to provide a consistent header across pages. + */ .mainheader { [class*="Profile_card"] { [class*="Dropdown__menu__list"] { diff --git a/ui/src/components/MainHeader/index.tsx b/ui/src/components/MainHeader/index.tsx index f1391406e..d6d728ea3 100644 --- a/ui/src/components/MainHeader/index.tsx +++ b/ui/src/components/MainHeader/index.tsx @@ -33,36 +33,46 @@ import NotificationModal from '../Common/NotificationModal'; // Styles import './index.scss'; +/** + * MainHeader component displays the main header of the application. + * It includes user information, organization selection, and logo. + */ const MainHeader = () => { - const user = useSelector((state:RootState)=>state?.authentication?.user); - const organisationsList = useSelector((state:RootState)=>state?.authentication?.organisationsList); - const selectedOrganisation = useSelector((state:RootState)=>state?.authentication?.selectedOrganisation); - const newMigrationData = useSelector((state:RootState)=> state?.migration?.newMigrationData); + // Selecting data from the Redux store + const user = useSelector((state: RootState) => state?.authentication?.user); + const organisationsList = useSelector((state: RootState) => state?.authentication?.organisationsList); + const selectedOrganisation = useSelector((state: RootState) => state?.authentication?.selectedOrganisation); + const newMigrationData = useSelector((state: RootState) => state?.migration?.newMigrationData); + // State variables const [data, setData] = useState({}); const [orgsList, setOrgsList] = useState([]); const [isModalOpen, setIsModalOpen] = useState(false); - const location = useLocation(); const navigate = useNavigate(); const dispatch = useDispatch(); const { logo, organization_label: organizationLabel } = data; + // Generating user initials const name = `${user?.first_name?.charAt(0)}${user?.last_name?.charAt(0)}`.toUpperCase() ?? ''; - + + /** + * Updates the organization list state. + * Sets the selected organization as default and updates the organization in local storage. + */ const updateOrganisationListState = () => { if (organisationsList) { - //set selected org as default + // Set selected org as default const list = organisationsList.map((org: IDropDown) => ({ ...org, default: org?.value === selectedOrganisation?.value })); - + setOrgsList(list); - - //Set organization in local storage, first check if selectedOrg.value exists, if not get org id from local storage and set. + + // Set organization in local storage, first check if selectedOrg.value exists, if not get org id from local storage and set. setDataInLocalStorage( 'organization', selectedOrganisation?.value || getDataFromLocalStorage('organization') @@ -70,8 +80,12 @@ const MainHeader = () => { } }; + /** + * Fetches data for the main header. + * Reads data from CMS data file if the offline CMS data field is set to true. + */ const fetchData = async () => { - //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 so, read data from CMS data file. getCMSDataFromFile(CS_ENTRIES.MAIN_HEADER) .then((data) => setData(data)) .catch((err) => { @@ -87,7 +101,12 @@ const MainHeader = () => { useEffect(() => { updateOrganisationListState(); }, [selectedOrganisation]); - + + /** + * Handles the dropdown change event. + * Dispatches the selected organization and updates the organization in local storage. + * @param data - The selected dropdown item. + */ const handleOnDropDownChange = (data: IDropDown) => { if (data.value === selectedOrganisation.value) return; @@ -152,22 +171,24 @@ const MainHeader = () => { navigate(`/projects`, { replace: true }); } }; + return (
-
- {logo?.image?.url ? ( -
- - {/* */} - Contentstack - {/* */} - -
- ) : ( - '' - )} - - {location.pathname === '/projects' &&
+
+ {logo?.image?.url ? ( +
+ + {/* */} + Contentstack + {/* */} + +
+ ) : ( + '' + )} + + {location.pathname === '/projects' && ( +
{ withArrow onChange={handleOnDropDownChange} > -
}
+ )} +
- {(location.pathname == '/projects' || location.pathname.includes('/projects/')) &&
-
- , - } - ]} - type="click" - className="Profile_card" - > -
{name}
-
-
-
} + {(location.pathname == '/projects' || location.pathname.includes('/projects/')) && ( +
+
+ + } + ]} + type="click" + className="Profile_card" + > +
{name}
+
+
+
+ )}
); }; diff --git a/ui/src/components/MainHeader/mainheader.interface.ts b/ui/src/components/MainHeader/mainheader.interface.ts index df7d11cf3..d4d1d1342 100644 --- a/ui/src/components/MainHeader/mainheader.interface.ts +++ b/ui/src/components/MainHeader/mainheader.interface.ts @@ -1,5 +1,8 @@ import { Logo } from '../../types/common.interface'; +/** + * Represents the type definition for the MainHeader component. + */ export interface MainHeaderType { log_out?: string; logo?: Logo; diff --git a/ui/src/components/MigrationExecution/MigrationExecution.scss b/ui/src/components/MigrationExecution/MigrationExecution.scss index 09cc16c8b..3dd85eb00 100644 --- a/ui/src/components/MigrationExecution/MigrationExecution.scss +++ b/ui/src/components/MigrationExecution/MigrationExecution.scss @@ -1,12 +1,17 @@ @import '../../scss/App.scss'; @import '../../scss/variables'; +/** + * Styles for the MigrationExecution component. + */ + .select-wrapper { display: flex; align-items: center; justify-content: space-around; margin-left: 5px; } + .terminal-container { background-color: #000; color: #fff; @@ -23,6 +28,7 @@ div .step-component .action-component-body { width: 100% !important; margin-left: 0px !important; } + .cta-wrapper { border-top: 1px solid $color-base-gray-40; bottom: 0; @@ -34,11 +40,13 @@ div .step-component .action-component-body { width: 100%; z-index: 1; } + .selectedOptions { color: $color-base-gray-20; padding: 5px 10px; margin: 5px; } + .icon-wrapper { display: flex; margin-left: 30px; /* Adds space to the left of the icon */ diff --git a/ui/src/components/MigrationExecution/index.scss b/ui/src/components/MigrationExecution/index.scss index 42f81c48b..b41e866b1 100644 --- a/ui/src/components/MigrationExecution/index.scss +++ b/ui/src/components/MigrationExecution/index.scss @@ -1,6 +1,10 @@ @import '../../scss/App.scss'; @import '../../scss/variables'; +/** + * Styles for the MigrationExecution component. + */ + .select-wrapper { display: flex; align-items: center; @@ -8,9 +12,11 @@ margin-bottom: 0; } } + .content-body.step-desc { padding: 1rem 1.5rem; } + .terminal-container { background-color: #000; color: #fff; @@ -27,6 +33,7 @@ div .step-component .action-component-body { width: 100% !important; margin-left: 0px !important; } + .cta-wrapper { border-top: 1px solid $color-base-gray-40; bottom: 0; @@ -38,11 +45,13 @@ div .step-component .action-component-body { width: 100%; z-index: 1; } + .selectedOptions { color: $color-base-gray-20; padding: 5px 10px; margin: 5px; } + .arrow-wrapper { align-items: center; display: flex; diff --git a/ui/src/components/MigrationExecution/index.tsx b/ui/src/components/MigrationExecution/index.tsx index 2706f78c4..ffb6064a9 100644 --- a/ui/src/components/MigrationExecution/index.tsx +++ b/ui/src/components/MigrationExecution/index.tsx @@ -19,6 +19,9 @@ import { DEFAULT_MIGRATION_EXECUTION } from '../../context/app/app.interface'; //stylesheet import './index.scss'; +/** + * Component for handling migration execution. + */ const MigrationExecution = () => { //const { migrationData, updateMigrationData, newMigrationData } = useContext(AppContext); const dispatch = useDispatch(); @@ -48,6 +51,11 @@ const MigrationExecution = () => { }); }, []); + /** + * Get the placeholder value based on the title. + * @param title - The title of the field. + * @returns The placeholder value. + */ const getPlaceHolder = (title: string) => { switch (title) { case 'Uploaded CMS': diff --git a/ui/src/components/MigrationFlow/index.scss b/ui/src/components/MigrationFlow/index.scss index 32586b5a9..edc4ca96e 100644 --- a/ui/src/components/MigrationFlow/index.scss +++ b/ui/src/components/MigrationFlow/index.scss @@ -1,5 +1,9 @@ @import '../../scss/variables'; +/** + * Styles for the MigrationFlow component. + */ + .basicinfo-tab { cursor: pointer; padding-bottom: $space-20; @@ -16,6 +20,7 @@ } } } + .basic-info-block { margin: $space-10 $space-10 0; padding-left: $space-12; @@ -26,6 +31,7 @@ color: $color-font-base; } } + .basic-info-block-active { background: $color-brand-white-base; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); @@ -40,6 +46,7 @@ font-weight: $font-weight-semi-bold; } } + .step-wrapper { padding: 15px 0; } diff --git a/ui/src/components/MigrationFlow/index.tsx b/ui/src/components/MigrationFlow/index.tsx index a20085b85..9fcc7f9bd 100644 --- a/ui/src/components/MigrationFlow/index.tsx +++ b/ui/src/components/MigrationFlow/index.tsx @@ -13,6 +13,17 @@ import { CARET_RIGHT } from '../../common/assets'; // Style import './index.scss'; +/** + * Renders the MigrationFlow component. + * + * @param {Object} props - The component props. + * @param {string} props.settingsText - The text for the settings. + * @param {Function} props.settingsClick - The click event handler for the settings. + * @param {boolean} props.showInfo - Indicates whether to show the info. + * @param {string} props.migrationStepsText - The text for the migration steps. + * @param {number} props.currentStep - The current step of the migration. + * @returns {JSX.Element} The rendered MigrationFlow component. + */ const MigrationFlow = ({ settingsText, settingsClick, diff --git a/ui/src/components/MigrationFlow/migrationFlow.interface.ts b/ui/src/components/MigrationFlow/migrationFlow.interface.ts index bbc4c0015..f6ced3e9f 100644 --- a/ui/src/components/MigrationFlow/migrationFlow.interface.ts +++ b/ui/src/components/MigrationFlow/migrationFlow.interface.ts @@ -1,7 +1,29 @@ +/** + * Represents the props for the MigrationFlow component. + */ export interface MigrationFlowProps { + /** + * The text to display for the settings. + */ settingsText: string; + + /** + * The text to display for the migration steps. + */ migrationStepsText: string; + + /** + * A callback function that is called when the settings are clicked. + */ settingsClick: () => void; + + /** + * A boolean value indicating whether to show the info. + */ showInfo: boolean; + + /** + * The current step of the migration flow. + */ currentStep: number; } diff --git a/ui/src/components/MigrationFlowHeader/index.scss b/ui/src/components/MigrationFlowHeader/index.scss index 61d7897ad..ee1a9bd1c 100644 --- a/ui/src/components/MigrationFlowHeader/index.scss +++ b/ui/src/components/MigrationFlowHeader/index.scss @@ -1,5 +1,12 @@ @import '../../scss/variables'; +/** + * Styles for the MigrationFlowHeader component. + * + * The MigrationFlowHeader component represents the header section of the migration flow. + * It provides styling for the background color, border, padding, position, width, and z-index. + * It also includes styling for the back button within the header. + */ .migration-flow-header { background-color: $color-base-white-10; border-bottom: 1px solid $color-base-gray-40; diff --git a/ui/src/components/MigrationFlowHeader/index.tsx b/ui/src/components/MigrationFlowHeader/index.tsx index 6187a1d26..a0456a20c 100644 --- a/ui/src/components/MigrationFlowHeader/index.tsx +++ b/ui/src/components/MigrationFlowHeader/index.tsx @@ -27,6 +27,15 @@ type MigrationFlowHeaderProps = { legacyCMSRef: React.MutableRefObject; }; +/** + * MigrationFlowHeader component displays the header of the migration flow. + * It includes the project name and a button to save and continue the migration process. + * + * @param handleOnClick - The function to handle the click event of the save and continue button. + * @param isLoading - A boolean indicating whether the save and continue button is in a loading state. + * @param isCompleted - A boolean indicating whether the migration process is completed. + * @param legacyCMSRef - A reference to the legacy CMS component. + */ const MigrationFlowHeader = ({ handleOnClick, isLoading, isCompleted , legacyCMSRef}: MigrationFlowHeaderProps) => { const [projectName, setProjectName] = useState(''); const [currentStep, setCurrentStep] = useState(0); diff --git a/ui/src/components/Migrations/NewMigration/ActionTitle.tsx b/ui/src/components/Migrations/NewMigration/ActionTitle.tsx index 2f3cb2e6d..6f47dfc0b 100644 --- a/ui/src/components/Migrations/NewMigration/ActionTitle.tsx +++ b/ui/src/components/Migrations/NewMigration/ActionTitle.tsx @@ -1,5 +1,13 @@ import { Tooltip } from '@contentstack/venus-components'; +/** + * Renders the action title component. + * + * @param {Object} props - The component props. + * @param {string} props.title - The title of the action. + * @param {string} props.stepName - The name of the step. + * @returns {JSX.Element} The rendered action title component. + */ export const ActionTitle = ({ title, stepName }: IActionTitleParams) => { return ( <> diff --git a/ui/src/components/Migrations/NewMigration/NewMigrationWrapper.scss b/ui/src/components/Migrations/NewMigration/NewMigrationWrapper.scss index db2d19a22..926f0b305 100644 --- a/ui/src/components/Migrations/NewMigration/NewMigrationWrapper.scss +++ b/ui/src/components/Migrations/NewMigration/NewMigrationWrapper.scss @@ -1,5 +1,9 @@ @import '../../../scss/variables'; +/** + * Styles for the NewMigrationWrapper component. + */ + .step-component .action-component-title { // height: 60px; // background: $color-brand-white-base; @@ -41,6 +45,7 @@ font-weight: $font-weight-semi-bold; flex: 2; } + #newMigration { .PageLayout.PageLayout--primary { display: flex; diff --git a/ui/src/components/Migrations/NewMigration/NewMigrationWrapper.tsx b/ui/src/components/Migrations/NewMigration/NewMigrationWrapper.tsx index 8847dbf83..60a44af4f 100644 --- a/ui/src/components/Migrations/NewMigration/NewMigrationWrapper.tsx +++ b/ui/src/components/Migrations/NewMigration/NewMigrationWrapper.tsx @@ -52,6 +52,10 @@ const MigrationExecutionComponentLazyLoaded = lazy( ); +/** + * Renders the wrapper component for creating a new migration. + * This component fetches project data and handles the flow steps. + */ const NewMigrationWrapper = () => { const params: Params = useParams(); const navigate = useNavigate(); diff --git a/ui/src/components/Modal/index.tsx b/ui/src/components/Modal/index.tsx index 3ec3cc865..b85d2f45e 100644 --- a/ui/src/components/Modal/index.tsx +++ b/ui/src/components/Modal/index.tsx @@ -22,6 +22,14 @@ import { useState } from 'react'; import { createProject } from '../../services/api/project.service'; +/** + * Modal component for creating a project. + * + * @component + * @param {ProjectModalProps} props - The props for the Modal component. + * @returns {JSX.Element} The rendered Modal component. + */ + const Modal = (props: ProjectModalProps) => { const { closeModal, diff --git a/ui/src/components/Modal/modal.interface.ts b/ui/src/components/Modal/modal.interface.ts index aeba5d278..116108d86 100644 --- a/ui/src/components/Modal/modal.interface.ts +++ b/ui/src/components/Modal/modal.interface.ts @@ -1,19 +1,62 @@ import { IDropDown } from '../../context/app/app.interface'; import { ModalType } from '../../pages/Projects/projects.interface'; +/** + * Represents a modal object. + */ export interface ModalObj { + /** + * Closes the modal. + */ closeModal: () => void; } +/** + * Represents the props for the ProjectModal component. + */ export interface ProjectModalProps { + /** + * The data for the modal. + */ modalData: ModalType; + + /** + * The selected organization from the dropdown. + */ selectedOrg: IDropDown; + + /** + * A function to close the modal. + */ closeModal: () => void; } +/** + * Represents the props for the SettingsModal component. + */ export interface SettingsModalProps { + /** + * The selected organization from the dropdown. + */ selectedOrg: IDropDown; + + /** + * The ID of the project. + */ projectId?: string; + + /** + * The name of the project. + */ projectName?: string; + + /** + * Callback function to close the modal. + */ closeModal: () => void; + + /** + * Function to navigate to a specific URL. + * @param url - The URL to navigate to. + */ navigate: (url: string) => void; } diff --git a/ui/src/components/ProfileHeader/index.scss b/ui/src/components/ProfileHeader/index.scss index 193fd1886..67f69b671 100644 --- a/ui/src/components/ProfileHeader/index.scss +++ b/ui/src/components/ProfileHeader/index.scss @@ -1,18 +1,26 @@ @import '../../scss/variables'; +/** + * Styles for the profile card component. + */ .profile-card { width: 300px; padding: 16px; - // background-color: #f8f9fa; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); text-align: center; } +/** + * Styles for the avatar in the profile card. + */ .profile-card__avatar { margin-bottom: 16px; } +/** + * Styles for the initials in the avatar. + */ .profile-card__initials { width: 64px; height: 64px; @@ -24,13 +32,18 @@ justify-content: center; font-size: 24px; margin: 12px auto; - } +/** + * Styles for the details section in the profile card. + */ .profile-card__details { margin-bottom: 16px; } +/** + * Styles for the name in the details section. + */ .profile-card__name { font-size: 16px; font-weight: 500; @@ -38,30 +51,45 @@ margin-bottom: 5px; } +/** + * Styles for the email in the details section. + */ .profile-card__email { font-size: 14px; color: #7f8c8d; margin-bottom: 5px; } +/** + * Styles for the logout section in the profile card. + */ .profile-card__logout { display: flex; align-items: center; cursor: pointer; color: #2c3e50; font-size: 14px; - height:56px; + height: 56px; } +/** + * Styles for the logout icon in the logout section. + */ .profile-card__logout-icon { margin-right: 8px; font-size: 16px; } +/** + * Styles for the logout text in the logout section. + */ .profile-card__logout-text { text-decoration: underline; } +/** + * Styles for the gray background element. + */ .profile-gray-background { min-height: 20px; position: absolute; @@ -72,6 +100,10 @@ background-color: #F9F8FF; z-index: 1; } + +/** + * Styles for the avatar element in the profile card. + */ .profile-card__avatar { z-index: 2; position: relative; diff --git a/ui/src/components/ProfileHeader/index.tsx b/ui/src/components/ProfileHeader/index.tsx index 63c3a9414..42b98c654 100644 --- a/ui/src/components/ProfileHeader/index.tsx +++ b/ui/src/components/ProfileHeader/index.tsx @@ -9,16 +9,25 @@ import { // Styles import './index.scss'; import { LOG_OUT } from '../../common/assets'; + +/** + * Renders the profile card component. + * @returns JSX element representing the profile card. + */ const ProfileCard = () => { - const user = useSelector((state:RootState)=>state?.authentication?.user); + const user = useSelector((state: RootState) => state?.authentication?.user); const name = `${user?.first_name?.charAt(0)}${user?.last_name?.charAt(0)}`.toUpperCase() ?? ''; const navigate = useNavigate(); - // Function for Logout - const handleLogout = () => { + + /** + * Handles the logout functionality. + */ + const handleLogout = () => { if (clearLocalStorage()) { navigate('/', { replace: true }); } }; + return (
diff --git a/ui/src/components/ProjectsHeader/index.tsx b/ui/src/components/ProjectsHeader/index.tsx index e52a4a05c..a99f8cc02 100644 --- a/ui/src/components/ProjectsHeader/index.tsx +++ b/ui/src/components/ProjectsHeader/index.tsx @@ -4,6 +4,19 @@ import { Button, Icon, PageHeader, Search } from '@contentstack/venus-components // Interface import { ProjectsHeaderType } from './projectsHeader.interface'; +/** + * Renders the ProjectsHeader component. + * + * @param {Object} props - The component props. + * @param {string} props.headingText - The heading text. + * @param {string} props.searchText - The search text. + * @param {Function} props.setSearchText - The function to set the search text. + * @param {string} props.searchPlaceholder - The search input placeholder text. + * @param {Object} props.cta - The call-to-action object. + * @param {Array} props.allProject - The array of all projects. + * @param {Function} props.handleModal - The function to handle modal. + * @returns {JSX.Element} The rendered ProjectsHeader component. + */ const ProjectsHeader = ({ headingText, searchText, @@ -14,6 +27,10 @@ const ProjectsHeader = ({ handleModal }: ProjectsHeaderType) => { let interval: ReturnType; + + /** + * Sets focus on the search input element. + */ function setFocus() { clearTimeout(interval); interval = setTimeout(() => { @@ -76,7 +93,6 @@ const ProjectsHeader = ({ ); - const pageActions: any = [ { label: cta && cta?.title && ( @@ -97,7 +113,7 @@ const ProjectsHeader = ({ type: 'primary' } ]; - + return ( <> void; + + /** + * The placeholder text for the search input in the ProjectsHeader component. + */ searchPlaceholder: string; + + /** + * A function to handle the modal in the ProjectsHeader component. + */ handleModal?: () => void; + + /** + * An array of projects for the ProjectsHeader component. + */ allProject: ProjectsObj[] | null; } diff --git a/ui/src/components/SchemaModal/index.scss b/ui/src/components/SchemaModal/index.scss index 8065e9dd7..868e9bdeb 100644 --- a/ui/src/components/SchemaModal/index.scss +++ b/ui/src/components/SchemaModal/index.scss @@ -1,5 +1,12 @@ @import '../../scss/variables'; +/** + * Styles for the SchemaModal component. + * + * The SchemaModal component is responsible for rendering a modal that displays a schema. + * It contains styles for various elements within the modal, such as the schema entries, icons, and chevrons. + * + */ .schema { min-height: 290px; } diff --git a/ui/src/components/SchemaModal/index.tsx b/ui/src/components/SchemaModal/index.tsx index 27bf9b88f..557c6c31b 100644 --- a/ui/src/components/SchemaModal/index.tsx +++ b/ui/src/components/SchemaModal/index.tsx @@ -10,6 +10,11 @@ import { FieldMapType } from '../ContentMapper/contentMapper.interface'; import './index.scss'; // Function for get icons +/** + * Retrieves the corresponding icon for a given field type. + * @param field - The field object containing the ContentstackFieldType property. + * @returns The icon name associated with the field type. + */ const getTopLevelIcons = (field: FieldMapType) => { const icons: Icons = { title: 'StarSmall', @@ -88,6 +93,10 @@ const getTopLevelIcons = (field: FieldMapType) => { return icons[field?.ContentstackFieldType as keyof Icons]; }; +/** + * Renders a tree view component based on the provided schema. + * @param schema - The schema data used to generate the tree view. + */ const TreeView = ({ schema = [] }: schemaType) => { const [nestedList, setNestedList] = useState([]); @@ -114,16 +123,29 @@ const TreeView = ({ schema = [] }: schemaType) => { setNestedList(data); }, [schema]); - // Check if schema is nested + /** + * Checks if a field has nested child fields. + * @param field - The field to check. + * @returns True if the field has nested child fields, false otherwise. + */ const hasNestedValue = (field: FieldMapType) => field && field?.child && field?.child?.length > 0; - // Remove Group name from its child + /** + * Removes the group name from a child field name. + * @param text - The child field name. + * @param groupName - The group name. + * @returns The child field name without the group name. + */ const getChildFieldName = (text?: string, groupName?: string) => { if (text?.startsWith(groupName + ' > ')) { return text?.replace(groupName + ' > ', ''); } }; + /** + * Handles the click event on a tree view item. + * @param event - The click event. + */ const handleClick = (event: React.MouseEvent) => { if (document?.querySelector('.iconsholder.active')) { document?.querySelector('.iconsholder.active')?.classList.remove('active'); @@ -145,6 +167,12 @@ const TreeView = ({ schema = [] }: schemaType) => { } }; + /** + * Generates the nested outline for a field. + * @param item - The field to generate the outline for. + * @param index - The index of the field. + * @returns The nested outline JSX. + */ const generateNestedOutline = (item: FieldMapType, index: number) => { return (
    0 ? '' : 'close'}> @@ -233,6 +261,12 @@ const TreeView = ({ schema = [] }: schemaType) => { ); }; +/** + * Renders a modal component for displaying a schema preview. + * + * @param props - The props for the SchemaModal component. + * @returns The rendered SchemaModal component. + */ const SchemaModal = (props: SchemaProps) => { return ( <> diff --git a/ui/src/components/SchemaModal/schemaModal.interface.ts b/ui/src/components/SchemaModal/schemaModal.interface.ts index 69bebfdd5..30d1cf262 100644 --- a/ui/src/components/SchemaModal/schemaModal.interface.ts +++ b/ui/src/components/SchemaModal/schemaModal.interface.ts @@ -1,5 +1,9 @@ import { FieldMapType } from '../ContentMapper/contentMapper.interface'; +/** + * Represents the Icons interface. + * This interface defines the structure of an object that contains various icon names. + */ export interface Icons { title?: string; text?: string; @@ -22,9 +26,24 @@ export interface Icons { tag?: string; experience_container?: string; } + +/** + * Represents the props for the SchemaModal component. + */ export interface SchemaProps { + /** + * The content type of the schema. + */ contentType?: string; + + /** + * A function to close the modal. + */ closeModal: () => void; + + /** + * The schema data as an array of FieldMapType. + */ schemaData: FieldMapType[]; } diff --git a/ui/src/components/SideBar/index.scss b/ui/src/components/SideBar/index.scss index dc581bd62..e5577565c 100644 --- a/ui/src/components/SideBar/index.scss +++ b/ui/src/components/SideBar/index.scss @@ -1,4 +1,10 @@ @import '../../scss/variables'; +/** + * Styles for the .recycle-wrapper class. + * + * The .recycle-wrapper class is used to style the wrapper element for the recycle component in the sidebar. + * It sets the margin-top to -1px, background-color to $color-brand-white-base, and z-index to 99. + */ .recycle-wrapper { margin-top: -1px; background-color: $color-brand-white-base; diff --git a/ui/src/components/SideBar/index.tsx b/ui/src/components/SideBar/index.tsx index 149ca958a..968282bf4 100644 --- a/ui/src/components/SideBar/index.tsx +++ b/ui/src/components/SideBar/index.tsx @@ -9,6 +9,12 @@ type SettingIconProp = { projectId: string; } +/** + * Renders the SideBar component. + * + * @param {SettingIconProp} props - The props object containing the projectId. + * @returns {JSX.Element} The rendered SideBar component. + */ const SideBar = ({projectId}: SettingIconProp) => { const navigate = useNavigate(); diff --git a/ui/src/components/Stepper/FlowStepper/FlowBlock.tsx b/ui/src/components/Stepper/FlowStepper/FlowBlock.tsx index 35a56243e..f30aee178 100644 --- a/ui/src/components/Stepper/FlowStepper/FlowBlock.tsx +++ b/ui/src/components/Stepper/FlowStepper/FlowBlock.tsx @@ -1,11 +1,23 @@ import React, { ReactNode } from 'react'; +/** + * Props for the FlowBlock component. + */ type FlowBlockProps = { children?: ReactNode; spear?: string; className?: string; }; +/** + * Represents a block in the flow stepper component. + * + * @param {FlowBlockProps} props - The props for the FlowBlock component. + * @param {ReactNode} props.children - The content of the FlowBlock component. + * @param {string} [props.spear=''] - The spear value for the FlowBlock component. + * @param {string} [props.className=''] - The additional CSS class name for the FlowBlock component. + * @returns {JSX.Element} The rendered FlowBlock component. + */ const FlowBlock = ({ children, spear = '', className = '' }: FlowBlockProps) => { return
    {children}
    ; }; diff --git a/ui/src/components/Stepper/FlowStepper/FlowBlockItem.tsx b/ui/src/components/Stepper/FlowStepper/FlowBlockItem.tsx index b7f330e73..faddf4d2e 100644 --- a/ui/src/components/Stepper/FlowStepper/FlowBlockItem.tsx +++ b/ui/src/components/Stepper/FlowStepper/FlowBlockItem.tsx @@ -12,6 +12,9 @@ import StepTitle from './StepTitle'; // Assets import { CARET_RIGHT } from '../../../common/assets'; +/** + * Props for the FlowBlockItem component. + */ interface FlowBlockItemProps { isActive?: boolean; isCompleted?: boolean; @@ -19,10 +22,17 @@ interface FlowBlockItemProps { onStepClick: (step: IFlowStep, isCompleted: boolean) => () => void; } +/** + * Represents a single block item in the flow stepper component. + */ const FlowBlockItem: FC = (props: FlowBlockItemProps) => { const [isHovered, setIsHovered] = useState(false); + /** + * Toggles the hover state of the block item. + * @param flag - The flag indicating whether the block item is being hovered. + */ const handleHoveredToggle = (flag: boolean) => () => { setIsHovered(flag); }; diff --git a/ui/src/components/Stepper/FlowStepper/FlowStepper.scss b/ui/src/components/Stepper/FlowStepper/FlowStepper.scss index cada94e2a..459713c9e 100644 --- a/ui/src/components/Stepper/FlowStepper/FlowStepper.scss +++ b/ui/src/components/Stepper/FlowStepper/FlowStepper.scss @@ -1,6 +1,11 @@ @import '../../../scss/variables'; +/** + * Styles for the FlowStepper component. + */ + .ft-block { + /* Background gradient for the block */ background: linear-gradient( rgb(247, 249, 252) $space-30, $color-base-gray-40 $space-20, @@ -16,6 +21,7 @@ } .ft-block-disabled { + /* Background gradient for the disabled block */ background: linear-gradient( rgb(247, 249, 252) $space-30, $color-base-gray-40 $space-20, @@ -49,6 +55,7 @@ } .ft-step-block-head:hover { + /* Hover styles for the step block head */ background: $color-brand-white-base; cursor: pointer; min-height: 78px; @@ -63,6 +70,7 @@ } .ft-step-block-head-active { + /* Styles for the active step block head */ background-color: white; border: 1px solid $color-base-gray-40; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); @@ -72,12 +80,15 @@ margin-left: -$space-10; min-height: 78px; } + .ft-block-item:has(.ft-step-block-head-disabled) { cursor: not-allowed; } + .ft-step-block-head-disabled { pointer-events: none; } + .ft-step-block-head-active:hover { background-color: white !important; cursor: pointer; diff --git a/ui/src/components/Stepper/FlowStepper/FlowStepper.tsx b/ui/src/components/Stepper/FlowStepper/FlowStepper.tsx index 70bba969b..3bad24b3f 100644 --- a/ui/src/components/Stepper/FlowStepper/FlowStepper.tsx +++ b/ui/src/components/Stepper/FlowStepper/FlowStepper.tsx @@ -26,6 +26,13 @@ type IProp = { currentStep: number; }; +/** + * FlowStepper component displays a stepper for the migration flow steps. + * + * @param {IProp} props - The component props. + * @param {number} props.currentStep - The current step of the migration flow. + * @returns {JSX.Element} The rendered FlowStepper component. + */ const FlowStepper = ({ currentStep }: IProp) => { /** ALL HOOKS Here */ const params = useParams(); @@ -34,6 +41,13 @@ const FlowStepper = ({ currentStep }: IProp) => { const migrationData = useSelector((state:any)=>state?.migration?.migrationData) + /** + * Handles the click event when a step is clicked in the stepper. + * + * @param {IFlowStep} step - The step object. + * @param {boolean} isCompleted - Indicates if the step is completed. + * @returns {Promise} A Promise that resolves when the click event is handled. + */ const onStepClick = (step: IFlowStep, isCompleted: boolean) => async () => { if (params?.stepId === `${step?.name}`) return; dispatch(updateMigrationData({ currentFlowStep: step })) diff --git a/ui/src/components/Stepper/FlowStepper/StepIcon.tsx b/ui/src/components/Stepper/FlowStepper/StepIcon.tsx index d7003e059..eef48ad80 100644 --- a/ui/src/components/Stepper/FlowStepper/StepIcon.tsx +++ b/ui/src/components/Stepper/FlowStepper/StepIcon.tsx @@ -1,11 +1,28 @@ import React from 'react'; import { addDomainInPath } from '../../../utilities/functions'; +/** + * Props for the StepIcon component. + */ type StepIconProps = { + /** + * The icon to be displayed. + */ icon?: string; + + /** + * Additional class name for the component. + */ className?: string; }; +/** + * Renders a step icon component. + * + * @param icon - The icon name. + * @param className - Additional CSS class names for the component. + * @returns The rendered step icon component. + */ const StepIcon = ({ icon = 'lightning', className = '' }: StepIconProps) => { return ( { return (
    diff --git a/ui/src/components/Stepper/FlowStepper/flowStep.interface.ts b/ui/src/components/Stepper/FlowStepper/flowStep.interface.ts index 15122194e..014db5c42 100644 --- a/ui/src/components/Stepper/FlowStepper/flowStep.interface.ts +++ b/ui/src/components/Stepper/FlowStepper/flowStep.interface.ts @@ -1,17 +1,64 @@ +/** + * Represents a flow step in the application. + */ export interface IFlowStep { + /** + * The group name of the flow step. + */ group_name?: string; + + /** + * The title of the flow step. + */ title: string; + + /** + * The description of the flow step. + */ description: string; + + /** + * The name of the flow step. + */ name: string; + + /** + * The ID of the flow that the step belongs to. + */ flow_id: string; + + /** + * Indicates whether the flow step is completed or not. + */ isCompleted: boolean; } +/** + * Represents the default flow step object. + */ export const DEFAULT_IFLOWSTEP: IFlowStep = { + /** + * The title of the flow step. + */ title: 'Legacy CMS', + /** + * The description of the flow step. + */ description: '', + /** + * The name of the flow step. + */ name: '1', + /** + * The ID of the flow. + */ flow_id: '', + /** + * The group name of the flow step. + */ group_name: '', + /** + * Indicates whether the flow step is completed or not. + */ isCompleted: false }; diff --git a/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.scss b/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.scss index 62e0b33df..d4616ab00 100644 --- a/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.scss +++ b/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.scss @@ -1,9 +1,14 @@ @import '../../../scss/variables'; +/** + * Styles for the horizontal stepper component. + */ + .stepper-wrapper { margin-top: 73px; position: fixed; } + .stepper { border-bottom: 1px solid $color-base-gray-40; display: flex; @@ -11,12 +16,12 @@ justify-content: space-between; gap: 0px; padding: 10px; + @media (max-width: 768px) { flex-direction: column; align-items: flex-start; } - -} +} .stepWrapperContainer { display: flex; @@ -24,8 +29,7 @@ justify-content: center; position: relative; flex: 0.6; - margin: 0 ; - + margin: 0; } .stepWrapper { @@ -36,9 +40,10 @@ position: relative; z-index: 1; - &.completed .badge{ - background-color:$color-brand-primary-base; + &.completed .badge { + background-color: $color-brand-primary-base; } + &.active .badge { background-color: white; border: $px-2 solid $color-brand-primary-base; @@ -67,14 +72,15 @@ overflow: hidden; white-space: nowrap; font-family: Inter; - } - &.disableEvents{ + + &.disableEvents { cursor: not-allowed; - opacity: 1 !important; + opacity: 1 !important; color: #475161 !important; } } + .stepWrapperContainer:has(.disableEvents) { cursor: not-allowed; } @@ -83,7 +89,7 @@ height: 4px; background-color: $color-brand-primary-base; flex-grow: 1; - margin: 0; + margin: 0; margin-bottom: 30px; border-radius: 4px; margin-left: -40px; @@ -95,14 +101,16 @@ flex-direction: column; align-items: center; } -.icon-wrapper{ + +.icon-wrapper { width: 16px; height: 11px; } -.disabled-connector{ + +.disabled-connector { background-color: $color-base-gray-40; flex-grow: 1; - margin: 0; + margin: 0; margin-bottom: 30px; border-radius: 4px; height: 4px; @@ -111,6 +119,7 @@ } /******************* Custom Classes *******************/ + .stepper-position { background-color: $color-brand-white-base; margin-top: 73px; @@ -119,6 +128,7 @@ width: calc(100% - 56px); z-index: 9; } + .stepContent { background-color: $color-base-white-10; height: calc(100vh - 56px); diff --git a/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.tsx b/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.tsx index 02ebf7231..c45132645 100644 --- a/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.tsx +++ b/ui/src/components/Stepper/HorizontalStepper/HorizontalStepper.tsx @@ -3,34 +3,101 @@ import { useNavigate, useParams } from 'react-router-dom'; import './HorizontalStepper.scss'; import { Icon } from '@contentstack/venus-components'; +/** + * Enum representing the status of a step in a horizontal stepper. + */ export enum StepStatus { + /** + * The step is currently active. + */ ACTIVE = "ACTIVE", + /** + * The step has been completed. + */ COMPLETED = "COMPLETED", + /** + * The step is disabled and cannot be accessed. + */ DISABLED = "DISABLED" } +/** + * Represents an array of steps in a horizontal stepper. + */ export type stepsArray = { + /** + * The unique identifier for the step. + */ id: string; + /** + * The title of the step. + */ title?: JSX.Element | string; + /** + * The data associated with the step. + */ data?: React.ReactElement; + /** + * The status of the step. + */ status?: StepStatus; }; +/** + * Props for the HorizontalStepper component. + */ export type stepperProps = { + /** + * An array of steps for the stepper. + */ steps: Array; + /** + * Optional class name for the stepper component. + */ className?: string; + /** + * Optional message or JSX element to display when the stepper is empty. + */ emptyStateMsg?: string | JSX.Element; + /** + * Additional props to be passed to each step component. + */ stepComponentProps?: any; + /** + * Determines whether to hide the tab view in the stepper. + */ hideTabView?: boolean; + /** + * Optional class name for the step content container. + */ stepContentClassName?: string; + /** + * Optional class name for the step title. + */ stepTitleClassName?: string; + /** + * Optional test ID for the stepper component. + */ testId?: string; }; +/** + * Represents the handles for the HorizontalStepper component. + */ export type HorizontalStepperHandles = { + /** + * Callback function to handle step change. + * @param currentStep - The current step number. + */ handleStepChange: (currentStep: number) => void; }; +/** + * A horizontal stepper component that displays a series of steps and allows navigation between them. + * @param props - The props for the HorizontalStepper component. + * @param ref - A ref object that can be used to access the imperative methods of the HorizontalStepper component. + * @returns The rendered HorizontalStepper component. + */ const HorizontalStepper = forwardRef( (props: stepperProps, ref: React.ForwardedRef) => { const { steps, className, emptyStateMsg, stepComponentProps, hideTabView, testId } = props; @@ -59,6 +126,10 @@ const HorizontalStepper = forwardRef( }, [stepId]); useImperativeHandle(ref, () => ({ + /** + * Changes the current step of the HorizontalStepper component. + * @param currentStep - The index of the step to change to. + */ handleStepChange: (currentStep: number) => { setShowStep(currentStep+ 1); setStepsCompleted(prev => { @@ -73,6 +144,10 @@ const HorizontalStepper = forwardRef( } })); + /** + * Sets the active step of the HorizontalStepper component and navigates to the corresponding URL. + * @param idx - The index of the step to set as active. + */ const setTabStep = (idx: number) => { if (stepsCompleted?.includes(idx) || stepsCompleted?.length === idx) { @@ -82,6 +157,9 @@ const HorizontalStepper = forwardRef( } }; + /** + * Renders the titles and circles for each step in the HorizontalStepper component. + */ const StepsTitleCreator: React.FC = () => (
    {steps?.map(({ id, title }, idx: number) => { diff --git a/ui/src/components/Stepper/VerticalStepper/AutoVerticalStepper.scss b/ui/src/components/Stepper/VerticalStepper/AutoVerticalStepper.scss index c185de9c1..19f514be0 100644 --- a/ui/src/components/Stepper/VerticalStepper/AutoVerticalStepper.scss +++ b/ui/src/components/Stepper/VerticalStepper/AutoVerticalStepper.scss @@ -1,23 +1,29 @@ @import '../../../scss/variables'; +/** + * Styles for the migration vertical stepper container. + */ .migration-vertical-stepper-container { display: flex; align-items: baseline; justify-content: flex-start; border-bottom: 1px solid $color-brand-secondary-lightest; gap: 8px; - - } +/** + * Styles for the stepper title. + */ .migration-vertical-stepper .stepper-title { margin-bottom: $space-10; margin: 10px 20px; color: $color-font-base; line-height: 21px; - } +/** + * Styles for the stepper description. + */ .migration-vertical-stepper .stepper-discription { font-family: 'Inter'; font-style: normal; @@ -29,6 +35,9 @@ margin: 10px 20px; } +/** + * Styles for the summery edit and summery lock icons. + */ .migration-vertical-stepper .summery-edit, .migration-vertical-stepper .summery-lock { position: absolute; @@ -36,11 +45,17 @@ right: $space-20; } +/** + * Styles for the summery edit and action icons. + */ .summery-edit, .action { top: 50%; } +/** + * Styles for the vertical stepper list items. + */ .StepperWrapper ol.Vertical > li:before { width: 2rem; height: 2rem; @@ -49,18 +64,30 @@ color: #475161 !important; } +/** + * Styles for the stepper title note. + */ .stepper-titleNote { font-size: $size-font-large; } +/** + * Styles for the active to disabled list item. + */ .StepperWrapper ol.Vertical > li.active__to__disabled { border-image: linear-gradient(0deg, #c0c0cd 0%, #0469e3 100%); } +/** + * Styles for the completed to active list item. + */ .StepperWrapper ol.Vertical > li.completed__to__active { border-image: linear-gradient(0deg, #6e6b86 0%, #007a52 100%); } +/** + * Styles for the list item bullet. + */ .StepperWrapper ol.Vertical > li::before { content: url('data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20x%3D%220.5%22%20y%3D%220.5%22%20width%3D%2223%22%20height%3D%2223%22%20rx%3D%2211.5%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%220.5%22%20y%3D%220.5%22%20width%3D%2223%22%20height%3D%2223%22%20rx%3D%2211.5%22%20stroke%3D%22%236E6B86%22%2F%3E%3C%2Fsvg%3E'); height: $space-24; @@ -69,19 +96,31 @@ background-color: transparent; } +/** + * Styles for the active list item bullet. + */ .StepperWrapper ol.Vertical > li.active::before { content: url('data:image/svg+xml,%3Csvg%20width%3D%2225%22%20height%3D%2224%22%20viewBox%3D%220%200%2025%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20x%3D%221%22%20y%3D%220.5%22%20width%3D%2223%22%20height%3D%2223%22%20rx%3D%2211.5%22%20fill%3D%22%23F5FDFF%22%2F%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M6.8889%2014.2536C6.73737%2014.4051%206.64671%2014.607%206.63413%2014.8209L6.50155%2017.0748C6.47078%2017.5978%206.90341%2018.0305%207.42642%2017.9997L9.68032%2017.8671C9.89425%2017.8545%2010.0961%2017.7639%2010.2477%2017.6123L18.245%209.61504C18.5867%209.27333%2018.5867%208.71931%2018.245%208.3776L16.1236%206.25628C15.7819%205.91457%2015.2279%205.91457%2014.8862%206.25628L6.8889%2014.2536ZM7.38283%2014.865C7.38463%2014.8344%207.39758%2014.8056%207.41923%2014.7839L13.9668%208.23635L16.1635%2010.433C16.1994%2010.469%2016.2408%2010.4961%2016.285%2010.5144L9.71733%2017.082C9.69568%2017.1037%209.66684%2017.1166%209.63628%2017.1184L7.38238%2017.251C7.30766%2017.2554%207.24586%2017.1936%207.25025%2017.1189L7.38283%2014.865ZM16.7751%2010.0242L17.7146%209.08471C17.7634%209.03589%2017.7634%208.95675%2017.7146%208.90793L15.5933%206.78661C15.5445%206.7378%2015.4654%206.7378%2015.4165%206.78661L14.4971%207.70602L16.6938%209.90271C16.7297%209.93862%2016.7568%209.98002%2016.7751%2010.0242Z%22%20fill%3D%22%230469E3%22%2F%3E%3Crect%20x%3D%221%22%20y%3D%220.5%22%20width%3D%2223%22%20height%3D%2223%22%20rx%3D%2211.5%22%20stroke%3D%22%230469E3%22%2F%3E%3C%2Fsvg%3E'); } +/** + * Styles for the completed list item bullet. + */ .StepperWrapper ol.Vertical > li.completed::before { content: url('data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20x%3D%220.5%22%20y%3D%220.5%22%20width%3D%2223%22%20height%3D%2223%22%20rx%3D%2211.5%22%20fill%3D%22%23F5FFFC%22%2F%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M17.7652%208.23483C17.9116%208.38128%2017.9116%208.61872%2017.7652%208.76517L10.7652%2015.7652C10.6187%2015.9116%2010.3813%2015.9116%2010.2348%2015.7652L6.73483%2012.2652C6.58839%2012.1187%206.58839%2011.8813%206.73483%2011.7348C6.88128%2011.5884%207.11872%2011.5884%207.26517%2011.7348L10.5%2014.9697L17.2348%208.23483C17.3813%208.08839%2017.6187%208.08839%2017.7652%208.23483Z%22%20fill%3D%22%23007A52%22%2F%3E%3Crect%20x%3D%220.5%22%20y%3D%220.5%22%20width%3D%2223%22%20height%3D%2223%22%20rx%3D%2211.5%22%20stroke%3D%22%23007A52%22%2F%3E%3C%2Fsvg%3E'); border: none; } +/** + * Styles for the stepper step. + */ .StepperWrapper__step { padding: $space-10; } +/** + * Styles for the action summary wrapper. + */ .action-summary-wrapper { padding: $space-4 $space-24; align-items: center; @@ -90,6 +129,9 @@ background: $color-brand-white-base; } +/** + * Styles for the action content wrapper. + */ .action-content-wrapper { box-shadow: rgba(0, 0, 0, 0.1) 0 $space-20 $space-30 0; opacity: 1; @@ -98,19 +140,30 @@ border-radius: 10px; } +/** + * Styles for the configure action logo. + */ .configure_action_logo { width: $space-24; height: $space-24; margin-right: $space-10; } -.step_block{ + +/** + * Styles for the step block. + */ +.step_block { border-radius: 4px; border: 1px solid $color-brand-secondary-lightest; background-color: $color-brand-white-base; - padding: 24px 30px, 24px, 30px; + padding: 24px 30px, 24px, 30px; gap: 24px; margin-bottom: 40px; } + +/** + * Styles for the organization wrapper. + */ .orgWrapper { display: flex; align-items: baseline; @@ -119,11 +172,15 @@ color: $color-stepper-title; } } + +/** + * Styles for the asterisk input. + */ .asterisk_input::after { - content:" *"; + content: " *"; color: $color-brand-warning-medium; - margin: 2px 0px 0px -15px; - font-size:medium; - padding: 10px 5px 0 0 !important; + margin: 2px 0px 0px -15px; + font-size: medium; + padding: 10px 5px 0 0 !important; padding-left: .25em; } \ No newline at end of file diff --git a/ui/src/components/Stepper/VerticalStepper/AutoVerticalStepper.tsx b/ui/src/components/Stepper/VerticalStepper/AutoVerticalStepper.tsx index 7c524f3f7..139e1b573 100644 --- a/ui/src/components/Stepper/VerticalStepper/AutoVerticalStepper.tsx +++ b/ui/src/components/Stepper/VerticalStepper/AutoVerticalStepper.tsx @@ -3,26 +3,76 @@ import './AutoVerticalStepper.scss'; import { Heading, Paragraph } from '@contentstack/venus-components'; +/** + * Enum representing the status of a step in a vertical stepper. + */ export enum StepStatus { + /** + * The step is currently active. + */ ACTIVE = 'ACTIVE', + /** + * The step has been completed. + */ COMPLETED = 'COMPLETED', + /** + * The step is disabled and cannot be accessed. + */ DISABLED = 'DISABLED' } +/** + * Props for the AutoVerticalStepper component. + */ type AutoVerticalStepperProps = { steps: any[]; className?: string; description?: string; stepComponentProps?: any; isEdit: boolean; - isRequired:boolean; + isRequired: boolean; handleOnAllStepsComplete: (flag: boolean) => void; }; +/** + * Represents the handles for the AutoVerticalStepper component. + */ export type AutoVerticalStepperComponentHandles = { + /** + * Handles the dynamic step change in the AutoVerticalStepper. + * @param stepIndex - The index of the step to change to. + * @param closeStep - Optional parameter to indicate if the step should be closed. + */ handleDynamicStepChange: (stepIndex: number, closeStep?: boolean) => void; }; +/** + * Represents a vertical stepper component that automatically manages the steps and their statuses. + * + * @component + * @example + * ```tsx + * { + * console.log('All steps completed'); + * }} + * /> + * ``` + * + * @param props - The component props. + * @param props.steps - An array of step objects. + * @param props.className - The CSS class name for the stepper component. + * @param props.description - The description for the stepper component. + * @param props.stepComponentProps - Additional props to be passed to the step components. + * @param props.isEdit - A boolean indicating whether the stepper is in edit mode. + * @param props.handleOnAllStepsComplete - A callback function to be called when all steps are completed. + * @returns The rendered `AutoVerticalStepper` component. + */ const AutoVerticalStepper = React.forwardRef< AutoVerticalStepperComponentHandles, React.PropsWithChildren diff --git a/ui/src/components/TestMigration/index.scss b/ui/src/components/TestMigration/index.scss index 8a8473c15..1f5592650 100644 --- a/ui/src/components/TestMigration/index.scss +++ b/ui/src/components/TestMigration/index.scss @@ -1,6 +1,13 @@ @import '../../scss/App.scss'; @import '../../scss/variables'; +/** + * Styles for the migration step container. + * + * The migration step container is a container element that holds the content of a migration step. + * It has a maximum height of 70% of the viewport height and enables vertical scrolling when the content exceeds the container's height. + * Horizontal scrolling is disabled. + */ .migration-step-container { max-height: 70vh; overflow-y: auto; diff --git a/ui/src/components/TestMigration/index.tsx b/ui/src/components/TestMigration/index.tsx index a4bdf8b76..6f0d18a8d 100644 --- a/ui/src/components/TestMigration/index.tsx +++ b/ui/src/components/TestMigration/index.tsx @@ -17,6 +17,11 @@ import LogViewer from '../LogScreen'; // CSS import './index.scss'; +/** + * TestMigration component. + * This component displays the UID and allows the user to select their current Content Management System. + * It also displays the execution logs using the LogViewer component. + */ const TestMigration = () => { const [data, setData] = useState({}); diff --git a/ui/src/components/TestMigration/testMigration.interface.ts b/ui/src/components/TestMigration/testMigration.interface.ts index cfc3427f8..086bdb2c5 100644 --- a/ui/src/components/TestMigration/testMigration.interface.ts +++ b/ui/src/components/TestMigration/testMigration.interface.ts @@ -1,9 +1,22 @@ +/** + * Represents the migration type. + */ export interface MigrationType { cta?: CTA; subtitle?: string; } +/** + * Represents a Call to Action (CTA) button. + */ export interface CTA { + /** + * The title of the CTA button. + */ title?: string; + + /** + * The URL that the CTA button should navigate to. + */ url?: string; } diff --git a/ui/src/components/layout/AppLayout/index.tsx b/ui/src/components/layout/AppLayout/index.tsx index 9fe955566..dd17126ea 100644 --- a/ui/src/components/layout/AppLayout/index.tsx +++ b/ui/src/components/layout/AppLayout/index.tsx @@ -13,6 +13,12 @@ type IProps = { children?: ReactNode; }; +/** + * Represents the layout component for the application. + * @param {Object} props - The component props. + * @param {React.ReactNode} props.children - The child components to render. + * @returns {JSX.Element} The rendered layout component. + */ const AppLayout: FC = ({ children }) => { const location = useLocation(); const dispatch = useDispatch(); diff --git a/ui/src/context/app/app.interface.ts b/ui/src/context/app/app.interface.ts index 52277bfe7..278665a75 100644 --- a/ui/src/context/app/app.interface.ts +++ b/ui/src/context/app/app.interface.ts @@ -6,94 +6,335 @@ import { ICardType, defaultCardType } from '../../components/Common/Card/card.in import { CTA } from '../../types/common.interface'; import { IFilterType } from '../../components/Common/Modal/FilterModal/filterModal.interface'; +/** + * Represents a Call-to-Action (CTA) object. + */ export interface ICTA { + /** + * The title of the CTA. + */ title: string; + + /** + * The URL or href of the CTA. + */ href: string; } +/** + * Represents a map of content types. + * The keys are strings and the values are also strings. + */ interface ContentTypeMap { [key: string]: string; } +/** + * Represents an organization. + */ export interface Organization { + /** + * The unique identifier of the organization. + */ uid: string; + + /** + * The name of the organization. + */ name: string; + + /** + * The plan ID of the organization. + */ plan_id: string; + + /** + * The expiration date of the organization's plan. + */ expires_on: string; + + /** + * Indicates whether the organization is enabled or not. + */ enabled: boolean; + + /** + * Indicates whether over-usage is allowed for the organization. + */ is_over_usage_allowed: boolean; + + /** + * The date and time when the organization was created. + */ created_at: string; + + /** + * The date and time when the organization was last updated. + */ updated_at: string; + + /** + * The tags associated with the organization. + */ tags: string[]; } +/** + * Represents a user in the application. + */ export interface User { + /** + * The email address of the user. + */ email: string; + + /** + * The username of the user. + */ username: string; + + /** + * The first name of the user. + */ first_name: string; + + /** + * The last name of the user. + */ last_name: string; + + /** + * The mobile number of the user. + */ mobile_number: string; + + /** + * The country code associated with the user's mobile number. + */ country_code: string; + + /** + * The organizations the user belongs to. + */ organizations: Organization[]; } + +/** + * Represents the details of a file. + */ export interface FileDetails { + /** + * Specifies whether the file path is a local path. + */ isLocalPath?: boolean; + + /** + * Specifies the type of CMS (Content Management System) for the file. + */ cmsType?: string; + + /** + * Specifies the local path of the file. + */ localPath?: string; + + /** + * Specifies the AWS (Amazon Web Services) data for the file. + */ awsData?: { + /** + * Specifies the AWS region for the file. + */ awsRegion?: string; + + /** + * Specifies the AWS bucket name for the file. + */ bucketName?: string; + + /** + * Specifies the AWS bucket key for the file. + */ buketKey?: string; }; } + +/** + * Represents a file object. + */ export interface IFile { + /** + * The unique identifier of the file. + */ id?: string; + + /** + * The name of the file. + */ name: string; + + /** + * The size of the file in bytes. + */ size?: number; + + /** + * The type of the file. + */ type?: string; + + /** + * The URL of the file. + */ url?: string; + + /** + * The validation status of the file. + */ validation?: string; + + /** + * The details of the file. + */ file_details?: FileDetails; + + /** + * Indicates whether the file has been validated. + */ isValidated: boolean; } +/** + * Represents a CMS Type. + * Extends the ICardType interface. + */ export interface ICMSType extends ICardType { allowed_file_formats: ICardType[]; doc_url: ICTA; parent: string; } +/** + * Represents a step in the application. + */ export interface IStep { + /** + * The unique identifier of the step. + */ step_id: string; + + /** + * The title of the step. + */ title: string; + + /** + * The description of the step. + */ description: string; + + /** + * The text to display when the step is locked. + */ step_lock_text?: string; + + /** + * The status of the step. + */ status?: string; + + /** + * Indicates whether the step is locked. + */ lock: boolean; + + /** + * Indicates whether the step is active. + */ active?: boolean; + + /** + * The data component to render for the step. + */ data?: (props: any) => JSX.Element; + + /** + * The summary component to render for the step. + */ summery?: (props: any) => JSX.Element; + + /** + * The placeholder text to display when the step is empty. + */ empty_step_placeholder?: string; } +/** + * Represents a URL type with a title and href. + */ export interface IURLType { title: string; href: string; } +/** + * Represents a legacy CMS component. + */ export interface ILegacyCMSComponent { + /** + * The title of the component. + */ title: string; + + /** + * An array of CMS types. + */ all_cms: ICMSType[]; + + /** + * The call-to-action text. + */ cta: string; + + /** + * An array of steps. + */ all_steps: IStep[]; + + /** + * The restricted keyword link. + */ restricted_keyword_link: IURLType; + + /** + * The text for the restricted keyword checkbox. + */ restricted_keyword_checkbox_text: string; + + /** + * The text for the file format checkbox. + */ file_format_checkbox_text: string; + + /** + * An array of filter types for CMS. + */ cmsFilterList: IFilterType[]; + + /** + * The affix call-to-action text. + */ affix_cta: string; + + /** + * The file format call-to-action text. + */ file_format_cta: string; } +/** + * Represents the interface for the destination stack component. + */ export interface IDestinationStackComponent { title: string; description: string; @@ -105,6 +346,10 @@ export interface IDestinationStackComponent { }; all_steps: IStep[]; } + +/** + * Represents the interface for content mapping. + */ export interface IContentMapping { content_types_heading: string; description: string; @@ -115,33 +360,64 @@ export interface IContentMapping { table_search_placeholder: ''; } +/** + * Represents the interface for MigrationExecution. + */ export interface MigrationExecution { disable: boolean; title: string; width: string; } + +/** + * Represents the migration execution information. + */ export interface IMigrationExecution { migration_information: MigrationExecution[]; } +/** + * Represents an action call-to-action (CTA). + */ interface ActionCta { + /** + * The title of the CTA. + */ title: string; + + /** + * The theme of the CTA. + */ theme: string; } +/** + * Represents the fields of a Contentstack object. + */ interface ContentstackFields { title: string; field_types: FieldTypes[]; } +/** + * Represents the types of fields. + */ interface FieldTypes { label: string; value: string; } + +/** + * Represents a locale. + */ interface locales { code: string; name: string; } + +/** + * Represents the interface for the legacy CMS. + */ export interface ILegacyCms { selectedCms: ICMSType; selectedFileFormat: ICardType; @@ -151,14 +427,25 @@ export interface ILegacyCms { isFileFormatCheckboxChecked: boolean; currentStep:number } + +/** + * Represents the destination stack information. + */ export interface IDestinationStack { selectedOrg: IDropDown; selectedStack: IDropDown; } + +/** + * Represents the interface for the content mapper. + */ export interface IContentMapper { content_type_mapping: ContentTypeMap; } +/** + * Represents the interface for a new migration. + */ export interface INewMigration { legacy_cms: ILegacyCms; destination_stack: IDestinationStack; @@ -166,18 +453,59 @@ export interface INewMigration { test_migration: ITestMigration; } +/** + * Represents the data structure for migration data. + */ export interface IMigrationData { + /** + * An array of all flow steps. + */ allFlowSteps: IFlowStep[]; + + /** + * The current flow step. + */ currentFlowStep: IFlowStep; + + /** + * The legacy CMS component data. + */ legacyCMSData: ILegacyCMSComponent; + + /** + * The destination stack component data. + */ destinationStackData: IDestinationStackComponent; + + /** + * The content mapping data. + */ contentMappingData: IContentMapping; + + /** + * The migration execution data. + */ migrationexecution: IMigrationExecution; + + /** + * The settings data. + */ settings: string; + + /** + * The heading for migration steps. + */ migration_steps_heading: string; + + /** + * The test migration data. + */ testmigrationData: ITestMigration; } +/** + * Represents a dropdown item. + */ export interface IDropDown { uid?: string; label: string; @@ -187,27 +515,100 @@ export interface IDropDown { locales: locales[]; created_at: string; } + +/** + * Represents the interface for the migration test. + */ export interface ITestMigration { stack_link: string; stack_api_key: string; } + +/** + * Represents the interface for the application context. + */ export interface IAppContext { + /** + * The authentication token. + */ authToken: string; + + /** + * Sets the authentication token. + * @param token - The authentication token. + */ setAuthToken: (token: string) => void; + + /** + * The user object. + */ user: User; + + /** + * Updates the user object. + * @param user - The updated user object. + */ updateUser: (user: User) => void; + + /** + * The list of organisations as dropdown options. + */ organisationsList: IDropDown[]; + + /** + * Updates the list of organisations. + * @param list - The updated list of organisations. + */ updateOrganisationsList: (list: IDropDown[]) => void; + + /** + * The selected organisation as a dropdown option. + */ selectedOrganisation: IDropDown; + + /** + * Updates the selected organisation. + * @param dropdown - The updated selected organisation. + */ updateSelectedOrganisation: (dropdown: IDropDown) => void; + + /** + * Indicates whether the user is authenticated or not. + */ isAuthenticated: boolean; + + /** + * Sets the authentication flag. + * @param flag - The authentication flag. + */ setIsAuthenticated: (flag: boolean) => void; + + /** + * The data for a new migration. + */ newMigrationData: INewMigration; + + /** + * Updates the data for a new migration. + * @param data - The updated data for a new migration. + */ updateNewMigrationData: (data: Partial) => void; + + /** + * The data for a migration. + */ migrationData: IMigrationData; + + /** + * Updates the data for a migration. + * @param data - The updated data for a migration. + */ updateMigrationData: (data: Partial) => void; } +/** + * Represents the default dropdown configuration. + */ export const DEFAULT_DROPDOWN: IDropDown = { label: '', value: '', @@ -218,6 +619,9 @@ export const DEFAULT_DROPDOWN: IDropDown = { created_at: '' }; +/** + * Represents the default organization. + */ export const DEFAULT_ORGANISATION: Organization = { uid: '', name: '', @@ -230,6 +634,9 @@ export const DEFAULT_ORGANISATION: Organization = { tags: [] }; +/** + * Represents the default user object. + */ export const DEFAULT_USER: User = { email: '', username: '', @@ -240,36 +647,114 @@ export const DEFAULT_USER: User = { organizations: [] }; +/** + * Represents a file with its details. + */ export const DEFAULT_FILE: IFile = { + /** + * The unique identifier of the file. + */ id: '', + /** + * The name of the file. + */ name: '', + /** + * The size of the file in bytes. + */ size: 0, + /** + * The type of the file. + */ type: '', + /** + * Additional details about the file. + */ file_details: { + /** + * Indicates if the file is a local path. + */ isLocalPath: false, + /** + * The type of the CMS (Content Management System) associated with the file. + */ cmsType: '', + /** + * The local path of the file. + */ localPath: '', + /** + * AWS (Amazon Web Services) data associated with the file. + */ awsData: { + /** + * The AWS region where the file is stored. + */ awsRegion: '', + /** + * The name of the AWS S3 bucket where the file is stored. + */ bucketName: '', + /** + * The key of the file in the AWS S3 bucket. + */ buketKey: '' } }, + /** + * Indicates if the file has been validated. + */ isValidated: false }; +/** + * Represents the default CMS type. + */ export const DEFAULT_CMS_TYPE: ICMSType = { + /** + * The allowed file formats for the CMS type. + */ allowed_file_formats: [], + + /** + * The title of the CMS type. + */ title: '', + + /** + * The description of the CMS type. + */ description: '', + + /** + * The group name of the CMS type. + */ group_name: '', + + /** + * The documentation URL for the CMS type. + */ doc_url: { + /** + * The href of the documentation URL. + */ href: '', + + /** + * The title of the documentation URL. + */ title: '' }, + + /** + * The parent of the CMS type. + */ parent: '' }; +/** + * Represents the default legacy CMS configuration. + */ export const DEFAULT_LEGACY_CMS: ILegacyCms = { selectedCms: DEFAULT_CMS_TYPE, selectedFileFormat: defaultCardType, @@ -280,20 +765,32 @@ export const DEFAULT_LEGACY_CMS: ILegacyCms = { currentStep:-1, }; +/** + * Represents the default destination stack. + */ export const DEFAULT_DESTINATION_STACK: IDestinationStack = { selectedOrg: DEFAULT_DROPDOWN, selectedStack: DEFAULT_DROPDOWN }; +/** + * Default content mapper object. + */ export const DEFAULT_CONTENT_MAPPER: IContentMapper = { content_type_mapping: {} }; +/** + * Default test migration object. + */ export const DEFAULT_TEST_MIGRATION: ITestMigration = { stack_link: '', stack_api_key: '' }; +/** + * Default new migration object. + */ export const DEFAULT_NEW_MIGRATION: INewMigration = { legacy_cms: DEFAULT_LEGACY_CMS, destination_stack: DEFAULT_DESTINATION_STACK, @@ -301,24 +798,63 @@ export const DEFAULT_NEW_MIGRATION: INewMigration = { test_migration: DEFAULT_TEST_MIGRATION }; +/** + * Represents the default URL type. + */ export const DEFAULT_URL_TYPE: IURLType = { title: '', href: '' }; +/** + * Represents the default legacy CMS data. + */ export const DEFAULT_LEGACY_CMS_DATA: ILegacyCMSComponent = { + /** + * The title of the legacy CMS component. + */ title: '', + /** + * An array of all CMS items. + */ all_cms: [], + /** + * The call-to-action text. + */ cta: '', + /** + * An array of all steps. + */ all_steps: [], + /** + * The restricted keyword link. + */ restricted_keyword_link: DEFAULT_URL_TYPE, + /** + * The list of CMS filter items. + */ cmsFilterList: [], + /** + * The text for the restricted keyword checkbox. + */ restricted_keyword_checkbox_text: '', + /** + * The text for the file format checkbox. + */ file_format_checkbox_text: '', + /** + * The affix call-to-action text. + */ affix_cta: '', + /** + * The file format call-to-action text. + */ file_format_cta: '' }; +/** + * Represents the default destination stack data. + */ export const DEFAULT_DESTINATION_STACK_DATA: IDestinationStackComponent = { title: '', cta: '', @@ -331,6 +867,9 @@ export const DEFAULT_DESTINATION_STACK_DATA: IDestinationStackComponent = { all_steps: [] }; +/** + * Represents the default content mapping data. + */ export const DEFAULT_CONTENT_MAPPING_DATA: IContentMapping = { content_types_heading: '', description: '', @@ -347,6 +886,9 @@ export const DEFAULT_CONTENT_MAPPING_DATA: IContentMapping = { table_search_placeholder: '' }; +/** + * Represents the default migration execution object. + */ export const DEFAULT_MIGRATION_EXECUTION: IMigrationExecution = { migration_information: [ { @@ -357,6 +899,9 @@ export const DEFAULT_MIGRATION_EXECUTION: IMigrationExecution = { ] }; +/** + * Default migration data object. + */ export const DEFAULT_MIGRATION_DATA: IMigrationData = { allFlowSteps: [], currentFlowStep: DEFAULT_IFLOWSTEP, @@ -369,32 +914,77 @@ export const DEFAULT_MIGRATION_DATA: IMigrationData = { testmigrationData: DEFAULT_TEST_MIGRATION }; +/** + * Default application context object. + */ export const DEFAULT_APP_CONTEXT: IAppContext = { + /** + * Authentication token. + */ authToken: '', + /** + * Function to set the authentication token. + */ setAuthToken: function (): void { return; }, + /** + * User object. + */ user: DEFAULT_USER, + /** + * Function to update the user object. + */ updateUser: function (): void { return; }, + /** + * Flag indicating whether the user is authenticated. + */ isAuthenticated: false, + /** + * Function to set the authentication status. + */ setIsAuthenticated: function (): void { return; }, + /** + * New migration data object. + */ newMigrationData: DEFAULT_NEW_MIGRATION, + /** + * Function to update the new migration data object. + */ updateNewMigrationData: function (): void { return; }, + /** + * Migration data object. + */ migrationData: DEFAULT_MIGRATION_DATA, + /** + * Function to update the migration data object. + */ updateMigrationData: function (): void { return; }, + /** + * List of organisations. + */ organisationsList: [], + /** + * Function to update the list of organisations. + */ updateOrganisationsList: function () { return; }, + /** + * Selected organisation object. + */ selectedOrganisation: DEFAULT_DROPDOWN, + /** + * Function to update the selected organisation object. + */ updateSelectedOrganisation: function (): void { return; } diff --git a/ui/src/context/app/app.provider.tsx b/ui/src/context/app/app.provider.tsx index 855669ca7..0ebc2ba57 100644 --- a/ui/src/context/app/app.provider.tsx +++ b/ui/src/context/app/app.provider.tsx @@ -35,6 +35,15 @@ type IProps = { children?: ReactNode; }; +/** + * Provides the AppContext for the application. + * + * @component + * @param {Object} props - The component props. + * @param {React.ReactNode} props.children - The child components. + * @returns {JSX.Element} The rendered component. + */ + const AppContextProvider: FC = ({ children }) => { //********* ALL STATES HERE *********/ const [authToken, setAuthToken] = useState(''); diff --git a/ui/src/hooks/index.ts b/ui/src/hooks/index.ts index 74c7e86bd..1a55a7ec3 100644 --- a/ui/src/hooks/index.ts +++ b/ui/src/hooks/index.ts @@ -1,4 +1,10 @@ // Use this hook for any frequent changes , that impect on performance +/** + * Creates a debounced version of a callback function. + * @param callback The callback function to be debounced. + * @param wait The debounce wait time in milliseconds (default: 250ms). + * @returns A debounced version of the callback function. + */ export function useDebouncer(callback: (...args: Params) => any, wait = 250) { let timeoutId: any = null; return (...args: Params) => { diff --git a/ui/src/pages/Errors/error.interface.ts b/ui/src/pages/Errors/error.interface.ts index db60669e6..a1f8fa97e 100644 --- a/ui/src/pages/Errors/error.interface.ts +++ b/ui/src/pages/Errors/error.interface.ts @@ -1,3 +1,6 @@ +/** + * Represents the error type. + */ export interface ErrorType { section_title: string; description: string; diff --git a/ui/src/pages/Errors/index.tsx b/ui/src/pages/Errors/index.tsx index 2e484f070..4806d976b 100644 --- a/ui/src/pages/Errors/index.tsx +++ b/ui/src/pages/Errors/index.tsx @@ -18,11 +18,21 @@ type IErrorProps = { children?: ReactNode; }; +/** + * Represents the ErrorPage component. + * @param {IErrorProps} props - The props for the ErrorPage component. + * @param {string} props.contentType - The content type. + * @param {ReactNode} props.children - The children of the ErrorPage component. + * @returns {JSX.Element} The rendered ErrorPage component. + */ const ErrorPage: FC = ({ contentType, children }: IErrorProps) => { const [data, setData] = useState(default_error_type); const { url, type } = contentType; + /** + * Fetches data for the ErrorPage component. + */ const fetchData = () => { // getContentByURL({ // contentType: type, diff --git a/ui/src/pages/Home/home.interface.ts b/ui/src/pages/Home/home.interface.ts index 1ae83303a..716ce7b7b 100644 --- a/ui/src/pages/Home/home.interface.ts +++ b/ui/src/pages/Home/home.interface.ts @@ -1,12 +1,33 @@ +/** + * Represents the type for the homepage. + */ export interface HomepageType { cta?: CTA; description?: string; heading?: string; } +/** + * Represents a Call to Action (CTA) item. + */ export interface CTA { + /** + * The title of the CTA. + */ title?: string; + + /** + * The URL of the CTA. + */ url?: string; + + /** + * The theme of the CTA. + */ theme?: string; + + /** + * Indicates whether the CTA should be displayed with an icon. + */ with_icon?: boolean; } diff --git a/ui/src/pages/Home/index.tsx b/ui/src/pages/Home/index.tsx index 2436eaf71..cee71e635 100644 --- a/ui/src/pages/Home/index.tsx +++ b/ui/src/pages/Home/index.tsx @@ -13,9 +13,15 @@ import { CS_ENTRIES } from '../../utilities/constants'; // Interface import { HomepageType } from './home.interface'; +/** + * Represents the Home page component. + */ const Home = () => { const [data, setData] = useState({}); + /** + * Fetches data for the Home page. + */ const fetchData = async () => { //check if offline CMS data field is set to true, if then read data from cms data file. getCMSDataFromFile(CS_ENTRIES.HOME_PAGE) diff --git a/ui/src/pages/Login/index.tsx b/ui/src/pages/Login/index.tsx index 0f343717f..aca3c73f1 100644 --- a/ui/src/pages/Login/index.tsx +++ b/ui/src/pages/Login/index.tsx @@ -39,6 +39,15 @@ import './index.scss'; import { AppContext } from '../../context/app/app.context'; +/** + * Login component for user authentication. + * + * @component + * @example + * return ( + * + * ) + */ const Login: FC = () => { const [data, setData] = useState({}); diff --git a/ui/src/pages/Login/login.interface.ts b/ui/src/pages/Login/login.interface.ts index 6eec0465d..266f54f08 100644 --- a/ui/src/pages/Login/login.interface.ts +++ b/ui/src/pages/Login/login.interface.ts @@ -2,11 +2,33 @@ import { NotificationItemProps } from '@contentstack/venus-components/build/comp import { ReactNode } from 'react'; import { CTA } from '../../types/common.interface'; +/** + * Represents the login type. + */ export interface LoginType { + /** + * The heading of the login page. + */ heading?: string; + + /** + * The login details. + */ login?: Login; + + /** + * The subtitle of the login page. + */ subtitle?: string; + + /** + * The two-factor authentication details. + */ two_factor_authentication?: TFA; + + /** + * The copyright text. + */ copyrightText?: string; } interface Login { @@ -37,6 +59,9 @@ interface SMS { pre_link_text?: string; } +/** + * Represents the interface for the login states. + */ export type IStates = { sso_loading: boolean; error: any; @@ -50,10 +75,16 @@ export type IStates = { submitted: boolean; }; +/** + * Represents the props for the Login component. + */ export interface IProps { children?: ReactNode; } +/** + * Represents the default states for the login interface. + */ export const defaultStates: IStates = { sso_loading: false, activeTab: 0, @@ -70,24 +101,62 @@ export const defaultStates: IStates = { submitted: false }; +/** + * Represents a user object. + */ export interface User { + /** + * The email address of the user. + */ email: string; + + /** + * The password of the user. + */ password: string; + + /** + * The region of the user. (Optional) + */ region?: string | null; + + /** + * The two-factor authentication token of the user. (Optional) + */ tfa_token?: string | null; } +/** + * Represents the response object returned by the server when a user logs in. + */ export interface UserRes { + /** + * The message associated with the response. + */ message?: string; + + /** + * The status code of the response. + */ status?: number; + + /** + * The data payload of the response. + */ data?: Response; } +/** + * Represents the response object returned from the login API. + */ interface Response { notice?: string; error_message?: string; } +/** + * Represents the SMS token used for login. + */ export interface SmsToken { email: string; password: string; diff --git a/ui/src/pages/Migration/index.tsx b/ui/src/pages/Migration/index.tsx index 8fb6b009d..7a3f78f93 100644 --- a/ui/src/pages/Migration/index.tsx +++ b/ui/src/pages/Migration/index.tsx @@ -36,6 +36,13 @@ import TestMigration from '../../components/TestMigration'; import MigrationExecution from '../../components/MigrationExecution'; import { Notification } from '@contentstack/venus-components'; +/** + * Represents the Migration component. + * This component is responsible for managing the migration process. + * It fetches data from the CMS file, updates the app context, and handles the step changes. + * It also renders the migration steps and provides navigation between them. + */ + const Migration = () => { const [projectData, setProjectData] = useState(); const [isLoading, setIsLoading] = useState(false); diff --git a/ui/src/pages/MigrationEditor/index.scss b/ui/src/pages/MigrationEditor/index.scss index 3cc4e4105..3959ee3f2 100644 --- a/ui/src/pages/MigrationEditor/index.scss +++ b/ui/src/pages/MigrationEditor/index.scss @@ -1,5 +1,11 @@ @import '../../scss/variables'; +/** + * Styles for the MigrationEditor page. + */ .migration-container { + /** + * Styles for the body section of the page layout. + */ #PageLayout__body { //display: flex; margin-left: 0; @@ -8,6 +14,10 @@ padding: 0; overflow: hidden; } + + /** + * Styles for the page title. + */ .PageTitle { margin-left: 1rem; font-weight: 700; @@ -18,6 +28,10 @@ white-space: nowrap; line-height: normal; } + + /** + * Styles for the step flow wrapper tree area. + */ .step-flow-wrapper-tree-area { // border-right: 1px solid $color-base-gray-40; display: flex; @@ -26,6 +40,10 @@ max-height: 94vh; min-height: calc(100vh - 115px); } + + /** + * Styles for the step flow wrapper content area. + */ .step-flow-wrapper-content-area { display: flex; flex-direction: column; diff --git a/ui/src/pages/MigrationEditor/index.tsx b/ui/src/pages/MigrationEditor/index.tsx index 9fbceeee9..ecc85f947 100644 --- a/ui/src/pages/MigrationEditor/index.tsx +++ b/ui/src/pages/MigrationEditor/index.tsx @@ -18,6 +18,9 @@ import NewMigrationWrapper from '../../components/Migrations/NewMigration/NewMig import './index.scss'; import { updateNewMigrationData } from '../../store/slice/migrationDataSlice'; +/** + * Represents the Migration Editor page. + */ const MigrationEditor = () => { const navigate = useNavigate(); const params: Params = useParams(); diff --git a/ui/src/pages/Projects/index.scss b/ui/src/pages/Projects/index.scss index f814d301a..7266190a6 100644 --- a/ui/src/pages/Projects/index.scss +++ b/ui/src/pages/Projects/index.scss @@ -1,5 +1,9 @@ @import '../../scss/variables'; +/** + * Styles for the Projects page. + */ + .project-search-wrapper { margin-left: $px-12; .Search { @@ -32,6 +36,7 @@ } } } + .EmptyState__description { p { color: $color-font-base; @@ -48,6 +53,7 @@ } } } + .EmptyStateWrapper { .EmptyState { max-width: 35rem !important; diff --git a/ui/src/pages/Projects/index.tsx b/ui/src/pages/Projects/index.tsx index bfc9f6fc6..d85fdc265 100644 --- a/ui/src/pages/Projects/index.tsx +++ b/ui/src/pages/Projects/index.tsx @@ -36,6 +36,11 @@ import './index.scss'; import { getUserDetails } from '../../store/slice/authSlice'; +/** + * Renders the Projects page. + * + * @returns The Projects component. + */ const Projects = () => { const [data, setData] = useState({}); const { diff --git a/ui/src/pages/Projects/projects.interface.ts b/ui/src/pages/Projects/projects.interface.ts index 8f6aacfc2..e88afb1d8 100644 --- a/ui/src/pages/Projects/projects.interface.ts +++ b/ui/src/pages/Projects/projects.interface.ts @@ -1,5 +1,8 @@ import { CTA } from '../../types/common.interface'; +/** + * Represents the type definition for the ProjectsType interface. + */ export interface ProjectsType { cta?: CTA; restore_cta?: CTA; @@ -9,6 +12,9 @@ export interface ProjectsType { create_project_modal?: ModalType; } +/** + * Represents the interface for the ModalType object. + */ export interface ModalType { cta?: CTA[]; description?: string; @@ -20,6 +26,10 @@ export interface ModalType { primary_cta?: CTA; secondary_cta?: CTA; } + +/** + * Represents the empty state of a project. + */ interface EmptyState { cta?: CTA[]; description: string; @@ -28,12 +38,40 @@ interface EmptyState { empty_search_heading: string; empty_search_description: string; } + +/** + * Represents a project object. + */ export interface ProjectsObj { + /** + * The unique identifier of the project. + */ uid: string; + + /** + * The name of the project. + */ name: string; + + /** + * The creation date of the project. + */ created_at: string; + + /** + * The last update date of the project. + */ updated_at: string; + + /** + * The optional identifier of the project. + */ id?: string; + + /** + * The status of the project. + */ status: string; + // tags?: TagPill[]; } diff --git a/ui/src/pages/RegionalLogin/index.scss b/ui/src/pages/RegionalLogin/index.scss index 2e8ad1f31..f57ee8b02 100644 --- a/ui/src/pages/RegionalLogin/index.scss +++ b/ui/src/pages/RegionalLogin/index.scss @@ -1,15 +1,25 @@ @import '../../scss/variables'; +/** + * Styles for the RegionalLogin page. + */ .mainWrapper { display: flex; } +/** + * Styles for the cmsImageWrapper element. + */ .cmsImageWrapper { background-color: #6c5ce7; height: 100vh; max-width: 35%; flex: 0 0 35%; } + +/** + * Styles for the formWrapper element. + */ .formWrapper { align-items: center; display: flex; @@ -18,9 +28,16 @@ max-width: 65%; } +/** + * Styles for the textStone600 class. + */ .textStone600 { color: $color-font-gray; } + +/** + * Styles for the card element. + */ .card { border: 3px solid transparent; box-shadow: 0 $space-4 $space-20 0 rgba(0, 0, 0, 0.1); @@ -32,37 +49,73 @@ background-color: $color-base-white-5; background-clip: border-box; border-radius: 0.5rem; + + /** + * Styles for the card element when hovered. + */ &:hover { border: 3px solid #7c4dff; + + /** + * Styles for link-arrow elements inside the card element when hovered. + */ [class*='link-arrow'] { &:after { margin-left: $space-4; } } + + /** + * Styles for anchor elements inside the card element when hovered. + */ a { text-decoration: none; } } + + /** + * Styles for the cardBody element inside the card element. + */ .cardBody { color: $color-font-black; flex: 1 1 auto; padding: 1.25rem 1.25rem; + + /** + * Styles for the h2 element inside the cardBody element. + */ h2 { font-size: 1.25rem; font-weight: 700; letter-spacing: 0; } + + /** + * Styles for the p element inside the cardBody element. + */ p { color: $color-font-black; } } + + /** + * Styles for the CardFooter element inside the card element. + */ .CardFooter { background-color: rgba(0, 0, 0, 0); border-top: 0 solid rgba(34, 34, 34, 0.125); padding: 0.625rem 1.25rem; + + /** + * Styles for the stretched-link class inside the CardFooter element. + */ .stretched-link { line-height: $line-height-default; } + + /** + * Styles for link-arrow elements inside the CardFooter element. + */ [class*='link-arrow'] { &:after { top: 6px; diff --git a/ui/src/pages/RegionalLogin/index.tsx b/ui/src/pages/RegionalLogin/index.tsx index 2af72a937..ecbe8df6f 100644 --- a/ui/src/pages/RegionalLogin/index.tsx +++ b/ui/src/pages/RegionalLogin/index.tsx @@ -16,11 +16,17 @@ import { RegionType } from './regionalLogin.interface'; // Style import './index.scss'; +/** + * Component for regional login. + */ const RegionalLogin = () => { const [data, setData] = useState({}); const navigate = useNavigate(); + /** + * Fetches data from CMS. + */ const fetchData = async () => { //check if offline CMS data field is set to true, if then read data from cms data file. await getCMSDataFromFile(CS_ENTRIES.REGIONS) @@ -35,6 +41,11 @@ const RegionalLogin = () => { fetchData(); }, []); + /** + * Handles the login click event. + * @param regionName - The name of the region. + * @param serviceName - The name of the service. + */ const loginClick = (regionName: string, serviceName: string) => { let loginUrl: string; diff --git a/ui/src/pages/RegionalLogin/regionalLogin.interface.ts b/ui/src/pages/RegionalLogin/regionalLogin.interface.ts index 9d5d60eac..87f9ba980 100644 --- a/ui/src/pages/RegionalLogin/regionalLogin.interface.ts +++ b/ui/src/pages/RegionalLogin/regionalLogin.interface.ts @@ -1,11 +1,28 @@ // Interface import { Image, CTA } from '../../types/common.interface'; +/** + * Represents the type of a region. + */ export interface RegionType { + /** + * The description of the region type. + */ description?: string; + + /** + * The heading of the region type. + */ heading?: string; + + /** + * The regions associated with the region type. + */ regions?: Region[]; } +/** + * Represents a region. + */ interface Region { cta?: CTA; region_title?: string; diff --git a/ui/src/services/api/login.service.ts b/ui/src/services/api/login.service.ts index 69ee0dc4c..4a44a72aa 100644 --- a/ui/src/services/api/login.service.ts +++ b/ui/src/services/api/login.service.ts @@ -3,6 +3,11 @@ import { User, SmsToken } from '../../pages/Login/login.interface'; import { postCall } from './service'; +/** + * Creates a user session by making a POST request to the '/user-session' endpoint. + * @param data - The user data to be sent in the request body. + * @returns A Promise that resolves to the response from the server, or an error object if the request fails. + */ export const userSession = (data: User) => { try { return postCall(`${AUTH_ROUTES}/user-session`, data); @@ -11,6 +16,11 @@ export const userSession = (data: User) => { } }; +/** + * Requests an SMS token. + * @param data - The data for the SMS token request. + * @returns A Promise that resolves to the response of the API call. + */ export const requestSMSToken = (data: SmsToken) => { try { return postCall(`${AUTH_ROUTES}/request-token-sms`, data); diff --git a/ui/src/services/api/migration.service.ts b/ui/src/services/api/migration.service.ts index ecbf72acf..6bb72ff09 100644 --- a/ui/src/services/api/migration.service.ts +++ b/ui/src/services/api/migration.service.ts @@ -8,6 +8,12 @@ const options = { } }; +/** + * Retrieves migration data for a specific organization and project. + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @returns A Promise that resolves to the migration data. + */ export const getMigrationData = (orgId: string, projectId: string) => { try { return getCall(`${API_VERSION}/org/${orgId}/project/${projectId}/`, options); @@ -16,6 +22,14 @@ export const getMigrationData = (orgId: string, projectId: string) => { } }; +/** + * Updates the legacy CMS data for a specific organization and project. + * + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @param data - The data to be updated. + * @returns The result of the update operation. + */ export const updateLegacyCMSData = (orgId: string, projectId: string, data: any) => { try { return putCall(`${API_VERSION}/org/${orgId}/project/${projectId}/legacy-cms`, data, options); @@ -24,6 +38,14 @@ export const updateLegacyCMSData = (orgId: string, projectId: string, data: any) } }; +/** + * Updates the affix data for a specific organization and project. + * + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @param data - The data to be updated. + * @returns A promise that resolves to the updated data or an error object. + */ export const updateAffixData = (orgId: string, projectId: string, data: any) => { try { return putCall(`${API_VERSION}/org/${orgId}/project/${projectId}/affix`, data, options); @@ -32,6 +54,14 @@ export const updateAffixData = (orgId: string, projectId: string, data: any) => } }; +/** + * Updates the file format data for a specific organization and project. + * + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @param data - The data to be updated. + * @returns The result of the update operation. + */ export const updateFileFormatData = (orgId: string, projectId: string, data: any) => { try { return putCall(`${API_VERSION}/org/${orgId}/project/${projectId}/file-format`, data, options); @@ -40,6 +70,14 @@ export const updateFileFormatData = (orgId: string, projectId: string, data: any } }; +/** + * Updates the destination stack for a given organization and project. + * + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @param data - The data to be sent in the request body. + * @returns A Promise that resolves to the result of the API call or an error object. + */ export const updateDestinationStack = (orgId: string, projectId: string, data: any) => { try { return putCall( @@ -52,6 +90,14 @@ export const updateDestinationStack = (orgId: string, projectId: string, data: a } }; +/** + * Updates the current step data for a specific organization and project. + * + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @param data - The data to be updated. Defaults to an empty object. + * @returns A promise that resolves to the updated data or an error object. + */ export const updateCurrentStepData = (orgId: string, projectId: string, data: any = {}) => { try { return putCall(`${API_VERSION}/org/${orgId}/project/${projectId}/current-step`, data, options); @@ -60,6 +106,13 @@ export const updateCurrentStepData = (orgId: string, projectId: string, data: an } }; +/** + * Affixes confirmation to a project in an organization. + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @param data - Additional data to be sent with the request. + * @returns A promise that resolves to the result of the API call or an error object. + */ export const affixConfirmation = (orgId: string, projectId: string, data: any = {}) => { try { return putCall( @@ -72,6 +125,13 @@ export const affixConfirmation = (orgId: string, projectId: string, data: any = } }; +/** + * Sends a file format confirmation request to the server. + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @param data - Additional data to be sent with the request. + * @returns A promise that resolves to the response from the server, or an error object if an error occurs. + */ export const fileformatConfirmation = (orgId: string, projectId: string, data: any = {}) => { try { return putCall( @@ -84,6 +144,15 @@ export const fileformatConfirmation = (orgId: string, projectId: string, data: a } }; +/** + * Retrieves content types from the server. + * + * @param projectId - The ID of the project. + * @param skip - The number of items to skip. + * @param limit - The maximum number of items to retrieve. + * @param searchText - The text to search for. + * @returns A Promise that resolves to the retrieved content types or an error. + */ export const getContentTypes = ( projectId: string, skip: number, @@ -100,6 +169,15 @@ export const getContentTypes = ( } }; +/** + * Retrieves the field mapping for a given content type. + * + * @param contentTypeId - The ID of the content type. + * @param skip - The number of records to skip. + * @param limit - The maximum number of records to retrieve. + * @param searchText - The text to search for in the field mapping. + * @returns A Promise that resolves to the field mapping data. + */ export const getFieldMapping = async ( contentTypeId: string, skip: number, @@ -116,6 +194,11 @@ export const getFieldMapping = async ( } }; +/** + * Retrieves the existing content types for a given project. + * @param projectId - The ID of the project. + * @returns A Promise that resolves to the existing content types, or an error if the request fails. + */ export const getExistingContentTypes = async (projectId: string) => { try { return await getCall(`${API_VERSION}/mapper/${projectId}`, options); @@ -124,6 +207,15 @@ export const getExistingContentTypes = async (projectId: string) => { } }; +/** + * Updates the content type with the specified ID. + * + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @param contentTypeId - The ID of the content type. + * @param data - The data to update the content type with. + * @returns A Promise that resolves to the updated content type, or an error if the update fails. + */ export const updateContentType = async ( orgId: string, projectId: string, @@ -141,6 +233,15 @@ export const updateContentType = async ( } }; +/** + * Resets the fields of a content type to their initial mapping. + * + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @param contentTypeId - The ID of the content type. + * @param data - The data to be sent in the request body. + * @returns A promise that resolves to the response from the server, or an error object if the request fails. + */ export const resetToInitialMapping = async ( orgId: string, projectId: string, @@ -158,6 +259,13 @@ export const resetToInitialMapping = async ( } }; +/** + * Creates a test stack for migration. + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @param data - The data for the test stack. + * @returns A promise that resolves to the result of the API call. + */ export const createTestStack = async (orgId: string, projectId: string, data: any) => { try { return await postCall( @@ -170,6 +278,13 @@ export const createTestStack = async (orgId: string, projectId: string, data: an } }; +/** + * Fetches an existing content type from the server. + * + * @param projectId - The ID of the project. + * @param contentTypeUid - The UID of the content type. + * @returns A promise that resolves to the fetched content type, or an error if the request fails. + */ export const fetchExistingContentType = async (projectId: string, contentTypeUid: string) => { try { return await getCall(`${API_VERSION}/mapper/${projectId}/${contentTypeUid}`, options); @@ -178,6 +293,12 @@ export const fetchExistingContentType = async (projectId: string, contentTypeUid } } +/** + * Retrieves the content mapper for a specific organization and project. + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @returns A Promise that resolves to the content mapper. + */ export const removeContentMapper = async(orgId: string, projectId: string) => { try { return await getCall(`${API_VERSION}/mapper/${orgId}/${projectId}/content-mapper`, options); diff --git a/ui/src/services/api/project.service.ts b/ui/src/services/api/project.service.ts index dfc368910..e4f8f3c2c 100644 --- a/ui/src/services/api/project.service.ts +++ b/ui/src/services/api/project.service.ts @@ -2,12 +2,22 @@ import { API_VERSION } from '../../utilities/constants'; import { getDataFromLocalStorage } from '../../utilities/functions'; import { getCall, postCall, putCall, deleteCall } from './service'; +/** + * Returns the options object for API requests. + * The options object includes the headers with the app token. + * @returns The options object. + */ const options = () => ({ headers: { app_token: getDataFromLocalStorage('app_token') } }); +/** + * Retrieves all projects for a given organization. + * @param orgId - The ID of the organization. + * @returns A promise that resolves to the list of projects, or an error if the request fails. + */ export const getAllProjects = async (orgId: string) => { try { return await getCall(`${API_VERSION}/org/${orgId}/project`, options()); @@ -16,6 +26,12 @@ export const getAllProjects = async (orgId: string) => { } }; +/** + * Retrieves a project by its organization ID and project ID. + * @param orgId The ID of the organization. + * @param projectId The ID of the project. + * @returns A Promise that resolves to the project data, or an error if the request fails. + */ export const getProject = async (orgId: string, projectId: string) => { try { return await getCall(`${API_VERSION}/org/${orgId}/project/${projectId}`, options()); @@ -24,6 +40,13 @@ export const getProject = async (orgId: string, projectId: string) => { } }; +/** + * Creates a new project for the specified organization. + * + * @param orgId - The ID of the organization. + * @param data - The data for the new project. + * @returns A Promise that resolves to the created project, or an error if the request fails. + */ export const createProject = async (orgId: string, data: any) => { try { return await postCall(`${API_VERSION}/org/${orgId}/project/`, data, options()); @@ -32,6 +55,13 @@ export const createProject = async (orgId: string, data: any) => { } }; +/** + * Updates a project. + * @param orgId - The ID of the organization. + * @param projectId - The ID of the project. + * @param data - The data to update the project with. + * @returns A promise that resolves to the updated project, or an error if the update fails. + */ export const updateProject = async (orgId: string, projectId: string, data: any) => { try { return await putCall(`${API_VERSION}/org/${orgId}/project/${projectId}`, data, options()); @@ -40,6 +70,12 @@ export const updateProject = async (orgId: string, projectId: string, data: any) } }; +/** + * Deletes a project. + * @param {string} orgId - The ID of the organization. + * @param {string} projectId - The ID of the project to delete. + * @returns {Promise} - A promise that resolves to the result of the delete operation, or an error object if an error occurs. + */ export const deleteProject = async (orgId: string, projectId: string) => { try { return await deleteCall(`${API_VERSION}/org/${orgId}/project/${projectId}`, options()); diff --git a/ui/src/services/api/service.interface.ts b/ui/src/services/api/service.interface.ts index f52ef611d..3d1ee4ef6 100644 --- a/ui/src/services/api/service.interface.ts +++ b/ui/src/services/api/service.interface.ts @@ -1,13 +1,22 @@ +/** + * Represents an error object. + */ export interface Error { code: number; message: string; } +/** + * Represents the response object for an organisation. + */ export interface OrganisationResponse { org_id: string; org_name: string; } +/** + * Represents the response object returned by the stack API. + */ export interface StackResponse { name: string; api_key: string; @@ -16,6 +25,9 @@ export interface StackResponse { created_at: string; } +/** + * Represents the response object for a migration. + */ export interface MigrationResponse { legacy_cms: LegacyCms; _id: string; @@ -34,11 +46,17 @@ export interface MigrationResponse { current_step: number; } +/** + * Represents the Legacy CMS interface. + */ export interface LegacyCms { cms: string; file_format: string; } +/** + * Represents the default migration response object. + */ export const defaultMigrationResponse: MigrationResponse = { legacy_cms: { cms: '', diff --git a/ui/src/services/api/service.ts b/ui/src/services/api/service.ts index 4381ee4d5..9da8483a2 100644 --- a/ui/src/services/api/service.ts +++ b/ui/src/services/api/service.ts @@ -2,6 +2,12 @@ import axios from 'axios'; import { BASE_API_URL } from '../../utilities/constants'; // ALL Axios Call +/** + * Makes a GET request to the specified URL. + * @param url - The URL to make the GET request to. + * @param options - Optional configuration for the request. + * @returns A Promise that resolves to the response data, or rejects with the error response. + */ export const getCall = async (url: string, options?: any) => { try { return await axios.get(`${BASE_API_URL}${url}`, { ...options }); @@ -10,6 +16,13 @@ export const getCall = async (url: string, options?: any) => { } }; +/** + * Makes a POST request to the specified URL with the provided data and options. + * @param url - The URL to make the POST request to. + * @param data - The data to send in the request body. + * @param options - Optional additional options for the request. + * @returns A Promise that resolves to the response data, or rejects with the error response. + */ export const postCall = async (url: string, data: any, options?: any) => { try { return await axios.post(`${BASE_API_URL}${url}`, data, options); @@ -18,6 +31,13 @@ export const postCall = async (url: string, data: any, options?: any) => { } }; +/** + * Makes a PUT request to the specified URL with the provided data and options. + * @param url - The URL to send the PUT request to. + * @param data - The data to send in the request body. + * @param options - Additional options for the request. + * @returns A Promise that resolves to the response data, or rejects with the error response. + */ export const putCall = async (url: string, data: any, options?: any) => { try { return await axios.put(`${BASE_API_URL}${url}`, data, options); @@ -26,6 +46,12 @@ export const putCall = async (url: string, data: any, options?: any) => { } }; +/** + * Sends a DELETE request to the specified URL with optional request options. + * @param url - The URL to send the DELETE request to. + * @param options - Optional request options. + * @returns A Promise that resolves to the response data if the request is successful, or the error response if the request fails. + */ export const deleteCall = async (url: string, options?: any) => { try { return await axios.delete(`${BASE_API_URL}${url}`, options); @@ -34,6 +60,13 @@ export const deleteCall = async (url: string, options?: any) => { } }; +/** + * Makes a PATCH request to the specified URL with the provided data and options. + * @param url - The URL to send the PATCH request to. + * @param data - The data to be sent in the request body. + * @param options - Additional options for the request (optional). + * @returns A Promise that resolves to the response data if the request is successful, or the error response if the request fails. + */ export const patchCall = async (url: string, data: any, options?: any) => { try { return await axios.patch(`${BASE_API_URL}${url}`, data, options); diff --git a/ui/src/services/api/stacks.service.ts b/ui/src/services/api/stacks.service.ts index 334b2b7a6..15c4af7da 100644 --- a/ui/src/services/api/stacks.service.ts +++ b/ui/src/services/api/stacks.service.ts @@ -2,12 +2,23 @@ import { API_VERSION } from '../../utilities/constants'; import { getDataFromLocalStorage } from '../../utilities/functions'; import { getCall, postCall } from './service'; +/** + * Options for the API request. + * @property {Object} headers - The headers for the request. + * @property {string} headers.app_token - The app token retrieved from local storage. + */ const options = { headers: { app_token: getDataFromLocalStorage('app_token') } }; +/** + * Retrieves all stacks in an organization based on the provided organization ID and search text. + * @param orgId - The ID of the organization. + * @param searchText - The search text used to filter the stacks. + * @returns A promise that resolves to the result of the API call. + */ export const getAllStacksInOrg = async (orgId: string,searchText: string) => { try { return await getCall(`${API_VERSION}/org/${orgId}/stacks/${searchText}?`, options); @@ -16,6 +27,13 @@ export const getAllStacksInOrg = async (orgId: string,searchText: string) => { } }; +/** + * Creates stacks in an organization. + * + * @param orgId - The ID of the organization. + * @param data - The data for creating the stacks. + * @returns A promise that resolves to the result of the API call. + */ export const createStacksInOrg = async (orgId: string, data: any) => { try { return await postCall(`${API_VERSION}/org/${orgId}/stacks`, data, options); @@ -24,6 +42,12 @@ export const createStacksInOrg = async (orgId: string, data: any) => { } }; +/** + * Retrieves the status of a stack. + * @param orgId - The ID of the organization. + * @param data - The stack API key. + * @returns A Promise that resolves to the stack status. + */ export const getStackStatus = async (orgId: string, data: string) => { try { const stack_api = { diff --git a/ui/src/services/api/upload.service.ts b/ui/src/services/api/upload.service.ts index ead7f3f28..7baaae418 100644 --- a/ui/src/services/api/upload.service.ts +++ b/ui/src/services/api/upload.service.ts @@ -5,6 +5,12 @@ import { API_VERSION } from '../../utilities/constants'; import { getDataFromLocalStorage } from '../../utilities/functions'; //Axios Calls for Upload server +/** + * Makes a GET request to the specified URL with optional request options. + * @param url - The URL to make the GET request to. + * @param options - Optional request options. + * @returns A Promise that resolves to the response data if the request is successful, or the error response if the request fails. + */ export const getCall = async (url: string, options?: any) => { try { const response = await axios.get(url, { ...options }); @@ -14,6 +20,13 @@ export const getCall = async (url: string, options?: any) => { } }; +/** + * Makes a POST request to the specified URL with the provided data. + * @param url - The URL to make the POST request to. + * @param data - The data to send in the request body. + * @param options - Additional options for the request. + * @returns A Promise that resolves to the response from the server. + */ export const postCall = async (url: string, data: User, options?: any) => { try { const response = await axios.post(url, data, options); @@ -23,6 +36,13 @@ export const postCall = async (url: string, data: User, options?: any) => { } }; +/** + * Makes a PUT request to the specified URL with the provided data and options. + * @param url - The URL to send the PUT request to. + * @param data - The data to be sent in the request body. + * @param options - Optional additional options for the request. + * @returns A Promise that resolves to the response from the server, or rejects with an error response. + */ export const putCall = async (url: string, data: User, options?: any) => { try { const response = await axios.put(url, data, options); @@ -33,10 +53,19 @@ export const putCall = async (url: string, data: User, options?: any) => { }; //upload file to s3 +/** + * Returns the upload file path. + * @returns The upload file path. + */ export const uploadFilePath = () => { return `${UPLOAD_FILE_RELATIVE_URL}upload`; }; +/** + * Validates a file for a specific project. + * @param projectId - The ID of the project. + * @returns A Promise that resolves to the result of the file validation. + */ export const fileValidation = (projectId: string) => { try { const options = { @@ -52,6 +81,11 @@ export const fileValidation = (projectId: string) => { } }; +/** + * Retrieves the configuration for uploading files. + * @returns {Promise} A promise that resolves to the configuration object. + * @throws {Error} If an error occurs while retrieving the configuration. + */ export const getConfig = () => { try { return getCall(`${UPLOAD_FILE_RELATIVE_URL}config`); diff --git a/ui/src/services/api/user.service.ts b/ui/src/services/api/user.service.ts index f9668f6b4..041af1de5 100644 --- a/ui/src/services/api/user.service.ts +++ b/ui/src/services/api/user.service.ts @@ -2,6 +2,10 @@ import { API_VERSION } from '../../utilities/constants'; import { getDataFromLocalStorage } from '../../utilities/functions'; import { getCall } from './service'; +/** + * Retrieves user profile data from the server. + * @returns {Promise} A promise that resolves to the user profile data. + */ export const getUser = async () => { const options = { headers: { @@ -16,6 +20,11 @@ export const getUser = async () => { } }; +/** + * Retrieves all locales for a given organization. + * @param orgId - The ID of the organization. + * @returns A Promise that resolves to the locales data, or an error if the request fails. + */ export const getAllLocales = async (orgId: string) => { const options = { headers: { diff --git a/ui/src/store/index.tsx b/ui/src/store/index.tsx index 8ba9b8184..40fef8523 100644 --- a/ui/src/store/index.tsx +++ b/ui/src/store/index.tsx @@ -10,12 +10,21 @@ import { persistReducer, persistStore } from 'redux-persist'; import authMiddleware from './middleware/authMiddleware'; +/** + * Configuration object for persisting the Redux store. + * @property {string} key - The key to use for storing the state in the storage. + * @property {Object} storage - The storage engine to use for persisting the state. + */ const persistConfig = { key: 'root', storage, }; // Combine reducers +/** + * Root reducer function that combines all the reducers for the Redux store. + * @returns The combined reducer object. + */ const rootReducer = combineReducers({ migration: migrationDataSlice, authentication: authSlice, @@ -24,6 +33,14 @@ const rootReducer = combineReducers({ const persistedReducer = persistReducer(persistConfig, rootReducer); // Create the store +/** + * Creates the Redux store with the specified reducer and middleware. + * + * @param {Object} options - The options for configuring the store. + * @param {Function} options.reducer - The root reducer function for the store. + * @param {Function} options.middleware - The middleware function for the store. + * @returns {Object} The Redux store object. + */ const store = configureStore({ reducer: persistedReducer, middleware: (getDefaultMiddleware:any) => diff --git a/ui/src/store/middleware/authMiddleware.tsx b/ui/src/store/middleware/authMiddleware.tsx index 3b7b3b6c1..94c893553 100644 --- a/ui/src/store/middleware/authMiddleware.tsx +++ b/ui/src/store/middleware/authMiddleware.tsx @@ -5,6 +5,11 @@ import { getUserDetails } from '../slice/authSlice'; // Adjust import path // Your other imports... +/** + * Middleware function that handles authentication-related actions. + * @param {Object} store - The Redux store object. + * @returns {Function} - The next middleware function in the chain. + */ const authMiddleware: Middleware = ({dispatch}) => (next) => (action: any) => { if (action.type === '@@INIT') { dispatch(getUserDetails()); diff --git a/ui/src/store/slice/authSlice.tsx b/ui/src/store/slice/authSlice.tsx index 4abe1409c..cc9e5d5ff 100644 --- a/ui/src/store/slice/authSlice.tsx +++ b/ui/src/store/slice/authSlice.tsx @@ -13,18 +13,26 @@ import { getUser } from '../../services/api/user.service'; import { OrganisationResponse } from '../../services/api/service.interface'; +/** + * Represents the initial state of the authentication slice. + */ const initialState = { - authToken: getDataFromLocalStorage('app_token'), - user : DEFAULT_USER, - isAuthenticated:false, - organisationsList: [], - selectedOrganisation: DEFAULT_DROPDOWN - + authToken: getDataFromLocalStorage('app_token'), + user : DEFAULT_USER, + isAuthenticated:false, + organisationsList: [], + selectedOrganisation: DEFAULT_DROPDOWN } -const getUserDetails:any = createAsyncThunk( +/** + * Async thunk function to get user details. + * @param _ - The payload (not used in this case) + * @param dispatch - The Redux dispatch function + * @returns A Promise that resolves to an object containing user details, organisations list, and selected organisation + */ +const getUserDetails: any = createAsyncThunk( 'get/getUserDetails', - async (_,{dispatch}) => { + async (_, { dispatch }) => { try { const response = await getUser(); @@ -71,45 +79,66 @@ const getUserDetails:any = createAsyncThunk( } ); +/** + * Represents the authentication slice of the Redux store. + */ const authSlice = createSlice({ - name:'authentication', - initialState, - reducers:{ - setAuthToken : (state, action)=>{ - state.authToken = action?.payload; - state.isAuthenticated = !!action?.payload; - }, - setUser : (state, action) => { - state.user = action?.payload; - }, - reInitiliseState: (state) => { - state.authToken = ''; - state.user = DEFAULT_USER; - state.isAuthenticated = false; - state.organisationsList = []; - state.selectedOrganisation = DEFAULT_DROPDOWN; - }, - setOrganisationsList: (state, action)=>{ - state.organisationsList = action?.payload - - }, - setSelectedOrganisation: (state, action) => { - state.selectedOrganisation = action?.payload; - } - - + name:'authentication', + initialState, + reducers:{ + /** + * Sets the authentication token and updates the authentication status. + * @param state - The current state of the authentication slice. + * @param action - The Redux action containing the payload. + */ + setAuthToken : (state, action)=>{ + state.authToken = action?.payload; + state.isAuthenticated = !!action?.payload; }, - extraReducers: (builder) => { - builder.addCase(getUserDetails?.fulfilled,(state, action:any)=>{ - state.user = action?.payload?.user; - state.organisationsList = action?.payload?.organisationsList; - state.selectedOrganisation = action?.payload?.selectedOrganisation ; - state.isAuthenticated = !isEmptyString(state?.authToken || ''); - - - }) - + /** + * Sets the user object in the authentication slice. + * @param state - The current state of the authentication slice. + * @param action - The Redux action containing the payload. + */ + setUser : (state, action) => { + state.user = action?.payload; + }, + /** + * Reinitializes the state of the authentication slice to its default values. + * @param state - The current state of the authentication slice. + */ + reInitiliseState: (state) => { + state.authToken = ''; + state.user = DEFAULT_USER; + state.isAuthenticated = false; + state.organisationsList = []; + state.selectedOrganisation = DEFAULT_DROPDOWN; }, + /** + * Sets the list of organizations in the authentication slice. + * @param state - The current state of the authentication slice. + * @param action - The Redux action containing the payload. + */ + setOrganisationsList: (state, action)=>{ + state.organisationsList = action?.payload; + }, + /** + * Sets the selected organization in the authentication slice. + * @param state - The current state of the authentication slice. + * @param action - The Redux action containing the payload. + */ + setSelectedOrganisation: (state, action) => { + state.selectedOrganisation = action?.payload; + } + }, + extraReducers: (builder) => { + builder.addCase(getUserDetails?.fulfilled,(state, action:any)=>{ + state.user = action?.payload?.user; + state.organisationsList = action?.payload?.organisationsList; + state.selectedOrganisation = action?.payload?.selectedOrganisation ; + state.isAuthenticated = !isEmptyString(state?.authToken || ''); + }) + }, }) export const { setAuthToken, reInitiliseState, setOrganisationsList, setSelectedOrganisation, setUser } = authSlice.actions; diff --git a/ui/src/store/slice/migrationDataSlice.tsx b/ui/src/store/slice/migrationDataSlice.tsx index cfd2733ec..db5090c83 100644 --- a/ui/src/store/slice/migrationDataSlice.tsx +++ b/ui/src/store/slice/migrationDataSlice.tsx @@ -5,28 +5,54 @@ import { createSlice } from '@reduxjs/toolkit' import { DEFAULT_CONTENT_MAPPING_DATA, DEFAULT_DESTINATION_STACK_DATA, DEFAULT_LEGACY_CMS_DATA, DEFAULT_MIGRATION_DATA, DEFAULT_MIGRATION_EXECUTION, DEFAULT_NEW_MIGRATION, DEFAULT_TEST_MIGRATION, IMigrationData, INewMigration} from '../../context/app/app.interface'; import { DEFAULT_IFLOWSTEP } from '../../components/Stepper/FlowStepper/flowStep.interface'; +/** + * Represents the initial state of the migration data slice. + */ const initialState = { - migrationData: DEFAULT_MIGRATION_DATA , - newMigrationData: DEFAULT_NEW_MIGRATION -} + migrationData: DEFAULT_MIGRATION_DATA, + newMigrationData: DEFAULT_NEW_MIGRATION, +}; + +/** + * Represents the migration data slice. + */ const migrationSlice = createSlice({ name:'migration', initialState, reducers:{ + /** + * Sets the new migration data. + * @param state - The current state. + * @param action - The action containing the payload. + */ setNewMigrationData: (state, action) => { state.newMigrationData = action?.payload; }, + /** + * Updates the new migration data. + * @param state - The current state. + * @param action - The action containing the payload. + */ updateNewMigrationData: (state, action)=>{ state.newMigrationData = {...state?.newMigrationData,...action?.payload}; }, + /** + * Sets the migration data. + * @param state - The current state. + * @param action - The action containing the payload. + */ setMigrationData: (state, action) => { state.migrationData = action?.payload; }, + /** + * Updates the migration data. + * @param state - The current state. + * @param action - The action containing the payload. + */ updateMigrationData: (state, action) => { state.migrationData = {...state?.migrationData, ...action?.payload}; } - } }) diff --git a/ui/src/types/common.interface.ts b/ui/src/types/common.interface.ts index 11e8b35cd..0a92d6203 100644 --- a/ui/src/types/common.interface.ts +++ b/ui/src/types/common.interface.ts @@ -1,16 +1,51 @@ +/** + * Represents a Call-to-Action (CTA) element. + */ export interface CTA { + /** + * The title of the CTA. + */ title?: string; + + /** + * The URL that the CTA should navigate to. + */ url?: string; + + /** + * The theme or style of the CTA. + */ theme?: string; + + /** + * Indicates whether the CTA should be displayed with an icon. + */ with_icon?: boolean; + + /** + * Indicates whether the CTA is a secondary button. + */ secondary_button?: boolean; } +/** + * Represents an image. + */ export interface Image { + /** + * The title of the image. + */ title?: string; + + /** + * The URL of the image. + */ url: string; } +/** + * Represents a logo with an image and a URL. + */ export interface Logo { image: Image; url: string; diff --git a/ui/src/utilities/functions.ts b/ui/src/utilities/functions.ts index 7035f1e39..291ecab96 100644 --- a/ui/src/utilities/functions.ts +++ b/ui/src/utilities/functions.ts @@ -1,17 +1,49 @@ import { Notification } from '@contentstack/venus-components'; import { WEBSITE_BASE_URL } from './constants'; +/** + * Represents a collection of locale codes and their corresponding values. + */ export const Locales = { + /** + * English locale code. + */ en: 'en-us', + /** + * French locale code. + */ fr: 'fr-fr', + /** + * German locale code. + */ de: 'de-de', + /** + * Japanese locale code. + */ jp: 'ja-jp', + /** + * Korean locale code. + */ kr: 'ko-kr', + /** + * Chinese locale code. + */ cn: 'zh-cn', + /** + * Spanish locale code. + */ es: 'es-mx', + /** + * Portuguese locale code. + */ pt: 'pt-br' }; +/** + * Returns the locale code based on the provided locale. + * @param loc The locale for which to retrieve the locale code. Defaults to 'en'. + * @returns The locale code corresponding to the provided locale. + */ export const getLocaleCode = (loc = 'en') => { return Locales[loc as keyof typeof Locales]; }; @@ -26,8 +58,18 @@ export const validateArray = (array: T[]) => Array.isArray(array) && array.le // Use: validateSingleImage(image) export const validateImage = (image: any) => image && image?.url; +/** + * Validates a link by checking if it exists and has a URL. + * @param link - The link to validate. + * @returns True if the link is valid, false otherwise. + */ export const validateLink = (link: any) => link && link?.url; +/** + * Replaces the domain URL of an image with the website base URL. + * @param url - The URL of the image. + * @returns The modified URL with the website base URL. + */ export const imageWithSiteDomainUrl = (url: string) => { if (WEBSITE_BASE_URL && url?.indexOf('https://images.contentstack.io') > -1) { return url.replace('https://images.contentstack.io', WEBSITE_BASE_URL); @@ -38,10 +80,19 @@ export const imageWithSiteDomainUrl = (url: string) => { return url; }; +/** + * Adds the domain to the given path. + * @param path - The path to which the domain needs to be added. + * @returns The updated path with the domain added. + */ export const addDomainInPath = (path: string) => { return `${WEBSITE_BASE_URL}${path}`; }; +/** + * Displays a failure notification with the given error message. + * @param errorMessage - The error message to display. + */ export const failtureNotification = (errorMessage: string) => { Notification({ text: errorMessage, @@ -55,16 +106,31 @@ export const failtureNotification = (errorMessage: string) => { }); }; +/** + * Clears performance marks. + * @param markName - The name of the mark to clear. + * @param clearAll - Optional. If true, clears all marks. Defaults to false. + */ export const clearMarks = (markName: string, clearAll?: boolean) => { if (clearAll) performance.clearMarks(); else performance.clearMarks(markName); }; +/** + * Clears the performance measures. + * @param measreName - The name of the measure to clear. + * @param clearAll - Optional. If true, clears all measures. Defaults to false. + */ export const clearMeasures = (measreName: string, clearAll?: boolean) => { if (clearAll) performance.clearMeasures(); else performance.clearMeasures(measreName); }; +/** + * Extracts the window object from a given string containing HTML script tags. + * @param str - The string containing HTML script tags. + * @returns The extracted window object as a string, or null if not found. + */ export const extractWindowObj = (str: string): string | null => { const re = /]*>([\s\S]*?)<\/script>/g; @@ -77,11 +143,20 @@ export const extractWindowObj = (str: string): string | null => { return null; }; +/** + * Clears the local storage. + * @returns {boolean} - Returns true if the local storage is cleared successfully, otherwise false. + */ export const clearLocalStorage = () => { localStorage.clear(); return localStorage.length === 0; }; +/** + * Retrieves data from the local storage based on the provided key. + * @param key - The key used to retrieve the data from the local storage. + * @returns The data stored in the local storage for the provided key, or null if the key does not exist. + */ export const getDataFromLocalStorage = (key: string) => { if (localStorage.getItem(key)) { return localStorage.getItem(key); @@ -90,6 +165,12 @@ export const getDataFromLocalStorage = (key: string) => { return null; }; +/** + * Sets data in the local storage with the specified key. + * @param key - The key to set the data with. + * @param data - The data to be stored in the local storage. + * @returns True if the data was successfully set in the local storage, false otherwise. + */ export const setDataInLocalStorage = (key: string, data: any) => { localStorage.setItem(key, data); @@ -100,6 +181,13 @@ export const setDataInLocalStorage = (key: string, data: any) => { return true; }; +/** + * Calculates the time difference between the given day and the present day. + * Returns a string representation of the time difference in a human-readable format. + * + * @param day - The day to calculate the time difference from. + * @returns A string representation of the time difference. + */ export const getDays = (day: any) => { const presentDay = new Date().getTime(); const projectDate = new Date(day).getTime(); @@ -127,9 +215,23 @@ export const getDays = (day: any) => { }); }; +/** + * Checks if a string is empty or consists of only whitespace characters. + * @param str - The string to check. + * @returns `true` if the string is empty or consists of only whitespace characters, `false` otherwise. + */ export const isEmptyString = (str: string | undefined) => str === undefined || str === null || str.trim().length < 1; +/** + * Returns a shortened version of the given name if it exceeds 25 characters. + * The shortened name will include the first 15 characters, followed by an ellipsis, + * and the last 8 characters of the original name. + * If the name is 25 characters or less, it will be returned as is. + * + * @param name - The name to be shortened. + * @returns The shortened name if it exceeds 25 characters, otherwise the original name. + */ export const shortName = (name: string) => { if (name && name.length > 25) { name = `${name.slice(0, 15)}...${name.slice(name.length - 8, name.length)}`; @@ -139,6 +241,11 @@ export const shortName = (name: string) => { return name; }; +/** + * Returns the file size in a human-readable format. + * @param number - The file size in bytes. + * @returns The file size in a human-readable format (bytes, KB, or MB). + */ export const returnFileSize = (number: number) => { if (number < 1024) { return number + 'bytes'; @@ -149,6 +256,13 @@ export const returnFileSize = (number: number) => { } }; +/** + * Checks if the given data is a valid prefix. + * A valid prefix should consist of 2 to 5 alphabetic characters (uppercase or lowercase). + * + * @param data - The data to be checked. + * @returns True if the data is a valid prefix, false otherwise. + */ export const isValidPrefix = (data: string): boolean => { const regEx = /^[a-z A-Z]{2,5}$/; diff --git a/uplaode-api/migration-sitecore/libs/configuration.js b/uplaode-api/migration-sitecore/libs/configuration.js index 7875dde07..9c21aa8ce 100644 --- a/uplaode-api/migration-sitecore/libs/configuration.js +++ b/uplaode-api/migration-sitecore/libs/configuration.js @@ -4,15 +4,23 @@ const read = require("fs-readdir-recursive"); const helper = require("../utils/helper"); +/** + * Assigns a folder name based on the provided path. + * + * @param {Object} options - The options object. + * @param {string} options.path - The path to be processed. + * @returns {string} The modified path with the folder name. + */ const assignFolderName = ({ path }) => { const spliter = "/sitecore"; const newPath = path.split(spliter)?.[1]; return `${spliter}${newPath}`; } - - - +/** + * Extracts configuration data from the specified sitecore_folder. + * @param {string} sitecore_folder - The path to the sitecore_folder. + */ function ExtractConfiguration(sitecore_folder) { const xml_folder = read(sitecore_folder); const obj = {}; diff --git a/uplaode-api/migration-sitecore/libs/contenttypes.js b/uplaode-api/migration-sitecore/libs/contenttypes.js index 570384ecc..a4b7e5f37 100644 --- a/uplaode-api/migration-sitecore/libs/contenttypes.js +++ b/uplaode-api/migration-sitecore/libs/contenttypes.js @@ -9,10 +9,24 @@ const configChecker = "/content/Common/Configuration"; const append = "a" +/** + * Checks if a given key is present in the timeZones array. + * + * @param {string} keyToFind - The key to search for. + * @param {Array} timeZones - The array of time zones to search in. + * @returns {boolean} - Returns true if the key is present in any of the time zones, otherwise returns false. + */ function isKeyPresent(keyToFind, timeZones) { return timeZones?.some?.(timeZone => Object?.keys?.(timeZone)?.includes?.(keyToFind)); } +/** + * Creates a template based on the provided components. + * + * @param {Object} options - The options object. + * @param {Object} options.components - The components object. + * @returns {Object} - The created template object. + */ const createTemplate = ({ components }) => { components.item.$.field = components?.item?.fields?.field return components?.item?.$ @@ -347,6 +361,17 @@ const groupFlat = (data, item) => { } +/** + * Maps the content types based on the provided parameters. + * + * @param {Object} options - The options object. + * @param {Array} options.components - The components array. + * @param {Object} options.standardValues - The standard values object. + * @param {string} options.content_type - The content type string. + * @param {string} options.basePath - The base path string. + * @param {string} options.sitecore_folder - The sitecore folder string. + * @returns {Array} - The mapped content types array. + */ const contentTypeMapper = ({ components, standardValues, content_type, basePath, sitecore_folder }) => { const source = helper.readFile( path.join(process.cwd(), "/sitecoreMigrationData/MapperData/configuration.json") diff --git a/uplaode-api/src/config/index.ts b/uplaode-api/src/config/index.ts index d0722ca5a..3ecf77d80 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' +}; \ No newline at end of file diff --git a/uplaode-api/src/controllers/sitecore/index.ts b/uplaode-api/src/controllers/sitecore/index.ts index 2ca0823d0..1438b9174 100644 --- a/uplaode-api/src/controllers/sitecore/index.ts +++ b/uplaode-api/src/controllers/sitecore/index.ts @@ -7,6 +7,16 @@ import { HTTP_CODES, HTTP_TEXTS } from "../../constants"; // eslint-disable-next-line @typescript-eslint/no-var-requires const { contentTypes, ExtractConfiguration, reference, ExtractFiles } = require('migration-sitecore'); +/** + * Creates a Sitecore mapper by performing various operations such as extracting files, extracting configuration, + * retrieving content types, and creating dummy data for a given project ID. + * + * @param filePath - The file path where the items are located. + * @param projectId - The ID of the project. + * @param app_token - The application token. + * @returns A Promise that resolves when the Sitecore mapper is created successfully. + * @throws If any error occurs during the process. + */ const createSitecoreMapper = async (filePath: string = "", projectId: string | string[], app_token: string | string[]) => { try { const path = `${filePath}/items`; @@ -18,7 +28,13 @@ const createSitecoreMapper = async (filePath: string = "", projectId: string | s const fieldMapping: any = { contentTypes: [] }; for await (const contentType of infoMap?.contentTypeUids ?? []) { fieldMapping?.contentTypes?.push( - JSON.parse(readFileSync(`${infoMap?.path}/content_types/${contentType}`, 'utf8')) + JSON.parse(readFileSync(`${infoMap?.path}/content_types/${contentType}`, 'utf8')), + ); + } + + for await (const globalField of infoMap?.globalFieldUids ?? []) { + fieldMapping?.globalFields?.push( + JSON.parse(readFileSync(`${infoMap?.path}/global_fields/${globalField}`, 'utf8')), ); } const config = {