/* ------------------------------------------------------------- 1. Socket‑IO connection & helper functions (unchanged) ------------------------------------------------------------- */ const socket = io(); socket.on('host_stats', renderStatsTable); socket.on('connect_error', err => { safeSetText('host_stats', `Could not connect to server - ${err.message}`); }); socket.on('reconnect', attempt => { safeSetText('host_stats', `Re‑connected (attempt ${attempt})`); }); function safeSetText(id, txt) { const el = document.getElementById(id); if (el) el.textContent = txt; } /* ------------------------------------------------------------- 2. Table rendering – the table remains a ------------------------------------------------------------- */ function renderStatsTable(data) { renderGenericTable('host_stats', data, 'No Stats available'); } function renderGenericTable(containerId, data, emptyMsg) { const container = document.getElementById(containerId); if (!Array.isArray(data) || !data.length) { container.textContent = emptyMsg; return; } /* 2️⃣ Merge “System Class Variable” rows first */ const mergedData = mergeSystemClassVariableRows(data); /* 3️⃣ Build the table from the merged data */ const table = buildTable(mergedData); container.innerHTML = ''; container.appendChild(table); } /* ------------------------------------------------------------- 3. Merge consecutive rows whose type === "System Class Variable" ------------------------------------------------------------- */ function mergeSystemClassVariableRows(data) { const result = []; let i = 0; while (i < data.length) { const cur = data[i]; if (cur.type && cur.type.trim() === 'System Class Variable') { const group = []; while ( i < data.length && data[i].type && data[i].type.trim() === 'System Class Variable' ) { group.push(data[i]); i++; } /* Build one merged object – keep each column as an array */ const merged = { type: 'System Class Variable' }; const cols = Object.keys(group[0]).filter(k => k !== 'type'); cols.forEach(col => { const vals = group .map(row => row[col]) .filter(v => v !== undefined && v !== null); merged[col] = vals; // ← array, not joined string }); result.push(merged); } else { /* Normal row – just copy it */ result.push(cur); i++; } } return result; } /* ------------------------------------------------------------- 4. Build an HTML table from an array of objects ------------------------------------------------------------- */ function buildTable(data) { const cols = Object.keys(data[0]); // column order const table = document.createElement('table'); /* Header */ const thead = table.createTHead(); const headerRow = thead.insertRow(); cols.forEach(col => { const th = document.createElement('th'); th.textContent = col; headerRow.appendChild(th); }); /* Body */ const tbody = table.createTBody(); data.forEach(item => { const tr = tbody.insertRow(); cols.forEach(col => { const td = tr.insertCell(); const val = item[col]; /* If the value is an array → render as
    */ if (Array.isArray(val)) { const ol = document.createElement('ol'); val.forEach(v => { const li = document.createElement('li'); li.textContent = v; ol.appendChild(li); }); td.appendChild(ol); } else { td.textContent = val; // normal text } }); }); return table; }