|
@@ -496,43 +496,40 @@ function renderDashboard() {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const ifaceTbody = document.getElementById('quick-interfaces-table');
|
|
const ifaceTbody = document.getElementById('quick-interfaces-table');
|
|
|
- ifaceTbody.innerHTML = '';
|
|
|
|
|
- (state.interfaces || []).slice(0, 6).forEach(i => {
|
|
|
|
|
- const isUp = i.state === 'UP';
|
|
|
|
|
- const tr = document.createElement('tr');
|
|
|
|
|
- tr.className = 'hover:bg-slate-800/40 transition cursor-pointer';
|
|
|
|
|
- tr.onclick = () => openIfaceModal(i.name);
|
|
|
|
|
- tr.innerHTML = `
|
|
|
|
|
- <td class="py-2.5 font-bold text-white flex items-center gap-2">
|
|
|
|
|
- <span class="w-1.5 h-1.5 rounded-full ${isUp ? 'bg-emerald-400' : 'bg-rose-400'}"></span>
|
|
|
|
|
- <span>${i.name}</span>
|
|
|
|
|
- </td>
|
|
|
|
|
- <td class="py-2.5 text-slate-300 font-sans"><span class="px-1.5 py-0.5 rounded text-[10px] bg-slate-800 text-slate-300">${i.role || 'LAN'}</span></td>
|
|
|
|
|
- <td class="py-2.5 text-slate-300">${i.ipv4 && i.ipv4.length > 0 ? i.ipv4[0] : '<span class="text-slate-600">-</span>'}</td>
|
|
|
|
|
- <td class="py-2.5 text-right font-sans font-semibold ${isUp ? 'text-emerald-400' : 'text-rose-400'}">${i.state}</td>
|
|
|
|
|
- `;
|
|
|
|
|
- ifaceTbody.appendChild(tr);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- const vlanTbody = document.getElementById('quick-vlans-table');
|
|
|
|
|
- vlanTbody.innerHTML = '';
|
|
|
|
|
- const vlans = state.vlans || [];
|
|
|
|
|
- if (vlans.length === 0) {
|
|
|
|
|
- vlanTbody.innerHTML = `<tr><td colspan="4" class="py-4 text-center text-slate-500 font-sans">No VLANs configured. Click "+ Add" above to create one.</td></tr>`;
|
|
|
|
|
- } else {
|
|
|
|
|
- vlans.slice(0, 6).forEach(v => {
|
|
|
|
|
|
|
+ if (ifaceTbody) {
|
|
|
|
|
+ ifaceTbody.innerHTML = '';
|
|
|
|
|
+ (state.interfaces || []).forEach(i => {
|
|
|
|
|
+ const isUp = i.state === 'UP';
|
|
|
const tr = document.createElement('tr');
|
|
const tr = document.createElement('tr');
|
|
|
tr.className = 'hover:bg-slate-800/40 transition cursor-pointer';
|
|
tr.className = 'hover:bg-slate-800/40 transition cursor-pointer';
|
|
|
- tr.onclick = () => openIfaceModal(v.name);
|
|
|
|
|
|
|
+ tr.onclick = () => openIfaceModal(i.name);
|
|
|
|
|
+ const rxStr = i.rate?.rx_human || '0 B/s';
|
|
|
|
|
+ const txStr = i.rate?.tx_human || '0 B/s';
|
|
|
tr.innerHTML = `
|
|
tr.innerHTML = `
|
|
|
- <td class="py-2.5"><span class="px-2 py-0.5 rounded text-[11px] bg-cyan-950 text-cyan-400 border border-cyan-800 font-bold">VLAN ${v.vlan_id}</span></td>
|
|
|
|
|
- <td class="py-2.5 text-white font-bold">${v.name}</td>
|
|
|
|
|
- <td class="py-2.5 text-slate-300">${v.ipv4 && v.ipv4.length > 0 ? v.ipv4[0] : '<span class="text-slate-600">Unnumbered</span>'}</td>
|
|
|
|
|
- <td class="py-2.5 text-right text-slate-400">${v.parent_name || 'eth0'}</td>
|
|
|
|
|
|
|
+ <td class="py-2.5 font-bold text-white flex items-center gap-2">
|
|
|
|
|
+ <span class="w-2 h-2 rounded-full ${isUp ? 'bg-emerald-400 shadow-sm shadow-emerald-400/50' : 'bg-rose-400'}"></span>
|
|
|
|
|
+ <span>${i.name}</span>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td class="py-2.5 text-slate-300 font-sans">
|
|
|
|
|
+ <span class="px-2 py-0.5 rounded text-[10px] bg-slate-800 text-slate-300 font-medium">${i.role || i.type || 'Ethernet'}</span>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td class="py-2.5 text-slate-400 text-[11px] font-mono">${i.mac || '-'}</td>
|
|
|
|
|
+ <td class="py-2.5 text-slate-200 font-semibold">${i.ipv4 && i.ipv4.length > 0 ? i.ipv4.join(', ') : '<span class="text-slate-600 font-normal">Unassigned</span>'}</td>
|
|
|
|
|
+ <td class="py-2.5 text-slate-300 text-[11px] font-mono">
|
|
|
|
|
+ <span class="text-emerald-400">↓ ${rxStr}</span> <span class="text-slate-600">•</span> <span class="text-cyan-400">↑ ${txStr}</span>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td class="py-2.5 text-right font-sans font-semibold">
|
|
|
|
|
+ <span class="px-2 py-0.5 rounded text-[10px] ${isUp ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20' : 'bg-rose-500/10 text-rose-400 border border-rose-500/20'}">${i.state}</span>
|
|
|
|
|
+ </td>
|
|
|
`;
|
|
`;
|
|
|
- vlanTbody.appendChild(tr);
|
|
|
|
|
|
|
+ ifaceTbody.appendChild(tr);
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ const vlanTbody = document.getElementById('quick-vlans-table');
|
|
|
|
|
+ if (vlanTbody) {
|
|
|
|
|
+ vlanTbody.innerHTML = '';
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Expand / Collapse Handlers
|
|
// Expand / Collapse Handlers
|