feat: Implementación completa Fase 4 - Sistema de monitoreo con API REST y WebSocket
✨ Nuevas funcionalidades: - API REST unificada en puerto 8080 (eliminado CORS) - WebSocket para logs en tiempo real desde journalctl - Integración completa con systemd para gestión de servicios - Escaneo automático de procesos Node.js y Python - Rate limiting (1 operación/segundo por app) - Interface web moderna con Tailwind CSS (tema oscuro) - Documentación API estilo Swagger completamente en español 🎨 Interface Web (todas las páginas en español): - Dashboard con estadísticas en tiempo real - Visor de escaneo de procesos con filtros - Formulario de registro de aplicaciones con variables de entorno - Visor de logs en tiempo real con WebSocket y sidebar - Página de selección de apps detectadas - Documentación completa de API REST 🏗️ Arquitectura: - Módulo models: ServiceConfig, ManagedApp, AppStatus - Módulo systemd: wrapper de systemctl, generador de .service, parser - Módulo orchestrator: AppManager, LifecycleManager con validaciones - Módulo api: handlers REST, WebSocket manager, DTOs - Servidor unificado en puerto 8080 (Web + API + WS) 🔧 Mejoras técnicas: - Eliminación de CORS mediante servidor unificado - Separación clara frontend/backend con carga dinámica - Thread-safe con Arc<DashMap> para estado compartido - Reconciliación de estados: sysinfo vs systemd - Validaciones de paths, usuarios y configuraciones - Manejo robusto de errores con thiserror 📝 Documentación: - README.md actualizado con arquitectura completa - EJEMPLOS.md con casos de uso detallados - ESTADO_PROYECTO.md con progreso de Fase 4 - API docs interactiva en /api-docs - Script de despliegue mejorado con health checks 🚀 Producción: - Deployment script con validaciones - Health checks y rollback capability - Configuración de sudoers para systemctl - Hardening de seguridad en servicios systemd
This commit is contained in:
295
web/success.html
295
web/success.html
@@ -1,58 +1,241 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="refresh" content="3;url=/select">
|
||||
<title>Proceso Agregado - SIAX</title>
|
||||
<style>
|
||||
body {
|
||||
background: #0f172a;
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
.success {
|
||||
background: #064e3b;
|
||||
border: 2px solid #22c55e;
|
||||
padding: 40px;
|
||||
border-radius: 16px;
|
||||
max-width: 500px;
|
||||
margin: 100px auto;
|
||||
}
|
||||
h1 {
|
||||
color: #22c55e;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.details {
|
||||
background: #0f172a;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-top: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
.label {
|
||||
color: #60a5fa;
|
||||
font-weight: bold;
|
||||
}
|
||||
.redirect-msg {
|
||||
color: #94a3b8;
|
||||
margin-top: 30px;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="success">
|
||||
<h1>✅ Proceso Agregado Exitosamente</h1>
|
||||
<p style="color:#94a3b8;">El proceso será monitoreado en el próximo ciclo</p>
|
||||
<!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>Éxito - SIAX Monitor</title>
|
||||
<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&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>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#101922",
|
||||
},
|
||||
fontFamily: { display: ["Inter", "sans-serif"] },
|
||||
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 font-display text-white min-h-screen flex flex-col"
|
||||
>
|
||||
<!-- Sticky Top Navigation -->
|
||||
<header
|
||||
class="sticky top-0 z-50 w-full border-b border-solid border-[#283039] bg-background-dark/80 backdrop-blur-md px-4 md:px-10 py-3"
|
||||
>
|
||||
<div
|
||||
class="max-w-[1200px] mx-auto flex items-center justify-between whitespace-nowrap"
|
||||
>
|
||||
<div class="flex items-center gap-8">
|
||||
<div class="flex items-center gap-4 text-white">
|
||||
<div
|
||||
class="size-8 bg-primary rounded-lg flex items-center justify-center"
|
||||
>
|
||||
<span class="material-symbols-outlined text-white"
|
||||
>monitoring</span
|
||||
>
|
||||
</div>
|
||||
<h2
|
||||
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
||||
>
|
||||
SIAX Monitor
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-1 justify-end gap-6 items-center">
|
||||
<nav class="hidden md:flex items-center gap-6">
|
||||
<a
|
||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||
href="/"
|
||||
>
|
||||
Panel
|
||||
</a>
|
||||
<a
|
||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||
href="/scan"
|
||||
>
|
||||
Escanear
|
||||
</a>
|
||||
<a
|
||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||
href="/select"
|
||||
>
|
||||
Agregar Detectada
|
||||
</a>
|
||||
<a
|
||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||
href="/register"
|
||||
>
|
||||
Nueva App
|
||||
</a>
|
||||
<a
|
||||
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
||||
href="/logs"
|
||||
>
|
||||
Registros
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="details">
|
||||
<p><span class="label">Aplicación:</span> {{APP_NAME}}</p>
|
||||
<p><span class="label">Puerto:</span> {{PORT}}</p>
|
||||
</div>
|
||||
<main class="flex-1 flex items-center justify-center px-4 py-16">
|
||||
<div class="max-w-2xl w-full">
|
||||
<!-- Success Card -->
|
||||
<div
|
||||
class="rounded-xl border border-green-500/30 bg-green-500/10 p-8 text-center space-y-6"
|
||||
>
|
||||
<!-- Success Icon -->
|
||||
<div class="flex justify-center">
|
||||
<div
|
||||
class="flex items-center justify-center w-24 h-24 rounded-full bg-green-500/20 border-4 border-green-500/30"
|
||||
>
|
||||
<span
|
||||
class="material-symbols-outlined text-green-400"
|
||||
style="font-size: 60px"
|
||||
>check_circle</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="redirect-msg">Redirigiendo en 3 segundos...</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<!-- Success Message -->
|
||||
<div class="space-y-2">
|
||||
<h1
|
||||
class="text-white text-3xl font-black leading-tight tracking-[-0.033em]"
|
||||
>
|
||||
Operation Successful!
|
||||
</h1>
|
||||
<p class="text-green-400 text-lg font-medium">
|
||||
The process has been added to monitoring
|
||||
successfully
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Application Info -->
|
||||
<div
|
||||
class="rounded-xl border border-[#283039] bg-[#161f2a] p-6 space-y-4"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-[#9dabb9] text-sm font-medium"
|
||||
>Nombre de Aplicación</span
|
||||
>
|
||||
<span class="text-white text-sm font-bold"
|
||||
>{{APP_NAME}}</span
|
||||
>
|
||||
</div>
|
||||
<div class="border-t border-[#283039]"></div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-[#9dabb9] text-sm font-medium"
|
||||
>Puerto</span
|
||||
>
|
||||
<span class="text-white text-sm font-bold"
|
||||
>{{PORT}}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Info Message -->
|
||||
<div
|
||||
class="rounded-xl border border-primary/30 bg-primary/10 p-4"
|
||||
>
|
||||
<div class="flex items-start gap-3">
|
||||
<span
|
||||
class="material-symbols-outlined text-primary mt-0.5"
|
||||
>info</span
|
||||
>
|
||||
<p class="text-[#9dabb9] text-sm text-left">
|
||||
The monitor will start reporting metrics in the
|
||||
next cycle (60 segundos...You can view the
|
||||
application status on the dashboard.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div
|
||||
class="flex flex-col sm:flex-row gap-3 justify-center pt-4"
|
||||
>
|
||||
<a
|
||||
href="/"
|
||||
class="flex items-center justify-center rounded-lg h-12 px-6 bg-primary hover:brightness-110 text-white text-sm font-bold transition-all gap-2"
|
||||
>
|
||||
<span class="material-symbols-outlined text-[18px]"
|
||||
>home</span
|
||||
>
|
||||
<span>Ir al Panel</span>
|
||||
</a>
|
||||
<a
|
||||
href="/select"
|
||||
class="flex items-center justify-center rounded-lg h-12 px-6 bg-[#1c2730] hover:bg-[#283039] border border-[#283039] text-white text-sm font-bold transition-colors gap-2"
|
||||
>
|
||||
<span class="material-symbols-outlined text-[18px]"
|
||||
>add_circle</span
|
||||
>
|
||||
<span>Agregar Otra</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Auto-redirect countdown -->
|
||||
<div class="mt-6 text-center">
|
||||
<p class="text-[#9dabb9] text-sm">
|
||||
Redirigiendo al panel en
|
||||
<span id="countdown" class="text-white font-bold"
|
||||
>5</span
|
||||
>
|
||||
segundos...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
// Auto-redirect countdown
|
||||
let segundos...5;
|
||||
const countdownElement = document.getElementById("countdown");
|
||||
|
||||
const interval = setInterval(() => {
|
||||
segundos...
|
||||
if (countdownElement) {
|
||||
countdownElement.textContent = seconds;
|
||||
}
|
||||
|
||||
if (segundos... 0) {
|
||||
clearInterval(interval);
|
||||
window.location.href = "/";
|
||||
}
|
||||
}, 1000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user