Merge branch 'develop' into rm-actions
This commit is contained in:
@@ -225,6 +225,28 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
||||
|
||||
notify('error', `Text data "${currentTextGroupName}" discarded`);
|
||||
};
|
||||
|
||||
const checkForDuplicateName = (stepId: number, type: 'list' | 'text' | 'screenshot', newName: string): boolean => {
|
||||
const trimmedName = newName.trim();
|
||||
|
||||
if (type === 'list') {
|
||||
const listSteps = browserSteps.filter(step => step.type === 'list' && step.id !== stepId);
|
||||
const duplicate = listSteps.find(step => step.name === trimmedName);
|
||||
if (duplicate) {
|
||||
notify('error', `A list with the name "${trimmedName}" already exists. Please choose a different name.`);
|
||||
return true;
|
||||
}
|
||||
} else if (type === 'screenshot') {
|
||||
const screenshotSteps = browserSteps.filter(step => step.type === 'screenshot' && step.id !== stepId);
|
||||
const duplicate = screenshotSteps.find(step => step.name === trimmedName);
|
||||
if (duplicate) {
|
||||
notify('error', `A screenshot with the name "${trimmedName}" already exists. Please choose a different name.`);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const startEdit = (stepId: number, type: 'list' | 'text' | 'screenshot', currentValue: string) => {
|
||||
setEditing({ stepId, type, value: currentValue });
|
||||
@@ -240,6 +262,10 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkForDuplicateName(stepId, type, finalValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === 'list') {
|
||||
updateListStepName(stepId, finalValue);
|
||||
} else if (type === 'text') {
|
||||
@@ -378,6 +404,8 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
||||
shouldOpenDrawer = true;
|
||||
}
|
||||
lastListDataLength.current = captureListData.length;
|
||||
} else if (hasScrapeListAction && captureListData.length === 0) {
|
||||
lastListDataLength.current = 0;
|
||||
}
|
||||
|
||||
if (hasScrapeSchemaAction && captureTextData.length > 0 && !getText) {
|
||||
@@ -387,6 +415,8 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
||||
shouldOpenDrawer = true;
|
||||
}
|
||||
lastTextDataLength.current = captureTextData.length;
|
||||
} else if (hasScrapeSchemaAction && captureTextData.length === 0) {
|
||||
lastTextDataLength.current = 0;
|
||||
}
|
||||
|
||||
if (hasScreenshotAction && screenshotData.length > 0) {
|
||||
@@ -396,6 +426,8 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
||||
shouldOpenDrawer = true;
|
||||
}
|
||||
lastScreenshotDataLength.current = screenshotData.length;
|
||||
} else if (hasScreenshotAction && screenshotData.length === 0) {
|
||||
lastScreenshotDataLength.current = 0;
|
||||
}
|
||||
|
||||
const getLatestCaptureType = () => {
|
||||
@@ -538,7 +570,7 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
||||
{t('interpretation_log.titles.output_preview')}
|
||||
</Typography>
|
||||
|
||||
{!(hasScrapeListAction || hasScrapeSchemaAction || hasScreenshotAction) && (
|
||||
{!(hasScrapeListAction || hasScrapeSchemaAction || hasScreenshotAction) && !showPreviewData && availableTabs.length === 0 && (
|
||||
<Grid container justifyContent="center" alignItems="center" style={{ height: '100%' }}>
|
||||
<Grid item>
|
||||
<Typography variant="h6" gutterBottom align="left">
|
||||
|
||||
@@ -115,27 +115,29 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
||||
const rawKeys = Object.keys(row.binaryOutput);
|
||||
|
||||
const isLegacyPattern = rawKeys.every(key => /^item-\d+-\d+$/.test(key));
|
||||
|
||||
let normalizedScreenshotKeys: string[];
|
||||
|
||||
if (isLegacyPattern) {
|
||||
const renamedKeys = rawKeys.map((_, index) => `Screenshot ${index + 1}`);
|
||||
const keyMap: Record<string, string> = {};
|
||||
|
||||
renamedKeys.forEach((displayName, index) => {
|
||||
keyMap[displayName] = rawKeys[index];
|
||||
});
|
||||
|
||||
setScreenshotKeys(renamedKeys);
|
||||
setScreenshotKeyMap(keyMap);
|
||||
// Legacy unnamed screenshots → Screenshot 1, Screenshot 2...
|
||||
normalizedScreenshotKeys = rawKeys.map((_, index) => `Screenshot ${index + 1}`);
|
||||
} else {
|
||||
const keyMap: Record<string, string> = {};
|
||||
rawKeys.forEach(key => {
|
||||
keyMap[key] = key;
|
||||
// Same rule as captured lists: if name missing or generic, auto-label
|
||||
normalizedScreenshotKeys = rawKeys.map((key, index) => {
|
||||
if (!key || key.toLowerCase().includes("screenshot")) {
|
||||
return `Screenshot ${index + 1}`;
|
||||
}
|
||||
return key;
|
||||
});
|
||||
|
||||
setScreenshotKeys(rawKeys);
|
||||
setScreenshotKeyMap(keyMap);
|
||||
}
|
||||
|
||||
const keyMap: Record<string, string> = {};
|
||||
normalizedScreenshotKeys.forEach((displayName, index) => {
|
||||
keyMap[displayName] = rawKeys[index];
|
||||
});
|
||||
|
||||
setScreenshotKeys(normalizedScreenshotKeys);
|
||||
setScreenshotKeyMap(keyMap);
|
||||
setCurrentScreenshotIndex(0);
|
||||
} else {
|
||||
setScreenshotKeys([]);
|
||||
@@ -202,7 +204,14 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
||||
|
||||
const processSchemaData = (schemaOutput: any) => {
|
||||
const keys = Object.keys(schemaOutput);
|
||||
setSchemaKeys(keys);
|
||||
const normalizedKeys = keys.map((key, index) => {
|
||||
if (!key || key.toLowerCase().includes("scrapeschema")) {
|
||||
return keys.length === 1 ? "Texts" : `Text ${index + 1}`;
|
||||
}
|
||||
return key;
|
||||
});
|
||||
|
||||
setSchemaKeys(normalizedKeys);
|
||||
|
||||
const dataByKey: Record<string, any[]> = {};
|
||||
const columnsByKey: Record<string, string[]> = {};
|
||||
@@ -248,8 +257,17 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
||||
}
|
||||
});
|
||||
|
||||
setSchemaDataByKey(dataByKey);
|
||||
setSchemaColumnsByKey(columnsByKey);
|
||||
const remappedDataByKey: Record<string, any[]> = {};
|
||||
const remappedColumnsByKey: Record<string, string[]> = {};
|
||||
|
||||
normalizedKeys.forEach((newKey, idx) => {
|
||||
const oldKey = keys[idx];
|
||||
remappedDataByKey[newKey] = dataByKey[oldKey];
|
||||
remappedColumnsByKey[newKey] = columnsByKey[oldKey];
|
||||
});
|
||||
|
||||
setSchemaDataByKey(remappedDataByKey);
|
||||
setSchemaColumnsByKey(remappedColumnsByKey);
|
||||
|
||||
if (allData.length > 0) {
|
||||
const allColumns = new Set<string>();
|
||||
@@ -290,7 +308,14 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
||||
|
||||
setListData(tablesList);
|
||||
setListColumns(columnsList);
|
||||
setListKeys(keys);
|
||||
const normalizedListKeys = keys.map((key, index) => {
|
||||
if (!key || key.toLowerCase().includes("scrapelist")) {
|
||||
return `List ${index + 1}`;
|
||||
}
|
||||
return key;
|
||||
});
|
||||
|
||||
setListKeys(normalizedListKeys);
|
||||
setCurrentListIndex(0);
|
||||
};
|
||||
|
||||
@@ -617,10 +642,15 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
||||
<TabContext value={tab}>
|
||||
<TabPanel value='output' sx={{ width: '100%', maxWidth: '900px' }}>
|
||||
{row.status === 'running' || row.status === 'queued' ? (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<CircularProgress size={22} sx={{ marginRight: '10px' }} />
|
||||
{t('run_content.loading')}
|
||||
</Box>
|
||||
<>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
||||
<CircularProgress size={22} sx={{ marginRight: '10px' }} />
|
||||
{t('run_content.loading')}
|
||||
</Box>
|
||||
<Button color="error" onClick={abortRunHandler} sx={{ mt: 1 }}>
|
||||
{t('run_content.buttons.stop')}
|
||||
</Button>
|
||||
</>
|
||||
) : (!hasData && !hasScreenshots
|
||||
? <Typography>{t('run_content.empty_output')}</Typography>
|
||||
: null)}
|
||||
|
||||
Reference in New Issue
Block a user