import { useState, useEffect } from 'react'; import { Cpu, Server, Play, Pause, XCircle, RefreshCw, AlertCircle, Clock, CheckCircle, Loader, ChevronDown, ChevronUp, } from 'lucide-react'; import { useComputeStore, formatPrice } from '../../store/compute'; export default function ComputeDashboard() { const { providers, jobs, isLoading, isSubmitting, error, clearError, fetchProviders, fetchJobs, submitJob, cancelJob, } = useComputeStore(); const [activeTab, setActiveTab] = useState<'providers' | 'jobs'>('providers'); const [showSubmitForm, setShowSubmitForm] = useState(false); const [selectedProvider, setSelectedProvider] = useState(''); const [dockerImage, setDockerImage] = useState(''); const [command, setCommand] = useState(''); const [inputCid, setInputCid] = useState(''); const [cpuCores, setCpuCores] = useState(4); const [memoryGb, setMemoryGb] = useState(8); const [maxHours, setMaxHours] = useState(1); const [gpuType, setGpuType] = useState(''); const [expandedJob, setExpandedJob] = useState(null); useEffect(() => { fetchProviders(); fetchJobs(); }, [fetchProviders, fetchJobs]); const handleSubmitJob = async () => { if (!selectedProvider || !dockerImage || !command) return; try { await submitJob({ provider: selectedProvider, inputCid, dockerImage, command: command.split(' '), gpuType: gpuType || undefined, cpuCores, memoryGb, maxHours, }); setShowSubmitForm(false); setSelectedProvider(''); setDockerImage(''); setCommand(''); setInputCid(''); fetchJobs(); } catch { // Error handled by store } }; const handleCancelJob = async (jobId: string) => { await cancelJob(jobId); fetchJobs(); }; const getStatusIcon = (status: string) => { switch (status) { case 'pending': return ; case 'running': return ; case 'completed': return ; case 'failed': return ; case 'cancelled': return ; default: return ; } }; const getStatusColor = (status: string) => { switch (status) { case 'pending': return 'text-yellow-400'; case 'running': return 'text-blue-400'; case 'completed': return 'text-green-400'; case 'failed': return 'text-red-400'; case 'cancelled': return 'text-gray-400'; default: return 'text-gray-400'; } }; // Get unique GPU types from all providers const availableGpuTypes = [...new Set(providers.flatMap((p) => p.gpuTypes))]; return (
{/* Header */}

Compute Marketplace

Decentralized GPU and CPU compute resources

{/* Error Alert */} {error && (

{error}

)} {/* Submit Job Form Modal */} {showSubmitForm && (

Submit Compute Job

setDockerImage(e.target.value)} placeholder="pytorch/pytorch:latest" className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white placeholder-gray-500 focus:outline-none focus:border-synor-500" />
setCommand(e.target.value)} placeholder="python train.py --epochs 10" className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white placeholder-gray-500 focus:outline-none focus:border-synor-500" />
setInputCid(e.target.value)} placeholder="Qm..." className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white font-mono placeholder-gray-500 focus:outline-none focus:border-synor-500" />
setCpuCores(Number(e.target.value))} min={1} max={64} className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white focus:outline-none focus:border-synor-500" />
setMemoryGb(Number(e.target.value))} min={1} max={512} className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white focus:outline-none focus:border-synor-500" />
setMaxHours(Number(e.target.value))} min={1} max={168} className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white focus:outline-none focus:border-synor-500" />
)} {/* Tabs */}
{/* Providers Tab */} {activeTab === 'providers' && (
{providers.map((provider) => (

{provider.name}

{provider.address.slice(0, 12)}...

{provider.isAvailable ? 'Available' : 'Busy'}
{provider.gpuTypes.length > 0 && (

GPUs

{provider.gpuTypes.join(', ')}

)}

CPU Cores

{provider.cpuCores}

Memory

{provider.memoryGb} GB

Price

{formatPrice(provider.pricePerHour)}/hr

Reputation

{provider.reputation}%

{provider.isAvailable && ( )}
))} {providers.length === 0 && (
No compute providers available
)}
)} {/* Jobs Tab */} {activeTab === 'jobs' && (
{jobs.map((job) => (
setExpandedJob(expandedJob === job.jobId ? null : job.jobId)} >
{getStatusIcon(job.status)}

Job {job.jobId.slice(0, 8)}

{job.gpuType || `${job.cpuCores} cores`} • {job.provider.slice(0, 8)}...

{job.status.charAt(0).toUpperCase() + job.status.slice(1)} {expandedJob === job.jobId ? ( ) : ( )}
{expandedJob === job.jobId && (
{job.startedAt && (

Started

{new Date(job.startedAt).toLocaleString()}

)} {job.endedAt && (

Ended

{new Date(job.endedAt).toLocaleString()}

)}

Cost

{formatPrice(job.totalCost)}

Memory

{job.memoryGb} GB

{job.resultCid && (

Result CID

{job.resultCid}
)} {(job.status === 'pending' || job.status === 'running') && ( )}
)}
))} {jobs.length === 0 && (
No compute jobs. Submit a job to get started.
)}
)}
); }