Merge pull request #974 from getmaxun/auto-detect-ui

feat: auto detect pagination ui
This commit is contained in:
Karishma Shukla
2026-02-15 02:22:28 +05:30
committed by GitHub

View File

@@ -28,7 +28,7 @@ const fetchWorkflow = (id: string, callback: (response: WorkflowFile) => void) =
throw new Error("No workflow found"); throw new Error("No workflow found");
} }
} }
).catch((error) => { console.log(`Failed to fetch workflow:`,error.message) }) ).catch((error) => { console.log(`Failed to fetch workflow:`, error.message) })
}; };
interface RightSidePanelProps { interface RightSidePanelProps {
@@ -48,22 +48,22 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
} | null>(null); } | null>(null);
const autoDetectionRunRef = useRef<string | null>(null); const autoDetectionRunRef = useRef<string | null>(null);
const { notify, currentWorkflowActionsState, setCurrentWorkflowActionsState, resetInterpretationLog, currentListActionId, setCurrentListActionId, currentTextActionId, setCurrentTextActionId, currentScreenshotActionId, setCurrentScreenshotActionId, isDOMMode, updateDOMMode, currentTextGroupName } = useGlobalInfoStore(); const { notify, currentWorkflowActionsState, setCurrentWorkflowActionsState, resetInterpretationLog, currentListActionId, setCurrentListActionId, currentTextActionId, setCurrentTextActionId, currentScreenshotActionId, setCurrentScreenshotActionId, isDOMMode, updateDOMMode, currentTextGroupName } = useGlobalInfoStore();
const { const {
getText, startGetText, stopGetText, getText, startGetText, stopGetText,
getList, startGetList, stopGetList, getList, startGetList, stopGetList,
getScreenshot, startGetScreenshot, stopGetScreenshot, getScreenshot, startGetScreenshot, stopGetScreenshot,
startPaginationMode, stopPaginationMode, startPaginationMode, stopPaginationMode,
paginationType, updatePaginationType, paginationType, updatePaginationType,
limitType, customLimit, updateLimitType, updateCustomLimit, limitType, customLimit, updateLimitType, updateCustomLimit,
stopLimitMode, startLimitMode, stopLimitMode, startLimitMode,
captureStage, setCaptureStage, captureStage, setCaptureStage,
showPaginationOptions, setShowPaginationOptions, showPaginationOptions, setShowPaginationOptions,
showLimitOptions, setShowLimitOptions, showLimitOptions, setShowLimitOptions,
workflow, setWorkflow, workflow, setWorkflow,
activeAction, setActiveAction, finishAction activeAction, setActiveAction, finishAction
} = useActionContext(); } = useActionContext();
const { browserSteps, addScreenshotStep, updateListStepLimit, updateListStepPagination, deleteStepsByActionId, updateListStepData, updateScreenshotStepData, emitActionForStep } = useBrowserSteps(); const { browserSteps, addScreenshotStep, updateListStepLimit, updateListStepPagination, deleteStepsByActionId, updateListStepData, updateScreenshotStepData, emitActionForStep } = useBrowserSteps();
const { id, socket } = useSocketStore(); const { id, socket } = useSocketStore();
const { t } = useTranslation(); const { t } = useTranslation();
@@ -214,7 +214,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
} }
}); });
} }
return () => { return () => {
socket?.off('listDataExtracted'); socket?.off('listDataExtracted');
}; };
@@ -223,16 +223,16 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
useEffect(() => { useEffect(() => {
if (socket) { if (socket) {
const handleDirectScreenshot = (data: any) => { const handleDirectScreenshot = (data: any) => {
const screenshotSteps = browserSteps.filter(step => const screenshotSteps = browserSteps.filter(step =>
step.type === 'screenshot' && step.actionId === currentScreenshotActionId step.type === 'screenshot' && step.actionId === currentScreenshotActionId
); );
if (screenshotSteps.length > 0) { if (screenshotSteps.length > 0) {
const latestStep = screenshotSteps[screenshotSteps.length - 1]; const latestStep = screenshotSteps[screenshotSteps.length - 1];
updateScreenshotStepData(latestStep.id, data.screenshot); updateScreenshotStepData(latestStep.id, data.screenshot);
emitActionForStep(latestStep); emitActionForStep(latestStep);
} }
setCurrentScreenshotActionId(''); setCurrentScreenshotActionId('');
}; };
@@ -288,11 +288,11 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
iframeDoc, iframeDoc,
listSelector, listSelector,
fields, fields,
5 5
); );
updateListStepData(currentListId, extractedData); updateListStepData(currentListId, extractedData);
if (extractedData.length === 0) { if (extractedData.length === 0) {
console.warn("⚠️ No data extracted - this might indicate selector issues"); console.warn("⚠️ No data extracted - this might indicate selector issues");
notify("warning", "No data was extracted. Please verify your selections."); notify("warning", "No data was extracted. Please verify your selections.");
@@ -355,14 +355,14 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
notify('error', t('right_panel.errors.no_text_captured')); notify('error', t('right_panel.errors.no_text_captured'));
return; return;
} }
stopGetText(); stopGetText();
if (currentTextActionStep) { if (currentTextActionStep) {
emitActionForStep(currentTextActionStep); emitActionForStep(currentTextActionStep);
} }
setCurrentTextActionId(''); setCurrentTextActionId('');
resetInterpretationLog(); resetInterpretationLog();
finishAction('text'); finishAction('text');
onFinishCapture(); onFinishCapture();
clientSelectorGenerator.cleanup(); clientSelectorGenerator.cleanup();
}, [stopGetText, socket, browserSteps, resetInterpretationLog, finishAction, notify, onFinishCapture, t, currentTextActionId, currentTextGroupName, emitActionForStep]); }, [stopGetText, socket, browserSteps, resetInterpretationLog, finishAction, notify, onFinishCapture, t, currentTextActionId, currentTextGroupName, emitActionForStep]);
@@ -453,7 +453,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
const getLatestListStep = (steps: BrowserStep[]) => { const getLatestListStep = (steps: BrowserStep[]) => {
const listSteps = steps.filter(step => step.type === 'list'); const listSteps = steps.filter(step => step.type === 'list');
if (listSteps.length === 0) return null; if (listSteps.length === 0) return null;
return listSteps.sort((a, b) => b.id - a.id)[0]; return listSteps.sort((a, b) => b.id - a.id)[0];
}; };
@@ -466,12 +466,12 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
step.listSelector && step.listSelector &&
Object.keys(step.fields).length > 0 Object.keys(step.fields).length > 0
); );
if (!hasValidListSelectorForCurrentAction) { if (!hasValidListSelectorForCurrentAction) {
notify('error', t('right_panel.errors.capture_list_first')); notify('error', t('right_panel.errors.capture_list_first'));
return; return;
} }
const currentListStepForAutoDetect = browserSteps.find( const currentListStepForAutoDetect = browserSteps.find(
step => step.type === 'list' && step.actionId === currentListActionId step => step.type === 'list' && step.actionId === currentListActionId
) as (BrowserStep & { type: 'list'; listSelector?: string }) | undefined; ) as (BrowserStep & { type: 'list'; listSelector?: string }) | undefined;
@@ -657,7 +657,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
notify('error', t('right_panel.errors.select_pagination')); notify('error', t('right_panel.errors.select_pagination'));
return; return;
} }
const currentListStepForPagination = browserSteps.find( const currentListStepForPagination = browserSteps.find(
step => step.type === 'list' && step.actionId === currentListActionId step => step.type === 'list' && step.actionId === currentListActionId
) as (BrowserStep & { type: 'list' }) | undefined; ) as (BrowserStep & { type: 'list' }) | undefined;
@@ -728,15 +728,15 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
const discardGetText = useCallback(() => { const discardGetText = useCallback(() => {
stopGetText(); stopGetText();
if (currentTextActionId) { if (currentTextActionId) {
deleteStepsByActionId(currentTextActionId); deleteStepsByActionId(currentTextActionId);
if (socket) { if (socket) {
socket.emit('removeAction', { actionId: currentTextActionId }); socket.emit('removeAction', { actionId: currentTextActionId });
} }
} }
setCurrentTextActionId(''); setCurrentTextActionId('');
clientSelectorGenerator.cleanup(); clientSelectorGenerator.cleanup();
notify('error', t('right_panel.errors.capture_text_discarded')); notify('error', t('right_panel.errors.capture_text_discarded'));
@@ -744,10 +744,10 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
const discardGetList = useCallback(() => { const discardGetList = useCallback(() => {
stopGetList(); stopGetList();
if (currentListActionId) { if (currentListActionId) {
deleteStepsByActionId(currentListActionId); deleteStepsByActionId(currentListActionId);
if (socket) { if (socket) {
socket.emit('removeAction', { actionId: currentListActionId }); socket.emit('removeAction', { actionId: currentListActionId });
} }
@@ -792,7 +792,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
} }
} }
} }
resetListState(); resetListState();
stopPaginationMode(); stopPaginationMode();
stopLimitMode(); stopLimitMode();
@@ -808,7 +808,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
const captureScreenshot = (fullPage: boolean) => { const captureScreenshot = (fullPage: boolean) => {
const screenshotCount = browserSteps.filter(s => s.type === 'screenshot').length + 1; const screenshotCount = browserSteps.filter(s => s.type === 'screenshot').length + 1;
const screenshotName = `Screenshot ${screenshotCount}`; const screenshotName = `Screenshot ${screenshotCount}`;
const screenshotSettings = { const screenshotSettings = {
fullPage, fullPage,
type: 'png' as const, type: 'png' as const,
@@ -819,7 +819,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
name: screenshotName, name: screenshotName,
actionId: currentScreenshotActionId actionId: currentScreenshotActionId
}; };
socket?.emit('captureDirectScreenshot', screenshotSettings); socket?.emit('captureDirectScreenshot', screenshotSettings);
addScreenshotStep(fullPage, currentScreenshotActionId); addScreenshotStep(fullPage, currentScreenshotActionId);
stopGetScreenshot(); stopGetScreenshot();
resetInterpretationLog(); resetInterpretationLog();
@@ -838,8 +838,8 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
{!isAnyActionActive && ( {!isAnyActionActive && (
<> <>
{showCaptureList && ( {showCaptureList && (
<Button <Button
variant="contained" variant="contained"
onClick={handleStartGetList} onClick={handleStartGetList}
> >
{t('right_panel.buttons.capture_list')} {t('right_panel.buttons.capture_list')}
@@ -847,8 +847,8 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
)} )}
{showCaptureText && ( {showCaptureText && (
<Button <Button
variant="contained" variant="contained"
onClick={handleStartGetText} onClick={handleStartGetText}
> >
{t('right_panel.buttons.capture_text')} {t('right_panel.buttons.capture_text')}
@@ -856,8 +856,8 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
)} )}
{showCaptureScreenshot && ( {showCaptureScreenshot && (
<Button <Button
variant="contained" variant="contained"
onClick={handleStartGetScreenshot} onClick={handleStartGetScreenshot}
> >
{t('right_panel.buttons.capture_screenshot')} {t('right_panel.buttons.capture_screenshot')}
@@ -909,25 +909,25 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
{t('right_panel.buttons.discard')} {t('right_panel.buttons.discard')}
</Button> </Button>
</Box> </Box>
{showPaginationOptions && ( {showPaginationOptions && (
<Box display="flex" flexDirection="column" gap={2} style={{ margin: '13px' }}> <Box display="flex" flexDirection="column" gap={2} style={{ margin: '13px' }}>
<Typography>{t('right_panel.pagination.title')}</Typography> <Typography>{t('right_panel.pagination.title')}</Typography>
{autoDetectedPagination && autoDetectedPagination.type !== '' && ( {autoDetectedPagination && autoDetectedPagination.type !== '' && (
<Box <Box
sx={{ sx={{
p: 2, p: 2,
mb: 1, mb: 1,
borderRadius: '8px', borderRadius: '8px',
backgroundColor: isDarkMode ? '#1a3a1a' : '#e8f5e9', color: '#1E2124',
border: `1px solid ${isDarkMode ? '#2e7d32' : '#4caf50'}`, backgroundColor: isDarkMode ? '#f4f6f4' : '#f4f6f4',
border: `1px solid ${isDarkMode ? '#f4f6f4' : '#f4f6f4'}`,
}} }}
> >
<Typography <Typography
variant="body2" variant="body2"
sx={{ sx={{
color: isDarkMode ? '#81c784' : '#2e7d32',
fontWeight: 'bold', fontWeight: 'bold',
mb: 0.5 mb: 0.5
}} }}
@@ -943,7 +943,6 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
<Typography <Typography
variant="caption" variant="caption"
sx={{ sx={{
color: isDarkMode ? '#a5d6a7' : '#388e3c',
display: 'block', display: 'block',
mb: 1 mb: 1
}} }}
@@ -1008,11 +1007,11 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
} }
}} }}
sx={{ sx={{
color: isDarkMode ? '#81c784' : '#2e7d32', color: '#ff00c3 !important',
borderColor: isDarkMode ? '#81c784' : '#2e7d32', borderColor: '#ff00c3 !important',
'&:hover': { '&:hover': {
borderColor: isDarkMode ? '#a5d6a7' : '#4caf50', borderColor: '#ff00c3 !important',
backgroundColor: isDarkMode ? '#1a3a1a' : '#f1f8f4', backgroundColor: '#f4f6f4 !important',
} }
}} }}
> >
@@ -1072,15 +1071,15 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
{t('right_panel.pagination.none')}</Button> {t('right_panel.pagination.none')}</Button>
</Box> </Box>
)} )}
{showLimitOptions && ( {showLimitOptions && (
<FormControl> <FormControl>
<Typography variant="h6" sx={{ <Typography variant="h6" sx={{
fontSize: '16px', fontSize: '16px',
fontWeight: 'bold', fontWeight: 'bold',
mb: 1, mb: 1,
whiteSpace: 'normal', whiteSpace: 'normal',
wordBreak: 'break-word' wordBreak: 'break-word'
}}> }}>
{t('right_panel.limit.title')} {t('right_panel.limit.title')}
</Typography> </Typography>
@@ -1134,7 +1133,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
)} )}
</Box> </Box>
)} )}
{getText && ( {getText && (
<Box> <Box>
<Box display="flex" justifyContent="space-between" gap={2} style={{ margin: '15px' }}> <Box display="flex" justifyContent="space-between" gap={2} style={{ margin: '15px' }}>
@@ -1164,7 +1163,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
</Box> </Box>
</Box> </Box>
)} )}
{getScreenshot && ( {getScreenshot && (
<Box display="flex" flexDirection="column" gap={2}> <Box display="flex" flexDirection="column" gap={2}>
<Button variant="contained" onClick={() => captureScreenshot(true)}> <Button variant="contained" onClick={() => captureScreenshot(true)}>