From 2231f011f0d394738c996d671de32bfb8bccbf5f Mon Sep 17 00:00:00 2001 From: Rohit Kini Date: Wed, 10 Jul 2024 12:16:05 +0530 Subject: [PATCH 1/3] logs details --- api/package.json | 3 ++ api/src/constants/index.ts | 8 ++-- .../projects.contentMapper.controller.ts | 2 +- api/src/controllers/projects.controller.ts | 2 +- api/src/models/contentTypesMapper-lowdb.ts | 2 +- api/src/models/project-lowdb.ts | 2 +- api/src/routes/contentMapper.routes.ts | 1 - api/src/routes/projects.routes.ts | 2 +- api/src/server.ts | 43 ++++++++++++++++++- api/src/services/contentMapper.service.ts | 41 ++++++++++-------- api/src/services/org.service.ts | 13 +++--- api/src/services/projects.service.ts | 41 ++++++++++-------- 12 files changed, 106 insertions(+), 54 deletions(-) diff --git a/api/package.json b/api/package.json index 58a03e9be..325a9ce00 100644 --- a/api/package.json +++ b/api/package.json @@ -26,14 +26,17 @@ "homepage": "https://github.com/contentstack-expert-services/migration-v2-node-server#readme", "dependencies": { "axios": "^1.6.5", + "chokidar": "^3.6.0", "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", "express-validator": "^7.0.1", "express-winston": "^4.2.0", "helmet": "^7.1.0", + "http": "^0.0.1-security", "jsonwebtoken": "^9.0.2", "lowdb": "^7.0.1", + "socket.io": "^4.7.5", "uuid": "^9.0.1", "winston": "^3.11.0" }, diff --git a/api/src/constants/index.ts b/api/src/constants/index.ts index e3a8c6138..19e712e40 100644 --- a/api/src/constants/index.ts +++ b/api/src/constants/index.ts @@ -72,10 +72,8 @@ export const HTTP_TEXTS = { "Sorry, the requested content mapper id does not exists.", ADMIN_LOGIN_ERROR: "Sorry, You Don't have admin access in any of the Organisation", - PROJECT_DELETE: - "Project Deleted Successfully", - PROJECT_REVERT: - "Project Reverted Successfully" + PROJECT_DELETE: "Project Deleted Successfully", + PROJECT_REVERT: "Project Reverted Successfully", }; export const HTTP_RESPONSE_HEADERS = { @@ -145,4 +143,4 @@ export const CONTENT_TYPE_STATUS = { 2: 2, //verified 3: 3, //mapping failed 4: 4, //auto-dump -} +}; diff --git a/api/src/controllers/projects.contentMapper.controller.ts b/api/src/controllers/projects.contentMapper.controller.ts index 797d5a9bf..a64af4834 100644 --- a/api/src/controllers/projects.contentMapper.controller.ts +++ b/api/src/controllers/projects.contentMapper.controller.ts @@ -53,5 +53,5 @@ export const contentMapperController = { putContentTypeFields, resetContentType, // removeMapping, - getSingleContentTypes + getSingleContentTypes, }; diff --git a/api/src/controllers/projects.controller.ts b/api/src/controllers/projects.controller.ts index 223254c94..dbe1abb97 100644 --- a/api/src/controllers/projects.controller.ts +++ b/api/src/controllers/projects.controller.ts @@ -77,5 +77,5 @@ export const projectController = { updateDestinationStack, updateCurrentStep, deleteProject, - revertProject + revertProject, }; diff --git a/api/src/models/contentTypesMapper-lowdb.ts b/api/src/models/contentTypesMapper-lowdb.ts index 3846c998e..ad8e137cd 100644 --- a/api/src/models/contentTypesMapper-lowdb.ts +++ b/api/src/models/contentTypesMapper-lowdb.ts @@ -9,7 +9,7 @@ interface ContentTypesMapper { updateAt: Date; contentstackTitle: string; contentstackUid: string; - status:number; + status: number; fieldMapping: []; } diff --git a/api/src/models/project-lowdb.ts b/api/src/models/project-lowdb.ts index 683c60c56..2e5df806e 100644 --- a/api/src/models/project-lowdb.ts +++ b/api/src/models/project-lowdb.ts @@ -18,7 +18,7 @@ interface LegacyCMS { awsRegion: string; bucketName: string; buketKey: string; -} + }; file_path: string; is_fileValid: boolean; } diff --git a/api/src/routes/contentMapper.routes.ts b/api/src/routes/contentMapper.routes.ts index 1fc8ba35c..ce37c4dbf 100644 --- a/api/src/routes/contentMapper.routes.ts +++ b/api/src/routes/contentMapper.routes.ts @@ -42,5 +42,4 @@ router.get( asyncRouter(contentMapperController.getSingleContentTypes) ); - export default router; diff --git a/api/src/routes/projects.routes.ts b/api/src/routes/projects.routes.ts index 2cca80ab5..5c7a54099 100644 --- a/api/src/routes/projects.routes.ts +++ b/api/src/routes/projects.routes.ts @@ -69,6 +69,6 @@ router.put( router.delete("/:projectId", asyncRouter(projectController.deleteProject)); //revert Project Route -router.patch("/:projectId", asyncRouter(projectController.revertProject)) +router.patch("/:projectId", asyncRouter(projectController.revertProject)); export default router; diff --git a/api/src/server.ts b/api/src/server.ts index 9e0a1a8a5..b6a47070f 100644 --- a/api/src/server.ts +++ b/api/src/server.ts @@ -16,7 +16,10 @@ import { unmatchedRoutesMiddleware } from "./middlewares/unmatched-routes.middle import logger from "./utils/logger.js"; import contentMapperRoutes from "./routes/contentMapper.routes.js"; import migrationRoutes from "./routes/migration.routes.js"; - +import chokidar from "chokidar"; +import { Server } from "socket.io"; +import http from "http"; +import fs from "fs"; try { const app = express(); app.use( @@ -48,9 +51,45 @@ try { // starting the server & DB connection. (async () => { await connectToDatabase(); - app.listen(config.PORT, () => + const server = app.listen(config.PORT, () => logger.info(`Server listening at port ${config.PORT}`) ); + // Chokidar - Watch for log file changes + const logFilePath = "/Users/rohit/migration-v2-node-server/api/combine.log"; // Replace with the actual path to your log file + const watcher = chokidar.watch(logFilePath); + // Socket.IO - Send logs to client + const io = new Server( + server, + (http, + { + cors: { + origin: "*", // This allows all origins. For production, specify exact origins for security. + methods: ["GET", "POST"], // Specify which HTTP methods are allowed. + allowedHeaders: ["my-custom-header"], // Specify which headers are allowed. + credentials: true, // If your client needs to send cookies or credentials with the requests. + }, + }) + ); + + watcher.on("change", (path) => { + // Read the updated log file + fs.readFile(path, "utf8", (err, data) => { + if (err) { + logger.error(`Error reading log file: ${err}`); + return; + } + // Get just the updated data + // const updatedData = data.slice(data.lastIndexOf("\n") + 1); + console.info("updates", data); + // Emit the updated data to all connected clients + try { + const parsedData = data; + io.emit("logUpdate", parsedData); + } catch (error) { + logger.error(`Error parsing data: ${error}`); + } + }); + }); })(); } catch (e) { logger.error("Error while starting the server!"); diff --git a/api/src/services/contentMapper.service.ts b/api/src/services/contentMapper.service.ts index c21772457..052f9298f 100644 --- a/api/src/services/contentMapper.service.ts +++ b/api/src/services/contentMapper.service.ts @@ -10,7 +10,7 @@ import { STEPPER_STEPS, NEW_PROJECT_STATUS, CONTENT_TYPE_STATUS, - VALIDATION_ERRORS + VALIDATION_ERRORS, } from "../constants/index.js"; import logger from "../utils/logger.js"; import { config } from "../config/index.js"; @@ -36,7 +36,7 @@ const putTestData = async (req: Request) => { return { id, isDeleted: true, ...field }; }); FieldMapperModel.update((data: any) => { - data.field_mapper = [...data?.field_mapper ?? [], ...fields]; + data.field_mapper = [...(data?.field_mapper ?? []), ...fields]; }); contentTypes[index].fieldMapping = fieldIds; }); @@ -108,7 +108,7 @@ const getContentTypes = async (req: Request) => { .value(); content_mapper.push(contentMapperData); }); - + if (!isEmpty(content_mapper)) { if (search) { const filteredResult = content_mapper @@ -254,10 +254,7 @@ const updateContentType = async (req: Request) => { const project = ProjectModelLowdb.data.projects[projectIndex]; if ( - [ - NEW_PROJECT_STATUS[5], - NEW_PROJECT_STATUS[4], - ].includes(project.status) || + [NEW_PROJECT_STATUS[5], NEW_PROJECT_STATUS[4]].includes(project.status) || project.current_step < STEPPER_STEPS.CONTENT_MAPPING ) { logger.error( @@ -280,25 +277,36 @@ const updateContentType = async (req: Request) => { throw new BadRequestError(HTTP_TEXTS.INVALID_CONTENT_TYPE); } - try { await ContentTypesMapperModelLowdb.read(); if (fieldMapping) { - fieldMapping.forEach(async(field: any) => { - if (!field.ContentstackFieldType || field.ContentstackFieldType === '' || field.ContentstackFieldType === 'No matches found' || field.contentstackFieldUid === '') { + fieldMapping.forEach(async (field: any) => { + if ( + !field.ContentstackFieldType || + field.ContentstackFieldType === "" || + field.ContentstackFieldType === "No matches found" || + field.contentstackFieldUid === "" + ) { logger.error( getLogMessage( srcFun, - `${VALIDATION_ERRORS.STRING_REQUIRED.replace("$", "ContentstackFieldType or contentstackFieldUid")}` + `${VALIDATION_ERRORS.STRING_REQUIRED.replace( + "$", + "ContentstackFieldType or contentstackFieldUid" + )}` ) ); await ContentTypesMapperModelLowdb.read(); ContentTypesMapperModelLowdb.update((data: any) => { - data.ContentTypesMappers[updateIndex].status = CONTENT_TYPE_STATUS[3]; + data.ContentTypesMappers[updateIndex].status = + CONTENT_TYPE_STATUS[3]; }); throw new BadRequestError( - `${VALIDATION_ERRORS.STRING_REQUIRED.replace("$", "ContentstackFieldType or contentstackFieldUid")}` + `${VALIDATION_ERRORS.STRING_REQUIRED.replace( + "$", + "ContentstackFieldType or contentstackFieldUid" + )}` ); } }); @@ -323,7 +331,6 @@ const updateContentType = async (req: Request) => { data.ContentTypesMappers[updateIndex].contentstackUid = contentTypeData?.contentstackUid; } - }); if (updateIndex < 0) { @@ -342,7 +349,7 @@ const updateContentType = async (req: Request) => { const fieldIndex = FieldMapperModel.data.field_mapper.findIndex( (f: any) => f?.id === field?.id ); - if (fieldIndex > -1 && field?.ContentstackFieldType !== '') { + if (fieldIndex > -1 && field?.ContentstackFieldType !== "") { FieldMapperModel.update((data: any) => { data.field_mapper[fieldIndex] = field; data.field_mapper[fieldIndex].isDeleted = false; @@ -360,7 +367,7 @@ const updateContentType = async (req: Request) => { .get("ContentTypesMappers") .find({ id: contentTypeId }) .value(); - + return { updatedContentType }; } catch (error: any) { logger.error( @@ -716,5 +723,5 @@ export const contentMapperService = { resetToInitialMapping, resetAllContentTypesMapping, removeMapping, - getSingleContentTypes + getSingleContentTypes, }; diff --git a/api/src/services/org.service.ts b/api/src/services/org.service.ts index bc69192e8..90324fb39 100644 --- a/api/src/services/org.service.ts +++ b/api/src/services/org.service.ts @@ -49,13 +49,14 @@ const getAllStacks = async (req: Request): Promise => { }; } let stacks = res?.data?.stacks; - if(search){ - stacks = stacks.filter((stack:{name: string, description:string})=>{ + if (search) { + stacks = stacks.filter((stack: { name: string; description: string }) => { const stackName = stack?.name?.toLowerCase(); const stackDescription = stack?.description?.toLowerCase(); - return stackName?.includes(search) || stackDescription?.includes(search); - - }) + return ( + stackName?.includes(search) || stackDescription?.includes(search) + ); + }); } const locale = await getStackLocal(token_payload, stacks); return { @@ -301,7 +302,7 @@ const getStackLocal = async (token_payload: any, data: any) => { token_payload?.region as keyof typeof config.CS_API ]!}/locales`, headers: { - api_key: stack.api_key, + api_key: stack.api_key, authtoken, }, }) diff --git a/api/src/services/projects.service.ts b/api/src/services/projects.service.ts index 337f05fa9..f5e4bae00 100644 --- a/api/src/services/projects.service.ts +++ b/api/src/services/projects.service.ts @@ -1,8 +1,8 @@ import { Request } from "express"; import ProjectModelLowdb from "../models/project-lowdb.js"; -import ContentTypesMapperModelLowdb from "../models/contentTypesMapper-lowdb.js" +import ContentTypesMapperModelLowdb from "../models/contentTypesMapper-lowdb.js"; import FieldMapperModel from "../models/FieldMapper.js"; - + import { BadRequestError, ExceptionFunction, @@ -35,7 +35,7 @@ const getAllProjects = async (req: Request) => { org_id: orgId, region, owner: user_id, - isDeleted:false + isDeleted: false, }) .value(); @@ -84,18 +84,19 @@ const createProject = async (req: Request) => { test_stacks: [], current_test_stack_id: "", legacy_cms: { - "is_fileValid":false, + is_fileValid: false, awsDetails: { awsRegion: "", bucketName: "", - buketKey: "" - } }, + buketKey: "", + }, + }, content_mapper: [], execution_log: [], created_by: user_id, updated_at: new Date().toISOString(), created_at: new Date().toISOString(), - isDeleted:false + isDeleted: false, }; try { @@ -352,7 +353,8 @@ const affixConfirmation = async (req: Request) => { const updateFileFormat = async (req: Request) => { const { orgId, projectId } = req.params; - const { token_payload, file_format,file_path,is_fileValid,awsDetails } = req.body; + const { token_payload, file_format, file_path, is_fileValid, awsDetails } = + req.body; const srcFunc = "updateFileFormat"; const projectIndex = (await getProjectUtil( projectId, @@ -394,16 +396,19 @@ const updateFileFormat = async (req: Request) => { } try { - ProjectModelLowdb.update((data: any) => { + ProjectModelLowdb.update((data: any) => { data.projects[projectIndex].legacy_cms.file_format = file_format; data.projects[projectIndex].legacy_cms.file_path = file_path; data.projects[projectIndex].legacy_cms.is_fileValid = is_fileValid; data.projects[projectIndex].current_step = STEPPER_STEPS.LEGACY_CMS; data.projects[projectIndex].status = NEW_PROJECT_STATUS[0]; data.projects[projectIndex].updated_at = new Date().toISOString(); - data.projects[projectIndex].legacy_cms.awsDetails.awsRegion = awsDetails.awsRegion; - data.projects[projectIndex].legacy_cms.awsDetails.bucketName = awsDetails.bucketName; - data.projects[projectIndex].legacy_cms.awsDetails.buketKey = awsDetails.buketKey; + data.projects[projectIndex].legacy_cms.awsDetails.awsRegion = + awsDetails.awsRegion; + data.projects[projectIndex].legacy_cms.awsDetails.bucketName = + awsDetails.bucketName; + data.projects[projectIndex].legacy_cms.awsDetails.buketKey = + awsDetails.buketKey; }); logger.info( @@ -643,7 +648,7 @@ const updateCurrentStep = async (req: Request) => { ProjectModelLowdb.update((data: any) => { data.projects[projectIndex].current_step = STEPPER_STEPS.CONTENT_MAPPING; - // data.projects[projectIndex].status = NEW_PROJECT_STATUS[3]; + // data.projects[projectIndex].status = NEW_PROJECT_STATUS[3]; data.projects[projectIndex].updated_at = new Date().toISOString(); }); break; @@ -778,9 +783,9 @@ const revertProject = async (req: Request) => { )) as number; const projects = ProjectModelLowdb.data.projects[projectIndex]; - if (!projects){ + if (!projects) { throw new NotFoundError(HTTP_TEXTS.PROJECT_NOT_FOUND); - } else{ + } else { ProjectModelLowdb.update((data: any) => { data.projects[projectIndex].isDeleted = false; }); @@ -795,11 +800,11 @@ const revertProject = async (req: Request) => { status: HTTP_CODES.OK, data: { message: HTTP_TEXTS.PROJECT_REVERT, - Project:projects + Project: projects, }, }; } -} +}; export const projectService = { getAllProjects, getProject, @@ -813,5 +818,5 @@ export const projectService = { updateDestinationStack, updateCurrentStep, deleteProject, - revertProject + revertProject, }; From 9754728f96855c0b9d8ac61548acd5ba34b18577 Mon Sep 17 00:00:00 2001 From: Rohit Kini Date: Wed, 10 Jul 2024 12:25:43 +0530 Subject: [PATCH 2/3] logger --- ui/package-lock.json | 224 +++++++++++++++++++++- ui/package.json | 3 + ui/src/components/LogScreen/index.scss | 25 +++ ui/src/components/LogScreen/index.tsx | 81 ++++++++ ui/src/components/ProfileHeader/index.tsx | 12 +- ui/src/pages/Home/index.tsx | 3 +- 6 files changed, 337 insertions(+), 11 deletions(-) create mode 100644 ui/src/components/LogScreen/index.scss create mode 100644 ui/src/components/LogScreen/index.tsx diff --git a/ui/package-lock.json b/ui/package-lock.json index d2cab51b3..e78b26cd1 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -19,6 +19,7 @@ "@types/react-redux": "^7.1.33", "axios": "^1.5.1", "bootstrap": "5.1.3", + "chokidar": "^3.6.0", "html-react-parser": "^4.2.9", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -29,6 +30,8 @@ "react-scripts": "5.0.1", "redux-persist": "^6.0.0", "sass": "^1.68.0", + "socket.io": "^4.7.5", + "socket.io-client": "^4.7.5", "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, @@ -5024,6 +5027,11 @@ "@sinonjs/commons": "^1.7.0" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + }, "node_modules/@storybook/addons": { "version": "6.5.16", "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.5.16.tgz", @@ -5914,6 +5922,19 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/css-modules": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/css-modules/-/css-modules-1.0.5.tgz", @@ -7785,6 +7806,14 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -8156,15 +8185,9 @@ "integrity": "sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==" }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -8177,6 +8200,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -8535,6 +8561,18 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -9804,6 +9842,94 @@ "node": ">= 0.8" } }, + "node_modules/engine.io": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz", + "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/enhanced-resolve": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", @@ -21630,6 +21756,78 @@ "resolved": "https://registry.npmjs.org/sleep-promise/-/sleep-promise-8.0.1.tgz", "integrity": "sha512-nfwyX+G1dsx2R1DMMKWLpNxuHMOCL7JIRBUw0fl7Z4nZ1YZK0apZuGY8MDexn0HDZzgbERgj/CrNtsYpo/B7eA==" }, + "node_modules/socket.io": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/socket.io-client": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", + "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -24153,6 +24351,14 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/ui/package.json b/ui/package.json index e578593c2..51f70482f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,6 +14,7 @@ "@types/react-redux": "^7.1.33", "axios": "^1.5.1", "bootstrap": "5.1.3", + "chokidar": "^3.6.0", "html-react-parser": "^4.2.9", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -24,6 +25,8 @@ "react-scripts": "5.0.1", "redux-persist": "^6.0.0", "sass": "^1.68.0", + "socket.io": "^4.7.5", + "socket.io-client": "^4.7.5", "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, diff --git a/ui/src/components/LogScreen/index.scss b/ui/src/components/LogScreen/index.scss new file mode 100644 index 000000000..f08a7940f --- /dev/null +++ b/ui/src/components/LogScreen/index.scss @@ -0,0 +1,25 @@ +@import '../../scss/variables'; + +.logs-container { + font-family: Arial, sans-serif; +} + +.log-entry { + display: flex; +} + +.log-time { + font-weight: bold; + margin-right: 8px; + color: #333; + padding-right: 5px; +} + +.log-message { + flex-grow: 1; + color: #555; +} + +.log-entry:nth-child(odd) { + background-color: #f9f9f9; +} diff --git a/ui/src/components/LogScreen/index.tsx b/ui/src/components/LogScreen/index.tsx new file mode 100644 index 000000000..f80ad5a3c --- /dev/null +++ b/ui/src/components/LogScreen/index.tsx @@ -0,0 +1,81 @@ +import React, { useEffect, useState } from 'react'; +import { PageLayout, PageTitle, Button } from '@contentstack/venus-components'; +import io from 'socket.io-client'; +import './index.scss'; +const logStyles: { [key: string]: React.CSSProperties } = { + info: { backgroundColor: '#f1f1f1' }, + warn: { backgroundColor: '#ffeeba', color: '#856404' }, + error: { backgroundColor: '#f8d7da', color: '#721c24' }, + success: { backgroundColor: '#d4edda', color: '#155724' }, +}; + +const LogViewer = () => { + const [logs, setLogs] = useState(["Loading logs..."]); + + useEffect(() => { + const socket = io('http://localhost:5000'); // Connect to the server + socket.on('logUpdate', (newLogs: string) => { + const logArray = newLogs.split('\n'); + // console.log(logArray); + setLogs(logArray); + + }); + + return () => { + socket.disconnect(); // Cleanup on component unmount + }; + }, []); + +return( +
+ List Data
+ }} + footer={{ + // component:
2020 Contentstack. All rights reserved. Support | Privacy | Terms
+ }} + header={{ + // backNavigation: function noRefCheck(){}, + component:

Logs

, + }} + type="edit" + // version="v1" + /> + +) + // return ( + //
+ //

Execution Logs

+ //
+ // {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); + // } + // })} + //
+ //
+ // ); +}; + +export default LogViewer; \ No newline at end of file diff --git a/ui/src/components/ProfileHeader/index.tsx b/ui/src/components/ProfileHeader/index.tsx index 36c067b1a..63c3a9414 100644 --- a/ui/src/components/ProfileHeader/index.tsx +++ b/ui/src/components/ProfileHeader/index.tsx @@ -29,7 +29,17 @@ const ProfileCard = () => {
{user?.first_name} {user?.last_name}
{user?.email}
-
+
{ + if (event.key === 'Enter' || event.key === ' ') { + handleLogout(); + } + }} + > {LOG_OUT} Log out
diff --git a/ui/src/pages/Home/index.tsx b/ui/src/pages/Home/index.tsx index 2436eaf71..79b1f9b4f 100644 --- a/ui/src/pages/Home/index.tsx +++ b/ui/src/pages/Home/index.tsx @@ -3,7 +3,7 @@ import { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { Button } from '@contentstack/venus-components'; import parse from 'html-react-parser'; - +import LogViewer from '../../components/LogScreen'; // Services import { getCMSDataFromFile } from '../../cmsData/cmsSelector'; @@ -45,6 +45,7 @@ const Home = () => { )} +
); }; From ad2adc9bec493eb693a7d1ab22591ba46c4b49e7 Mon Sep 17 00:00:00 2001 From: Sayali Joshi Date: Wed, 10 Jul 2024 19:40:41 +0530 Subject: [PATCH 3/3] Test Migration Logger screen completed --- api/src/server.ts | 2 +- ui/public/index.html | 6 +- ui/src/components/LogScreen/index.scss | 58 +++++++++-- ui/src/components/LogScreen/index.tsx | 109 ++++++++++----------- ui/src/components/TestMigration/index.scss | 13 +-- ui/src/components/TestMigration/index.tsx | 11 ++- ui/src/pages/Home/index.tsx | 3 +- 7 files changed, 121 insertions(+), 81 deletions(-) diff --git a/api/src/server.ts b/api/src/server.ts index b6a47070f..678121afd 100644 --- a/api/src/server.ts +++ b/api/src/server.ts @@ -55,7 +55,7 @@ try { logger.info(`Server listening at port ${config.PORT}`) ); // Chokidar - Watch for log file changes - const logFilePath = "/Users/rohit/migration-v2-node-server/api/combine.log"; // Replace with the actual path to your log file + const logFilePath = "/Users/sayali.joshi/Projects/migration-v2-node-server/api/combine.log"; // Replace with the actual path to your log file const watcher = chokidar.watch(logFilePath); // Socket.IO - Send logs to client const io = new Server( diff --git a/ui/public/index.html b/ui/public/index.html index 9eb09bff4..b730eece4 100644 --- a/ui/public/index.html +++ b/ui/public/index.html @@ -21,18 +21,18 @@ crossorigin="anonymous" /> + + - - - +