/* Eno.Health Console — app shell, login, routing */ const A = window.ENO; const LS = { get: (k, d) => { try { return JSON.parse(localStorage.getItem("eno_" + k)) ?? d; } catch { return d; } }, set: (k, v) => { try { localStorage.setItem("eno_" + k, JSON.stringify(v)); } catch {} }, }; const NAV = [ { group: "Operate", items: [ { key: "overview", label: "Overview", icon: "overview" }, { key: "documents", label: "Documents", icon: "documents" }, { key: "streams", label: "Streams", icon: "activity" }, { key: "runs", label: "Ingestion runs", icon: "runs" }, { key: "upload", label: "Upload", icon: "upload" }, ] }, { group: "Govern", items: [ { key: "policies", label: "Policies", icon: "policies" }, { key: "retention", label: "Retention & compliance", icon: "retention" }, { key: "webhooks", label: "Webhooks", icon: "webhooks" }, ] }, { group: "Reference", items: [ { key: "terminology", label: "Terminologies", icon: "hash" }, { key: "labs", label: "Laboratories & tests", icon: "beaker" }, ] }, { group: "Administer", items: [ { key: "tenants", label: "Tenants & users", icon: "tenants" }, ] }, ]; const NAV_LABEL = {}; NAV.forEach((g) => g.items.forEach((i) => (NAV_LABEL[i.key] = i.label))); /* ---- Logo ---------------------------------------------------------------- */ function Logo({ size = 22 }) { return h("span", { className: "logo", style: { width: size, height: size } }, h("svg", { viewBox: "0 0 24 24", width: size, height: size, fill: "none" }, h("rect", { x: 1, y: 1, width: 22, height: 22, rx: 7, fill: "var(--accent)" }), h("path", { d: "M5 13h3l1.6-4 2.4 8 1.8-5 1.2 2.4H19", stroke: "#fff", strokeWidth: 1.7, strokeLinecap: "round", strokeLinejoin: "round" }))); } /* ======================================================================== */ /* LOGIN */ /* ======================================================================== */ function Login({ onAuth }) { const [email, setEmail] = useState("noor@eno.health"); const [pw, setPw] = useState("••••••••••"); const [busy, setBusy] = useState(false); const submit = (e) => { e.preventDefault(); setBusy(true); setTimeout(() => { onAuth(); }, 650); }; return h("div", { className: "login" }, h("div", { className: "login-aside" }, h("div", { className: "login-brand" }, h(Logo, { size: 30 }), h("span", null, "Eno.Health")), h("div", { className: "login-aside-mid" }, h("h2", null, "Management Console"), h("p", null, "Operate the Document Ingestion Pipeline — monitor cells, debug documents, and govern tenants, policies and retention from one place."), h("div", { className: "login-feats" }, ["Live pipeline & cell health", "Document-level debugging", "Policy, quota & redaction governance", "Retention & GDPR controls"].map((f) => h("div", { className: "login-feat", key: f }, h(Icon, { name: "check", size: 15 }), f)))), h("div", { className: "login-aside-foot dim" }, "DIP-1 · cells eu-be · eu-nl · eu-de · ae-du")), h("div", { className: "login-main" }, h("form", { className: "login-card", onSubmit: submit }, h("h1", null, "Owner sign in"), h("p", { className: "login-sub" }, "Restricted to Eno.Health platform owners."), h(Field, { label: "Work email" }, h("input", { className: "input", type: "email", value: email, onChange: (e) => setEmail(e.target.value) })), h(Field, { label: "Password" }, h("input", { className: "input", type: "password", value: pw, onChange: (e) => setPw(e.target.value) })), h("label", { className: "login-row" }, h("span", { className: "login-check" }, h("input", { type: "checkbox", defaultChecked: true }), "Trust this device"), h("a", { href: "#", onClick: (e) => e.preventDefault() }, "SSO / SAML")), h(Button, { variant: "primary", size: "lg", type: "submit", className: "login-btn", disabled: busy }, busy ? h(React.Fragment, null, h(Icon, { name: "spinner", size: 16, className: "spin" }), "Signing in…") : "Sign in"), h("div", { className: "login-fine dim" }, h(Icon, { name: "lock", size: 12 }), "Protected admin access · all actions audited")))); } /* ======================================================================== */ /* CELL SWITCHER */ /* ======================================================================== */ function CellSwitcher({ cell, onChange }) { const [open, setOpen] = useState(false); const ref = useRef(); useEffect(() => { const f = (e) => ref.current && !ref.current.contains(e.target) && setOpen(false); window.addEventListener("click", f); return () => window.removeEventListener("click", f); }, []); const dot = (s) => s === "healthy" ? "up" : s === "degraded" ? "stale" : "down"; return h("div", { className: "cellsw", ref }, h("button", { className: "cellsw-btn", onClick: (e) => { e.stopPropagation(); setOpen((o) => !o); } }, h("span", { className: `svc-dot svc-${dot(cell.status)}` }), h("span", { className: "cellsw-flag" }, cell.flag), h("span", { className: "cellsw-id mono" }, cell.id), h("span", { className: "cellsw-name dim" }, cell.name), h(Icon, { name: "chevron", size: 14 })), open && h("div", { className: "cellsw-menu" }, h("div", { className: "cellsw-head" }, "Regional cell"), A.CELLS.map((c) => h("button", { key: c.id, className: "cellsw-item" + (c.id === cell.id ? " on" : ""), onClick: () => { onChange(c); setOpen(false); } }, h("span", { className: `svc-dot svc-${dot(c.status)}` }), h("span", { className: "cellsw-flag" }, c.flag), h("div", { className: "cellsw-item-main" }, h("div", { className: "mono" }, c.id), h("div", { className: "dim small" }, c.name, " · ", c.jurisdiction.toUpperCase())), c.id === cell.id && h(Icon, { name: "check", size: 15 }))), h("div", { className: "cellsw-foot dim" }, "Edge routes ", h(Mono, null, "eu-*"), " requests to the owning cell"))); } /* ======================================================================== */ /* SHELL */ /* ======================================================================== */ function Shell({ onLogout }) { const [nav, setNav] = useState(LS.get("nav", "overview")); const [cellId, setCellId] = useState(LS.get("cell", "eu-be")); const [doc, setDoc] = useState(null); const [device, setDevice] = useState(null); const [ownerMenu, setOwnerMenu] = useState(false); const cell = A.CELLS.find((c) => c.id === cellId) || A.CELLS[0]; const ownerRef = useRef(); useEffect(() => LS.set("nav", nav), [nav]); useEffect(() => LS.set("cell", cellId), [cellId]); useEffect(() => { const f = (e) => ownerRef.current && !ownerRef.current.contains(e.target) && setOwnerMenu(false); window.addEventListener("click", f); return () => window.removeEventListener("click", f); }, []); const goto = (k) => { setNav(k); window.scrollTo(0, 0); }; const openDoc = (d) => setDoc(d); const openDevice = (d) => setDevice(d); const views = { overview: h(OverviewView, { cell, onOpenDoc: openDoc, goto, onSelectCell: (id) => setCellId(id), onOpenDevice: openDevice }), documents: h(DocumentsView, { cell, onOpenDoc: openDoc }), streams: h(StreamsView, { onSelectCell: (id) => setCellId(id), onOpenDevice: openDevice }), runs: h(RunsView, { cell, onOpenDoc: openDoc }), upload: h(UploadView, { cell }), policies: h(PoliciesView, null), retention: h(RetentionView, null), webhooks: h(WebhooksView, null), terminology: h(TerminologyView, null), labs: h(LaboratoriesView, null), tenants: h(TenantsView, { onOpenDoc: openDoc }), }; const attention = A.DOCUMENTS.filter((d) => d.statusKey === "failed" || d.stuck).length; const unsupportedLabs = A.LABS.filter((l) => l.status === "unsupported").length; return h("div", { className: "shell" }, /* Sidebar */ h("aside", { className: "sidebar" }, h("div", { className: "side-brand" }, h(Logo, { size: 24 }), h("div", null, h("div", { className: "side-name" }, "Eno.Health"), h("div", { className: "side-tag" }, "Console"))), h("nav", { className: "side-nav" }, NAV.map((g) => h("div", { className: "nav-group", key: g.group }, h("div", { className: "nav-group-label" }, g.group), g.items.map((it) => h("button", { key: it.key, className: "nav-item" + (nav === it.key ? " on" : ""), onClick: () => goto(it.key) }, h(Icon, { name: it.icon, size: 17 }), h("span", null, it.label), it.key === "documents" && attention > 0 && h("span", { className: "nav-badge" }, attention), it.key === "labs" && unsupportedLabs > 0 && h("span", { className: "nav-badge nav-badge-soft" }, unsupportedLabs), it.key === "retention" && h("span", { className: "nav-badge nav-badge-soft" }, A.RETENTION_QUEUE.length)))))), h("div", { className: "side-foot" }, h("div", { className: "side-env" }, h("span", { className: "svc-dot svc-up" }), "development"))), /* Main */ h("div", { className: "main" }, h("header", { className: "topbar" }, h("div", { className: "topbar-left" }, h("span", { className: "crumb" }, "DIP"), h(Icon, { name: "chevronR", size: 13, className: "dim" }), h("span", { className: "crumb-cur" }, NAV_LABEL[nav])), h("div", { className: "topbar-right" }, h(CellSwitcher, { cell, onChange: (c) => setCellId(c.id) }), h("button", { className: "icon-btn", title: "Alerts" }, h(Icon, { name: "bell", size: 18 }), attention > 0 && h("span", { className: "bell-dot" })), h("div", { className: "owner", ref: ownerRef }, h("button", { className: "owner-btn", onClick: (e) => { e.stopPropagation(); setOwnerMenu((o) => !o); } }, h(Avatar, { initials: A.OWNER.initials, size: 30 }), h("div", { className: "owner-meta" }, h("div", { className: "owner-name" }, A.OWNER.name), h("div", { className: "owner-role dim" }, A.OWNER.role)), h(Icon, { name: "chevron", size: 14, className: "dim" })), ownerMenu && h("div", { className: "owner-menu" }, h("div", { className: "owner-menu-head" }, h("div", null, A.OWNER.name), h("div", { className: "dim small" }, A.OWNER.email)), h("button", { className: "owner-menu-item", onClick: onLogout }, h(Icon, { name: "logout", size: 15 }), "Sign out"))))), h("main", { className: "content" }, views[nav]), h(DocumentDrawer, { doc, onClose: () => setDoc(null) }), h(DeviceDrawer, { device, onClose: () => setDevice(null) }))); } /* ======================================================================== */ /* ROOT */ /* ======================================================================== */ function App() { const [authed, setAuthed] = useState(LS.get("authed", false)); useEffect(() => LS.set("authed", authed), [authed]); return h(ToastHost, null, authed ? h(Shell, { onLogout: () => setAuthed(false) }) : h(Login, { onAuth: () => setAuthed(true) })); } ReactDOM.createRoot(document.getElementById("root")).render(h(App, null));