fix: runAgent fire-and-forget + polling sur la page /agents
Some checks failed
Deploy to Production / Build and Deploy (push) Has been cancelled
Some checks failed
Deploy to Production / Build and Deploy (push) Has been cancelled
Le bouton Play des cartes agents appelait runAgent (Server Action) qui
attendait executeAgent (~2-5 min) → spinner bloqué sans résultat.
- runAgent retourne immédiatement { success, agentId }
- agent-card.tsx lance un polling toutes les 3s sur GET
/api/agents/run-for-note?agentId= jusqu'au statut terminal
- Toast persistant Sonner pendant la génération, mis à jour au résultat
- Cleanup automatique du polling au démontage
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
* Compact card matching the reference design — with a "Next Run / Status" footer.
|
||||
*/
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import { formatDistanceToNow } from 'date-fns'
|
||||
import { fr } from 'date-fns/locale/fr'
|
||||
import { enUS } from 'date-fns/locale/en-US'
|
||||
@@ -83,21 +83,51 @@ export function AgentCard({ agent, onEdit, onRefresh, onToggle }: AgentCardProps
|
||||
const dateLocale = language === 'fr' ? fr : enUS
|
||||
const isNew = Date.now() - new Date(agent.createdAt).getTime() < 5 * 60 * 1000
|
||||
|
||||
const pollRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
||||
|
||||
// Cleanup polling on unmount
|
||||
useEffect(() => () => { if (pollRef.current) clearInterval(pollRef.current) }, [])
|
||||
|
||||
const handleRun = async () => {
|
||||
setIsRunning(true)
|
||||
const toastId = toast.loading(
|
||||
t('agents.toasts.running') || `Agent "${agent.name}" en cours…`,
|
||||
{ description: t('agents.toasts.runningDesc') || 'La génération peut prendre quelques minutes.', duration: Infinity }
|
||||
)
|
||||
try {
|
||||
const { runAgent } = await import('@/app/actions/agent-actions')
|
||||
const result = await runAgent(agent.id)
|
||||
if (result.success) {
|
||||
toast.success(t('agents.toasts.runSuccess', { name: agent.name }))
|
||||
} else {
|
||||
toast.error(t('agents.toasts.runError', { error: result.error || t('agents.toasts.runFailed') }))
|
||||
if (!result.success) {
|
||||
toast.error(t('agents.toasts.runError', { error: result.error || t('agents.toasts.runFailed') }), { id: toastId })
|
||||
setIsRunning(false)
|
||||
return
|
||||
}
|
||||
|
||||
// Poll status every 3 s until terminal state
|
||||
if (pollRef.current) clearInterval(pollRef.current)
|
||||
pollRef.current = setInterval(async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/agents/run-for-note?agentId=${agent.id}`)
|
||||
const data = await res.json()
|
||||
if (data.status === 'success') {
|
||||
clearInterval(pollRef.current!)
|
||||
pollRef.current = null
|
||||
setIsRunning(false)
|
||||
toast.success(t('agents.toasts.runSuccess', { name: agent.name }), { id: toastId, duration: 6000 })
|
||||
onRefresh()
|
||||
} else if (data.status === 'failure') {
|
||||
clearInterval(pollRef.current!)
|
||||
pollRef.current = null
|
||||
setIsRunning(false)
|
||||
toast.error(t('agents.toasts.runError', { error: data.error || t('agents.toasts.runFailed') }), { id: toastId })
|
||||
onRefresh()
|
||||
}
|
||||
} catch { /* network error — keep polling */ }
|
||||
}, 3000)
|
||||
|
||||
} catch {
|
||||
toast.error(t('agents.toasts.runGenericError'))
|
||||
} finally {
|
||||
toast.error(t('agents.toasts.runGenericError'), { id: toastId })
|
||||
setIsRunning(false)
|
||||
onRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user