Index: /branches/amp_4_0/dev/architecture/container_architecture.mmd
===================================================================
--- /branches/amp_4_0/dev/architecture/container_architecture.mmd	(nonexistent)
+++ /branches/amp_4_0/dev/architecture/container_architecture.mmd	(working copy)
@@ -0,0 +1,69 @@
+%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#e3f2fd', 'primaryTextColor': '#1565c0', 'primaryBorderColor': '#1976d2', 'lineColor': '#546e7a', 'secondaryColor': '#f3e5f5', 'tertiaryColor': '#e8f5e9'}}}%%
+
+flowchart TB
+    %% Styling
+    classDef client fill:#e0f7fa,stroke:#00838f,stroke-width:2px
+    classDef vip fill:#ffecb3,stroke:#ff8f00,stroke-width:2px
+    classDef proxy fill:#b3e5fc,stroke:#0277bd,stroke-width:2px
+    classDef global fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
+    classDef stateful fill:#ffccbc,stroke:#bf360c,stroke-width:2px
+    classDef storage fill:#d1c4e9,stroke:#512da8,stroke-width:2px
+
+    %% External
+    Client[("👤 Users / Devices")]:::client
+
+    subgraph VIP_Layer ["🌐 Virtual IP Layer"]
+        VIP["Keepalived VIP<br/>VRRP Failover"]:::vip
+    end
+
+    Client --> VIP
+
+    subgraph Swarm ["🐳 Docker Swarm Cluster (3+ Nodes)"]
+        direction TB
+        
+        subgraph AccessLayer ["📡 Access Layer (Global Mode - Host Network)"]
+            direction LR
+            Nginx["**Nginx**<br/>:443/:80<br/>Reverse Proxy + GUI"]:::proxy
+            HAProxy["**HAProxy**<br/>:5432<br/>DB Load Balancer"]:::proxy
+            PgBouncer["**PgBouncer**<br/>Connection Pool"]:::proxy
+        end
+
+        subgraph ComputeLayer ["⚙️ Compute Layer (Global Mode)"]
+            direction LR
+            AmpCore["**amp-core**<br/>:8000 API<br/>:8889 Agent<br/>:9993 FTP"]:::global
+            OSDash["**OpenSearch<br/>Dashboards**<br/>:5601"]:::global
+            Grafana["**Grafana**<br/>:3000"]:::global
+            Logstash["**Logstash**<br/>:514 Syslog"]:::global
+            Telegraf["**Telegraf**<br/>SNMP Poller"]:::global
+        end
+
+        subgraph StorageLayer ["💾 Storage Layer (Replicated - 3 instances)"]
+            direction LR
+            OpenSearch["**OpenSearch**<br/>:9200/:9300<br/>3-Node Cluster"]:::stateful
+            TimescaleDB["**TimescaleDB**<br/>:5433<br/>Patroni HA"]:::stateful
+            Etcd["**etcd**<br/>:2379<br/>Raft Consensus"]:::stateful
+        end
+    end
+
+    VIP --> Nginx
+    
+    %% Nginx routes
+    Nginx -->|"/visualization"| OSDash
+    Nginx -->|"/monitoring"| Grafana
+    Nginx -->|"/api/v2"| AmpCore
+    Nginx -->|"/"| Nginx
+
+    %% Database flow
+    AmpCore --> PgBouncer
+    Grafana --> PgBouncer
+    PgBouncer --> HAProxy
+    HAProxy -->|"Route to Leader"| TimescaleDB
+
+    %% Log/Metrics flow
+    Logstash --> OpenSearch
+    Telegraf --> TimescaleDB
+    OSDash --> OpenSearch
+    Grafana --> OpenSearch
+
+    %% Patroni coordination
+    TimescaleDB <-->|"Leader Election"| Etcd
Index: /branches/amp_4_0/dev/architecture/data_flow.mmd
===================================================================
--- /branches/amp_4_0/dev/architecture/data_flow.mmd	(nonexistent)
+++ /branches/amp_4_0/dev/architecture/data_flow.mmd	(working copy)
@@ -0,0 +1,56 @@
+%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#fff3e0', 'lineColor': '#546e7a'}}}%%
+
+flowchart LR
+    %% Styling
+    classDef device fill:#e0f7fa,stroke:#006064,stroke-width:2px
+    classDef collection fill:#fff3e0,stroke:#e65100,stroke-width:2px
+    classDef storage fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px
+    classDef viz fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
+    classDef api fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
+
+    subgraph Sources ["📡 Data Sources"]
+        Devices["Array AG/APV/ASF<br/>+ Generic Devices"]:::device
+    end
+
+    subgraph Collection ["🔄 Data Collection"]
+        Telegraf["Telegraf<br/>SNMP Polling"]:::collection
+        Logstash["Logstash<br/>Syslog UDP/TCP:514"]:::collection
+    end
+
+    subgraph Storage ["💾 Data Storage"]
+        TimescaleDB[("TimescaleDB<br/>Metrics Store")]:::storage
+        OpenSearch[("OpenSearch<br/>Log Store")]:::storage
+        PostgreSQL[("PostgreSQL<br/>Config/Metadata")]:::storage
+    end
+
+    subgraph Backend ["⚙️ AMP Backend"]
+        AmpCore["amp-core<br/>Django REST API"]:::api
+    end
+
+    subgraph Visualization ["📊 Visualization"]
+        Grafana["Grafana<br/>Metrics Dashboard"]:::viz
+        OSDash["OpenSearch Dashboards<br/>Log Analytics"]:::viz
+        GUI["AMP Web GUI<br/>Angular"]:::viz
+    end
+
+    %% Metrics Flow
+    Devices -->|"SNMP<br/>:161"| Telegraf
+    Telegraf -->|"Metrics"| TimescaleDB
+    TimescaleDB --> Grafana
+
+    %% Log Flow
+    Devices -->|"Syslog<br/>RFC5424"| Logstash
+    Logstash -->|"Parsed Logs"| OpenSearch
+    OpenSearch --> OSDash
+
+    %% API Flow
+    GUI <-->|"REST API"| AmpCore
+    AmpCore <-->|"CRUD"| PostgreSQL
+    AmpCore -->|"Query"| TimescaleDB
+    AmpCore -->|"Query"| OpenSearch
+    AmpCore -->|"Config Push"| Devices
+
+    %% Link styling
+    linkStyle 0,1,2 stroke:#0288d1,stroke-width:2px
+    linkStyle 3,4,5 stroke:#f57c00,stroke-width:2px
+    linkStyle 6,7,8,9,10 stroke:#7b1fa2,stroke-width:2px
Index: /branches/amp_4_0/dev/architecture/network_topology.mmd
===================================================================
--- /branches/amp_4_0/dev/architecture/network_topology.mmd	(nonexistent)
+++ /branches/amp_4_0/dev/architecture/network_topology.mmd	(working copy)
@@ -0,0 +1,92 @@
+%%{init: {'theme': 'base', 'themeVariables': { 'lineColor': '#37474f'}}}%%
+
+flowchart TB
+    %% Styling
+    classDef external fill:#e1f5fe,stroke:#0288d1,stroke-width:2px
+    classDef vip fill:#fff9c4,stroke:#f9a825,stroke-width:2px
+    classDef node fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
+    classDef hostnet fill:#ffccbc,stroke:#e64a19,stroke-width:2px
+    classDef overlay fill:#c8e6c9,stroke:#388e3c,stroke-width:2px
+
+    Internet["🌐 External Traffic"]:::external
+
+    subgraph VIPLayer ["Virtual IP (Keepalived VRRP)"]
+        VIP["VIP Address<br/>Floats between nodes"]:::vip
+    end
+
+    Internet --> VIP
+
+    subgraph Node1 ["📦 Node 1 (Manager/Leader)"]
+        direction TB
+        N1_Host["Host Network :443, :514, :5432, :9200"]:::hostnet
+        N1_Overlay["Overlay Network (amp-overlay)"]:::overlay
+        
+        N1_Nginx["Nginx"]
+        N1_HAProxy["HAProxy"]
+        N1_OS["OpenSearch"]
+        N1_TSDB["TimescaleDB"]
+        N1_Etcd["etcd"]
+        
+        N1_Host --> N1_Nginx
+        N1_Host --> N1_HAProxy
+        N1_Host --> N1_OS
+        N1_Host --> N1_TSDB
+        N1_Host --> N1_Etcd
+        
+        N1_Grafana["Grafana"]
+        N1_OSDash["Dashboards"]
+        N1_Overlay --> N1_Grafana
+        N1_Overlay --> N1_OSDash
+    end
+
+    subgraph Node2 ["📦 Node 2 (Manager/Replica)"]
+        direction TB
+        N2_Host["Host Network"]:::hostnet
+        N2_Overlay["Overlay Network"]:::overlay
+        
+        N2_Nginx["Nginx"]
+        N2_HAProxy["HAProxy"]
+        N2_OS["OpenSearch"]
+        N2_TSDB["TimescaleDB"]
+        N2_Etcd["etcd"]
+        
+        N2_Host --> N2_Nginx
+        N2_Host --> N2_HAProxy
+        N2_Host --> N2_OS
+        N2_Host --> N2_TSDB
+        N2_Host --> N2_Etcd
+    end
+
+    subgraph Node3 ["📦 Node 3 (Manager/Replica)"]
+        direction TB
+        N3_Host["Host Network"]:::hostnet
+        N3_Overlay["Overlay Network"]:::overlay
+        
+        N3_Nginx["Nginx"]
+        N3_HAProxy["HAProxy"]
+        N3_OS["OpenSearch"]
+        N3_TSDB["TimescaleDB"]
+        N3_Etcd["etcd"]
+        
+        N3_Host --> N3_Nginx
+        N3_Host --> N3_HAProxy
+        N3_Host --> N3_OS
+        N3_Host --> N3_TSDB
+        N3_Host --> N3_Etcd
+    end
+
+    VIP --> N1_Host
+    VIP -.->|"Failover"| N2_Host
+    VIP -.->|"Failover"| N3_Host
+
+    %% Cross-node replication
+    N1_OS <-->|"Cluster Sync<br/>:9300"| N2_OS
+    N2_OS <-->|"Cluster Sync"| N3_OS
+    N3_OS <-->|"Cluster Sync"| N1_OS
+
+    N1_TSDB <-->|"Patroni Replication"| N2_TSDB
+    N2_TSDB <-->|"Patroni Replication"| N3_TSDB
+
+    N1_Etcd <-->|"Raft Consensus<br/>:2379/:2380"| N2_Etcd
+    N2_Etcd <-->|"Raft"| N3_Etcd
+    N3_Etcd <-->|"Raft"| N1_Etcd
Index: /branches/amp_4_0/dev/architecture/service_dependencies.mmd
===================================================================
--- /branches/amp_4_0/dev/architecture/service_dependencies.mmd	(nonexistent)
+++ /branches/amp_4_0/dev/architecture/service_dependencies.mmd	(working copy)
@@ -0,0 +1,61 @@
+%%{init: {'theme': 'base'}}%%
+
+graph TD
+    %% Styling
+    classDef core fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
+    classDef db fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
+    classDef search fill:#fff3e0,stroke:#ff9800,stroke-width:2px
+    classDef ui fill:#fce4ec,stroke:#e91e63,stroke-width:2px
+    classDef infra fill:#f5f5f5,stroke:#616161,stroke-width:2px
+
+    subgraph Infrastructure ["Infrastructure Services"]
+        Etcd["etcd<br/>(Consensus)"]:::infra
+        Registry["Docker Registry<br/>:5000"]:::infra
+    end
+
+    subgraph Database ["Database Layer"]
+        TimescaleDB["TimescaleDB<br/>+ Patroni"]:::db
+        HAProxy["HAProxy<br/>(DB LB)"]:::db
+        PgBouncer["PgBouncer<br/>(Pool)"]:::db
+        PostgreSQL["PostgreSQL<br/>(cm database)"]:::db
+    end
+
+    subgraph Search ["Search & Analytics"]
+        OpenSearch["OpenSearch<br/>Cluster"]:::search
+        Logstash["Logstash<br/>(Syslog)"]:::search
+        OSDash["OpenSearch<br/>Dashboards"]:::search
+    end
+
+    subgraph Application ["Application Layer"]
+        AmpCore["amp-core<br/>(Django API)"]:::core
+        Nginx["Nginx<br/>(Gateway)"]:::core
+    end
+
+    subgraph Monitoring ["Monitoring"]
+        Grafana["Grafana"]:::ui
+        Telegraf["Telegraf"]:::ui
+    end
+
+    %% Dependencies
+    TimescaleDB -->|"Leader Election"| Etcd
+    HAProxy -->|"Health Check :8008"| TimescaleDB
+    PgBouncer --> HAProxy
+    
+    AmpCore --> PgBouncer
+    AmpCore --> OpenSearch
+    Grafana --> PgBouncer
+    Grafana --> OpenSearch
+    
+    Logstash --> OpenSearch
+    Telegraf --> TimescaleDB
+    
+    OSDash --> OpenSearch
+    
+    Nginx --> AmpCore
+    Nginx --> Grafana
+    Nginx --> OSDash
+
+    %% Startup order (implied)
+    Etcd -.->|"Must start first"| TimescaleDB
+    OpenSearch -.->|"Before"| Logstash
+    TimescaleDB -.->|"Before"| AmpCore
Index: /branches/amp_4_0/dev/architecture/tech_stack.mmd
===================================================================
--- /branches/amp_4_0/dev/architecture/tech_stack.mmd	(nonexistent)
+++ /branches/amp_4_0/dev/architecture/tech_stack.mmd	(working copy)
@@ -0,0 +1,64 @@
+%%{init: {'theme': 'base', 'themeVariables': { 'fontSize': '14px'}}}%%
+
+graph LR
+    %% Styling
+    classDef infra fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
+    classDef data fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
+    classDef search fill:#fff3e0,stroke:#f57c00,stroke-width:2px
+    classDef observe fill:#fce4ec,stroke:#c2185b,stroke-width:2px
+    classDef app fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
+
+    subgraph Infrastructure ["🏗️ Infrastructure"]
+        direction TB
+        Swarm["Docker Swarm"]:::infra
+        Rocky["Rocky Linux 9.6"]:::infra
+        Registry["Registry 3.0.0"]:::infra
+    end
+
+    subgraph DataLayer ["💾 Data Layer"]
+        direction TB
+        TSDB["TimescaleDB PG14"]:::data
+        Patroni["Patroni HA"]:::data
+        Etcd["etcd v3.5.17"]:::data
+        HAProxy["HAProxy 3.3"]:::data
+        PgBouncer["PgBouncer 1.25.1"]:::data
+    end
+
+    subgraph SearchAnalytics ["🔍 Search & Analytics"]
+        direction TB
+        OS["OpenSearch 3.4.0"]:::search
+        OSD["OpenSearch Dashboards 3.4.0"]:::search
+        LS["Logstash 8.9.0"]:::search
+    end
+
+    subgraph Observability ["📊 Observability"]
+        direction TB
+        Graf["Grafana 11.5.0"]:::observe
+        Tele["Telegraf 1.36.4"]:::observe
+    end
+
+    subgraph Application ["⚙️ Application"]
+        direction TB
+        Django["Django 5.2.3"]:::app
+        Angular["Angular 21.x"]:::app
+        Nginx["Nginx 1.25.3"]:::app
+        Core["amp-core 1.0.0"]:::app
+    end
+
+    %% Grouping relationships
+    Swarm --> Patroni
+    Patroni --> TSDB
+    Patroni --> Etcd
+    TSDB --> HAProxy
+    HAProxy --> PgBouncer
+
+    OS --> OSD
+    LS --> OS
+
+    Tele --> TSDB
+    Graf --> TSDB
+    Graf --> OS
+
+    Angular --> Nginx
+    Nginx --> Django
+    Django --> Core
Index: /branches/amp_4_0/platform/tools/container/DEPLOYMENT.md
===================================================================
--- /branches/amp_4_0/platform/tools/container/DEPLOYMENT.md	(revision 2927)
+++ /branches/amp_4_0/platform/tools/container/DEPLOYMENT.md	(working copy)
@@ -318,6 +318,7 @@
 | etcd | `quay.io/coreos/etcd` | Distributed key-value store |
 | haproxy | `haproxy` | Database load balancer |
 | pgbouncer | `edoburu/pgbouncer` | Connection pooling |
+| amp-core | Custom build | Django API + WebUI Agent + FTP |
 
 ---
 
@@ -326,10 +327,18 @@
 | Port | Service | Notes |
 |------|---------|-------|
 | 80/443 | Nginx | Web UI entry |
-| 514 | Logstash | Syslog ingestion |
+| 514 | Logstash | Syslog ingestion (TCP/UDP) |
 | 2377 | Docker Swarm | Cluster management |
 | 3000 | Grafana | Monitoring UI |
+| 4789/udp | Docker Swarm | Overlay network traffic |
 | 5000 | Registry | Local image storage |
 | 5432 | HAProxy | Database (via LB) |
+| 5433 | TimescaleDB | PostgreSQL direct (Patroni) |
 | 5601 | Dashboards | OpenSearch UI |
+| 7946/tcp+udp | Docker Swarm | Node communication |
+| 8000 | AMP Core | Django REST API |
+| 8008 | Patroni | REST API for HA management |
+| 8889 | AMP Core | WebUI Agent |
 | 9200 | OpenSearch | REST API |
+| 9300 | OpenSearch | Internal cluster transport |
+| 9993 | AMP Core | FTP service |
Index: /branches/amp_4_0/platform/tools/container/services/telegraf/telegraf.conf
===================================================================
--- /branches/amp_4_0/platform/tools/container/services/telegraf/telegraf.conf	(revision 2927)
+++ /branches/amp_4_0/platform/tools/container/services/telegraf/telegraf.conf	(working copy)
@@ -6,7 +6,7 @@
   collection_jitter = "0s"
   flush_interval = "10s"
   precision = ""
-  hostname = "amp-docker"
+
   # logfile = "/var/log/telegraf/telegraf.log"
   debug = true
   quiet = false
@@ -32,8 +32,7 @@
   percpu = true
   totalcpu = true
 [[inputs.disk]]
-  mount_points = ["/rootfs", "/rootfs/home", "/rootfs/var"]
-  ignore_fs = ["tmpfs", "devtmpfs", "overlay", "rootfs"]
+  ignore_fs = ["tmpfs", "devtmpfs", "rootfs"]
 [[inputs.mem]]
 [[inputs.diskio]]
 [[inputs.net]]
@@ -175,4 +174,3 @@
 
     return metric
 '''
-
Index: /branches/amp_4_0/platform/tools/container/stack.yml.template
===================================================================
--- /branches/amp_4_0/platform/tools/container/stack.yml.template	(revision 2927)
+++ /branches/amp_4_0/platform/tools/container/stack.yml.template	(working copy)
@@ -365,6 +365,10 @@
     entrypoint: ["telegraf", "--config", "/etc/telegraf/telegraf.conf", "--config", "/etc/telegraf/telegraf.d/apv.toml", "--config", "/etc/telegraf/telegraf.d/ag.toml", "--config", "/etc/telegraf/telegraf.d/asf.toml"]
     environment:
       PG_PASSWORD_FILE: /run/secrets/pg_password
+      HOST_PROC: /rootfs/proc
+      HOST_SYS: /rootfs/sys
+      HOST_ETC: /rootfs/etc
+      HOST_MOUNT_PREFIX: /rootfs
     secrets:
       - pg_password
     configs:
@@ -373,6 +377,7 @@
     volumes:
       - /var/run/docker.sock:/var/run/docker.sock
       - /dev:/dev:ro
+      - /:/rootfs:ro
       - /proc:/rootfs/proc:ro
       - /sys:/rootfs/sys:ro
       - /etc:/rootfs/etc:ro
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.html	(revision 2927)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.html	(working copy)
@@ -109,7 +109,6 @@
         </mat-card-title>
       </div>
       @if (nodeMetrics && nodeMetrics.length > 0) {
-      <p class="status-details">{{ nodeMetrics.length }} {{ nodeMetrics.length === 1 ? 'Node' : 'Nodes' }}</p>
       <div class="chart-flex-container centered-content" [ngClass]="{'single-node-chart': nodeMetrics.length === 1}">
         <div echarts [autoResize]="true" [options]="diskChartOption1" class="chart-container full-width"></div>
       </div>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.ts	(revision 2927)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.ts	(working copy)
@@ -2,6 +2,7 @@
 import { SharedModule } from '../../../shared/shared-module';
 import { NgxEchartsModule } from 'ngx-echarts';
 import { EChartsOption } from 'echarts';
+import * as echarts from 'echarts';
 import { MAT_DIALOG_DATA, MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog';
 import { startWith, take, tap } from 'rxjs/operators';
 import { DeviceFacade } from '../../../services/facades/device.facade';
@@ -21,7 +22,7 @@
 @Component({
   selector: 'app-dashboard-system-insights',
   standalone: true,
-  imports: [SharedModule, BytesPipe, NgxEchartsModule],
+  imports: [SharedModule, NgxEchartsModule],
   templateUrl: './dashboard-system-insights.html',
   styleUrl: './dashboard-system-insights.scss'
 })
@@ -253,30 +254,38 @@
               ? (aggregatedDisk.used_bytes / aggregatedDisk.total_bytes) * 100
               : 0;
 
-            const netMetric = this.currentSystemMetrics?.net_metrics?.find((n: any) => n.host === host);
+            // Aggregate network metrics for this host (sum of all interfaces)
+            const netMetricsForHost = this.currentSystemMetrics?.net_metrics?.filter((n: any) => n.host === host) || [];
+            const aggregatedNet = netMetricsForHost.reduce((acc: any, net: any) => {
+              return {
+                host: host,
+                sent: (acc.sent || 0) + (net.sent || 0),
+                received: (acc.received || 0) + (net.received || 0)
+              };
+            }, { host: host, sent: 0, received: 0 });
 
             this.nodeMetrics.push({
               host: host,
               cpu: cpuMetric,
               memory: memMetric,
               disk: aggregatedDisk,
-              network: netMetric
+              network: aggregatedNet
             });
           });
 
-
-
           console.log('Multi-node detected:', this.isMultiNode);
           console.log('Node metrics:', this.nodeMetrics);
 
-          // Handle network metrics
+          // Handle single-node specific legacy variable `networkMetrics` (sum of all interfaces)
           if (this.currentSystemMetrics?.net_metrics && this.currentSystemMetrics.net_metrics.length > 0) {
-            this.networkMetrics = this.currentSystemMetrics.net_metrics[0];
+            this.networkMetrics = this.currentSystemMetrics.net_metrics.reduce((acc: any, net: any) => {
+              return {
+                sent: (acc.sent || 0) + (net.sent || 0),
+                received: (acc.received || 0) + (net.received || 0)
+              };
+            }, { sent: 0, received: 0 });
           }
 
-
-
-
           this.updateChartOption();
         },
         error: (error: { message: string; }) => {
@@ -374,7 +383,7 @@
     }
 
     if (this.deviceConnectionStats && this.deviceConnectionStats.yAxisData && this.deviceConnectionStats.yAxisData.length > 0) {
-      this.connectionChartOption1 = this._chartOptions.connectedDeviceLineChart(this.deviceConnectionStats)
+      this.connectionChartOption1 = this.getConnectedDeviceBarChartOptions(this.deviceConnectionStats);
     } else {
       this.connectionChartOption1 = this._chartOptions.getNoDataChartOptions();
     }
@@ -728,7 +737,11 @@
           const node = this.nodeMetrics[nodeIndex];
           const sent = node.network?.sent || 0;
           const received = node.network?.received || 0;
-          return `<strong>${node.host || 'Node ' + (nodeIndex + 1)}</strong><br/>Inbound: ${this.formatBytes(received)}/s<br/>Outbound: ${this.formatBytes(sent)}/s`;
+          return `
+            <strong>${node.host || 'Node ' + (nodeIndex + 1)}</strong><br/>
+            Inbound: ${this.formatBits(received)}<br/>
+            Outbound: ${this.formatBits(sent)}
+          `;
         }
       },
       legend: {
@@ -737,7 +750,7 @@
         textStyle: { color: themeColors.textMain }
       },
       grid: {
-        left: '10%',
+        left: '12%',
         right: '10%',
         bottom: isSingleNode ? '35%' : '25%',
         top: '10%',
@@ -757,9 +770,8 @@
       },
       yAxis: {
         type: 'value',
-        minInterval: 1,
         axisLabel: {
-          formatter: (value: number) => this.formatBytes(value, 1),
+          formatter: (value: number) => this.formatBits(value, 0),
           color: themeColors.textMuted
         },
         splitLine: { lineStyle: { color: isDarkTheme ? '#505050' : '#e0e0e0' } }
@@ -768,20 +780,22 @@
         {
           name: 'Inbound',
           type: 'bar',
-          stack: 'total',
-          barWidth: isSingleNode ? '40%' : '30',
+          barGap: '10%', // Gap between bars in same category
+          barCategoryGap: '30%', // Gap between categories (nodes)
           data: receivedData,
-          emphasis: { focus: 'none' },
-          itemStyle: { color: themeColors.green }
+          itemStyle: {
+            color: themeColors.green,
+            borderRadius: [4, 4, 0, 0]
+          }
         },
         {
           name: 'Outbound',
           type: 'bar',
-          stack: 'total',
-          barWidth: isSingleNode ? '40%' : '30',
           data: sentData,
-          emphasis: { focus: 'none' },
-          itemStyle: { color: themeColors.accent, borderRadius: [4, 4, 0, 0] }
+          itemStyle: {
+            color: themeColors.accent,
+            borderRadius: [4, 4, 0, 0]
+          }
         }
       ]
     };
@@ -893,6 +907,17 @@
     return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
   }
 
+  formatBits(bits: number, decimals = 2): string {
+    if (bits <= 0) return '0 bps';
+    const k = 1000;
+    const dm = decimals < 0 ? 0 : decimals;
+    const sizes = ['bps', 'Kbps', 'Mbps', 'Gbps', 'Tbps', 'Pbps', 'Ebps', 'Zbps', 'Ybps'];
+    let i = Math.floor(Math.log(bits) / Math.log(k));
+    if (i < 0) i = 0;
+    if (i >= sizes.length) i = sizes.length - 1;
+    return parseFloat((bits / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
+  }
+
   updateHistoricalCharts(isDark_in?: boolean) {
     const isDark = isDark_in !== undefined ? isDark_in : document.body.classList.contains('dark-theme');
     const factor: any = 1024 * 1024;
@@ -906,14 +931,14 @@
       Object.keys(cpuByTime).forEach(time => {
         const metrics = cpuByTime[time];
         const avgCpu = metrics.reduce((acc: number, m: any) => acc + (m.cpu_percent || 0), 0) / metrics.length;
-        aggregatedCPU.push([Number(time), avgCpu]);
+        aggregatedCPU.push([new Date(time).getTime(), avgCpu]);
       });
 
       const memByTime = this.groupHistoricalByTime(this.historicalMemoryMetrics);
       Object.keys(memByTime).forEach(time => {
         const metrics = memByTime[time];
         const avgMem = metrics.reduce((acc: number, m: any) => acc + (m.mem_percent || 0), 0) / metrics.length;
-        aggregatedMem.push([Number(time), avgMem]);
+        aggregatedMem.push([new Date(time).getTime(), avgMem]);
       });
 
       this.systemLoadChartOption1 = this._chartOptions.historicalCPUMemoryChartOptions(aggregatedCPU, aggregatedMem);
@@ -930,8 +955,8 @@
         const metrics = netByTime[time];
         const totalSent = metrics.reduce((acc: number, m: any) => acc + (m.sent || 0), 0);
         const totalReceived = metrics.reduce((acc: number, m: any) => acc + (m.received || 0), 0);
-        aggregatedSent.push([Number(time), totalSent / factor]);
-        aggregatedReceived.push([Number(time), totalReceived / factor]);
+        aggregatedSent.push([new Date(time).getTime(), totalSent / factor]);
+        aggregatedReceived.push([new Date(time).getTime(), totalReceived / factor]);
       });
 
       this.networkThroughputChartOption1 = this._chartOptions.historicalThroughputChartOptions(aggregatedReceived, aggregatedSent)
@@ -945,7 +970,7 @@
       Object.keys(diskByTime).forEach(time => {
         const metrics = diskByTime[time];
         const avgDisk = metrics.reduce((acc: number, m: any) => acc + (m.disk_io_percent || 0), 0) / metrics.length;
-        aggregatedDiskIO.push([Number(time), avgDisk]);
+        aggregatedDiskIO.push([new Date(time).getTime(), avgDisk]);
       });
       this.diskIOChartOption1 = this._chartOptions.historicalDiskIOChartOptions(aggregatedDiskIO);
     } else {
@@ -987,6 +1012,7 @@
 
   private updateDeviceMetricsCharts(isDark_in?: boolean): void {
     const isDark = isDark_in !== undefined ? isDark_in : document.body.classList.contains('dark-theme');
+
     if (!this.connectedDevicesMetrics || this.connectedDevicesMetrics.length === 0) {
       this.devicesCPUChartOption1 = this._chartOptions.getNoDataChartOptions();
       this.devicesMemoryChartOption1 = this._chartOptions.getNoDataChartOptions();
@@ -1042,16 +1068,8 @@
   }
 
   getHorizontalBarChartOptions(label: string, metrics: any[], color: string): EChartsOption {
-    // This is called by updateDeviceMetricsCharts which now sets the theme context, 
-    // but if called directly we might need consistent isDark. 
-    // However, for now we can likely rely on DOM for this helper as it's not the top-level updater,
-    // OR ideally we pass colors in. But for now, let's keep it DOM based or pass it.
-    // Given the method signature is used elsewhere, let's stick to DOM here OR update signature.
-    // Simpler: The caller (updateDeviceMetricsCharts) calls this, but this method re-reads theme.
-    // Let's rely on the caller passing 'colors' properly? No, 'colors' arg is just BAR color.
-    // We should patch this too.
     const isDark = document.body.classList.contains('dark-theme');
-    const themeColors = this.getThemeColors(isDark); // Rename to avoid conflict with 'color' arg
+    const themeColors = this.getThemeColors(isDark);
 
     return {
       tooltip: {
@@ -1097,6 +1115,9 @@
         },
         axisLine: {
           show: false
+        },
+        axisTick: {
+          show: false
         }
       },
       series: [
@@ -1138,8 +1159,9 @@
         formatter: (params: any) => {
           let tooltipContent = `${params[0].name}<br/>`;
           params.forEach((param: any) => {
-            const valueInMbps = param.value.toFixed(2);
-            tooltipContent += `${param.marker} ${param.seriesName}: ${valueInMbps} Mbps<br/>`;
+            // value is in bits, use formatBits
+            const formattedValue = this.formatBits(param.value);
+            tooltipContent += `${param.marker} ${param.seriesName}: ${formattedValue}<br/>`;
           });
           return tooltipContent;
         }
@@ -1151,24 +1173,28 @@
       },
       grid: {
         left: '3%',
-        right: '15%',
+        right: '5%',
         bottom: '10%',
         containLabel: true
       },
       xAxis: {
         type: 'value',
         boundaryGap: [0, 0.01],
-        name: 'Mbps',
-        nameLocation: 'end',
-        nameGap: 20,
+        // name: 'Mbps', // Removed specific unit label as formatBits handles it
+        // nameLocation: 'end',
+        // nameGap: 20,
         axisLabel: {
-          color: colors.textMuted
+          color: colors.textMuted,
+          formatter: (value: number) => this.formatBits(value, 0)
         },
         splitLine: {
           show: false
         },
         nameTextStyle: {
           color: colors.textMuted
+        },
+        axisLine: {
+          lineStyle: { color: isDark ? '#616161' : '#ccc' }
         }
       },
       yAxis: {
@@ -1179,22 +1205,26 @@
           width: 80,
           overflow: 'truncate',
           color: colors.textMuted
-        }
+        },
+        axisLine: { show: false },
+        axisTick: { show: false }
       },
       series: [
         {
           name: 'Inbound',
           type: 'bar',
-          stack: 'total',
+          // stack: 'total', // Removed for grouped bar
           data: data.map(item => item.inbound),
           itemStyle: {
-            color: colors.green
-          }
+            color: colors.green,
+            borderRadius: [0, 4, 4, 0]
+          },
+          barGap: '20%' // Add spacing between bars
         },
         {
           name: 'Outbound',
           type: 'bar',
-          stack: 'total',
+          // stack: 'total', // Removed for grouped bar
           data: data.map(item => item.outbound),
           itemStyle: {
             color: colors.accent,
@@ -1205,7 +1235,91 @@
     };
   }
 
+  getConnectedDeviceBarChartOptions(metrics: any): EChartsOption {
+    const isDark = document.body.classList.contains('dark-theme');
+    const colors = this.getThemeColors(isDark);
 
+    return {
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+          type: 'shadow'
+        },
+        backgroundColor: isDark ? '#424242' : '#fff',
+        borderColor: isDark ? '#616161' : '#ccc',
+        textStyle: {
+          color: colors.textMain
+        }
+      },
+      legend: {
+        bottom: '0',
+        textStyle: {
+          color: colors.textMain
+        }
+      },
+      grid: {
+        left: '3%',
+        right: '4%',
+        bottom: '10%',
+        containLabel: true
+      },
+      yAxis: {
+        type: 'value',
+        axisLabel: {
+          formatter: function (value: number) {
+            if (value % 1 === 0) {
+              return String(value);
+            }
+            return '';
+          },
+          color: colors.textMuted
+        },
+        splitLine: {
+          show: false
+        },
+        axisLine: {
+          lineStyle: { color: isDark ? '#616161' : '#ccc' }
+        }
+      },
+      xAxis: {
+        type: 'category',
+        data: metrics?.yAxisData, // Assuming yAxisData holds category names
+        axisLabel: {
+          color: colors.textMuted
+        },
+        axisLine: {
+          lineStyle: { color: isDark ? '#616161' : '#ccc' }
+        },
+        axisTick: { show: false }
+      },
+      series: [
+        {
+          name: 'Connected',
+          type: 'bar',
+          stack: 'total',
+          data: metrics?.connectedData,
+          itemStyle: {
+            color: 'green', // MATCHED TO DOUGHNUT CHART
+            borderRadius: [0, 0, 0, 0]
+          },
+          barWidth: '40%'
+        },
+        {
+          name: 'Disconnected',
+          type: 'bar',
+          stack: 'total',
+          data: metrics?.disconnectedData,
+          itemStyle: {
+            color: 'red', // MATCHED TO DOUGHNUT CHART
+            borderRadius: [4, 4, 0, 0] // Top radius
+          },
+          barWidth: '40%'
+        }
+      ]
+    };
+  }
+
+
 
   dialogConfig = new MatDialogConfig();
 
@@ -1719,31 +1833,142 @@
 
   updateChartOptions() {
 
-    // Update Trend Chart (Aggregated)
+    // Update Trend Chart (Per Node)
     const isDark = document.body.classList.contains('dark-theme');
     const factor: any = 1024 * 1024;
+    const colors = this.getThemeColors(isDark);
 
     if (this.historicalNetworkMetrics && this.historicalNetworkMetrics.length > 0) {
-      // Group by time and sum metrics
-      const netByTime = this.historicalNetworkMetrics.reduce((acc: any, item: any) => {
-        const time = item.time;
-        if (!acc[time]) acc[time] = [];
-        acc[time].push(item);
-        return acc;
-      }, {});
-
-      const aggregatedSent: any[] = [];
-      const aggregatedReceived: any[] = [];
+      // Get unique hosts
+      const hosts = Array.from(new Set(this.historicalNetworkMetrics.map((m: any) => m.host))).sort();
+      const series: any[] = [];
+      const legendData: string[] = [];
 
-      Object.keys(netByTime).sort().forEach(time => {
-        const metrics = netByTime[time];
-        const totalSent = metrics.reduce((sum: number, m: any) => sum + (m.sent || 0), 0);
-        const totalReceived = metrics.reduce((sum: number, m: any) => sum + (m.received || 0), 0);
-        aggregatedSent.push([Number(time), totalSent / factor]);
-        aggregatedReceived.push([Number(time), totalReceived / factor]);
+      const palette = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'];
+
+      hosts.forEach((host: any, index: number) => {
+        const hostMetrics = this.historicalNetworkMetrics.filter((m: any) => m.host === host);
+
+        const netByTime = hostMetrics.reduce((acc: any, item: any) => {
+          const time = item.time;
+          if (!acc[time]) acc[time] = [];
+          acc[time].push(item);
+          return acc;
+        }, {});
+
+        const hostSent: any[] = [];
+        const hostReceived: any[] = [];
+
+        Object.keys(netByTime).sort().forEach(time => {
+          const metrics = netByTime[time];
+          const totalSent = metrics.reduce((sum: number, m: any) => sum + (m.sent || 0), 0);
+          const totalReceived = metrics.reduce((sum: number, m: any) => sum + (m.received || 0), 0);
+          // Sent/Received are bits per second from backend (already multiplied by 8 in query? No, let's check query. 
+          // Query: ROUND(SUM(bytes_sent_diff) * 8 / GREATEST(1, SUM(time_diff_sec)), 2) AS sent
+          // Yes, backend returns BITS per second.
+          // factor was 1024*1024 for MB/s. 
+          // We want raw bits for formatBits. So remove factor division.
+          hostSent.push([new Date(time).getTime(), totalSent]);
+          hostReceived.push([new Date(time).getTime(), totalReceived]);
+        });
+
+        const color = palette[index % palette.length];
+
+        // Inbound Series (Top Grid - Index 0)
+        series.push({
+          name: `${host}`, // Just Host Name for cleaner legend or "${host} In"? Let's keep distinct.
+          type: 'line',
+          xAxisIndex: 0,
+          yAxisIndex: 0,
+          data: hostReceived,
+          showSymbol: false,
+          smooth: true,
+          lineStyle: { width: 2, color: color },
+          itemStyle: { color: color },
+          areaStyle: { opacity: 0.1, color: color },
+          emphasis: { focus: 'series' }
+        });
+
+        // Outbound Series (Bottom Grid - Index 1)
+        series.push({
+          name: `${host}`, // Same name to link legend? No, ECharts merges legend by name. 
+          // If we use same name, toggling one toggles both. That's actually good!
+          // But we need to distinguish in tooltip. 
+          // Let's use same name for Legend, but formatted tooltip will distinguish via axis index or value?
+          // Actually, if we use same name, they share color and legend item.
+          type: 'line',
+          xAxisIndex: 1,
+          yAxisIndex: 1,
+          data: hostSent,
+          showSymbol: false,
+          smooth: true,
+          lineStyle: { width: 2, type: 'dashed', color: color },
+          itemStyle: { color: color },
+          emphasis: { focus: 'series' }
+        });
+
+        legendData.push(host); // Just host name
       });
 
-      this.trendChartOption = this._chartOptions.historicalThroughputChartOptions(aggregatedReceived, aggregatedSent);
+      // Deduplicate legend data
+      const uniqueLegendData = Array.from(new Set(legendData));
+
+      this.trendChartOption = {
+        title: [
+          { text: 'Inbound Traffic', left: 'center', top: '5%', textStyle: { color: colors.textMain, fontSize: 13, fontWeight: 'normal' } },
+          { text: 'Outbound Traffic', left: 'center', top: '50%', textStyle: { color: colors.textMain, fontSize: 13, fontWeight: 'normal' } }
+        ],
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: { type: 'line', animation: false },
+          formatter: (params: any) => {
+            let res = '';
+            if (params.length > 0) {
+              const date = new Date(params[0].value[0]);
+              res += `${date.toLocaleTimeString()}<br/>`;
+            }
+
+            // params contains series from both axes if they align on time (they should)
+            // Separate by axis
+            const inbound = params.filter((p: any) => p.axisIndex === 0);
+            const outbound = params.filter((p: any) => p.axisIndex === 1);
+
+            if (inbound.length > 0) {
+              res += `<strong>Inbound</strong><br/>`;
+              inbound.forEach((p: any) => {
+                res += `${p.marker} ${p.seriesName}: ${this.formatBits(p.value[1])}<br/>`;
+              });
+            }
+            if (outbound.length > 0) {
+              res += `<strong>Outbound</strong><br/>`;
+              outbound.forEach((p: any) => {
+                res += `${p.marker} ${p.seriesName}: ${this.formatBits(p.value[1])}<br/>`;
+              });
+            }
+            return res;
+          }
+        },
+        axisPointer: { link: [{ xAxisIndex: 'all' }] }, // Sync axes
+        legend: {
+          data: uniqueLegendData,
+          bottom: 5,
+          type: 'scroll',
+          textStyle: { color: colors.textMain }
+        },
+        grid: [
+          { left: '3%', right: '4%', height: '30%', top: '15%', containLabel: true }, // Top Grid
+          { left: '3%', right: '4%', height: '30%', top: '60%', containLabel: true }  // Bottom Grid
+        ],
+        xAxis: [
+          { type: 'time', gridIndex: 0, splitLine: { show: false }, axisLabel: { show: false }, axisTick: { show: false } }, // Hide X labels on top
+          { type: 'time', gridIndex: 1, splitLine: { show: false }, axisLabel: { color: colors.textMuted } }
+        ],
+        yAxis: [
+          { type: 'value', gridIndex: 0, name: 'Inbound', splitLine: { show: true, lineStyle: { type: 'dashed', color: isDark ? '#505050' : '#e0e0e0' } }, axisLabel: { formatter: (v: number) => this.formatBits(v, 0), color: colors.textMuted } },
+          { type: 'value', gridIndex: 1, name: 'Outbound', splitLine: { show: true, lineStyle: { type: 'dashed', color: isDark ? '#505050' : '#e0e0e0' } }, axisLabel: { formatter: (v: number) => this.formatBits(v, 0), color: colors.textMuted } }
+        ],
+        series: series
+      };
     } else {
       this.trendChartOption = this._chartOptions.getNoDataChartOptions();
     }
@@ -1760,6 +1985,27 @@
   onCancel() {
     this.dialogRef.close();
   }
+
+  formatBits(bits: number, decimals = 2): string {
+    if (bits <= 0) return '0 bps';
+    const k = 1000;
+    const dm = decimals < 0 ? 0 : decimals;
+    const sizes = ['bps', 'Kbps', 'Mbps', 'Gbps', 'Tbps', 'Pbps', 'Ebps', 'Zbps', 'Ybps'];
+    let i = Math.floor(Math.log(bits) / Math.log(k));
+    if (i < 0) i = 0;
+    if (i >= sizes.length) i = sizes.length - 1;
+    return parseFloat((bits / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
+  }
+
+  getThemeColors(isDark: boolean): any {
+    return {
+      textMain: isDark ? '#e0e0e0' : '#333333',
+      textMuted: isDark ? '#a0a0a0' : '#777777',
+      green: isDark ? '#a5d6a7' : '#4caf50',
+      orange: isDark ? '#ffcc80' : '#ff9800',
+      accent: '#1170cf'
+    };
+  }
 }
 
 
@@ -1771,7 +2017,9 @@
 export class EnlargeSystemDiskUsage implements OnInit {
 
   diskChartOption: EChartsOption = {};
+  diskIOChartOption: EChartsOption = {};
   nodeMetrics: any[] = [];
+  historicalDiskIOMetrics: any[] = [];
 
   readonly data = inject(MAT_DIALOG_DATA);
   readonly dialogRef = inject(MatDialogRef<EnlargeSystemDiskUsage>);
@@ -1793,6 +2041,7 @@
           startWith(0),
           tap(() => {
             this.getLatestSystemMetrics();
+            this.getHistoricalSystemMetrics();
           }),
           takeUntilDestroyed(this.destroyRef)
         )
@@ -1815,13 +2064,31 @@
       });
   }
 
+  getHistoricalSystemMetrics() {
+    this.systemFacade.getHistoricalSystemMetrics()
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          this.historicalDiskIOMetrics = result?.disk_io_history || [];
+          this.updateDiskIOChart();
+        },
+        error: (error: { message: string; }) => {
+          console.log(error);
+        }
+      });
+  }
+
   processNodeMetrics(result: any) {
     this.nodeMetrics = [];
+    // Ensure inputs are arrays or fallback
     const diskData = Array.isArray(result?.disk_usage) ? result.disk_usage : (result?.disk_usage ? [result.disk_usage] : []);
+
+    // Determine hosts
     const hosts = Array.from(new Set(diskData.map((d: any) => d.host).filter((h: any) => h)));
 
+    // If we have hosts, process per host
     if (hosts.length > 0) {
-      hosts.forEach(host => {
+      hosts.forEach((host: any) => {
         const diskMetricsForHost = diskData.filter((d: any) => d.host === host);
         const aggregatedDisk = diskMetricsForHost.reduce((acc: any, disk: any) => {
           return {
@@ -1830,11 +2097,17 @@
             free_bytes: (acc.free_bytes || 0) + (disk.free_bytes || 0),
           };
         }, {});
-        aggregatedDisk.used_percent = aggregatedDisk.total_bytes > 0 ? (aggregatedDisk.used_bytes / aggregatedDisk.total_bytes) * 100 : 0;
+
+        if (aggregatedDisk.total_bytes > 0) {
+          aggregatedDisk.used_percent = (aggregatedDisk.used_bytes / aggregatedDisk.total_bytes) * 100;
+        } else {
+          aggregatedDisk.used_percent = 0;
+        }
+
         this.nodeMetrics.push({ host: host, disk: aggregatedDisk });
       });
     } else if (diskData.length > 0) {
-      // Fallback for cases without host field
+      // Fallback for single node without host info
       this.nodeMetrics.push({ host: 'Node 1', disk: diskData[0] });
     }
   }
@@ -1844,12 +2117,102 @@
     this.applyThemeToOption(this.diskChartOption);
   }
 
+  updateDiskIOChart() {
+    const isDark = document.body.classList.contains('dark-theme');
+    const colors = this.getThemeColors(isDark);
+
+    if (this.historicalDiskIOMetrics && this.historicalDiskIOMetrics.length > 0) {
+      const hosts = Array.from(new Set(this.historicalDiskIOMetrics.map((m: any) => m.host))).filter(h => h).sort();
+
+      // If no host field, fallback to single line (legacy)
+      if (hosts.length === 0) {
+        // ... existing single line logic or fallback ...
+        // Actually, if hosts are missing, we can treat it as one "Node"
+        hosts.push('Node');
+      }
+
+      const series: any[] = [];
+      const legendData: string[] = [];
+      const palette = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'];
+
+      hosts.forEach((host: any, idx) => {
+        const hostMetrics = this.historicalDiskIOMetrics.filter((m: any) => m.host === host || (hosts.length === 1 && hosts[0] === 'Node'));
+        const data: any[] = [];
+
+        // Group by time in case of duplicates, though unlikely for disk_io if strictly per host
+        const byTime = hostMetrics.reduce((acc: any, item: any) => {
+          acc[item.time] = item;
+          return acc;
+        }, {});
+
+        Object.keys(byTime).sort().forEach(time => {
+          data.push([new Date(time).getTime(), byTime[time].disk_io_percent || 0]);
+        });
+
+        const color = palette[idx % palette.length];
+
+        series.push({
+          name: host,
+          type: 'line',
+          data: data,
+          showSymbol: false,
+          smooth: true,
+          itemStyle: { color: color },
+          lineStyle: { color: color, width: 2 }
+        });
+        legendData.push(host);
+      });
+
+      this.diskIOChartOption = {
+        tooltip: {
+          trigger: 'axis',
+          formatter: (params: any) => {
+            const date = new Date(params[0].value[0]);
+            const formattedTime = date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false });
+            let res = `Time: ${formattedTime}<br/>`;
+            params.forEach((p: any) => {
+              res += `${p.marker} ${p.seriesName}: ${p.value[1].toFixed(2)}%<br/>`;
+            });
+            return res;
+          }
+        },
+        legend: {
+          data: legendData,
+          bottom: 0,
+          textStyle: { color: colors.textMain }
+        },
+        grid: {
+          left: '5%', right: '4%', bottom: '15%', top: '10%', containLabel: true
+        },
+        xAxis: {
+          type: 'time',
+          splitLine: { show: false },
+          axisLabel: { color: colors.textMuted }
+        },
+        yAxis: {
+          type: 'value',
+          name: 'Disk I/O %',
+          splitLine: { show: true, lineStyle: { type: 'dashed', color: isDark ? '#505050' : '#e0e0e0' } },
+          axisLabel: { color: colors.textMuted },
+          nameTextStyle: { color: colors.textMuted }
+        },
+        series: series
+      };
+
+    } else {
+      this.diskIOChartOption = this._chartOptions.getNoDataChartOptions();
+    }
+
+    this.applyThemeToOption(this.diskIOChartOption, isDark);
+  }
+
   updateChartTheme(isDark: boolean) {
     this.applyThemeToOption(this.diskChartOption, isDark);
+    this.applyThemeToOption(this.diskIOChartOption, isDark);
     this.diskChartOption = { ...this.diskChartOption };
+    this.diskIOChartOption = { ...this.diskIOChartOption };
   }
 
-  // REPLICATED LOGIC
   getMultiNodeDiskChartOptions(isDark?: boolean): EChartsOption {
     const themeColors = this.getThemeColors(isDark || document.body.classList.contains('dark-theme'));
 
@@ -1863,14 +2226,14 @@
     const isSingleNode = nodeCount === 1;
 
     // Adjust grid to reduce height for single node
-    const gridTop = isSingleNode ? '25%' : '20%'; // Need space for title
+    const gridTop = isSingleNode ? '25%' : '20%';
     const gridBottom = isSingleNode ? '35%' : '15%';
 
     // Bar width (thickness) - smaller for single node
     const barWidth = isSingleNode ? '40%' : undefined; // undefined = auto
 
-    // Create simple node labels (Node 1, Node 2, etc.)
-    const nodeLabels = this.nodeMetrics.map((_, index) => `Node ${index + 1}`);
+    // Create simple node labels
+    const nodeLabels = this.nodeMetrics.map((n, index) => n.host || `Node ${index + 1}`);
 
     return {
       title: {
@@ -1890,9 +2253,6 @@
         borderColor: isDark ? '#616161' : '#ccc',
         textStyle: { color: themeColors.textMain },
         confine: true,
-        position: function (point: any, params: any, dom: any, rect: any, size: any) {
-          return [point[0] + 20, point[1] - size.contentSize[1] / 2];
-        },
         formatter: (params: any) => {
           const nodeIndex = params[0].dataIndex;
           const node = this.nodeMetrics[nodeIndex];
@@ -1914,35 +2274,19 @@
         textStyle: { color: themeColors.textMain }
       },
       grid: {
-        left: '18%',
-        right: '5%',
-        bottom: gridBottom,
-        top: gridTop,
-        containLabel: false
+        left: '18%', right: '5%', bottom: gridBottom, top: gridTop, containLabel: false
       },
       xAxis: {
         type: 'value',
         max: 100,
-        axisLabel: {
-          formatter: '{value}%',
-          color: themeColors.textMuted,
-          fontSize: 11
-        },
-        splitLine: {
-          lineStyle: { color: isDark ? '#505050' : '#e0e0e0' }
-        }
+        axisLabel: { formatter: '{value}%', color: themeColors.textMuted, fontSize: 11 },
+        splitLine: { lineStyle: { color: isDark ? '#505050' : '#e0e0e0' } }
       },
       yAxis: {
         type: 'category',
         data: nodeLabels,
-        axisLabel: {
-          color: themeColors.textMain,
-          fontSize: 11,
-          fontWeight: 500
-        },
-        axisLine: {
-          lineStyle: { color: isDark ? '#616161' : '#ccc' }
-        }
+        axisLabel: { color: themeColors.textMain, fontSize: 11, fontWeight: 500 },
+        axisLine: { lineStyle: { color: isDark ? '#616161' : '#ccc' } }
       },
       series: [
         {
@@ -1951,19 +2295,8 @@
           stack: 'total',
           data: usedData,
           barWidth: barWidth,
-          emphasis: { focus: 'none' }, // DISABLE FADE
-          itemStyle: {
-            color: themeColors.orange,
-            borderRadius: [0, 0, 0, 0]
-          },
-          label: {
-            show: true,
-            position: 'inside',
-            formatter: (params: any) => params.value > 10 ? `${params.value.toFixed(1)}%` : '',
-            color: '#fff',
-            fontWeight: 600,
-            fontSize: 11
-          }
+          itemStyle: { color: themeColors.orange, borderRadius: [0, 0, 0, 0] },
+          label: { show: true, position: 'inside', formatter: (params: any) => params.value > 10 ? `${params.value.toFixed(1)}%` : '', color: '#fff', fontWeight: 600, fontSize: 11 }
         },
         {
           name: 'Free',
@@ -1971,19 +2304,8 @@
           stack: 'total',
           data: freeData,
           barWidth: barWidth,
-          emphasis: { focus: 'none' }, // DISABLE FADE
-          itemStyle: {
-            color: themeColors.green,
-            borderRadius: [0, 4, 4, 0]
-          },
-          label: {
-            show: true,
-            position: 'inside',
-            formatter: (params: any) => params.value > 10 ? `${params.value.toFixed(1)}%` : '',
-            color: '#fff',
-            fontWeight: 600,
-            fontSize: 11
-          }
+          itemStyle: { color: themeColors.green, borderRadius: [0, 4, 4, 0] },
+          label: { show: true, position: 'inside', formatter: (params: any) => params.value > 10 ? `${params.value.toFixed(1)}%` : '', color: '#fff', fontWeight: 600, fontSize: 11 }
         }
       ]
     };
@@ -1992,9 +2314,7 @@
   getThemeColors(isDark: boolean): any {
     return {
       textMain: isDark ? '#e0e0e0' : '#333333',
-      bgMuted: isDark ? '#2c2c2c' : '#f0f0f0',
-      bg: isDark ? '#424242' : '#ffffff',
-      accent: '#1170cf',
+      textMuted: isDark ? '#a0a0a0' : '#777777',
       green: isDark ? '#a5d6a7' : '#4caf50',
       orange: isDark ? '#ffcc80' : '#ff9800',
       teal: isDark ? '#80cbc4' : '#009688'
@@ -2012,13 +2332,21 @@
     return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
   }
 
+  formatBits(bits: number, decimals = 2): string {
+    if (bits <= 0) return '0 bps';
+    const k = 1000;
+    const dm = decimals < 0 ? 0 : decimals;
+    const sizes = ['bps', 'Kbps', 'Mbps', 'Gbps', 'Tbps', 'Pbps', 'Ebps', 'Zbps', 'Ybps'];
+    let i = Math.floor(Math.log(bits) / Math.log(k));
+    if (i < 0) i = 0;
+    if (i >= sizes.length) i = sizes.length - 1;
+    return parseFloat((bits / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
+  }
+
   applyThemeToOption(option: any, isDark_in?: boolean) {
     if (!option) return;
     const isDark = isDark_in !== undefined ? isDark_in : document.body.classList.contains('dark-theme');
-    const colors = {
-      textMain: isDark ? '#e0e0e0' : '#333333',
-      textMuted: isDark ? '#a0a0a0' : '#777777'
-    };
+    const colors = { textMain: isDark ? '#e0e0e0' : '#333333', textMuted: isDark ? '#a0a0a0' : '#777777' };
     option.backgroundColor = 'transparent';
     if (option.tooltip) {
       option.tooltip.backgroundColor = isDark ? '#424242' : '#fff';
@@ -2026,17 +2354,11 @@
       if (!option.tooltip.textStyle) option.tooltip.textStyle = {};
       option.tooltip.textStyle.color = colors.textMain;
     }
-    if (option.legend) {
-      if (!option.legend.textStyle) option.legend.textStyle = {};
-      option.legend.textStyle.color = colors.textMain;
-    }
     const applyAxisTheme = (axis: any) => {
       if (!axis) return;
       if (Array.isArray(axis)) { axis.forEach(a => applyAxisTheme(a)); return; }
       if (!axis.axisLabel) axis.axisLabel = {};
       axis.axisLabel.color = colors.textMuted;
-      if (!axis.nameTextStyle) axis.nameTextStyle = {};
-      axis.nameTextStyle.color = colors.textMuted;
     };
     applyAxisTheme(option.xAxis);
     applyAxisTheme(option.yAxis);
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-disk-usage.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-disk-usage.html	(revision 2927)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-disk-usage.html	(working copy)
@@ -1,7 +1,8 @@
 <h2 mat-dialog-title>System Disk Usage (Live)</h2>
-<mat-dialog-content>
-  <div class="metrics-container" style="height: 100%; min-height: 300px;">
-    <div echarts [autoResize]="true" [options]="diskChartOption" class="chart-container" style="height: 300px;"></div>
+<mat-dialog-content class="metrics-dialog-content">
+  <div class="metrics-container" style="display: flex; flex-direction: column; gap: 20px; height: 100%; min-height: 600px;">
+    <div echarts [autoResize]="true" [options]="diskChartOption" class="chart-container" style="height: 300px; width: 100%;"></div>
+    <div echarts [autoResize]="true" [options]="diskIOChartOption" class="chart-container" style="height: 300px; width: 100%;"></div>
   </div>
 </mat-dialog-content>
 <mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/controller/system_metrics.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/controller/system_metrics.py	(revision 2927)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/controller/system_metrics.py	(working copy)
@@ -30,7 +30,8 @@
 def handle_get_historical_system_metrics(request, path=None):
     try:
         if request.method == 'GET':
-            status_data = get_historical_system_metrics()
+            host = request.GET.get('host', None)
+            status_data = get_historical_system_metrics(host=host)
             return JsonResponse(status_data, safe=False)
         else:
             return JsonResponse({
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/repositories/system_metrics.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/repositories/system_metrics.py	(revision 2927)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/repositories/system_metrics.py	(working copy)
@@ -46,36 +46,61 @@
 
     @staticmethod
     @with_db_connection
-    def get_latest_disk_io(cur, host="AN"):
-        disk_query = """
-                         SELECT
+    def get_latest_disk_io(cur, host=None):
+        if host:
+            host_filter = "AND host = %s"
+            params = (host,)
+        else:
+            host_filter = ""
+            params = ()
+
+        disk_query = f"""
+                         SELECT DISTINCT ON (host)
+                             host,
                              bucket_time,
                              ROUND(LEAST((SUM(io_time_total_ms) * 100.0 / 60000), 100), 2) AS disk_io_percent,
                              ROUND(SUM(read_bytes_diff) / GREATEST(1, SUM(time_diff_sec)), 2) AS read_speed_bps,
                              ROUND(SUM(write_bytes_diff) / GREATEST(1, SUM(time_diff_sec)), 2) AS write_speed_bps
                          FROM (
                                   SELECT
+                                      host,
                                       time_bucket('1 minute', time) AS bucket_time,
-                                      GREATEST(io_time::BIGINT - LAG(io_time) OVER (PARTITION BY host ORDER BY time), 0) AS io_time_total_ms,
-                                      GREATEST(read_bytes::BIGINT - LAG(read_bytes) OVER (PARTITION BY host ORDER BY time), 0) AS read_bytes_diff,
-                                      GREATEST(write_bytes::BIGINT - LAG(write_bytes) OVER (PARTITION BY host ORDER BY time), 0) AS write_bytes_diff,
-                                      EXTRACT(EPOCH FROM (time - LAG(time) OVER (PARTITION BY host ORDER BY time))) AS time_diff_sec
+                                      GREATEST(io_time::BIGINT - LAG(io_time) OVER (PARTITION BY host, name ORDER BY time), 0) AS io_time_total_ms,
+                                      GREATEST(read_bytes::BIGINT - LAG(read_bytes) OVER (PARTITION BY host, name ORDER BY time), 0) AS read_bytes_diff,
+                                      GREATEST(write_bytes::BIGINT - LAG(write_bytes) OVER (PARTITION BY host, name ORDER BY time), 0) AS write_bytes_diff,
+                                      EXTRACT(EPOCH FROM (time - LAG(time) OVER (PARTITION BY host, name ORDER BY time))) AS time_diff_sec
                                   FROM diskio
-                                  WHERE time > (NOW() AT TIME ZONE 'UTC') - INTERVAL '5 minutes'
+                                  WHERE time > (NOW() AT TIME ZONE 'UTC') - INTERVAL '15 minutes'
+                                  {host_filter}
                               ) sub
                          WHERE io_time_total_ms IS NOT NULL
-                         GROUP BY bucket_time
-                         ORDER BY bucket_time DESC
-                         LIMIT 1;
+                         GROUP BY host, bucket_time
+                         ORDER BY host, bucket_time DESC;
                          """
-        cur.execute(disk_query)
-        result = cur.fetchone()
+        cur.execute(disk_query, params)
+        results = cur.fetchall()
         cur.close()
-        if result:
-            time, disk_io_percent, read_speed, write_speed = result
+
+        if not results:
+            return None
+
+        # If single host, return single object for backward compatibility
+        if len(results) == 1:
+            host, time, disk_io_percent, read_speed, write_speed = results[0]
             return SystemMetrics(time=time, host=host, disk_io_percent=disk_io_percent, read_speed=read_speed,
                                  write_speed=write_speed)
-        return None
+
+        # Multi-node: return list of metrics per host
+        metrics_list = []
+        for host, time, disk_io_percent, read_speed, write_speed in results:
+            metrics_list.append(SystemMetrics(
+                time=time,
+                host=host,
+                disk_io_percent=disk_io_percent,
+                read_speed=read_speed,
+                write_speed=write_speed
+            ))
+        return [m.to_dict() for m in metrics_list]
 
     @staticmethod
     @with_db_connection
@@ -204,12 +229,12 @@
             params = ()
         
         net_query = f"""
-                    SELECT
+                    SELECT DISTINCT ON (host, interface)
                         host,
                         bucket_time,
                         interface,
-                        ROUND(SUM(bytes_sent_diff) / GREATEST(1, SUM(time_diff_sec)), 2) AS sent,
-                        ROUND(SUM(bytes_recv_diff) / GREATEST(1, SUM(time_diff_sec)), 2) AS received
+                        ROUND(SUM(bytes_sent_diff) * 8 / GREATEST(1, SUM(time_diff_sec)), 2) AS sent,
+                        ROUND(SUM(bytes_recv_diff) * 8 / GREATEST(1, SUM(time_diff_sec)), 2) AS received
                     FROM (
                              SELECT
                                  host,
@@ -225,8 +250,7 @@
                          ) sub
                     WHERE bytes_sent_diff IS NOT NULL
                     GROUP BY host, bucket_time, interface
-                    ORDER BY host, bucket_time DESC
-                    LIMIT 10;
+                    ORDER BY host, interface, bucket_time DESC;
                     """
         cur.execute(net_query, params)
         results = cur.fetchall()
@@ -245,17 +269,41 @@
 
     @staticmethod
     @with_db_connection
-    def get_historical_cpu(cur, bucket_interval, start_time, end_time, host='AN'):
-        cpu_query = """
-                    SELECT time_bucket(%s, time)        AS bucket_time,
+    def get_historical_cpu(cur, bucket_interval, start_time, end_time, host=None):
+        if host:
+            host_filter = "AND host = %s"
+            params = (bucket_interval, start_time, end_time, host)
+        else:
+            host_filter = ""
+            params = (bucket_interval, start_time, end_time)
+
+        cpu_query = f"""
+                    SELECT time_bucket('%s', time)        AS bucket_time,
                            last(100 - usage_idle, time) AS cpu_usage
                     FROM cpu
                     WHERE time BETWEEN %s AND %s
                       AND cpu = 'cpu-total'
+                      {host_filter}
                     GROUP BY bucket_time
                     ORDER BY bucket_time ASC; \
                     """
-        cur.execute(cpu_query, (bucket_interval, start_time, end_time))
+        # Execute with params directly to avoid string formatting issues if bucket_interval is safe
+        # Note: bucket_interval in time_bucket usually can't be parameterized as a string literal 
+        # but here we follow the pattern. 
+        # Safer to use f-string for query construction if params are trusted or validated.
+        
+        cpu_query = f"""
+                    SELECT time_bucket(%s, time)        AS bucket_time,
+                           last(100 - usage_idle, time) AS cpu_usage
+                    FROM cpu
+                    WHERE time BETWEEN %s AND %s
+                      AND cpu = 'cpu-total'
+                      {host_filter}
+                    GROUP BY bucket_time
+                    ORDER BY bucket_time ASC;
+                    """
+        
+        cur.execute(cpu_query, params)
         results = cur.fetchall()
         cur.close()
 
@@ -263,23 +311,31 @@
         for time_bucket, usage in results:
             metrics_list.append(SystemMetrics(
                 time=time_bucket,
-                host=host,
+                host=host if host else 'All',
                 cpu_percent=usage
             ))
         return [m.to_dict() for m in metrics_list]
 
     @staticmethod
     @with_db_connection
-    def get_historical_memory(cur, bucket_interval, start_time, end_time, host='AN'):
-        mem_query = """
+    def get_historical_memory(cur, bucket_interval, start_time, end_time, host=None):
+        if host:
+            host_filter = "AND host = %s"
+            params = (bucket_interval, start_time, end_time, host)
+        else:
+            host_filter = ""
+            params = (bucket_interval, start_time, end_time)
+
+        mem_query = f"""
                     SELECT time_bucket(%s, time)    AS bucket_time,
                            last(used_percent, time) AS mem_usage
                     FROM mem
                     WHERE time BETWEEN %s AND %s
+                    {host_filter}
                     GROUP BY bucket_time
                     ORDER BY bucket_time ASC; \
                     """
-        cur.execute(mem_query, (bucket_interval, start_time, end_time))
+        cur.execute(mem_query, params)
         results = cur.fetchall()
         cur.close()
 
@@ -287,34 +343,45 @@
         for time_bucket, usage in results:
             metrics_list.append(SystemMetrics(
                 time=time_bucket,
-                host=host,
+                host=host if host else 'All',
                 mem_percent=usage
             ))
         return [m.to_dict() for m in metrics_list]
 
     @staticmethod
     @with_db_connection
-    def get_historical_disk_io(cur, bucket_interval, start_time, end_time, host='AN'):
-        disk_io_query = """
-                       SELECT bucket_time,
+    def get_historical_disk_io(cur, bucket_interval, start_time, end_time, host=None):
+        if host:
+            host_filter = "AND host = %s"
+            params = (start_time, end_time, host)
+        else:
+            host_filter = ""
+            params = (start_time, end_time)
+
+        disk_io_query = f"""
+                       SELECT host,
+                              bucket_time,
                               ROUND(LEAST((disk_io_total_ms * 100.0 / 60000), 100), 2) AS disk_io_percent
-                       FROM (SELECT time_bucket('1 minute', time)                            AS bucket_time,
+                       FROM (SELECT host,
+                                    time_bucket('1 minute', time)                            AS bucket_time,
                                     SUM(GREATEST(io_time::BIGINT - prev_io_time::BIGINT, 0)) AS disk_io_total_ms
                              FROM (SELECT time,
+                                          host,
                                           io_time,
-                                          LAG(io_time) OVER (PARTITION BY host ORDER BY time) AS prev_io_time
+                                          LAG(io_time) OVER (PARTITION BY host, name ORDER BY time) AS prev_io_time
                                    FROM diskio
-                                   WHERE time BETWEEN %s AND %s) sub
+                                   WHERE time BETWEEN %s AND %s
+                                   {host_filter}) sub
                              WHERE prev_io_time IS NOT NULL
-                             GROUP BY bucket_time) final
-                       ORDER BY bucket_time ASC; \
+                             GROUP BY host, bucket_time) final
+                       ORDER BY host, bucket_time ASC; \
                        """
-        cur.execute(disk_io_query, (start_time, end_time))
+        cur.execute(disk_io_query, params)
         results = cur.fetchall()
         cur.close()
 
         metrics_list = []
-        for time_bucket, usage in results:
+        for host, time_bucket, usage in results:
             metrics_list.append(SystemMetrics(
                 time=time_bucket,
                 host=host,
@@ -324,14 +391,23 @@
 
     @staticmethod
     @with_db_connection
-    def get_historical_throughput(cur, bucket_interval, start_time, end_time, host='AN'):
-        net_query = """
-                    SELECT bucket_time,
+    def get_historical_throughput(cur, bucket_interval, start_time, end_time, host=None):
+        if host:
+            host_filter = "AND host = %s"
+            params = (start_time, end_time, host)
+        else:
+            host_filter = ""
+            params = (start_time, end_time)
+
+        net_query = f"""
+                    SELECT host,
+                           bucket_time,
                            interface,
                            ROUND(SUM(bytes_sent_diff) * 8 / GREATEST(1, SUM(time_diff_sec)),
                                  2)                                                                       AS sent,
                            ROUND(SUM(bytes_recv_diff) * 8 / GREATEST(1, SUM(time_diff_sec)), 2) AS received
-                    FROM (SELECT time_bucket('1 minute', time)                                                            AS bucket_time,
+                    FROM (SELECT host,
+                                 time_bucket('1 minute', time)                                                            AS bucket_time,
                                  interface,
                                  GREATEST(bytes_sent::BIGINT -
                                           LAG(bytes_sent) OVER (PARTITION BY host, interface ORDER BY time),
@@ -343,17 +419,18 @@
                                          (time - LAG(time) OVER (PARTITION BY host, interface ORDER BY time)))            AS time_diff_sec
                           FROM net
                           WHERE interface NOT LIKE 'lo' AND interface NOT LIKE 'all'
-                            AND time BETWEEN %s AND %s) sub
+                            AND time BETWEEN %s AND %s
+                            {host_filter}) sub
                     WHERE bytes_sent_diff IS NOT NULL
-                    GROUP BY bucket_time, interface
-                    ORDER BY bucket_time ASC; \
+                    GROUP BY host, bucket_time, interface
+                    ORDER BY host, interface, bucket_time DESC; \
                     """
-        cur.execute(net_query, (start_time, end_time))
+        cur.execute(net_query, params)
         results = cur.fetchall()
         cur.close()
 
         metrics_list = []
-        for time, interface, sent, received in results:
+        for host, time, interface, sent, received in results:
             metrics_list.append(NetworkMetrics(
                 time=time,
                 host=host,
@@ -362,3 +439,4 @@
                 received=received
             ))
         return [m.to_dict() for m in metrics_list]
+
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/services/system_metrics.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/services/system_metrics.py	(revision 2927)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/services/system_metrics.py	(working copy)
@@ -5,13 +5,14 @@
 
 from concurrent.futures import ThreadPoolExecutor
 
-def get_latest_system_metrics():
+
+def get_latest_system_metrics(host=None):
     with ThreadPoolExecutor() as executor:
-        future_cpu = executor.submit(SystemMetricsRepo.get_latest_cpu)
-        future_mem = executor.submit(SystemMetricsRepo.get_latest_memory)
-        future_disk_io = executor.submit(SystemMetricsRepo.get_latest_disk_io)
-        future_disk = executor.submit(SystemMetricsRepo.get_latest_disk_usage)
-        future_net = executor.submit(SystemMetricsRepo.get_latest_throughput)
+        future_cpu = executor.submit(SystemMetricsRepo.get_latest_cpu, host)
+        future_mem = executor.submit(SystemMetricsRepo.get_latest_memory, host)
+        future_disk_io = executor.submit(SystemMetricsRepo.get_latest_disk_io, host)
+        future_disk = executor.submit(SystemMetricsRepo.get_latest_disk_usage, host)
+        future_net = executor.submit(SystemMetricsRepo.get_latest_throughput, host)
 
         cpu_metrics = future_cpu.result()
         mem_metrics = future_mem.result()
@@ -20,53 +21,53 @@
         net_metrics = future_net.result()
 
     return {
-        'cpu': cpu_metrics.to_dict() if cpu_metrics else None,
-        'memory': mem_metrics.to_dict() if mem_metrics else None,
-        'disk_io': disk_io_metrics.to_dict() if disk_io_metrics else None,
+        'cpu': cpu_metrics.to_dict() if cpu_metrics and not isinstance(cpu_metrics, list) else cpu_metrics,
+        'memory': mem_metrics.to_dict() if mem_metrics and not isinstance(mem_metrics, list) else mem_metrics,
+        'disk_io': disk_io_metrics.to_dict() if disk_io_metrics and not isinstance(disk_io_metrics, list) else disk_io_metrics,
         'disk_usage': disk_metrics,
         'net_metrics': net_metrics
     }
 
 
 # --- LAST 1HOUR METRICS FUNCTIONS ---
-def _get_historical_cpu_metrics(hours=1):
+def _get_historical_cpu_metrics(hours=1, host=None):
     now_utc_aware = datetime.now(timezone.utc)
     end_time = now_utc_aware.replace(tzinfo=None)
     start_time = end_time - timedelta(hours=hours)
     bucket_interval = '1 minute'
-    return SystemMetricsRepo.get_historical_cpu(bucket_interval, start_time, end_time)
+    return SystemMetricsRepo.get_historical_cpu(bucket_interval, start_time, end_time, host)
 
 
-def _get_historical_mem_metrics(hours=1):
+def _get_historical_mem_metrics(hours=1, host=None):
     now_utc_aware = datetime.now(timezone.utc)
     end_time = now_utc_aware.replace(tzinfo=None)
     start_time = end_time - timedelta(hours=hours)
     bucket_interval = '1 minute'
-    return SystemMetricsRepo.get_historical_memory(bucket_interval, start_time, end_time)
+    return SystemMetricsRepo.get_historical_memory(bucket_interval, start_time, end_time, host)
 
 
-def _get_historical_disk_io_metrics(hours=1):
+def _get_historical_disk_io_metrics(hours=1, host=None):
     now_utc_aware = datetime.now(timezone.utc)
     end_time = now_utc_aware.replace(tzinfo=None)
     start_time = end_time - timedelta(hours=hours)
     bucket_interval = '1 minute'
-    return SystemMetricsRepo.get_historical_disk_io(bucket_interval, start_time, end_time)
+    return SystemMetricsRepo.get_historical_disk_io(bucket_interval, start_time, end_time, host)
 
 
-def _get_historical_net_metrics(hours=1):
+def _get_historical_net_metrics(hours=1, host=None):
     now_utc_aware = datetime.now(timezone.utc)
     end_time = now_utc_aware.replace(tzinfo=None)
     start_time = end_time - timedelta(hours=hours)
     bucket_interval = '1 minute'
-    return SystemMetricsRepo.get_historical_throughput(bucket_interval, start_time, end_time)
+    return SystemMetricsRepo.get_historical_throughput(bucket_interval, start_time, end_time, host)
 
 
-def get_historical_system_metrics():
+def get_historical_system_metrics(host=None):
     with ThreadPoolExecutor() as executor:
-        future_cpu = executor.submit(_get_historical_cpu_metrics)
-        future_mem = executor.submit(_get_historical_mem_metrics)
-        future_disk_io = executor.submit(_get_historical_disk_io_metrics)
-        future_net = executor.submit(_get_historical_net_metrics)
+        future_cpu = executor.submit(_get_historical_cpu_metrics, 1, host)
+        future_mem = executor.submit(_get_historical_mem_metrics, 1, host)
+        future_disk_io = executor.submit(_get_historical_disk_io_metrics, 1, host)
+        future_net = executor.submit(_get_historical_net_metrics, 1, host)
 
         cpu_metrics = future_cpu.result()
         mem_metrics = future_mem.result()
@@ -79,3 +80,4 @@
         'disk_io_history': disk_io_metrics,
         'net_history': net_metrics
     }
+
