"use client"; import { useState } from "react"; import SamShell from "@/components/SamShell"; import { refreshModules, useModules, useMe } from "@/lib/store" import { assignColorsForModules, displayName, envOf, getModuleMeta, isValidHexColor, itMenu, } from "@/lib/sam"; // Actualizar: redeploy manual + reinstalación de webhook por módulo. export default function Actualizar() { const { data, error } = useModules(); const me = useMe(); const modules = data?.modules ?? []; const [busy, setBusy] = useState(null); const [msg, setMsg] = useState<{ ok: boolean; text: string } | null>(null); const toggleVisible = async (name: string, current: boolean) => { setBusy(`visible:${name}`); try { const res = await fetch(`/api/deployer/modules/${name}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ visible: !current }), cache: "no-store", }); if (!res.ok) throw new Error(`HTTP ${res.status}`); refreshModules(); } catch (e) { setMsg({ ok: false, text: e instanceof Error ? e.message : "Error" }); } finally { setBusy(null); } }; const call = async (name: string, action: "deploy" | "webhook") => { setBusy(`${action}:${name}`); setMsg(null); try { const res = await fetch( action === "deploy" ? `/api/deployer/modules/${name}/deploy` : `/api/deployer/modules/${name}/webhook`, { method: "POST", cache: "no-store" } ); const j = await res.json(); if (!res.ok) throw new Error(j.error || `HTTP ${res.status}`); setMsg({ ok: true, text: action === "deploy" ? `"${name}" actualizado (sha ${(j.sha || "").slice(0, 7)})` : `"${name}": webhook ${j.created ? `creado #${j.created}` : j.updated ? `actualizado #${j.updated}` : "ok"}`, }); refreshModules(); } catch (e) { setMsg({ ok: false, text: e instanceof Error ? e.message : "Error", }); } finally { setBusy(null); } }; // Rellena el color de los módulos ya importados que aún no lo tienen // guardado: lo genera de forma autoritaria y lo persiste en el deployer. const missingColor = modules.filter((m) => !isValidHexColor(m.color)); const backfillColors = async () => { if (missingColor.length === 0) return; setBusy("color:backfill"); setMsg(null); try { const assigned = assignColorsForModules(modules); let ok = 0; const failed: string[] = []; for (const m of missingColor) { try { const res = await fetch( `/api/deployer/modules/${encodeURIComponent(m.name)}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ color: assigned[m.name] }), cache: "no-store", } ); if (!res.ok) throw new Error(`HTTP ${res.status}`); ok++; } catch { failed.push(m.name); } } refreshModules(); setMsg({ ok: failed.length === 0, text: failed.length === 0 ? `Colores generados y guardados en ${ok} módulo${ok !== 1 ? "s" : ""}.` : `Guardados ${ok}, fallaron: ${failed.join(", ")}.`, }); } finally { setBusy(null); } }; return (
Actualizar módulos
{error &&
{error}
} {msg && (
{msg.text}
)}
{missingColor.length > 0 && (
Hay {missingColor.length} módulo{missingColor.length !== 1 ? "s" : ""} sin color guardado ({missingColor.map((m) => m.name).join(", ")}).
)}
{modules.map((m) => { const env = envOf(m.branch); return ( ); })} {modules.length === 0 && ( )}
Módulo Rama Último deploy Acciones
{displayName(m.name)}{" "} {env.label} {" "} {m.kind === "backend" && ( backend )}{" "} {m.visible === false && ( oculto )}
{m.lastDeploy ? `${(m.lastDeploy.sha || "").slice(0, 7)} · ${m.lastDeploy.ok ? "ok" : "falló"}` : "sin deploys"}
{m.branch} {m.lastDeploy?.time ? new Date(m.lastDeploy.time).toLocaleString("es-CL") : "—"}
No hay módulos integrados.
); }