import React, { useEffect, useState, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { Plug, Box, CircleCheck, CircleX, Loader2, Info, Container, Clock, Cpu, HardDrive, Network, Image, FolderOpen, } from 'lucide-react'; import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { ApiRespPluginSystemStatus, ApiRespBoxStatus, BoxSessionInfo, } from '@/app/infra/entities/api'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip'; import { httpClient } from '@/app/infra/http/HttpClient'; type StatusState = 'ok' | 'disabled' | 'failed' | null; function StatusDot({ state }: { state: StatusState }) { if (state === null) return ; if (state === 'ok') return ; if (state === 'disabled') return ; return ; } interface SystemStatusCardProps { refreshKey?: number; } export default function SystemStatusCard({ refreshKey, }: SystemStatusCardProps) { const { t } = useTranslation(); const [pluginStatus, setPluginStatus] = useState(null); const [boxStatus, setBoxStatus] = useState(null); const [boxSessions, setBoxSessions] = useState([]); const [loading, setLoading] = useState(true); const [dialogOpen, setDialogOpen] = useState(false); const fetchStatus = useCallback(async () => { try { const [plugin, box] = await Promise.all([ httpClient.getPluginSystemStatus().catch(() => null), httpClient.getBoxStatus().catch(() => null), ]); const sessions = box?.hidden ? [] : await httpClient.getBoxSessions().catch(() => [] as BoxSessionInfo[]); setPluginStatus(plugin); setBoxStatus(box); setBoxSessions(Array.isArray(sessions) ? sessions : []); } finally { setLoading(false); } }, []); useEffect(() => { fetchStatus(); const interval = setInterval(fetchStatus, 30_000); return () => clearInterval(interval); }, [fetchStatus, refreshKey]); const pluginOk = pluginStatus ? pluginStatus.is_enable && pluginStatus.is_connected : null; const pluginState: StatusState = pluginStatus ? pluginStatus.is_enable && pluginStatus.is_connected ? 'ok' : !pluginStatus.is_enable ? 'disabled' : 'failed' : null; const boxOk = boxStatus ? boxStatus.available : null; const hideBoxRuntime = boxStatus?.hidden === true; // Box has three observable states: connected (ok), disabled by config // (enabled = false → distinct gray dot + "disabled" hint), and configured // but failed (red dot + connector_error). The dashboard must distinguish // them so operators can tell intentional-off from misconfigured. const boxState: StatusState = boxStatus ? boxStatus.available ? 'ok' : boxStatus.enabled === false ? 'disabled' : 'failed' : null; const handleOpenDialog = (e: React.MouseEvent) => { e.stopPropagation(); fetchStatus(); setDialogOpen(true); }; if (loading) { return ( {t('monitoring.systemStatus')}
); } return ( <> {t('monitoring.systemStatus')}
{t('monitoring.pluginRuntime')}
{!hideBoxRuntime && (
{t('monitoring.boxRuntime')}
)}
{t('monitoring.systemStatus')}
{/* Plugin Runtime */}
{t('monitoring.pluginRuntime')}
{pluginOk ? ( ) : ( )} {pluginOk ? t('monitoring.connected') : pluginStatus && !pluginStatus.is_enable ? t('monitoring.disabled') : t('monitoring.disconnected')}
{pluginStatus && !pluginStatus.is_enable && (

{t('monitoring.pluginDisabled')}

)} {pluginStatus && !pluginOk && pluginStatus.is_enable && pluginStatus.plugin_connector_error && pluginStatus.plugin_connector_error !== 'ok' && (

{pluginStatus.plugin_connector_error}

)}
{!hideBoxRuntime && ( <>
{/* Box Runtime */}
{t('monitoring.boxRuntime')}
{boxState === 'ok' ? ( ) : ( )} {boxState === 'ok' ? t('monitoring.connected') : boxState === 'disabled' ? t('monitoring.disabled') : t('monitoring.disconnected')}
{boxState === 'disabled' && (

{t('monitoring.boxDisabled')}

)} {boxState === 'failed' && boxStatus?.connector_error && (

{boxStatus.connector_error}

)} {boxStatus && (
{boxStatus.backend && (

{t('monitoring.boxBackend')}:{' '} {boxStatus.backend.name}

)}

{t('monitoring.boxProfile')}:{' '} {boxStatus.profile}

{boxOk && boxStatus.active_sessions !== undefined && (

{t('monitoring.boxSandboxes')}:{' '} {boxStatus.active_sessions}

)}
)} {/* Active Sandboxes */} {boxSessions.length > 0 && (
{boxSessions.map((session) => (
{session.session_id} {session.session_id}
{session.image} {session.image}
{session.backend_name}
{session.cpus} CPU / {session.memory_mb} MB
{session.network}
{session.host_path && (
{session.host_path} :{' '} {session.mount_path}{' '} ({session.host_path_mode}) {session.host_path} :{' '} {session.mount_path} ( {session.host_path_mode})
)}
{t('monitoring.boxSessionCreated')}:{' '} {new Date( session.created_at, ).toLocaleString()}
{t('monitoring.boxSessionLastUsed')}:{' '} {new Date( session.last_used_at, ).toLocaleString()}
))}
)}
)}
); }