QueueCard.tsx
1 import { useQueue } from '@/hooks/useDashboard' 2 3 export function QueueCard() { 4 const { data, isLoading, isError } = useQueue() 5 6 // Handle both new format (running/pending) and old format (flat queue) 7 let running = data?.running ?? [] 8 let pending = data?.pending ?? [] 9 const queue = data?.queue ?? [] 10 11 if (running.length === 0 && pending.length === 0 && queue.length > 0) { 12 running = queue.filter(item => item.status === 'running') 13 pending = queue.filter(item => item.status !== 'running') 14 } 15 16 const totalCount = running.length + pending.length 17 18 return ( 19 <section 20 className="rounded-lg overflow-hidden" 21 style={{ background: 'var(--bg-secondary)', border: '1px solid var(--border-color)' }} 22 > 23 <h2 24 className="px-6 py-4 text-base font-semibold flex items-center gap-3" 25 style={{ background: 'var(--bg-tertiary)', borderBottom: '1px solid var(--border-color)', color: 'var(--text-primary)' }} 26 > 27 Queue 28 <span 29 className="px-2 py-0.5 rounded-full text-xs font-semibold text-white" 30 style={{ background: 'var(--accent-blue)' }} 31 > 32 {totalCount} 33 </span> 34 </h2> 35 36 <ul className="list-none" style={{ maxHeight: '400px', overflowY: 'auto' }}> 37 {isLoading && ( 38 <li className="px-4 py-8 text-center" style={{ color: 'var(--text-muted)' }}>Loading...</li> 39 )} 40 {isError && ( 41 <li className="px-4 py-8 text-center" style={{ color: 'var(--text-muted)' }}>Failed to load queue</li> 42 )} 43 {!isLoading && !isError && totalCount === 0 && ( 44 <li className="px-4 py-8 text-center" style={{ color: 'var(--text-muted)' }}>No active runs</li> 45 )} 46 47 {running.length > 0 && ( 48 <li> 49 <div 50 className="px-4 py-2 text-xs font-semibold uppercase tracking-wider" 51 style={{ color: 'var(--text-secondary)', borderBottom: '1px solid var(--border-color)' }} 52 > 53 Running ({running.length}) 54 </div> 55 {running.map((item, i) => ( 56 <div 57 key={i} 58 className="px-4 py-3 flex items-center justify-between" 59 style={{ borderBottom: '1px solid var(--border-color)' }} 60 > 61 <span className="font-medium" style={{ color: 'var(--text-primary)' }}> 62 {item.repo} 63 </span> 64 {item.agent && ( 65 <span className="text-xs" style={{ color: 'var(--text-secondary)' }}> 66 on {item.agent} 67 </span> 68 )} 69 </div> 70 ))} 71 </li> 72 )} 73 74 {pending.length > 0 && ( 75 <li> 76 <div 77 className="px-4 py-2 text-xs font-semibold uppercase tracking-wider" 78 style={{ color: 'var(--text-secondary)', borderBottom: '1px solid var(--border-color)' }} 79 > 80 Pending ({pending.length}) 81 </div> 82 {pending.map((item, i) => ( 83 <div 84 key={i} 85 className="px-4 py-3 flex items-center justify-between" 86 style={{ borderBottom: '1px solid var(--border-color)' }} 87 > 88 <span className="font-medium" style={{ color: 'var(--text-primary)' }}> 89 {item.repo} 90 </span> 91 {item.waiting_for && ( 92 <span className="text-xs" style={{ color: 'var(--text-secondary)' }}> 93 awaiting {item.waiting_for} 94 </span> 95 )} 96 </div> 97 ))} 98 </li> 99 )} 100 </ul> 101 </section> 102 ) 103 }