import { createContext, useContext, useEffect, useState, type FormEvent } from "react"; import { NavLink, Navigate, Route, Routes, useLocation, useNavigate } from "react-router"; import { api, UNAUTH_EVENT, type Me } from "./api"; import { useTheme } from "./hooks"; import { Loading } from "./components/ui"; import Login from "./pages/Login"; import Overview from "./pages/Overview"; import Apis from "./pages/Apis"; import ApiDetail from "./pages/ApiDetail"; import AkpDetail from "./pages/AkpDetail"; import GraphPage from "./pages/GraphPage"; import Executions from "./pages/Executions"; import ExecutionDetail from "./pages/ExecutionDetail"; import Credentials from "./pages/Credentials"; import Policy from "./pages/Policy"; import Lineage from "./pages/Lineage"; import DatasetDetail from "./pages/DatasetDetail"; import DebtPage from "./pages/Debt"; import Projects from "./pages/Projects"; import ProjectDetail from "./pages/ProjectDetail"; import Settings from "./pages/Settings"; import Operations from "./pages/Operations"; import SearchPage from "./pages/Search"; import VersionDetail from "./pages/VersionDetail"; import EndpointDetail from "./pages/EndpointDetail"; export const MeContext = createContext<{ me: Me | null; refresh: () => void }>({ me: null, refresh: () => {} }); export const useMe = () => useContext(MeContext); const NAV: { group: string; items: { to: string; label: string }[] }[] = [ { group: "Knowledge", items: [{ to: "/", label: "Overview" }, { to: "/apis", label: "API Atlas" }, { to: "/graph", label: "Knowledge Graph" }] }, { group: "Execution", items: [{ to: "/executions", label: "Execution Observatory" }, { to: "/credentials", label: "Credential Vault" }, { to: "/policy", label: "Policy Center" }] }, { group: "Research", items: [{ to: "/lineage", label: "Research Lineage" }, { to: "/debt", label: "Knowledge Debt" }] }, { group: "Admin", items: [{ to: "/projects", label: "Agents & Projects" }, { to: "/operations", label: "Operations" }, { to: "/settings", label: "Settings" }] }, ]; function Nav({ onNavigate }: { onNavigate?: () => void }) { return (
{NAV.map((g) => (
{g.group}
{g.items.map((it) => {it.label})}
))}
); } function Shell({ me, refresh, children }: { me: Me; refresh: () => void; children: React.ReactNode }) { const [open, setOpen] = useState(false); const [q, setQ] = useState(""); const nav = useNavigate(); const loc = useLocation(); const { theme, toggle } = useTheme(); useEffect(() => { setOpen(false); }, [loc.pathname]); const submit = (e: FormEvent) => { e.preventDefault(); if (q.trim()) nav(`/search?q=${encodeURIComponent(q.trim())}`); }; const logout = async () => { await api("auth/logout", { method: "POST" }).catch(() => {}); refresh(); }; return (
AKOS
setQ(e.target.value)} />
{me.email} · {me.role}
setOpen(false)} />
{children}
); } export default function App() { const [me, setMe] = useState(undefined); const [tick, setTick] = useState(0); const refresh = () => setTick((t) => t + 1); useEffect(() => { api("auth/me", { noRedirect: true }).then(setMe).catch(() => setMe(null)); }, [tick]); useEffect(() => { const h = () => setMe(null); window.addEventListener(UNAUTH_EVENT, h); return () => window.removeEventListener(UNAUTH_EVENT, h); }, []); const loc = useLocation(); if (me === undefined) return
; if (!me) return } />} />; return ( } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> Page not found.
} /> ); }