fix(network-ui): enable flashing table updates for network activity, remote ingress, and VPN views
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-04-08 - 13.9.1 - fix(network-ui)
|
||||||
|
enable flashing table updates for network activity, remote ingress, and VPN views
|
||||||
|
|
||||||
|
- adds stable row keys to dees-table instances so existing rows can be diffed correctly
|
||||||
|
- enables flash highlighting for changed rows and cells across network activity, top IPs, backends, remote ingress edges, and VPN clients
|
||||||
|
- updates network activity request data on every refresh so live metrics like duration and byte counts visibly refresh
|
||||||
|
|
||||||
## 2026-04-08 - 13.9.0 - feat(dns)
|
## 2026-04-08 - 13.9.0 - feat(dns)
|
||||||
add built-in dcrouter DNS provider support and rename manual domains to dcrouter-hosted/local
|
add built-in dcrouter DNS provider support and rename manual domains to dcrouter-hosted/local
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@serve.zone/dcrouter',
|
name: '@serve.zone/dcrouter',
|
||||||
version: '13.9.0',
|
version: '13.9.1',
|
||||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@serve.zone/dcrouter',
|
name: '@serve.zone/dcrouter',
|
||||||
version: '13.9.0',
|
version: '13.9.1',
|
||||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -323,6 +323,8 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|||||||
<!-- Requests Table -->
|
<!-- Requests Table -->
|
||||||
<dees-table
|
<dees-table
|
||||||
.data=${this.networkRequests}
|
.data=${this.networkRequests}
|
||||||
|
.rowKey=${'id'}
|
||||||
|
.highlightUpdates=${'flash'}
|
||||||
.displayFunction=${(req: INetworkRequest) => ({
|
.displayFunction=${(req: INetworkRequest) => ({
|
||||||
Time: new Date(req.timestamp).toLocaleTimeString(),
|
Time: new Date(req.timestamp).toLocaleTimeString(),
|
||||||
Protocol: html`<span class="protocolBadge ${req.protocol}">${req.protocol.toUpperCase()}</span>`,
|
Protocol: html`<span class="protocolBadge ${req.protocol}">${req.protocol.toUpperCase()}</span>`,
|
||||||
@@ -595,6 +597,8 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|||||||
return html`
|
return html`
|
||||||
<dees-table
|
<dees-table
|
||||||
.data=${this.networkState.topIPs}
|
.data=${this.networkState.topIPs}
|
||||||
|
.rowKey=${'ip'}
|
||||||
|
.highlightUpdates=${'flash'}
|
||||||
.displayFunction=${(ipData: { ip: string; count: number }) => {
|
.displayFunction=${(ipData: { ip: string; count: number }) => {
|
||||||
const bw = bandwidthByIP.get(ipData.ip);
|
const bw = bandwidthByIP.get(ipData.ip);
|
||||||
return {
|
return {
|
||||||
@@ -624,6 +628,8 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|||||||
return html`
|
return html`
|
||||||
<dees-table
|
<dees-table
|
||||||
.data=${backends}
|
.data=${backends}
|
||||||
|
.rowKey=${'backend'}
|
||||||
|
.highlightUpdates=${'flash'}
|
||||||
.displayFunction=${(item: interfaces.data.IBackendInfo) => {
|
.displayFunction=${(item: interfaces.data.IBackendInfo) => {
|
||||||
const totalErrors = item.connectErrors + item.handshakeErrors + item.requestErrors;
|
const totalErrors = item.connectErrors + item.handshakeErrors + item.requestErrors;
|
||||||
const protocolClass = item.protocol.toLowerCase().replace(/[^a-z0-9]/g, '');
|
const protocolClass = item.protocol.toLowerCase().replace(/[^a-z0-9]/g, '');
|
||||||
@@ -724,37 +730,24 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|||||||
this.requestsPerSecHistory.shift();
|
this.requestsPerSecHistory.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only update if connections changed significantly
|
// Reassign unconditionally so dees-table's flash diff can compare per-cell
|
||||||
const newConnectionCount = this.networkState.connections.length;
|
// values against the previous snapshot. Row identity is preserved via
|
||||||
const oldConnectionCount = this.networkRequests.length;
|
// rowKey='id', so DOM nodes are reused across ticks.
|
||||||
|
this.networkRequests = this.networkState.connections.map((conn) => ({
|
||||||
// Check if we need to update the network requests array
|
id: conn.id,
|
||||||
const shouldUpdate = newConnectionCount !== oldConnectionCount ||
|
timestamp: conn.startTime,
|
||||||
newConnectionCount === 0 ||
|
method: 'GET', // Default method for proxy connections
|
||||||
(newConnectionCount > 0 && this.networkRequests.length === 0);
|
url: '/',
|
||||||
|
hostname: conn.remoteAddress,
|
||||||
if (shouldUpdate) {
|
port: conn.protocol === 'https' ? 443 : 80,
|
||||||
// Convert connection data to network requests format
|
protocol: conn.protocol === 'https' || conn.protocol === 'http' ? conn.protocol : 'tcp',
|
||||||
if (newConnectionCount > 0) {
|
statusCode: conn.state === 'connected' ? 200 : undefined,
|
||||||
this.networkRequests = this.networkState.connections.map((conn, index) => ({
|
duration: Date.now() - conn.startTime,
|
||||||
id: conn.id,
|
bytesIn: conn.bytesReceived,
|
||||||
timestamp: conn.startTime,
|
bytesOut: conn.bytesSent,
|
||||||
method: 'GET', // Default method for proxy connections
|
remoteIp: conn.remoteAddress,
|
||||||
url: '/',
|
route: 'proxy',
|
||||||
hostname: conn.remoteAddress,
|
}));
|
||||||
port: conn.protocol === 'https' ? 443 : 80,
|
|
||||||
protocol: conn.protocol === 'https' || conn.protocol === 'http' ? conn.protocol : 'tcp',
|
|
||||||
statusCode: conn.state === 'connected' ? 200 : undefined,
|
|
||||||
duration: Date.now() - conn.startTime,
|
|
||||||
bytesIn: conn.bytesReceived,
|
|
||||||
bytesOut: conn.bytesSent,
|
|
||||||
remoteIp: conn.remoteAddress,
|
|
||||||
route: 'proxy',
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
this.networkRequests = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load server-side throughput history into chart (once)
|
// Load server-side throughput history into chart (once)
|
||||||
if (!this.historyLoaded && this.networkState.throughputHistory && this.networkState.throughputHistory.length > 0) {
|
if (!this.historyLoaded && this.networkState.throughputHistory && this.networkState.throughputHistory.length > 0) {
|
||||||
|
|||||||
@@ -220,6 +220,8 @@ export class OpsViewRemoteIngress extends DeesElement {
|
|||||||
.heading1=${'Edge Nodes'}
|
.heading1=${'Edge Nodes'}
|
||||||
.heading2=${'Manage remote ingress edge registrations'}
|
.heading2=${'Manage remote ingress edge registrations'}
|
||||||
.data=${this.riState.edges}
|
.data=${this.riState.edges}
|
||||||
|
.rowKey=${'id'}
|
||||||
|
.highlightUpdates=${'flash'}
|
||||||
.showColumnFilters=${true}
|
.showColumnFilters=${true}
|
||||||
.displayFunction=${(edge: interfaces.data.IRemoteIngress) => ({
|
.displayFunction=${(edge: interfaces.data.IRemoteIngress) => ({
|
||||||
name: edge.name,
|
name: edge.name,
|
||||||
|
|||||||
@@ -305,6 +305,8 @@ export class OpsViewVpn extends DeesElement {
|
|||||||
.heading1=${'VPN Clients'}
|
.heading1=${'VPN Clients'}
|
||||||
.heading2=${'Manage WireGuard and SmartVPN client registrations'}
|
.heading2=${'Manage WireGuard and SmartVPN client registrations'}
|
||||||
.data=${clients}
|
.data=${clients}
|
||||||
|
.rowKey=${'clientId'}
|
||||||
|
.highlightUpdates=${'flash'}
|
||||||
.showColumnFilters=${true}
|
.showColumnFilters=${true}
|
||||||
.displayFunction=${(client: interfaces.data.IVpnClient) => {
|
.displayFunction=${(client: interfaces.data.IVpnClient) => {
|
||||||
const conn = this.getConnectedInfo(client);
|
const conn = this.getConnectedInfo(client);
|
||||||
|
|||||||
Reference in New Issue
Block a user