'use client' import { useEffect, useState, useRef, useCallback } from 'react' import { motion } from 'framer-motion' import { cn, formatUptime, timeAgo } from '@/lib/utils' import { useEngineStore } from '@/store/engineStore' import { pauseEngine, resumeEngine, restartEngine, killEngine, } from '@/lib/api/engine' import type { TargetSite } from '@/lib/types' const BASE = 'http://localhost:8000' const SITE_POLL_MS = 25_000 function StatusOrb({ status }: { status: 'Running' | 'Paused' | 'Idle' }) { const map = { Running: { color: '#00e87b', label: 'Running', shadow: 'rgba(0,232,123,0.5)' }, Paused: { color: '#fbbf24', label: 'Paused', shadow: 'rgba(251,191,36,0.5)' }, Idle: { color: '#3d4f78', label: 'Idle', shadow: 'rgba(61,79,120,0.3)' }, } const m = map[status] ?? map.Idle return (
{/* Pulsing dot + aura */}
{status === 'Running' && ( )}
{m.label}
) } interface CtrlBtn { label: string icon: React.ReactNode onClick: () => void variant: 'default' | 'danger' disabled?: boolean } function ControlButton({ label, icon, onClick, variant, disabled }: CtrlBtn) { const [busy, setBusy] = useState(false) const handle = async () => { if (busy || disabled) return setBusy(true) try { await onClick() } finally { setTimeout(() => setBusy(false), 1500) } } return ( {busy ? ( ) : icon} {label} ) } function SiteRow({ site }: { site: TargetSite }) { const isEnabled = site.enabled === 1 const isCooling = site.cooldown_until ? new Date(site.cooldown_until) > new Date() : false const hasError = site.consecutive_failures > 0 let statusColor = '#3d4f78' let statusLabel = 'Disabled' if (isEnabled && isCooling) { statusColor = '#fbbf24'; statusLabel = 'Cooldown' } else if (isEnabled && hasError) { statusColor = '#f43f5e'; statusLabel = `${site.consecutive_failures}x fail` } else if (isEnabled) { statusColor = '#00e87b'; statusLabel = 'Active' } return (
{site.name} {statusLabel}
) } export default function EngineConsole() { const { status, uptime_seconds, total_scanned, last_cycle, isOffline } = useEngineStore() const [sites, setSites] = useState([]) const [cycleAgo, setCycleAgo] = useState('—') const aliveRef = useRef(true) const fetchSites = useCallback(async () => { try { const res = await fetch(`${BASE}/api/sites`) const data: TargetSite[] = await res.json() if (aliveRef.current) setSites(Array.isArray(data) ? data : []) } catch { /* silent */ } }, []) useEffect(() => { aliveRef.current = true fetchSites() const id = setInterval(fetchSites, SITE_POLL_MS) return () => { aliveRef.current = false; clearInterval(id) } }, [fetchSites]) // Live relative timestamp useEffect(() => { const tick = () => setCycleAgo(timeAgo(last_cycle === 'Never' ? null : last_cycle)) tick() const id = setInterval(tick, 5000) return () => clearInterval(id) }, [last_cycle]) const isRunning = status === 'Running' const isPaused = status === 'Paused' const enabledCount = sites.filter(s => s.enabled === 1).length const controls: CtrlBtn[] = [ { label: 'Pause', variant: 'default', disabled: !isRunning, onClick: () => pauseEngine(), icon: ( ), }, { label: 'Resume', variant: 'default', disabled: !isPaused, onClick: () => resumeEngine(), icon: ( ), }, { label: 'Restart', variant: 'default', disabled: false, onClick: () => restartEngine(), icon: ( ), }, { label: 'Kill', variant: 'danger', disabled: false, onClick: () => killEngine(), icon: ( ), }, ] return ( {/* ── Status Hero ── */}
Engine Status {isOffline && ( OFFLINE )}
{/* Big status */} {/* Telemetry strip */}

Uptime

{formatUptime(uptime_seconds)}

Last Scan

{cycleAgo}

Lots Scanned

{total_scanned.toLocaleString()}

{/* ── Controls ── */}
Controls
{controls.map(btn => ( ))}
{/* ── Site Health ── */}
Sites {enabledCount}/{sites.length} active
{sites.length === 0 ? (

No sites configured

) : ( sites.map(s => ) )}
) }