2026-01-12 10:57:54 +00:00
|
|
|
import {
|
|
|
|
|
customElement,
|
|
|
|
|
DeesElement,
|
|
|
|
|
type TemplateResult,
|
|
|
|
|
html,
|
|
|
|
|
property,
|
|
|
|
|
css,
|
|
|
|
|
cssManager,
|
|
|
|
|
state,
|
|
|
|
|
} from '@design.estate/dees-element';
|
|
|
|
|
import { DeesAppuiSecondarymenu, DeesIcon, DeesStatsGrid } from '@design.estate/dees-catalog';
|
|
|
|
|
import type { ISecondaryMenuGroup, ISecondaryMenuItem } from '../../elements/interfaces/secondarymenu.js';
|
|
|
|
|
import { demo } from './eco-view-system.demo.js';
|
|
|
|
|
|
|
|
|
|
// Ensure components are registered
|
|
|
|
|
DeesAppuiSecondarymenu;
|
|
|
|
|
DeesIcon;
|
|
|
|
|
DeesStatsGrid;
|
|
|
|
|
|
|
|
|
|
declare global {
|
|
|
|
|
interface HTMLElementTagNameMap {
|
|
|
|
|
'eco-view-system': EcoViewSystem;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type TSystemPanel =
|
|
|
|
|
| 'overview'
|
|
|
|
|
| 'cpu'
|
|
|
|
|
| 'memory'
|
|
|
|
|
| 'storage'
|
|
|
|
|
| 'network'
|
|
|
|
|
| 'processes';
|
|
|
|
|
|
|
|
|
|
@customElement('eco-view-system')
|
|
|
|
|
export class EcoViewSystem extends DeesElement {
|
|
|
|
|
public static demo = demo;
|
|
|
|
|
public static demoGroup = 'Views';
|
|
|
|
|
|
|
|
|
|
public static styles = [
|
|
|
|
|
cssManager.defaultStyles,
|
|
|
|
|
css`
|
|
|
|
|
:host {
|
|
|
|
|
display: block;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
background: ${cssManager.bdTheme('#f5f5f7', 'hsl(240 6% 10%)')};
|
|
|
|
|
color: ${cssManager.bdTheme('hsl(0 0% 10%)', 'hsl(0 0% 98%)')};
|
|
|
|
|
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.system-container {
|
|
|
|
|
display: flex;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dees-appui-secondarymenu {
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
background: ${cssManager.bdTheme('#ffffff', 'hsl(240 6% 8%)')};
|
|
|
|
|
border-right: 1px solid ${cssManager.bdTheme('hsl(0 0% 90%)', 'hsl(240 5% 15%)')};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.content {
|
|
|
|
|
flex: 1;
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
padding: 32px 48px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.panel-header {
|
|
|
|
|
margin-bottom: 32px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.panel-title {
|
|
|
|
|
font-size: 28px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: ${cssManager.bdTheme('hsl(0 0% 10%)', 'hsl(0 0% 98%)')};
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.panel-description {
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
color: ${cssManager.bdTheme('hsl(0 0% 50%)', 'hsl(0 0% 60%)')};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.stats-section {
|
|
|
|
|
margin-bottom: 32px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section-title {
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: ${cssManager.bdTheme('hsl(0 0% 50%)', 'hsl(0 0% 50%)')};
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
letter-spacing: 0.5px;
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dees-statsgrid {
|
|
|
|
|
--dees-statsgrid-gap: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.process-list {
|
|
|
|
|
background: ${cssManager.bdTheme('#ffffff', 'hsl(240 6% 12%)')};
|
|
|
|
|
border: 1px solid ${cssManager.bdTheme('hsl(0 0% 90%)', 'hsl(240 5% 18%)')};
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.process-header {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: 2fr 1fr 1fr 1fr;
|
|
|
|
|
padding: 12px 16px;
|
|
|
|
|
background: ${cssManager.bdTheme('hsl(0 0% 97%)', 'hsl(240 5% 14%)')};
|
|
|
|
|
border-bottom: 1px solid ${cssManager.bdTheme('hsl(0 0% 90%)', 'hsl(240 5% 18%)')};
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: ${cssManager.bdTheme('hsl(0 0% 50%)', 'hsl(0 0% 55%)')};
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
letter-spacing: 0.5px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.process-row {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: 2fr 1fr 1fr 1fr;
|
|
|
|
|
padding: 12px 16px;
|
|
|
|
|
border-bottom: 1px solid ${cssManager.bdTheme('hsl(0 0% 94%)', 'hsl(240 5% 15%)')};
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 85%)')};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.process-row:last-child {
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.process-name {
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.process-value {
|
|
|
|
|
color: ${cssManager.bdTheme('hsl(0 0% 40%)', 'hsl(0 0% 65%)')};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.process-value.high {
|
|
|
|
|
color: hsl(0 84% 60%);
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
|
|
|
|
`,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
@property({ type: String })
|
|
|
|
|
accessor activePanel: TSystemPanel = 'overview';
|
|
|
|
|
|
2026-01-12 15:16:01 +00:00
|
|
|
// System data (can be set externally)
|
|
|
|
|
@property({ type: Number })
|
|
|
|
|
accessor cpuUsage = 0;
|
2026-01-12 10:57:54 +00:00
|
|
|
|
2026-01-12 15:16:01 +00:00
|
|
|
@property({ type: Number })
|
|
|
|
|
accessor memoryUsage = 0;
|
2026-01-12 10:57:54 +00:00
|
|
|
|
2026-01-12 15:16:01 +00:00
|
|
|
@property({ type: Number })
|
|
|
|
|
accessor diskUsage = 0;
|
2026-01-12 10:57:54 +00:00
|
|
|
|
2026-01-12 15:16:01 +00:00
|
|
|
@property({ type: Number })
|
|
|
|
|
accessor cpuTemp = 0;
|
2026-01-12 10:57:54 +00:00
|
|
|
|
2026-01-12 15:16:01 +00:00
|
|
|
@property({ type: String })
|
|
|
|
|
accessor uptime = '--';
|
|
|
|
|
|
|
|
|
|
@property({ type: Number })
|
|
|
|
|
accessor cpuCores = 0;
|
|
|
|
|
|
2026-01-12 18:10:20 +00:00
|
|
|
@property({ type: Number })
|
|
|
|
|
accessor cpuPhysicalCores = 0;
|
|
|
|
|
|
2026-01-12 15:16:01 +00:00
|
|
|
@property({ type: String })
|
|
|
|
|
accessor cpuModel = 'Unknown';
|
|
|
|
|
|
|
|
|
|
@property({ type: Number })
|
|
|
|
|
accessor cpuSpeed = 0;
|
|
|
|
|
|
2026-01-12 18:10:20 +00:00
|
|
|
@property({ type: Number })
|
|
|
|
|
accessor cpuSpeedMax = 0;
|
|
|
|
|
|
2026-01-12 15:16:01 +00:00
|
|
|
@property({ type: Number })
|
|
|
|
|
accessor memoryTotal = 0;
|
|
|
|
|
|
|
|
|
|
@property({ type: Number })
|
|
|
|
|
accessor memoryUsed = 0;
|
|
|
|
|
|
|
|
|
|
@property({ type: Number })
|
|
|
|
|
accessor memoryFree = 0;
|
|
|
|
|
|
2026-01-12 18:10:20 +00:00
|
|
|
@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;
|
|
|
|
|
|
2026-01-12 15:16:01 +00:00
|
|
|
@property({ type: String })
|
|
|
|
|
accessor hostname = 'Unknown';
|
|
|
|
|
|
|
|
|
|
@property({ type: String })
|
|
|
|
|
accessor platform = 'Unknown';
|
|
|
|
|
|
2026-01-12 18:10:20 +00:00
|
|
|
@property({ type: String })
|
|
|
|
|
accessor distro = '';
|
|
|
|
|
|
2026-01-12 15:16:01 +00:00
|
|
|
@property({ type: Array })
|
|
|
|
|
accessor loadAvg: number[] = [0, 0, 0];
|
2026-01-12 10:57:54 +00:00
|
|
|
|
2026-01-12 18:10:20 +00:00
|
|
|
@property({ type: Array })
|
|
|
|
|
accessor coreLoads: number[] = [];
|
|
|
|
|
|
2026-01-12 10:57:54 +00:00
|
|
|
@state()
|
2026-01-12 18:10:20 +00:00
|
|
|
accessor networkInHistory: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
2026-01-12 10:57:54 +00:00
|
|
|
|
|
|
|
|
@state()
|
2026-01-12 18:10:20 +00:00
|
|
|
accessor networkOutHistory: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
2026-01-12 15:16:01 +00:00
|
|
|
|
2026-01-12 23:44:05 +00:00
|
|
|
@state()
|
|
|
|
|
accessor memoryUsageHistory: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
|
|
|
|
|
|
|
|
// Process data
|
|
|
|
|
@state()
|
|
|
|
|
accessor processTotal = 0;
|
|
|
|
|
|
|
|
|
|
@state()
|
|
|
|
|
accessor processRunning = 0;
|
|
|
|
|
|
|
|
|
|
@state()
|
|
|
|
|
accessor processSleeping = 0;
|
|
|
|
|
|
|
|
|
|
@state()
|
|
|
|
|
accessor processBlocked = 0;
|
|
|
|
|
|
|
|
|
|
@state()
|
|
|
|
|
accessor topProcesses: Array<{ name: string; pid: number; cpu: number; memory: number; state: string }> = [];
|
|
|
|
|
|
2026-01-12 15:16:01 +00:00
|
|
|
// Public method to update metrics from backend
|
|
|
|
|
public setMetrics(metrics: {
|
2026-01-12 18:10:20 +00:00
|
|
|
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 };
|
2026-01-12 15:16:01 +00:00
|
|
|
}): void {
|
2026-01-12 18:10:20 +00:00
|
|
|
// CPU metrics
|
2026-01-12 15:16:01 +00:00
|
|
|
this.cpuUsage = metrics.cpu.usage;
|
|
|
|
|
this.cpuCores = metrics.cpu.cores;
|
2026-01-12 18:10:20 +00:00
|
|
|
this.cpuPhysicalCores = metrics.cpu.physicalCores || metrics.cpu.cores;
|
2026-01-12 15:16:01 +00:00
|
|
|
this.cpuModel = metrics.cpu.model;
|
|
|
|
|
this.cpuSpeed = metrics.cpu.speed;
|
2026-01-12 18:10:20 +00:00
|
|
|
this.cpuSpeedMax = metrics.cpu.speedMax || metrics.cpu.speed;
|
2026-01-12 15:16:01 +00:00
|
|
|
this.loadAvg = metrics.cpu.loadAvg;
|
2026-01-12 18:10:20 +00:00
|
|
|
this.coreLoads = metrics.cpu.coreLoads || [];
|
|
|
|
|
|
|
|
|
|
// Memory metrics
|
2026-01-12 15:16:01 +00:00
|
|
|
this.memoryUsage = metrics.memory.usagePercent;
|
|
|
|
|
this.memoryTotal = metrics.memory.total;
|
|
|
|
|
this.memoryUsed = metrics.memory.used;
|
|
|
|
|
this.memoryFree = metrics.memory.free;
|
2026-01-12 18:10:20 +00:00
|
|
|
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;
|
|
|
|
|
|
2026-01-12 23:44:05 +00:00
|
|
|
// Update memory usage history for trend chart
|
|
|
|
|
this.memoryUsageHistory = [...this.memoryUsageHistory.slice(1), metrics.memory.usagePercent];
|
|
|
|
|
|
2026-01-12 18:10:20 +00:00
|
|
|
// 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
|
2026-01-12 15:16:01 +00:00
|
|
|
this.hostname = metrics.system.hostname;
|
|
|
|
|
this.platform = metrics.system.platform;
|
2026-01-12 18:10:20 +00:00
|
|
|
this.distro = metrics.system.distro || '';
|
2026-01-12 15:16:01 +00:00
|
|
|
this.uptime = metrics.system.uptimeFormatted;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-12 18:10:20 +00:00
|
|
|
// 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
|
2026-01-12 23:44:05 +00:00
|
|
|
public setProcesses(data: { total: number; running: number; sleeping: number; blocked?: number; list: Array<{ name: string; pid: number; cpu: number; memory: number; state: string }> }): void {
|
|
|
|
|
this.processTotal = data.total;
|
|
|
|
|
this.processRunning = data.running;
|
|
|
|
|
this.processSleeping = data.sleeping;
|
|
|
|
|
this.processBlocked = data.blocked || 0;
|
|
|
|
|
this.topProcesses = data.list || [];
|
2026-01-12 18:10:20 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-12 15:16:01 +00:00
|
|
|
// Helper to format bytes
|
|
|
|
|
private formatBytes(bytes: number): string {
|
|
|
|
|
if (bytes === 0) return '0 B';
|
|
|
|
|
const k = 1024;
|
|
|
|
|
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
|
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
|
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
|
|
|
|
}
|
2026-01-12 10:57:54 +00:00
|
|
|
|
|
|
|
|
private getMenuGroups(): ISecondaryMenuGroup[] {
|
|
|
|
|
return [
|
|
|
|
|
{
|
|
|
|
|
name: 'Monitor',
|
|
|
|
|
iconName: 'lucide:activity',
|
|
|
|
|
items: [
|
|
|
|
|
{
|
|
|
|
|
key: 'overview',
|
|
|
|
|
iconName: 'lucide:layoutDashboard',
|
|
|
|
|
action: () => this.activePanel = 'overview',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'Hardware',
|
|
|
|
|
iconName: 'lucide:cpu',
|
|
|
|
|
items: [
|
|
|
|
|
{
|
|
|
|
|
key: 'cpu',
|
|
|
|
|
iconName: 'lucide:cpu',
|
|
|
|
|
action: () => this.activePanel = 'cpu',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
key: 'memory',
|
|
|
|
|
iconName: 'lucide:memoryStick',
|
|
|
|
|
action: () => this.activePanel = 'memory',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
key: 'storage',
|
|
|
|
|
iconName: 'lucide:hardDrive',
|
|
|
|
|
action: () => this.activePanel = 'storage',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'Network',
|
|
|
|
|
iconName: 'lucide:network',
|
|
|
|
|
items: [
|
|
|
|
|
{
|
|
|
|
|
key: 'network',
|
|
|
|
|
iconName: 'lucide:wifi',
|
|
|
|
|
action: () => this.activePanel = 'network',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'Software',
|
|
|
|
|
iconName: 'lucide:layers',
|
|
|
|
|
items: [
|
|
|
|
|
{
|
|
|
|
|
key: 'processes',
|
|
|
|
|
iconName: 'lucide:listTree',
|
|
|
|
|
action: () => this.activePanel = 'processes',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private getSelectedItem(): ISecondaryMenuItem | null {
|
|
|
|
|
for (const group of this.getMenuGroups()) {
|
|
|
|
|
for (const item of group.items) {
|
|
|
|
|
if ('key' in item && item.key === this.activePanel) {
|
|
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public render(): TemplateResult {
|
|
|
|
|
return html`
|
|
|
|
|
<div class="system-container">
|
|
|
|
|
<dees-appui-secondarymenu
|
|
|
|
|
.heading=${'System'}
|
|
|
|
|
.groups=${this.getMenuGroups()}
|
|
|
|
|
.selectedItem=${this.getSelectedItem()}
|
|
|
|
|
></dees-appui-secondarymenu>
|
|
|
|
|
<div class="content">
|
|
|
|
|
${this.renderActivePanel()}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private renderActivePanel(): TemplateResult {
|
|
|
|
|
switch (this.activePanel) {
|
|
|
|
|
case 'overview':
|
|
|
|
|
return this.renderOverviewPanel();
|
|
|
|
|
case 'cpu':
|
|
|
|
|
return this.renderCpuPanel();
|
|
|
|
|
case 'memory':
|
|
|
|
|
return this.renderMemoryPanel();
|
|
|
|
|
case 'storage':
|
|
|
|
|
return this.renderStoragePanel();
|
|
|
|
|
case 'network':
|
|
|
|
|
return this.renderNetworkPanel();
|
|
|
|
|
case 'processes':
|
|
|
|
|
return this.renderProcessesPanel();
|
|
|
|
|
default:
|
|
|
|
|
return this.renderOverviewPanel();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-12 18:10:20 +00:00
|
|
|
// 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];
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-12 10:57:54 +00:00
|
|
|
private renderOverviewPanel(): TemplateResult {
|
|
|
|
|
const overviewTiles = [
|
|
|
|
|
{
|
|
|
|
|
id: 'cpu',
|
|
|
|
|
title: 'CPU Usage',
|
|
|
|
|
value: this.cpuUsage,
|
|
|
|
|
type: 'gauge' as const,
|
|
|
|
|
icon: 'lucide:cpu',
|
2026-01-12 18:10:20 +00:00
|
|
|
description: this.cpuModel !== 'Unknown' ? `${this.cpuPhysicalCores} cores @ ${this.cpuSpeed} GHz` : undefined,
|
2026-01-12 10:57:54 +00:00
|
|
|
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: 'memory',
|
|
|
|
|
title: 'Memory Usage',
|
|
|
|
|
value: this.memoryUsage,
|
|
|
|
|
type: 'gauge' as const,
|
|
|
|
|
icon: 'lucide:memoryStick',
|
2026-01-12 15:16:01 +00:00
|
|
|
description: this.memoryTotal ? `${this.formatBytes(this.memoryUsed)} of ${this.formatBytes(this.memoryTotal)}` : undefined,
|
2026-01-12 10:57:54 +00:00
|
|
|
gaugeOptions: {
|
|
|
|
|
min: 0,
|
|
|
|
|
max: 100,
|
|
|
|
|
thresholds: [
|
|
|
|
|
{ value: 0, color: 'hsl(142 71% 45%)' },
|
|
|
|
|
{ value: 70, color: 'hsl(45 93% 47%)' },
|
|
|
|
|
{ value: 85, color: 'hsl(0 84% 60%)' },
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'disk',
|
|
|
|
|
title: 'Disk Usage',
|
|
|
|
|
value: this.diskUsage,
|
|
|
|
|
type: 'gauge' as const,
|
|
|
|
|
icon: 'lucide:hardDrive',
|
2026-01-12 18:10:20 +00:00
|
|
|
description: this.diskTotal ? `${this.formatBytes(this.diskUsed)} of ${this.formatBytes(this.diskTotal)}` : undefined,
|
2026-01-12 10:57:54 +00:00
|
|
|
gaugeOptions: {
|
|
|
|
|
min: 0,
|
|
|
|
|
max: 100,
|
|
|
|
|
thresholds: [
|
|
|
|
|
{ value: 0, color: 'hsl(142 71% 45%)' },
|
|
|
|
|
{ value: 75, color: 'hsl(45 93% 47%)' },
|
|
|
|
|
{ value: 90, color: 'hsl(0 84% 60%)' },
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'temp',
|
|
|
|
|
title: 'CPU Temp',
|
|
|
|
|
value: this.cpuTemp,
|
|
|
|
|
unit: '°C',
|
|
|
|
|
type: 'gauge' as const,
|
|
|
|
|
icon: 'lucide:thermometer',
|
|
|
|
|
gaugeOptions: {
|
|
|
|
|
min: 0,
|
|
|
|
|
max: 100,
|
|
|
|
|
thresholds: [
|
|
|
|
|
{ value: 0, color: 'hsl(217 91% 60%)' },
|
|
|
|
|
{ value: 50, color: 'hsl(142 71% 45%)' },
|
|
|
|
|
{ value: 70, color: 'hsl(45 93% 47%)' },
|
|
|
|
|
{ value: 85, color: 'hsl(0 84% 60%)' },
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'network-in',
|
|
|
|
|
title: 'Network In',
|
2026-01-12 18:10:20 +00:00
|
|
|
value: this.formatSpeed(this.networkRxSec),
|
2026-01-12 10:57:54 +00:00
|
|
|
type: 'trend' as const,
|
|
|
|
|
icon: 'lucide:download',
|
2026-01-12 18:10:20 +00:00
|
|
|
trendData: this.networkInHistory,
|
2026-01-12 10:57:54 +00:00
|
|
|
color: 'hsl(142 71% 45%)',
|
2026-01-12 18:10:20 +00:00
|
|
|
description: `Total: ${this.formatBytes(this.networkRxTotal)}`,
|
2026-01-12 10:57:54 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'network-out',
|
|
|
|
|
title: 'Network Out',
|
2026-01-12 18:10:20 +00:00
|
|
|
value: this.formatSpeed(this.networkTxSec),
|
2026-01-12 10:57:54 +00:00
|
|
|
type: 'trend' as const,
|
|
|
|
|
icon: 'lucide:upload',
|
2026-01-12 18:10:20 +00:00
|
|
|
trendData: this.networkOutHistory,
|
2026-01-12 10:57:54 +00:00
|
|
|
color: 'hsl(217 91% 60%)',
|
2026-01-12 18:10:20 +00:00
|
|
|
description: `Total: ${this.formatBytes(this.networkTxTotal)}`,
|
2026-01-12 10:57:54 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'uptime',
|
|
|
|
|
title: 'System Uptime',
|
|
|
|
|
value: this.uptime,
|
|
|
|
|
type: 'text' as const,
|
|
|
|
|
icon: 'lucide:clock',
|
|
|
|
|
color: 'hsl(142 71% 45%)',
|
|
|
|
|
description: 'Since last reboot',
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-12 15:16:01 +00:00
|
|
|
id: 'hostname',
|
|
|
|
|
title: 'Hostname',
|
|
|
|
|
value: this.hostname,
|
|
|
|
|
type: 'text' as const,
|
|
|
|
|
icon: 'lucide:server',
|
2026-01-12 18:10:20 +00:00
|
|
|
description: this.distro ? `${this.distro} - ${this.cpuCores} threads` : `${this.platform} - ${this.cpuCores} threads`,
|
2026-01-12 10:57:54 +00:00
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return html`
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
<div class="panel-title">System Overview</div>
|
|
|
|
|
<div class="panel-description">Real-time system performance metrics</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="stats-section">
|
|
|
|
|
<dees-statsgrid
|
|
|
|
|
.tiles=${overviewTiles}
|
|
|
|
|
.minTileWidth=${220}
|
|
|
|
|
.gap=${16}
|
|
|
|
|
></dees-statsgrid>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private renderCpuPanel(): TemplateResult {
|
2026-01-12 18:10:20 +00:00
|
|
|
// Generate cores data for cpuCores tile type
|
|
|
|
|
const coresData = this.coreLoads.map((load, index) => ({
|
|
|
|
|
id: index,
|
|
|
|
|
usage: load,
|
|
|
|
|
label: `Core ${index}`,
|
|
|
|
|
}));
|
|
|
|
|
|
2026-01-12 10:57:54 +00:00
|
|
|
const cpuTiles = [
|
|
|
|
|
{
|
|
|
|
|
id: 'cpu-total',
|
|
|
|
|
title: 'Total CPU Usage',
|
|
|
|
|
value: this.cpuUsage,
|
|
|
|
|
type: 'gauge' as const,
|
|
|
|
|
icon: 'lucide:cpu',
|
2026-01-12 18:10:20 +00:00
|
|
|
description: `${this.cpuCores} threads on ${this.cpuPhysicalCores} cores`,
|
2026-01-12 10:57:54 +00:00
|
|
|
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%)' },
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-12 18:10:20 +00:00
|
|
|
id: 'cpu-cores',
|
|
|
|
|
title: 'Core Usage',
|
|
|
|
|
value: this.cpuUsage,
|
|
|
|
|
type: 'cpuCores' as const,
|
|
|
|
|
coresData: coresData,
|
|
|
|
|
columnSpan: 2,
|
2026-01-12 10:57:54 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'load-avg',
|
|
|
|
|
title: 'Load Average',
|
2026-01-12 18:10:20 +00:00
|
|
|
value: this.loadAvg[0]?.toFixed(2) || '0',
|
2026-01-12 10:57:54 +00:00
|
|
|
type: 'trend' as const,
|
|
|
|
|
icon: 'lucide:activity',
|
2026-01-12 18:10:20 +00:00
|
|
|
trendData: this.loadAvg,
|
|
|
|
|
description: `1m: ${this.loadAvg[0]?.toFixed(2)}, 5m: ${this.loadAvg[1]?.toFixed(2)}, 15m: ${this.loadAvg[2]?.toFixed(2)}`,
|
2026-01-12 10:57:54 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'cpu-temp',
|
|
|
|
|
title: 'Temperature',
|
|
|
|
|
value: this.cpuTemp,
|
|
|
|
|
unit: '°C',
|
|
|
|
|
type: 'gauge' as const,
|
|
|
|
|
icon: 'lucide:thermometer',
|
|
|
|
|
gaugeOptions: {
|
|
|
|
|
min: 0,
|
|
|
|
|
max: 100,
|
|
|
|
|
thresholds: [
|
|
|
|
|
{ value: 0, color: 'hsl(217 91% 60%)' },
|
|
|
|
|
{ value: 50, color: 'hsl(142 71% 45%)' },
|
|
|
|
|
{ value: 70, color: 'hsl(45 93% 47%)' },
|
|
|
|
|
{ value: 85, color: 'hsl(0 84% 60%)' },
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'freq',
|
|
|
|
|
title: 'Clock Speed',
|
2026-01-12 18:10:20 +00:00
|
|
|
value: this.cpuSpeed.toFixed(1),
|
2026-01-12 10:57:54 +00:00
|
|
|
unit: 'GHz',
|
|
|
|
|
type: 'number' as const,
|
|
|
|
|
icon: 'lucide:gauge',
|
2026-01-12 18:10:20 +00:00
|
|
|
description: this.cpuSpeedMax ? `Max: ${this.cpuSpeedMax.toFixed(1)} GHz` : undefined,
|
2026-01-12 10:57:54 +00:00
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return html`
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
<div class="panel-title">CPU</div>
|
2026-01-12 18:10:20 +00:00
|
|
|
<div class="panel-description">${this.cpuModel}</div>
|
2026-01-12 10:57:54 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="stats-section">
|
|
|
|
|
<dees-statsgrid
|
|
|
|
|
.tiles=${cpuTiles}
|
|
|
|
|
.minTileWidth=${200}
|
|
|
|
|
.gap=${16}
|
|
|
|
|
></dees-statsgrid>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private renderMemoryPanel(): TemplateResult {
|
2026-01-12 18:10:20 +00:00
|
|
|
const swapUsagePercent = this.swapTotal > 0 ? Math.round((this.swapUsed / this.swapTotal) * 100) : 0;
|
|
|
|
|
|
2026-01-12 10:57:54 +00:00
|
|
|
const memoryTiles = [
|
|
|
|
|
{
|
|
|
|
|
id: 'ram-usage',
|
|
|
|
|
title: 'RAM Usage',
|
|
|
|
|
value: this.memoryUsage,
|
|
|
|
|
type: 'gauge' as const,
|
|
|
|
|
icon: 'lucide:memoryStick',
|
|
|
|
|
gaugeOptions: {
|
|
|
|
|
min: 0,
|
|
|
|
|
max: 100,
|
|
|
|
|
thresholds: [
|
|
|
|
|
{ value: 0, color: 'hsl(142 71% 45%)' },
|
|
|
|
|
{ value: 70, color: 'hsl(45 93% 47%)' },
|
|
|
|
|
{ value: 85, color: 'hsl(0 84% 60%)' },
|
|
|
|
|
],
|
|
|
|
|
},
|
2026-01-12 18:10:20 +00:00
|
|
|
description: `${this.formatBytes(this.memoryUsed)} of ${this.formatBytes(this.memoryTotal)}`,
|
2026-01-12 10:57:54 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'swap-usage',
|
|
|
|
|
title: 'Swap Usage',
|
2026-01-12 18:10:20 +00:00
|
|
|
value: swapUsagePercent,
|
2026-01-12 10:57:54 +00:00
|
|
|
type: 'gauge' as const,
|
|
|
|
|
icon: 'lucide:hardDrive',
|
|
|
|
|
gaugeOptions: {
|
|
|
|
|
min: 0,
|
|
|
|
|
max: 100,
|
|
|
|
|
thresholds: [
|
|
|
|
|
{ value: 0, color: 'hsl(142 71% 45%)' },
|
|
|
|
|
{ value: 50, color: 'hsl(45 93% 47%)' },
|
|
|
|
|
{ value: 75, color: 'hsl(0 84% 60%)' },
|
|
|
|
|
],
|
|
|
|
|
},
|
2026-01-12 18:10:20 +00:00
|
|
|
description: this.swapTotal > 0 ? `${this.formatBytes(this.swapUsed)} of ${this.formatBytes(this.swapTotal)}` : 'No swap',
|
2026-01-12 10:57:54 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'mem-trend',
|
|
|
|
|
title: 'Memory History',
|
2026-01-12 18:10:20 +00:00
|
|
|
value: `${this.memoryUsage}%`,
|
2026-01-12 10:57:54 +00:00
|
|
|
type: 'trend' as const,
|
|
|
|
|
icon: 'lucide:trendingUp',
|
2026-01-12 23:44:05 +00:00
|
|
|
trendData: this.memoryUsageHistory,
|
2026-01-12 18:10:20 +00:00
|
|
|
description: 'Recent usage',
|
2026-01-12 10:57:54 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'cached',
|
|
|
|
|
title: 'Cached',
|
2026-01-12 18:10:20 +00:00
|
|
|
value: this.formatBytes(this.memoryCached),
|
|
|
|
|
type: 'text' as const,
|
2026-01-12 10:57:54 +00:00
|
|
|
icon: 'lucide:database',
|
|
|
|
|
color: 'hsl(217 91% 60%)',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'buffers',
|
|
|
|
|
title: 'Buffers',
|
2026-01-12 18:10:20 +00:00
|
|
|
value: this.formatBytes(this.memoryBuffers),
|
|
|
|
|
type: 'text' as const,
|
2026-01-12 10:57:54 +00:00
|
|
|
icon: 'lucide:layers',
|
|
|
|
|
color: 'hsl(262 83% 58%)',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'available',
|
|
|
|
|
title: 'Available',
|
2026-01-12 18:10:20 +00:00
|
|
|
value: this.formatBytes(this.memoryAvailable),
|
|
|
|
|
type: 'text' as const,
|
2026-01-12 10:57:54 +00:00
|
|
|
icon: 'lucide:checkCircle',
|
|
|
|
|
color: 'hsl(142 71% 45%)',
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return html`
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
<div class="panel-title">Memory</div>
|
|
|
|
|
<div class="panel-description">RAM and swap usage details</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="stats-section">
|
|
|
|
|
<dees-statsgrid
|
|
|
|
|
.tiles=${memoryTiles}
|
|
|
|
|
.minTileWidth=${220}
|
|
|
|
|
.gap=${16}
|
|
|
|
|
></dees-statsgrid>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private renderStoragePanel(): TemplateResult {
|
|
|
|
|
const storageTiles = [
|
|
|
|
|
{
|
2026-01-12 18:10:20 +00:00
|
|
|
id: 'disk-total',
|
|
|
|
|
title: 'Total Storage',
|
2026-01-12 10:57:54 +00:00
|
|
|
value: this.diskUsage,
|
|
|
|
|
type: 'percentage' as const,
|
|
|
|
|
icon: 'lucide:hardDrive',
|
2026-01-12 18:10:20 +00:00
|
|
|
description: `${this.formatBytes(this.diskUsed)} of ${this.formatBytes(this.diskTotal)} used`,
|
2026-01-12 10:57:54 +00:00
|
|
|
color: 'hsl(217 91% 60%)',
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-12 18:10:20 +00:00
|
|
|
id: 'disk-free',
|
|
|
|
|
title: 'Free Space',
|
|
|
|
|
value: this.formatBytes(this.diskFree),
|
|
|
|
|
type: 'text' as const,
|
2026-01-12 10:57:54 +00:00
|
|
|
icon: 'lucide:hardDrive',
|
2026-01-12 18:10:20 +00:00
|
|
|
description: 'Available storage',
|
2026-01-12 10:57:54 +00:00
|
|
|
color: 'hsl(142 71% 45%)',
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-12 18:10:20 +00:00
|
|
|
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%)',
|
2026-01-12 10:57:54 +00:00
|
|
|
},
|
|
|
|
|
{
|
2026-01-12 18:10:20 +00:00
|
|
|
id: 'disk-total-size',
|
|
|
|
|
title: 'Total Capacity',
|
|
|
|
|
value: this.formatBytes(this.diskTotal),
|
|
|
|
|
type: 'text' as const,
|
|
|
|
|
icon: 'lucide:server',
|
|
|
|
|
description: 'All filesystems',
|
2026-01-12 10:57:54 +00:00
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return html`
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
<div class="panel-title">Storage</div>
|
|
|
|
|
<div class="panel-description">Disk usage and I/O performance</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="stats-section">
|
|
|
|
|
<dees-statsgrid
|
|
|
|
|
.tiles=${storageTiles}
|
|
|
|
|
.minTileWidth=${220}
|
|
|
|
|
.gap=${16}
|
|
|
|
|
></dees-statsgrid>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private renderNetworkPanel(): TemplateResult {
|
|
|
|
|
const networkTiles = [
|
|
|
|
|
{
|
|
|
|
|
id: 'download',
|
2026-01-12 18:10:20 +00:00
|
|
|
title: 'Download Speed',
|
|
|
|
|
value: this.formatSpeed(this.networkRxSec),
|
2026-01-12 10:57:54 +00:00
|
|
|
type: 'trend' as const,
|
|
|
|
|
icon: 'lucide:download',
|
2026-01-12 18:10:20 +00:00
|
|
|
trendData: this.networkInHistory,
|
2026-01-12 10:57:54 +00:00
|
|
|
color: 'hsl(142 71% 45%)',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'upload',
|
2026-01-12 18:10:20 +00:00
|
|
|
title: 'Upload Speed',
|
|
|
|
|
value: this.formatSpeed(this.networkTxSec),
|
2026-01-12 10:57:54 +00:00
|
|
|
type: 'trend' as const,
|
|
|
|
|
icon: 'lucide:upload',
|
2026-01-12 18:10:20 +00:00
|
|
|
trendData: this.networkOutHistory,
|
2026-01-12 10:57:54 +00:00
|
|
|
color: 'hsl(217 91% 60%)',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'total-down',
|
|
|
|
|
title: 'Total Downloaded',
|
2026-01-12 18:10:20 +00:00
|
|
|
value: this.formatBytes(this.networkRxTotal),
|
|
|
|
|
type: 'text' as const,
|
|
|
|
|
icon: 'lucide:arrowDownCircle',
|
|
|
|
|
description: 'Since boot',
|
2026-01-12 10:57:54 +00:00
|
|
|
color: 'hsl(142 71% 45%)',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'total-up',
|
|
|
|
|
title: 'Total Uploaded',
|
2026-01-12 18:10:20 +00:00
|
|
|
value: this.formatBytes(this.networkTxTotal),
|
|
|
|
|
type: 'text' as const,
|
|
|
|
|
icon: 'lucide:arrowUpCircle',
|
|
|
|
|
description: 'Since boot',
|
2026-01-12 10:57:54 +00:00
|
|
|
color: 'hsl(217 91% 60%)',
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return html`
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
<div class="panel-title">Network</div>
|
|
|
|
|
<div class="panel-description">Network traffic and connectivity</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="stats-section">
|
|
|
|
|
<dees-statsgrid
|
|
|
|
|
.tiles=${networkTiles}
|
|
|
|
|
.minTileWidth=${220}
|
|
|
|
|
.gap=${16}
|
|
|
|
|
></dees-statsgrid>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private renderProcessesPanel(): TemplateResult {
|
|
|
|
|
const processTiles = [
|
|
|
|
|
{
|
|
|
|
|
id: 'total-processes',
|
|
|
|
|
title: 'Total Processes',
|
2026-01-12 23:44:05 +00:00
|
|
|
value: this.processTotal,
|
2026-01-12 10:57:54 +00:00
|
|
|
type: 'number' as const,
|
|
|
|
|
icon: 'lucide:layers',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'running',
|
|
|
|
|
title: 'Running',
|
2026-01-12 23:44:05 +00:00
|
|
|
value: this.processRunning,
|
2026-01-12 10:57:54 +00:00
|
|
|
type: 'number' as const,
|
|
|
|
|
icon: 'lucide:play',
|
|
|
|
|
color: 'hsl(142 71% 45%)',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'sleeping',
|
|
|
|
|
title: 'Sleeping',
|
2026-01-12 23:44:05 +00:00
|
|
|
value: this.processSleeping,
|
2026-01-12 10:57:54 +00:00
|
|
|
type: 'number' as const,
|
|
|
|
|
icon: 'lucide:moon',
|
|
|
|
|
color: 'hsl(217 91% 60%)',
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-12 23:44:05 +00:00
|
|
|
id: 'blocked',
|
|
|
|
|
title: 'Blocked',
|
|
|
|
|
value: this.processBlocked,
|
2026-01-12 10:57:54 +00:00
|
|
|
type: 'number' as const,
|
2026-01-12 23:44:05 +00:00
|
|
|
icon: 'lucide:pauseCircle',
|
|
|
|
|
color: 'hsl(0 84% 60%)',
|
2026-01-12 10:57:54 +00:00
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return html`
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
<div class="panel-title">Processes</div>
|
|
|
|
|
<div class="panel-description">Running processes and resource usage</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="stats-section">
|
|
|
|
|
<dees-statsgrid
|
|
|
|
|
.tiles=${processTiles}
|
|
|
|
|
.minTileWidth=${180}
|
|
|
|
|
.gap=${16}
|
|
|
|
|
></dees-statsgrid>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="stats-section">
|
|
|
|
|
<div class="section-title">Top Processes by CPU</div>
|
|
|
|
|
<div class="process-list">
|
|
|
|
|
<div class="process-header">
|
|
|
|
|
<span>Process</span>
|
|
|
|
|
<span>PID</span>
|
|
|
|
|
<span>CPU %</span>
|
|
|
|
|
<span>Memory %</span>
|
|
|
|
|
</div>
|
2026-01-12 23:44:05 +00:00
|
|
|
${this.topProcesses.length > 0 ? this.topProcesses.map(proc => html`
|
2026-01-12 10:57:54 +00:00
|
|
|
<div class="process-row">
|
|
|
|
|
<span class="process-name">${proc.name}</span>
|
|
|
|
|
<span class="process-value">${proc.pid}</span>
|
|
|
|
|
<span class="process-value ${proc.cpu > 10 ? 'high' : ''}">${proc.cpu}%</span>
|
|
|
|
|
<span class="process-value ${proc.memory > 10 ? 'high' : ''}">${proc.memory}%</span>
|
|
|
|
|
</div>
|
2026-01-12 23:44:05 +00:00
|
|
|
`) : html`<div class="process-row"><span class="process-name">Loading...</span></div>`}
|
2026-01-12 10:57:54 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
}
|