From 776339bbedf2831d937e593294736deb3bdebe2c Mon Sep 17 00:00:00 2001 From: Rohit Date: Mon, 23 Jun 2025 14:34:08 +0530 Subject: [PATCH] feat: shift out preview data capture logic --- src/components/recorder/RightSidePanel.tsx | 144 ++++++++++++++++++++- 1 file changed, 141 insertions(+), 3 deletions(-) diff --git a/src/components/recorder/RightSidePanel.tsx b/src/components/recorder/RightSidePanel.tsx index 8d8cac22..e7268b09 100644 --- a/src/components/recorder/RightSidePanel.tsx +++ b/src/components/recorder/RightSidePanel.tsx @@ -21,6 +21,7 @@ import ActionDescriptionBox from '../action/ActionDescriptionBox'; import { useThemeMode } from '../../context/theme-provider'; import { useTranslation } from 'react-i18next'; import { useBrowserDimensionsStore } from '../../context/browserDimensions'; +import { clientListExtractor } from '../../helpers/clientListExtractor'; const fetchWorkflow = (id: string, callback: (response: WorkflowFile) => void) => { getActiveWorkflow(id).then( @@ -51,6 +52,8 @@ export const RightSidePanel: React.FC = ({ onFinishCapture const [isCaptureTextConfirmed, setIsCaptureTextConfirmed] = useState(false); const [isCaptureListConfirmed, setIsCaptureListConfirmed] = useState(false); const { panelHeight } = useBrowserDimensionsStore(); + const [isDOMMode, setIsDOMMode] = useState(false); + const [currentSnapshot, setCurrentSnapshot] = useState(null); const { lastAction, notify, currentWorkflowActionsState, setCurrentWorkflowActionsState, resetInterpretationLog, currentListActionId, setCurrentListActionId, currentTextActionId, setCurrentTextActionId, currentScreenshotActionId, setCurrentScreenshotActionId } = useGlobalInfoStore(); const { @@ -69,7 +72,7 @@ export const RightSidePanel: React.FC = ({ onFinishCapture startAction, finishAction } = useActionContext(); - const { browserSteps, updateBrowserTextStepLabel, deleteBrowserStep, addScreenshotStep, updateListTextFieldLabel, removeListTextField, updateListStepLimit, deleteStepsByActionId } = useBrowserSteps(); + const { browserSteps, updateBrowserTextStepLabel, deleteBrowserStep, addScreenshotStep, updateListTextFieldLabel, removeListTextField, updateListStepLimit, deleteStepsByActionId, updateListStepData } = useBrowserSteps(); const { id, socket } = useSocketStore(); const { t } = useTranslation(); @@ -79,6 +82,42 @@ export const RightSidePanel: React.FC = ({ onFinishCapture setWorkflow(data); }, [setWorkflow]); + useEffect(() => { + if (socket) { + const domModeHandler = (data: any) => { + if (!data.userId || data.userId === id) { + setIsDOMMode(true); + } + }; + + const screenshotModeHandler = (data: any) => { + if (!data.userId || data.userId === id) { + setIsDOMMode(false); + setCurrentSnapshot(null); + } + }; + + const domcastHandler = (data: any) => { + if (!data.userId || data.userId === id) { + if (data.snapshotData && data.snapshotData.snapshot) { + setCurrentSnapshot(data.snapshotData); + setIsDOMMode(true); + } + } + }; + + socket.on("dom-mode-enabled", domModeHandler); + socket.on("screenshot-mode-enabled", screenshotModeHandler); + socket.on("domcast", domcastHandler); + + return () => { + socket.off("dom-mode-enabled", domModeHandler); + socket.off("screenshot-mode-enabled", screenshotModeHandler); + socket.off("domcast", domcastHandler); + }; + } + }, [socket, id]); + useEffect(() => { if (socket) { socket.on("workflow", workflowHandler); @@ -129,6 +168,100 @@ export const RightSidePanel: React.FC = ({ onFinishCapture setShowCaptureText(true); }, [workflow, setCurrentWorkflowActionsState]); + useEffect(() => { + if (socket) { + socket.on('listDataExtracted', (response) => { + if (!isDOMMode) { + const { currentListId, data } = response; + updateListStepData(currentListId, data); + } + }); + } + + return () => { + socket?.off('listDataExtracted'); + }; + }, [socket, updateListStepData, isDOMMode]); + + const extractDataClientSide = useCallback( + ( + listSelector: string, + fields: Record, + currentListId: number + ) => { + if (isDOMMode && currentSnapshot) { + try { + // Find the DOM iframe element + let iframeElement = document.querySelector( + "#dom-browser-iframe" + ) as HTMLIFrameElement; + + if (!iframeElement) { + iframeElement = document.querySelector( + "#browser-window iframe" + ) as HTMLIFrameElement; + } + + if (!iframeElement) { + const browserWindow = document.querySelector("#browser-window"); + if (browserWindow) { + iframeElement = browserWindow.querySelector( + "iframe" + ) as HTMLIFrameElement; + } + } + + if (!iframeElement) { + console.error( + "Could not find the DOM iframe element for extraction" + ); + return; + } + + const iframeDoc = iframeElement.contentDocument; + if (!iframeDoc) { + console.error("Failed to get iframe document"); + return; + } + + // Use client-side extraction + const extractedData = clientListExtractor.extractListData( + iframeDoc, + listSelector, + fields, + 5 // limit for preview + ); + + updateListStepData(currentListId, extractedData); + console.log("✅ Client-side extraction completed:", extractedData); + } catch (error) { + console.error("Error in client-side data extraction:", error); + notify("error", "Failed to extract data client-side"); + } + } else { + // Fallback to socket-based extraction for screenshot mode + if (!socket) { + console.error("Socket not available for backend extraction"); + return; + } + + try { + socket.emit("extractListData", { + listSelector, + fields, + currentListId, + pagination: { type: "", selector: "" }, + }); + + console.log("📤 Sent extraction request to backend"); + } catch (error) { + console.error("Error in backend data extraction:", error); + } + } + }, + [isDOMMode, currentSnapshot, updateListStepData, socket, notify] + ); + const handleMouseEnter = (id: number) => { setHoverStates(prev => ({ ...prev, [id]: true })); }; @@ -338,17 +471,22 @@ export const RightSidePanel: React.FC = ({ onFinishCapture const stopCaptureAndEmitGetListSettings = useCallback(() => { const settings = getListSettingsObject(); - if (settings) { + + const latestListStep = getLatestListStep(browserSteps); + if (latestListStep && settings) { + extractDataClientSide(latestListStep.listSelector!, latestListStep.fields, latestListStep.id); + socket?.emit('action', { action: 'scrapeList', settings }); } else { notify('error', t('right_panel.errors.unable_create_settings')); } + handleStopGetList(); setCurrentListActionId(''); resetInterpretationLog(); finishAction('list'); onFinishCapture(); - }, [getListSettingsObject, socket, notify, handleStopGetList, resetInterpretationLog, finishAction, onFinishCapture, t]); + }, [getListSettingsObject, socket, notify, handleStopGetList, resetInterpretationLog, finishAction, onFinishCapture, t, browserSteps, extractDataClientSide]); const hasUnconfirmedListTextFields = browserSteps.some(step => step.type === 'list' &&