feat: métriques réseau+hardware serveur+dashboard + API /agents/{id} + iperf3
Serveur:
- Modèles Go: NetworkInterface, HardwareInfo dans Agent + AgentMetrics
- DB: migrations network_info_json + hardware_info_json dans agents
- UpsertAgent: stocke les données lentes si présentes dans le payload
- GetAgents: désérialise network_info_json + hardware_info_json
- GET /api/agents/{id}: endpoint single agent
- docker-compose: service iperf3 (port 5201)
Dashboard:
- Popup détail: section RÉSEAU (tableau interfaces: type, vitesse, MAC, WoL, iperf3)
- Popup détail: section HARDWARE (carte mère, CPU, RAM slots/type/vitesse)
- CSS: .net-table/.net-row pour le tableau réseau
- Font-size global appliqué sur html root (au lieu de body)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -109,7 +109,7 @@ const App = (() => {
|
||||
document.documentElement.style.setProperty('--tile-min', _serverConfig.tile_min_width + 'px');
|
||||
}
|
||||
if (_serverConfig.font_size) {
|
||||
document.body.style.fontSize = _serverConfig.font_size + 'px';
|
||||
document.documentElement.style.fontSize = _serverConfig.font_size + 'px';
|
||||
}
|
||||
if (_serverConfig.popup_detail_w && _serverConfig.popup_detail_h) {
|
||||
const pd = document.getElementById('popup-detail');
|
||||
|
||||
@@ -151,6 +151,47 @@ const Popups = (() => {
|
||||
${smartBadges}
|
||||
</div>
|
||||
</div>
|
||||
${(() => {
|
||||
const ni = entry?.agent?.network_info;
|
||||
if (!ni?.length) return '';
|
||||
const wol = v => v == null ? '—' : v ? '<span style="color:var(--ok)">Oui</span>' : '<span style="color:var(--ink-4)">Non</span>';
|
||||
const spd = v => v == null ? '—' : v >= 1000 ? '1 Gb' : v + ' Mb';
|
||||
const rows = ni.map(iface => `
|
||||
<div class="net-row">
|
||||
<span style="color:var(--ink-3);font-size:12px"><i class="fa-solid fa-${iface.if_type === 'wifi' ? 'wifi' : 'ethernet'}"></i></span>
|
||||
<span style="color:var(--ink-1);font-weight:600">${esc(iface.name)}</span>
|
||||
<span style="color:var(--ink-3)">${spd(iface.speed_mbps)}</span>
|
||||
<span style="color:var(--ink-4);font-size:9px;letter-spacing:.04em">${esc(iface.mac)}</span>
|
||||
<span>WoL : ${wol(iface.wol)}</span>
|
||||
<span style="color:var(--blue)">${iface.iperf_mbps != null ? iface.iperf_mbps.toFixed(1) + ' Mb/s' : '—'}</span>
|
||||
</div>`).join('');
|
||||
return `<div>
|
||||
<div class="sec-title">RÉSEAU</div>
|
||||
<div class="net-table">
|
||||
<div class="net-row" style="background:var(--bg-4);font-size:9px;color:var(--ink-4);letter-spacing:.06em">
|
||||
<span></span><span>INTERFACE</span><span>VITESSE</span><span>MAC</span><span>WAKE ON LAN</span><span>IPERF3</span>
|
||||
</div>
|
||||
${rows}
|
||||
</div>
|
||||
</div>`;
|
||||
})()}
|
||||
${(() => {
|
||||
const hw = entry?.agent?.hardware_info;
|
||||
if (!hw) return '';
|
||||
const row = (lbl, val) => val ? `<div class="meta"><div class="meta-lbl">${lbl}</div><div class="meta-val">${esc(String(val))}</div></div>` : '';
|
||||
const ramSlots = hw.ram_slots_used != null && hw.ram_slots_total != null
|
||||
? `${hw.ram_slots_used}/${hw.ram_slots_total} slots` : null;
|
||||
const ramInfo = [hw.ram_type, hw.ram_speed_mhz ? hw.ram_speed_mhz + ' MHz' : null, ramSlots]
|
||||
.filter(Boolean).join(' · ') || null;
|
||||
return `<div>
|
||||
<div class="sec-title">HARDWARE</div>
|
||||
<div class="meta-grid">
|
||||
${row('CARTE MÈRE', hw.motherboard_vendor && hw.motherboard_model ? hw.motherboard_vendor + ' ' + hw.motherboard_model : hw.motherboard_model || hw.motherboard_vendor)}
|
||||
${row('PROCESSEUR', hw.cpu_model)}
|
||||
${row('MÉMOIRE RAM', ramInfo)}
|
||||
</div>
|
||||
</div>`;
|
||||
})()}
|
||||
<div>
|
||||
<div class="sec-title">INFORMATIONS</div>
|
||||
<div class="meta-grid">
|
||||
|
||||
Reference in New Issue
Block a user