Merge pull request #776 from getmaxun/captext-fix
fix: capture text display
This commit is contained in:
@@ -43,6 +43,7 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
|
|
||||||
const [schemaData, setSchemaData] = useState<any[]>([]);
|
const [schemaData, setSchemaData] = useState<any[]>([]);
|
||||||
const [schemaColumns, setSchemaColumns] = useState<string[]>([]);
|
const [schemaColumns, setSchemaColumns] = useState<string[]>([]);
|
||||||
|
const [isSchemaTabular, setIsSchemaTabular] = useState<boolean>(false);
|
||||||
|
|
||||||
const [listData, setListData] = useState<any[][]>([]);
|
const [listData, setListData] = useState<any[][]>([]);
|
||||||
const [listColumns, setListColumns] = useState<string[][]>([]);
|
const [listColumns, setListColumns] = useState<string[][]>([]);
|
||||||
@@ -62,6 +63,18 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
}, [interpretationInProgress]);
|
}, [interpretationInProgress]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (row.status === 'running' || row.status === 'queued' || row.status === 'scheduled') {
|
||||||
|
setSchemaData([]);
|
||||||
|
setSchemaColumns([]);
|
||||||
|
setListData([]);
|
||||||
|
setListColumns([]);
|
||||||
|
setLegacyData([]);
|
||||||
|
setLegacyColumns([]);
|
||||||
|
setIsLegacyData(false);
|
||||||
|
setIsSchemaTabular(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!row.serializableOutput) return;
|
if (!row.serializableOutput) return;
|
||||||
|
|
||||||
if (!row.serializableOutput.scrapeSchema &&
|
if (!row.serializableOutput.scrapeSchema &&
|
||||||
@@ -76,20 +89,29 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
setIsLegacyData(false);
|
setIsLegacyData(false);
|
||||||
|
|
||||||
if (row.serializableOutput.scrapeSchema && Object.keys(row.serializableOutput.scrapeSchema).length > 0) {
|
if (row.serializableOutput.scrapeSchema && Object.keys(row.serializableOutput.scrapeSchema).length > 0) {
|
||||||
processDataCategory(row.serializableOutput.scrapeSchema, setSchemaData, setSchemaColumns);
|
processSchemaData(row.serializableOutput.scrapeSchema);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row.serializableOutput.scrapeList) {
|
if (row.serializableOutput.scrapeList) {
|
||||||
processScrapeList(row.serializableOutput.scrapeList);
|
processScrapeList(row.serializableOutput.scrapeList);
|
||||||
}
|
}
|
||||||
}, [row.serializableOutput]);
|
}, [row.serializableOutput, row.status]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (row.status === 'running' || row.status === 'queued' || row.status === 'scheduled') {
|
||||||
|
setScreenshotKeys([]);
|
||||||
|
setCurrentScreenshotIndex(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (row.binaryOutput && Object.keys(row.binaryOutput).length > 0) {
|
if (row.binaryOutput && Object.keys(row.binaryOutput).length > 0) {
|
||||||
setScreenshotKeys(Object.keys(row.binaryOutput));
|
setScreenshotKeys(Object.keys(row.binaryOutput));
|
||||||
setCurrentScreenshotIndex(0);
|
setCurrentScreenshotIndex(0);
|
||||||
|
} else {
|
||||||
|
setScreenshotKeys([]);
|
||||||
|
setCurrentScreenshotIndex(0);
|
||||||
}
|
}
|
||||||
}, [row.binaryOutput]);
|
}, [row.binaryOutput, row.status]);
|
||||||
|
|
||||||
const processLegacyData = (legacyOutput: Record<string, any>) => {
|
const processLegacyData = (legacyOutput: Record<string, any>) => {
|
||||||
let allData: any[] = [];
|
let allData: any[] = [];
|
||||||
@@ -115,20 +137,57 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const processDataCategory = (
|
const processSchemaData = (schemaOutput: any) => {
|
||||||
categoryData: Record<string, any>,
|
if (Array.isArray(schemaOutput)) {
|
||||||
setData: React.Dispatch<React.SetStateAction<any[]>>,
|
const filteredData = schemaOutput.filter(row =>
|
||||||
setColumns: React.Dispatch<React.SetStateAction<string[]>>
|
row && Object.values(row).some(value => value !== undefined && value !== "")
|
||||||
) => {
|
);
|
||||||
let allData: any[] = [];
|
|
||||||
|
|
||||||
Object.keys(categoryData).forEach(key => {
|
if (filteredData.length > 0) {
|
||||||
const data = categoryData[key];
|
const allColumns = new Set<string>();
|
||||||
|
filteredData.forEach(item => {
|
||||||
|
Object.keys(item).forEach(key => allColumns.add(key));
|
||||||
|
});
|
||||||
|
|
||||||
|
setSchemaData(filteredData);
|
||||||
|
setSchemaColumns(Array.from(allColumns));
|
||||||
|
setIsSchemaTabular(filteredData.length > 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (schemaOutput['schema-tabular']) {
|
||||||
|
const tabularData = schemaOutput['schema-tabular'];
|
||||||
|
if (Array.isArray(tabularData) && tabularData.length > 0) {
|
||||||
|
const filteredData = tabularData.filter(row =>
|
||||||
|
Object.values(row).some(value => value !== undefined && value !== "")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (filteredData.length > 0) {
|
||||||
|
const allColumns = new Set<string>();
|
||||||
|
filteredData.forEach(item => {
|
||||||
|
Object.keys(item).forEach(key => allColumns.add(key));
|
||||||
|
});
|
||||||
|
|
||||||
|
setSchemaData(filteredData);
|
||||||
|
setSchemaColumns(Array.from(allColumns));
|
||||||
|
setIsSchemaTabular(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allData: any[] = [];
|
||||||
|
let hasMultipleEntries = false;
|
||||||
|
|
||||||
|
Object.keys(schemaOutput).forEach(key => {
|
||||||
|
const data = schemaOutput[key];
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
const filteredData = data.filter(row =>
|
const filteredData = data.filter(row =>
|
||||||
Object.values(row).some(value => value !== undefined && value !== "")
|
Object.values(row).some(value => value !== undefined && value !== "")
|
||||||
);
|
);
|
||||||
allData = [...allData, ...filteredData];
|
allData = [...allData, ...filteredData];
|
||||||
|
if (filteredData.length > 1) hasMultipleEntries = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -138,8 +197,9 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
Object.keys(item).forEach(key => allColumns.add(key));
|
Object.keys(item).forEach(key => allColumns.add(key));
|
||||||
});
|
});
|
||||||
|
|
||||||
setData(allData);
|
setSchemaData(allData);
|
||||||
setColumns(Array.from(allColumns));
|
setSchemaColumns(Array.from(allColumns));
|
||||||
|
setIsSchemaTabular(hasMultipleEntries || allData.length > 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -193,28 +253,29 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
setCurrentListIndex(0);
|
setCurrentListIndex(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to convert table data to CSV format
|
const convertToCSV = (data: any[], columns: string[], isSchemaData: boolean = false, isTabular: boolean = false): string => {
|
||||||
const convertToCSV = (data: any[], columns: string[], isSchemaData: boolean = false): string => {
|
if (isSchemaData && !isTabular && data.length === 1) {
|
||||||
if (isSchemaData) {
|
|
||||||
// For schema data, export as Label-Value pairs
|
|
||||||
const header = 'Label,Value';
|
const header = 'Label,Value';
|
||||||
const rows = columns.map(column =>
|
const rows = columns.map(column =>
|
||||||
`"${column}","${data[0][column] || ""}"`
|
`"${column}","${data[0][column] || ""}"`
|
||||||
);
|
);
|
||||||
return [header, ...rows].join('\n');
|
return [header, ...rows].join('\n');
|
||||||
} else {
|
} else {
|
||||||
// For regular table data, export as normal table
|
const header = columns.map(col => `"${col}"`).join(',');
|
||||||
const header = columns.join(',');
|
|
||||||
const rows = data.map(row =>
|
const rows = data.map(row =>
|
||||||
columns.map(col => JSON.stringify(row[col] || "", null, 2)).join(',')
|
columns.map(col => {
|
||||||
|
const value = row[col] || "";
|
||||||
|
const escapedValue = String(value).replace(/"/g, '""');
|
||||||
|
return `"${escapedValue}"`;
|
||||||
|
}).join(',')
|
||||||
);
|
);
|
||||||
return [header, ...rows].join('\n');
|
return [header, ...rows].join('\n');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to download a specific dataset as CSV
|
// Function to download a specific dataset as CSV
|
||||||
const downloadCSV = (data: any[], columns: string[], filename: string, isSchemaData: boolean = false) => {
|
const downloadCSV = (data: any[], columns: string[], filename: string, isSchemaData: boolean = false, isTabular: boolean = false) => {
|
||||||
const csvContent = convertToCSV(data, columns, isSchemaData);
|
const csvContent = convertToCSV(data, columns, isSchemaData, isTabular);
|
||||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
@@ -224,6 +285,10 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
document.body.removeChild(link);
|
document.body.removeChild(link);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}, 100);
|
||||||
};
|
};
|
||||||
|
|
||||||
const downloadJSON = (data: any[], filename: string) => {
|
const downloadJSON = (data: any[], filename: string) => {
|
||||||
@@ -261,11 +326,12 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
|
|
||||||
const renderDataTable = (
|
const renderDataTable = (
|
||||||
data: any[],
|
data: any[],
|
||||||
columns: any[],
|
columns: string[],
|
||||||
title: string,
|
title: string,
|
||||||
csvFilename: string,
|
csvFilename: string,
|
||||||
jsonFilename: string,
|
jsonFilename: string,
|
||||||
isPaginatedList: boolean = false
|
isPaginatedList: boolean = false,
|
||||||
|
isSchemaData: boolean = false
|
||||||
) => {
|
) => {
|
||||||
if (!isPaginatedList && data.length === 0) return null;
|
if (!isPaginatedList && data.length === 0) return null;
|
||||||
if (isPaginatedList && (listData.length === 0 || currentListIndex >= listData.length)) return null;
|
if (isPaginatedList && (listData.length === 0 || currentListIndex >= listData.length)) return null;
|
||||||
@@ -275,7 +341,7 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
|
|
||||||
if (!currentData || currentData.length === 0) return null;
|
if (!currentData || currentData.length === 0) return null;
|
||||||
|
|
||||||
const isSchemaData = title.toLowerCase().includes('text') || title.toLowerCase().includes('schema');
|
const shouldShowAsKeyValue = isSchemaData && !isSchemaTabular && currentData.length === 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Accordion defaultExpanded sx={{ mb: 2 }}>
|
<Accordion defaultExpanded sx={{ mb: 2 }}>
|
||||||
@@ -314,7 +380,7 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
component="a"
|
component="a"
|
||||||
onClick={() => downloadCSV(currentData, currentColumns, csvFilename, isSchemaData)}
|
onClick={() => downloadCSV(currentData, currentColumns, csvFilename, isSchemaData, isSchemaTabular)}
|
||||||
sx={{
|
sx={{
|
||||||
color: '#FF00C3',
|
color: '#FF00C3',
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
@@ -366,7 +432,7 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
<Table stickyHeader aria-label="sticky table">
|
<Table stickyHeader aria-label="sticky table">
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
{isSchemaData ? (
|
{shouldShowAsKeyValue ? (
|
||||||
<>
|
<>
|
||||||
<TableCell
|
<TableCell
|
||||||
sx={{
|
sx={{
|
||||||
@@ -404,7 +470,8 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{isSchemaData ? (
|
{shouldShowAsKeyValue ? (
|
||||||
|
// Single schema entry - show as key-value pairs
|
||||||
currentColumns.map((column) => (
|
currentColumns.map((column) => (
|
||||||
<TableRow key={column}>
|
<TableRow key={column}>
|
||||||
<TableCell sx={{ fontWeight: 500 }}>
|
<TableCell sx={{ fontWeight: 500 }}>
|
||||||
@@ -416,6 +483,7 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
|
// Multiple entries or list data - show as table
|
||||||
currentData.map((row, index) => (
|
currentData.map((row, index) => (
|
||||||
<TableRow key={index}>
|
<TableRow key={index}>
|
||||||
{(isPaginatedList ? currentColumns : columns).map((column) => (
|
{(isPaginatedList ? currentColumns : columns).map((column) => (
|
||||||
@@ -536,15 +604,17 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
{renderDataTable(
|
{renderDataTable(
|
||||||
schemaData,
|
schemaData,
|
||||||
schemaColumns,
|
schemaColumns,
|
||||||
t('run_content.captured_data.schema_title'),
|
t('run_content.captured_data.schema_title', 'Captured Texts'),
|
||||||
'schema_data.csv',
|
'schema_data.csv',
|
||||||
'schema_data.json'
|
'schema_data.json',
|
||||||
|
false,
|
||||||
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{listData.length > 0 && renderDataTable(
|
{listData.length > 0 && renderDataTable(
|
||||||
listData,
|
[],
|
||||||
listColumns,
|
[],
|
||||||
t('run_content.captured_data.list_title'),
|
t('run_content.captured_data.list_title', 'Captured Lists'),
|
||||||
'list_data.csv',
|
'list_data.csv',
|
||||||
'list_data.json',
|
'list_data.json',
|
||||||
true
|
true
|
||||||
|
|||||||
Reference in New Issue
Block a user