/* 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 };