'use client'; import type { ReactNode } from 'react'; import { Loader2, Play, RotateCw, Server, Square } from 'lucide-react'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, Badge, Button, Card, CardContent, CardHeader, CardTitle, } from '@spoon/ui'; export type BoxStatus = { running: boolean; image: string | null; startedAt: string | null; memoryLimitBytes: number | null; containerName: string; }; export type LifecycleAction = 'start' | 'stop' | 'restart'; const formatUptime = (startedAt: string | null): string => { if (!startedAt) return '—'; const started = new Date(startedAt).getTime(); if (Number.isNaN(started)) return '—'; const seconds = Math.max(0, Math.floor((Date.now() - started) / 1000)); const days = Math.floor(seconds / 86_400); const hours = Math.floor((seconds % 86_400) / 3_600); const minutes = Math.floor((seconds % 3_600) / 60); if (days > 0) return `${days}d ${hours}h`; if (hours > 0) return `${hours}h ${minutes}m`; if (minutes > 0) return `${minutes}m`; return `${seconds}s`; }; const formatMemory = (bytes: number | null): string => { if (bytes === null) return 'Unlimited'; const gib = bytes / 1024 ** 3; return `${gib.toFixed(gib < 10 ? 1 : 0)} GiB`; }; const Detail = ({ label, value }: { label: string; value: string }) => (

{label}

{value}

); // Stopping or restarting the box tears down the SAME per-user container that a // running agent thread job executes in, so both actions are destructive and get // a confirmation step. Start is safe and stays a plain button. const ConfirmLifecycleButton = ({ icon, label, busy, title, description, confirmLabel, onConfirm, }: { icon: ReactNode; label: string; busy: boolean; title: string; description: string; confirmLabel: string; onConfirm: () => void; }) => ( {title} {description} Cancel {confirmLabel} ); export const BoxStatusCard = ({ status, pendingAction, onAction, }: { status: BoxStatus | null | undefined; pendingAction: LifecycleAction | null; onAction: (action: LifecycleAction) => void; }) => { const loading = status === undefined; const running = Boolean(status?.running); const busy = pendingAction !== null; return ( My Machine {loading ? ( Checking… ) : running ? ( Running ) : ( Stopped )}
{running ? ( <> ) : ( ) } title='Stop this machine?' description='Stopping the machine shuts down the container it runs in. Any agent thread job currently running in this machine will be interrupted and lose its in-progress work.' confirmLabel='Stop machine' onConfirm={() => onAction('stop')} /> ) : ( ) } title='Restart this machine?' description='Restarting the machine recreates the container it runs in. Any agent thread job currently running in this machine will be interrupted and lose its in-progress work.' confirmLabel='Restart machine' onConfirm={() => onAction('restart')} /> ) : ( )}
); };