Skip to content
Merged

Dev #423

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions api/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,41 @@ try {
credentials: true,
},
});
let fileOffset = 0;
const CHUNK_SIZE = 1024 * 1024; // Limit batch size to 1MB

// Emit initial log file content to connected clients
// File watcher for log file changes
watcher.on("change", async (path) => {
console.info(`File changed: ${path}`);
// Read the updated file content
try {
const data = await fs.promises.readFile(path, "utf8")
// Emit the updated log content to connected clients
io.emit("logUpdate", data);
const fileStats = await fs.promises.stat(path);

// Read the entire file if there is an update (new logs or changes)
const stream = fs.createReadStream(path, { start: fileOffset });
let fileData = '';

stream.on('data', (chunk) => {
fileData += chunk.toString(); // Collect the file data as a string
});

stream.on('end', () => {
// Emit the file content in chunks
let index = 0;
while (index < fileData?.length) {
const chunk = fileData?.slice(index, index + CHUNK_SIZE); // Get the next chunk

io.emit('logUpdate', chunk);
index += CHUNK_SIZE; // Move to the next chunk
}

// Update the file offset for the next read
fileOffset = fileStats.size;
});

stream.on('error', (err) => {
console.error('Error reading log file:', err);
});
} catch (error) {
logger.error(`Error emitting log data: ${error}`);
}
Expand Down
21 changes: 12 additions & 9 deletions ui/src/components/ContentMapper/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1694,7 +1694,7 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R
}
};

const handleCTDeleted = async(isContentType:boolean) => {
const handleCTDeleted = async(isContentType:boolean, contentTypes:ContentTypeList[]) => {
const updatedContentTypeMapping = Object.fromEntries(
Object.entries(newMigrationData?.content_mapping?.content_type_mapping || {}).filter(
([key]) => !selectedContentType?.contentstackUid.includes(key)
Expand Down Expand Up @@ -1776,6 +1776,7 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R
...newMigrationData,
content_mapping:{
...newMigrationData?.content_mapping,
existingCT: contentTypes,
content_type_mapping : updatedContentTypeMapping

}
Expand All @@ -1793,10 +1794,10 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R
if (isContentType) {
try {
const { data , status} = await getExistingContentTypes(projectId, otherContentType?.id ?? '');
if (status == 201 && data?.contentTypes?.length > 0 && data?.selectedContentType) {
if (status == 201 && data?.contentTypes?.length > 0) {
(otherContentType?.id === data?.selectedContentType?.uid) && setsCsCTypeUpdated(false);

(otherContentType?.id && otherContentType?.label !== data?.selectedContentType?.title)
(otherContentType?.id && otherContentType?.label !== data?.selectedContentType?.title && data?.selectedContentType?.title)
&& setOtherContentType({
label: data?.selectedContentType?.title,
value: data?.selectedContentType?.title,
Expand Down Expand Up @@ -1824,8 +1825,6 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R
setContentTypeSchema(data?.selectedContentType?.schema);
}
} else {

await handleCTDeleted(isContentType);
Notification({
notificationContent: { text: "No content found in the stack" },
notificationProps: {
Expand All @@ -1835,6 +1834,9 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R
type: 'error'
});
}
if(otherContentType?.id && data?.contentTypes?.every((item: any) => item?.uid !== otherContentType?.id)){
await handleCTDeleted(isContentType, data?.contentTypes);
}
} catch (error) {
console.log(error);
return error;
Expand All @@ -1843,10 +1845,10 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R
try {
const { data, status } = await getExistingGlobalFields(projectId, otherContentType?.id ?? '');

if (status == 201 && data?.globalFields?.length > 0 && data?.selectedGlobalField) {
if (status == 201 && data?.globalFields?.length > 0) {
(otherContentType?.id === data?.selectedGlobalField?.uid) && setsCsCTypeUpdated(false);

(otherContentType?.id && otherContentType?.label !== data?.selectedGlobalField?.title)
(otherContentType?.id && otherContentType?.label !== data?.selectedGlobalField?.title && data?.selectedGlobalField?.title)
&& setOtherContentType({
label: data?.selectedGlobalField?.title,
value:data?.selectedGlobalField?.title,
Expand Down Expand Up @@ -1874,8 +1876,6 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R
});
} else {

await handleCTDeleted(isContentType);

Notification({
notificationContent: { text: "No Global Fields found in the stack" },
notificationProps: {
Expand All @@ -1885,6 +1885,9 @@ const ContentMapper = forwardRef(({handleStepChange}: contentMapperProps, ref: R
type: 'error'
});
}
if(otherContentType?.id && data?.globalFields?.every((item: any) => item?.uid !== otherContentType?.id)){
await handleCTDeleted(isContentType, data?.globalFields);
}
} catch (error) {
console.log(error);
return error;
Expand Down
12 changes: 6 additions & 6 deletions ui/src/components/DestinationStack/Actions/LoadStacks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ const LoadStacks = (props: LoadFileFormatProps) => {


};

/**** ALL METHODS HERE ****/

//Handle Legacy cms selection
Expand Down Expand Up @@ -214,11 +214,11 @@ const LoadStacks = (props: LoadFileFormatProps) => {
return stack?.value === newMigrationData?.destination_stack?.selectedStack?.value
}
)
: DEFAULT_DROPDOWN;
if (stackData?.data?.stacks?.length === 0 && (!stackData?.data?.stack)) {
setIsError(true);
setErrorMessage("Please create new stack there is no stack available");
}
: null;
// if (stackData?.data?.stacks?.length === 0 && (!stackData?.data?.stack)) {
// setIsError(true);
// setErrorMessage("Please create new stack there is no stack available");
// }

if(selectedStackData){
setSelectedStack(selectedStackData);
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/LegacyCms/Actions/LoadFileFormat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const LoadFileFormat = (props: LoadFileFormatProps) => {
const cmsType = !isEmptyString(newMigrationData?.legacy_cms?.selectedCms?.parent) ? newMigrationData?.legacy_cms?.selectedCms?.parent : data?.cmsType?.toLowerCase();
const filePath = data?.localPath?.toLowerCase();
const fileFormat = getFileExtension(filePath);
if(! isEmptyString(selectedCard?.fileformat_id)){
if(! isEmptyString(selectedCard?.fileformat_id) && selectedCard?.fileformat_id !== fileFormat && newMigrationData?.project_current_step > 1){
setFileIcon(selectedCard?.title);
}
else{
Expand Down
95 changes: 64 additions & 31 deletions ui/src/components/LogScreen/MigrationLogViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,18 @@ type LogsType = {
handleStepChange: (currentStep: number) => void;
}

export interface LogEntry {
level?: string;
message?: string;
timestamp?: string | null;
}

/**
* MigrationLogViewer component displays logs received from the server.
* @param {string} serverPath - The path of the server to connect to.
*/
const MigrationLogViewer = ({ serverPath }: LogsType) => {
const [logs, setLogs] = useState<string[]>([JSON.stringify({ message: "Migration logs will appear here once the process begins.", level: '' })]);
const [logs, setLogs] = useState<LogEntry[]>([{ message: "Migration logs will appear here once the process begins.", level: '' }]);
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const [zoomLevel, setZoomLevel] = useState(1);

Expand Down Expand Up @@ -75,8 +81,27 @@ const MigrationLogViewer = ({ serverPath }: LogsType) => {
* @param {string} newLogs - The new logs received from the server.
*/
socket.on('logUpdate', (newLogs: string) => {
const logArray = newLogs.split('\n');
setLogs(logArray);
const parsedLogsArray: LogEntry[] = [];
const logArray = newLogs?.split('\n')

logArray?.forEach((logLine) => {
try {
//parse each log entry as a JSON object
const parsedLog = JSON?.parse(logLine);

// Build the log object with default values
const plogs = {
level: parsedLog.level || 'info',
message: parsedLog.message || 'Unknown message',
timestamp: parsedLog.timestamp || null,
};
parsedLogsArray.push(plogs);
}catch(error){
console.log("error in parsing logs : ", error);
}
});

setLogs((prevLogs) => [...prevLogs, ...parsedLogsArray]);
});

return () => {
Expand Down Expand Up @@ -147,8 +172,8 @@ const MigrationLogViewer = ({ serverPath }: LogsType) => {

logs?.forEach((log) => {
try {
const logObject = JSON.parse(log);
const message = logObject.message;
//const logObject = JSON.parse(log);
const message = log.message;

if (message === "Migration Process Completed") {

Expand Down Expand Up @@ -209,38 +234,46 @@ const MigrationLogViewer = ({ serverPath }: LogsType) => {
transformOrigin: "top left",
transition: "transform 0.1s ease"
}}>
{logs?.map((log, index) => {
const key = `${index}-${new Date().getMilliseconds()}`
try {
const logObject = JSON.parse(log);
const level = logObject.level;
const timestamp = logObject.timestamp;
const message = logObject.message;

return (
{logs.map((log, index) => {
try {
//const logObject = JSON.parse(log);
const { level, timestamp, message } = log;

return (
newMigrationData?.destination_stack?.migratedStacks?.includes(newMigrationData?.destination_stack?.selectedStack?.value) ?
<div key={`${index?.toString}`} style={logStyles[level] || logStyles.info} className="log-entry text-center">
<div className="log-message">Migration has already done in selected stack. Please create a new project.</div>
</div>
:
message === "Migration logs will appear here once the process begins."
? <div key={`${index?.toString}`} style={logStyles[level] || logStyles.info} className="log-entry text-center">
<div className="log-message">{message}</div>
<div key={`${index?.toString}`} style={logStyles[level || ''] || logStyles.info} className="log-entry text-center">
<div className="log-message">Migration has already done in selected stack. Please create a new project.</div>
</div>
: <div key={key} style={logStyles[level] || logStyles.info} className="log-entry logs-bg">
<div className="log-number">{index}</div>
<div className="log-time">{timestamp ? new Date(timestamp)?.toTimeString()?.split(' ')[0] : new Date()?.toTimeString()?.split(' ')[0]}</div>
<div className="log-message">{message}</div>
:
<div
key={index}
// style={logStyles[level || ''] || logStyles.info}
// className="log-entry logs-bg"
>
{message === "Migration logs will appear here once the process begins."
? <div style={logStyles[level || ''] || logStyles.info} className="log-entry text-center">
<div className="log-message">{message}</div>
</div> :
<div style={logStyles[level || ''] || logStyles.info} className="log-entry logs-bg" >
<div className="log-number">{index}</div>
<div className="log-time">
{timestamp ? new Date(timestamp)?.toTimeString()?.split(' ')[0] :
new Date()?.toTimeString()?.split(' ')[0]}
</div>
<div className="log-message">{message}</div>
</div>
}
</div>
);
} catch (error) {
console.error('Invalid JSON string', error);
}
})}
);
} catch (error) {
console.error('Invalid log format', error);
return null;
}
})}
</div>
}
</div>
{!newMigrationData?.migration_execution?.migrationCompleted && (
{!newMigrationData?.migration_execution?.migrationCompleted && !logs?.every((log) => log.message === "Migration logs will appear here once the process begins.") && (
<div className='action-items'>
<Icon icon="ArrowUp" version='v2' onClick={handleScrollToTop} />
<Icon icon="ArrowDown" version='v2' onClick={handleScrollToBottom} />
Expand Down
Loading
Loading