diff --git a/frontend-modern/src/App.tsx b/frontend-modern/src/App.tsx index ebb7dd2..2689971 100644 --- a/frontend-modern/src/App.tsx +++ b/frontend-modern/src/App.tsx @@ -99,8 +99,96 @@ function DockerRoute() { return
Loading...
; } const { state, activeAlerts } = wsContext; - const hosts = createMemo(() => state.dockerHosts ?? []); - return ; + + // Use unified resources if available, fall back to legacy state.dockerHosts + const hosts = createMemo(() => { + const dockerHostResources = state.resources?.filter(r => r.type === 'docker-host') ?? []; + const dockerContainerResources = state.resources?.filter(r => r.type === 'docker-container') ?? []; + + // If we have unified resources, convert and reconstruct hierarchy + if (dockerHostResources.length > 0) { + return dockerHostResources.map(h => { + const platformData = h.platformData as Record | undefined; + + // Find containers belonging to this host + const hostContainers = dockerContainerResources + .filter(c => c.parentId === h.id) + .map(c => { + const cPlatform = c.platformData as Record | undefined; + return { + id: c.id, + name: c.name, + image: cPlatform?.image as string ?? '', + state: c.status === 'running' ? 'running' : 'exited', + status: c.status, + health: cPlatform?.health as string | undefined, + cpuPercent: c.cpu?.current ?? 0, + memoryUsageBytes: c.memory?.used ?? 0, + memoryLimitBytes: c.memory?.total ?? 0, + memoryPercent: c.memory?.current ?? 0, + uptimeSeconds: c.uptime ?? 0, + restartCount: cPlatform?.restartCount as number ?? 0, + exitCode: cPlatform?.exitCode as number ?? 0, + createdAt: cPlatform?.createdAt as number ?? 0, + startedAt: cPlatform?.startedAt as number | undefined, + finishedAt: cPlatform?.finishedAt as number | undefined, + ports: cPlatform?.ports, + labels: cPlatform?.labels as Record | undefined, + networks: cPlatform?.networks, + }; + }); + + return { + id: h.id, + agentId: platformData?.agentId as string ?? h.id, + hostname: h.identity?.hostname ?? h.name, + displayName: h.displayName || h.name, + customDisplayName: platformData?.customDisplayName as string | undefined, + machineId: h.identity?.machineId, + os: platformData?.os as string | undefined, + kernelVersion: platformData?.kernelVersion as string | undefined, + architecture: platformData?.architecture as string | undefined, + runtime: platformData?.runtime as string ?? 'docker', + runtimeVersion: platformData?.runtimeVersion as string | undefined, + dockerVersion: platformData?.dockerVersion as string | undefined, + cpus: platformData?.cpus as number ?? 0, + totalMemoryBytes: h.memory?.total ?? 0, + uptimeSeconds: h.uptime ?? 0, + cpuUsagePercent: h.cpu?.current, + loadAverage: platformData?.loadAverage as number[] | undefined, + memory: h.memory ? { + total: h.memory.total ?? 0, + used: h.memory.used ?? 0, + free: h.memory.free ?? 0, + usage: h.memory.current, + } : undefined, + disks: platformData?.disks, + networkInterfaces: platformData?.networkInterfaces, + status: h.status === 'online' || h.status === 'running' ? 'online' : h.status, + lastSeen: h.lastSeen, + intervalSeconds: platformData?.intervalSeconds as number ?? 30, + agentVersion: platformData?.agentVersion as string | undefined, + containers: hostContainers, + services: platformData?.services, + tasks: platformData?.tasks, + swarm: platformData?.swarm, + tokenId: platformData?.tokenId as string | undefined, + tokenName: platformData?.tokenName as string | undefined, + tokenHint: platformData?.tokenHint as string | undefined, + tokenLastUsedAt: platformData?.tokenLastUsedAt as number | undefined, + hidden: platformData?.hidden as boolean | undefined, + pendingUninstall: platformData?.pendingUninstall as boolean | undefined, + command: platformData?.command, + isLegacy: platformData?.isLegacy as boolean | undefined, + }; + }); + } + + // Fall back to legacy data + return state.dockerHosts ?? []; + }); + + return ; } function HostsRoute() { @@ -782,9 +870,141 @@ function App() { // Pass through the store directly (only when initialized) const enhancedStore = () => wsStore(); - const DashboardView = () => ( - - ); + // Dashboard view using unified resources with fallback + const DashboardView = () => { + // Use unified resources if available, fall back to legacy data + const vms = createMemo(() => { + const vmResources = state().resources?.filter(r => r.type === 'vm') ?? []; + if (vmResources.length > 0) { + return vmResources.map(r => { + const platformData = r.platformData as Record | undefined; + return { + id: r.id, + vmid: platformData?.vmid as number ?? 0, + name: r.name, + node: r.parentId ?? '', + instance: r.platformId, + status: r.status === 'running' ? 'running' : 'stopped', + type: 'qemu', + cpu: r.cpu?.current ?? 0, + cpus: platformData?.cpus as number ?? 1, + memory: r.memory ? { + total: r.memory.total ?? 0, + used: r.memory.used ?? 0, + free: r.memory.free ?? 0, + usage: r.memory.current, + } : { total: 0, used: 0, free: 0, usage: 0 }, + disk: r.disk ? { + total: r.disk.total ?? 0, + used: r.disk.used ?? 0, + free: r.disk.free ?? 0, + usage: r.disk.current, + } : { total: 0, used: 0, free: 0, usage: 0 }, + networkIn: r.network?.rxBytes ?? 0, + networkOut: r.network?.txBytes ?? 0, + diskRead: 0, + diskWrite: 0, + uptime: r.uptime ?? 0, + template: platformData?.template as boolean ?? false, + lastBackup: platformData?.lastBackup as number ?? 0, + tags: r.tags ?? [], + lock: platformData?.lock as string ?? '', + lastSeen: new Date(r.lastSeen).toISOString(), + }; + }); + } + return state().vms ?? []; + }); + + const containers = createMemo(() => { + const containerResources = state().resources?.filter(r => r.type === 'container') ?? []; + if (containerResources.length > 0) { + return containerResources.map(r => { + const platformData = r.platformData as Record | undefined; + return { + id: r.id, + vmid: platformData?.vmid as number ?? 0, + name: r.name, + node: r.parentId ?? '', + instance: r.platformId, + status: r.status === 'running' ? 'running' : 'stopped', + type: 'lxc', + cpu: r.cpu?.current ?? 0, + cpus: platformData?.cpus as number ?? 1, + memory: r.memory ? { + total: r.memory.total ?? 0, + used: r.memory.used ?? 0, + free: r.memory.free ?? 0, + usage: r.memory.current, + } : { total: 0, used: 0, free: 0, usage: 0 }, + disk: r.disk ? { + total: r.disk.total ?? 0, + used: r.disk.used ?? 0, + free: r.disk.free ?? 0, + usage: r.disk.current, + } : { total: 0, used: 0, free: 0, usage: 0 }, + networkIn: r.network?.rxBytes ?? 0, + networkOut: r.network?.txBytes ?? 0, + diskRead: 0, + diskWrite: 0, + uptime: r.uptime ?? 0, + template: platformData?.template as boolean ?? false, + lastBackup: platformData?.lastBackup as number ?? 0, + tags: r.tags ?? [], + lock: platformData?.lock as string ?? '', + lastSeen: new Date(r.lastSeen).toISOString(), + }; + }); + } + return state().containers ?? []; + }); + + const nodes = createMemo(() => { + const nodeResources = state().resources?.filter(r => r.type === 'node') ?? []; + if (nodeResources.length > 0) { + return nodeResources.map(r => { + const platformData = r.platformData as Record | undefined; + return { + id: r.id, + name: r.name, + displayName: r.displayName, + instance: r.platformId, + host: platformData?.host as string ?? '', + status: r.status, + type: 'node', + cpu: r.cpu?.current ?? 0, + memory: r.memory ? { + total: r.memory.total ?? 0, + used: r.memory.used ?? 0, + free: r.memory.free ?? 0, + usage: r.memory.current, + } : { total: 0, used: 0, free: 0, usage: 0 }, + disk: r.disk ? { + total: r.disk.total ?? 0, + used: r.disk.used ?? 0, + free: r.disk.free ?? 0, + usage: r.disk.current, + } : { total: 0, used: 0, free: 0, usage: 0 }, + uptime: r.uptime ?? 0, + loadAverage: platformData?.loadAverage as number[] ?? [], + kernelVersion: platformData?.kernelVersion as string ?? '', + pveVersion: platformData?.pveVersion as string ?? '', + cpuInfo: platformData?.cpuInfo ?? { model: '', cores: 0, sockets: 0, mhz: '' }, + temperature: platformData?.temperature, + lastSeen: new Date(r.lastSeen).toISOString(), + connectionHealth: platformData?.connectionHealth as string ?? 'unknown', + isClusterMember: platformData?.isClusterMember as boolean | undefined, + clusterName: platformData?.clusterName as string | undefined, + }; + }); + } + return state().nodes ?? []; + }); + + return ( + + ); + }; const SettingsRoute = () => (