From b800740d5d9ef5c2ec561812dda863d8fa3aa3bb Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Mon, 12 Jan 2026 18:10:20 +0000 Subject: [PATCH] feat(eco-view-system): add extended system metrics and display formatted total network usage in eco system view --- changelog.md | 7 + package.json | 2 +- pnpm-lock.yaml | 12 +- ts_web/00_commitinfo_data.ts | 2 +- .../views/eco-view-system/eco-view-system.ts | 378 +++++++++--------- 5 files changed, 202 insertions(+), 199 deletions(-) diff --git a/changelog.md b/changelog.md index aaf778b..7e73d4e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Changelog +## 2026-01-12 - 3.38.0 - feat(eco-view-system) +add extended system metrics and display formatted total network usage in eco system view + +- Added numerous new observable properties for richer system telemetry: cpuPhysicalCores, cpuSpeedMax, memoryAvailable, memoryCached, memoryBuffers, swapTotal, swapUsed, diskTotal, diskUsed, diskFree, networkRxSec, networkTxSec, networkRxTotal, networkTxTotal, distro, and coreLoads. +- Reworked network/usage UI: removed several temporary network/latency cards and replaced them with Total Downloaded/Uploaded cards that use formatBytes(...) and show totals since boot. +- Bumped dependency @design.estate/dees-catalog from ^3.34.1 to ^3.35.0. + ## 2026-01-12 - 3.37.0 - feat(elements) add eco-provider-frame and dataprovider interfaces; improve virtual keyboard interactions; add demos, exports and bump dev dependencies diff --git a/package.json b/package.json index 4b2b07e..7d57a01 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "author": "Lossless GmbH", "license": "MIT", "dependencies": { - "@design.estate/dees-catalog": "^3.34.1", + "@design.estate/dees-catalog": "^3.35.0", "@design.estate/dees-domtools": "^2.3.7", "@design.estate/dees-element": "^2.1.5", "@push.rocks/smartpromise": "^4.2.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5f77391..41dc04b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@design.estate/dees-catalog': - specifier: ^3.34.1 - version: 3.34.1(@tiptap/pm@2.27.2) + specifier: ^3.35.0 + version: 3.35.0(@tiptap/pm@2.27.2) '@design.estate/dees-domtools': specifier: ^2.3.7 version: 2.3.7 @@ -398,8 +398,8 @@ packages: '@configvault.io/interfaces@1.0.17': resolution: {integrity: sha512-bEcCUR2VBDJsTin8HQh8Uw/mlYl2v8A3jMIaQ+MTB9Hrqd6CZL2dL7iJdWyFl/3EIX+LDxWFR+Oq7liIq7w+1Q==} - '@design.estate/dees-catalog@3.34.1': - resolution: {integrity: sha512-jm/ZPoLgBHicIlrGPTiCynztFEemJGHweiz+GQK9FppFfjCCC47AOHI4ZjIhrNibfyPXGfqfFWr7DI0zCOl1gw==} + '@design.estate/dees-catalog@3.35.0': + resolution: {integrity: sha512-6K5ddjpZOh8JVmxr/XkBGOARGLDIXKWPeyo+NeGrmNMG5HOFSdGj2RnDqK9FkH0zxG1u1hG9T/EdIMmcEKgIvw==} '@design.estate/dees-comms@1.0.30': resolution: {integrity: sha512-KchMlklJfKAjQiJiR0xmofXtQ27VgZtBIxcMwPE9d+h3jJRv+lPZxzBQVOM0eyM0uS44S5vJMZ11IeV4uDXSHg==} @@ -4309,7 +4309,7 @@ snapshots: '@api.global/typedrequest-interfaces': 3.0.19 '@api.global/typedsocket': 4.1.0(@push.rocks/smartserve@1.4.0) '@cloudflare/workers-types': 4.20251211.0 - '@design.estate/dees-catalog': 3.34.1(@tiptap/pm@2.27.2) + '@design.estate/dees-catalog': 3.35.0(@tiptap/pm@2.27.2) '@design.estate/dees-comms': 1.0.30 '@push.rocks/lik': 6.2.2 '@push.rocks/smartdelay': 3.0.5 @@ -5317,7 +5317,7 @@ snapshots: dependencies: '@api.global/typedrequest-interfaces': 3.0.19 - '@design.estate/dees-catalog@3.34.1(@tiptap/pm@2.27.2)': + '@design.estate/dees-catalog@3.35.0(@tiptap/pm@2.27.2)': dependencies: '@design.estate/dees-domtools': 2.3.7 '@design.estate/dees-element': 2.1.5 diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts index b4dc90a..e62e426 100644 --- a/ts_web/00_commitinfo_data.ts +++ b/ts_web/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@ecobridge.xyz/catalog', - version: '3.37.0', + version: '3.38.0', description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.' } diff --git a/ts_web/views/eco-view-system/eco-view-system.ts b/ts_web/views/eco-view-system/eco-view-system.ts index 17ca507..756ae94 100644 --- a/ts_web/views/eco-view-system/eco-view-system.ts +++ b/ts_web/views/eco-view-system/eco-view-system.ts @@ -168,12 +168,18 @@ export class EcoViewSystem extends DeesElement { @property({ type: Number }) accessor cpuCores = 0; + @property({ type: Number }) + accessor cpuPhysicalCores = 0; + @property({ type: String }) accessor cpuModel = 'Unknown'; @property({ type: Number }) accessor cpuSpeed = 0; + @property({ type: Number }) + accessor cpuSpeedMax = 0; + @property({ type: Number }) accessor memoryTotal = 0; @@ -183,41 +189,129 @@ export class EcoViewSystem extends DeesElement { @property({ type: Number }) accessor memoryFree = 0; + @property({ type: Number }) + accessor memoryAvailable = 0; + + @property({ type: Number }) + accessor memoryCached = 0; + + @property({ type: Number }) + accessor memoryBuffers = 0; + + @property({ type: Number }) + accessor swapTotal = 0; + + @property({ type: Number }) + accessor swapUsed = 0; + + @property({ type: Number }) + accessor diskTotal = 0; + + @property({ type: Number }) + accessor diskUsed = 0; + + @property({ type: Number }) + accessor diskFree = 0; + + @property({ type: Number }) + accessor networkRxSec = 0; + + @property({ type: Number }) + accessor networkTxSec = 0; + + @property({ type: Number }) + accessor networkRxTotal = 0; + + @property({ type: Number }) + accessor networkTxTotal = 0; + @property({ type: String }) accessor hostname = 'Unknown'; @property({ type: String }) accessor platform = 'Unknown'; + @property({ type: String }) + accessor distro = ''; + @property({ type: Array }) accessor loadAvg: number[] = [0, 0, 0]; - @state() - accessor networkIn = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + @property({ type: Array }) + accessor coreLoads: number[] = []; @state() - accessor networkOut = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + accessor networkInHistory: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + @state() + accessor networkOutHistory: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // Public method to update metrics from backend public setMetrics(metrics: { - cpu: { usage: number; cores: number; model: string; speed: number; loadAvg: number[] }; - memory: { total: number; used: number; free: number; usagePercent: number }; - system: { platform: string; hostname: string; uptimeFormatted: string }; + cpu: { usage: number; cores: number; physicalCores?: number; model: string; speed: number; speedMax?: number; loadAvg: number[]; coreLoads?: number[] }; + memory: { total: number; used: number; free: number; available?: number; usagePercent: number; swapTotal?: number; swapUsed?: number; cached?: number; buffers?: number }; + disk?: { total: number; used: number; free: number; usagePercent: number }; + network?: { rxSec: number; txSec: number; rxTotal: number; txTotal: number }; + system: { platform: string; distro?: string; hostname: string; uptimeFormatted: string }; }): void { + // CPU metrics this.cpuUsage = metrics.cpu.usage; this.cpuCores = metrics.cpu.cores; + this.cpuPhysicalCores = metrics.cpu.physicalCores || metrics.cpu.cores; this.cpuModel = metrics.cpu.model; this.cpuSpeed = metrics.cpu.speed; + this.cpuSpeedMax = metrics.cpu.speedMax || metrics.cpu.speed; this.loadAvg = metrics.cpu.loadAvg; + this.coreLoads = metrics.cpu.coreLoads || []; + + // Memory metrics this.memoryUsage = metrics.memory.usagePercent; this.memoryTotal = metrics.memory.total; this.memoryUsed = metrics.memory.used; this.memoryFree = metrics.memory.free; + this.memoryAvailable = metrics.memory.available || metrics.memory.free; + this.memoryCached = metrics.memory.cached || 0; + this.memoryBuffers = metrics.memory.buffers || 0; + this.swapTotal = metrics.memory.swapTotal || 0; + this.swapUsed = metrics.memory.swapUsed || 0; + + // Disk metrics + if (metrics.disk) { + this.diskUsage = metrics.disk.usagePercent; + this.diskTotal = metrics.disk.total; + this.diskUsed = metrics.disk.used; + this.diskFree = metrics.disk.free; + } + + // Network metrics + if (metrics.network) { + this.networkRxSec = metrics.network.rxSec; + this.networkTxSec = metrics.network.txSec; + this.networkRxTotal = metrics.network.rxTotal; + this.networkTxTotal = metrics.network.txTotal; + + // Update history for trend charts + this.networkInHistory = [...this.networkInHistory.slice(1), metrics.network.rxSec]; + this.networkOutHistory = [...this.networkOutHistory.slice(1), metrics.network.txSec]; + } + + // System metrics this.hostname = metrics.system.hostname; this.platform = metrics.system.platform; + this.distro = metrics.system.distro || ''; this.uptime = metrics.system.uptimeFormatted; } + // Method to set CPU temperature separately (may not always be available) + public setTemperature(temp: { main: number; cores?: number[]; max?: number }): void { + this.cpuTemp = temp.main || 0; + } + + // Method to set processes data + public setProcesses(data: { total: number; running: number; sleeping: number; list: any[] }): void { + // Could store and display process data if needed + } + // Helper to format bytes private formatBytes(bytes: number): string { if (bytes === 0) return '0 B'; @@ -331,6 +425,15 @@ export class EcoViewSystem extends DeesElement { } } + // Helper to format bytes per second as speed + private formatSpeed(bytesPerSec: number): string { + if (bytesPerSec === 0) return '0 B/s'; + const k = 1024; + const sizes = ['B/s', 'KB/s', 'MB/s', 'GB/s']; + const i = Math.floor(Math.log(bytesPerSec) / Math.log(k)); + return parseFloat((bytesPerSec / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; + } + private renderOverviewPanel(): TemplateResult { const overviewTiles = [ { @@ -339,6 +442,7 @@ export class EcoViewSystem extends DeesElement { value: this.cpuUsage, type: 'gauge' as const, icon: 'lucide:cpu', + description: this.cpuModel !== 'Unknown' ? `${this.cpuPhysicalCores} cores @ ${this.cpuSpeed} GHz` : undefined, gaugeOptions: { min: 0, max: 100, @@ -372,6 +476,7 @@ export class EcoViewSystem extends DeesElement { value: this.diskUsage, type: 'gauge' as const, icon: 'lucide:hardDrive', + description: this.diskTotal ? `${this.formatBytes(this.diskUsed)} of ${this.formatBytes(this.diskTotal)}` : undefined, gaugeOptions: { min: 0, max: 100, @@ -403,22 +508,22 @@ export class EcoViewSystem extends DeesElement { { id: 'network-in', title: 'Network In', - value: '85', - unit: 'Mbps', + value: this.formatSpeed(this.networkRxSec), type: 'trend' as const, icon: 'lucide:download', - trendData: this.networkIn, + trendData: this.networkInHistory, color: 'hsl(142 71% 45%)', + description: `Total: ${this.formatBytes(this.networkRxTotal)}`, }, { id: 'network-out', title: 'Network Out', - value: '65', - unit: 'Mbps', + value: this.formatSpeed(this.networkTxSec), type: 'trend' as const, icon: 'lucide:upload', - trendData: this.networkOut, + trendData: this.networkOutHistory, color: 'hsl(217 91% 60%)', + description: `Total: ${this.formatBytes(this.networkTxTotal)}`, }, { id: 'uptime', @@ -435,7 +540,7 @@ export class EcoViewSystem extends DeesElement { value: this.hostname, type: 'text' as const, icon: 'lucide:server', - description: `${this.platform} - ${this.cpuCores} cores`, + description: this.distro ? `${this.distro} - ${this.cpuCores} threads` : `${this.platform} - ${this.cpuCores} threads`, }, ]; @@ -456,6 +561,13 @@ export class EcoViewSystem extends DeesElement { } private renderCpuPanel(): TemplateResult { + // Generate cores data for cpuCores tile type + const coresData = this.coreLoads.map((load, index) => ({ + id: index, + usage: load, + label: `Core ${index}`, + })); + const cpuTiles = [ { id: 'cpu-total', @@ -463,6 +575,7 @@ export class EcoViewSystem extends DeesElement { value: this.cpuUsage, type: 'gauge' as const, icon: 'lucide:cpu', + description: `${this.cpuCores} threads on ${this.cpuPhysicalCores} cores`, gaugeOptions: { min: 0, max: 100, @@ -474,73 +587,21 @@ export class EcoViewSystem extends DeesElement { }, }, { - id: 'core-0', - title: 'Core 0', - value: 38, - type: 'gauge' as const, - gaugeOptions: { - min: 0, - max: 100, - thresholds: [ - { value: 0, color: 'hsl(142 71% 45%)' }, - { value: 60, color: 'hsl(45 93% 47%)' }, - { value: 80, color: 'hsl(0 84% 60%)' }, - ], - }, - }, - { - id: 'core-1', - title: 'Core 1', - value: 52, - type: 'gauge' as const, - gaugeOptions: { - min: 0, - max: 100, - thresholds: [ - { value: 0, color: 'hsl(142 71% 45%)' }, - { value: 60, color: 'hsl(45 93% 47%)' }, - { value: 80, color: 'hsl(0 84% 60%)' }, - ], - }, - }, - { - id: 'core-2', - title: 'Core 2', - value: 45, - type: 'gauge' as const, - gaugeOptions: { - min: 0, - max: 100, - thresholds: [ - { value: 0, color: 'hsl(142 71% 45%)' }, - { value: 60, color: 'hsl(45 93% 47%)' }, - { value: 80, color: 'hsl(0 84% 60%)' }, - ], - }, - }, - { - id: 'core-3', - title: 'Core 3', - value: 33, - type: 'gauge' as const, - gaugeOptions: { - min: 0, - max: 100, - thresholds: [ - { value: 0, color: 'hsl(142 71% 45%)' }, - { value: 60, color: 'hsl(45 93% 47%)' }, - { value: 80, color: 'hsl(0 84% 60%)' }, - ], - }, + id: 'cpu-cores', + title: 'Core Usage', + value: this.cpuUsage, + type: 'cpuCores' as const, + coresData: coresData, + columnSpan: 2, }, { id: 'load-avg', title: 'Load Average', - value: '2.45', + value: this.loadAvg[0]?.toFixed(2) || '0', type: 'trend' as const, icon: 'lucide:activity', - trendData: [1.8, 2.1, 2.4, 2.2, 2.5, 2.3, 2.6, 2.4, 2.45], - description: '1m: 2.45, 5m: 2.32, 15m: 2.18', + trendData: this.loadAvg, + description: `1m: ${this.loadAvg[0]?.toFixed(2)}, 5m: ${this.loadAvg[1]?.toFixed(2)}, 15m: ${this.loadAvg[2]?.toFixed(2)}`, }, { id: 'cpu-temp', @@ -563,18 +624,18 @@ export class EcoViewSystem extends DeesElement { { id: 'freq', title: 'Clock Speed', - value: '3.2', + value: this.cpuSpeed.toFixed(1), unit: 'GHz', type: 'number' as const, icon: 'lucide:gauge', - description: 'Max: 4.2 GHz', + description: this.cpuSpeedMax ? `Max: ${this.cpuSpeedMax.toFixed(1)} GHz` : undefined, }, ]; return html`
CPU
-
Processor usage and performance
+
${this.cpuModel}
@@ -588,6 +649,8 @@ export class EcoViewSystem extends DeesElement { } private renderMemoryPanel(): TemplateResult { + const swapUsagePercent = this.swapTotal > 0 ? Math.round((this.swapUsed / this.swapTotal) * 100) : 0; + const memoryTiles = [ { id: 'ram-usage', @@ -604,12 +667,12 @@ export class EcoViewSystem extends DeesElement { { value: 85, color: 'hsl(0 84% 60%)' }, ], }, - description: '10.7 GB of 16 GB', + description: `${this.formatBytes(this.memoryUsed)} of ${this.formatBytes(this.memoryTotal)}`, }, { id: 'swap-usage', title: 'Swap Usage', - value: 12, + value: swapUsagePercent, type: 'gauge' as const, icon: 'lucide:hardDrive', gaugeOptions: { @@ -621,41 +684,38 @@ export class EcoViewSystem extends DeesElement { { value: 75, color: 'hsl(0 84% 60%)' }, ], }, - description: '0.5 GB of 4 GB', + description: this.swapTotal > 0 ? `${this.formatBytes(this.swapUsed)} of ${this.formatBytes(this.swapTotal)}` : 'No swap', }, { id: 'mem-trend', title: 'Memory History', - value: '67%', + value: `${this.memoryUsage}%`, type: 'trend' as const, icon: 'lucide:trendingUp', - trendData: [58, 62, 65, 63, 68, 72, 70, 65, 67], - description: 'Last hour', + trendData: [58, 62, 65, 63, 68, 72, 70, 65, this.memoryUsage], + description: 'Recent usage', }, { id: 'cached', title: 'Cached', - value: '3.2', - unit: 'GB', - type: 'number' as const, + value: this.formatBytes(this.memoryCached), + type: 'text' as const, icon: 'lucide:database', color: 'hsl(217 91% 60%)', }, { id: 'buffers', title: 'Buffers', - value: '512', - unit: 'MB', - type: 'number' as const, + value: this.formatBytes(this.memoryBuffers), + type: 'text' as const, icon: 'lucide:layers', color: 'hsl(262 83% 58%)', }, { id: 'available', title: 'Available', - value: '5.3', - unit: 'GB', - type: 'number' as const, + value: this.formatBytes(this.memoryAvailable), + type: 'text' as const, icon: 'lucide:checkCircle', color: 'hsl(142 71% 45%)', }, @@ -680,58 +740,39 @@ export class EcoViewSystem extends DeesElement { private renderStoragePanel(): TemplateResult { const storageTiles = [ { - id: 'disk-main', - title: 'System Drive', + id: 'disk-total', + title: 'Total Storage', value: this.diskUsage, type: 'percentage' as const, icon: 'lucide:hardDrive', - description: '275 GB of 512 GB used', + description: `${this.formatBytes(this.diskUsed)} of ${this.formatBytes(this.diskTotal)} used`, color: 'hsl(217 91% 60%)', }, { - id: 'disk-data', - title: 'Data Drive', - value: 38, - type: 'percentage' as const, + id: 'disk-free', + title: 'Free Space', + value: this.formatBytes(this.diskFree), + type: 'text' as const, icon: 'lucide:hardDrive', - description: '380 GB of 1 TB used', + description: 'Available storage', color: 'hsl(142 71% 45%)', }, { - id: 'read-speed', - title: 'Read Speed', - value: '245', - unit: 'MB/s', - type: 'trend' as const, - icon: 'lucide:download', - trendData: [180, 220, 195, 280, 245, 210, 265, 230, 245], - color: 'hsl(142 71% 45%)', + id: 'disk-used', + title: 'Used Space', + value: this.formatBytes(this.diskUsed), + type: 'text' as const, + icon: 'lucide:database', + description: 'Currently in use', + color: 'hsl(45 93% 47%)', }, { - id: 'write-speed', - title: 'Write Speed', - value: '128', - unit: 'MB/s', - type: 'trend' as const, - icon: 'lucide:upload', - trendData: [95, 110, 85, 145, 120, 105, 138, 115, 128], - color: 'hsl(217 91% 60%)', - }, - { - id: 'iops-read', - title: 'Read IOPS', - value: '12.4k', - type: 'number' as const, - icon: 'lucide:gauge', - description: 'Operations/sec', - }, - { - id: 'iops-write', - title: 'Write IOPS', - value: '8.2k', - type: 'number' as const, - icon: 'lucide:gauge', - description: 'Operations/sec', + id: 'disk-total-size', + title: 'Total Capacity', + value: this.formatBytes(this.diskTotal), + type: 'text' as const, + icon: 'lucide:server', + description: 'All filesystems', }, ]; @@ -755,83 +796,38 @@ export class EcoViewSystem extends DeesElement { const networkTiles = [ { id: 'download', - title: 'Download', - value: '85.2', - unit: 'Mbps', + title: 'Download Speed', + value: this.formatSpeed(this.networkRxSec), type: 'trend' as const, icon: 'lucide:download', - trendData: this.networkIn, + trendData: this.networkInHistory, color: 'hsl(142 71% 45%)', }, { id: 'upload', - title: 'Upload', - value: '64.8', - unit: 'Mbps', + title: 'Upload Speed', + value: this.formatSpeed(this.networkTxSec), type: 'trend' as const, icon: 'lucide:upload', - trendData: this.networkOut, + trendData: this.networkOutHistory, color: 'hsl(217 91% 60%)', }, - { - id: 'latency', - title: 'Latency', - value: 12, - unit: 'ms', - type: 'gauge' as const, - icon: 'lucide:activity', - gaugeOptions: { - min: 0, - max: 100, - thresholds: [ - { value: 0, color: 'hsl(142 71% 45%)' }, - { value: 30, color: 'hsl(45 93% 47%)' }, - { value: 60, color: 'hsl(0 84% 60%)' }, - ], - }, - }, - { - id: 'packets-in', - title: 'Packets In', - value: '1.2M', - type: 'number' as const, - icon: 'lucide:arrowDownCircle', - description: 'Per second', - }, - { - id: 'packets-out', - title: 'Packets Out', - value: '892k', - type: 'number' as const, - icon: 'lucide:arrowUpCircle', - description: 'Per second', - }, - { - id: 'connections', - title: 'Active Connections', - value: 48, - type: 'number' as const, - icon: 'lucide:link', - description: '12 established, 36 waiting', - }, { id: 'total-down', title: 'Total Downloaded', - value: '24.5', - unit: 'GB', - type: 'number' as const, - icon: 'lucide:database', - description: 'This session', + value: this.formatBytes(this.networkRxTotal), + type: 'text' as const, + icon: 'lucide:arrowDownCircle', + description: 'Since boot', color: 'hsl(142 71% 45%)', }, { id: 'total-up', title: 'Total Uploaded', - value: '8.2', - unit: 'GB', - type: 'number' as const, - icon: 'lucide:database', - description: 'This session', + value: this.formatBytes(this.networkTxTotal), + type: 'text' as const, + icon: 'lucide:arrowUpCircle', + description: 'Since boot', color: 'hsl(217 91% 60%)', }, ];