feat: agente con métricas de red, swap, top procesos y TCP; dashboard mejorado

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-06-25 08:49:39 -05:00
co-authored by Claude Sonnet 4.6
parent 491e908448
commit 34b9c81262
2 changed files with 197 additions and 25 deletions
+80
View File
@@ -109,6 +109,79 @@
<p class="text-[10px] text-slate-400 mt-0.5" x-text="'+' + (m.discos.length - 3) + ' más'"></p>
</template>
</div>
<!-- Swap -->
<template x-if="m.swap?.total_gb > 0">
<div>
<div class="flex justify-between text-xs mb-1">
<span class="text-slate-500 font-medium">🔄 Swap</span>
<span class="font-mono font-bold text-slate-700"
x-text="m.swap.usado_gb + ' / ' + m.swap.total_gb + ' GB (' + m.swap.porcentaje + '%)'"></span>
</div>
<div class="w-full bg-slate-100 rounded-full h-1.5">
<div class="h-1.5 rounded-full transition-all"
:class="m.swap.porcentaje > 85 ? 'bg-red-500' : m.swap.porcentaje > 50 ? 'bg-amber-400' : 'bg-purple-400'"
:style="'width:' + Math.min(m.swap.porcentaje, 100) + '%'"></div>
</div>
</div>
</template>
<!-- Red -->
<template x-if="(m.red || []).length > 0">
<div>
<div class="flex justify-between text-xs mb-1">
<span class="text-slate-500 font-medium">🌐 Red</span>
<span class="text-[10px] text-slate-400" x-text="(m.red || []).length + ' interfaz(es)'"></span>
</div>
<template x-for="r in (m.red || []).slice(0,2)" :key="r.interface">
<div class="flex justify-between text-[10px] text-slate-500 font-mono mb-0.5">
<span x-text="r.interface"></span>
<span>
<span class="text-green-600"><span x-text="fmtMB(r.bytes_rec_mb)"></span></span>
<span class="text-blue-600 ml-1"><span x-text="fmtMB(r.bytes_env_mb)"></span></span>
</span>
</div>
</template>
</div>
</template>
<!-- TCP + Top Procs -->
<div class="flex items-center justify-between text-xs text-slate-500 pt-1 border-t border-slate-100">
<span>🔌 TCP: <strong x-text="m.tcp_conns ?? '—'"></strong></span>
<span>📊 Load: <strong x-text="m.load_avg?.load1 ?? '—'"></strong></span>
</div>
<!-- Top Procesos -->
<template x-if="(m.top_procs || []).length > 0">
<div x-data="{ showProcs: false }">
<button @click="showProcs=!showProcs" class="w-full text-left text-[10px] text-slate-400 hover:text-slate-600 flex items-center gap-1">
<svg class="w-3 h-3 transition-transform" :class="showProcs ? 'rotate-90' : ''" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
Top procesos (<span x-text="(m.top_procs||[]).length"></span>)
</button>
<template x-if="showProcs">
<div class="mt-1.5 bg-slate-50 rounded-lg overflow-hidden">
<table class="w-full text-[10px]">
<thead><tr class="text-slate-400 border-b border-slate-200">
<th class="px-2 py-1 text-left">Proceso</th>
<th class="px-2 py-1 text-right">CPU%</th>
<th class="px-2 py-1 text-right">RAM</th>
</tr></thead>
<tbody>
<template x-for="p in (m.top_procs||[]).slice(0,8)" :key="p.pid">
<tr class="border-b border-slate-100 last:border-0">
<td class="px-2 py-1 font-mono truncate max-w-[90px]" x-text="p.nombre"></td>
<td class="px-2 py-1 text-right font-bold"
:class="p.cpu > 50 ? 'text-red-600' : p.cpu > 20 ? 'text-amber-600' : 'text-slate-600'"
x-text="p.cpu + '%'"></td>
<td class="px-2 py-1 text-right text-slate-500 font-mono" x-text="fmtMB(p.ram_mb)"></td>
</tr>
</template>
</tbody>
</table>
</div>
</template>
</div>
</template>
<!-- Uptime + OS -->
<div class="flex justify-between text-xs text-slate-400 pt-1 border-t border-slate-100">
<span><span x-text="m.uptime || '—'"></span></span>
@@ -654,6 +727,13 @@
catch { return {}; }
},
fmtMB(mb) {
if (mb === undefined || mb === null) return '—';
if (mb >= 1024) return (mb / 1024).toFixed(1) + ' GB';
if (mb >= 1) return mb.toFixed(0) + ' MB';
return (mb * 1024).toFixed(0) + ' KB';
},
copiar(texto) {
navigator.clipboard.writeText(texto).catch(() => {});
},