mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-02-01 23:13:36 +00:00
feat: add concurrent agents with dependency system and delightful UI
Major feature implementation for parallel agent execution with dependency-aware scheduling and an engaging multi-agent UI experience. Backend Changes: - Add parallel_orchestrator.py for concurrent feature processing - Add api/dependency_resolver.py with cycle detection (Kahn's algorithm + DFS) - Add atomic feature_claim_next() with retry limit and exponential backoff - Fix circular dependency check arguments in 4 locations - Add AgentTracker class for parsing agent output and emitting updates - Add browser isolation with --isolated flag for Playwright MCP - Extend WebSocket protocol with agent_update messages and log attribution - Add WSAgentUpdateMessage schema with agent states and mascot names - Fix WSProgressMessage to include in_progress field New UI Components: - AgentMissionControl: Dashboard showing active agents with collapsible activity - AgentCard: Individual agent status with avatar and thought bubble - AgentAvatar: SVG mascots (Spark, Fizz, Octo, Hoot, Buzz) with animations - ActivityFeed: Recent activity stream with stable keys (no flickering) - CelebrationOverlay: Confetti animation with click/Escape dismiss - DependencyGraph: Interactive node graph visualization with dagre layout - DependencyBadge: Visual indicator for feature dependencies - ViewToggle: Switch between Kanban and Graph views - KeyboardShortcutsHelp: Help overlay accessible via ? key UI/UX Improvements: - Celebration queue system to handle rapid success messages - Accessibility attributes on AgentAvatar (role, aria-label, aria-live) - Collapsible Recent Activity section with persisted preference - Agent count display in header - Keyboard shortcut G to toggle Kanban/Graph view - Real-time thought bubbles and state animations Bug Fixes: - Fix circular dependency validation (swapped source/target arguments) - Add MAX_CLAIM_RETRIES=10 to prevent stack overflow under contention - Fix THOUGHT_PATTERNS to match actual [Tool: name] format - Fix ActivityFeed key prop to prevent re-renders on new items - Add featureId/agentIndex to log messages for proper attribution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
120
ui/src/components/CelebrationOverlay.tsx
Normal file
120
ui/src/components/CelebrationOverlay.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { Sparkles, PartyPopper } from 'lucide-react'
|
||||
import { AgentAvatar } from './AgentAvatar'
|
||||
import type { AgentMascot } from '../lib/types'
|
||||
|
||||
interface CelebrationOverlayProps {
|
||||
agentName: AgentMascot
|
||||
featureName: string
|
||||
onComplete?: () => void
|
||||
}
|
||||
|
||||
// Generate random confetti particles
|
||||
function generateConfetti(count: number) {
|
||||
return Array.from({ length: count }, (_, i) => ({
|
||||
id: i,
|
||||
x: Math.random() * 100,
|
||||
delay: Math.random() * 0.5,
|
||||
duration: 1 + Math.random() * 1,
|
||||
color: ['#ff006e', '#ffd60a', '#70e000', '#00b4d8', '#8338ec'][Math.floor(Math.random() * 5)],
|
||||
rotation: Math.random() * 360,
|
||||
}))
|
||||
}
|
||||
|
||||
export function CelebrationOverlay({ agentName, featureName, onComplete }: CelebrationOverlayProps) {
|
||||
const [isVisible, setIsVisible] = useState(true)
|
||||
const [confetti] = useState(() => generateConfetti(30))
|
||||
|
||||
const dismiss = useCallback(() => {
|
||||
setIsVisible(false)
|
||||
setTimeout(() => onComplete?.(), 300) // Wait for fade animation
|
||||
}, [onComplete])
|
||||
|
||||
useEffect(() => {
|
||||
// Auto-dismiss after 3 seconds
|
||||
const timer = setTimeout(dismiss, 3000)
|
||||
|
||||
// Escape key to dismiss early
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
return () => {
|
||||
clearTimeout(timer)
|
||||
window.removeEventListener('keydown', handleKeyDown)
|
||||
}
|
||||
}, [dismiss])
|
||||
|
||||
if (!isVisible) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
fixed inset-0 z-50 flex items-center justify-center
|
||||
pointer-events-none
|
||||
transition-opacity duration-300
|
||||
${isVisible ? 'opacity-100' : 'opacity-0'}
|
||||
`}
|
||||
>
|
||||
{/* Confetti particles */}
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
{confetti.map((particle) => (
|
||||
<div
|
||||
key={particle.id}
|
||||
className="absolute w-3 h-3 animate-confetti"
|
||||
style={{
|
||||
left: `${particle.x}%`,
|
||||
top: '-20px',
|
||||
backgroundColor: particle.color,
|
||||
animationDelay: `${particle.delay}s`,
|
||||
animationDuration: `${particle.duration}s`,
|
||||
transform: `rotate(${particle.rotation}deg)`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Celebration card - click to dismiss */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={dismiss}
|
||||
className="neo-card p-6 bg-[var(--color-neo-done)] animate-bounce-in pointer-events-auto cursor-pointer hover:scale-105 transition-transform focus:outline-none focus:ring-2 focus:ring-neo-accent"
|
||||
>
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
{/* Icons */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Sparkles size={24} className="text-neo-pending animate-pulse" />
|
||||
<PartyPopper size={28} className="text-neo-accent" />
|
||||
<Sparkles size={24} className="text-neo-pending animate-pulse" />
|
||||
</div>
|
||||
|
||||
{/* Avatar celebrating */}
|
||||
<AgentAvatar name={agentName} state="success" size="lg" />
|
||||
|
||||
{/* Message */}
|
||||
<div className="text-center">
|
||||
<h3 className="font-display text-lg font-bold text-neo-text-on-bright mb-1">
|
||||
Feature Complete!
|
||||
</h3>
|
||||
<p className="text-sm text-neo-text-on-bright/80 max-w-[200px] truncate">
|
||||
{featureName}
|
||||
</p>
|
||||
<p className="text-xs text-neo-text-on-bright/60 mt-2">
|
||||
Great job, {agentName}!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Dismiss hint */}
|
||||
<p className="text-xs text-neo-text-on-bright/40 mt-1">
|
||||
Click or press Esc to dismiss
|
||||
</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user