Files
parcer/src/components/run/InterpretationLog.tsx

451 lines
18 KiB
TypeScript
Raw Normal View History

2024-06-24 22:34:40 +05:30
import * as React from 'react';
import SwipeableDrawer from '@mui/material/SwipeableDrawer';
2024-06-24 22:34:40 +05:30
import Typography from '@mui/material/Typography';
2025-05-07 09:22:50 +05:30
import { Button, Grid, Box } from '@mui/material';
2024-06-24 22:34:40 +05:30
import { useCallback, useEffect, useRef, useState } from "react";
2024-08-22 06:08:19 +05:30
import { useBrowserDimensionsStore } from "../../context/browserDimensions";
2024-08-25 22:46:52 +05:30
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
2024-08-25 22:49:07 +05:30
import Paper from '@mui/material/Paper';
2024-08-26 19:57:30 +05:30
import StorageIcon from '@mui/icons-material/Storage';
2024-10-24 01:04:55 +05:30
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
2025-01-09 20:07:42 +05:30
import { SidePanelHeader } from '../recorder/SidePanelHeader';
import { useGlobalInfoStore } from '../../context/globalInfo';
2024-11-24 00:49:39 +05:30
import { useThemeMode } from '../../context/theme-provider';
import { useTranslation } from 'react-i18next';
2025-05-07 09:22:50 +05:30
import { useBrowserSteps } from '../../context/browserSteps';
2024-08-25 22:49:07 +05:30
2024-09-08 07:50:59 +05:30
interface InterpretationLogProps {
isOpen: boolean;
setIsOpen: (isOpen: boolean) => void;
}
2024-09-27 23:39:30 +05:30
export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, setIsOpen }) => {
const { t } = useTranslation();
2025-04-29 00:27:35 +05:30
const [captureListData, setCaptureListData] = useState<any[]>([]);
const [captureTextData, setCaptureTextData] = useState<any[]>([]);
const [screenshotData, setScreenshotData] = useState<string[]>([]);
2024-06-24 22:34:40 +05:30
2025-04-29 00:27:35 +05:30
const [captureListPage, setCaptureListPage] = useState<number>(0);
const [screenshotPage, setScreenshotPage] = useState<number>(0);
const [activeTab, setActiveTab] = useState(0);
2024-06-24 22:34:40 +05:30
const logEndRef = useRef<HTMLDivElement | null>(null);
2025-05-07 09:22:50 +05:30
const { browserSteps } = useBrowserSteps();
const { browserWidth, outputPreviewHeight, outputPreviewWidth } = useBrowserDimensionsStore();
2025-06-25 12:53:47 +05:30
const { currentWorkflowActionsState, shouldResetInterpretationLog } = useGlobalInfoStore();
const [showPreviewData, setShowPreviewData] = useState<boolean>(false);
2024-08-22 06:08:19 +05:30
const toggleDrawer = (newOpen: boolean) => (event: React.KeyboardEvent | React.MouseEvent) => {
if (
event.type === 'keydown' &&
((event as React.KeyboardEvent).key === 'Tab' ||
(event as React.KeyboardEvent).key === 'Shift')
) {
return;
}
2024-09-08 07:50:59 +05:30
setIsOpen(newOpen);
2024-06-24 22:34:40 +05:30
};
2025-05-07 09:22:50 +05:30
const updateActiveTab = useCallback(() => {
const availableTabs = getAvailableTabs();
if (captureListData.length > 0 && availableTabs.findIndex(tab => tab.id === 'captureList') !== -1) {
setActiveTab(availableTabs.findIndex(tab => tab.id === 'captureList'));
} else if (captureTextData.length > 0 && availableTabs.findIndex(tab => tab.id === 'captureText') !== -1) {
setActiveTab(availableTabs.findIndex(tab => tab.id === 'captureText'));
} else if (screenshotData.length > 0 && availableTabs.findIndex(tab => tab.id === 'captureScreenshot') !== -1) {
setActiveTab(availableTabs.findIndex(tab => tab.id === 'captureScreenshot'));
}
}, [captureListData.length, captureTextData.length, screenshotData.length]);
2025-06-25 12:53:47 +05:30
useEffect(() => {
const textSteps = browserSteps.filter(step => step.type === 'text');
if (textSteps.length > 0) {
const textDataRow: Record<string, string> = {};
textSteps.forEach(step => {
textDataRow[step.label] = step.data;
});
setCaptureTextData([textDataRow]);
2025-04-29 00:27:35 +05:30
}
2025-06-25 12:53:47 +05:30
const listSteps = browserSteps.filter(step => step.type === 'list');
if (listSteps.length > 0) {
setCaptureListData(listSteps);
}
2024-06-24 22:34:40 +05:30
2025-06-25 12:53:47 +05:30
const screenshotSteps = browserSteps.filter(step =>
step.type === 'screenshot'
) as Array<{ type: 'screenshot'; id: number; fullPage: boolean; actionId?: string; screenshotData?: string }>;
2025-05-07 09:22:50 +05:30
2025-06-25 12:53:47 +05:30
const screenshotsWithData = screenshotSteps.filter(step => step.screenshotData);
if (screenshotsWithData.length > 0) {
const screenshots = screenshotsWithData.map(step => step.screenshotData!);
setScreenshotData(screenshots);
}
updateActiveTab();
}, [browserSteps, updateActiveTab]);
2024-08-28 23:56:30 +05:30
useEffect(() => {
if (shouldResetInterpretationLog) {
2025-04-29 00:27:35 +05:30
setCaptureListData([]);
setCaptureTextData([]);
setScreenshotData([]);
setActiveTab(0);
setCaptureListPage(0);
setScreenshotPage(0);
2025-06-25 12:53:47 +05:30
setShowPreviewData(false);
}
}, [shouldResetInterpretationLog]);
2025-04-29 00:27:35 +05:30
const getAvailableTabs = useCallback(() => {
const tabs = [];
if (captureListData.length > 0) {
tabs.push({ id: 'captureList', label: 'Lists' });
}
if (captureTextData.length > 0) {
tabs.push({ id: 'captureText', label: 'Texts' });
}
if (screenshotData.length > 0) {
tabs.push({ id: 'captureScreenshot', label: 'Screenshots' });
}
return tabs;
2025-06-25 12:53:47 +05:30
}, [captureListData.length, captureTextData.length, screenshotData.length, showPreviewData]);
2024-09-27 23:39:30 +05:30
2025-04-29 00:27:35 +05:30
const availableTabs = getAvailableTabs();
useEffect(() => {
if (activeTab >= availableTabs.length && availableTabs.length > 0) {
setActiveTab(0);
}
}, [activeTab, availableTabs.length]);
const { hasScrapeListAction, hasScreenshotAction, hasScrapeSchemaAction } = currentWorkflowActionsState;
useEffect(() => {
if (hasScrapeListAction || hasScrapeSchemaAction || hasScreenshotAction) {
setIsOpen(true);
}
}, [hasScrapeListAction, hasScrapeSchemaAction, hasScreenshotAction, setIsOpen]);
2025-01-09 19:15:37 +05:30
const { darkMode } = useThemeMode();
2024-11-24 00:49:39 +05:30
2025-04-29 00:27:35 +05:30
const getCaptureTextColumns = captureTextData.length > 0 ? Object.keys(captureTextData[0]) : [];
const shouldShowTabs = availableTabs.length > 1;
const getSingleContentType = () => {
if (availableTabs.length === 1) {
return availableTabs[0].id;
}
return null;
};
const singleContentType = getSingleContentType();
2024-06-24 22:34:40 +05:30
return (
2024-10-21 15:21:12 +05:30
<Grid container>
<Grid item xs={12} md={9} lg={9}>
<div style={{ height: '20px' }}></div>
2024-10-21 15:21:12 +05:30
<Button
onClick={toggleDrawer(true)}
variant="contained"
color="primary"
sx={{
2025-01-09 19:15:37 +05:30
marginTop: '10px',
2024-10-21 15:21:12 +05:30
color: 'white',
position: 'absolute',
background: '#ff00c3',
border: 'none',
padding: '10px 20px',
width: browserWidth,
2024-10-21 15:21:12 +05:30
overflow: 'hidden',
textAlign: 'left',
justifyContent: 'flex-start',
'&:hover': {
backgroundColor: '#ff00c3',
},
}}
>
2025-01-09 19:15:37 +05:30
<ArrowUpwardIcon fontSize="inherit" sx={{ marginRight: '10px' }} />
{t('interpretation_log.titles.output_preview')}
2024-10-21 15:21:12 +05:30
</Button>
<SwipeableDrawer
anchor="bottom"
open={isOpen}
onClose={toggleDrawer(false)}
onOpen={toggleDrawer(true)}
PaperProps={{
sx: {
2025-01-08 21:04:43 +05:30
background: `${darkMode ? '#1e2124' : 'white'}`,
color: `${darkMode ? 'white' : 'black'}`,
2024-10-21 15:21:12 +05:30
padding: '10px',
height: outputPreviewHeight,
width: outputPreviewWidth,
2024-10-21 15:21:12 +05:30
display: 'flex',
2025-04-29 00:27:35 +05:30
flexDirection: 'column',
borderRadius: '10px 10px 0 0',
2024-10-21 15:21:12 +05:30
},
}}
>
<Typography variant="h6" gutterBottom style={{ display: 'flex', alignItems: 'center' }}>
2025-01-09 19:15:37 +05:30
<StorageIcon style={{ marginRight: '8px' }} />
{t('interpretation_log.titles.output_preview')}
</Typography>
2025-04-29 00:27:35 +05:30
2025-06-25 12:53:47 +05:30
{showPreviewData && availableTabs.length > 0 ? (
2025-04-29 00:27:35 +05:30
<>
{shouldShowTabs && (
<Box
sx={{
display: 'flex',
borderBottom: '1px solid',
borderColor: darkMode ? '#3a4453' : '#dee2e6',
backgroundColor: darkMode ? '#2a3441' : '#f8f9fa'
}}
>
{availableTabs.map((tab, index) => (
<Box
key={tab.id}
onClick={() => setActiveTab(index)}
sx={{
px: 4,
py: 2,
cursor: 'pointer',
borderBottom: activeTab === index ? '2px solid' : 'none',
borderColor: activeTab === index ? (darkMode ? '#ff00c3' : '#ff00c3') : 'transparent',
backgroundColor: activeTab === index ? (darkMode ? '#34404d' : '#e9ecef') : 'transparent',
color: darkMode ? 'white' : 'black',
fontWeight: activeTab === index ? 500 : 400,
textAlign: 'center',
position: 'relative',
'&:hover': {
backgroundColor: activeTab !== index ? (darkMode ? '#303b49' : '#e2e6ea') : undefined
}
}}
>
<Typography variant="body1">
{tab.label}
</Typography>
</Box>
))}
</Box>
)}
2025-04-29 00:27:35 +05:30
<Box sx={{ flexGrow: 1, overflow: 'auto', p: 0 }}>
{(activeTab === availableTabs.findIndex(tab => tab.id === 'captureList') || singleContentType === 'captureList') && captureListData.length > 0 && (
2025-04-29 00:27:35 +05:30
<Box>
<Box sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
mb: 2,
mt: 2
}}>
<Typography variant="body2">
{`Table ${captureListPage + 1} of ${captureListData.length}`}
</Typography>
<Box>
<Button
onClick={() => setCaptureListPage(prev => Math.max(0, prev - 1))}
disabled={captureListPage === 0}
size="small"
>
Previous
</Button>
<Button
onClick={() => setCaptureListPage(prev => Math.min(captureListData.length - 1, prev + 1))}
disabled={captureListPage >= captureListData.length - 1}
size="small"
sx={{ ml: 1 }}
>
Next
</Button>
</Box>
</Box>
<TableContainer component={Paper} sx={{ boxShadow: 'none', borderRadius: 0 }}>
<Table>
<TableHead>
<TableRow>
2025-05-07 09:22:50 +05:30
{Object.values(captureListData[captureListPage]?.fields || {}).map((field: any, index) => (
<TableCell
key={index}
sx={{
borderBottom: '1px solid',
borderColor: darkMode ? '#3a4453' : '#dee2e6',
backgroundColor: darkMode ? '#2a3441' : '#f8f9fa'
}}
>
{field.label}
</TableCell>
))}
2025-04-29 00:27:35 +05:30
</TableRow>
</TableHead>
<TableBody>
2025-05-07 09:22:50 +05:30
{(captureListData[captureListPage]?.data || [])
.slice(0, Math.min(captureListData[captureListPage]?.limit || 10, 5))
.map((row: any, rowIndex: any) => (
<TableRow
key={rowIndex}
sx={{
borderBottom: rowIndex < Math.min(
(captureListData[captureListPage]?.data?.length || 0),
Math.min(captureListData[captureListPage]?.limit || 10, 5)
) - 1 ? '1px solid' : 'none',
borderColor: darkMode ? '#3a4453' : '#dee2e6'
}}
>
{Object.values(captureListData[captureListPage]?.fields || {}).map((field: any, colIndex) => (
<TableCell
key={colIndex}
sx={{
borderBottom: 'none',
py: 2
}}
>
{row[field.label]}
</TableCell>
))}
</TableRow>
))
}
2025-04-29 00:27:35 +05:30
</TableBody>
</Table>
</TableContainer>
</Box>
)}
{(activeTab === availableTabs.findIndex(tab => tab.id === 'captureScreenshot') || singleContentType === 'captureScreenshot') && screenshotData.length > 0 && (
2025-04-29 00:27:35 +05:30
<Box>
{screenshotData.length > 1 && (
<Box sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
mb: 2,
mt: 2
}}>
<Typography variant="body2">
{`Screenshot ${screenshotPage + 1} of ${screenshotData.length}`}
</Typography>
<Box>
<Button
onClick={() => setScreenshotPage(prev => Math.max(0, prev - 1))}
disabled={screenshotPage === 0}
size="small"
>
Previous
</Button>
<Button
onClick={() => setScreenshotPage(prev => Math.min(screenshotData.length - 1, prev + 1))}
disabled={screenshotPage >= screenshotData.length - 1}
size="small"
sx={{ ml: 1 }}
>
Next
</Button>
</Box>
</Box>
)}
{screenshotData.length > 0 && (
<Box sx={{ p: 3 }}>
<Typography variant="body1" gutterBottom>
{t('interpretation_log.titles.screenshot')} {screenshotPage + 1}
</Typography>
<img
src={screenshotData[screenshotPage]}
alt={`${t('interpretation_log.titles.screenshot')} ${screenshotPage + 1}`}
style={{ maxWidth: '100%' }}
/>
</Box>
)}
</Box>
)}
{(activeTab === availableTabs.findIndex(tab => tab.id === 'captureText') || singleContentType === 'captureText') && captureTextData.length > 0 && (
2025-04-29 00:27:35 +05:30
<TableContainer component={Paper} sx={{ boxShadow: 'none', borderRadius: 0 }}>
<Table>
2024-10-24 01:00:04 +05:30
<TableHead>
<TableRow>
2025-04-29 00:27:35 +05:30
{getCaptureTextColumns.map((column) => (
<TableCell
key={column}
sx={{
borderBottom: '1px solid',
borderColor: darkMode ? '#3a4453' : '#dee2e6',
backgroundColor: darkMode ? '#2a3441' : '#f8f9fa'
}}
>
{column}
</TableCell>
2024-10-21 15:57:51 +05:30
))}
</TableRow>
2024-10-24 01:00:04 +05:30
</TableHead>
<TableBody>
2025-04-29 00:27:35 +05:30
{captureTextData.map((row, idx) => (
<TableRow
key={idx}
sx={{
borderBottom: '1px solid',
borderColor: darkMode ? '#3a4453' : '#dee2e6'
}}
>
{getCaptureTextColumns.map((column) => (
<TableCell
key={column}
sx={{
borderBottom: 'none',
py: 2
}}
>
{row[column]}
</TableCell>
2024-10-24 01:00:04 +05:30
))}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
2025-04-29 00:27:35 +05:30
)}
</Box>
</>
) : (
<Grid container justifyContent="center" alignItems="center" style={{ height: '100%' }}>
<Grid item>
{hasScrapeListAction || hasScrapeSchemaAction || hasScreenshotAction ? (
<>
<Typography variant="h6" gutterBottom align="left">
{t('interpretation_log.messages.successful_training')}
</Typography>
2025-06-25 12:53:47 +05:30
<SidePanelHeader onPreviewClick={() => setShowPreviewData(true)} />
2025-04-29 00:27:35 +05:30
</>
) : (
<Typography variant="h6" gutterBottom align="left">
{t('interpretation_log.messages.no_selection')}
</Typography>
)}
</Grid>
</Grid>
)}
<div style={{ float: 'left', clear: 'both' }} ref={logEndRef} />
2024-10-21 15:21:12 +05:30
</SwipeableDrawer>
2024-10-19 14:47:54 +05:30
</Grid>
2024-10-21 15:21:12 +05:30
</Grid>
);
};