diff --git a/src/components/recorder/RightSidePanel.tsx b/src/components/recorder/RightSidePanel.tsx index e22ab08b..de0dfcb0 100644 --- a/src/components/recorder/RightSidePanel.tsx +++ b/src/components/recorder/RightSidePanel.tsx @@ -534,9 +534,24 @@ export const RightSidePanel: React.FC = ({ onFinishCapture const isDarkMode = theme.darkMode; return ( - + - + {!isAnyActionActive && ( <> {showCaptureList && ( diff --git a/src/components/robot/pages/RobotEditPage.tsx b/src/components/robot/pages/RobotEditPage.tsx index 96f7c9d3..fa745160 100644 --- a/src/components/robot/pages/RobotEditPage.tsx +++ b/src/components/robot/pages/RobotEditPage.tsx @@ -436,15 +436,6 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => { // update the standard name field action.name = newName; - // also update legacy __name location if present (args[0].__name) - if (action.args && action.args.length > 0 && typeof action.args[0] === 'object' && action.args[0] !== null && '__name' in action.args[0]) { - try { - action.args[0] = { ...action.args[0], __name: newName }; - } catch (e) { - console.error('Failed to update legacy __name field:', e); - } - } - updatedWorkflow[pairIndex].what[actionIndex] = action; } @@ -510,27 +501,35 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => { {t("List Limits")} - {scrapeListLimits.map((limitInfo, index) => ( - { - const value = parseInt(e.target.value, 10); - if (value >= 1) { - handleLimitChange( - limitInfo.pairIndex, - limitInfo.actionIndex, - limitInfo.argIndex, - value - ); - } - }} - inputProps={{ min: 1 }} - style={{ marginBottom: "20px" }} - /> - ))} + {scrapeListLimits.map((limitInfo, index) => { + // Get the corresponding scrapeList action to extract its name + const scrapeListAction = robot?.recording?.workflow?.[limitInfo.pairIndex]?.what?.[limitInfo.actionIndex]; + const actionName = + scrapeListAction?.name || + `List Limit ${index + 1}`; + + return ( + { + const value = parseInt(e.target.value, 10); + if (value >= 1) { + handleLimitChange( + limitInfo.pairIndex, + limitInfo.actionIndex, + limitInfo.argIndex, + value + ); + } + }} + inputProps={{ min: 1 }} + style={{ marginBottom: "20px" }} + /> + ); + })} ); }; @@ -543,17 +542,50 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => { const screenshotInputs: JSX.Element[] = []; const listInputs: JSX.Element[] = []; + let textCount = 0; + let screenshotCount = 0; + let listCount = 0; + robot.recording.workflow.forEach((pair, pairIndex) => { if (!pair.what) return; pair.what.forEach((action, actionIndex) => { if (!editableActions.has(String(action.action))) return; - const currentName = + let currentName = action.name || - (action.args && action.args[0] && typeof action.args[0] === 'object' && action.args[0].__name) || + (action.args && action.args[0] && typeof action.args[0] === 'object') || ''; + if (!currentName) { + switch (action.action) { + case 'scrapeSchema': + textCount++; + currentName = `Text ${textCount}`; + break; + case 'screenshot': + screenshotCount++; + currentName = `Screenshot ${screenshotCount}`; + break; + case 'scrapeList': + listCount++; + currentName = `List ${listCount}`; + break; + } + } else { + switch (action.action) { + case 'scrapeSchema': + textCount++; + break; + case 'screenshot': + screenshotCount++; + break; + case 'scrapeList': + listCount++; + break; + } + } + const textField = ( { ); switch (action.action) { - case 'scrapeSchema': - textInputs.push(textField); + case 'scrapeSchema': { + const existingName = + currentName || + (action.args && action.args[0] && typeof action.args[0] === "object") || + "Texts"; + + if (!textInputs.length) { + textInputs.push( + { + const newName = e.target.value; + + setRobot((prev) => { + if (!prev?.recording?.workflow) return prev; + + const updated = { ...prev }; + updated.recording = { ...prev.recording }; + updated.recording.workflow = prev.recording.workflow.map((p) => ({ + ...p, + what: p.what?.map((a) => { + if (a.action === "scrapeSchema") { + const updatedAction = { ...a }; + updatedAction.name = newName; + return updatedAction; + } + return a; + }), + })); + + return updated; + }); + }} + style={{ marginBottom: "12px" }} + fullWidth + /> + ); + } + break; + } case 'screenshot': screenshotInputs.push(textField); break; diff --git a/src/components/run/RunContent.tsx b/src/components/run/RunContent.tsx index ee397bf4..4cc787d1 100644 --- a/src/components/run/RunContent.tsx +++ b/src/components/run/RunContent.tsx @@ -87,8 +87,8 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe const hasOldFormat = !row.serializableOutput.scrapeSchema && !row.serializableOutput.scrapeList && Object.keys(row.serializableOutput).length > 0; if (hasLegacySchema || hasLegacyList || hasOldFormat) { - setIsLegacyData(true); processLegacyData(row.serializableOutput); + setIsLegacyData(false); return; } @@ -154,11 +154,12 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe const data = legacyOutput[key]; if (Array.isArray(data)) { - const isNestedArray = data.length > 0 && Array.isArray(data[0]); + const firstNonNullElement = data.find(item => item !== null && item !== undefined); + const isNestedArray = firstNonNullElement && Array.isArray(firstNonNullElement); if (isNestedArray) { data.forEach((subArray, index) => { - if (Array.isArray(subArray) && subArray.length > 0) { + if (subArray !== null && subArray !== undefined && Array.isArray(subArray) && subArray.length > 0) { const filteredData = subArray.filter(row => row && typeof row === 'object' && Object.values(row).some(value => value !== undefined && value !== "") ); @@ -171,7 +172,7 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe }); } else { const filteredData = data.filter(row => - row && typeof row === 'object' && Object.values(row).some(value => value !== undefined && value !== "") + row && typeof row === 'object' && !Array.isArray(row) && Object.values(row).some(value => value !== undefined && value !== "") ); if (filteredData.length > 0) { @@ -208,7 +209,7 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe if (Array.isArray(schemaOutput)) { const filteredData = schemaOutput.filter(row => - row && Object.values(row).some(value => value !== undefined && value !== "") + row && typeof row === 'object' && Object.values(row).some(value => value !== undefined && value !== "") ); if (filteredData.length > 0) { @@ -231,7 +232,7 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe const data = schemaOutput[key]; if (Array.isArray(data)) { const filteredData = data.filter(row => - Object.values(row).some(value => value !== undefined && value !== "") + row && typeof row === 'object' && Object.values(row).some(value => value !== undefined && value !== "") ); dataByKey[key] = filteredData; @@ -272,7 +273,7 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe const tableData = scrapeListData[key]; if (Array.isArray(tableData) && tableData.length > 0) { const filteredData = tableData.filter(row => - Object.values(row).some(value => value !== undefined && value !== "") + row && typeof row === 'object' && Object.values(row).some(value => value !== undefined && value !== "") ); if (filteredData.length > 0) { tablesList.push(filteredData); diff --git a/src/helpers/clientSelectorGenerator.ts b/src/helpers/clientSelectorGenerator.ts index 03ad67a2..3189a430 100644 --- a/src/helpers/clientSelectorGenerator.ts +++ b/src/helpers/clientSelectorGenerator.ts @@ -564,14 +564,15 @@ class ClientSelectorGenerator { return true; } - if (element.children.length > 0) { - return false; + const text = (element.textContent || "").trim(); + const hasVisibleText = text.length > 0; + + if (hasVisibleText || element.querySelector("svg")) { + return true; } - const text = (element.textContent || "").trim(); - - if (text.length > 0) { - return true; + if (element.children.length > 0) { + return false; } return false;