import { useEffect, useState, useRef } from 'react' import api from '../api/client' import { Upload, RefreshCw, CheckCircle, AlertTriangle, ArrowUpCircle, X, Monitor, Server, Cpu, Package, Copy, Check } from 'lucide-react' import { copyToClipboard } from '../utils/clipboard' const PLATFORMS = [ { id: 'freebsd', label: 'FreeBSD / OPNsense', icon: Server }, { id: 'linux', label: 'Linux', icon: Monitor }, { id: 'windows', label: 'Windows', icon: Cpu }, ] import { BACKEND_URL } from '../config' export default function Firmware() { const [firmwareData, setFirmwareData] = useState(null) const [installerData, setInstallerData] = useState(null) const [agents, setAgents] = useState([]) const [loading, setLoading] = useState(true) const [uploading, setUploading] = useState(false) const [installerUploading, setInstallerUploading] = useState(false) const [version, setVersion] = useState('') const [platform, setPlatform] = useState('freebsd') const [installerPlatform, setInstallerPlatform] = useState('freebsd') const [msg, setMsg] = useState('') const [msgType, setMsgType] = useState('info') const fileRef = useRef(null) const installerFileRef = useRef(null) const [copied, setCopied] = useState(false) const load = async () => { try { const [fw, ag, inst] = await Promise.all([ api.getFirmwareInfo().catch(() => null), api.getAgents().catch(() => []), api.getInstallerInfo().catch(() => null), ]) setFirmwareData(fw) setAgents(Array.isArray(ag) ? ag : []) setInstallerData(inst) } finally { setLoading(false) } } useEffect(() => { load() }, []) const showMsg = (text, type = 'info') => { setMsg(text) setMsgType(type) setTimeout(() => setMsg(''), 5000) } const getFwForPlatform = (p) => { if (!firmwareData?.platforms) return null return firmwareData.platforms.find(f => f.platform === p) } const handleUpload = async () => { const file = fileRef.current?.files?.[0] if (!file) return showMsg('Bitte Binary auswaehlen', 'error') if (!version.trim()) return showMsg('Bitte Version angeben', 'error') setUploading(true) try { const result = await api.uploadFirmware(version.trim(), platform, file) showMsg(`Firmware v${result.version} (${result.platform}) hochgeladen (${formatSize(result.size)})`, 'success') setVersion('') fileRef.current.value = '' load() } catch (err) { showMsg(`Upload fehlgeschlagen: ${err.message}`, 'error') } finally { setUploading(false) } } const requestUpdate = async (agentId, name) => { try { await api.requestAgentUpdate(agentId) showMsg(`Update fuer ${name} angefordert`, 'success') load() } catch (err) { showMsg(`Fehler: ${err.message}`, 'error') } } const cancelUpdate = async (agentId, name) => { try { await api.cancelAgentUpdate(agentId) showMsg(`Update-Anforderung fuer ${name} geloescht`, 'info') load() } catch (err) { showMsg(`Fehler: ${err.message}`, 'error') } } const requestAll = async () => { try { const result = await api.requestUpdateAll() showMsg(result.message || 'Update fuer alle angefordert', 'success') load() } catch (err) { showMsg(`Fehler: ${err.message}`, 'error') } } const formatSize = (bytes) => { if (!bytes) return '--' if (bytes > 1048576) return `${(bytes / 1048576).toFixed(1)} MB` return `${(bytes / 1024).toFixed(0)} KB` } if (loading) return
Laden...
const getFwForAgent = (agent) => { const p = agent.platform || 'freebsd' return getFwForPlatform(p) } const needsUpdate = (agent) => { const fw = getFwForAgent(agent) if (!fw) return false return agent.agent_version !== fw.version } const hasAnyFirmware = PLATFORMS.some(p => getFwForPlatform(p.id)) return (

Agent-Firmware

{/* Status Message */} {msg && (
{msgType === 'success' ? : msgType === 'error' ? : null} {msg}
)} {/* Platform Firmware Overview */}

Verfuegbare Firmware

{PLATFORMS.map(p => { const fw = getFwForPlatform(p.id) const Icon = p.icon return (
{p.label}
{fw ? (
v{fw.version}
{formatSize(fw.size)}
{fw.hash?.substring(0, 16)}...
) : (
Nicht hochgeladen
)}
) })}
{/* Upload */}

Neue Firmware hochladen

setVersion(e.target.value)} className="bg-gray-900 border border-gray-700 rounded px-3 py-2 text-sm text-white placeholder-gray-500 focus:border-orange-500 focus:outline-none w-40" />
{/* Installer Packages */}

Installer-Pakete

ZIP-Pakete mit install.sh und Plugin-Dateien. Werden auf neuen Geraeten per fetch heruntergeladen und ausgefuehrt.

{/* Existing installers */} {installerData?.installers?.length > 0 && (
{installerData.installers.map(inst => (
{inst.platform === 'linux' ? 'Linux' : 'OPNsense / FreeBSD'}
{inst.filename} — {formatSize(inst.size)} — {new Date(inst.uploaded_at).toLocaleString('de-DE')}
{inst.sha256?.substring(0, 32)}...
))}
)} {/* Install command */} {installerData?.installers?.some(i => i.platform === 'freebsd') && (
Installationsbefehl (OPNsense):
{`fetch --no-verify-peer --no-verify-hostname -o /tmp/installer.zip "${BACKEND_URL}/api/v1/installer/download?platform=freebsd&api_key=YOUR_API_KEY" && cd /tmp && unzip -o installer.zip && sh /tmp/install.sh`}
)} {/* Upload */}
{/* Agent List */}

Agents

{hasAnyFirmware && ( )}
{agents.map((agent) => { const outdated = needsUpdate(agent) const pending = agent.update_requested const agentPlatform = agent.platform || 'freebsd' const fw = getFwForAgent(agent) const platformLabel = agentPlatform === 'linux' ? 'Linux' : 'FreeBSD' const platformColor = agentPlatform === 'linux' ? 'bg-blue-900/50 text-blue-400' : 'bg-orange-900/50 text-orange-400' return (
{agent.name} {platformLabel}
Version: {agent.agent_version || '--'} {fw && (aktuell: v{fw.version})} {!fw && (keine Firmware fuer {platformLabel})} {pending && ( Update ausstehend )} {!outdated && fw && agent.agent_version && ( Aktuell )}
{pending ? ( ) : outdated ? ( ) : null}
) })}
) }