import { useEffect, useState } from "preact/hooks"; import { t } from "../../i18n"; import { api, apiErrorText } from "../../features/customize/api"; import { custTab } from "../../features/customize/actions"; import { asList, asString, hint } from "../../features/customize/host"; import { MEMORY_BLOCKS, memScopeLabel, memScopes } from "../../features/customize/memory"; import { useAlive } from "./use-timer-lease"; import { markCustomizeFailed, markCustomizeLoaded } from "../../features/customize/load"; import { Empty, Hdr, IconGhost, Pill, Subhead, Toggle } from "./ui"; export function MemoryTab() { const alive = useAlive(); const [err, setErr] = useState(null); const [enabled, setEnabled] = useState(false); const [memories, setMemories] = useState[]>([]); const [cats, setCats] = useState[]>([]); const [ctx, setCtx] = useState | null>(null); const scopes = memScopes(); const active = scopes[scopes.length - 1]?.id || "global"; const [block, setBlock] = useState("user"); const [scope, setScope] = useState(active); const [content, setContent] = useState(""); useEffect(() => { void (async () => { try { const m = await api("/memory/enabled"); const mem = await api("/memory?project_id=all").catch(() => ({ memories: [] })); const cat = await api("/memory/categories?project_id=all").catch(() => ({ categories: [], })); const context = await api( `/memory/context?project_id=${encodeURIComponent(active)}`, ).catch(() => null); if (!alive()) return; setEnabled(!!m.enabled); setMemories(asList(mem.memories) as Record[]); setCats(asList(cat.categories) as Record[]); setCtx(context); setScope(active); markCustomizeLoaded(); } catch (e) { if (!alive()) return; const message = t("versions.load.err", (e as Error).message); setErr(message); markCustomizeFailed(message); } })(); }, [alive, active]); if (err) return
{err}
; const groups: Record[]> = {}; memories.forEach((x) => { const b = asString(x.block, "general"); (groups[b] = groups[b] || []).push(x); }); return (
{t("cust.memory.enableName")}
{enabled ? t("cust.memory.enabledDesc") : t("cust.memory.disabledDesc")}
{ const on = !enabled; setEnabled(on); try { await api("/memory/enabled", { method: "PUT", body: JSON.stringify({ enabled: on }), }); hint(on ? t("toast.memory.enabled") : t("toast.memory.disabled")); } catch { setEnabled(!on); } }} />
{t("cust.memory.addName")}
setContent((e.target as HTMLInputElement).value)} />
{ctx ? (
{t("cust.memory.injectedInto", memScopeLabel(active))}
{t( "cust.memory.injectedCounts", String(ctx.included_count || 0), String(asList(ctx.omitted).length), String(ctx.inherited_count || 0), String(ctx.overridden_count || 0), )}
) : null} {cats.length ? (
{t("cust.memory.categories")}
{cats.map((k, i) => ( {asString(k.block, "general") + " ยท " + String(k.count)} ))}
) : null} {Object.keys(groups) .sort() .map((b) => (
{b} {(groups[b] || []).map((x) => (
{asString(x.content)}
{memScopeLabel(asString(x.project_id))} {x.updated_at ? {t("cust.memory.edited")} : null}
{ const next = window.prompt(t("cust.memory.editPrompt"), asString(x.content)); if (next === null) return; const value = String(next).trim(); if (!value || value === asString(x.content)) return; try { await api( `/memory/${x.memory_id}?project_id=${encodeURIComponent(asString(x.project_id, "global"))}`, { method: "PATCH", body: JSON.stringify({ content: value }) }, ); custTab("memory"); } catch (e) { hint(apiErrorText(e), true); } }} /> { try { await api( `/memory/${x.memory_id}?project_id=${encodeURIComponent(asString(x.project_id, "global"))}`, { method: "DELETE" }, ); custTab("memory"); } catch (e) { hint(apiErrorText(e), true); } }} />
))}
))} {!memories.length ? {t("cust.memory.empty")} : null}
); }