diff --git a/frontend-modern/src/App.tsx b/frontend-modern/src/App.tsx index 3a95d3d5e..9bfe20263 100644 --- a/frontend-modern/src/App.tsx +++ b/frontend-modern/src/App.tsx @@ -71,8 +71,8 @@ function DockerRoute() { return
Loading...
; } const { state, activeAlerts } = wsContext; - const hosts = state().dockerHosts || []; - return ; + const hosts = createMemo(() => state.dockerHosts ?? []); + return ; } function App() { diff --git a/frontend-modern/src/components/Docker/DockerHosts.tsx b/frontend-modern/src/components/Docker/DockerHosts.tsx index e1c1e51ba..83ea2940b 100644 --- a/frontend-modern/src/components/Docker/DockerHosts.tsx +++ b/frontend-modern/src/components/Docker/DockerHosts.tsx @@ -11,6 +11,7 @@ import { DockerFilter } from './DockerFilter'; import { getAlertStyles } from '@/utils/alerts'; // import type { DockerHostSummary } from './DockerHostSummaryTable'; import { renderDockerStatusBadge } from './DockerStatusBadge'; +import { useWebSocket } from '@/App'; interface DockerHostsProps { hosts: DockerHost[]; @@ -362,12 +363,20 @@ const DockerContainerRow: Component<{ - + ); }; export const DockerHosts: Component = (props) => { + const { initialDataReceived, reconnecting, connected } = useWebSocket(); + const isLoading = createMemo(() => { + if (typeof initialDataReceived === 'function') { + const hostCount = Array.isArray(props.hosts) ? props.hosts.length : 0; + return !initialDataReceived() && hostCount === 0; + } + return false; + }); const sortedHosts = createMemo(() => { const hosts = props.hosts || []; return [...hosts].sort((a, b) => a.displayName.localeCompare(b.displayName)); @@ -545,249 +554,287 @@ export const DockerHosts: Component = (props) => { return (
- - {/* Filters */} - setSelectedHostId(null)} - onReset={() => setSelectedHostId(null)} - /> + + + + + + + } + title={reconnecting() ? 'Reconnecting to Docker agents...' : 'Loading Docker data...'} + description={ + reconnecting() + ? 'Re-establishing metrics from the monitoring service.' + : connected() + ? 'Waiting for the first Docker update.' + : 'Connecting to the monitoring service.' + } + /> + + - {/* Master-Detail Layout */} -
- {/* Left: Host List */} - -
-

Docker Hosts

-

{sortedHosts().length} {sortedHosts().length === 1 ? 'host' : 'hosts'}

-
-
- - {(host) => { - const isSelected = () => selectedHostId() === host.id; - const containerCount = (host.containers || []).length; - const runningCount = (host.containers || []).filter(c => c.state?.toLowerCase() === 'running').length; + + + {/* Filters */} + setSelectedHostId(null)} + onReset={() => setSelectedHostId(null)} + /> - return ( -
-
- {runningCount}/{containerCount} running - - {formatRelativeTime(host.lastSeen!)} - -
- - ); - }} - -
- +
+ {runningCount}/{containerCount} running + + {formatRelativeTime(host.lastSeen!)} + +
+ + ); + }} + +
+ - {/* Right: Container List */} -
- - - - } - > - - - - - - - - - - - - - - - - - - - - - - {(group) => ( - <> - {/* Host Section Header */} - - + + {/* Host Containers */} + + {(entry) => } + + + )} + + +
- Container - - Status - - CPU - - Memory - - Restarts -
-
-
-

{group.host.displayName}

- - ({group.host.hostname}) - - {renderDockerStatusBadge(group.host.status)} - - {group.containers.length} {group.containers.length === 1 ? 'container' : 'containers'} - + {/* Right: Container List */} +
+ + + + } + > + + + + + + + + + + + + + + + + + + + + + + {(group) => ( + <> + {/* Host Section Header */} + + - - {/* Host Containers */} - - {(entry) => } - - - )} - - -
+ Container + + Status + + CPU + + Memory + + Restarts +
+
+
+

{group.host.displayName}

+ + ({group.host.hostname}) + + {renderDockerStatusBadge(group.host.status)} + + {group.containers.length} {group.containers.length === 1 ? 'container' : 'containers'} + +
+
+ + Updated {formatRelativeTime(group.host.lastSeen!)} + + + Agent {group.host.agentVersion} + +
-
- - Updated {formatRelativeTime(group.host.lastSeen!)} - - - Agent {group.host.agentVersion} - -
- -
-
-
-
- } - > - {(host) => ( - 0} - fallback={ - - +
+
- } - > - - {/* Host Info Header */} -
-
-
-

{host().displayName}

- - ({host().hostname}) - - {renderDockerStatusBadge(host().status)} - - {selectedHostContainers().length} {selectedHostContainers().length === 1 ? 'container' : 'containers'} - -
-
- - Updated {formatRelativeTime(host().lastSeen!)} - - - Agent {host().agentVersion} - + + } + > + {(host) => ( + 0} + fallback={ + + + + } + > + + {/* Host Info Header */} +
+
+
+

{host().displayName}

+ + ({host().hostname}) + + {renderDockerStatusBadge(host().status)} + + {selectedHostContainers().length} {selectedHostContainers().length === 1 ? 'container' : 'containers'} + +
+
+ + Updated {formatRelativeTime(host().lastSeen!)} + + + Agent {host().agentVersion} + +
-
- {/* Containers Table */} - - - - - - - - - - - - - - - - - - - - - {(entry) => ( - - )} - - -
- Container - - Status - - CPU - - Memory - - Restarts -
-
- - - )} - + {/* Containers Table */} + + + + + + + + + + + + + + + + + + + + + {(entry) => ( + + )} + + +
+ Container + + Status + + CPU + + Memory + + Restarts +
+
+ + + )} + +
-
- - } - > + + } + > = (props) => { } /> + );