"use client"; import { useState, useEffect, useCallback } from "react"; import { useRouter } from "next/navigation"; import { signOut } from "next-auth/react"; import { Command } from "cmdk"; import { Activity, GitBranch, Key, Settings, LogOut, Plus, Search, ArrowRight, } from "lucide-react"; import { cn } from "@/lib/utils"; interface RecentTrace { id: string; name: string; status: string; startedAt: string; } export function CommandPalette() { const router = useRouter(); const [open, setOpen] = useState(false); const [recentTraces, setRecentTraces] = useState([]); const [loading, setLoading] = useState(false); const fetchRecentTraces = useCallback(async () => { setLoading(true); try { const res = await fetch("/api/traces?limit=5", { cache: "no-store" }); if (res.ok) { const data = await res.json(); setRecentTraces(data.traces ?? []); } } catch { // Silently fail -- palette still works for navigation } finally { setLoading(false); } }, []); useEffect(() => { if (open) { fetchRecentTraces(); } }, [open, fetchRecentTraces]); useEffect(() => { function handleKeyDown(e: KeyboardEvent) { if ((e.metaKey || e.ctrlKey) && e.key === "k") { e.preventDefault(); setOpen((prev) => !prev); } } document.addEventListener("keydown", handleKeyDown); return () => document.removeEventListener("keydown", handleKeyDown); }, []); function runCommand(command: () => void) { setOpen(false); command(); } if (!open) return null; return (
{/* Backdrop */}
setOpen(false)} /> {/* Palette */}
{/* Search input */}
ESC
{/* Results */} No results found. {/* Recent Traces */} {recentTraces.length > 0 && ( {loading ? (
Loading traces...
) : ( recentTraces.map((trace) => ( runCommand(() => router.push(`/dashboard/traces/${trace.id}`) ) } className={cn( "flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm cursor-pointer transition-colors", "text-neutral-300 data-[selected=true]:bg-emerald-500/10 data-[selected=true]:text-emerald-400" )} > {trace.name} {trace.status.toLowerCase()} )) )}
)} {/* Navigation */} runCommand(() => router.push("/dashboard")) } className="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm cursor-pointer text-neutral-300 data-[selected=true]:bg-emerald-500/10 data-[selected=true]:text-emerald-400 transition-colors" > Dashboard runCommand(() => router.push("/dashboard/decisions")) } className="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm cursor-pointer text-neutral-300 data-[selected=true]:bg-emerald-500/10 data-[selected=true]:text-emerald-400 transition-colors" > Decisions runCommand(() => router.push("/dashboard/keys")) } className="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm cursor-pointer text-neutral-300 data-[selected=true]:bg-emerald-500/10 data-[selected=true]:text-emerald-400 transition-colors" > API Keys runCommand(() => router.push("/dashboard/settings")) } className="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm cursor-pointer text-neutral-300 data-[selected=true]:bg-emerald-500/10 data-[selected=true]:text-emerald-400 transition-colors" > Settings {/* Actions */} runCommand(() => router.push("/dashboard/keys")) } className="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm cursor-pointer text-neutral-300 data-[selected=true]:bg-emerald-500/10 data-[selected=true]:text-emerald-400 transition-colors" > New API Key runCommand(() => signOut({ callbackUrl: "/" })) } className="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm cursor-pointer text-neutral-300 data-[selected=true]:bg-red-500/10 data-[selected=true]:text-red-400 transition-colors" > Logout
{/* Footer */}
↑↓ Navigate Select esc Close
); }