/* jshint esversion: 2024, module: true */ import { Utils } from "./utils.js"; import { InterfaceState } from "./enums.js"; /** * Static Interface Renderer for displaying network interfaces * @class InterfaceRenderer */ class InterfaceRenderer { /** * Render interface tabs * @static * @param {Array} interfaces - Array of interface objects * @param {Object} currentInterface - Current interface object * @returns {string} HTML string */ static renderInterfaceTabs(interfaces, currentInterface) { if (!interfaces.length) { return '
No network interfaces found
'; } 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 ` `; }) .join(""); return `
${tabsHTML}
`; } /** * Show detailed interface information * @static * @param {Object} iface - Interface object * @returns {string} HTML string */ 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", InterfaceRenderer.renderNTPServerList(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 `
${details}
`; } /** * Render a detail row with abbreviations * @static * @param {string} label - Row label * @param {string} value - Row value * @param {string} [valueClass] - CSS class for value * @returns {string} HTML string */ static renderDetailRow(label, value, valueClass = "") { if (!value && value !== 0 && value !== false) return ""; const abbreviations = { MTU: "Maximum Transmission Unit", QDisc: "Queueing Discipline", Tx: "Transmit", Rx: "Receive", DNS: "Domain Name System", NTP: "Network Time Protocol", DHCP: "Dynamic Host Configuration Protocol", MAC: "Media Access Control", IP: "Internet Protocol", IPv6: "Internet Protocol version 6", }; const abbrLabel = Object.keys(abbreviations).includes(label) ? `${label}` : label; // Handle different value types let displayValue; if (typeof value === "string") { displayValue = Utils.sanitizeHTML(value); } else if (typeof value === "object") { // Handle object rendering displayValue = InterfaceRenderer.renderObjectValue(value); } else { displayValue = Utils.sanitizeHTML(String(value)); } return `
${abbrLabel}: ${displayValue}
`; } /** * Render object value for display * @static * @param {Object} obj - Object to render * @returns {string} HTML string */ static renderObjectValue(obj) { if (obj === null || obj === undefined) return ""; // Handle array of objects if (Array.isArray(obj)) { return obj .map((item) => InterfaceRenderer.renderObjectValue(item)) .join(", "); } // Handle plain object if (typeof obj === "object") { // Check if it's an IP address object if (obj.Address && Array.isArray(obj.Address)) { return Utils.ipFromArray(obj); } // Check if it's a simple key-value object we can stringify try { const simpleObj = {}; for (const [key, value] of Object.entries(obj)) { if ( value !== null && value !== undefined && typeof value !== "object" ) { simpleObj[key] = value; } } if (Object.keys(simpleObj).length > 0) { return Utils.sanitizeHTML(JSON.stringify(simpleObj)); } } catch (e) { // Fall through to default handling } return Utils.sanitizeHTML(String(obj)); } return Utils.sanitizeHTML(String(obj)); } /** * Render address list * @static * @param {Array} addresses - Array of addresses * @returns {string} Formatted addresses */ static renderAddressList(addresses) { if (!addresses?.length) return ""; const addressItems = addresses .map((addr) => { const ip = Utils.ipFromArray(addr); return ip ? Utils.sanitizeHTML(ip) : ""; }) .filter((ip) => ip) .join(", "); return addressItems || ""; } /** * Render DNS server list * @static * @param {Array} dnsServers - Array of DNS servers * @returns {string} Formatted DNS servers */ static renderDNSServerList(dnsServers) { if (!dnsServers?.length) return ""; const dnsItems = dnsServers .map((dns) => { const server = Utils.ipFromArray(dns.Address ?? dns); return server ? Utils.sanitizeHTML(server) : ""; }) .filter((server) => server) .join(", "); return dnsItems || ""; } /** * Render NTP server list * @static * @param {Array} ntpServers - Array of NTP servers * @returns {string} Formatted NTP servers */ static renderNTPServerList(ntpServers) { if (!ntpServers?.length) return ""; const ntpItems = ntpServers .map((ntp) => { if (typeof ntp === "string") { return Utils.sanitizeHTML(ntp); } else if (ntp && typeof ntp === "object") { // Handle NTP server object if (ntp.Address && Array.isArray(ntp.Address)) { return Utils.ipFromArray(ntp); } else if (ntp.Server) { return Utils.sanitizeHTML(ntp.Server); } else { // Try to extract any stringifiable value return InterfaceRenderer.renderObjectValue(ntp); } } return ""; }) .filter((server) => server) .join(", "); return ntpItems || ""; } /** * Render DHCP leases * @static * @param {Array} leases - Array of DHCP leases * @returns {string} Formatted leases */ static renderDHCPLeases(leases) { if (!leases?.length) return ""; const leaseItems = leases .map((lease) => { if (typeof lease === "string") { return Utils.sanitizeHTML(lease); } else if (lease && typeof lease === "object") { const ip = lease.IP ?? lease.Address ?? lease; const to = lease.To ?? lease.MAC ?? lease.ClientIdentifier ?? ""; if (ip && to) { return `${Utils.sanitizeHTML(String(ip))} (to ${Utils.sanitizeHTML(String(to))})`; } else if (ip) { return Utils.sanitizeHTML(String(ip)); } else { return InterfaceRenderer.renderObjectValue(lease); } } return ""; }) .filter((lease) => lease) .join(", "); return leaseItems || ""; } } export { InterfaceRenderer };