import React, { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { getRequest } from '@/common/utils/RequestUtil.js'; import { useToast } from '@/common/contexts/ToastContext.jsx'; import Card, { CardHeader, CardBody } from '@/common/components/Card'; import Grid from '@/common/components/Grid'; import LoadingSpinner from '@/common/components/LoadingSpinner'; import EmptyState from '@/common/components/EmptyState'; import PageHeader from '@/common/components/PageHeader'; import DetailItem, { DetailList } from '@/common/components/DetailItem'; import Badge from '@/common/components/Badge'; import Button from '@/common/components/Button'; import { ArrowLeft, Camera, HardDrive, Folder, Calendar, Hash, Database, Devices } from '@phosphor-icons/react'; import './styles.sass'; export const MachineDetails = () => { const { id } = useParams(); const navigate = useNavigate(); const toast = useToast(); const [machine, setMachine] = useState(null); const [snapshots, setSnapshots] = useState([]); const [loading, setLoading] = useState(true); const [selectedSnapshot, setSelectedSnapshot] = useState(null); useEffect(() => { if (id) { fetchMachineData(); } }, [id]); const fetchMachineData = async () => { try { setLoading(true); // Fetch machine info and snapshots in parallel const [machineResponse, snapshotsResponse] = await Promise.all([ getRequest(`machines/${id}`), getRequest(`machines/${id}/snapshots`) ]); setMachine(machineResponse); setSnapshots(snapshotsResponse); } catch (error) { console.error('Failed to fetch machine data:', error); toast.error('Failed to load machine details'); } finally { setLoading(false); } }; const formatBytes = (bytes) => { if (!bytes) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`; }; const formatDate = (dateString) => { if (!dateString || dateString === 'Unknown') return 'Unknown'; try { return new Date(dateString).toLocaleString(); } catch { return dateString; } }; const getFsTypeColor = (fsType) => { switch (fsType?.toLowerCase()) { case 'ext': return 'success'; case 'ntfs': return 'info'; case 'fat32': return 'warning'; default: return 'secondary'; } }; if (loading) { return (
navigate('/machines')}> Back to Machines } />
); } if (!machine) { return (
navigate('/machines')}> Back to Machines } /> } title="Machine Not Found" subtitle="This machine may have been deleted or you don't have access to it." />
); } return (
navigate('/machines')}> Back to Machines } /> {/* Machine Information */}

Machine Information

Active } />
{/* Snapshots */}

Snapshots ({snapshots.length})

{snapshots.length === 0 ? ( } title="No Snapshots" subtitle="This machine hasn't created any snapshots yet." /> ) : ( {snapshots.map((snapshot) => (

Snapshot #{snapshot.id}

{snapshot.disks.length} disk{snapshot.disks.length !== 1 ? 's' : ''}
{formatDate(snapshot.created_at)}
} /> {snapshot.snapshot_hash.substring(0, 16)}... } /> {/* Disks */}
Disks
{snapshot.disks.map((disk, diskIndex) => ( {/* Partitions */} {disk.partitions.length > 0 && (
Partitions
{disk.partitions.map((partition, partIndex) => ( {partition.fs_type.toUpperCase()} } /> ))}
)}
))}
))} )} ); }; export default MachineDetails;