diff --git a/server/src/workflow-management/classes/Interpreter.ts b/server/src/workflow-management/classes/Interpreter.ts index 8c1f7e5e6..f46ae1601 100644 --- a/server/src/workflow-management/classes/Interpreter.ts +++ b/server/src/workflow-management/classes/Interpreter.ts @@ -625,7 +625,6 @@ export class WorkflowInterpreter { try { const sequelize = require('../../storage/db').default; await sequelize.transaction(async (transaction: any) => { - const { Run } = require('../../models'); const run = await Run.findOne({ where: { runId: this.currentRunId! }, transaction @@ -690,6 +689,10 @@ export class WorkflowInterpreter { } } finally { this.persistenceInProgress = false; + + if (this.persistenceBuffer.length > 0 && !this.persistenceTimer) { + this.scheduleBatchFlush(); + } } }; } diff --git a/src/context/socket.tsx b/src/context/socket.tsx index 05a8c989c..25440f50a 100644 --- a/src/context/socket.tsx +++ b/src/context/socket.tsx @@ -9,7 +9,7 @@ interface SocketState { queueSocket: Socket | null; id: string; setId: (id: string) => void; - connectToQueueSocket: (userId: string, onRunCompleted?: (data: any) => void) => void; + connectToQueueSocket: (userId: string, onRunCompleted?: (data: any) => void, onRunStarted?: (data: any) => void, onRunRecovered?: (data: any) => void, onRunScheduled?: (data: any) => void) => void; disconnectQueueSocket: () => void; }; @@ -29,6 +29,9 @@ export const SocketProvider = ({ children }: { children: JSX.Element }) => { const [queueSocket, setQueueSocket] = useState(socketStore.queueSocket); const [id, setActiveId] = useState(socketStore.id); const runCompletedCallbackRef = useRef<((data: any) => void) | null>(null); + const runStartedCallbackRef = useRef<((data: any) => void) | null>(null); + const runRecoveredCallbackRef = useRef<((data: any) => void) | null>(null); + const runScheduledCallbackRef = useRef<((data: any) => void) | null>(null); const setId = useCallback((id: string) => { // the socket client connection is recomputed whenever id changes -> the new browser has been initialized @@ -45,8 +48,11 @@ export const SocketProvider = ({ children }: { children: JSX.Element }) => { setActiveId(id); }, [setSocket]); - const connectToQueueSocket = useCallback((userId: string, onRunCompleted?: (data: any) => void) => { + const connectToQueueSocket = useCallback((userId: string, onRunCompleted?: (data: any) => void, onRunStarted?: (data: any) => void, onRunRecovered?: (data: any) => void, onRunScheduled?: (data: any) => void) => { runCompletedCallbackRef.current = onRunCompleted || null; + runStartedCallbackRef.current = onRunStarted || null; + runRecoveredCallbackRef.current = onRunRecovered || null; + runScheduledCallbackRef.current = onRunScheduled || null; const newQueueSocket = io(`${SERVER_ENDPOINT}/queued-run`, { transports: ["websocket"], @@ -69,6 +75,27 @@ export const SocketProvider = ({ children }: { children: JSX.Element }) => { } }); + newQueueSocket.on('run-started', (startedData) => { + console.log('Run started event received:', startedData); + if (runStartedCallbackRef.current) { + runStartedCallbackRef.current(startedData); + } + }); + + newQueueSocket.on('run-recovered', (recoveredData) => { + console.log('Run recovered event received:', recoveredData); + if (runRecoveredCallbackRef.current) { + runRecoveredCallbackRef.current(recoveredData); + } + }); + + newQueueSocket.on('run-scheduled', (scheduledData) => { + console.log('Run scheduled event received:', scheduledData); + if (runScheduledCallbackRef.current) { + runScheduledCallbackRef.current(scheduledData); + } + }); + setQueueSocket(currentSocket => { if (currentSocket) { currentSocket.disconnect(); @@ -89,6 +116,8 @@ export const SocketProvider = ({ children }: { children: JSX.Element }) => { socketStore.queueSocket = null; runCompletedCallbackRef.current = null; + runRecoveredCallbackRef.current = null; + runScheduledCallbackRef.current = null; }, []); // Cleanup on unmount diff --git a/src/helpers/clientSelectorGenerator.ts b/src/helpers/clientSelectorGenerator.ts index dac49d022..385aa8ecb 100644 --- a/src/helpers/clientSelectorGenerator.ts +++ b/src/helpers/clientSelectorGenerator.ts @@ -3906,24 +3906,6 @@ class ClientSelectorGenerator { let elements = iframeDoc.elementsFromPoint(x, y) as HTMLElement[]; if (!elements.length) return null; - const dialogElement = this.findDialogElement(elements); - if (dialogElement) { - const dialogRect = dialogElement.getBoundingClientRect(); - const isClickInsideDialog = x >= dialogRect.left && x <= dialogRect.right && - y >= dialogRect.top && y <= dialogRect.bottom; - - if (isClickInsideDialog) { - const dialogElements = elements.filter( - (el) => el === dialogElement || dialogElement.contains(el) - ); - - const deepestInDialog = this.findDeepestInDialog(dialogElements, dialogElement); - if (deepestInDialog) { - return deepestInDialog; - } - } - } - const filteredElements = this.filterLogicalElements(elements, x, y); const targetElements = filteredElements.length > 0 ? filteredElements : elements; @@ -4061,72 +4043,6 @@ class ClientSelectorGenerator { return depth; } - /** - * Find dialog element in the elements array - */ - private findDialogElement(elements: HTMLElement[]): HTMLElement | null { - let dialogElement = elements.find((el) => el.getAttribute("role") === "dialog"); - - if (!dialogElement) { - dialogElement = elements.find((el) => el.tagName.toLowerCase() === "dialog"); - } - - if (!dialogElement) { - dialogElement = elements.find((el) => { - const classList = el.classList.toString().toLowerCase(); - const id = (el.id || "").toLowerCase(); - - return ( - classList.includes("modal") || - classList.includes("dialog") || - classList.includes("popup") || - classList.includes("overlay") || - id.includes("modal") || - id.includes("dialog") || - id.includes("popup") - ); - }); - } - - return dialogElement || null; - } - - /** - * Find the deepest element within a dialog - */ - private findDeepestInDialog( - dialogElements: HTMLElement[], - dialogElement: HTMLElement - ): HTMLElement | null { - if (!dialogElements.length) return null; - if (dialogElements.length === 1) return dialogElements[0]; - - let deepestElement = dialogElements[0]; - let maxDepth = 0; - - for (const element of dialogElements) { - let depth = 0; - let current = element; - - // Calculate depth within the dialog context - while ( - current && - current.parentElement && - current !== dialogElement.parentElement - ) { - depth++; - current = current.parentElement; - } - - if (depth > maxDepth) { - maxDepth = depth; - deepestElement = element; - } - } - - return deepestElement; - } - /** * Check if an element is a dialog */ diff --git a/src/pages/MainPage.tsx b/src/pages/MainPage.tsx index 2067fc885..a0a86707e 100644 --- a/src/pages/MainPage.tsx +++ b/src/pages/MainPage.tsx @@ -215,6 +215,14 @@ export const MainPage = ({ handleEditRecording, initialContent }: MainPageProps) useEffect(() => { if (user?.id) { + const handleRunStarted = (startedData: any) => { + setRerenderRuns(true); + invalidateRuns(); + + const robotName = startedData.robotName || 'Unknown Robot'; + notify('info', t('main_page.notifications.run_started', { name: robotName })); + }; + const handleRunCompleted = (completionData: any) => { setRerenderRuns(true); invalidateRuns(); @@ -235,14 +243,36 @@ export const MainPage = ({ handleEditRecording, initialContent }: MainPageProps) notify('error', t('main_page.notifications.interpretation_failed', { name: robotName })); } }; + + const handleRunRecovered = (recoveredData: any) => { + setRerenderRuns(true); + invalidateRuns(); + + if (queuedRuns.has(recoveredData.runId)) { + setQueuedRuns(prev => { + const newSet = new Set(prev); + newSet.delete(recoveredData.runId); + return newSet; + }); + } + + const robotName = recoveredData.robotName || 'Unknown Robot'; + notify('error', t('main_page.notifications.interpretation_failed', { name: robotName })); + }; + + const handleRunScheduled = (scheduledData: any) => { + setRerenderRuns(true); + invalidateRuns(); + }; - connectToQueueSocket(user.id, handleRunCompleted); + connectToQueueSocket(user.id, handleRunCompleted, handleRunStarted, handleRunRecovered, handleRunScheduled); return () => { + console.log('Disconnecting persistent queue socket for user:', user.id); disconnectQueueSocket(); }; } - }, [user?.id, connectToQueueSocket, disconnectQueueSocket, t, setRerenderRuns, queuedRuns, setQueuedRuns, invalidateRuns]); + }, [user?.id, connectToQueueSocket, disconnectQueueSocket, t, setRerenderRuns, queuedRuns, setQueuedRuns]); const DisplayContent = () => { switch (content) {