diff --git a/backend/db/postgres.go b/backend/db/postgres.go index 85ad234..f411107 100644 --- a/backend/db/postgres.go +++ b/backend/db/postgres.go @@ -492,7 +492,7 @@ func (d *Database) writeMetrics(tx *sql.Tx, agentID string, ts time.Time, data * } func (d *Database) GetAgents() ([]models.Agent, error) { - rows, err := d.db.Query("SELECT id, name, hostname, ip, opnsense_version, agent_version, platform, registered_at, last_heartbeat, customer_id, update_requested FROM agents ORDER BY name") + rows, err := d.db.Query("SELECT id, name, hostname, ip, opnsense_version, agent_version, platform, registered_at, last_heartbeat, customer_id, update_requested, last_api_key FROM agents ORDER BY name") if err != nil { return nil, err } @@ -504,7 +504,7 @@ func (d *Database) GetAgents() ([]models.Agent, error) { var lastHB sql.NullTime var custID sql.NullInt64 - if err := rows.Scan(&a.ID, &a.Name, &a.Hostname, &a.IP, &a.OPNsenseVersion, &a.AgentVersion, &a.Platform, &a.RegisteredAt, &lastHB, &custID, &a.UpdateRequested); err != nil { + if err := rows.Scan(&a.ID, &a.Name, &a.Hostname, &a.IP, &a.OPNsenseVersion, &a.AgentVersion, &a.Platform, &a.RegisteredAt, &lastHB, &custID, &a.UpdateRequested, &a.LastAPIKey); err != nil { return nil, err } if lastHB.Valid { diff --git a/frontend/src/components/ProxmoxPanel.jsx b/frontend/src/components/ProxmoxPanel.jsx index 502f15c..bd3a597 100644 --- a/frontend/src/components/ProxmoxPanel.jsx +++ b/frontend/src/components/ProxmoxPanel.jsx @@ -11,32 +11,51 @@ import { MonitorSmartphone, Terminal, Cable, ExternalLink, Plus, Unplug, Search, Shield, Play, FileCode, } from 'lucide-react' -const buildTabs = (hasPBS) => [ - { id: 'overview', label: 'Uebersicht' }, - { id: 'vms', label: 'Virtuelle Maschinen' }, - { id: 'containers', label: 'Container' }, - { id: 'storage', label: 'Storage' }, - { id: 'zfs', label: 'ZFS' }, - ...(hasPBS ? [{ id: 'pbs', label: 'Backup Server' }] : []), - { id: 'tunnel', label: 'Tunnel' }, - { id: 'services', label: 'Dienste' }, - { id: 'updates', label: 'Updates' }, - { id: 'tasks', label: 'Aufgaben' }, - { id: 'backups', label: 'Backups' }, - { id: 'agent', label: 'Agent' }, +const mainCategories = [ + { id: 'uebersicht', label: 'Uebersicht' }, + { id: 'virtualisierung', label: 'Virtualisierung' }, + { id: 'speicher', label: 'Speicher' }, + { id: 'system', label: 'System' }, ] +const buildSubTabs = (hasPBS) => ({ + virtualisierung: [ + { id: 'vms', label: 'VMs' }, + { id: 'containers', label: 'Container' }, + ], + speicher: [ + { id: 'storage', label: 'Storage' }, + { id: 'zfs', label: 'ZFS' }, + { id: 'backups', label: 'Backups' }, + ...(hasPBS ? [{ id: 'pbs', label: 'Backup Server' }] : []), + ], + system: [ + { id: 'services', label: 'Dienste' }, + { id: 'updates', label: 'Updates' }, + { id: 'tasks', label: 'Aufgaben' }, + { id: 'tunnel', label: 'Tunnel' }, + { id: 'agent', label: 'Agent' }, + ], +}) + export default function ProxmoxPanel({ agentId, customers, onClose, onReload }) { const [data, setData] = useState(null) - const [tab, setTab] = useState('overview') + const [mainTab, setMainTab] = useState('uebersicht') + const [subTab, setSubTab] = useState(null) const [loading, setLoading] = useState(true) useEffect(() => { setLoading(true) - setTab('overview') + setMainTab('uebersicht') + setSubTab(null) api.getAgent(agentId).then(setData).finally(() => setLoading(false)) }, [agentId]) + const handleMainTab = (id, subTabs) => { + setMainTab(id) + setSubTab(subTabs?.[id]?.[0]?.id ?? null) + } + useEffect(() => { if (!data) return const iv = setInterval(() => { @@ -52,12 +71,32 @@ export default function ProxmoxPanel({ agentId, customers, onClose, onReload }) const proxmox = sys?.proxmox const pbs = sys?.pbs const cust = agent.customer_id ? customers.find((c) => c.id === agent.customer_id) : null - const tabs = buildTabs(pbs?.available) + const subs = buildSubTabs(pbs?.available) + const currentSubs = mainTab !== 'uebersicht' ? (subs[mainTab] || []) : [] + const activeSubTab = currentSubs.find(s => s.id === subTab)?.id ?? currentSubs[0]?.id if (!proxmox?.available) { return
Keine Proxmox-Daten verfuegbar
} + const renderContent = () => { + if (!sys) return
Keine Systemdaten
+ if (mainTab === 'uebersicht') return + const t = activeSubTab + if (t === 'vms') return + if (t === 'containers') return + if (t === 'storage') return + if (t === 'zfs') return + if (t === 'backups') return + if (t === 'pbs') return + if (t === 'services') return + if (t === 'updates') return + if (t === 'tasks') return + if (t === 'tunnel') return + if (t === 'agent') return + return null + } + return ( {/* Header */} @@ -92,53 +131,49 @@ export default function ProxmoxPanel({ agentId, customers, onClose, onReload }) - {/* Tabs */} -
- {tabs.map((t) => ( + {/* Haupt-Tabs */} +
+ {mainCategories.map((cat) => ( ))}
+ {/* Sub-Tabs */} + {currentSubs.length > 0 && ( +
+ + {mainCategories.find(c => c.id === mainTab)?.label} + + {currentSubs.map((s) => ( + + ))} +
+ )} + {/* Content */}
- {!sys ? ( -
Keine Systemdaten
- ) : tab === 'overview' ? ( - - ) : tab === 'vms' ? ( - - ) : tab === 'containers' ? ( - - ) : tab === 'storage' ? ( - - ) : tab === 'zfs' ? ( - - ) : tab === 'tunnel' ? ( - - ) : tab === 'services' ? ( - - ) : tab === 'updates' ? ( - - ) : tab === 'tasks' ? ( - - ) : tab === 'pbs' ? ( - - ) : tab === 'backups' ? ( - - ) : tab === 'agent' ? ( - - ) : null} + {renderContent()}
)