feat: Implement dees-statsgrid in DCRouter UI for enhanced stats visualization

- Added new readme.statsgrid.md outlining the implementation plan for dees-statsgrid component.
- Replaced custom stats cards in ops-view-overview.ts and ops-view-network.ts with dees-statsgrid for better visualization.
- Introduced consistent color scheme for success, warning, error, and info states.
- Enhanced interactive features including click actions, context menus, and real-time updates.
- Developed ops-view-emails.ts for email management with features like composing, searching, and viewing emails.
- Integrated mock data generation for emails and network requests to facilitate testing.
- Added responsive design elements and improved UI consistency across components.
This commit is contained in:
Juergen Kunz
2025-06-12 08:04:30 +00:00
parent 0eb4963247
commit facae93e4b
9 changed files with 1543 additions and 499 deletions

View File

@ -9,7 +9,9 @@ import {
state,
css,
cssManager,
type TemplateResult,
} from '@design.estate/dees-element';
import { type IStatsTile } from '@design.estate/dees-catalog';
@customElement('ops-view-overview')
export class OpsViewOverview extends DeesElement {
@ -38,39 +40,13 @@ export class OpsViewOverview extends DeesElement {
cssManager.defaultStyles,
shared.viewHostCss,
css`
.statsGrid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
grid-gap: 16px;
margin-bottom: 40px;
}
.statCard {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 24px;
}
.statCard h3 {
margin: 0 0 16px 0;
font-size: 18px;
h2 {
margin: 32px 0 16px 0;
font-size: 24px;
font-weight: 600;
color: #333;
}
.statValue {
font-size: 32px;
font-weight: 700;
color: #2196F3;
margin-bottom: 8px;
}
.statLabel {
font-size: 14px;
color: #666;
}
.chartGrid {
display: grid;
grid-template-columns: repeat(2, 1fr);
@ -92,6 +68,10 @@ export class OpsViewOverview extends DeesElement {
color: #c00;
margin: 16px 0;
}
dees-statsgrid {
margin-bottom: 32px;
}
`,
];
@ -109,79 +89,11 @@ export class OpsViewOverview extends DeesElement {
Error loading statistics: ${this.statsState.error}
</div>
` : html`
<div class="statsGrid">
${this.statsState.serverStats ? html`
<div class="statCard">
<h3>Server Status</h3>
<div class="statValue">${this.statsState.serverStats.uptime ? 'Online' : 'Offline'}</div>
<div class="statLabel">Uptime: ${this.formatUptime(this.statsState.serverStats.uptime)}</div>
</div>
<div class="statCard">
<h3>Connections</h3>
<div class="statValue">${this.statsState.serverStats.activeConnections}</div>
<div class="statLabel">Active connections</div>
</div>
${this.renderServerStats()}
<div class="statCard">
<h3>Memory Usage</h3>
<div class="statValue">${this.formatBytes(this.statsState.serverStats.memoryUsage.heapUsed)}</div>
<div class="statLabel">of ${this.formatBytes(this.statsState.serverStats.memoryUsage.heapTotal)}</div>
</div>
${this.renderEmailStats()}
<div class="statCard">
<h3>CPU Usage</h3>
<div class="statValue">${Math.round((this.statsState.serverStats.cpuUsage.user + this.statsState.serverStats.cpuUsage.system) / 2)}%</div>
<div class="statLabel">Average load</div>
</div>
` : ''}
</div>
${this.statsState.emailStats ? html`
<h2>Email Statistics</h2>
<div class="statsGrid">
<div class="statCard">
<h3>Emails Sent</h3>
<div class="statValue">${this.statsState.emailStats.sent}</div>
<div class="statLabel">Total sent</div>
</div>
<div class="statCard">
<h3>Emails Received</h3>
<div class="statValue">${this.statsState.emailStats.received}</div>
<div class="statLabel">Total received</div>
</div>
<div class="statCard">
<h3>Failed Deliveries</h3>
<div class="statValue">${this.statsState.emailStats.failed}</div>
<div class="statLabel">Delivery failures</div>
</div>
<div class="statCard">
<h3>Queued</h3>
<div class="statValue">${this.statsState.emailStats.queued}</div>
<div class="statLabel">In queue</div>
</div>
</div>
` : ''}
${this.statsState.dnsStats ? html`
<h2>DNS Statistics</h2>
<div class="statsGrid">
<div class="statCard">
<h3>DNS Queries</h3>
<div class="statValue">${this.statsState.dnsStats.totalQueries}</div>
<div class="statLabel">Total queries handled</div>
</div>
<div class="statCard">
<h3>Cache Hit Rate</h3>
<div class="statValue">${Math.round(this.statsState.dnsStats.cacheHitRate * 100)}%</div>
<div class="statLabel">Cache efficiency</div>
</div>
</div>
` : ''}
${this.renderDnsStats()}
<div class="chartGrid">
<dees-chart-area .label=${'Email Traffic (24h)'} .data=${[]}></dees-chart-area>
@ -222,4 +134,171 @@ export class OpsViewOverview extends DeesElement {
return `${size.toFixed(1)} ${units[unitIndex]}`;
}
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 tiles: IStatsTile[] = [
{
id: 'status',
title: 'Server Status',
value: this.statsState.serverStats.uptime ? 'Online' : 'Offline',
type: 'text',
icon: 'server',
color: this.statsState.serverStats.uptime ? '#22c55e' : '#ef4444',
description: `Uptime: ${this.formatUptime(this.statsState.serverStats.uptime)}`,
},
{
id: 'connections',
title: 'Active Connections',
value: this.statsState.serverStats.activeConnections,
type: 'number',
icon: 'networkWired',
color: '#3b82f6',
description: `Total: ${this.statsState.serverStats.totalConnections}`,
},
{
id: 'cpu',
title: 'CPU Usage',
value: cpuUsage,
type: 'gauge',
icon: 'microchip',
gaugeOptions: {
min: 0,
max: 100,
thresholds: [
{ value: 0, color: '#22c55e' },
{ value: 60, color: '#f59e0b' },
{ value: 80, color: '#ef4444' },
],
},
},
{
id: 'memory',
title: 'Memory Usage',
value: memoryUsage,
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)}`,
},
];
return html`
<dees-statsgrid
.tiles=${tiles}
.gridActions=${[
{
name: 'Refresh',
iconName: 'arrowsRotate',
action: async () => {
await appstate.statsStatePart.dispatchAction(appstate.fetchAllStatsAction, null);
},
},
]}
></dees-statsgrid>
`;
}
private renderEmailStats(): TemplateResult {
if (!this.statsState.emailStats) return html``;
const deliveryRate = this.statsState.emailStats.deliveryRate || 0;
const bounceRate = this.statsState.emailStats.bounceRate || 0;
const tiles: IStatsTile[] = [
{
id: 'sent',
title: 'Emails Sent',
value: this.statsState.emailStats.sent,
type: 'number',
icon: 'paperPlane',
color: '#22c55e',
description: `Delivery rate: ${(deliveryRate * 100).toFixed(1)}%`,
},
{
id: 'received',
title: 'Emails Received',
value: this.statsState.emailStats.received,
type: 'number',
icon: 'envelope',
color: '#3b82f6',
},
{
id: 'queued',
title: 'Queued',
value: this.statsState.emailStats.queued,
type: 'number',
icon: 'clock',
color: '#f59e0b',
description: 'Pending delivery',
},
{
id: 'failed',
title: 'Failed',
value: this.statsState.emailStats.failed,
type: 'number',
icon: 'triangleExclamation',
color: '#ef4444',
description: `Bounce rate: ${(bounceRate * 100).toFixed(1)}%`,
},
];
return html`
<h2>Email Statistics</h2>
<dees-statsgrid .tiles=${tiles}></dees-statsgrid>
`;
}
private renderDnsStats(): TemplateResult {
if (!this.statsState.dnsStats) return html``;
const cacheHitRate = Math.round(this.statsState.dnsStats.cacheHitRate * 100);
const tiles: IStatsTile[] = [
{
id: 'queries',
title: 'DNS Queries',
value: this.statsState.dnsStats.totalQueries,
type: 'number',
icon: 'globe',
color: '#3b82f6',
description: 'Total queries handled',
},
{
id: 'cacheRate',
title: 'Cache Hit Rate',
value: cacheHitRate,
type: 'percentage',
icon: 'database',
color: cacheHitRate > 80 ? '#22c55e' : cacheHitRate > 60 ? '#f59e0b' : '#ef4444',
description: `${this.statsState.dnsStats.cacheHits} hits / ${this.statsState.dnsStats.cacheMisses} misses`,
},
{
id: 'domains',
title: 'Active Domains',
value: this.statsState.dnsStats.activeDomains,
type: 'number',
icon: 'sitemap',
color: '#8b5cf6',
},
{
id: 'responseTime',
title: 'Avg Response Time',
value: this.statsState.dnsStats.averageResponseTime.toFixed(1),
unit: 'ms',
type: 'number',
icon: 'clockRotateLeft',
color: this.statsState.dnsStats.averageResponseTime < 50 ? '#22c55e' : '#f59e0b',
},
];
return html`
<h2>DNS Statistics</h2>
<dees-statsgrid .tiles=${tiles}></dees-statsgrid>
`;
}
}