feat: Integrate SmartMetrics for enhanced CPU and memory monitoring in UI

This commit is contained in:
Juergen Kunz
2025-06-12 11:22:18 +00:00
parent facae93e4b
commit 8ce6c88d58
8 changed files with 154 additions and 170 deletions

View File

@ -1,5 +1,6 @@
import { DeesElement, property, html, customElement, type TemplateResult, css, state, cssManager } from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
import * as shared from './shared/index.js';
declare global {
interface HTMLElementTagNameMap {
@ -56,95 +57,39 @@ export class OpsViewEmails extends DeesElement {
public static styles = [
cssManager.defaultStyles,
shared.viewHostCss,
css`
:host {
display: block;
height: 100%;
padding: 24px;
}
.emailContainer {
display: grid;
grid-template-columns: 250px 1fr;
gap: 24px;
height: calc(100vh - 200px);
grid-template-columns: 280px 1fr;
gap: 16px;
height: 100%;
min-height: 600px;
}
.sidebar {
background: white;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 16px;
display: flex;
flex-direction: column;
gap: 16px;
}
.folderList {
display: flex;
flex-direction: column;
gap: 8px;
}
.folderItem {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
position: relative;
}
.folderItem:hover {
background: #f5f5f5;
}
.folderItem.selected {
background: #e3f2fd;
color: #1976d2;
}
.folderIcon {
font-size: 18px;
}
.folderLabel {
flex: 1;
font-weight: 500;
}
.folderCount {
background: #e0e0e0;
color: #666;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
}
.folderItem.selected .folderCount {
background: #1976d2;
color: white;
}
.mainContent {
background: white;
border: 1px solid #e9ecef;
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
gap: 16px;
overflow: hidden;
}
.emailToolbar {
display: flex;
align-items: center;
gap: 16px;
padding: 16px;
border-bottom: 1px solid #e9ecef;
background: #fafafa;
gap: 12px;
flex-wrap: wrap;
}
.searchBox {

View File

@ -100,18 +100,8 @@ export class OpsViewNetwork extends DeesElement {
margin-bottom: 24px;
}
.chartSection {
background: white;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 24px;
}
.tableSection {
background: white;
border: 1px solid #e9ecef;
border-radius: 8px;
overflow: hidden;
dees-chart-area {
margin-bottom: 24px;
}
.protocolBadge {
@ -224,51 +214,47 @@ export class OpsViewNetwork extends DeesElement {
${this.renderNetworkStats()}
<!-- Traffic Chart -->
<div class="chartSection">
<dees-chart-area
.label=${'Network Traffic'}
.series=${[
{
name: 'Requests/min',
data: this.trafficData,
}
]}
></dees-chart-area>
</div>
<dees-chart-area
.label=${'Network Traffic'}
.series=${[
{
name: 'Requests/min',
data: this.trafficData,
}
]}
></dees-chart-area>
<!-- Requests Table -->
<div class="tableSection">
<dees-table
.data=${this.getFilteredRequests()}
.displayFunction=${(req: INetworkRequest) => ({
Time: new Date(req.timestamp).toLocaleTimeString(),
Protocol: html`<span class="protocolBadge ${req.protocol}">${req.protocol.toUpperCase()}</span>`,
Method: req.method,
'Host:Port': `${req.hostname}:${req.port}`,
Path: this.truncateUrl(req.url),
Status: this.renderStatus(req.statusCode),
Duration: `${req.duration}ms`,
'In/Out': `${this.formatBytes(req.bytesIn)} / ${this.formatBytes(req.bytesOut)}`,
'Remote IP': req.remoteIp,
})}
.dataActions=${[
{
name: 'View Details',
iconName: 'magnifyingGlass',
type: ['inRow', 'doubleClick', 'contextmenu'],
actionFunc: async (actionData) => {
await this.showRequestDetails(actionData.item);
}
<dees-table
.data=${this.getFilteredRequests()}
.displayFunction=${(req: INetworkRequest) => ({
Time: new Date(req.timestamp).toLocaleTimeString(),
Protocol: html`<span class="protocolBadge ${req.protocol}">${req.protocol.toUpperCase()}</span>`,
Method: req.method,
'Host:Port': `${req.hostname}:${req.port}`,
Path: this.truncateUrl(req.url),
Status: this.renderStatus(req.statusCode),
Duration: `${req.duration}ms`,
'In/Out': `${this.formatBytes(req.bytesIn)} / ${this.formatBytes(req.bytesOut)}`,
'Remote IP': req.remoteIp,
})}
.dataActions=${[
{
name: 'View Details',
iconName: 'magnifyingGlass',
type: ['inRow', 'doubleClick', 'contextmenu'],
actionFunc: async (actionData) => {
await this.showRequestDetails(actionData.item);
}
]}
heading1="Recent Network Activity"
heading2="Last ${this.selectedTimeRange} of network requests"
searchable
.pagination=${true}
.paginationSize=${50}
dataName="request"
></dees-table>
</div>
}
]}
heading1="Recent Network Activity"
heading2="Last ${this.selectedTimeRange} of network requests"
searchable
.pagination=${true}
.paginationSize=${50}
dataName="request"
></dees-table>
</div>
`;
}

View File

@ -138,8 +138,10 @@ export class OpsViewOverview extends DeesElement {
private renderServerStats(): TemplateResult {
if (!this.statsState.serverStats) return html``;
const cpuUsage = Math.round((this.statsState.serverStats.cpuUsage.user + this.statsState.serverStats.cpuUsage.system) / 2);
const memoryUsage = Math.round((this.statsState.serverStats.memoryUsage.heapUsed / this.statsState.serverStats.memoryUsage.heapTotal) * 100);
const cpuUsage = Math.round(this.statsState.serverStats.cpuUsage.user);
const memoryUsage = this.statsState.serverStats.memoryUsage.actualUsagePercentage !== undefined
? Math.round(this.statsState.serverStats.memoryUsage.actualUsagePercentage)
: Math.round((this.statsState.serverStats.memoryUsage.heapUsed / this.statsState.serverStats.memoryUsage.heapTotal) * 100);
const tiles: IStatsTile[] = [
{
@ -183,7 +185,9 @@ export class OpsViewOverview extends DeesElement {
type: 'percentage',
icon: 'memory',
color: memoryUsage > 80 ? '#ef4444' : memoryUsage > 60 ? '#f59e0b' : '#22c55e',
description: `${this.formatBytes(this.statsState.serverStats.memoryUsage.heapUsed)} / ${this.formatBytes(this.statsState.serverStats.memoryUsage.heapTotal)}`,
description: this.statsState.serverStats.memoryUsage.actualUsageBytes !== undefined && this.statsState.serverStats.memoryUsage.maxMemoryMB !== undefined
? `${this.formatBytes(this.statsState.serverStats.memoryUsage.actualUsageBytes)} / ${this.formatBytes(this.statsState.serverStats.memoryUsage.maxMemoryMB * 1024 * 1024)}`
: `${this.formatBytes(this.statsState.serverStats.memoryUsage.rss)} / ${this.formatBytes(this.statsState.serverStats.memoryUsage.heapTotal)}`,
},
];