Simple debug view

This commit is contained in:
Neo
2026-02-19 12:06:20 +00:00
parent e92e576d22
commit 457e652310

View File

@@ -2,238 +2,39 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
type TaskStatus = 'todo' | 'in-progress' | 'done'; type Task = { id: string; title: string; status: string; assignee: string };
type Task = { id: string; title: string; status: TaskStatus; assignee: string; priority?: string };
type CronJob = { name: string; enabled: boolean; status: string }; type CronJob = { name: string; enabled: boolean; status: string };
type Memory = { id: string; title: string; date: string; preview: string };
type ServerStatus = { cpu: string; ram: string; disk: string; uptime: string; containers: string };
type Backup = { name: string; status: string; lastRun: string };
type Agent = { name: string; role: string; status: string };
type WhatsAppStatus = { status: string; chats: number; lastUpdate: string };
export default function MissionControl() { export default function MissionControl() {
const [activeTab, setActiveTab] = useState('tasks'); const [tab, setTab] = useState('tasks');
const [tasks, setTasks] = useState<Task[]>([]); const [data, setData] = useState<any>(null);
const [crons, setCrons] = useState<CronJob[]>([]);
const [memories, setMemories] = useState<Memory[]>([]);
const [server, setServer] = useState<ServerStatus | null>(null);
const [backups, setBackups] = useState<Backup[]>([]);
const [agents, setAgents] = useState<Agent[]>([]);
const [whatsapp, setWhatsapp] = useState<WhatsAppStatus | null>(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [mounted, setMounted] = useState(false);
useEffect(() => { useEffect(() => {
setMounted(true); setLoading(true);
async function fetchData() { fetch('/api/data?type=' + tab)
try { .then(r => r.json())
const [tasksRes, cronsRes, memoryRes, serverRes, backupsRes, agentsRes, waRes] = await Promise.all([ .then(d => { setData(d); setLoading(false); })
fetch('/api/data?type=tasks'), .catch(() => setLoading(false));
fetch('/api/data?type=crons'), }, [tab]);
fetch('/api/data?type=memory'),
fetch('/api/data?type=server'),
fetch('/api/data?type=backups'),
fetch('/api/data?type=agents'),
fetch('/api/data?type=whatsapp')
]);
setTasks(await tasksRes.json());
setCrons(await cronsRes.json());
setMemories(await memoryRes.json());
setServer(await serverRes.json());
setBackups(await backupsRes.json());
setAgents(await agentsRes.json());
setWhatsapp(await waRes.json());
} catch (e) {
console.error(e);
} finally {
setLoading(false);
}
}
fetchData();
}, []);
const tabs = ['tasks', 'crons', 'server', 'backups', 'agents', 'whatsapp', 'memory'];
return ( return (
<div style={{ minHeight: '100vh', background: '#0a0a0f', color: '#e4e4e7', fontFamily: "'JetBrains Mono', monospace" }}> <div style={{ minHeight: '100vh', background: '#0a0a0f', color: '#fff', padding: '20px', fontFamily: 'monospace' }}>
{/* Background */} <h1 style={{ fontSize: '24px', marginBottom: '20px' }}>MISSION CONTROL</h1>
<div style={{ position: 'fixed', inset: 0, background: 'radial-gradient(ellipse at 20% 20%, rgba(120,0,255,0.15) 0%, transparent 50%), radial-gradient(ellipse at 80% 80%, rgba(255,0,80,0.1) 0%, transparent 50%)', pointerEvents: 'none', zIndex: 0 }} />
{/* Header */} <div style={{ display: 'flex', gap: '10px', marginBottom: '20px', flexWrap: 'wrap' }}>
<header style={{ position: 'relative', zIndex: 10, padding: '15px', borderBottom: '1px solid rgba(255,255,255,0.08)', background: 'rgba(10,10,15,0.8)', backdropFilter: 'blur(10px)' }}> {['tasks', 'crons', 'server', 'backups', 'agents', 'whatsapp', 'memory'].map(t => (
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> <button key={t} onClick={() => setTab(t)} style={{ padding: '10px 20px', background: tab === t ? '#ff0050' : '#333', color: '#fff', border: 'none', borderRadius: '5px', cursor: 'pointer' }}>{t}</button>
<div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<div style={{ width: '32px', height: '32px', borderRadius: '8px', background: 'linear-gradient(135deg, #ff0050 0%, #7800ff 100%)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '16px' }}></div>
<h1 style={{ fontSize: '1rem', fontWeight: 700, background: 'linear-gradient(90deg, #fff 0%, #a0a0a0 100%)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent' }}>MISSION CONTROL</h1>
</div>
<nav style={{ display: 'flex', gap: '3px', flexWrap: 'wrap' }}>
{tabs.map(tab => (
<button key={tab} onClick={() => setActiveTab(tab)} style={{ padding: '8px 12px', background: activeTab === tab ? 'rgba(255,0,80,0.2)' : 'transparent', border: activeTab === tab ? '1px solid rgba(255,0,80,0.3)' : '1px solid transparent', borderRadius: '6px', color: activeTab === tab ? '#ff0050' : '#666', cursor: 'pointer', fontSize: '0.65rem', textTransform: 'uppercase', letterSpacing: '0.5px' }}>{tab}</button>
))} ))}
</nav>
</div> </div>
</header>
{/* Content */} {loading ? (
<main style={{ position: 'relative', zIndex: 10, padding: '15px', maxWidth: '1200px', margin: '0 auto' }}> <p>Loading...</p>
{!mounted || loading ? (
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '50vh', flexDirection: 'column', gap: '15px' }}>
<div style={{ width: '40px', height: '40px', border: '3px solid rgba(255,0,80,0.2)', borderTopColor: '#ff0050', borderRadius: '50%', animation: 'spin 1s linear infinite' }} />
<style>{`@keyframes spin { to { transform: rotate(360deg); } }`}</style>
<p style={{ color: '#666', fontSize: '0.7rem' }}>INITIALIZING...</p>
</div>
) : ( ) : (
<> <pre style={{ background: '#111', padding: '20px', borderRadius: '10px', overflow: 'auto', maxHeight: '70vh' }}>
{activeTab === 'tasks' && <TasksBoard tasks={tasks} />} {JSON.stringify(data, null, 2)}
{activeTab === 'crons' && <CronMonitor crons={crons} />} </pre>
{activeTab === 'server' && <ServerStatus server={server} />}
{activeTab === 'backups' && <BackupStatus backups={backups} />}
{activeTab === 'agents' && <AgentStatus agents={agents} />}
{activeTab === 'whatsapp' && <WhatsAppStatus whatsapp={whatsapp} />}
{activeTab === 'memory' && <MemoryVault memories={memories} />}
</>
)} )}
</main>
</div> </div>
); );
} }
function TasksBoard({ tasks }: { tasks: Task[] }) {
const cols: { status: TaskStatus; label: string; color: string }[] = [
{ status: 'todo', label: 'Queued', color: '#fbbf24' },
{ status: 'in-progress', label: 'Active', color: '#ff0050' },
{ status: 'done', label: 'Complete', color: '#00ff88' },
];
return (
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '15px' }}>
{cols.map(col => (
<div key={col.status} style={{ background: 'rgba(20,20,30,0.6)', borderRadius: '12px', padding: '15px', border: '1px solid rgba(255,255,255,0.05)' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '15px', paddingBottom: '10px', borderBottom: '1px solid rgba(255,255,255,0.05)' }}>
<div style={{ width: '8px', height: '8px', borderRadius: '50%', background: col.color, boxShadow: `0 0 10px ${col.color}` }} />
<span style={{ color: col.color, fontSize: '0.7rem', textTransform: 'uppercase', letterSpacing: '1px' }}>{col.label}</span>
<span style={{ marginLeft: 'auto', background: 'rgba(255,255,255,0.05)', padding: '2px 8px', borderRadius: '10px', fontSize: '0.65rem' }}>{tasks.filter(t => t.status === col.status).length}</span>
</div>
{tasks.filter(t => t.status === col.status).map(task => (
<div key={task.id} style={{ background: 'rgba(255,255,255,0.03)', borderRadius: '8px', padding: '10px', marginBottom: '8px' }}>
<p style={{ fontSize: '0.8rem', marginBottom: '5px' }}>{task.title}</p>
<span style={{ fontSize: '0.6rem', color: '#666' }}>@{task.assignee}</span>
</div>
))}
</div>
))}
</div>
);
}
function CronMonitor({ crons }: { crons: CronJob[] }) {
return (
<div style={{ background: 'rgba(20,20,30,0.6)', borderRadius: '12px', padding: '15px', border: '1px solid rgba(255,255,255,0.05)' }}>
<h2 style={{ fontSize: '0.9rem', marginBottom: '15px' }}> Cron Jobs ({crons.length})</h2>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: '10px' }}>
{crons.map((cron, i) => (
<div key={i} style={{ background: 'rgba(255,255,255,0.03)', borderRadius: '8px', padding: '12px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ fontSize: '0.75rem' }}>{cron.name}</span>
<span style={{ width: '6px', height: '6px', borderRadius: '50%', background: cron.status === 'ok' ? '#00ff88' : '#ff0050' }} />
</div>
))}
</div>
</div>
);
}
function ServerStatus({ server }: { server: ServerStatus | null }) {
if (!server) return <p style={{ color: '#666' }}>Loading...</p>;
return (
<div style={{ background: 'rgba(20,20,30,0.6)', borderRadius: '12px', padding: '15px', border: '1px solid rgba(255,255,255,0.05)' }}>
<h2 style={{ fontSize: '0.9rem', marginBottom: '15px' }}>🖥 Server Status</h2>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))', gap: '10px' }}>
{Object.entries(server).map(([key, value]) => (
<div key={key} style={{ background: 'rgba(255,255,255,0.03)', borderRadius: '8px', padding: '12px' }}>
<p style={{ color: '#666', fontSize: '0.65rem', textTransform: 'uppercase', marginBottom: '5px' }}>{key}</p>
<p style={{ fontSize: '0.85rem' }}>{value}</p>
</div>
))}
</div>
</div>
);
}
function BackupStatus({ backups }: { backups: Backup[] }) {
return (
<div style={{ background: 'rgba(20,20,30,0.6)', borderRadius: '12px', padding: '15px', border: '1px solid rgba(255,255,255,0.05)' }}>
<h2 style={{ fontSize: '0.9rem', marginBottom: '15px' }}>💾 Backup Status</h2>
{backups.map((backup, i) => (
<div key={i} style={{ background: 'rgba(255,255,255,0.03)', borderRadius: '8px', padding: '12px', marginBottom: '10px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<p style={{ fontSize: '0.85rem' }}>{backup.name}</p>
<p style={{ fontSize: '0.65rem', color: '#666' }}>{backup.lastRun}</p>
</div>
<span style={{ width: '8px', height: '8px', borderRadius: '50%', background: backup.status === 'ok' ? '#00ff88' : '#ff0050' }} />
</div>
))}
{backups.length === 0 && <p style={{ color: '#666', fontSize: '0.8rem' }}>No backups found</p>}
</div>
);
}
function AgentStatus({ agents }: { agents: Agent[] }) {
return (
<div style={{ background: 'rgba(20,20,30,0.6)', borderRadius: '12px', padding: '15px', border: '1px solid rgba(255,255,255,0.05)' }}>
<h2 style={{ fontSize: '0.9rem', marginBottom: '15px' }}>🤖 Agents</h2>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '10px' }}>
{agents.map((agent, i) => (
<div key={i} style={{ background: 'rgba(255,255,255,0.03)', borderRadius: '8px', padding: '15px', display: 'flex', alignItems: 'center', gap: '12px' }}>
<div style={{ width: '40px', height: '40px', borderRadius: '50%', background: 'linear-gradient(135deg, #7800ff 0%, #ff0050 100%)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '16px' }}>{agent.name[0]}</div>
<div>
<p style={{ fontSize: '0.85rem' }}>{agent.name}</p>
<p style={{ fontSize: '0.65rem', color: '#666' }}>{agent.role}</p>
<span style={{ fontSize: '0.6rem', color: agent.status === 'online' ? '#00ff88' : '#666' }}> {agent.status}</span>
</div>
</div>
))}
</div>
</div>
);
}
function WhatsAppStatus({ whatsapp }: { whatsapp: WhatsAppStatus | null }) {
if (!whatsapp) return <p style={{ color: '#666' }}>Loading...</p>;
return (
<div style={{ background: 'rgba(20,20,30,0.6)', borderRadius: '12px', padding: '15px', border: '1px solid rgba(255,255,255,0.05)' }}>
<h2 style={{ fontSize: '0.9rem', marginBottom: '15px' }}>💬 WhatsApp Chats</h2>
<div style={{ background: 'rgba(255,255,255,0.03)', borderRadius: '8px', padding: '15px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '10px' }}>
<span style={{ color: '#666', fontSize: '0.75rem' }}>Status</span>
<span style={{ color: whatsapp.status === 'ok' ? '#00ff88' : '#ff0050', fontSize: '0.75rem' }}>{whatsapp.status}</span>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '10px' }}>
<span style={{ color: '#666', fontSize: '0.75rem' }}>Chats</span>
<span style={{ fontSize: '0.75rem' }}>{whatsapp.chats}</span>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<span style={{ color: '#666', fontSize: '0.75rem' }}>Last Update</span>
<span style={{ fontSize: '0.75rem' }}>{whatsapp.lastUpdate}</span>
</div>
</div>
</div>
);
}
function MemoryVault({ memories }: { memories: Memory[] }) {
const [search, setSearch] = useState('');
const filtered = memories.filter(m => m.title.toLowerCase().includes(search.toLowerCase()));
return (
<div>
<input type="text" placeholder="Search memories..." value={search} onChange={e => setSearch(e.target.value)} style={{ width: '100%', padding: '10px', borderRadius: '8px', border: '1px solid rgba(255,255,255,0.1)', background: 'rgba(20,20,30,0.6)', color: '#e4e4e7', fontSize: '0.8rem', marginBottom: '15px', outline: 'none' }} />
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: '10px' }}>
{filtered.map((mem, i) => (
<div key={i} style={{ background: 'rgba(20,20,30,0.6)', borderRadius: '8px', padding: '12px' }}>
<p style={{ fontSize: '0.8rem', marginBottom: '5px' }}>{mem.title}</p>
<span style={{ fontSize: '0.6rem', color: '#444' }}>{mem.date}</span>
</div>
))}
</div>
</div>
);
}
// Force rebuild Thu Feb 19 11:59:30 AM UTC 2026