feat: tablero de gestion con graficas de estado y carga por aplicacion

This commit is contained in:
Nurfog committed 2026-09-08 16:56:11 -03:00
1 parent 646a3bf628
commit 3949224d94
5 files changed
+459 -56

No files matched your search

+8 -56
View File
@@ -1,7 +1,7 @@
"use client";
import { useSyncExternalStore } from "react";
import Link from "next/link";
import { useModules, refreshModules } from "@/lib/store";
import {
displayName,
envOf,
@@ -16,61 +16,10 @@ import {
type RefApp,
} from "@/lib/sam";
// Store externo: evita setState en efectos (regla react-hooks)
// y auto-refresca cada 15s. Los clics llaman a load() directo.
let cache: ApiResponse | null = null;
let loadError: string | null = null;
let started = false;
let snap: { data: ApiResponse | null; error: string | null } = {
data: null,
error: null,
};
const listeners = new Set<() => void>();
function notify() {
listeners.forEach((l) => l());
}
async function load() {
try {
const res = await fetch("/api/modules", { cache: "no-store" });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
cache = await res.json();
loadError = null;
} catch (e) {
loadError = e instanceof Error ? e.message : "Error al cargar módulos";
}
// Referencia estable: solo cambia si cambian los datos (evita loops)
if (snap.data !== cache || snap.error !== loadError) {
snap = { data: cache, error: loadError };
}
notify();
}
function subscribe(cb: () => void) {
if (!started) {
started = true;
load();
setInterval(load, 15000);
}
listeners.add(cb);
return () => {
listeners.delete(cb);
};
}
function snapshot(): { data: ApiResponse | null; error: string | null } {
return snap;
}
export default function Home() {
const { data, error } = useSyncExternalStore(
subscribe,
snapshot,
() => ({ data: null, error: null })
);
const { data, error } = useModules();
const loading = data === null && error === null;
const fetchModules = load;
const fetchModules = refreshModules;
const modules = data?.modules ?? [];
const backend = data?.backend;
@@ -190,8 +139,11 @@ export default function Home() {
<div className="col-12 text-center">
<h4 className="fw-semibold opacity-75">Aplicaciones</h4>
</div>
<div className="col-12 text-center mt-4">
<Link href="/upload" className="btn btn-light btn-sm px-4">
<div className="col-12 text-center mt-4 d-flex flex-column gap-2 align-items-center">
<Link href="/tablero" className="btn btn-light btn-sm px-4">
<i className="bx bx-pie-chart-alt-2 me-1" /> Tablero
</Link>
<Link href="/upload" className="btn btn-outline-light btn-sm px-4">
<i className="bx bx-plus me-1" /> Nuevo Módulo
</Link>
</div>