Files
Krow-workspace/internal/api-harness/src/components/Layout.jsx
2026-02-26 15:13:26 -05:00

125 lines
3.9 KiB
JavaScript

import { Link, Navigate, Outlet, useLocation } from "react-router-dom";
import { useAuthState } from "react-firebase-hooks/auth";
import { auth } from "../firebase";
import { krowSDK } from "@/api/krowSDK";
import { Button } from "@/components/ui/button";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
import { ChevronDown } from "lucide-react";
import { useState } from "react";
const navLinks = {
auth: [
{ path: "/auth/me", title: "Get Me" },
{ path: "/auth/update-me", title: "Update Me" },
],
core: [
{ path: "/core/send-email", title: "Send Email" },
{ path: "/core/invoke-llm", title: "Invoke LLM" },
{ path: "/core/upload-file", title: "Upload File" },
{ path: "/core/upload-private-file", title: "Upload Private File" },
{ path: "/core/create-signed-url", title: "Create Signed URL" },
{ path: "/core/extract-data", title: "Extract Data from File" },
{ path: "/core/generate-image", title: "Generate Image" },
],
entities: [
{ path: "/entities", title: "Entity API Tester" }
]
};
const NavSection = ({ title, links }) => {
const location = useLocation();
const [isOpen, setIsOpen] = useState(true);
const navLinkClasses = (path) =>
`flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors ${
location.pathname === path
? "bg-slate-200 text-slate-900"
: "text-slate-600 hover:bg-slate-100"
}`;
return (
<Collapsible open={isOpen} onOpenChange={setIsOpen}>
<CollapsibleTrigger className="w-full">
<div className="flex items-center justify-between px-3 py-2">
<h2 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">
{title}
</h2>
<ChevronDown className={`w-4 h-4 text-slate-400 transition-transform ${isOpen ? 'rotate-180' : ''}`} />
</div>
</CollapsibleTrigger>
<CollapsibleContent className="space-y-1">
{links.map((api) => (
<Link key={api.path} to={api.path} className={navLinkClasses(api.path)}>
{api.title}
</Link>
))}
</CollapsibleContent>
</Collapsible>
);
}
const Layout = () => {
const [user, loading] = useAuthState(auth);
const location = useLocation();
if (loading) {
return (
<div className="flex items-center justify-center h-screen">
<div>Loading...</div>
</div>
);
}
if (!user) {
return <Navigate to="/login" />;
}
const handleLogout = () => {
krowSDK.auth.logout();
};
return (
<div className="flex h-screen bg-slate-50">
{/* Sidebar */}
<aside className="w-72 bg-white border-r border-slate-200 flex flex-col">
<div className="p-6 border-b border-slate-200">
<div className="flex items-center space-x-3">
<img src="/logo.svg" alt="KROW Logo" className="h-12 w-12" />
<div>
<h1 className="text-xl font-bold text-slate-900">KROW</h1>
<p className="text-xs text-slate-500">API Test Harness ({import.meta.env.VITE_HARNESS_ENVIRONMENT})</p>
</div>
</div>
</div>
<nav className="flex-1 overflow-y-auto p-4 space-y-2">
<NavSection title="Auth" links={navLinks.auth} />
<NavSection title="Core Integrations" links={navLinks.core} />
<NavSection title="Entities" links={navLinks.entities} />
</nav>
<div className="p-4 border-t border-slate-200">
<div className="text-sm text-slate-600 truncate mb-2" title={user.email}>{user.email}</div>
<Button onClick={handleLogout} className="w-full">
Logout
</Button>
</div>
</aside>
{/* Main Content */}
<main className="flex-1 overflow-y-auto">
<div className="p-8">
<Outlet />
</div>
</main>
</div>
);
};
export default Layout;