feat: shift out preview data capture logic
This commit is contained in:
@@ -21,6 +21,7 @@ import ActionDescriptionBox from '../action/ActionDescriptionBox';
|
|||||||
import { useThemeMode } from '../../context/theme-provider';
|
import { useThemeMode } from '../../context/theme-provider';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useBrowserDimensionsStore } from '../../context/browserDimensions';
|
import { useBrowserDimensionsStore } from '../../context/browserDimensions';
|
||||||
|
import { clientListExtractor } from '../../helpers/clientListExtractor';
|
||||||
|
|
||||||
const fetchWorkflow = (id: string, callback: (response: WorkflowFile) => void) => {
|
const fetchWorkflow = (id: string, callback: (response: WorkflowFile) => void) => {
|
||||||
getActiveWorkflow(id).then(
|
getActiveWorkflow(id).then(
|
||||||
@@ -51,6 +52,8 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
|
|||||||
const [isCaptureTextConfirmed, setIsCaptureTextConfirmed] = useState(false);
|
const [isCaptureTextConfirmed, setIsCaptureTextConfirmed] = useState(false);
|
||||||
const [isCaptureListConfirmed, setIsCaptureListConfirmed] = useState(false);
|
const [isCaptureListConfirmed, setIsCaptureListConfirmed] = useState(false);
|
||||||
const { panelHeight } = useBrowserDimensionsStore();
|
const { panelHeight } = useBrowserDimensionsStore();
|
||||||
|
const [isDOMMode, setIsDOMMode] = useState(false);
|
||||||
|
const [currentSnapshot, setCurrentSnapshot] = useState<any>(null);
|
||||||
|
|
||||||
const { lastAction, notify, currentWorkflowActionsState, setCurrentWorkflowActionsState, resetInterpretationLog, currentListActionId, setCurrentListActionId, currentTextActionId, setCurrentTextActionId, currentScreenshotActionId, setCurrentScreenshotActionId } = useGlobalInfoStore();
|
const { lastAction, notify, currentWorkflowActionsState, setCurrentWorkflowActionsState, resetInterpretationLog, currentListActionId, setCurrentListActionId, currentTextActionId, setCurrentTextActionId, currentScreenshotActionId, setCurrentScreenshotActionId } = useGlobalInfoStore();
|
||||||
const {
|
const {
|
||||||
@@ -69,7 +72,7 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
|
|||||||
startAction, finishAction
|
startAction, finishAction
|
||||||
} = useActionContext();
|
} = 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 { id, socket } = useSocketStore();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -79,6 +82,42 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
|
|||||||
setWorkflow(data);
|
setWorkflow(data);
|
||||||
}, [setWorkflow]);
|
}, [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(() => {
|
useEffect(() => {
|
||||||
if (socket) {
|
if (socket) {
|
||||||
socket.on("workflow", workflowHandler);
|
socket.on("workflow", workflowHandler);
|
||||||
@@ -129,6 +168,100 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
|
|||||||
setShowCaptureText(true);
|
setShowCaptureText(true);
|
||||||
}, [workflow, setCurrentWorkflowActionsState]);
|
}, [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<string, any>,
|
||||||
|
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) => {
|
const handleMouseEnter = (id: number) => {
|
||||||
setHoverStates(prev => ({ ...prev, [id]: true }));
|
setHoverStates(prev => ({ ...prev, [id]: true }));
|
||||||
};
|
};
|
||||||
@@ -338,17 +471,22 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
|
|||||||
|
|
||||||
const stopCaptureAndEmitGetListSettings = useCallback(() => {
|
const stopCaptureAndEmitGetListSettings = useCallback(() => {
|
||||||
const settings = getListSettingsObject();
|
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 });
|
socket?.emit('action', { action: 'scrapeList', settings });
|
||||||
} else {
|
} else {
|
||||||
notify('error', t('right_panel.errors.unable_create_settings'));
|
notify('error', t('right_panel.errors.unable_create_settings'));
|
||||||
}
|
}
|
||||||
|
|
||||||
handleStopGetList();
|
handleStopGetList();
|
||||||
setCurrentListActionId('');
|
setCurrentListActionId('');
|
||||||
resetInterpretationLog();
|
resetInterpretationLog();
|
||||||
finishAction('list');
|
finishAction('list');
|
||||||
onFinishCapture();
|
onFinishCapture();
|
||||||
}, [getListSettingsObject, socket, notify, handleStopGetList, resetInterpretationLog, finishAction, onFinishCapture, t]);
|
}, [getListSettingsObject, socket, notify, handleStopGetList, resetInterpretationLog, finishAction, onFinishCapture, t, browserSteps, extractDataClientSide]);
|
||||||
|
|
||||||
const hasUnconfirmedListTextFields = browserSteps.some(step =>
|
const hasUnconfirmedListTextFields = browserSteps.some(step =>
|
||||||
step.type === 'list' &&
|
step.type === 'list' &&
|
||||||
|
|||||||
Reference in New Issue
Block a user