import { useEffect, useState } from 'react'; import { HardDrive, Activity, Wifi, Signal, Clock, RefreshCw, FolderOpen, Map, Loader2 } from 'lucide-react'; import DeviceDetailOverlay from './DeviceDetailOverlay'; import MediaSet from './MediaSet'; import { ImageWithFallback } from './figma/ImageWithFallback'; import { Dialog, DialogContent, DialogTitle, DialogDescription } from './ui/dialog'; import DirectoryListing from './DirectoryListing'; import { listDirectory, normalizePath, splitPath, type EntryInfo } from '../webdav'; interface StatusPageProps { config: any; setConfig: (config: any) => void; } export default function StatusPage({ config, setConfig }: StatusPageProps) { // Mock memory stats const memory = { heap: { total: 4096, free: 1024 }, // in KB psram: { total: 8192, free: 4096 }, }; // Overlay state for active device const [showDeviceOverlay, setShowDeviceOverlay] = useState(false); // Find the first enabled device as the active device const findActiveDevice = () => { if (config.iec?.devices?.drive) { for (const [num, device] of Object.entries(config.iec.devices.drive)) { if (num !== 'vdrive' && num !== 'rom' && (device as any).enabled) { return { number: num, ...device as any, type: 'drive' }; } } } return null; }; const activeDevice = findActiveDevice(); const mediaSetFiles: string[] | null = (() => { if (!activeDevice?.url) return null; if (Array.isArray(activeDevice.media_set) && activeDevice.media_set.length > 0) return activeDevice.media_set as string[]; const match = (activeDevice.url as string).match(/^(.+?)(\d+)(\.[^.]+)$/); if (!match) return null; const [, prefix, , ext] = match; return Array.from({ length: 10 }, (_, i) => `${prefix}${i + 1}${ext}`); })(); const switchActiveMedia = (file: string) => { const newConfig = JSON.parse(JSON.stringify(config)); if (newConfig.iec?.devices?.drive?.[activeDevice!.number]) { newConfig.iec.devices.drive[activeDevice!.number].url = file; setConfig(newConfig); } }; // Mock activity log - in a real app this would come from device monitoring const activityLog = [ { time: '14:32:15', event: 'File opened: game.d64', type: 'info' }, { time: '14:32:14', event: 'Device mounted', type: 'success' }, { time: '14:32:10', event: 'Read sector 18/0', type: 'info' }, { time: '14:32:08', event: 'Directory listing requested', type: 'info' }, { time: '14:32:05', event: 'Connection established', type: 'success' }, { time: '14:31:58', event: 'Device reset', type: 'warning' } ]; // Mock loading/progress state const [loading, setLoading] = useState(false); const [progress, setProgress] = useState(0.0); // 0.0 to 1.0 // Mock file info (replace with real data if available) const lastFile = 'MEATLOAF MANIACS.PRG'; const fileSize = '1.44 MB'; // Replace with real size if available const transferSpeed = '250 KB/s'; // Replace with real speed if available // Mock image association (replace with real logic if available) const imageUrl = lastFile.endsWith('.d64') ? '/assets/floppy.png' : undefined; // Dialog/modal state for reset actions const [showResetModal, setShowResetModal] = useState(null); const [resetStatus, setResetStatus] = useState('idle'); // 'idle' | 'in-progress' | 'done' // Overlay state for directory/disk map const [showDirectory, setShowDirectory] = useState(false); const [showDiskMap, setShowDiskMap] = useState(false); // Real directory contents for the active device's mounted file. // Pulled from the WebDAV server (parent folder of the mounted image). const [dirEntries, setDirEntries] = useState([]); const [dirLoading, setDirLoading] = useState(false); const [dirError, setDirError] = useState(null); const directoryPath: string | null = (() => { const url = activeDevice?.url; if (!url) return null; return splitPath(normalizePath(url)).parent; })(); useEffect(() => { if (!showDirectory) return; if (!directoryPath) { setDirEntries([]); setDirError(null); return; } let cancelled = false; setDirLoading(true); setDirError(null); listDirectory(directoryPath) .then((items) => { if (cancelled) return; setDirEntries(items); }) .catch((e: any) => { if (cancelled) return; setDirError((e && e.message) || 'Failed to load directory'); setDirEntries([]); }) .finally(() => { if (cancelled) return; setDirLoading(false); }); return () => { cancelled = true; }; }, [showDirectory, directoryPath]); return (
{activeDevice && ( <>

Active Device

{mediaSetFiles && (
)} {/* Directory and Disk Map buttons at bottom */} {/* New device info cards */}
Last File
{lastFile}
Size
{fileSize}
Transfer Speed
{transferSpeed}
{/* Progress bar (shows when loading) */} {loading && (
)} {/* Image placeholder if associated */} {imageUrl && (
)}
{showDeviceOverlay && ( setShowDeviceOverlay(false)} onNavigate={() => {}} hasPrev={false} hasNext={false} /> )} {/* Directory Overlay */} {showDirectory && ( <>
setShowDirectory(false)} />
e.stopPropagation()}>

Directory

Device #{activeDevice.number} • {activeDevice.url ? activeDevice.url.split('/').pop() : 'No file mounted'}
{!activeDevice?.url && (
No file mounted on this device.
)} {activeDevice?.url && dirLoading && (
Loading directory from WebDAV…
)} {activeDevice?.url && !dirLoading && dirError && (
Failed to load directory
{dirError}
)} {activeDevice?.url && !dirLoading && !dirError && ( ({ name: e.name, type: e.type === 'folder' ? 'DIR' : (e.name.split('.').pop() || 'FILE').toUpperCase(), blocks: e.type === 'file' ? Math.max(1, Math.ceil(e.size / 254)) : 0, }))} footerNote={`${dirEntries.length} ENTRIES · ${directoryPath ?? ''}`} /> )}
)} {/* Disk Map Overlay */} {showDiskMap && ( <>
setShowDiskMap(false)} />
e.stopPropagation()}>

Disk Map

Disk map visualization goes here.
)} {/* Reset Activity Modal */} !open && setShowResetModal(null)}> {showResetModal === 'meatloaf' ? 'Reset Meatloaf' : 'Reset Host'} {resetStatus === 'idle' && ( <> Are you sure you want to reset {showResetModal === 'meatloaf' ? 'the Meatloaf device' : 'the Host'}?
)} {resetStatus === 'in-progress' && (
Resetting...
)} {resetStatus === 'done' && (
Reset complete!
)}
)} {!activeDevice && (
No active device
Enable a device to see activity
)}

Activity Log

{activityLog.map((entry, index) => (
{entry.time}
{entry.event}
))}

System Status

{/* System Status Action Buttons at bottom */}
Memory Utilization
{/* Heap Graph */}
Heap {memory.heap.free} KB free / {memory.heap.total} KB
{/* PSRAM Graph */}
PSRAM {memory.psram.free} KB free / {memory.psram.total} KB
WiFi
Connected
IP Address
192.168.1.100
MAC Address
AA:BB:CC:DD:EE:FF
Uptime
3h 24m
); }