summaryrefslogtreecommitdiffstats
path: root/static/interface-renderer.js
diff options
context:
space:
mode:
authorPetri Hienonen <petri.hienonen@gmail.com>2025-09-28 15:08:14 +0300
committerPetri Hienonen <petri.hienonen@gmail.com>2025-09-28 15:08:14 +0300
commit8489f1f83da5dcc5818401393b1f6a430eea677c (patch)
treed55c205a0b45127765c1547fef5904d08e1171a4 /static/interface-renderer.js
parent289e73570674b67f7a1561cff9cec61498efc6cc (diff)
downloadnetwork-8489f1f83da5dcc5818401393b1f6a430eea677c.tar.zst
Intial version
Diffstat (limited to 'static/interface-renderer.js')
-rw-r--r--static/interface-renderer.js232
1 files changed, 72 insertions, 160 deletions
diff --git a/static/interface-renderer.js b/static/interface-renderer.js
index 93364c8..8c01696 100644
--- a/static/interface-renderer.js
+++ b/static/interface-renderer.js
@@ -1,111 +1,92 @@
/* jshint esversion: 2024, module: true */
+import { Utils } from './utils.js';
+import { InterfaceState } from './enums.js';
+
/**
- * Interface Renderer for displaying network interfaces
+ * Static Interface Renderer for displaying network interfaces
* @class InterfaceRenderer
*/
class InterfaceRenderer {
/**
- * @param {Object} elements - DOM elements
- * @param {Object} state - Application state
- */
- constructor(elements, state) {
- this.elements = elements;
- this.state = state;
- }
-
- /**
* Render interface tabs
- * @method renderInterfaceTabs
+ * @static
* @param {Array} interfaces - Array of interface objects
+ * @param {Object} currentInterface - Current interface object
+ * @returns {string} HTML string
*/
- renderInterfaceTabs(interfaces) {
+ static renderInterfaceTabs(interfaces, currentInterface) {
if (!interfaces.length) {
- this.elements.outputs.ifaceTabs.innerHTML = '<div class="no-interfaces">No network interfaces found</div>';
- this.elements.outputs.ifaceDetails.innerHTML = '';
- return;
+ return '<div class="no-interfaces">No network interfaces found</div>';
}
- const tabsHTML = interfaces.map(iface => `
- <button class="interface-tab ${iface === this.state.currentInterface ? 'active' : ''}"
- data-interface="${iface.Name}">
- ${iface.Name}
- <span class="interface-state ${this.getStateClass(iface)}">${this.getStateText(iface)}</span>
- </button>
- `).join('');
-
- this.elements.outputs.ifaceTabs.innerHTML = `<div class="interface-tabs-container">${tabsHTML}</div>`;
-
- // Add event listeners to tabs
- this.elements.outputs.ifaceTabs.querySelectorAll('.interface-tab').forEach(tab => {
- tab.addEventListener('click', (event) => {
- const ifaceName = event.currentTarget.dataset.interface;
- const iface = interfaces.find(i => i.Name === ifaceName);
- if (iface) {
- this.showInterfaceDetails(iface);
- }
- });
- });
+ const tabsHTML = interfaces.map(iface => {
+ const state = Utils.getInterfaceState(iface);
+ const stateClass = Utils.getStateClass(state);
+ const stateText = Utils.getStateText(iface);
+ const isActive = iface === currentInterface;
+
+ return `
+ <button class="interface-tab ${isActive ? 'active' : ''}"
+ data-interface="${Utils.sanitizeHTML(iface.Name)}">
+ ${Utils.sanitizeHTML(iface.Name)}
+ <span class="interface-state ${stateClass}">${Utils.sanitizeHTML(stateText)}</span>
+ </button>
+ `;
+ }).join('');
+
+ return `<div class="interface-tabs-container">${tabsHTML}</div>`;
}
/**
- * Show detailed interface information with abbreviations
- * @method showInterfaceDetails
+ * Show detailed interface information
+ * @static
* @param {Object} iface - Interface object
+ * @returns {string} HTML string
*/
- showInterfaceDetails(iface) {
- this.state.currentInterface = iface;
-
- // Update active tab
- this.elements.outputs.ifaceTabs.querySelectorAll('.interface-tab').forEach(tab => {
- tab.classList.toggle('active', tab.dataset.interface === iface.Name);
- });
-
- const detailsHTML = `
- <div class="interface-detail-grid">
- ${this.renderDetailRow('Link File', iface.LinkFile)}
- ${this.renderDetailRow('Network File', iface.NetworkFile)}
- ${this.renderDetailRow('State', iface.State, this.getStateClass(iface))}
- ${this.renderDetailRow('Online State', iface.OnlineState)}
- ${this.renderDetailRow('Type', iface.Type)}
- ${this.renderDetailRow('Path', iface.Path)}
- ${this.renderDetailRow('Driver', iface.Driver)}
- ${this.renderDetailRow('Vendor', iface.Vendor)}
- ${this.renderDetailRow('Model', iface.Model)}
- ${this.renderDetailRow('Hardware Address', this.arrayToMac(iface.HardwareAddress))}
- ${this.renderDetailRow('MTU', iface.MTU ? `${iface.MTU} (min: ${iface.MTUMin ?? '?'}, max: ${iface.MTUMax ?? '?'})` : '')}
- ${this.renderDetailRow('QDisc', iface.QDisc)}
- ${this.renderDetailRow('IPv6 Address Generation Mode', iface.IPv6AddressGenerationMode)}
- ${this.renderDetailRow('Number of Queues (Tx/Rx)', iface.Queues ? `${iface.Queues.Tx ?? '?'}/${iface.Queues.Rx ?? '?'}` : '')}
- ${this.renderDetailRow('Auto negotiation', iface.AutoNegotiation ? 'yes' : 'no')}
- ${this.renderDetailRow('Speed', iface.Speed)}
- ${this.renderDetailRow('Duplex', iface.Duplex)}
- ${this.renderDetailRow('Port', iface.Port)}
- ${this.renderDetailRow('Address', this.renderAddressList(iface.Addresses))}
- ${this.renderDetailRow('DNS', this.renderDNSServerList(iface.DNS))}
- ${this.renderDetailRow('NTP', iface.NTP)}
- ${this.renderDetailRow('Activation Policy', iface.ActivationPolicy)}
- ${this.renderDetailRow('Required For Online', iface.RequiredForOnline ? 'yes' : 'no')}
- ${this.renderDetailRow('Connected To', iface.ConnectedTo)}
- ${this.renderDetailRow('Offered DHCP leases', this.renderDHCPLeases(iface.DHCPLeases))}
- </div>
- `;
-
- this.elements.outputs.ifaceDetails.innerHTML = detailsHTML;
+ static showInterfaceDetails(iface) {
+ const details = [
+ InterfaceRenderer.renderDetailRow('Link File', iface.LinkFile),
+ InterfaceRenderer.renderDetailRow('Network File', iface.NetworkFile),
+ InterfaceRenderer.renderDetailRow('State', iface.State, Utils.getStateClass(Utils.getInterfaceState(iface))),
+ InterfaceRenderer.renderDetailRow('Online State', iface.OnlineState),
+ InterfaceRenderer.renderDetailRow('Type', iface.Type),
+ InterfaceRenderer.renderDetailRow('Path', iface.Path),
+ InterfaceRenderer.renderDetailRow('Driver', iface.Driver),
+ InterfaceRenderer.renderDetailRow('Vendor', iface.Vendor),
+ InterfaceRenderer.renderDetailRow('Model', iface.Model),
+ InterfaceRenderer.renderDetailRow('Hardware Address', Utils.arrayToMac(iface.HardwareAddress)),
+ InterfaceRenderer.renderDetailRow('MTU', iface.MTU ? `${iface.MTU} (min: ${iface.MTUMin ?? '?'}, max: ${iface.MTUMax ?? '?'})` : ''),
+ InterfaceRenderer.renderDetailRow('QDisc', iface.QDisc),
+ InterfaceRenderer.renderDetailRow('IPv6 Address Generation Mode', iface.IPv6AddressGenerationMode),
+ InterfaceRenderer.renderDetailRow('Number of Queues (Tx/Rx)', iface.Queues ? `${iface.Queues.Tx ?? '?'}/${iface.Queues.Rx ?? '?'}` : ''),
+ InterfaceRenderer.renderDetailRow('Auto negotiation', iface.AutoNegotiation ? 'yes' : 'no'),
+ InterfaceRenderer.renderDetailRow('Speed', iface.Speed),
+ InterfaceRenderer.renderDetailRow('Duplex', iface.Duplex),
+ InterfaceRenderer.renderDetailRow('Port', iface.Port),
+ InterfaceRenderer.renderDetailRow('Address', InterfaceRenderer.renderAddressList(iface.Addresses)),
+ InterfaceRenderer.renderDetailRow('DNS', InterfaceRenderer.renderDNSServerList(iface.DNS)),
+ InterfaceRenderer.renderDetailRow('NTP', iface.NTP),
+ InterfaceRenderer.renderDetailRow('Activation Policy', iface.ActivationPolicy),
+ InterfaceRenderer.renderDetailRow('Required For Online', iface.RequiredForOnline ? 'yes' : 'no'),
+ InterfaceRenderer.renderDetailRow('Connected To', iface.ConnectedTo),
+ InterfaceRenderer.renderDetailRow('Offered DHCP leases', InterfaceRenderer.renderDHCPLeases(iface.DHCPLeases))
+ ].filter(Boolean).join('');
+
+ return `<div class="interface-detail-grid">${details}</div>`;
}
/**
* Render a detail row with abbreviations
- * @method renderDetailRow
+ * @static
* @param {string} label - Row label
* @param {string} value - Row value
* @param {string} [valueClass] - CSS class for value
* @returns {string} HTML string
*/
- renderDetailRow(label, value, valueClass = '') {
+ static renderDetailRow(label, value, valueClass = '') {
if (!value) return '';
- // Add abbreviations for common networking terms
const abbreviations = {
'MTU': 'Maximum Transmission Unit',
'QDisc': 'Queueing Discipline',
@@ -126,125 +107,56 @@ class InterfaceRenderer {
return `
<div class="detail-row">
<span class="detail-label">${abbrLabel}:</span>
- <span class="detail-value ${valueClass}">${value}</span>
+ <span class="detail-value ${valueClass}">${Utils.sanitizeHTML(value)}</span>
</div>
`;
}
/**
* Render address list
- * @method renderAddressList
+ * @static
* @param {Array} addresses - Array of addresses
* @returns {string} Formatted addresses
*/
- renderAddressList(addresses) {
+ static renderAddressList(addresses) {
if (!addresses?.length) return '';
return addresses.map(addr => {
- const ip = this.ipFromArray(addr);
- return ip ? `<div class="address-item">${ip}</div>` : '';
+ const ip = Utils.ipFromArray(addr);
+ return ip ? `<div class="address-item">${Utils.sanitizeHTML(ip)}</div>` : '';
}).join('');
}
/**
* Render DNS server list
- * @method renderDNSServerList
+ * @static
* @param {Array} dnsServers - Array of DNS servers
* @returns {string} Formatted DNS servers
*/
- renderDNSServerList(dnsServers) {
+ static renderDNSServerList(dnsServers) {
if (!dnsServers?.length) return '';
return dnsServers.map(dns => {
- const server = this.ipFromArray(dns.Address ?? dns);
- return server ? `<div class="dns-item">${server}</div>` : '';
+ const server = Utils.ipFromArray(dns.Address ?? dns);
+ return server ? `<div class="dns-item">${Utils.sanitizeHTML(server)}</div>` : '';
}).join('');
}
/**
* Render DHCP leases
- * @method renderDHCPLeases
+ * @static
* @param {Array} leases - Array of DHCP leases
* @returns {string} Formatted leases
*/
- renderDHCPLeases(leases) {
+ static renderDHCPLeases(leases) {
if (!leases?.length) return '';
return leases.map(lease => {
const ip = lease.IP ?? lease;
const to = lease.To ?? lease.MAC ?? '';
- return `<div class="lease-item">${ip} (to ${to})</div>`;
+ return `<div class="lease-item">${Utils.sanitizeHTML(ip)} (to ${Utils.sanitizeHTML(to)})</div>`;
}).join('');
}
-
- /**
- * Get CSS class for interface state
- * @method getStateClass
- * @param {Object} iface - Interface object
- * @returns {string} CSS class
- */
- getStateClass(iface) {
- const state = iface.OperationalState ?? iface.AdministrativeState ?? iface.State ?? '';
- return state.toLowerCase().includes('up') ||
- state.toLowerCase().includes('routable') ||
- state.toLowerCase().includes('configured') ? 'state-up' : 'state-down';
- }
-
- /**
- * Get display text for interface state
- * @method getStateText
- * @param {Object} iface - Interface object
- * @returns {string} State text
- */
- getStateText(iface) {
- return iface.OperationalState ?? iface.AdministrativeState ?? iface.State ?? 'unknown';
- }
-
- /**
- * Convert byte array to MAC address
- * @method arrayToMac
- * @param {Array} bytes - Byte array
- * @returns {string} MAC address
- */
- arrayToMac(bytes) {
- if (!Array.isArray(bytes)) return '';
-
- return bytes.map(byte => byte.toString(16).padStart(2, '0')).join(':');
- }
-
- /**
- * Convert byte array to IP address
- * @method ipFromArray
- * @param {Array|Object} obj - IP data
- * @returns {string} IP address
- */
- ipFromArray(obj) {
- let bytes = null;
-
- if (Array.isArray(obj)) {
- bytes = obj;
- } else if (obj?.Address && Array.isArray(obj.Address)) {
- bytes = obj.Address;
- } else {
- return '';
- }
-
- // IPv4
- if (bytes.length === 4) {
- return bytes.join('.');
- }
-
- // IPv6
- if (bytes.length === 16) {
- const parts = [];
- for (let i = 0; i < 16; i += 2) {
- parts.push(((bytes[i] << 8) | bytes[i + 1]).toString(16));
- }
- return parts.join(':').replace(/(^|:)0+/g, '$1').replace(/:{3,}/, '::');
- }
-
- return '';
- }
}
export { InterfaceRenderer };