import { useState, useEffect } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from './ui/card'; import { Button } from './ui/button'; import { Input } from './ui/input'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from './ui/dialog'; import { Activity, Square, PauseCircle, ArrowRight, Plus, Cpu, HardDrive, MemoryStick } from 'lucide-react'; import { apiFetch } from '@/lib/api'; import { toast } from 'sonner'; import { Label } from './ui/label'; interface Stats { active: number; exited: number; total: number; inactive: number; } interface SystemStats { cpu: { usage: string; cores: number; }; memory: { total: number; used: number; free: number; usagePercent: string; }; disk: { fs: string; mount: string; total: number; used: number; free: number; usagePercent: string; } | null; } function formatBytes(bytes: number): string { const gb = bytes / (1024 * 1024 * 1024); if (gb >= 1024) { return (gb / 1024).toFixed(1) + ' TB'; } return gb.toFixed(1) + ' GB'; } export default function HomeDashboard() { const [dockerRunInput, setDockerRunInput] = useState(''); const [isConverting, setIsConverting] = useState(false); const [convertedYaml, setConvertedYaml] = useState(''); const [createDialogOpen, setCreateDialogOpen] = useState(false); const [newStackName, setNewStackName] = useState(''); const [stats, setStats] = useState({ active: 0, exited: 0, total: 0, inactive: 0 }); const [systemStats, setSystemStats] = useState(null); // Fetch stats from backend useEffect(() => { const fetchStats = async () => { try { const res = await apiFetch('/stats'); const data = await res.json(); setStats(data); } catch (error) { console.error('Failed to fetch stats:', error); } }; fetchStats(); const interval = setInterval(fetchStats, 5000); return () => clearInterval(interval); }, []); // Fetch system stats from backend useEffect(() => { const fetchSystemStats = async () => { try { const res = await apiFetch('/system/stats'); const data = await res.json(); setSystemStats(data); } catch (error) { console.error('Failed to fetch system stats:', error); } }; fetchSystemStats(); const interval = setInterval(fetchSystemStats, 5000); return () => clearInterval(interval); }, []); const handleConvert = async () => { if (!dockerRunInput.trim()) return; setIsConverting(true); try { const response = await apiFetch('/convert', { method: 'POST', body: JSON.stringify({ dockerRun: dockerRunInput }), }); if (!response.ok) throw new Error('Conversion failed'); const data = await response.json(); setConvertedYaml(data.yaml); } catch (error) { console.error('Conversion error:', error); toast.error('Failed to convert docker run command'); } finally { setIsConverting(false); } }; const handleCreateStack = async () => { if (!newStackName.trim() || !convertedYaml) return; // Send stackName directly (no .yml extension - backend creates directory) const stackName = newStackName.trim(); try { // Create the stack const createResponse = await apiFetch('/stacks', { method: 'POST', body: JSON.stringify({ stackName }), }); if (!createResponse.ok) throw new Error('Failed to create stack'); // Save the converted YAML content const saveResponse = await apiFetch(`/stacks/${stackName}`, { method: 'PUT', body: JSON.stringify({ content: convertedYaml }), }); if (!saveResponse.ok) throw new Error('Failed to save stack content'); setCreateDialogOpen(false); setNewStackName(''); setConvertedYaml(''); setDockerRunInput(''); window.location.reload(); // Refresh to show new stack } catch (error) { console.error('Failed to create stack:', error); toast.error('Failed to create stack'); } }; const handleUseConvertedYaml = () => { setCreateDialogOpen(true); }; return (
{/* Container Stats Row */}
Active Containers
{stats.active}

Currently running

Exited Containers
{stats.exited}

Stopped or crashed

Inactive Stacks
{Math.max(0, stats.inactive)}

Not deployed

{/* Host System Stats Row */}
Host CPU
{systemStats ? `${systemStats.cpu.usage}%` : '...'}

{systemStats ? `${systemStats.cpu.cores} cores` : 'Loading...'}

Host RAM
{systemStats ? `${systemStats.memory.usagePercent}%` : '...'}

{systemStats ? `${formatBytes(systemStats.memory.used)} / ${formatBytes(systemStats.memory.total)}` : 'Loading...'}

Host Disk
{systemStats?.disk ? `${systemStats.disk.usagePercent}%` : '...'}

{systemStats?.disk ? `${formatBytes(systemStats.disk.used)} / ${formatBytes(systemStats.disk.total)}` : 'Loading...'}

{/* Docker Run Converter */} Convert Docker Run to Compose

Paste your docker run command below to convert it to a Docker Compose YAML file.