Index: /branches/amp_4_0/platform/tools/container/services/postgres/initdb.d/01_system_metrics.sql
===================================================================
--- /branches/amp_4_0/platform/tools/container/services/postgres/initdb.d/01_system_metrics.sql	(nonexistent)
+++ /branches/amp_4_0/platform/tools/container/services/postgres/initdb.d/01_system_metrics.sql	(working copy)
@@ -0,0 +1,175 @@
+-- 01_system_metrics.sql
+-- System Metrics Tables for Telegraf -> TimescaleDB
+
+BEGIN;
+
+\c amp_ts
+
+-- ============================================================================
+-- CPU Metrics
+-- ============================================================================
+CREATE TABLE IF NOT EXISTS cpu (
+    time TIMESTAMPTZ NOT NULL,
+    host TEXT,
+    cpu TEXT,
+    usage_guest DOUBLE PRECISION,
+    usage_guest_nice DOUBLE PRECISION,
+    usage_idle DOUBLE PRECISION,
+    usage_iowait DOUBLE PRECISION,
+    usage_irq DOUBLE PRECISION,
+    usage_nice DOUBLE PRECISION,
+    usage_softirq DOUBLE PRECISION,
+    usage_steal DOUBLE PRECISION,
+    usage_system DOUBLE PRECISION,
+    usage_user DOUBLE PRECISION
+);
+
+-- Create hypertable for time-series optimization
+SELECT create_hypertable('cpu', 'time', if_not_exists => TRUE);
+
+-- Create index for faster queries
+CREATE INDEX IF NOT EXISTS idx_cpu_time_host ON cpu (time DESC, host, cpu);
+
+-- ============================================================================
+-- Memory Metrics
+-- ============================================================================
+CREATE TABLE IF NOT EXISTS mem (
+    time TIMESTAMPTZ NOT NULL,
+    host TEXT,
+    active BIGINT,
+    available BIGINT,
+    available_percent DOUBLE PRECISION,
+    buffered BIGINT,
+    cached BIGINT,
+    commit_limit BIGINT,
+    committed_as BIGINT,
+    dirty BIGINT,
+    free BIGINT,
+    high_free BIGINT,
+    high_total BIGINT,
+    huge_page_size BIGINT,
+    huge_pages_free BIGINT,
+    huge_pages_total BIGINT,
+    inactive BIGINT,
+    low_free BIGINT,
+    low_total BIGINT,
+    mapped BIGINT,
+    page_tables BIGINT,
+    shared BIGINT,
+    slab BIGINT,
+    sreclaimable BIGINT,
+    sunreclaim BIGINT,
+    swap_cached BIGINT,
+    swap_free BIGINT,
+    swap_total BIGINT,
+    total BIGINT,
+    used BIGINT,
+    used_percent DOUBLE PRECISION,
+    vmalloc_chunk BIGINT,
+    vmalloc_total BIGINT,
+    vmalloc_used BIGINT,
+    write_back BIGINT,
+    write_back_tmp BIGINT
+);
+
+SELECT create_hypertable('mem', 'time', if_not_exists => TRUE);
+CREATE INDEX IF NOT EXISTS idx_mem_time_host ON mem (time DESC, host);
+
+-- ============================================================================
+-- Disk Usage Metrics
+-- ============================================================================
+CREATE TABLE IF NOT EXISTS disk (
+    time TIMESTAMPTZ NOT NULL,
+    host TEXT,
+    device TEXT,
+    path TEXT,
+    fstype TEXT,
+    mode TEXT,
+    free BIGINT,
+    inodes_free BIGINT,
+    inodes_total BIGINT,
+    inodes_used BIGINT,
+    total BIGINT,
+    used BIGINT,
+    used_percent DOUBLE PRECISION,
+    label TEXT,
+    inodes_used_percent DOUBLE PRECISION
+);
+
+SELECT create_hypertable('disk', 'time', if_not_exists => TRUE);
+CREATE INDEX IF NOT EXISTS idx_disk_time_host_device ON disk (time DESC, host, device);
+CREATE INDEX IF NOT EXISTS idx_disk_fstype ON disk (fstype);
+
+-- ============================================================================
+-- Disk I/O Metrics
+-- ============================================================================
+CREATE TABLE IF NOT EXISTS diskio (
+    time TIMESTAMPTZ NOT NULL,
+    host TEXT,
+    name TEXT,
+    serial TEXT,
+    io_time BIGINT,
+    iops_in_progress BIGINT,
+    merged_reads BIGINT,
+    merged_writes BIGINT,
+    read_bytes BIGINT,
+    read_time BIGINT,
+    reads BIGINT,
+    weighted_io_time BIGINT,
+    write_bytes BIGINT,
+    write_time BIGINT,
+    writes BIGINT
+);
+
+SELECT create_hypertable('diskio', 'time', if_not_exists => TRUE);
+CREATE INDEX IF NOT EXISTS idx_diskio_time_host ON diskio (time DESC, host);
+
+-- ============================================================================
+-- Network Metrics
+-- ============================================================================
+CREATE TABLE IF NOT EXISTS net (
+    time TIMESTAMPTZ NOT NULL,
+    host TEXT,
+    interface TEXT,
+    bytes_recv BIGINT,
+    bytes_sent BIGINT,
+    drop_in BIGINT,
+    drop_out BIGINT,
+    err_in BIGINT,
+    err_out BIGINT,
+    packets_recv BIGINT,
+    packets_sent BIGINT
+);
+
+SELECT create_hypertable('net', 'time', if_not_exists => TRUE);
+CREATE INDEX IF NOT EXISTS idx_net_time_host_interface ON net (time DESC, host, interface);
+
+-- ============================================================================
+-- System Metrics (load, uptime)
+-- ============================================================================
+CREATE TABLE IF NOT EXISTS system (
+    time TIMESTAMPTZ NOT NULL,
+    host TEXT,
+    load1 DOUBLE PRECISION,
+    load5 DOUBLE PRECISION,
+    load15 DOUBLE PRECISION,
+    n_cpus INTEGER,
+    n_users INTEGER,
+    uptime BIGINT,
+    uptime_format TEXT
+);
+
+SELECT create_hypertable('system', 'time', if_not_exists => TRUE);
+CREATE INDEX IF NOT EXISTS idx_system_time_host ON system (time DESC, host);
+
+-- ============================================================================
+-- Set retention policies
+-- ============================================================================
+SELECT add_retention_policy('cpu', INTERVAL '30 days', if_not_exists => TRUE);
+SELECT add_retention_policy('mem', INTERVAL '30 days', if_not_exists => TRUE);
+SELECT add_retention_policy('disk', INTERVAL '30 days', if_not_exists => TRUE);
+SELECT add_retention_policy('diskio', INTERVAL '30 days', if_not_exists => TRUE);
+SELECT add_retention_policy('net', INTERVAL '30 days', if_not_exists => TRUE);
+SELECT add_retention_policy('system', INTERVAL '30 days', if_not_exists => TRUE);
+
+COMMIT;
Index: /branches/amp_4_0/platform/tools/container/services/telegraf/telegraf.conf
===================================================================
--- /branches/amp_4_0/platform/tools/container/services/telegraf/telegraf.conf	(revision 2905)
+++ /branches/amp_4_0/platform/tools/container/services/telegraf/telegraf.conf	(working copy)
@@ -32,7 +32,7 @@
   percpu = true
   totalcpu = true
 [[inputs.disk]]
-  mount_points = ["/"]
+  mount_points = ["/rootfs", "/rootfs/home", "/rootfs/var"]
   ignore_fs = ["tmpfs", "devtmpfs", "overlay", "rootfs"]
 [[inputs.mem]]
 [[inputs.diskio]]
Index: /branches/amp_4_0/platform/tools/container/services/timescaledb/post_bootstrap.sh
===================================================================
--- /branches/amp_4_0/platform/tools/container/services/timescaledb/post_bootstrap.sh	(revision 2905)
+++ /branches/amp_4_0/platform/tools/container/services/timescaledb/post_bootstrap.sh	(working copy)
@@ -82,6 +82,11 @@
 
 # 4. Initialize Tables for AMP_TS (Hypertables)
 echo "Running initialization scripts for $AMP_DB..."
+if [ -f /docker-entrypoint-initdb.d/01_system_metrics.sql ]; then
+    echo "Executing 01_system_metrics.sql..."
+    psql -U postgres -d $AMP_DB -f /docker-entrypoint-initdb.d/01_system_metrics.sql
+fi
+
 if [ -f /docker-entrypoint-initdb.d/02_telegraf_snmp.sql ]; then
     echo "Executing 02_telegraf_snmp.sql..."
     # These scripts explicitly do '\c amp_ts', so we can connect to default and let script handle switch,
Index: /branches/amp_4_0/platform/tools/container/stack.yml
===================================================================
--- /branches/amp_4_0/platform/tools/container/stack.yml	(revision 2905)
+++ /branches/amp_4_0/platform/tools/container/stack.yml	(working copy)
@@ -39,6 +39,8 @@
     file: services/postgres/initdb.d/init_db.sql
   telegraf_snmp_sql:
     file: services/postgres/initdb.d/02_telegraf_snmp.sql
+  system_metrics_sql:
+    file: services/postgres/initdb.d/01_system_metrics.sql
   docker_metrics_sql:
     file: services/postgres/initdb.d/03_docker_metrics.sql
   # Certificate configs (created by manage_amp.sh from certs-vol)
@@ -175,6 +177,8 @@
         target: /docker-entrypoint-initdb.d/init_db.sql
       - source: telegraf_snmp_sql
         target: /docker-entrypoint-initdb.d/02_telegraf_snmp.sql
+      - source: system_metrics_sql
+        target: /docker-entrypoint-initdb.d/01_system_metrics.sql
       - source: docker_metrics_sql
         target: /docker-entrypoint-initdb.d/03_docker_metrics.sql
     secrets:
@@ -430,6 +434,7 @@
       - source: telegraf_asf_conf
         target: /etc/telegraf/telegraf.d/asf.toml
     volumes:
+      - /:/rootfs:ro
       - /var/run/docker.sock:/var/run/docker.sock
       - /dev:/dev:ro
       - /proc:/rootfs/proc:ro
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/djproject/settings.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/djproject/settings.py	(revision 2906)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/djproject/settings.py	(working copy)
@@ -106,6 +106,7 @@
 )
 SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
 CSRF_COOKIE_SECURE = True
+CSRF_TRUSTED_ORIGINS = ['http://localhost:4200', 'https://localhost:4200']
 ROOT_URLCONF = 'djproject.urls'
 
 # Python dotted the path to the WSGI application used by Django's runserver.
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/proxy.conf.json
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/proxy.conf.json	(revision 2905)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/proxy.conf.json	(working copy)
@@ -1,20 +1,14 @@
 {
-  "/api/v2/proxy_req_dev/api": {
-    "target": "http://192.168.85.41:8000",
+  "/api/v2/proxy_req_dev": {
+    "target": "https://192.168.162.139",
     "secure": false,
     "changeOrigin": true,
-    "pathRewrite": {
-      "^/api/v2": ""
-    },
     "logLevel": "debug"
   },
   "/api/v2": {
-    "target": "http://192.168.85.41:8000",
+    "target": "https://192.168.162.139",
     "secure": false,
     "changeOrigin": true,
-    "pathRewrite": {
-      "^/api/v2": ""
-    },
     "logLevel": "debug"
   }
 }
\ No newline at end of file
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/charts-config.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/charts-config.ts	(revision 2905)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/charts-config.ts	(working copy)
@@ -1,5 +1,5 @@
 import * as echarts from 'echarts/core';
-import {BarChart, LineChart, PictorialBarChart, PieChart} from 'echarts/charts';
+import { BarChart, GaugeChart, LineChart, PictorialBarChart, PieChart } from 'echarts/charts';
 
 import {
   DataZoomComponent, GraphicComponent,
@@ -10,10 +10,11 @@
   VisualMapComponent
 } from 'echarts/components';
 
-import {CanvasRenderer} from 'echarts/renderers';
+import { CanvasRenderer } from 'echarts/renderers';
 
 echarts.use([
   BarChart,
+  GaugeChart,
   LineChart,
   PieChart,
   PictorialBarChart,
@@ -28,4 +29,4 @@
 ]);
 
 
-export {echarts};
+export { echarts };
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 2905)
+++ /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)
@@ -87,18 +87,14 @@
         </mat-card-title>
       </div>
       <div class="card-body-content">
-        <div class="main-chart-layout centered-content">
-          <div class="chart-column chart-stack-container vertical-layout">
-            <div class="metric-item large-metric">
-              <span class="metric-value large-text">{{ networkMetrics?.sent | bytes }}</span>
-              <span class="metric-label">Sent</span>
-            </div>
-            <div class="metric-item large-metric">
-              <span class="metric-value large-text">{{ networkMetrics?.received | bytes }}</span>
-              <span class="metric-label">Received</span>
-            </div>
+        @if (nodeMetrics && nodeMetrics.length > 0) {
+        <div class="main-chart-layout centered-content" [ngClass]="{'single-node-chart': nodeMetrics.length === 1}">
+          <div echarts [autoResize]="true" [options]="networkThroughputChartOption2" class="chart-container full-width">
           </div>
         </div>
+        } @else {
+        <p class="status-details">No data available</p>
+        }
       </div>
     </mat-card-content>
   </mat-card>
@@ -112,21 +108,14 @@
             (click)="enlargeSystemDiskUsage()"></fa-icon>
         </mat-card-title>
       </div>
-      <div class="main-chart-layout centered-content">
-        <div class="chart-column chart-stack-container vertical-layout">
-          <div echarts [autoResize]="true" [options]="diskChartOption1" class="chart-container full-width-h-50"></div>
-          <div class="metric-details full-width-h-50">
-            <div class="metric-item">
-              <span class="metric-value">{{ diskMetrics?.used_bytes | bytes }}</span>
-              <span class="metric-label">Used</span>
-            </div>
-            <div class="metric-item">
-              <span class="metric-value">{{ diskMetrics?.free_bytes | bytes }}</span>
-              <span class="metric-label">Free</span>
-            </div>
-          </div>
-        </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>
+      } @else {
+      <p class="status-details">No data available</p>
+      }
     </mat-card-content>
   </mat-card>
 
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.scss
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.scss	(revision 2905)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.scss	(working copy)
@@ -156,6 +156,15 @@
   height: 100%;
 }
 
+/* Constrain width and height for single node */
+.single-node-chart {
+  max-width: 70%;
+  max-height: 180px;
+  margin: 0 auto;
+}
+
+
+
 /* The original vertical layout for metrics */
 .metrics-container {
   display: flex;
@@ -164,6 +173,14 @@
   gap: 20px;
 }
 
+/* Ensure the card content stays within bounds */
+/* Ensure the card content stays within bounds */
+.card-content-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+}
+
 /* Container to center content vertically and horizontally */
 .card-body-content {
   flex-grow: 1;
@@ -172,6 +189,23 @@
   align-items: center;
 }
 
+.chart-stack-container {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  width: 100%;
+  gap: 15px;
+}
+
+.full-width-h-50 {
+  width: 100%;
+  height: calc(50% - 15px);
+  /* Reduce height to account for gap */
+  flex-shrink: 1;
+}
+
+
+
 /* New CSS for the metrics block */
 .metrics-horizontal-container {
   display: flex;
@@ -311,4 +345,128 @@
   color: var(--text-muted);
   text-transform: uppercase;
   margin-top: 5px;
+}
+
+/* Disk Cards Layout */
+.disk-cards-container {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  width: 100%;
+  padding: 8px 0;
+}
+
+.disk-card {
+  background: var(--card-bg);
+  border: 1px solid rgba(0, 0, 0, 0.08);
+  border-radius: 8px;
+  padding: 12px 16px;
+  transition: all 0.2s ease;
+
+  &:hover {
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transform: translateY(-1px);
+  }
+}
+
+:host-context(.dark-theme) .disk-card {
+  border-color: rgba(255, 255, 255, 0.12);
+
+  &:hover {
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
+  }
+}
+
+.disk-card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 10px;
+}
+
+.node-hostname {
+  font-size: 0.95rem;
+  font-weight: 600;
+  color: var(--text-main);
+}
+
+.disk-percentage {
+  font-size: 1.1rem;
+  font-weight: 700;
+
+  &.status-healthy {
+    color: #4caf50;
+  }
+
+  &.status-warning {
+    color: #ff9800;
+  }
+
+  &.status-critical {
+    color: #f44336;
+  }
+}
+
+.progress-bar-container {
+  margin-bottom: 12px;
+}
+
+.progress-bar-bg {
+  width: 100%;
+  height: 8px;
+  background-color: rgba(0, 0, 0, 0.08);
+  border-radius: 4px;
+  overflow: hidden;
+}
+
+:host-context(.dark-theme) .progress-bar-bg {
+  background-color: rgba(255, 255, 255, 0.1);
+}
+
+.progress-bar-fill {
+  height: 100%;
+  border-radius: 4px;
+  transition: width 0.3s ease, background-color 0.3s ease;
+
+  &.fill-healthy {
+    background: linear-gradient(90deg, #4caf50 0%, #66bb6a 100%);
+  }
+
+  &.fill-warning {
+    background: linear-gradient(90deg, #ff9800 0%, #ffa726 100%);
+  }
+
+  &.fill-critical {
+    background: linear-gradient(90deg, #f44336 0%, #ef5350 100%);
+  }
+}
+
+.disk-card-details {
+  display: flex;
+  justify-content: space-between;
+  gap: 12px;
+}
+
+.detail-item {
+  display: flex;
+  flex-direction: column;
+  flex: 1;
+  min-width: 0;
+}
+
+.detail-label {
+  font-size: 0.75rem;
+  color: var(--text-muted);
+  text-transform: uppercase;
+  letter-spacing: 0.5px;
+  margin-bottom: 2px;
+}
+
+.detail-value {
+  font-size: 0.9rem;
+  font-weight: 600;
+  color: var(--text-main);
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
 }
\ No newline at end of file
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 2905)
+++ /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)
@@ -32,6 +32,7 @@
   systemLoadChartOption3: EChartsOption = {};
 
   networkThroughputChartOption1: EChartsOption = {};
+  networkThroughputChartOption2: EChartsOption = {};
 
   diskIOChartOption1: EChartsOption = {};
   diskChartOption1: EChartsOption = {};
@@ -39,6 +40,10 @@
   connectionChartOption1: EChartsOption = {};
   connectionChartOption2: EChartsOption = {};
 
+  // Multi-node support
+  isMultiNode: boolean = false;
+  nodeMetrics: any[] = []; // Array of {host, cpuChart, memChart, diskChart}
+
   private destroyRef = inject(DestroyRef);
   private deviceFacade = inject(DeviceFacade);
   private systemFacade = inject(SystemFacade);
@@ -87,11 +92,12 @@
       this.connectionChartOption2,
       this.devicesCPUChartOption1,
       this.devicesMemoryChartOption1,
-      this.devicesThroughputChartOption1
+      this.devicesThroughputChartOption1,
+      this.networkThroughputChartOption2
     ].forEach(opt => this.applyThemeToOption(opt, isDark));
 
     // Specific overrides for charts with hardcoded titles/series from service
-    [this.systemLoadChartOption2, this.systemLoadChartOption3, this.diskChartOption1].forEach(opt => {
+    [this.systemLoadChartOption2, this.systemLoadChartOption3, this.diskChartOption1, this.networkThroughputChartOption2].forEach(opt => {
       if (opt && opt.title) {
         const title: any = opt.title;
         if (Array.isArray(title)) {
@@ -205,12 +211,72 @@
       .subscribe({
         next: (result: any) => {
           this.currentSystemMetrics = result;
-          if (this.currentSystemMetrics?.disk_usage && this.currentSystemMetrics.disk_usage.length > 0) {
-            this.diskMetrics = this.currentSystemMetrics.disk_usage[0];
+
+          // Detect multi-node deployment
+          const isCpuArray = Array.isArray(this.currentSystemMetrics?.cpu);
+          const isMemArray = Array.isArray(this.currentSystemMetrics?.memory);
+          this.isMultiNode = isCpuArray || isMemArray;
+
+          // Always populate nodeMetrics for consistent disk chart display
+          this.nodeMetrics = [];
+          const cpuData = isCpuArray ? this.currentSystemMetrics.cpu : (this.currentSystemMetrics.cpu ? [this.currentSystemMetrics.cpu] : []);
+          const memData = isMemArray ? this.currentSystemMetrics.memory : (this.currentSystemMetrics.memory ? [this.currentSystemMetrics.memory] : []);
+
+          // Get unique hosts
+          const hosts = new Set([
+            ...cpuData.map((c: any) => c.host).filter((h: any) => h),
+            ...memData.map((m: any) => m.host).filter((h: any) => h)
+          ]);
+
+          // If no hosts from CPU/memory, get from disk
+          if (hosts.size === 0 && this.currentSystemMetrics?.disk_usage) {
+            this.currentSystemMetrics.disk_usage.forEach((d: any) => {
+              if (d.host) hosts.add(d.host);
+            });
           }
+
+          hosts.forEach(host => {
+            const cpuMetric = cpuData.find((c: any) => c.host === host);
+            const memMetric = memData.find((m: any) => m.host === host);
+
+            // Get disk metrics for this host
+            const diskMetricsForHost = this.currentSystemMetrics?.disk_usage?.filter((d: any) => d.host === host) || [];
+            const aggregatedDisk = diskMetricsForHost.reduce((acc: any, disk: any) => {
+              return {
+                total_bytes: (acc.total_bytes || 0) + (disk.total_bytes || 0),
+                used_bytes: (acc.used_bytes || 0) + (disk.used_bytes || 0),
+                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;
+
+            const netMetric = this.currentSystemMetrics?.net_metrics?.find((n: any) => n.host === host);
+
+            this.nodeMetrics.push({
+              host: host,
+              cpu: cpuMetric,
+              memory: memMetric,
+              disk: aggregatedDisk,
+              network: netMetric
+            });
+          });
+
+
+
+          console.log('Multi-node detected:', this.isMultiNode);
+          console.log('Node metrics:', this.nodeMetrics);
+
+          // Handle network metrics
           if (this.currentSystemMetrics?.net_metrics && this.currentSystemMetrics.net_metrics.length > 0) {
             this.networkMetrics = this.currentSystemMetrics.net_metrics[0];
           }
+
+
+
+
           this.updateChartOption();
         },
         error: (error: { message: string; }) => {
@@ -283,43 +349,28 @@
 
   private updateChartOption(isDark_in?: boolean) {
     const isDark = isDark_in !== undefined ? isDark_in : document.body.classList.contains('dark-theme');
-    let _data: any = {
-      cpu: {
-        usage: this.currentSystemMetrics?.cpu?.cpu_percent,
-        remaining: 100 - this.currentSystemMetrics?.cpu?.cpu_percent
-      },
-      memory: {
-        usage: this.currentSystemMetrics?.memory?.mem_percent,
-        remaining: 100 - this.currentSystemMetrics?.memory?.mem_percent
-      },
-      disk: {
-        usage: this.diskMetrics?.used_percent,
-        remaining: 100 - this.diskMetrics?.used_percent,
-      },
-      diskIO: {
-        usage: this.currentSystemMetrics?.disk_io?.disk_io_percent,
-        remaining: 100 - this.currentSystemMetrics?.disk_io?.disk_io_percent,
-      }
-    }
+    const colors = this.getThemeColors(isDark);
 
-    const colors = this.getThemeColors(isDark);
-
-    if (_data.cpu.usage !== undefined && _data.cpu.usage !== null) {
-      this.systemLoadChartOption2 = this._chartOptions.systemStatusPieChartOptions('CPU', _data?.cpu?.usage, colors.accent);
+    // Unified CPU & Memory charts for both single and multi-node
+    if (this.nodeMetrics && this.nodeMetrics.length > 0) {
+      this.systemLoadChartOption2 = this.getMultiNodeCpuChartOptions(isDark);
+      this.systemLoadChartOption3 = this.getMultiNodeMemoryChartOptions(isDark);
     } else {
       this.systemLoadChartOption2 = this._chartOptions.getNoDataChartOptions();
+      this.systemLoadChartOption3 = this._chartOptions.getNoDataChartOptions();
     }
 
-    if (_data.memory.usage !== undefined && _data.memory.usage !== null) {
-      this.systemLoadChartOption3 = this._chartOptions.systemStatusPieChartOptions('Memory', _data?.memory?.usage, colors.teal);
+    if (this.nodeMetrics && this.nodeMetrics.length > 0) {
+      this.diskChartOption1 = this.getMultiNodeDiskChartOptions(isDark);
     } else {
-      this.systemLoadChartOption3 = this._chartOptions.getNoDataChartOptions();
+      this.diskChartOption1 = this._chartOptions.getNoDataChartOptions();
     }
 
-    if (_data.disk.usage !== undefined && _data.disk.usage !== null) {
-      this.diskChartOption1 = this._chartOptions.systemStatusPieChartOptions('Disk', _data?.disk?.usage, colors.orange);
+    // Network Throughput Chart
+    if (this.nodeMetrics && this.nodeMetrics.length > 0) {
+      this.networkThroughputChartOption2 = this.getMultiNodeNetworkChartOptions(isDark);
     } else {
-      this.diskChartOption1 = this._chartOptions.getNoDataChartOptions();
+      this.networkThroughputChartOption2 = this._chartOptions.getNoDataChartOptions();
     }
 
     if (this.deviceConnectionStats && this.deviceConnectionStats.yAxisData && this.deviceConnectionStats.yAxisData.length > 0) {
@@ -334,35 +385,582 @@
       this.connectionChartOption2 = this._chartOptions.getNoDataChartOptions();
     }
     this.applyThemeOverrides();
+  }
+
+  getMultiNodeCpuChartOptions(isDark?: boolean): EChartsOption {
+    const themeColors = this.getThemeColors(isDark || document.body.classList.contains('dark-theme'));
+    const usedData = this.nodeMetrics.map(n => n.cpu?.cpu_percent || 0);
+    const freeData = this.nodeMetrics.map(n => 100 - (n.cpu?.cpu_percent || 0));
+
+    return this.getGenericMultiNodeChartOptions(
+      themeColors,
+      usedData,
+      freeData,
+      themeColors.accent,
+      (node, value) => {
+        return `
+          <strong>${node.host}</strong><br/>
+          Used: ${value.toFixed(1)}%<br/>
+          Free: ${(100 - value).toFixed(1)}%
+        `;
+      },
+      'CPU Usage' // Add Title
+    );
+  }
+
+  getMultiNodeMemoryChartOptions(isDark?: boolean): EChartsOption {
+    const themeColors = this.getThemeColors(isDark || document.body.classList.contains('dark-theme'));
+    const usedData = this.nodeMetrics.map(n => n.memory?.mem_percent || 0);
+    const freeData = this.nodeMetrics.map(n => 100 - (n.memory?.mem_percent || 0));
+
+    return this.getGenericMultiNodeChartOptions(
+      themeColors,
+      usedData,
+      freeData,
+      themeColors.teal,
+      (node, value) => {
+        const used = node.memory?.used || 0;
+        const total = node.memory?.total || 0;
+        const free = total - used;
+        return `
+          <strong>${node.host}</strong><br/>
+          Used: ${value.toFixed(1)}% (${this.formatBytes(used)})<br/>
+          Free: ${(100 - value).toFixed(1)}% (${this.formatBytes(free)})<br/>
+          Total: ${this.formatBytes(total)}
+        `;
+      },
+      'Memory Usage' // Add Title
+    );
+  }
+
+  // Shared generic method for basic horizontal bar charts (CPU/Memory)
+  // Disk has specific byte formatting needs so we keep it separate or could be refactored later
+  getGenericMultiNodeChartOptions(
+    themeColors: any,
+    usedData: number[],
+    freeData: number[],
+    usedColor: string,
+    tooltipFormatter: (node: any, value: number) => string,
+    titleText?: string
+  ): EChartsOption {
+    // Dynamic sizing based on number of nodes
+    const nodeCount = this.nodeMetrics.length;
+    const isSingleNode = nodeCount === 1;
+
+    // More generous spacing for multi-node to prevent cutoffs, but less bottom space if no legend
+    const gridTop = isSingleNode ? '25%' : '20%'; // Need space for Title
+    const gridBottom = isSingleNode ? '35%' : '5%'; // Very little bottom space needed without legend
+    const barWidth = isSingleNode ? '40%' : undefined;
+
+    // Create simple node labels (Node 1, Node 2, etc.)
+    const nodeLabels = this.nodeMetrics.map((_, index) => `Node ${index + 1}`);
+
+    return {
+      title: titleText ? {
+        text: titleText,
+        left: 'center',
+        top: 0,
+        textStyle: {
+          fontSize: 12,
+          color: themeColors.textMain,
+          fontWeight: 'normal'
+        }
+      } : undefined,
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: { type: 'shadow' },
+        backgroundColor: themeColors.bg ? themeColors.bg : (document.body.classList.contains('dark-theme') ? '#424242' : '#fff'),
+        borderColor: document.body.classList.contains('dark-theme') ? '#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];
+          // Determine which param is the 'Used' value (usually index 0, but checking seriesName is safer if mixed)
+          const usedValue = params[0].value;
+          return tooltipFormatter(node, usedValue);
+        }
+      },
+      legend: {
+        show: isSingleNode, // Only show legend for single node
+        data: ['Used', 'Free'],
+        bottom: 0,
+        itemGap: 15,
+        textStyle: { color: themeColors.textMain, fontSize: 11 }
+      },
+      grid: {
+        left: '20%', // More space for labels
+        right: '10%',
+        bottom: gridBottom,
+        top: gridTop,
+        containLabel: false
+      },
+      xAxis: {
+        type: 'value',
+        max: 100,
+        axisLabel: {
+          formatter: '{value}%',
+          color: themeColors.textMuted,
+          fontSize: 10 // Slightly smaller font
+        },
+        splitLine: {
+          lineStyle: { color: document.body.classList.contains('dark-theme') ? '#505050' : '#e0e0e0' }
+        }
+      },
+      yAxis: {
+        type: 'category',
+        data: nodeLabels,
+        axisLabel: {
+          color: themeColors.textMain,
+          fontSize: 11,
+          fontWeight: 500,
+          width: 80, // Allow more width for "Node X"
+          overflow: 'truncate'
+        },
+        axisLine: {
+          lineStyle: { color: document.body.classList.contains('dark-theme') ? '#616161' : '#ccc' }
+        }
+      },
+      series: [
+        {
+          name: 'Used',
+          type: 'bar' as const,
+          stack: 'total',
+          data: usedData,
+          barWidth: barWidth,
+          itemStyle: {
+            color: usedColor,
+            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',
+          type: 'bar' as const,
+          stack: 'total',
+          data: freeData,
+          barWidth: barWidth,
+          itemStyle: {
+            color: '#e0e0e0', // Light grey for free space
+            borderRadius: [0, 4, 4, 0]
+          },
+          label: { show: false }
+        }
+      ]
+    };
+  }
+
+  getMultiNodeDiskChartOptions(isDark?: boolean): EChartsOption {
+    const themeColors = this.getThemeColors(isDark || document.body.classList.contains('dark-theme'));
+
+    // Prepare data for horizontal bar chart
+    const hostnames = this.nodeMetrics.map(n => n.host);
+    const usedData = this.nodeMetrics.map(n => n.disk?.used_percent || 0);
+    const freeData = this.nodeMetrics.map(n => 100 - (n.disk?.used_percent || 0));
+
+    // Dynamic sizing based on number of nodes
+    const nodeCount = this.nodeMetrics.length;
+    const isSingleNode = nodeCount === 1;
+
+    // Adjust grid to reduce height for single node
+    const gridTop = isSingleNode ? '25%' : '5%';
+    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}`);
+
+    return {
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+          type: 'shadow'
+        },
+        backgroundColor: isDark ? '#424242' : '#fff',
+        borderColor: isDark ? '#616161' : '#ccc',
+        textStyle: {
+          color: themeColors.textMain
+        },
+        confine: true,
+        position: function (point: any, params: any, dom: any, rect: any, size: any) {
+          // Position tooltip to the right of the cursor to avoid covering labels
+          return [point[0] + 20, point[1] - size.contentSize[1] / 2];
+        },
+        formatter: (params: any) => {
+          const nodeIndex = params[0].dataIndex;
+          const node = this.nodeMetrics[nodeIndex];
+          const usedBytes = node.disk?.used_bytes || 0;
+          const freeBytes = node.disk?.free_bytes || 0;
+          const totalBytes = node.disk?.total_bytes || 0;
+
+          return `
+            <strong>${node.host}</strong><br/>
+            Used: ${this.formatBytes(usedBytes)} (${params[0].value.toFixed(1)}%)<br/>
+            Free: ${this.formatBytes(freeBytes)} (${params[1].value.toFixed(1)}%)<br/>
+            Total: ${this.formatBytes(totalBytes)}
+          `;
+        }
+      },
+      legend: {
+        data: ['Used', 'Free'],
+        bottom: 0,
+        textStyle: { color: themeColors.textMain }
+      },
+      grid: {
+        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' }
+        }
+      },
+      yAxis: {
+        type: 'category',
+        data: nodeLabels,
+        axisLabel: {
+          color: themeColors.textMain,
+          fontSize: 11,
+          fontWeight: 500
+        },
+        axisLine: {
+          lineStyle: { color: isDark ? '#616161' : '#ccc' }
+        }
+      },
+      series: [
+        {
+          name: 'Used',
+          type: 'bar' as const,
+          stack: 'total',
+          data: usedData,
+          barWidth: barWidth,
+          itemStyle: {
+            color: themeColors.orange,
+            borderRadius: [0, 0, 0, 0]
+          },
+          label: {
+            show: true,
+            position: 'inside',
+            formatter: (params: any) => {
+              // Only show label if there's enough space (>10%)
+              return params.value > 10 ? `${params.value.toFixed(1)}%` : '';
+            },
+            color: '#fff',
+            fontWeight: 600,
+            fontSize: 11
+          }
+        },
+        {
+          name: 'Free',
+          type: 'bar' as const,
+          stack: 'total',
+          data: freeData,
+          barWidth: barWidth,
+          itemStyle: {
+            color: themeColors.green,
+            borderRadius: [0, 4, 4, 0]
+          },
+          label: {
+            show: true,
+            position: 'inside',
+            formatter: (params: any) => {
+              // Only show label if there's enough space (>10%)
+              return params.value > 10 ? `${params.value.toFixed(1)}%` : '';
+            },
+            color: '#fff',
+            fontWeight: 600,
+            fontSize: 11
+          }
+        }
+      ]
+    };
+  }
+
+  getMultiNodeNetworkChartOptions(isDark?: boolean): EChartsOption {
+    const isDarkTheme = isDark !== undefined ? isDark : document.body.classList.contains('dark-theme');
+    const themeColors = {
+      textMain: isDarkTheme ? '#e0e0e0' : '#333333',
+      textMuted: isDarkTheme ? '#a0a0a0' : '#777777',
+      orange: isDarkTheme ? '#ffcc80' : '#ff9800',
+      green: isDarkTheme ? '#a5d6a7' : '#4caf50',
+      accent: '#1170cf'
+    };
+
+    const sentData = this.nodeMetrics.map(n => n.network?.sent || 0);
+    const receivedData = this.nodeMetrics.map(n => n.network?.received || 0);
+
+    const nodeLabels = this.nodeMetrics.map((n, index) => n.host || `Node ${index + 1}`);
+    const nodeCount = this.nodeMetrics.length;
+    const isSingleNode = nodeCount === 1;
+
+    return {
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: { type: 'shadow' },
+        backgroundColor: isDarkTheme ? '#424242' : '#fff',
+        borderColor: isDarkTheme ? '#616161' : '#ccc',
+        textStyle: { color: themeColors.textMain },
+        confine: true,
+        formatter: (params: any) => {
+          const nodeIndex = params[0].dataIndex;
+          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`;
+        }
+      },
+      legend: {
+        data: ['Inbound', 'Outbound'],
+        bottom: 5,
+        textStyle: { color: themeColors.textMain }
+      },
+      grid: {
+        left: '10%',
+        right: '10%',
+        bottom: isSingleNode ? '35%' : '25%',
+        top: '10%',
+        containLabel: true
+      },
+      xAxis: {
+        type: 'category',
+        data: nodeLabels,
+        axisLabel: {
+          color: themeColors.textMain,
+          fontSize: 11,
+          fontWeight: 500,
+          interval: 0,
+          rotate: nodeCount > 4 ? 30 : 0
+        },
+        axisLine: { lineStyle: { color: isDarkTheme ? '#616161' : '#ccc' } }
+      },
+      yAxis: {
+        type: 'value',
+        minInterval: 1,
+        axisLabel: {
+          formatter: (value: number) => this.formatBytes(value, 1),
+          color: themeColors.textMuted
+        },
+        splitLine: { lineStyle: { color: isDarkTheme ? '#505050' : '#e0e0e0' } }
+      },
+      series: [
+        {
+          name: 'Inbound',
+          type: 'bar',
+          stack: 'total',
+          barWidth: isSingleNode ? '40%' : '30',
+          data: receivedData,
+          emphasis: { focus: 'none' },
+          itemStyle: { color: themeColors.green }
+        },
+        {
+          name: 'Outbound',
+          type: 'bar',
+          stack: 'total',
+          barWidth: isSingleNode ? '40%' : '30',
+          data: sentData,
+          emphasis: { focus: 'none' },
+          itemStyle: { color: themeColors.accent, borderRadius: [4, 4, 0, 0] }
+        }
+      ]
+    };
+  }
+
+
+  getMultiNodeDiskGaugeOptions(isDark?: boolean): EChartsOption {
+    const themeColors = this.getThemeColors(isDark || document.body.classList.contains('dark-theme'));
+
+    // Create a gauge for each node
+    const gauges = this.nodeMetrics.map((node, index) => {
+      const usedPercent = node.disk?.used_percent || 0;
+      const total = this.nodeMetrics.length;
+      const radius = total === 1 ? '70%' : '60%';
+      const centerX = total === 1 ? '50%' : `${(100 / (total + 1)) * (index + 1)}%`;
+
+      return {
+        type: 'gauge' as const,
+        center: [centerX, '55%'],
+        radius: radius,
+        startAngle: 90,
+        endAngle: -270,
+        min: 0,
+        max: 100,
+        splitNumber: 4,
+        axisLine: {
+          lineStyle: {
+            width: 15,
+            color: [
+              [0.7, themeColors.green] as [number, string],
+              [0.85, themeColors.orange] as [number, string],
+              [1, '#ff4d4f'] as [number, string]
+            ]
+          }
+        },
+        pointer: {
+          show: false
+        },
+        axisTick: {
+          show: false
+        },
+        splitLine: {
+          show: false
+        },
+        axisLabel: {
+          show: false
+        },
+        detail: {
+          formatter: (value: number) => {
+            const usedBytes = node.disk?.used_bytes || 0;
+            const totalBytes = node.disk?.total_bytes || 0;
+            return `{value|${value.toFixed(1)}%}\n{label|Used}\n{size|${this.formatBytes(usedBytes)}}\n{total|of ${this.formatBytes(totalBytes)}}`;
+          },
+          rich: {
+            value: {
+              fontSize: 20,
+              fontWeight: 600,
+              color: themeColors.textMain,
+              lineHeight: 30
+            },
+            label: {
+              fontSize: 11,
+              color: themeColors.textMuted,
+              lineHeight: 20
+            },
+            size: {
+              fontSize: 13,
+              fontWeight: 500,
+              color: themeColors.textMain,
+              lineHeight: 22
+            },
+            total: {
+              fontSize: 11,
+              color: themeColors.textMuted,
+              lineHeight: 18
+            }
+          },
+          offsetCenter: [0, '0%']
+        },
+        title: {
+          show: true,
+          offsetCenter: [0, '-85%'],
+          fontSize: 12,
+          fontWeight: 500,
+          color: themeColors.textMain
+        },
+        data: [
+          {
+            value: usedPercent,
+            name: node.host
+          }
+        ]
+      };
+    });
+
+    return {
+      series: gauges
+    };
   }
 
+  formatBytes(bytes: number, decimals = 2): string {
+    if (bytes <= 0) return '0 B';
+    const k = 1024;
+    const dm = decimals < 0 ? 0 : decimals;
+    const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
+    let i = Math.floor(Math.log(bytes) / Math.log(k));
+    if (i < 0) i = 0;
+    if (i >= sizes.length) i = sizes.length - 1;
+    return parseFloat((bytes / 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;
 
     if (this.historicalCPUMetrics && this.historicalCPUMetrics.length > 0 && this.historicalMemoryMetrics && this.historicalMemoryMetrics.length > 0) {
-      const cpu_data_formatted: any = this.historicalCPUMetrics.map((d: any) => [d.time, d.cpu_percent]);
-      const memory_data_formatted: any = this.historicalMemoryMetrics.map((d: any) => [d.time, d.mem_percent]);
-      this.systemLoadChartOption1 = this._chartOptions.historicalCPUMemoryChartOptions(cpu_data_formatted, memory_data_formatted);
+      // Aggregate historical CPU/Memory if they are per-node
+      const aggregatedCPU: any[] = [];
+      const aggregatedMem: any[] = [];
+
+      const cpuByTime = this.groupHistoricalByTime(this.historicalCPUMetrics);
+      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]);
+      });
+
+      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]);
+      });
+
+      this.systemLoadChartOption1 = this._chartOptions.historicalCPUMemoryChartOptions(aggregatedCPU, aggregatedMem);
     } else {
       this.systemLoadChartOption1 = this._chartOptions.getNoDataChartOptions();
     }
 
     if (this.historicalNetworkMetrics && this.historicalNetworkMetrics.length > 0) {
-      const sent_data_formatted: any = this.historicalNetworkMetrics.map((d: any) => [d.time, d.sent / factor]);
-      const received_data_formatted: any = this.historicalNetworkMetrics.map((d: any) => [d.time, d.received / factor]);
-      this.networkThroughputChartOption1 = this._chartOptions.historicalThroughputChartOptions(sent_data_formatted, received_data_formatted)
+      const netByTime = this.groupHistoricalByTime(this.historicalNetworkMetrics);
+      const aggregatedSent: any[] = [];
+      const aggregatedReceived: any[] = [];
+
+      Object.keys(netByTime).forEach(time => {
+        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]);
+      });
+
+      this.networkThroughputChartOption1 = this._chartOptions.historicalThroughputChartOptions(aggregatedReceived, aggregatedSent)
     } else {
       this.networkThroughputChartOption1 = this._chartOptions.getNoDataChartOptions();
     }
 
     if (this.historicalDiskIOMetrics && this.historicalDiskIOMetrics.length > 0) {
-      const disk_io_formatted = this.historicalDiskIOMetrics.map((d: any) => [d.time, d.disk_io_percent]);
-      this.diskIOChartOption1 = this._chartOptions.historicalDiskIOChartOptions(disk_io_formatted);
+      const diskByTime = this.groupHistoricalByTime(this.historicalDiskIOMetrics);
+      const aggregatedDiskIO: any[] = [];
+      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]);
+      });
+      this.diskIOChartOption1 = this._chartOptions.historicalDiskIOChartOptions(aggregatedDiskIO);
     } else {
       this.diskIOChartOption1 = this._chartOptions.getNoDataChartOptions();
     }
     this.applyThemeOverrides();
+  }
+
+  private groupHistoricalByTime(data: any[]): { [key: string]: any[] } {
+    return data.reduce((acc, item) => {
+      const time = item.time;
+      if (!acc[time]) acc[time] = [];
+      acc[time].push(item);
+      return acc;
+    }, {});
   }
 
   // Device Metrics Logic
@@ -744,7 +1342,9 @@
 })
 export class EnlargeSystemLoad implements OnInit {
 
-  chartOption1: EChartsOption = {};
+  cpuChartOption: EChartsOption = {};
+  memChartOption: EChartsOption = {};
+  nodeMetrics: any[] = [];
 
   readonly data = inject(MAT_DIALOG_DATA);
   readonly dialogRef = inject(MatDialogRef<EnlargeSystemLoad>);
@@ -765,7 +1365,7 @@
         .pipe(
           startWith(0),
           tap(() => {
-            this.getHistoricalSystemMetrics();
+            this.getLatestSystemMetrics();
           }),
           takeUntilDestroyed(this.destroyRef)
         )
@@ -773,16 +1373,12 @@
     })
   }
 
-  cpuMetrics: any = {};
-  memoryMetrics: any = {};
-
-  getHistoricalSystemMetrics() {
-    this.systemFacade.getHistoricalSystemMetrics()
+  getLatestSystemMetrics() {
+    this.systemFacade.getLatestSystemMetrics()
       .pipe(take(1))
       .subscribe({
         next: (result: any) => {
-          this.cpuMetrics = result?.cpu_history;
-          this.memoryMetrics = result?.mem_history;
+          this.processNodeMetrics(result);
           this.updateChartOptions();
         },
         error: (error: { message: string; }) => {
@@ -792,18 +1388,208 @@
       });
   }
 
-  updateChartOptions() {
-    const cpu_data_formatted = this.cpuMetrics.map((d: any) => [d.time, d.cpu_percent]);
-    const memory_data_formatted = this.memoryMetrics.map((d: any) => [d.time, d.mem_percent]);
-    this.chartOption1 = this._chartOptions.historicalCPUMemoryChartOptions(cpu_data_formatted, memory_data_formatted);
-    this.applyThemeToOption(this.chartOption1);
+  processNodeMetrics(result: any) {
+    const isCpuArray = Array.isArray(result?.cpu);
+    const isMemArray = Array.isArray(result?.memory);
+    this.nodeMetrics = [];
+
+    const cpuData = isCpuArray ? result.cpu : (result?.cpu ? [result.cpu] : []);
+    const memData = isMemArray ? result.memory : (result?.memory ? [result.memory] : []);
+
+    const hosts = new Set([
+      ...cpuData.map((c: any) => c.host).filter((h: any) => h),
+      ...memData.map((m: any) => m.host).filter((h: any) => h)
+    ]);
+
+    hosts.forEach(host => {
+      this.nodeMetrics.push({
+        host: host,
+        cpu: cpuData.find((c: any) => c.host === host),
+        memory: memData.find((m: any) => m.host === host)
+      });
+    });
   }
 
+  updateChartOptions() {
+    this.cpuChartOption = this.getMultiNodeCpuChartOptions();
+    this.memChartOption = this.getMultiNodeMemoryChartOptions();
+    this.applyThemeToOption(this.cpuChartOption);
+    this.applyThemeToOption(this.memChartOption);
+  }
+
   updateChartTheme(isDark: boolean) {
-    this.applyThemeToOption(this.chartOption1, isDark);
-    this.chartOption1 = { ...this.chartOption1 };
+    this.applyThemeToOption(this.cpuChartOption, isDark);
+    this.applyThemeToOption(this.memChartOption, isDark);
+    this.cpuChartOption = { ...this.cpuChartOption };
+    this.memChartOption = { ...this.memChartOption };
+  }
+
+  // --- Chart Generation Logic (Replicated) ---
+
+  getMultiNodeCpuChartOptions(isDark?: boolean): EChartsOption {
+    const themeColors = this.getThemeColors(isDark || document.body.classList.contains('dark-theme'));
+    const usedData = this.nodeMetrics.map(n => n.cpu?.cpu_percent || 0);
+    const freeData = this.nodeMetrics.map(n => 100 - (n.cpu?.cpu_percent || 0));
+
+    return this.getGenericMultiNodeChartOptions(
+      themeColors,
+      usedData,
+      freeData,
+      themeColors.accent,
+      (node, value) => {
+        return `
+          <strong>${node.host}</strong><br/>
+          Used: ${value.toFixed(1)}%<br/>
+          Free: ${(100 - value).toFixed(1)}%
+        `;
+      },
+      'CPU Usage'
+    );
+  }
+
+  getMultiNodeMemoryChartOptions(isDark?: boolean): EChartsOption {
+    const themeColors = this.getThemeColors(isDark || document.body.classList.contains('dark-theme'));
+    const usedData = this.nodeMetrics.map(n => n.memory?.mem_percent || 0);
+    const freeData = this.nodeMetrics.map(n => 100 - (n.memory?.mem_percent || 0));
+
+    return this.getGenericMultiNodeChartOptions(
+      themeColors,
+      usedData,
+      freeData,
+      themeColors.teal,
+      (node, value) => {
+        const used = node.memory?.used || 0;
+        const total = node.memory?.total || 0;
+        const free = total - used;
+        return `
+          <strong>${node.host}</strong><br/>
+          Used: ${value.toFixed(1)}% (${this.formatBytes(used)})<br/>
+          Free: ${(100 - value).toFixed(1)}% (${this.formatBytes(free)})<br/>
+          Total: ${this.formatBytes(total)}
+        `;
+      },
+      'Memory Usage'
+    );
+  }
+
+  getGenericMultiNodeChartOptions(
+    themeColors: any,
+    usedData: number[],
+    freeData: number[],
+    usedColor: string,
+    tooltipFormatter: (node: any, value: number) => string,
+    titleText?: string
+  ): EChartsOption {
+    const nodeCount = this.nodeMetrics.length;
+    const isSingleNode = nodeCount === 1;
+
+    const gridTop = isSingleNode ? '25%' : '20%';
+    const gridBottom = isSingleNode ? '35%' : '5%';
+
+    return {
+      title: titleText ? {
+        text: titleText,
+        left: 'center',
+        top: 0,
+        textStyle: {
+          fontSize: 12,
+          color: themeColors.textMain,
+          fontWeight: 'normal'
+        }
+      } : undefined,
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: { type: 'shadow' },
+        backgroundColor: themeColors.bg ? themeColors.bg : (document.body.classList.contains('dark-theme') ? '#424242' : '#fff'),
+        borderColor: document.body.classList.contains('dark-theme') ? '#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];
+          const usedValue = params[0].value;
+          return tooltipFormatter(node, usedValue);
+        }
+      },
+      legend: {
+        show: isSingleNode,
+        data: ['Used', 'Free'],
+        bottom: 0,
+        itemGap: 15,
+        textStyle: { color: themeColors.textMain, fontSize: 11 }
+      },
+      grid: {
+        left: '20%',
+        right: '10%',
+        bottom: gridBottom,
+        top: gridTop,
+        containLabel: false
+      },
+      xAxis: {
+        type: 'value',
+        max: 100,
+        splitLine: { show: false },
+        axisLabel: { show: false }
+      },
+      yAxis: {
+        type: 'category',
+        data: this.nodeMetrics.map((_, index) => `Node ${index + 1}`),
+        axisLine: { show: false },
+        axisTick: { show: false },
+        axisLabel: {
+          color: themeColors.textMain,
+          fontSize: 12,
+          formatter: (value: string) => value
+        }
+      },
+      series: [
+        {
+          name: 'Used',
+          type: 'bar',
+          stack: 'total',
+          label: { show: true, formatter: '{c}%' },
+          emphasis: { focus: 'none' },
+          data: usedData,
+          itemStyle: { color: usedColor, borderRadius: [4, 4, 4, 4] }
+        },
+        {
+          name: 'Free',
+          type: 'bar',
+          stack: 'total',
+          label: { show: false },
+          emphasis: { focus: 'none' },
+          data: freeData,
+          itemStyle: { color: themeColors.bgMuted, borderRadius: [4, 4, 4, 4] }
+        }
+      ]
+    };
+  }
+
+  // Helper Methods
+  getThemeColors(isDark: boolean): any {
+    return {
+      textMain: isDark ? '#e0e0e0' : '#333333',
+      bgMuted: isDark ? '#2c2c2c' : '#f0f0f0',
+      bg: isDark ? '#424242' : '#ffffff',
+      accent: '#1170cf', // Unified Brand Blue
+      teal: isDark ? '#80cbc4' : '#009688' // Teal
+    };
   }
 
+  formatBytes(bytes: number, decimals = 2): string {
+    if (bytes <= 0) return '0 B';
+    const k = 1024;
+    const dm = decimals < 0 ? 0 : decimals;
+    const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
+    let i = Math.floor(Math.log(bytes) / Math.log(k));
+    if (i < 0) i = 0;
+    if (i >= sizes.length) i = sizes.length - 1;
+    return parseFloat((bytes / 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');
@@ -855,7 +1641,8 @@
 })
 export class EnlargeSystemThroughput implements OnInit {
 
-  chartOption1: EChartsOption = {};
+  trendChartOption: EChartsOption = {};
+  historicalNetworkMetrics: any = [];
 
   readonly data = inject(MAT_DIALOG_DATA);
   readonly dialogRef = inject(MatDialogRef<EnlargeSystemThroughput>);
@@ -884,14 +1671,12 @@
     })
   }
 
-  networkMetrics: any = {};
-
   getHistoricalSystemMetrics() {
     this.systemFacade.getHistoricalSystemMetrics()
       .pipe(take(1))
       .subscribe({
         next: (result: any) => {
-          this.networkMetrics = result?.net_history;
+          this.historicalNetworkMetrics = result?.net_history || [];
           this.updateChartOptions();
         },
         error: (error: { message: string; }) => {
@@ -901,21 +1686,7 @@
       });
   }
 
-  updateChartOptions() {
-    const factor: any = 1024 * 1024;
-    const sent_data_formatted = this.networkMetrics.map((d: any) => [d.time, d.sent / factor]);
-    const received_data_formatted = this.networkMetrics.map((d: any) => [d.time, d.received / factor]);
-    this.chartOption1 = this._chartOptions.historicalThroughputChartOptions(sent_data_formatted, received_data_formatted)
-    this.applyThemeToOption(this.chartOption1);
-  }
-
-  updateChartTheme(isDark: boolean) {
-    this.applyThemeToOption(this.chartOption1, isDark);
-    this.chartOption1 = { ...this.chartOption1 };
-  }
-
   applyThemeToOption(option: any, isDark_in?: boolean) {
-    // Duplicated simple theme logic for now
     if (!option) return;
     const isDark = isDark_in !== undefined ? isDark_in : document.body.classList.contains('dark-theme');
     const colors = {
@@ -945,11 +1716,53 @@
     applyAxisTheme(option.yAxis);
   }
 
+
+  updateChartOptions() {
+
+    // Update Trend Chart (Aggregated)
+    const isDark = document.body.classList.contains('dark-theme');
+    const factor: any = 1024 * 1024;
+
+    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[] = [];
+
+      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]);
+      });
+
+      this.trendChartOption = this._chartOptions.historicalThroughputChartOptions(aggregatedReceived, aggregatedSent);
+    } else {
+      this.trendChartOption = this._chartOptions.getNoDataChartOptions();
+    }
+
+    this.applyThemeToOption(this.trendChartOption, isDark);
+  }
+
+  updateChartTheme(isDark: boolean) {
+    this.applyThemeToOption(this.trendChartOption, isDark);
+    this.trendChartOption = { ...this.trendChartOption };
+  }
+
+
   onCancel() {
     this.dialogRef.close();
   }
 }
 
+
 @Component({
   selector: 'enlarge-system-disk-usage',
   templateUrl: './enlarge-system-disk-usage.html',
@@ -957,7 +1770,8 @@
 })
 export class EnlargeSystemDiskUsage implements OnInit {
 
-  chartOption1: EChartsOption = {};
+  diskChartOption: EChartsOption = {};
+  nodeMetrics: any[] = [];
 
   readonly data = inject(MAT_DIALOG_DATA);
   readonly dialogRef = inject(MatDialogRef<EnlargeSystemDiskUsage>);
@@ -978,7 +1792,7 @@
         .pipe(
           startWith(0),
           tap(() => {
-            this.getHistoricalSystemMetrics();
+            this.getLatestSystemMetrics();
           }),
           takeUntilDestroyed(this.destroyRef)
         )
@@ -986,14 +1800,12 @@
     })
   }
 
-  diskIOMetrics: any = {};
-
-  getHistoricalSystemMetrics() {
-    this.systemFacade.getHistoricalSystemMetrics()
+  getLatestSystemMetrics() {
+    this.systemFacade.getLatestSystemMetrics()
       .pipe(take(1))
       .subscribe({
         next: (result: any) => {
-          this.diskIOMetrics = result?.disk_io_history;
+          this.processNodeMetrics(result);
           this.updateChartOptions();
         },
         error: (error: { message: string; }) => {
@@ -1003,17 +1815,203 @@
       });
   }
 
+  processNodeMetrics(result: any) {
+    this.nodeMetrics = [];
+    const diskData = Array.isArray(result?.disk_usage) ? result.disk_usage : (result?.disk_usage ? [result.disk_usage] : []);
+    const hosts = Array.from(new Set(diskData.map((d: any) => d.host).filter((h: any) => h)));
+
+    if (hosts.length > 0) {
+      hosts.forEach(host => {
+        const diskMetricsForHost = diskData.filter((d: any) => d.host === host);
+        const aggregatedDisk = diskMetricsForHost.reduce((acc: any, disk: any) => {
+          return {
+            total_bytes: (acc.total_bytes || 0) + (disk.total_bytes || 0),
+            used_bytes: (acc.used_bytes || 0) + (disk.used_bytes || 0),
+            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;
+        this.nodeMetrics.push({ host: host, disk: aggregatedDisk });
+      });
+    } else if (diskData.length > 0) {
+      // Fallback for cases without host field
+      this.nodeMetrics.push({ host: 'Node 1', disk: diskData[0] });
+    }
+  }
+
   updateChartOptions() {
-    const disk_io_formatted = this.diskIOMetrics.map((d: any) => [d.time, d.disk_io_percent]);
-    this.chartOption1 = this._chartOptions.historicalDiskIOChartOptions(disk_io_formatted);
-    this.applyThemeToOption(this.chartOption1);
+    this.diskChartOption = this.getMultiNodeDiskChartOptions();
+    this.applyThemeToOption(this.diskChartOption);
   }
 
   updateChartTheme(isDark: boolean) {
-    this.applyThemeToOption(this.chartOption1, isDark);
-    this.chartOption1 = { ...this.chartOption1 };
+    this.applyThemeToOption(this.diskChartOption, isDark);
+    this.diskChartOption = { ...this.diskChartOption };
+  }
+
+  // REPLICATED LOGIC
+  getMultiNodeDiskChartOptions(isDark?: boolean): EChartsOption {
+    const themeColors = this.getThemeColors(isDark || document.body.classList.contains('dark-theme'));
+
+    // Prepare data for horizontal bar chart
+    const hostnames = this.nodeMetrics.map(n => n.host);
+    const usedData = this.nodeMetrics.map(n => n.disk?.used_percent || 0);
+    const freeData = this.nodeMetrics.map(n => 100 - (n.disk?.used_percent || 0));
+
+    // Dynamic sizing based on number of nodes
+    const nodeCount = this.nodeMetrics.length;
+    const isSingleNode = nodeCount === 1;
+
+    // Adjust grid to reduce height for single node
+    const gridTop = isSingleNode ? '25%' : '20%'; // Need space for title
+    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}`);
+
+    return {
+      title: {
+        text: 'Disk Usage',
+        left: 'center',
+        top: 0,
+        textStyle: {
+          fontSize: 12,
+          color: themeColors.textMain,
+          fontWeight: 'normal'
+        }
+      },
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: { type: 'shadow' },
+        backgroundColor: isDark ? '#424242' : '#fff',
+        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];
+          const usedBytes = node.disk?.used_bytes || 0;
+          const freeBytes = node.disk?.free_bytes || 0;
+          const totalBytes = node.disk?.total_bytes || 0;
+
+          return `
+            <strong>${node.host}</strong><br/>
+            Used: ${this.formatBytes(usedBytes)} (${params[0].value.toFixed(1)}%)<br/>
+            Free: ${this.formatBytes(freeBytes)} (${params[1].value.toFixed(1)}%)<br/>
+            Total: ${this.formatBytes(totalBytes)}
+          `;
+        }
+      },
+      legend: {
+        data: ['Used', 'Free'],
+        bottom: 0,
+        textStyle: { color: themeColors.textMain }
+      },
+      grid: {
+        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' }
+        }
+      },
+      yAxis: {
+        type: 'category',
+        data: nodeLabels,
+        axisLabel: {
+          color: themeColors.textMain,
+          fontSize: 11,
+          fontWeight: 500
+        },
+        axisLine: {
+          lineStyle: { color: isDark ? '#616161' : '#ccc' }
+        }
+      },
+      series: [
+        {
+          name: 'Used',
+          type: 'bar',
+          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
+          }
+        },
+        {
+          name: 'Free',
+          type: 'bar',
+          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
+          }
+        }
+      ]
+    };
   }
 
+  getThemeColors(isDark: boolean): any {
+    return {
+      textMain: isDark ? '#e0e0e0' : '#333333',
+      bgMuted: isDark ? '#2c2c2c' : '#f0f0f0',
+      bg: isDark ? '#424242' : '#ffffff',
+      accent: '#1170cf',
+      green: isDark ? '#a5d6a7' : '#4caf50',
+      orange: isDark ? '#ffcc80' : '#ff9800',
+      teal: isDark ? '#80cbc4' : '#009688'
+    };
+  }
+
+  formatBytes(bytes: number, decimals = 2): string {
+    if (bytes <= 0) return '0 B';
+    const k = 1024;
+    const dm = decimals < 0 ? 0 : decimals;
+    const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
+    let i = Math.floor(Math.log(bytes) / Math.log(k));
+    if (i < 0) i = 0;
+    if (i >= sizes.length) i = sizes.length - 1;
+    return parseFloat((bytes / 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');
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 2905)
+++ /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,7 @@
-<h2 mat-dialog-title>System Disk Usage (Last 1 Hour)</h2>
+<h2 mat-dialog-title>System Disk Usage (Live)</h2>
 <mat-dialog-content>
-  <div class="dialog-charts-wrapper">
-    <div echarts [autoResize]="true" [options]="chartOption1" class="dialog-chart-container"></div>
+  <div class="metrics-container" style="height: 100%; min-height: 300px;">
+    <div echarts [autoResize]="true" [options]="diskChartOption" class="chart-container" style="height: 300px;"></div>
   </div>
 </mat-dialog-content>
 <mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-load.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-load.html	(revision 2905)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-load.html	(working copy)
@@ -1,6 +1,11 @@
-<h2 mat-dialog-title>System Load (Last 1 Hour)</h2>
+<h2 mat-dialog-title>System Load (Live)</h2>
 <mat-dialog-content>
-  <div echarts [autoResize]="true" [options]="chartOption1" class="chart-container"></div>
+  <div class="metrics-container" style="display: flex; flex-direction: column; height: 100%; gap: 20px;">
+    <div echarts [autoResize]="true" [options]="cpuChartOption" class="chart-container"
+      style="flex: 1; min-height: 200px;"></div>
+    <div echarts [autoResize]="true" [options]="memChartOption" class="chart-container"
+      style="flex: 1; min-height: 200px;"></div>
+  </div>
 </mat-dialog-content>
 <mat-dialog-actions>
   <button mat-button color="basic" (click)="onCancel()">
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-throughput.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-throughput.html	(revision 2905)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-throughput.html	(working copy)
@@ -1,6 +1,13 @@
-<h2 mat-dialog-title>Network Throughput (Last 1 Hour)</h2>
+<h2 mat-dialog-title>Network Throughput</h2>
 <mat-dialog-content>
-  <div echarts [autoResize]="true" [options]="chartOption1" class="chart-container"></div>
+  <div class="metrics-container" style="display: flex; flex-direction: column; gap: 24px;">
+    <!-- Historical Trend -->
+    <div class="chart-section" style="flex: 1;">
+      <h3 style="margin: 0 0 12px 0; font-size: 14px; font-weight: 500;">Historical Trend (Last 1 Hour)</h3>
+      <div echarts [autoResize]="true" [options]="trendChartOption" class="chart-container full-width"
+        style="height: 320px;"></div>
+    </div>
+  </div>
 </mat-dialog-content>
 <mat-dialog-actions>
   <button mat-button color="basic" (click)="onCancel()">
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/chart-options.service.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/chart-options.service.ts	(revision 2905)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/chart-options.service.ts	(working copy)
@@ -242,7 +242,8 @@
       grid: {
         left: '7%',
         right: '1%',
-        bottom: '1%',
+        bottom: '12%',
+        top: '12%',
         containLabel: true
       },
       tooltip: {
@@ -263,7 +264,8 @@
         }
       },
       legend: {
-        data: ['Sent', 'Received'],
+        data: ['Inbound', 'Outbound'],
+        bottom: 0,
         textStyle: {
           color: this.getTextColor()
         }
@@ -282,35 +284,35 @@
       },
       series: [
         {
-          name: 'Sent',
+          name: 'Inbound',
           type: 'line',
-          data: outbound,
+          data: inbound,
           showSymbol: false,
           smooth: true,
           itemStyle: {
-            color: '#2196f3'
+            color: '#4caf50'
           },
           lineStyle: {
-            color: '#2196f3'
+            color: '#4caf50'
           },
           areaStyle: {
-            color: '#e3f2fd'
+            color: '#e8f5e9'
           }
         },
         {
-          name: 'Received',
+          name: 'Outbound',
           type: 'line',
-          data: inbound,
+          data: outbound,
           showSymbol: false,
           smooth: true,
           itemStyle: {
-            color: '#4caf50'
+            color: '#2196f3'
           },
           lineStyle: {
-            color: '#4caf50'
+            color: '#2196f3'
           },
           areaStyle: {
-            color: '#e8f5e9'
+            color: '#e3f2fd'
           }
         }
       ]
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 2905)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/repositories/system_metrics.py	(working copy)
@@ -5,15 +5,44 @@
 class SystemMetricsRepo:
     @staticmethod
     @with_db_connection
-    def get_latest_cpu(cur, host="AN"):
-        cpu_query = "SELECT time, 100 - usage_idle as cpu_percent FROM cpu WHERE cpu = 'cpu-total' AND time > (NOW() AT TIME ZONE 'UTC') - INTERVAL '5 minutes' ORDER BY time DESC LIMIT 1;"
-        cur.execute(cpu_query)
-        result = cur.fetchone()
+    def get_latest_cpu(cur, host=None):
+        """Get latest CPU metrics. If host is None, returns data for all hosts."""
+        # Query for specific host or all hosts
+        if host:
+            host_filter = "AND host = %s"
+            params = (host,)
+        else:
+            host_filter = ""
+            params = ()
+        
+        cpu_query = f"""
+            SELECT DISTINCT ON (host)
+                host,
+                time,
+                100 - usage_idle as cpu_percent
+            FROM cpu
+            WHERE cpu = 'cpu-total'
+              AND time > (NOW() AT TIME ZONE 'UTC') - INTERVAL '5 minutes'
+              {host_filter}
+            ORDER BY host, time DESC;
+        """
+        cur.execute(cpu_query, params)
+        results = cur.fetchall()
         cur.close()
-        if result:
-            time, cpu_percent = result
+        
+        if not results:
+            return None
+            
+        # If single host, return single object for backward compatibility
+        if len(results) == 1:
+            host, time, cpu_percent = results[0]
             return SystemMetrics(time=time, host=host, cpu_percent=cpu_percent)
-        return None
+        
+        # Multi-node: return list of metrics per host
+        metrics_list = []
+        for host, time, cpu_percent in results:
+            metrics_list.append(SystemMetrics(time=time, host=host, cpu_percent=cpu_percent))
+        return [m.to_dict() for m in metrics_list]
 
     @staticmethod
     @with_db_connection
@@ -50,42 +79,106 @@
 
     @staticmethod
     @with_db_connection
-    def get_latest_memory(cur, host="AN"):
-        mem_query = "SELECT time, used_percent as mem_percent FROM mem WHERE time > (NOW() AT TIME ZONE 'UTC') - INTERVAL '5 minutes' ORDER BY time DESC LIMIT 1;"
-        cur.execute(mem_query)
-        result = cur.fetchone()
+    def get_latest_memory(cur, host=None):
+        """Get latest memory metrics. If host is None, returns data for all hosts."""
+        # Query for specific host or all hosts
+        if host:
+            host_filter = "AND host = %s"
+            params = (host,)
+        else:
+            host_filter = ""
+            params = ()
+        
+        mem_query = f"""
+            SELECT DISTINCT ON (host)
+                host,
+                time,
+                used_percent as mem_percent
+            FROM mem
+            WHERE time > (NOW() AT TIME ZONE 'UTC') - INTERVAL '5 minutes'
+              {host_filter}
+            ORDER BY host, time DESC;
+        """
+        cur.execute(mem_query, params)
+        results = cur.fetchall()
         cur.close()
-        if result:
-            time, mem_percent = result
+        
+        if not results:
+            return None
+            
+        # If single host, return single object for backward compatibility
+        if len(results) == 1:
+            host, time, mem_percent = results[0]
             return SystemMetrics(time=time, host=host, mem_percent=mem_percent)
-        return None
+        
+        # Multi-node: return list of metrics per host
+        metrics_list = []
+        for host, time, mem_percent in results:
+            metrics_list.append(SystemMetrics(time=time, host=host, mem_percent=mem_percent))
+        return [m.to_dict() for m in metrics_list]
 
     @staticmethod
     @with_db_connection
-    def get_latest_disk_usage(cur, host="AN"):
-        disk_query = """
-                     SELECT time,
-                            device,
-                            path,
-                            total,
-                            used,
-                            free,
-                            used_percent
-                     FROM disk
-                     WHERE (device, time) IN (SELECT device,
-                                                    MAX(time)
-                                                    FROM disk
-                                                    WHERE path NOT LIKE 'tmpfs'
-                                                      AND time > (NOW() AT TIME ZONE 'UTC') - INTERVAL '10 minutes'
-                                                    GROUP BY device)
-                     ORDER BY device ASC; \
-                     """
+    def get_latest_disk_usage(cur, host=None):
+        """Get latest disk usage. If host is None, returns data for all hosts."""
+        
+        # Build the query with optional host filter
+        if host:
+            disk_query = """
+                         SELECT host,
+                                time,
+                                device,
+                                path,
+                                total,
+                                used,
+                                free,
+                                used_percent
+                         FROM disk
+                         WHERE (host, device, time) IN (
+                             SELECT host,
+                                    device,
+                                    MAX(time)
+                             FROM disk
+                             WHERE time > (NOW() AT TIME ZONE 'UTC') - INTERVAL '10 minutes'
+                               AND fstype NOT IN ('tmpfs', 'devtmpfs', 'overlay', 'squashfs', 'iso9660')
+                               AND device NOT LIKE '/dev/loop%'
+                               AND path LIKE '/%'
+                               AND host = %s
+                             GROUP BY host, device
+                         )
+                         ORDER BY host, device ASC;
+                         """
+            cur.execute(disk_query, (host,))
+        else:
+            disk_query = """
+                         SELECT host,
+                                time,
+                                device,
+                                path,
+                                total,
+                                used,
+                                free,
+                                used_percent
+                         FROM disk
+                         WHERE (host, device, time) IN (
+                             SELECT host,
+                                    device,
+                                    MAX(time)
+                             FROM disk
+                             WHERE time > (NOW() AT TIME ZONE 'UTC') - INTERVAL '10 minutes'
+                               AND fstype NOT IN ('tmpfs', 'devtmpfs', 'overlay', 'squashfs', 'iso9660')
+                               AND device NOT LIKE '/dev/loop%'
+                               AND path LIKE '/%'
+                             GROUP BY host, device
+                         )
+                         ORDER BY host, device ASC;
+                         """
+            cur.execute(disk_query)
 
-        cur.execute(disk_query)
         results = cur.fetchall()
         cur.close()
         metrics_list = []
-        for time, device, path, total, used, free, used_percent in results:
+        for host, time, device, path, total, used, free, used_percent in results:
             metrics_list.append(DiskMetrics(
                 time=time,
                 host=host,
@@ -100,34 +193,47 @@
 
     @staticmethod
     @with_db_connection
-    def get_latest_throughput(cur, host="AN"):
-        net_query = """
+    def get_latest_throughput(cur, host=None):
+        """Get latest network throughput. If host is None, returns data for all hosts."""
+        # Query for specific host or all hosts
+        if host:
+            host_filter = "AND host = %s"
+            params = (host,)
+        else:
+            host_filter = ""
+            params = ()
+        
+        net_query = f"""
                     SELECT
+                        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
                     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), 0) AS bytes_sent_diff,
                                  GREATEST(bytes_recv::BIGINT - LAG(bytes_recv) OVER (PARTITION BY host, interface ORDER BY time), 0) AS bytes_recv_diff,
                                  EXTRACT(EPOCH FROM (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 > (NOW() AT TIME ZONE 'UTC') - INTERVAL '5 minutes'
+                             WHERE interface NOT LIKE 'lo' AND interface NOT LIKE 'all' 
+                               AND time > (NOW() AT TIME ZONE 'UTC') - INTERVAL '5 minutes'
+                               {host_filter}
                          ) sub
                     WHERE bytes_sent_diff IS NOT NULL
-                    GROUP BY bucket_time, interface
-                    ORDER BY bucket_time DESC
-                    LIMIT 1;
+                    GROUP BY host, bucket_time, interface
+                    ORDER BY host, bucket_time DESC
+                    LIMIT 10;
                     """
-        cur.execute(net_query, (host,))
+        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,
