feat: revamp output preview log ui
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import SwipeableDrawer from '@mui/material/SwipeableDrawer';
|
import SwipeableDrawer from '@mui/material/SwipeableDrawer';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { Button, Grid } from '@mui/material';
|
import { Button, Grid, Tabs, Tab, Box } from '@mui/material';
|
||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { useSocketStore } from "../../context/socket";
|
import { useSocketStore } from "../../context/socket";
|
||||||
import { Buffer } from 'buffer';
|
import { Buffer } from 'buffer';
|
||||||
@@ -29,9 +29,18 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [log, setLog] = useState<string>('');
|
const [log, setLog] = useState<string>('');
|
||||||
const [customValue, setCustomValue] = useState('');
|
const [customValue, setCustomValue] = useState('');
|
||||||
const [tableData, setTableData] = useState<any[]>([]);
|
|
||||||
const [binaryData, setBinaryData] = useState<string | null>(null);
|
const [captureListData, setCaptureListData] = useState<any[]>([]);
|
||||||
|
const [captureTextData, setCaptureTextData] = useState<any[]>([]);
|
||||||
|
const [screenshotData, setScreenshotData] = useState<string[]>([]);
|
||||||
|
const [otherData, setOtherData] = useState<any[]>([]);
|
||||||
|
|
||||||
|
const [captureListPage, setCaptureListPage] = useState<number>(0);
|
||||||
|
const [screenshotPage, setScreenshotPage] = useState<number>(0);
|
||||||
|
const [otherPage, setOtherPage] = useState<number>(0);
|
||||||
|
|
||||||
|
const [activeTab, setActiveTab] = useState(0);
|
||||||
|
|
||||||
const logEndRef = useRef<HTMLDivElement | null>(null);
|
const logEndRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const { browserWidth, outputPreviewHeight, outputPreviewWidth } = useBrowserDimensionsStore();
|
const { browserWidth, outputPreviewHeight, outputPreviewWidth } = useBrowserDimensionsStore();
|
||||||
@@ -62,34 +71,68 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
setLog((prevState) => prevState + '\n' + `[${new Date().toLocaleString()}] ` + msg);
|
setLog((prevState) => prevState + '\n' + `[${new Date().toLocaleString()}] ` + msg);
|
||||||
}
|
}
|
||||||
scrollLogToBottom();
|
scrollLogToBottom();
|
||||||
}, [log, scrollLogToBottom]);
|
}, []);
|
||||||
|
|
||||||
const handleSerializableCallback = useCallback((data: any) => {
|
const handleSerializableCallback = useCallback(({ type, data }: { type: string, data: any }) => {
|
||||||
setLog((prevState) =>
|
setLog((prevState) =>
|
||||||
prevState + '\n' + t('interpretation_log.data_sections.serializable_received') + '\n'
|
prevState + '\n' + t('interpretation_log.data_sections.serializable_received') + '\n'
|
||||||
+ JSON.stringify(data, null, 2) + '\n' + t('interpretation_log.data_sections.separator'));
|
+ JSON.stringify(data, null, 2) + '\n' + t('interpretation_log.data_sections.separator'));
|
||||||
|
|
||||||
if (Array.isArray(data)) {
|
if (type === 'captureList' && Array.isArray(data)) {
|
||||||
setTableData(data);
|
setCaptureListData(prev => [...prev, data]);
|
||||||
|
if (captureListData.length === 0) {
|
||||||
|
const availableTabs = getAvailableTabs();
|
||||||
|
const tabIndex = availableTabs.findIndex(tab => tab.id === 'captureList');
|
||||||
|
if (tabIndex !== -1) setActiveTab(tabIndex);
|
||||||
|
}
|
||||||
|
} else if (type === 'captureText') {
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
setCaptureTextData(data);
|
||||||
|
} else {
|
||||||
|
setCaptureTextData([data]);
|
||||||
|
}
|
||||||
|
if (captureTextData.length === 0) {
|
||||||
|
const availableTabs = getAvailableTabs();
|
||||||
|
const tabIndex = availableTabs.findIndex(tab => tab.id === 'captureText');
|
||||||
|
if (tabIndex !== -1) setActiveTab(tabIndex);
|
||||||
|
}
|
||||||
|
} else if (type === 'other') {
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
setOtherData(prev => [...prev, data]);
|
||||||
|
} else {
|
||||||
|
setOtherData(prev => [...prev, [data]]);
|
||||||
|
}
|
||||||
|
if (otherData.length === 0) {
|
||||||
|
const availableTabs = getAvailableTabs();
|
||||||
|
const tabIndex = availableTabs.findIndex(tab => tab.id === 'other');
|
||||||
|
if (tabIndex !== -1) setActiveTab(tabIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollLogToBottom();
|
scrollLogToBottom();
|
||||||
}, [log, scrollLogToBottom, t]);
|
}, [captureListData.length, captureTextData.length, otherData.length, t]);
|
||||||
|
|
||||||
const handleBinaryCallback = useCallback(({ data, mimetype }: any) => {
|
const handleBinaryCallback = useCallback(({ data, mimetype, type }: { data: any, mimetype: string, type: string }) => {
|
||||||
const base64String = Buffer.from(data).toString('base64');
|
const base64String = Buffer.from(data).toString('base64');
|
||||||
const imageSrc = `data:${mimetype};base64,${base64String}`;
|
const imageSrc = `data:${mimetype};base64,${base64String}`;
|
||||||
|
|
||||||
setLog((prevState) =>
|
setLog((prevState) =>
|
||||||
prevState + '\n' + t('interpretation_log.data_sections.binary_received') + '\n'
|
prevState + '\n' + t('interpretation_log.data_sections.binary_received') + '\n'
|
||||||
+ t('interpretation_log.data_sections.mimetype') + mimetype + '\n'
|
+ t('interpretation_log.data_sections.mimetype') + mimetype + '\n'
|
||||||
+ t('interpretation_log.data_sections.image_below') + '\n'
|
+ t('interpretation_log.data_sections.image_below') + '\n'
|
||||||
+ t('interpretation_log.data_sections.separator'));
|
+ t('interpretation_log.data_sections.separator'));
|
||||||
|
|
||||||
setBinaryData(imageSrc);
|
if (type === 'captureScreenshot') {
|
||||||
|
setScreenshotData(prev => [...prev, imageSrc]);
|
||||||
|
if (screenshotData.length === 0) {
|
||||||
|
const availableTabs = getAvailableTabs();
|
||||||
|
const tabIndex = availableTabs.findIndex(tab => tab.id === 'captureScreenshot');
|
||||||
|
if (tabIndex !== -1) setActiveTab(tabIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
scrollLogToBottom();
|
scrollLogToBottom();
|
||||||
}, [log, scrollLogToBottom, t]);
|
}, [screenshotData.length, t]);
|
||||||
|
|
||||||
|
|
||||||
const handleCustomValueChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleCustomValueChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setCustomValue(event.target.value);
|
setCustomValue(event.target.value);
|
||||||
@@ -98,8 +141,14 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (shouldResetInterpretationLog) {
|
if (shouldResetInterpretationLog) {
|
||||||
setLog('');
|
setLog('');
|
||||||
setTableData([]);
|
setCaptureListData([]);
|
||||||
setBinaryData(null);
|
setCaptureTextData([]);
|
||||||
|
setScreenshotData([]);
|
||||||
|
setOtherData([]);
|
||||||
|
setActiveTab(0);
|
||||||
|
setCaptureListPage(0);
|
||||||
|
setScreenshotPage(0);
|
||||||
|
setOtherPage(0);
|
||||||
}
|
}
|
||||||
}, [shouldResetInterpretationLog]);
|
}, [shouldResetInterpretationLog]);
|
||||||
|
|
||||||
@@ -114,10 +163,37 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
};
|
};
|
||||||
}, [socket, handleLog, handleSerializableCallback, handleBinaryCallback]);
|
}, [socket, handleLog, handleSerializableCallback, handleBinaryCallback]);
|
||||||
|
|
||||||
// Extract columns dynamically from the first item of tableData
|
const getAvailableTabs = useCallback(() => {
|
||||||
const columns = tableData.length > 0 ? Object.keys(tableData[0]) : [];
|
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' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherData.length > 0) {
|
||||||
|
tabs.push({ id: 'other', label: 'Other' });
|
||||||
|
}
|
||||||
|
|
||||||
|
return tabs;
|
||||||
|
}, [captureListData.length, captureTextData.length, screenshotData.length, otherData.length]);
|
||||||
|
|
||||||
const { hasScrapeListAction, hasScreenshotAction, hasScrapeSchemaAction } = currentWorkflowActionsState
|
const availableTabs = getAvailableTabs();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeTab >= availableTabs.length && availableTabs.length > 0) {
|
||||||
|
setActiveTab(0);
|
||||||
|
}
|
||||||
|
}, [activeTab, availableTabs.length]);
|
||||||
|
|
||||||
|
const { hasScrapeListAction, hasScreenshotAction, hasScrapeSchemaAction } = currentWorkflowActionsState;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hasScrapeListAction || hasScrapeSchemaAction || hasScreenshotAction) {
|
if (hasScrapeListAction || hasScrapeSchemaAction || hasScreenshotAction) {
|
||||||
@@ -127,6 +203,8 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
|
|
||||||
const { darkMode } = useThemeMode();
|
const { darkMode } = useThemeMode();
|
||||||
|
|
||||||
|
const getCaptureTextColumns = captureTextData.length > 0 ? Object.keys(captureTextData[0]) : [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs={12} md={9} lg={9}>
|
<Grid item xs={12} md={9} lg={9}>
|
||||||
@@ -167,6 +245,7 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
height: outputPreviewHeight,
|
height: outputPreviewHeight,
|
||||||
width: outputPreviewWidth,
|
width: outputPreviewWidth,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
borderRadius: '10px 10px 0 0',
|
borderRadius: '10px 10px 0 0',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -175,67 +254,318 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
<StorageIcon style={{ marginRight: '8px' }} />
|
<StorageIcon style={{ marginRight: '8px' }} />
|
||||||
{t('interpretation_log.titles.output_preview')}
|
{t('interpretation_log.titles.output_preview')}
|
||||||
</Typography>
|
</Typography>
|
||||||
<div
|
|
||||||
style={{
|
{availableTabs.length > 0 ? (
|
||||||
height: '50vh',
|
<>
|
||||||
overflow: 'none',
|
<Box
|
||||||
padding: '10px',
|
sx={{
|
||||||
}}
|
display: 'flex',
|
||||||
>
|
borderBottom: '1px solid',
|
||||||
{
|
borderColor: darkMode ? '#3a4453' : '#dee2e6',
|
||||||
binaryData ? (
|
backgroundColor: darkMode ? '#2a3441' : '#f8f9fa'
|
||||||
<div style={{ marginBottom: '20px' }}>
|
}}
|
||||||
<Typography variant="body1" gutterBottom>
|
>
|
||||||
{t('interpretation_log.titles.screenshot')}
|
{availableTabs.map((tab, index) => (
|
||||||
</Typography>
|
<Box
|
||||||
<img src={binaryData} alt={t('interpretation_log.titles.screenshot')} style={{ maxWidth: '100%' }} />
|
key={tab.id}
|
||||||
</div>
|
onClick={() => setActiveTab(index)}
|
||||||
) : tableData.length > 0 ? (
|
sx={{
|
||||||
<>
|
px: 4,
|
||||||
<TableContainer component={Paper}>
|
py: 2,
|
||||||
<Table sx={{ minWidth: 650 }} stickyHeader aria-label="output data table">
|
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>
|
||||||
|
|
||||||
|
<Box sx={{ flexGrow: 1, overflow: 'auto', p: 0 }}>
|
||||||
|
{activeTab === availableTabs.findIndex(tab => tab.id === 'captureList') && captureListData.length > 0 && (
|
||||||
|
<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>
|
||||||
|
{captureListData[captureListPage] && captureListData[captureListPage].length > 0 &&
|
||||||
|
Object.keys(captureListData[captureListPage][0]).map((column) => (
|
||||||
|
<TableCell
|
||||||
|
key={column}
|
||||||
|
sx={{
|
||||||
|
borderBottom: '1px solid',
|
||||||
|
borderColor: darkMode ? '#3a4453' : '#dee2e6',
|
||||||
|
backgroundColor: darkMode ? '#2a3441' : '#f8f9fa'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{column}
|
||||||
|
</TableCell>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{captureListData[captureListPage] &&
|
||||||
|
captureListData[captureListPage].map((row: any, idx: any) => (
|
||||||
|
<TableRow
|
||||||
|
key={idx}
|
||||||
|
sx={{
|
||||||
|
borderBottom: '1px solid',
|
||||||
|
borderColor: darkMode ? '#3a4453' : '#dee2e6'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Object.keys(row).map((column) => (
|
||||||
|
<TableCell
|
||||||
|
key={column}
|
||||||
|
sx={{
|
||||||
|
borderBottom: 'none',
|
||||||
|
py: 2
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{row[column]}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{activeTab === availableTabs.findIndex(tab => tab.id === 'captureScreenshot') && (
|
||||||
|
<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') && (
|
||||||
|
<TableContainer component={Paper} sx={{ boxShadow: 'none', borderRadius: 0 }}>
|
||||||
|
<Table>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
{columns.map((column) => (
|
{getCaptureTextColumns.map((column) => (
|
||||||
<TableCell key={column}>{column}</TableCell>
|
<TableCell
|
||||||
|
key={column}
|
||||||
|
sx={{
|
||||||
|
borderBottom: '1px solid',
|
||||||
|
borderColor: darkMode ? '#3a4453' : '#dee2e6',
|
||||||
|
backgroundColor: darkMode ? '#2a3441' : '#f8f9fa'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{column}
|
||||||
|
</TableCell>
|
||||||
))}
|
))}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{tableData.slice(0, Math.min(5, tableData.length)).map((row, index) => (
|
{captureTextData.map((row, idx) => (
|
||||||
<TableRow key={index}>
|
<TableRow
|
||||||
{columns.map((column) => (
|
key={idx}
|
||||||
<TableCell key={column}>{row[column]}</TableCell>
|
sx={{
|
||||||
|
borderBottom: '1px solid',
|
||||||
|
borderColor: darkMode ? '#3a4453' : '#dee2e6'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{getCaptureTextColumns.map((column) => (
|
||||||
|
<TableCell
|
||||||
|
key={column}
|
||||||
|
sx={{
|
||||||
|
borderBottom: 'none',
|
||||||
|
py: 2
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{row[column]}
|
||||||
|
</TableCell>
|
||||||
))}
|
))}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
<span style={{ marginLeft: '15px', marginTop: '10px', fontSize: '12px' }}>
|
)}
|
||||||
{t('interpretation_log.messages.additional_rows')}
|
|
||||||
</span>
|
{activeTab === availableTabs.findIndex(tab => tab.id === 'other') && otherData.length > 0 && (
|
||||||
</>
|
<Box>
|
||||||
) : (
|
{otherData.length > 1 && (
|
||||||
<Grid container justifyContent="center" alignItems="center" style={{ height: '100%' }}>
|
<Box sx={{
|
||||||
<Grid item>
|
display: 'flex',
|
||||||
{hasScrapeListAction || hasScrapeSchemaAction || hasScreenshotAction ? (
|
justifyContent: 'space-between',
|
||||||
<>
|
alignItems: 'center',
|
||||||
<Typography variant="h6" gutterBottom align="left">
|
mb: 2,
|
||||||
{t('interpretation_log.messages.successful_training')}
|
mt: 2
|
||||||
|
}}>
|
||||||
|
<Typography variant="body2">
|
||||||
|
{`Dataset ${otherPage + 1} of ${otherData.length}`}
|
||||||
</Typography>
|
</Typography>
|
||||||
<SidePanelHeader />
|
<Box>
|
||||||
</>
|
<Button
|
||||||
) : (
|
onClick={() => setOtherPage(prev => Math.max(0, prev - 1))}
|
||||||
<Typography variant="h6" gutterBottom align="left">
|
disabled={otherPage === 0}
|
||||||
{t('interpretation_log.messages.no_selection')}
|
size="small"
|
||||||
</Typography>
|
>
|
||||||
|
Previous
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => setOtherPage(prev => Math.min(otherData.length - 1, prev + 1))}
|
||||||
|
disabled={otherPage >= otherData.length - 1}
|
||||||
|
size="small"
|
||||||
|
sx={{ ml: 1 }}
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Grid>
|
<TableContainer component={Paper} sx={{ boxShadow: 'none', borderRadius: 0 }}>
|
||||||
</Grid>
|
<Table>
|
||||||
)}
|
<TableHead>
|
||||||
<div style={{ float: 'left', clear: 'both' }} ref={logEndRef} />
|
<TableRow>
|
||||||
</div>
|
{otherData[otherPage] && otherData[otherPage].length > 0 &&
|
||||||
|
Object.keys(otherData[otherPage][0]).map((column) => (
|
||||||
|
<TableCell
|
||||||
|
key={column}
|
||||||
|
sx={{
|
||||||
|
borderBottom: '1px solid',
|
||||||
|
borderColor: darkMode ? '#3a4453' : '#dee2e6',
|
||||||
|
backgroundColor: darkMode ? '#2a3441' : '#f8f9fa'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{column}
|
||||||
|
</TableCell>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{otherData[otherPage] &&
|
||||||
|
otherData[otherPage].map((row: any, idx: any) => (
|
||||||
|
<TableRow
|
||||||
|
key={idx}
|
||||||
|
sx={{
|
||||||
|
borderBottom: '1px solid',
|
||||||
|
borderColor: darkMode ? '#3a4453' : '#dee2e6'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Object.keys(row).map((column) => (
|
||||||
|
<TableCell
|
||||||
|
key={column}
|
||||||
|
sx={{
|
||||||
|
borderBottom: 'none',
|
||||||
|
py: 2
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{row[column]}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</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>
|
||||||
|
<SidePanelHeader />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Typography variant="h6" gutterBottom align="left">
|
||||||
|
{t('interpretation_log.messages.no_selection')}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
<div style={{ float: 'left', clear: 'both' }} ref={logEndRef} />
|
||||||
</SwipeableDrawer>
|
</SwipeableDrawer>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
Reference in New Issue
Block a user