feat: Agregar controles de Iniciar/Detener/Reiniciar en panel web
Cambios en el frontend (index.html):
- Cambiar header "Actions" a "Acciones"
- Agregar botones de control según estado de la app:
* Si está Running: botones Detener (rojo) y Reiniciar (amarillo)
* Si está Stopped: botón Iniciar (verde)
* Siempre: botón Ver logs (azul)
- Agregar función controlApp() para llamar a la API
- Diálogo de confirmación antes de ejecutar acciones
- Recarga automática de la tabla después de ejecutar acción
Cambios en el backend (lifecycle.rs):
- Corregir formato de service_name en start_app()
- Corregir formato de service_name en stop_app()
- Corregir formato de service_name en restart_app()
- Ahora usa: siax-app-{app_name}.service en lugar de {app_name}.service
Los botones ahora funcionan correctamente con los servicios systemd
This commit is contained in:
@@ -26,7 +26,7 @@ impl LifecycleManager {
|
||||
|
||||
logger.info("Lifecycle", &format!("Iniciando aplicación: {}", app_name));
|
||||
|
||||
let service_name = format!("{}.service", app_name);
|
||||
let service_name = format!("siax-app-{}.service", app_name);
|
||||
SystemCtl::start(&service_name)?;
|
||||
|
||||
// Actualizar rate limiter
|
||||
@@ -45,7 +45,7 @@ impl LifecycleManager {
|
||||
|
||||
logger.info("Lifecycle", &format!("Deteniendo aplicación: {}", app_name));
|
||||
|
||||
let service_name = format!("{}.service", app_name);
|
||||
let service_name = format!("siax-app-{}.service", app_name);
|
||||
SystemCtl::stop(&service_name)?;
|
||||
|
||||
// Actualizar rate limiter
|
||||
@@ -64,7 +64,7 @@ impl LifecycleManager {
|
||||
|
||||
logger.info("Lifecycle", &format!("Reiniciando aplicación: {}", app_name));
|
||||
|
||||
let service_name = format!("{}.service", app_name);
|
||||
let service_name = format!("siax-app-{}.service", app_name);
|
||||
SystemCtl::restart(&service_name)?;
|
||||
|
||||
// Actualizar rate limiter
|
||||
|
||||
@@ -364,7 +364,7 @@
|
||||
<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
|
||||
Acciones
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -557,9 +557,35 @@
|
||||
<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>
|
||||
<div class="flex items-center justify-end gap-2">
|
||||
${
|
||||
app.status === "Running"
|
||||
? `
|
||||
<button class="text-red-400 hover:text-red-300 transition-colors p-1.5 rounded hover:bg-red-900/20"
|
||||
onclick="controlApp('${app.name}', 'stop')"
|
||||
title="Detener">
|
||||
<span class="material-symbols-outlined text-[20px]">stop</span>
|
||||
</button>
|
||||
<button class="text-yellow-400 hover:text-yellow-300 transition-colors p-1.5 rounded hover:bg-yellow-900/20"
|
||||
onclick="controlApp('${app.name}', 'restart')"
|
||||
title="Reiniciar">
|
||||
<span class="material-symbols-outlined text-[20px]">refresh</span>
|
||||
</button>
|
||||
`
|
||||
: `
|
||||
<button class="text-green-400 hover:text-green-300 transition-colors p-1.5 rounded hover:bg-green-900/20"
|
||||
onclick="controlApp('${app.name}', 'start')"
|
||||
title="Iniciar">
|
||||
<span class="material-symbols-outlined text-[20px]">play_arrow</span>
|
||||
</button>
|
||||
`
|
||||
}
|
||||
<button class="text-blue-400 hover:text-blue-300 transition-colors p-1.5 rounded hover:bg-blue-900/20"
|
||||
onclick="window.location.href='/logs'"
|
||||
title="Ver logs">
|
||||
<span class="material-symbols-outlined text-[20px]">visibility</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
@@ -579,6 +605,44 @@
|
||||
`;
|
||||
}
|
||||
|
||||
async function controlApp(appName, action) {
|
||||
const actionNames = {
|
||||
start: "Iniciar",
|
||||
stop: "Detener",
|
||||
restart: "Reiniciar",
|
||||
};
|
||||
|
||||
const confirmed = confirm(
|
||||
`¿Estás seguro de ${actionNames[action]} la aplicación "${appName}"?`,
|
||||
);
|
||||
if (!confirmed) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/apps/${appName}/${action}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
alert(`✅ ${result.data.message}`);
|
||||
// Recargar la lista de apps
|
||||
loadApps();
|
||||
} else {
|
||||
alert(`❌ Error: ${result.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
alert("❌ Error al ejecutar la acción");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleMenu() {
|
||||
const menu = document.getElementById("mobile-menu");
|
||||
menu.classList.toggle("hidden");
|
||||
|
||||
Reference in New Issue
Block a user