import { useEffect } from "preact/hooks"; import { t } from "../../i18n"; import { closeCust, custTab } from "../../features/customize/actions"; import { CUST_LOAD_TIMEOUT_MS, markCustomizeTimedOut, } from "../../features/customize/load"; import { customizeGeneration, customizeLoad, customizeOpen, customizeTab, nestedEditor, } from "../../features/customize/state"; import { CUST_TABS, CUST_TAB_I18N, type CustTab } from "../../features/customize/tabs"; import { Icon } from "./icons"; import { GeneralTab } from "./GeneralTab"; import { SkillsTab } from "./SkillsTab"; import { SpecialistsTab } from "./SpecialistsTab"; import { ConnectorsTab } from "./ConnectorsTab"; import { ComputeTab } from "./ComputeTab"; import { PermissionsTab } from "./PermissionsTab"; import { NetworkTab } from "./NetworkTab"; import { MemoryTab } from "./MemoryTab"; import { ModelsTab } from "./ModelsTab"; import { NestedEditor } from "./NestedEditor"; import "./customize.css"; function ActiveTab() { switch (customizeTab.value) { case "general": return ; case "skills": return ; case "specialists": return ; case "connectors": return ; case "compute": return ; case "permissions": return ; case "network": return ; case "memory": return ; case "models": return ; } } /** * The bounded-load annotation above the tab body. "Loading…" while the tab's * first fetch is pending; after CUST_LOAD_TIMEOUT_MS with no answer, or when * the fetch failed, a Retry that reloads the tab (a new generation). The tab * body stays mounted underneath: a control the user is already using is * annotated, never discarded. */ function LoadStatus({ tab, generation }: { tab: CustTab; generation: number }) { const load = customizeLoad.value; useEffect(() => { const timer = setTimeout(() => markCustomizeTimedOut(generation), CUST_LOAD_TIMEOUT_MS); return () => clearTimeout(timer); }, [generation]); if (load.generation !== generation || load.state === "ready") return null; if (load.state === "loading") { return (
{t("common.loading")}
); } return ( ); } export function Customize() { const open = customizeOpen.value; const tab = customizeTab.value; const gen = customizeGeneration.value; const loading = customizeLoad.value.generation === gen && customizeLoad.value.state === "loading"; useEffect(() => { const onKey = (e: KeyboardEvent) => { if (e.key !== "Escape") return; if (!customizeOpen.value) return; if (nestedEditor.value) { nestedEditor.value = null; e.preventDefault(); return; } e.preventDefault(); closeCust(); }; document.addEventListener("keydown", onKey); return () => document.removeEventListener("keydown", onKey); }, []); return ( ); }