@serve.zone/dcrouter 13.2.2 → 13.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist_serve/bundle.js +1499 -1413
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts_web/00_commitinfo_data.js +1 -1
  4. package/dist_ts_web/appstate.d.ts +1 -0
  5. package/dist_ts_web/appstate.js +14 -38
  6. package/dist_ts_web/elements/access/index.d.ts +1 -0
  7. package/dist_ts_web/elements/access/index.js +2 -0
  8. package/dist_ts_web/elements/{ops-view-apitokens.d.ts → access/ops-view-apitokens.d.ts} +1 -1
  9. package/dist_ts_web/elements/{ops-view-apitokens.js → access/ops-view-apitokens.js} +4 -4
  10. package/dist_ts_web/elements/email/index.d.ts +2 -0
  11. package/dist_ts_web/elements/email/index.js +3 -0
  12. package/dist_ts_web/elements/email/ops-view-email-security.d.ts +14 -0
  13. package/dist_ts_web/elements/email/ops-view-email-security.js +197 -0
  14. package/dist_ts_web/elements/{ops-view-emails.d.ts → email/ops-view-emails.d.ts} +2 -2
  15. package/dist_ts_web/elements/{ops-view-emails.js → email/ops-view-emails.js} +5 -5
  16. package/dist_ts_web/elements/index.d.ts +5 -12
  17. package/dist_ts_web/elements/index.js +6 -13
  18. package/dist_ts_web/elements/network/index.d.ts +7 -0
  19. package/dist_ts_web/elements/network/index.js +8 -0
  20. package/dist_ts_web/elements/{ops-view-network.d.ts → network/ops-view-network-activity.d.ts} +3 -3
  21. package/dist_ts_web/elements/{ops-view-network.js → network/ops-view-network-activity.js} +20 -32
  22. package/dist_ts_web/elements/{ops-view-networktargets.d.ts → network/ops-view-networktargets.d.ts} +1 -1
  23. package/dist_ts_web/elements/{ops-view-networktargets.js → network/ops-view-networktargets.js} +5 -5
  24. package/dist_ts_web/elements/{ops-view-remoteingress.d.ts → network/ops-view-remoteingress.d.ts} +1 -1
  25. package/dist_ts_web/elements/{ops-view-remoteingress.js → network/ops-view-remoteingress.js} +5 -5
  26. package/dist_ts_web/elements/{ops-view-routes.d.ts → network/ops-view-routes.d.ts} +1 -1
  27. package/dist_ts_web/elements/{ops-view-routes.js → network/ops-view-routes.js} +5 -5
  28. package/dist_ts_web/elements/{ops-view-sourceprofiles.d.ts → network/ops-view-sourceprofiles.d.ts} +1 -1
  29. package/dist_ts_web/elements/{ops-view-sourceprofiles.js → network/ops-view-sourceprofiles.js} +5 -5
  30. package/dist_ts_web/elements/{ops-view-targetprofiles.d.ts → network/ops-view-targetprofiles.d.ts} +2 -2
  31. package/dist_ts_web/elements/{ops-view-targetprofiles.js → network/ops-view-targetprofiles.js} +6 -6
  32. package/dist_ts_web/elements/{ops-view-vpn.d.ts → network/ops-view-vpn.d.ts} +2 -2
  33. package/dist_ts_web/elements/{ops-view-vpn.js → network/ops-view-vpn.js} +6 -6
  34. package/dist_ts_web/elements/ops-dashboard.d.ts +8 -2
  35. package/dist_ts_web/elements/ops-dashboard.js +101 -83
  36. package/dist_ts_web/elements/overview/index.d.ts +2 -0
  37. package/dist_ts_web/elements/overview/index.js +3 -0
  38. package/dist_ts_web/elements/{ops-view-config.d.ts → overview/ops-view-config.d.ts} +2 -2
  39. package/dist_ts_web/elements/{ops-view-config.js → overview/ops-view-config.js} +9 -9
  40. package/dist_ts_web/elements/{ops-view-overview.d.ts → overview/ops-view-overview.d.ts} +2 -2
  41. package/dist_ts_web/elements/{ops-view-overview.js → overview/ops-view-overview.js} +4 -4
  42. package/dist_ts_web/elements/security/index.d.ts +3 -0
  43. package/dist_ts_web/elements/security/index.js +4 -0
  44. package/dist_ts_web/elements/security/ops-view-security-authentication.d.ts +13 -0
  45. package/dist_ts_web/elements/security/ops-view-security-authentication.js +157 -0
  46. package/dist_ts_web/elements/security/ops-view-security-blocked.d.ts +15 -0
  47. package/dist_ts_web/elements/security/ops-view-security-blocked.js +153 -0
  48. package/dist_ts_web/elements/security/ops-view-security-overview.d.ts +16 -0
  49. package/dist_ts_web/elements/security/ops-view-security-overview.js +205 -0
  50. package/dist_ts_web/router.d.ts +5 -3
  51. package/dist_ts_web/router.js +75 -17
  52. package/package.json +2 -2
  53. package/ts/00_commitinfo_data.ts +1 -1
  54. package/ts_web/00_commitinfo_data.ts +1 -1
  55. package/ts_web/appstate.ts +15 -42
  56. package/ts_web/elements/access/index.ts +1 -0
  57. package/ts_web/elements/{ops-view-apitokens.ts → access/ops-view-apitokens.ts} +3 -3
  58. package/ts_web/elements/email/index.ts +2 -0
  59. package/ts_web/elements/email/ops-view-email-security.ts +160 -0
  60. package/ts_web/elements/{ops-view-emails.ts → email/ops-view-emails.ts} +4 -4
  61. package/ts_web/elements/index.ts +6 -13
  62. package/ts_web/elements/network/index.ts +7 -0
  63. package/ts_web/elements/{ops-view-network.ts → network/ops-view-network-activity.ts} +43 -55
  64. package/ts_web/elements/{ops-view-networktargets.ts → network/ops-view-networktargets.ts} +4 -4
  65. package/ts_web/elements/{ops-view-remoteingress.ts → network/ops-view-remoteingress.ts} +4 -4
  66. package/ts_web/elements/{ops-view-routes.ts → network/ops-view-routes.ts} +4 -4
  67. package/ts_web/elements/{ops-view-sourceprofiles.ts → network/ops-view-sourceprofiles.ts} +4 -4
  68. package/ts_web/elements/{ops-view-targetprofiles.ts → network/ops-view-targetprofiles.ts} +5 -5
  69. package/ts_web/elements/{ops-view-vpn.ts → network/ops-view-vpn.ts} +5 -5
  70. package/ts_web/elements/ops-dashboard.ts +125 -90
  71. package/ts_web/elements/overview/index.ts +2 -0
  72. package/ts_web/elements/{ops-view-config.ts → overview/ops-view-config.ts} +8 -8
  73. package/ts_web/elements/{ops-view-overview.ts → overview/ops-view-overview.ts} +3 -3
  74. package/ts_web/elements/security/index.ts +3 -0
  75. package/ts_web/elements/security/ops-view-security-authentication.ts +121 -0
  76. package/ts_web/elements/security/ops-view-security-blocked.ts +118 -0
  77. package/ts_web/elements/security/ops-view-security-overview.ts +172 -0
  78. package/ts_web/router.ts +81 -17
  79. package/dist_ts_web/elements/ops-view-security.d.ts +0 -24
  80. package/dist_ts_web/elements/ops-view-security.js +0 -484
  81. package/ts_web/elements/ops-view-security.ts +0 -456
@@ -0,0 +1,160 @@
1
+ import * as appstate from '../../appstate.js';
2
+ import { viewHostCss } from '../shared/css.js';
3
+
4
+ import {
5
+ DeesElement,
6
+ customElement,
7
+ html,
8
+ state,
9
+ css,
10
+ cssManager,
11
+ type TemplateResult,
12
+ } from '@design.estate/dees-element';
13
+ import { type IStatsTile } from '@design.estate/dees-catalog';
14
+
15
+ declare global {
16
+ interface HTMLElementTagNameMap {
17
+ 'ops-view-email-security': OpsViewEmailSecurity;
18
+ }
19
+ }
20
+
21
+ @customElement('ops-view-email-security')
22
+ export class OpsViewEmailSecurity extends DeesElement {
23
+ @state()
24
+ accessor statsState: appstate.IStatsState = appstate.statsStatePart.getState()!;
25
+
26
+ constructor() {
27
+ super();
28
+ const sub = appstate.statsStatePart
29
+ .select((s) => s)
30
+ .subscribe((s) => {
31
+ this.statsState = s;
32
+ });
33
+ this.rxSubscriptions.push(sub);
34
+ }
35
+
36
+ public static styles = [
37
+ cssManager.defaultStyles,
38
+ viewHostCss,
39
+ css`
40
+ h2 {
41
+ margin: 32px 0 16px 0;
42
+ font-size: 24px;
43
+ font-weight: 600;
44
+ color: ${cssManager.bdTheme('#333', '#ccc')};
45
+ }
46
+ dees-statsgrid {
47
+ margin-bottom: 32px;
48
+ }
49
+ .securityCard {
50
+ background: ${cssManager.bdTheme('#fff', '#222')};
51
+ border: 1px solid ${cssManager.bdTheme('#e9ecef', '#333')};
52
+ border-radius: 8px;
53
+ padding: 24px;
54
+ position: relative;
55
+ overflow: hidden;
56
+ }
57
+ .actionButton {
58
+ margin-top: 16px;
59
+ }
60
+ `,
61
+ ];
62
+
63
+ public render(): TemplateResult {
64
+ const metrics = this.statsState.securityMetrics;
65
+
66
+ if (!metrics) {
67
+ return html`
68
+ <div class="loadingMessage">
69
+ <p>Loading security metrics...</p>
70
+ </div>
71
+ `;
72
+ }
73
+
74
+ const tiles: IStatsTile[] = [
75
+ {
76
+ id: 'malware',
77
+ title: 'Malware Detection',
78
+ value: metrics.malwareDetected,
79
+ type: 'number',
80
+ icon: 'lucide:BugOff',
81
+ color: metrics.malwareDetected > 0 ? '#ef4444' : '#22c55e',
82
+ description: 'Malware detected',
83
+ },
84
+ {
85
+ id: 'phishing',
86
+ title: 'Phishing Detection',
87
+ value: metrics.phishingDetected,
88
+ type: 'number',
89
+ icon: 'lucide:Fish',
90
+ color: metrics.phishingDetected > 0 ? '#ef4444' : '#22c55e',
91
+ description: 'Phishing attempts detected',
92
+ },
93
+ {
94
+ id: 'suspicious',
95
+ title: 'Suspicious Activities',
96
+ value: metrics.suspiciousActivities,
97
+ type: 'number',
98
+ icon: 'lucide:TriangleAlert',
99
+ color: metrics.suspiciousActivities > 5 ? '#ef4444' : '#f59e0b',
100
+ description: 'Suspicious activities detected',
101
+ },
102
+ {
103
+ id: 'spam',
104
+ title: 'Spam Detection',
105
+ value: metrics.spamDetected,
106
+ type: 'number',
107
+ icon: 'lucide:Ban',
108
+ color: '#f59e0b',
109
+ description: 'Spam emails blocked',
110
+ },
111
+ ];
112
+
113
+ return html`
114
+ <dees-heading level="hr">Email Security</dees-heading>
115
+
116
+ <dees-statsgrid
117
+ .tiles=${tiles}
118
+ .minTileWidth=${200}
119
+ ></dees-statsgrid>
120
+
121
+ <h2>Email Security Configuration</h2>
122
+ <div class="securityCard">
123
+ <dees-form>
124
+ <dees-input-checkbox
125
+ .key=${'enableSPF'}
126
+ .label=${'Enable SPF checking'}
127
+ .value=${true}
128
+ ></dees-input-checkbox>
129
+ <dees-input-checkbox
130
+ .key=${'enableDKIM'}
131
+ .label=${'Enable DKIM validation'}
132
+ .value=${true}
133
+ ></dees-input-checkbox>
134
+ <dees-input-checkbox
135
+ .key=${'enableDMARC'}
136
+ .label=${'Enable DMARC policy enforcement'}
137
+ .value=${true}
138
+ ></dees-input-checkbox>
139
+ <dees-input-checkbox
140
+ .key=${'enableSpamFilter'}
141
+ .label=${'Enable spam filtering'}
142
+ .value=${true}
143
+ ></dees-input-checkbox>
144
+ </dees-form>
145
+ <dees-button
146
+ class="actionButton"
147
+ type="highlighted"
148
+ @click=${() => this.saveEmailSecuritySettings()}
149
+ >
150
+ Save Settings
151
+ </dees-button>
152
+ </div>
153
+ `;
154
+ }
155
+
156
+ private async saveEmailSecuritySettings() {
157
+ // Config is read-only from the UI for now
158
+ alert('Email security settings are read-only. Update the dcrouter configuration file to change these settings.');
159
+ }
160
+ }
@@ -1,8 +1,8 @@
1
1
  import { DeesElement, property, html, customElement, type TemplateResult, css, state, cssManager } from '@design.estate/dees-element';
2
- import * as plugins from '../plugins.js';
3
- import * as appstate from '../appstate.js';
4
- import * as shared from './shared/index.js';
5
- import * as interfaces from '../../dist_ts_interfaces/index.js';
2
+ import * as plugins from '../../plugins.js';
3
+ import * as appstate from '../../appstate.js';
4
+ import * as shared from '../shared/index.js';
5
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
6
6
 
7
7
  declare global {
8
8
  interface HTMLElementTagNameMap {
@@ -1,16 +1,9 @@
1
1
  export * from './ops-dashboard.js';
2
- export * from './ops-view-overview.js';
3
- export * from './ops-view-network.js';
4
- export * from './ops-view-emails.js';
2
+ export * from './overview/index.js';
3
+ export * from './network/index.js';
4
+ export * from './email/index.js';
5
5
  export * from './ops-view-logs.js';
6
- export * from './ops-view-config.js';
7
- export * from './ops-view-routes.js';
8
- export * from './ops-view-apitokens.js';
9
- export * from './ops-view-security.js';
6
+ export * from './access/index.js';
7
+ export * from './security/index.js';
10
8
  export * from './ops-view-certificates.js';
11
- export * from './ops-view-remoteingress.js';
12
- export * from './ops-view-vpn.js';
13
- export * from './ops-view-sourceprofiles.js';
14
- export * from './ops-view-networktargets.js';
15
- export * from './ops-view-targetprofiles.js';
16
- export * from './shared/index.js';
9
+ export * from './shared/index.js';
@@ -0,0 +1,7 @@
1
+ export * from './ops-view-network-activity.js';
2
+ export * from './ops-view-routes.js';
3
+ export * from './ops-view-sourceprofiles.js';
4
+ export * from './ops-view-networktargets.js';
5
+ export * from './ops-view-targetprofiles.js';
6
+ export * from './ops-view-remoteingress.js';
7
+ export * from './ops-view-vpn.js';
@@ -1,12 +1,12 @@
1
1
  import { DeesElement, property, html, customElement, type TemplateResult, css, state, cssManager } from '@design.estate/dees-element';
2
- import * as appstate from '../appstate.js';
3
- import * as interfaces from '../../dist_ts_interfaces/index.js';
4
- import { viewHostCss } from './shared/css.js';
2
+ import * as appstate from '../../appstate.js';
3
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
4
+ import { viewHostCss } from '../shared/css.js';
5
5
  import { type IStatsTile } from '@design.estate/dees-catalog';
6
6
 
7
7
  declare global {
8
8
  interface HTMLElementTagNameMap {
9
- 'ops-view-network': OpsViewNetwork;
9
+ 'ops-view-network-activity': OpsViewNetworkActivity;
10
10
  }
11
11
  }
12
12
 
@@ -26,14 +26,14 @@ interface INetworkRequest {
26
26
  route?: string;
27
27
  }
28
28
 
29
- @customElement('ops-view-network')
30
- export class OpsViewNetwork extends DeesElement {
29
+ @customElement('ops-view-network-activity')
30
+ export class OpsViewNetworkActivity extends DeesElement {
31
31
  /** How far back the traffic chart shows */
32
32
  private static readonly CHART_WINDOW_MS = 5 * 60 * 1000; // 5 minutes
33
33
  /** How often a new data point is added */
34
34
  private static readonly UPDATE_INTERVAL_MS = 1000; // 1 second
35
35
  /** Derived: max data points the buffer holds */
36
- private static readonly MAX_DATA_POINTS = OpsViewNetwork.CHART_WINDOW_MS / OpsViewNetwork.UPDATE_INTERVAL_MS;
36
+ private static readonly MAX_DATA_POINTS = OpsViewNetworkActivity.CHART_WINDOW_MS / OpsViewNetworkActivity.UPDATE_INTERVAL_MS;
37
37
 
38
38
  @state()
39
39
  accessor statsState = appstate.statsStatePart.getState()!;
@@ -50,10 +50,10 @@ export class OpsViewNetwork extends DeesElement {
50
50
 
51
51
  @state()
52
52
  accessor trafficDataOut: Array<{ x: string | number; y: number }> = [];
53
-
53
+
54
54
  // Track if we need to update the chart to avoid unnecessary re-renders
55
55
  private lastChartUpdate = 0;
56
- private chartUpdateThreshold = OpsViewNetwork.UPDATE_INTERVAL_MS; // Minimum ms between chart updates
56
+ private chartUpdateThreshold = OpsViewNetworkActivity.UPDATE_INTERVAL_MS; // Minimum ms between chart updates
57
57
 
58
58
  private trafficUpdateTimer: any = null;
59
59
  private requestsPerSecHistory: number[] = []; // Track requests/sec over time for trend
@@ -101,17 +101,17 @@ export class OpsViewNetwork extends DeesElement {
101
101
  this.updateNetworkData();
102
102
  });
103
103
  this.rxSubscriptions.push(statsUnsubscribe);
104
-
104
+
105
105
  const networkUnsubscribe = appstate.networkStatePart.select().subscribe((state) => {
106
106
  this.networkState = state;
107
107
  this.updateNetworkData();
108
108
  });
109
109
  this.rxSubscriptions.push(networkUnsubscribe);
110
110
  }
111
-
111
+
112
112
  private initializeTrafficData() {
113
113
  const now = Date.now();
114
- const { MAX_DATA_POINTS, UPDATE_INTERVAL_MS } = OpsViewNetwork;
114
+ const { MAX_DATA_POINTS, UPDATE_INTERVAL_MS } = OpsViewNetworkActivity;
115
115
 
116
116
  // Initialize with empty data points for both in and out
117
117
  const emptyData = Array.from({ length: MAX_DATA_POINTS }, (_, i) => {
@@ -148,7 +148,7 @@ export class OpsViewNetwork extends DeesElement {
148
148
  y: Math.round((p.out * 8) / 1000000 * 10) / 10,
149
149
  }));
150
150
 
151
- const { MAX_DATA_POINTS, UPDATE_INTERVAL_MS } = OpsViewNetwork;
151
+ const { MAX_DATA_POINTS, UPDATE_INTERVAL_MS } = OpsViewNetworkActivity;
152
152
 
153
153
  // Use history as the chart data, keeping the most recent points within the window
154
154
  const sliceStart = Math.max(0, historyIn.length - MAX_DATA_POINTS);
@@ -285,8 +285,8 @@ export class OpsViewNetwork extends DeesElement {
285
285
 
286
286
  public render() {
287
287
  return html`
288
- <dees-heading level="2">Network Activity</dees-heading>
289
-
288
+ <dees-heading level="hr">Network Activity</dees-heading>
289
+
290
290
  <div class="networkContainer">
291
291
  <!-- Stats Grid -->
292
292
  ${this.renderNetworkStats()}
@@ -307,7 +307,7 @@ export class OpsViewNetwork extends DeesElement {
307
307
  }
308
308
  ]}
309
309
  .realtimeMode=${true}
310
- .rollingWindow=${OpsViewNetwork.CHART_WINDOW_MS}
310
+ .rollingWindow=${OpsViewNetworkActivity.CHART_WINDOW_MS}
311
311
  .yAxisFormatter=${(val: number) => `${val} Mbit/s`}
312
312
  ></dees-chart-area>
313
313
 
@@ -323,7 +323,6 @@ export class OpsViewNetwork extends DeesElement {
323
323
  <!-- Requests Table -->
324
324
  <dees-table
325
325
  .data=${this.networkRequests}
326
- .showColumnFilters=${true}
327
326
  .displayFunction=${(req: INetworkRequest) => ({
328
327
  Time: new Date(req.timestamp).toLocaleTimeString(),
329
328
  Protocol: html`<span class="protocolBadge ${req.protocol}">${req.protocol.toUpperCase()}</span>`,
@@ -358,7 +357,7 @@ export class OpsViewNetwork extends DeesElement {
358
357
 
359
358
  private async showRequestDetails(request: INetworkRequest) {
360
359
  const { DeesModal } = await import('@design.estate/dees-catalog');
361
-
360
+
362
361
  await DeesModal.createAndShow({
363
362
  heading: 'Request Details',
364
363
  content: html`
@@ -401,10 +400,10 @@ export class OpsViewNetwork extends DeesElement {
401
400
  if (!statusCode) {
402
401
  return html`<span class="statusBadge warning">N/A</span>`;
403
402
  }
404
-
403
+
405
404
  const statusClass = statusCode >= 200 && statusCode < 300 ? 'success' :
406
405
  statusCode >= 400 ? 'error' : 'warning';
407
-
406
+
408
407
  return html`<span class="statusBadge ${statusClass}">${statusCode}</span>`;
409
408
  }
410
409
 
@@ -427,26 +426,26 @@ export class OpsViewNetwork extends DeesElement {
427
426
  const units = ['B', 'KB', 'MB', 'GB'];
428
427
  let size = bytes;
429
428
  let unitIndex = 0;
430
-
429
+
431
430
  while (size >= 1024 && unitIndex < units.length - 1) {
432
431
  size /= 1024;
433
432
  unitIndex++;
434
433
  }
435
-
434
+
436
435
  return `${size.toFixed(1)} ${units[unitIndex]}`;
437
436
  }
438
-
437
+
439
438
  private formatBitsPerSecond(bytesPerSecond: number): string {
440
439
  const bitsPerSecond = bytesPerSecond * 8; // Convert bytes to bits
441
440
  const units = ['bit/s', 'kbit/s', 'Mbit/s', 'Gbit/s'];
442
441
  let size = bitsPerSecond;
443
442
  let unitIndex = 0;
444
-
443
+
445
444
  while (size >= 1000 && unitIndex < units.length - 1) {
446
445
  size /= 1000; // Use 1000 for bits (not 1024)
447
446
  unitIndex++;
448
447
  }
449
-
448
+
450
449
  return `${size.toFixed(1)} ${units[unitIndex]}`;
451
450
  }
452
451
 
@@ -521,18 +520,9 @@ export class OpsViewNetwork extends DeesElement {
521
520
  ];
522
521
 
523
522
  return html`
524
- <dees-statsgrid
523
+ <dees-statsgrid
525
524
  .tiles=${tiles}
526
525
  .minTileWidth=${200}
527
- .gridActions=${[
528
- {
529
- name: 'Export Data',
530
- iconName: 'lucide:FileOutput',
531
- action: async () => {
532
- console.log('Export feature coming soon');
533
- },
534
- },
535
- ]}
536
526
  ></dees-statsgrid>
537
527
  `;
538
528
  }
@@ -604,7 +594,6 @@ export class OpsViewNetwork extends DeesElement {
604
594
  return html`
605
595
  <dees-table
606
596
  .data=${this.networkState.topIPs}
607
- .showColumnFilters=${true}
608
597
  .displayFunction=${(ipData: { ip: string; count: number }) => {
609
598
  const bw = bandwidthByIP.get(ipData.ip);
610
599
  return {
@@ -632,7 +621,6 @@ export class OpsViewNetwork extends DeesElement {
632
621
  return html`
633
622
  <dees-table
634
623
  .data=${backends}
635
- .showColumnFilters=${true}
636
624
  .displayFunction=${(item: interfaces.data.IBackendInfo) => {
637
625
  const totalErrors = item.connectErrors + item.handshakeErrors + item.requestErrors;
638
626
  const protocolClass = item.protocol.toLowerCase().replace(/[^a-z0-9]/g, '');
@@ -735,12 +723,12 @@ export class OpsViewNetwork extends DeesElement {
735
723
  // Only update if connections changed significantly
736
724
  const newConnectionCount = this.networkState.connections.length;
737
725
  const oldConnectionCount = this.networkRequests.length;
738
-
726
+
739
727
  // Check if we need to update the network requests array
740
- const shouldUpdate = newConnectionCount !== oldConnectionCount ||
728
+ const shouldUpdate = newConnectionCount !== oldConnectionCount ||
741
729
  newConnectionCount === 0 ||
742
730
  (newConnectionCount > 0 && this.networkRequests.length === 0);
743
-
731
+
744
732
  if (shouldUpdate) {
745
733
  // Convert connection data to network requests format
746
734
  if (newConnectionCount > 0) {
@@ -763,62 +751,62 @@ export class OpsViewNetwork extends DeesElement {
763
751
  this.networkRequests = [];
764
752
  }
765
753
  }
766
-
754
+
767
755
  // Load server-side throughput history into chart (once)
768
756
  if (!this.historyLoaded && this.networkState.throughputHistory && this.networkState.throughputHistory.length > 0) {
769
757
  this.loadThroughputHistory();
770
758
  }
771
759
  }
772
-
760
+
773
761
  private startTrafficUpdateTimer() {
774
762
  this.stopTrafficUpdateTimer(); // Clear any existing timer
775
763
  this.trafficUpdateTimer = setInterval(() => {
776
764
  this.addTrafficDataPoint();
777
- }, OpsViewNetwork.UPDATE_INTERVAL_MS);
765
+ }, OpsViewNetworkActivity.UPDATE_INTERVAL_MS);
778
766
  }
779
-
767
+
780
768
  private addTrafficDataPoint() {
781
769
  const now = Date.now();
782
-
770
+
783
771
  // Throttle chart updates to avoid excessive re-renders
784
772
  if (now - this.lastChartUpdate < this.chartUpdateThreshold) {
785
773
  return;
786
774
  }
787
-
775
+
788
776
  const throughput = this.calculateThroughput();
789
-
777
+
790
778
  // Convert to Mbps (bytes * 8 / 1,000,000)
791
779
  const throughputInMbps = (throughput.in * 8) / 1000000;
792
780
  const throughputOutMbps = (throughput.out * 8) / 1000000;
793
-
781
+
794
782
  // Add new data points
795
783
  const timestamp = new Date(now).toISOString();
796
-
784
+
797
785
  const newDataPointIn = {
798
786
  x: timestamp,
799
787
  y: Math.round(throughputInMbps * 10) / 10
800
788
  };
801
-
789
+
802
790
  const newDataPointOut = {
803
791
  x: timestamp,
804
792
  y: Math.round(throughputOutMbps * 10) / 10
805
793
  };
806
-
794
+
807
795
  // In-place mutation then reassign for Lit reactivity (avoids 4 intermediate arrays)
808
- if (this.trafficDataIn.length >= OpsViewNetwork.MAX_DATA_POINTS) {
796
+ if (this.trafficDataIn.length >= OpsViewNetworkActivity.MAX_DATA_POINTS) {
809
797
  this.trafficDataIn.shift();
810
798
  this.trafficDataOut.shift();
811
799
  }
812
800
  this.trafficDataIn = [...this.trafficDataIn, newDataPointIn];
813
801
  this.trafficDataOut = [...this.trafficDataOut, newDataPointOut];
814
-
802
+
815
803
  this.lastChartUpdate = now;
816
804
  }
817
-
805
+
818
806
  private stopTrafficUpdateTimer() {
819
807
  if (this.trafficUpdateTimer) {
820
808
  clearInterval(this.trafficUpdateTimer);
821
809
  this.trafficUpdateTimer = null;
822
810
  }
823
811
  }
824
- }
812
+ }
@@ -7,9 +7,9 @@ import {
7
7
  state,
8
8
  cssManager,
9
9
  } from '@design.estate/dees-element';
10
- import * as appstate from '../appstate.js';
11
- import * as interfaces from '../../dist_ts_interfaces/index.js';
12
- import { viewHostCss } from './shared/css.js';
10
+ import * as appstate from '../../appstate.js';
11
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
12
+ import { viewHostCss } from '../shared/css.js';
13
13
  import { type IStatsTile } from '@design.estate/dees-catalog';
14
14
 
15
15
  declare global {
@@ -64,7 +64,7 @@ export class OpsViewNetworkTargets extends DeesElement {
64
64
  ];
65
65
 
66
66
  return html`
67
- <dees-heading level="2">Network Targets</dees-heading>
67
+ <dees-heading level="hr">Network Targets</dees-heading>
68
68
  <div class="targetsContainer">
69
69
  <dees-statsgrid .tiles=${statsTiles}></dees-statsgrid>
70
70
  <dees-table
@@ -7,9 +7,9 @@ import {
7
7
  state,
8
8
  cssManager,
9
9
  } from '@design.estate/dees-element';
10
- import * as appstate from '../appstate.js';
11
- import * as interfaces from '../../dist_ts_interfaces/index.js';
12
- import { viewHostCss } from './shared/css.js';
10
+ import * as appstate from '../../appstate.js';
11
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
12
+ import { viewHostCss } from '../shared/css.js';
13
13
  import { type IStatsTile } from '@design.estate/dees-catalog';
14
14
 
15
15
  declare global {
@@ -174,7 +174,7 @@ export class OpsViewRemoteIngress extends DeesElement {
174
174
  ];
175
175
 
176
176
  return html`
177
- <dees-heading level="2">Remote Ingress</dees-heading>
177
+ <dees-heading level="hr">Remote Ingress</dees-heading>
178
178
 
179
179
  ${this.riState.newEdgeId ? html`
180
180
  <div class="secretDialog">
@@ -1,6 +1,6 @@
1
- import * as appstate from '../appstate.js';
2
- import * as interfaces from '../../dist_ts_interfaces/index.js';
3
- import { viewHostCss } from './shared/css.js';
1
+ import * as appstate from '../../appstate.js';
2
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
3
+ import { viewHostCss } from '../shared/css.js';
4
4
  import { type IStatsTile } from '@design.estate/dees-catalog';
5
5
 
6
6
  import {
@@ -200,7 +200,7 @@ export class OpsViewRoutes extends DeesElement {
200
200
  });
201
201
 
202
202
  return html`
203
- <dees-heading level="2">Route Management</dees-heading>
203
+ <dees-heading level="hr">Route Management</dees-heading>
204
204
 
205
205
  <div class="routesContainer">
206
206
  <dees-statsgrid
@@ -7,9 +7,9 @@ import {
7
7
  state,
8
8
  cssManager,
9
9
  } from '@design.estate/dees-element';
10
- import * as appstate from '../appstate.js';
11
- import * as interfaces from '../../dist_ts_interfaces/index.js';
12
- import { viewHostCss } from './shared/css.js';
10
+ import * as appstate from '../../appstate.js';
11
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
12
+ import { viewHostCss } from '../shared/css.js';
13
13
  import { type IStatsTile } from '@design.estate/dees-catalog';
14
14
 
15
15
  declare global {
@@ -64,7 +64,7 @@ export class OpsViewSourceProfiles extends DeesElement {
64
64
  ];
65
65
 
66
66
  return html`
67
- <dees-heading level="2">Source Profiles</dees-heading>
67
+ <dees-heading level="hr">Source Profiles</dees-heading>
68
68
  <div class="profilesContainer">
69
69
  <dees-statsgrid .tiles=${statsTiles}></dees-statsgrid>
70
70
  <dees-table
@@ -7,10 +7,10 @@ import {
7
7
  state,
8
8
  cssManager,
9
9
  } from '@design.estate/dees-element';
10
- import * as plugins from '../plugins.js';
11
- import * as appstate from '../appstate.js';
12
- import * as interfaces from '../../dist_ts_interfaces/index.js';
13
- import { viewHostCss } from './shared/css.js';
10
+ import * as plugins from '../../plugins.js';
11
+ import * as appstate from '../../appstate.js';
12
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
13
+ import { viewHostCss } from '../shared/css.js';
14
14
  import { type IStatsTile } from '@design.estate/dees-catalog';
15
15
 
16
16
  declare global {
@@ -77,7 +77,7 @@ export class OpsViewTargetProfiles extends DeesElement {
77
77
  ];
78
78
 
79
79
  return html`
80
- <dees-heading level="2">Target Profiles</dees-heading>
80
+ <dees-heading level="hr">Target Profiles</dees-heading>
81
81
  <div class="profilesContainer">
82
82
  <dees-statsgrid .tiles=${statsTiles}></dees-statsgrid>
83
83
  <dees-table
@@ -7,10 +7,10 @@ import {
7
7
  state,
8
8
  cssManager,
9
9
  } from '@design.estate/dees-element';
10
- import * as plugins from '../plugins.js';
11
- import * as appstate from '../appstate.js';
12
- import * as interfaces from '../../dist_ts_interfaces/index.js';
13
- import { viewHostCss } from './shared/css.js';
10
+ import * as plugins from '../../plugins.js';
11
+ import * as appstate from '../../appstate.js';
12
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
13
+ import { viewHostCss } from '../shared/css.js';
14
14
  import { type IStatsTile } from '@design.estate/dees-catalog';
15
15
 
16
16
  /**
@@ -223,7 +223,7 @@ export class OpsViewVpn extends DeesElement {
223
223
  ];
224
224
 
225
225
  return html`
226
- <dees-heading level="2">VPN</dees-heading>
226
+ <dees-heading level="hr">VPN</dees-heading>
227
227
  <div class="vpnContainer">
228
228
 
229
229
  ${this.vpnState.newClientConfig ? html`