feat(overlay-sync): wire OverlaySyncService into DI, IPC and renderer gating

This commit is contained in:
2025-11-26 19:14:25 +01:00
parent d08f9e5264
commit 1d7c4f78d1
20 changed files with 611 additions and 561 deletions

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
interface SessionProgress {
sessionId: string;
@@ -36,6 +36,9 @@ const STEP_NAMES: { [key: number]: string } = {
};
export function SessionProgressMonitor({ sessionId, progress, isRunning }: SessionProgressMonitorProps) {
const [ackStatusByStep, setAckStatusByStep] = useState<Record<number, string>>({});
const [automationEventMsg, setAutomationEventMsg] = useState<string | null>(null);
const getStateColor = (state: string) => {
switch (state) {
case 'IN_PROGRESS': return '#0066cc';
@@ -56,6 +59,51 @@ export function SessionProgressMonitor({ sessionId, progress, isRunning }: Sessi
}
};
// Request overlay action when the current step changes (gate overlay rendering on ack)
useEffect(() => {
if (!progress || !sessionId) return;
const currentStep = progress.currentStep;
const action = {
id: `${progress.sessionId}-${currentStep}`,
label: STEP_NAMES[currentStep] || `Step ${currentStep}`,
meta: {},
timeoutMs: 1000
};
let mounted = true;
(async () => {
try {
// Use electronAPI overlayActionRequest to obtain ack
if ((window as any).electronAPI?.overlayActionRequest) {
const ack = await (window as any).electronAPI.overlayActionRequest(action);
if (!mounted) return;
setAckStatusByStep(prev => ({ ...prev, [currentStep]: ack.status }));
} else {
// If no IPC available, mark tentative as fallback
setAckStatusByStep(prev => ({ ...prev, [currentStep]: 'tentative' }));
}
} catch (e) {
if (!mounted) return;
setAckStatusByStep(prev => ({ ...prev, [currentStep]: 'failed' }));
}
})();
return () => { mounted = false; };
}, [progress?.currentStep, sessionId]);
// Subscribe to automation events for optional live updates
useEffect(() => {
if ((window as any).electronAPI?.onAutomationEvent) {
const off = (window as any).electronAPI.onAutomationEvent((ev: any) => {
if (ev && ev.payload && ev.payload.actionId && ev.type) {
setAutomationEventMsg(`${ev.type} ${ev.payload.actionId}`);
} else if (ev && ev.type) {
setAutomationEventMsg(ev.type);
}
});
return () => { if (typeof off === 'function') off(); };
}
return;
}, []);
if (!sessionId && !isRunning) {
return (
<div style={{ textAlign: 'center', color: '#666', paddingTop: '4rem' }}>