import { DeesElement, property, html, customElement, type TemplateResult, css, state, cssManager } from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
import { viewHostCss } from './shared/css.js';
import { type IStatsTile } from '@design.estate/dees-catalog';
declare global {
interface HTMLElementTagNameMap {
'ops-view-network': OpsViewNetwork;
}
}
interface INetworkRequest {
id: string;
timestamp: number;
method: string;
url: string;
hostname: string;
port: number;
protocol: 'http' | 'https' | 'tcp' | 'udp';
statusCode?: number;
duration: number;
bytesIn: number;
bytesOut: number;
remoteIp: string;
route?: string;
}
@customElement('ops-view-network')
export class OpsViewNetwork extends DeesElement {
@state()
private statsState = appstate.statsStatePart.getState();
@state()
private selectedTimeRange: '1m' | '5m' | '15m' | '1h' | '24h' = '5m';
@state()
private selectedProtocol: 'all' | 'http' | 'https' | 'smtp' | 'dns' = 'all';
@state()
private networkRequests: INetworkRequest[] = [];
@state()
private trafficData: Array<{ x: number; y: number }> = [];
@state()
private isLoading = false;
constructor() {
super();
this.subscribeToStateParts();
this.generateMockData(); // TODO: Replace with real data from metrics
}
private subscribeToStateParts() {
appstate.statsStatePart.state.subscribe((state) => {
this.statsState = state;
this.updateNetworkData();
});
}
public static styles = [
cssManager.defaultStyles,
viewHostCss,
css`
:host {
display: block;
padding: 24px;
}
.networkContainer {
display: flex;
flex-direction: column;
gap: 24px;
}
.controlBar {
background: white;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 16px;
display: flex;
gap: 16px;
align-items: center;
flex-wrap: wrap;
}
.controlGroup {
display: flex;
gap: 8px;
align-items: center;
}
.controlLabel {
font-size: 14px;
color: #666;
margin-right: 8px;
}
dees-statsgrid {
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;
}
.protocolBadge {
display: inline-flex;
align-items: center;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.protocolBadge.http {
background: #e3f2fd;
color: #1976d2;
}
.protocolBadge.https {
background: #e8f5e9;
color: #388e3c;
}
.protocolBadge.tcp {
background: #fff3e0;
color: #f57c00;
}
.protocolBadge.smtp {
background: #f3e5f5;
color: #7b1fa2;
}
.protocolBadge.dns {
background: #e0f2f1;
color: #00796b;
}
.statusBadge {
display: inline-flex;
align-items: center;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.statusBadge.success {
background: #e8f5e9;
color: #388e3c;
}
.statusBadge.error {
background: #ffebee;
color: #d32f2f;
}
.statusBadge.warning {
background: #fff3e0;
color: #f57c00;
}
`,
];
public render() {
return html`