"use client"; import { API_BASE } from "@/lib/api"; import React, { useState, useEffect, useCallback } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { Settings, ExternalLink, Key, Shield, X, Save, ChevronDown, ChevronUp } from "lucide-react"; interface ApiEntry { id: string; name: string; description: string; category: string; url: string | null; required: boolean; has_key: boolean; env_key: string | null; value_obfuscated: string | null; is_set: boolean; } // Category colors for the tactical UI const CATEGORY_COLORS: Record = { Aviation: "text-cyan-400 border-cyan-500/30 bg-cyan-950/20", Maritime: "text-blue-400 border-blue-500/30 bg-blue-950/20", Geophysical: "text-orange-400 border-orange-500/30 bg-orange-950/20", Space: "text-purple-400 border-purple-500/30 bg-purple-950/20", Intelligence: "text-red-400 border-red-500/30 bg-red-950/20", Geolocation: "text-green-400 border-green-500/30 bg-green-950/20", Weather: "text-yellow-400 border-yellow-500/30 bg-yellow-950/20", Markets: "text-emerald-400 border-emerald-500/30 bg-emerald-950/20", SIGINT: "text-rose-400 border-rose-500/30 bg-rose-950/20", }; const SettingsPanel = React.memo(function SettingsPanel({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) { const [apis, setApis] = useState([]); const [editingId, setEditingId] = useState(null); const [editValue, setEditValue] = useState(""); const [saving, setSaving] = useState(false); const [expandedCategories, setExpandedCategories] = useState>(new Set(["Aviation", "Maritime"])); const fetchKeys = useCallback(async () => { try { const res = await fetch(`${API_BASE}/api/settings/api-keys`); if (res.ok) { const data = await res.json(); setApis(data); } } catch (e) { console.error("Failed to fetch API keys", e); } }, []); useEffect(() => { if (isOpen) fetchKeys(); }, [isOpen, fetchKeys]); const startEditing = (api: ApiEntry) => { setEditingId(api.id); setEditValue(""); }; const saveKey = async (api: ApiEntry) => { if (!api.env_key) return; setSaving(true); try { const res = await fetch(`${API_BASE}/api/settings/api-keys`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ env_key: api.env_key, value: editValue }), }); if (res.ok) { setEditingId(null); fetchKeys(); // Refresh to get new obfuscated value } } catch (e) { console.error("Failed to save API key", e); } finally { setSaving(false); } }; const toggleCategory = (cat: string) => { setExpandedCategories(prev => { const next = new Set(prev); if (next.has(cat)) next.delete(cat); else next.add(cat); return next; }); }; // Group APIs by category const grouped = apis.reduce>((acc, api) => { if (!acc[api.category]) acc[api.category] = []; acc[api.category].push(api); return acc; }, {}); return ( {isOpen && ( <> {/* Backdrop */} {/* Settings Panel */} {/* Header */}

SYSTEM CONFIG

API KEY REGISTRY
{/* Info Banner */}

API keys are stored locally in the backend .env file. Keys marked with are required for full functionality. Public APIs need no key.

{/* API List */}
{Object.entries(grouped).map(([category, categoryApis]) => { const colorClass = CATEGORY_COLORS[category] || "text-gray-400 border-gray-700 bg-gray-900/20"; const isExpanded = expandedCategories.has(category); return (
{/* Category Header */} {/* APIs in Category */} {isExpanded && ( {categoryApis.map((api) => (
{/* API Name + Status */}
{api.required && } {api.name}
{api.has_key ? ( api.is_set ? ( KEY SET ) : ( MISSING ) ) : ( PUBLIC )} {api.url && ( e.stopPropagation()} > )}
{/* Description */}

{api.description}

{/* Key Field (only for APIs with keys) */} {api.has_key && (
{editingId === api.id ? ( /* Edit Mode */
setEditValue(e.target.value)} className="flex-1 bg-black/60 border border-cyan-900/50 rounded px-2 py-1.5 text-[11px] font-mono text-cyan-300 outline-none focus:border-cyan-500/70 transition-colors" placeholder="Enter API key..." autoFocus />
) : ( /* Display Mode */
startEditing(api)} > {api.is_set ? api.value_obfuscated : "Click to set key..."}
)}
)}
))}
)}
); })}
{/* Footer */}
{apis.length} REGISTERED APIs {apis.filter(a => a.has_key).length} KEYS CONFIGURED
)}
); }); export default SettingsPanel;