fix(vwb): bibliothèque de capture restait vide après 'Capturer'

Cause racine : le useEffect d'ajout à la bibliothèque écoutait la prop
'capture' venant du parent. Le path 'agent Windows distant' (doSmartCapture
quand l'agent V1 répond) faisait setCurrentCapture(state local) mais ne
déclenchait jamais la prop parente — donc useEffect [capture] ne tirait pas,
donc addCaptureToLibrary jamais appelé. La capture s'affichait, mais rien
n'était persisté côté backend.

Fix :
- Factorisation de l'ajout dans un useCallback addToLibrary(cap)
- Appel explicite après setCurrentCapture dans doSmartCapture
- Le path fallback local (via prop capture) garde le useEffect [capture]
  qui appelle aussi addToLibrary

Erreurs d'upload (réseau, backend down) avalées silencieusement avec
console.warn — la capture locale reste utilisable même si le backend
de bibliothèque est indisponible.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-04-29 21:13:56 +02:00
parent 90c1d8036f
commit a67d896104

View File

@@ -92,15 +92,12 @@ export default function CapturePanel({
} }
}, [library, libraryLoaded]); }, [library, libraryLoaded]);
// Ajouter capture à la bibliothèque (format v2 : PNG HD côté backend, // Helper : ajoute une capture à la bibliothèque (PNG HD upload backend +
// thumbnail 640x360 q85 dans le JSON pour la grille). // mise à jour de l'état local). Utilisé par le useEffect [capture] et par
useEffect(() => { // doSmartCapture (capture locale Windows qui ne passe pas par la prop parente).
if (!capture) return; const addToLibrary = useCallback(async (cap: Capture) => {
setCurrentCapture(capture); try {
let cancelled = false; const item = await addCaptureToLibrary(cap, { id: `cap_${Date.now()}` });
(async () => {
const item = await addCaptureToLibrary(capture, { id: `cap_${Date.now()}` });
if (cancelled) return;
setLibrary(prev => [ setLibrary(prev => [
{ {
id: item.id, id: item.id,
@@ -113,9 +110,17 @@ export default function CapturePanel({
}, },
...prev.slice(0, 19), ...prev.slice(0, 19),
]); ]);
})(); } catch (e) {
return () => { cancelled = true; }; console.warn('[CapturePanel] Échec ajout bibliothèque', e);
}, [capture]); }
}, []);
// Capture venant du parent (path "fallback local" via prop capture)
useEffect(() => {
if (!capture) return;
setCurrentCapture(capture);
void addToLibrary(capture);
}, [capture, addToLibrary]);
// Detecter les elements UI quand une capture arrive // Detecter les elements UI quand une capture arrive
useEffect(() => { useEffect(() => {
@@ -161,19 +166,24 @@ export default function CapturePanel({
const resp = await fetch('/api/screen-capture/capture-windows', { method: 'POST' }); const resp = await fetch('/api/screen-capture/capture-windows', { method: 'POST' });
const data = await resp.json(); const data = await resp.json();
if (resp.ok && data.image) { if (resp.ok && data.image) {
setCurrentCapture({ const cap: Capture = {
screenshot_base64: data.image, screenshot_base64: data.image,
width: data.width, width: data.width,
height: data.height, height: data.height,
source: data.source || 'windows', source: data.source || 'windows',
} as any); } as any;
setCurrentCapture(cap);
// Ajouter à la bibliothèque (le useEffect [capture] ne tire pas
// ici car on ne passe pas par la prop parente)
void addToLibrary(cap);
return; return;
} }
console.warn('Agent Windows indisponible, fallback local:', data.error); console.warn('Agent Windows indisponible, fallback local:', data.error);
} catch (err) { } catch (err) {
console.warn('Erreur capture Windows, fallback local:', err); console.warn('Erreur capture Windows, fallback local:', err);
} }
// Fallback : capture locale (ecran du serveur Linux) // Fallback : capture locale (ecran du serveur Linux) — passe par la prop
// parente, l'ajout se fera dans le useEffect [capture]
onCapture(); onCapture();
}; };