Files
SIAX-MONITOR/web/index.html
pablinux 87ce154789 fix: Corregir renderizado de apps en index.html
Problema:
- La tabla mostraba [object Object] en lugar del nombre de la app
- El estado siempre aparecía como Unknown
- No usaba las propiedades del objeto JSON (name, status, port, service_name)

Solución:
- Actualizar displayApps() para acceder a app.name, app.status, app.service_name
- Agregar badges de colores según estado:
  * Running: verde
  * Stopped: gris
  * Failed: rojo
  * Starting: azul
  * Stopping: amarillo
  * Unknown: gris
- Cambiar botón de more_vert a visibility para ver logs
- Mostrar service_name debajo del nombre de la app

Ahora la tabla muestra correctamente la información de las apps detectadas
2026-01-18 03:49:53 -05:00

591 lines
28 KiB
HTML

<!doctype html>
<html class="dark" lang="es" dir="ltr">
<head>
<meta charset="utf-8" />
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
<title>Panel de Monitoreo</title>
<link rel="icon" type="image/svg+xml" href="/static/icon/favicon.svg" />
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap"
rel="stylesheet"
/>
<script id="tailwind-config">
tailwind.config = {
darkMode: "class",
theme: {
extend: {
colors: {
primary: "#137fec",
"background-light": "#f6f7f8",
"background-dark": "#101922",
},
fontFamily: {
display: ["Inter"],
},
borderRadius: {
DEFAULT: "0.25rem",
lg: "0.5rem",
xl: "0.75rem",
full: "9999px",
},
},
},
};
</script>
<style>
body {
font-family: "Inter", sans-serif;
}
.material-symbols-outlined {
font-variation-settings:
"FILL" 0,
"wght" 400,
"GRAD" 0,
"opsz" 24;
}
</style>
</head>
<body
class="bg-background-light dark:bg-background-dark text-slate-900 dark:text-slate-100 min-h-screen"
>
<div class="flex h-full grow flex-col">
<!-- Sticky Top Navigation -->
<header class="border-b border-[#283039] bg-[#0a0f16]">
<div class="container mx-auto px-4 py-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div
class="rounded-full size-9 border-2 border-slate-700 overflow-hidden"
>
<img
src="/static/icon/logo.png"
alt="Logo"
class="w-full h-full object-cover"
/>
</div>
<div>
<h1 class="text-xl font-bold">SIAX Monitor</h1>
<p class="text-xs text-slate-400">Dashboard</p>
</div>
</div>
<!-- Desktop Navigation -->
<nav class="hidden md:flex items-center gap-2">
<a
href="/health"
class="px-4 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-2"
>
<span class="material-symbols-outlined text-lg"
>monitor_heart</span
>
<span>Health</span>
</a>
<a
href="/scan"
class="px-4 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-2"
>
<span class="material-symbols-outlined text-lg"
>search</span
>
<span>Escanear</span>
</a>
<a
href="/logs"
class="px-4 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-2"
>
<span class="material-symbols-outlined text-lg"
>article</span
>
<span>Logs</span>
</a>
<a
href="/register"
class="px-4 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-2"
>
<span class="material-symbols-outlined text-lg"
>app_registration</span
>
<span>Registrar</span>
</a>
</nav>
<!-- Mobile Menu Button -->
<button
onclick="toggleMenu()"
class="md:hidden px-3 py-2 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors"
>
<span class="material-symbols-outlined text-2xl"
>menu</span
>
</button>
</div>
<!-- Mobile Menu Dropdown -->
<div
id="mobile-menu"
class="hidden md:hidden mt-4 pb-4 space-y-2"
>
<a
href="/health"
class="block px-4 py-3 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-3"
>
<span class="material-symbols-outlined"
>monitor_heart</span
>
<span>Health</span>
</a>
<a
href="/scan"
class="block px-4 py-3 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-3"
>
<span class="material-symbols-outlined"
>search</span
>
<span>Escanear</span>
</a>
<a
href="/logs"
class="block px-4 py-3 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-3"
>
<span class="material-symbols-outlined"
>article</span
>
<span>Logs</span>
</a>
<a
href="/register"
class="block px-4 py-3 rounded-lg text-slate-300 hover:bg-[#161f2a] transition-colors flex items-center gap-3"
>
<span class="material-symbols-outlined"
>app_registration</span
>
<span>Registrar</span>
</a>
</div>
</div>
</header>
<main class="max-w-[1200px] mx-auto w-full px-4 lg:px-10 py-8">
<!-- Page Heading -->
<div
class="flex flex-wrap items-center justify-between gap-4 mb-8"
>
<div>
<h1
class="text-slate-900 dark:text-white text-3xl font-black tracking-tight"
>
Panel de Control
</h1>
<p class="text-slate-500 text-sm mt-1">
Monitoreo de salud del sistema y procesos en tiempo
real - Server: {{SERVER_NAME}}
</p>
</div>
<div class="flex gap-3">
<button
class="flex items-center gap-2 rounded-lg h-10 px-4 bg-slate-200 dark:bg-slate-800 text-slate-700 dark:text-white text-sm font-bold transition-colors hover:bg-slate-700"
onclick="window.location.href = '/scan'"
>
<span class="material-symbols-outlined text-lg"
>refresh</span
>
<span>Escanear Sistema</span>
</button>
<button
class="flex items-center gap-2 rounded-lg h-10 px-4 bg-primary text-white text-sm font-bold transition-opacity hover:opacity-90 lg:hidden"
onclick="window.location.href = '/register'"
>
<span class="material-symbols-outlined text-lg"
>add</span
>
<span>Registrar</span>
</button>
</div>
</div>
<!-- Stats Row -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-10">
<div
class="bg-white dark:bg-slate-800/50 rounded-xl p-6 border border-slate-200 dark:border-slate-800"
>
<div class="flex items-center justify-between mb-2">
<p
class="text-slate-500 dark:text-slate-400 text-sm font-medium"
>
Uso CPU
</p>
<span class="material-symbols-outlined text-primary"
>speed</span
>
</div>
<div class="flex items-end gap-2">
<p
class="text-slate-900 dark:text-white text-3xl font-bold"
>
24.8%
</p>
<p
class="text-red-500 text-sm font-semibold mb-1 flex items-center"
>
<span class="material-symbols-outlined text-sm"
>trending_up</span
>+2.4%
</p>
</div>
<div
class="mt-4 w-full bg-slate-200 dark:bg-slate-700 rounded-full h-1.5"
>
<div
class="bg-primary h-1.5 rounded-full"
style="width: 24.8%"
></div>
</div>
</div>
<div
class="bg-white dark:bg-slate-800/50 rounded-xl p-6 border border-slate-200 dark:border-slate-800"
>
<div class="flex items-center justify-between mb-2">
<p
class="text-slate-500 dark:text-slate-400 text-sm font-medium"
>
Consumo de Memoria
</p>
<span class="material-symbols-outlined text-primary"
>memory</span
>
</div>
<div class="flex items-end gap-2">
<p
class="text-slate-900 dark:text-white text-3xl font-bold"
>
12.4 GB
</p>
<p
class="text-emerald-500 text-sm font-semibold mb-1 flex items-center"
>
<span class="material-symbols-outlined text-sm"
>trending_down</span
>-0.5%
</p>
</div>
<p class="text-slate-500 text-xs mt-1">
of 32 GB Total RAM
</p>
</div>
<div
class="bg-white dark:bg-slate-800/50 rounded-xl p-6 border border-slate-200 dark:border-slate-800"
>
<div class="flex items-center justify-between mb-2">
<p
class="text-slate-500 dark:text-slate-400 text-sm font-medium"
>
Procesos Activos
</p>
<span class="material-symbols-outlined text-primary"
>apps</span
>
</div>
<div class="flex items-end gap-2">
<p
class="text-slate-900 dark:text-white text-3xl font-bold"
id="app-count"
>
0
</p>
<p
class="text-emerald-500 text-sm font-semibold mb-1 flex items-center"
>
<span class="material-symbols-outlined text-sm"
>add</span
>monitored
</p>
</div>
<div class="flex gap-1 mt-4">
<span
class="size-2 rounded-full bg-emerald-500"
></span>
<span
class="size-2 rounded-full bg-emerald-500"
></span>
<span
class="size-2 rounded-full bg-emerald-500"
></span>
<span
class="size-2 rounded-full bg-amber-500"
></span>
<span
class="size-2 rounded-full bg-emerald-500"
></span>
</div>
</div>
</div>
<!-- Aplicaciones Recientes Section -->
<div
class="bg-white dark:bg-slate-800/30 rounded-xl border border-slate-200 dark:border-slate-800 overflow-hidden"
>
<div
class="p-6 border-b border-slate-200 dark:border-slate-800 flex flex-col sm:flex-row sm:items-center justify-between gap-4"
>
<h2
class="text-slate-900 dark:text-white text-xl font-bold"
>
Aplicaciones Recientes
</h2>
<div class="flex items-center gap-2">
<div class="relative flex-1 sm:w-64">
<span
class="absolute inset-y-0 left-0 flex items-center pl-3 text-slate-500"
>
<span
class="material-symbols-outlined text-sm"
>filter_list</span
>
</span>
<input
class="form-input w-full rounded-lg border border-slate-200 dark:border-slate-700 bg-transparent text-sm py-1.5 pl-10 pr-4 placeholder:text-slate-500 focus:ring-1 focus:ring-primary"
placeholder="Filtrar por estado o nombre..."
type="text"
/>
</div>
</div>
</div>
<div class="overflow-x-auto" id="apps-table-container">
<table class="w-full text-left border-collapse">
<thead>
<tr
class="bg-slate-50 dark:bg-slate-800/50 text-slate-500 dark:text-slate-400 text-xs font-semibold uppercase tracking-wider"
>
<th class="px-6 py-4">Nombre de App</th>
<th class="px-6 py-4">Estado</th>
<th class="px-6 py-4">CPU %</th>
<th class="px-6 py-4">Mem %</th>
<th class="px-6 py-4">Tiempo Activo</th>
<th class="px-6 py-4 text-right">
Actions
</th>
</tr>
</thead>
<tbody
class="divide-y divide-slate-200 dark:divide-slate-800"
id="apps-tbody"
>
<tr>
<td
colspan="6"
class="px-6 py-8 text-center text-slate-500"
>
<span
class="material-symbols-outlined text-4xl mb-2"
>hourglass_empty</span
>
<p>Cargando aplicaciones...</p>
</td>
</tr>
</tbody>
</table>
</div>
<div
class="p-4 bg-slate-50 dark:bg-slate-800/50 border-t border-slate-200 dark:border-slate-800 text-center"
>
<a
class="text-primary text-sm font-bold hover:underline cursor-pointer"
onclick="window.location.href = '/scan'"
>Ver Todas las Aplicaciones</a
>
</div>
</div>
<!-- Quick Action Links -->
<div class="mt-10 grid grid-cols-1 md:grid-cols-2 gap-6">
<div
class="flex items-start gap-4 p-5 rounded-xl border-2 border-dashed border-slate-200 dark:border-slate-800 bg-transparent hover:border-primary/50 transition-colors cursor-pointer group"
onclick="window.location.href = '/register'"
>
<div
class="size-12 rounded-full bg-primary/10 flex items-center justify-center text-primary group-hover:bg-primary group-hover:text-white transition-all"
>
<span class="material-symbols-outlined"
>add_to_queue</span
>
</div>
<div>
<h3
class="text-slate-900 dark:text-white font-bold text-lg leading-tight"
>
Register New Service
</h3>
<p class="text-slate-500 text-sm">
Manually add a binary or process to the
monitoring queue.
</p>
</div>
</div>
<div
class="flex items-start gap-4 p-5 rounded-xl border-2 border-dashed border-slate-200 dark:border-slate-800 bg-transparent hover:border-primary/50 transition-colors cursor-pointer group"
onclick="window.location.href = '/logs'"
>
<div
class="size-12 rounded-full bg-primary/10 flex items-center justify-center text-primary group-hover:bg-primary group-hover:text-white transition-all"
>
<span class="material-symbols-outlined"
>history</span
>
</div>
<div>
<h3
class="text-slate-900 dark:text-white font-bold text-lg leading-tight"
>
View Event Logs
</h3>
<p class="text-slate-500 text-sm">
Review detailed historical data and error
reports from across your stack.
</p>
</div>
</div>
</div>
</main>
<footer
class="mt-auto border-t border-slate-200 dark:border-slate-800 py-6"
>
<div
class="max-w-[1200px] mx-auto px-4 lg:px-10 flex flex-col sm:flex-row justify-between items-center gap-4 text-slate-500 text-xs font-medium"
>
<p>
© 2024 SIAX Monitor Inc. Todos los procesos del sistema
rastreados.
</p>
<div class="flex gap-6">
<a class="hover:text-primary" href="#"
>Términos de Servicio</a
>
<a class="hover:text-primary" href="#"
>Política de Privacidad</a
>
<a class="hover:text-primary" href="/api-docs"
>Documentación de API</a
>
</div>
</div>
</footer>
</div>
<script>
async function loadApps() {
try {
const response = await fetch("/api/apps");
const result = await response.json();
if (result.success && result.data && result.data.apps) {
document.getElementById("app-count").textContent =
result.data.total || 0;
if (result.data.apps && result.data.apps.length > 0) {
displayApps(result.data.apps);
} else {
displayEmpty();
}
}
} catch (error) {
console.error("Error:", error);
displayEmpty();
}
}
function displayApps(apps) {
const tbody = document.getElementById("apps-tbody");
tbody.innerHTML = apps
.map((app) => {
// Determinar color del badge según estado
const statusColors = {
Running: {
bg: "bg-green-100 dark:bg-green-900/30",
text: "text-green-700 dark:text-green-400",
dot: "bg-green-500",
},
Stopped: {
bg: "bg-gray-100 dark:bg-gray-800",
text: "text-gray-700 dark:text-gray-400",
dot: "bg-gray-400",
},
Failed: {
bg: "bg-red-100 dark:bg-red-900/30",
text: "text-red-700 dark:text-red-400",
dot: "bg-red-500",
},
Starting: {
bg: "bg-blue-100 dark:bg-blue-900/30",
text: "text-blue-700 dark:text-blue-400",
dot: "bg-blue-500",
},
Stopping: {
bg: "bg-yellow-100 dark:bg-yellow-900/30",
text: "text-yellow-700 dark:text-yellow-400",
dot: "bg-yellow-500",
},
Unknown: {
bg: "bg-slate-100 dark:bg-slate-800",
text: "text-slate-700 dark:text-slate-400",
dot: "bg-slate-400",
},
};
const statusStyle =
statusColors[app.status] || statusColors["Unknown"];
return `
<tr class="hover:bg-slate-50 dark:hover:bg-slate-800/40 transition-colors">
<td class="px-6 py-4">
<div class="flex items-center gap-3">
<div class="size-8 rounded bg-slate-100 dark:bg-slate-700 flex items-center justify-center">
<span class="material-symbols-outlined text-primary text-lg">terminal</span>
</div>
<div>
<p class="text-slate-900 dark:text-white font-semibold text-sm">${app.name}</p>
<p class="text-slate-500 text-xs">${app.service_name || "Servicio"}</p>
</div>
</div>
</td>
<td class="px-6 py-4">
<span class="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium ${statusStyle.bg} ${statusStyle.text}">
<span class="size-1.5 rounded-full ${statusStyle.dot}"></span>
${app.status}
</span>
</td>
<td class="px-6 py-4 text-sm">-</td>
<td class="px-6 py-4 text-sm">-</td>
<td class="px-6 py-4 text-sm text-slate-500">-</td>
<td class="px-6 py-4 text-right">
<button class="text-slate-400 hover:text-white transition-colors" onclick="window.location.href='/logs'">
<span class="material-symbols-outlined">visibility</span>
</button>
</td>
</tr>
`;
})
.join("");
}
function displayEmpty() {
const tbody = document.getElementById("apps-tbody");
tbody.innerHTML = `
<tr>
<td colspan="6" class="px-6 py-8 text-center text-slate-500">
<span class="material-symbols-outlined text-4xl mb-2">inbox</span>
<p>No hay aplicaciones registradas aún</p>
</td>
</tr>
`;
}
function toggleMenu() {
const menu = document.getElementById("mobile-menu");
menu.classList.toggle("hidden");
}
window.addEventListener("DOMContentLoaded", loadApps);
</script>
</body>
</html>