import { useState, useEffect, useCallback } from 'react' import { Settings, Bot, Wifi, MessageSquare, Database, Brain, Eye, Terminal, Cpu, Cloud, Radio, BookOpen, Layers, Activity, Thermometer, LayoutDashboard, Save, RotateCcw, RefreshCw, Plus, Trash2, ChevronDown, ChevronRight, AlertTriangle, Check, X, Eye as EyeIcon, EyeOff } from 'lucide-react' // Types for config sections interface BotConfig { name: string owner: string respond_to_dms: boolean filter_bbs_protocols: boolean } interface ConnectionConfig { type: string serial_port: string tcp_host: string tcp_port: number } interface ResponseConfig { delay_min: number delay_max: number max_length: number max_messages: number } interface HistoryConfig { database: string max_messages_per_user: number conversation_timeout: number auto_cleanup: boolean cleanup_interval_hours: number max_age_days: number } interface MemoryConfig { enabled: boolean window_size: number summarize_threshold: number } interface ContextConfig { enabled: boolean observe_channels: number[] ignore_nodes: string[] max_age: number max_context_items: number } interface CommandsConfig { enabled: boolean prefix: string disabled_commands: string[] custom_commands: Record } interface LLMConfig { backend: string api_key: string base_url: string model: string timeout: number max_response_tokens: number system_prompt: string use_system_prompt: boolean web_search: boolean google_grounding: boolean } interface WeatherConfig { primary: string fallback: string default_location: string openmeteo: { url: string } wttr: { url: string } } interface MeshMonitorConfig { enabled: boolean url: string inject_into_prompt: boolean refresh_interval: number polite_mode: boolean } interface KnowledgeConfig { enabled: boolean backend: string qdrant_host: string qdrant_port: number qdrant_collection: string tei_host: string tei_port: number sparse_host: string sparse_port: number use_sparse: boolean db_path: string top_k: number } interface MeshSourceConfig { name: string type: string url: string api_token: string refresh_interval: number polite_mode: boolean enabled: boolean } interface RegionAnchor { name: string lat: number lon: number local_name: string description: string aliases: string[] cities: string[] } interface AlertRulesConfig { infra_offline: boolean infra_recovery: boolean new_router: boolean battery_trend_declining: boolean battery_warning: boolean battery_critical: boolean battery_emergency: boolean battery_warning_threshold: number battery_critical_threshold: number battery_emergency_threshold: number power_source_change: boolean solar_not_charging: boolean sustained_high_util: boolean high_util_threshold: number high_util_hours: number packet_flood: boolean packet_flood_threshold: number infra_single_gateway: boolean feeder_offline: boolean region_total_blackout: boolean mesh_score_alert: boolean mesh_score_threshold: number region_score_alert: boolean region_score_threshold: number } interface MeshIntelligenceConfig { enabled: boolean regions: RegionAnchor[] locality_radius_miles: number offline_threshold_hours: number packet_threshold: number battery_warning_percent: number critical_nodes: string[] alert_channel: number alert_cooldown_minutes: number alert_rules: AlertRulesConfig } interface NWSConfig { enabled: boolean tick_seconds: number areas: string[] severity_min: string user_agent: string } interface EnvironmentalConfig { enabled: boolean nws_zones: string[] nws: NWSConfig swpc: { enabled: boolean } ducting: { enabled: boolean; tick_seconds: number; latitude: number; longitude: number } fires: { enabled: boolean; tick_seconds: number; state: string } avalanche: { enabled: boolean; tick_seconds: number; center_ids: string[]; season_months: number[] } } interface DashboardConfig { enabled: boolean port: number host: string } interface FullConfig { bot: BotConfig connection: ConnectionConfig response: ResponseConfig history: HistoryConfig memory: MemoryConfig context: ContextConfig commands: CommandsConfig llm: LLMConfig weather: WeatherConfig meshmonitor: MeshMonitorConfig knowledge: KnowledgeConfig mesh_sources: MeshSourceConfig[] mesh_intelligence: MeshIntelligenceConfig environmental: EnvironmentalConfig dashboard: DashboardConfig } type SectionKey = keyof FullConfig const SECTIONS: { key: SectionKey; label: string; icon: typeof Settings }[] = [ { key: 'bot', label: 'Bot', icon: Bot }, { key: 'connection', label: 'Connection', icon: Wifi }, { key: 'response', label: 'Response', icon: MessageSquare }, { key: 'history', label: 'History', icon: Database }, { key: 'memory', label: 'Memory', icon: Brain }, { key: 'context', label: 'Context', icon: Eye }, { key: 'commands', label: 'Commands', icon: Terminal }, { key: 'llm', label: 'LLM', icon: Cpu }, { key: 'weather', label: 'Weather', icon: Cloud }, { key: 'meshmonitor', label: 'MeshMonitor', icon: Radio }, { key: 'knowledge', label: 'Knowledge', icon: BookOpen }, { key: 'mesh_sources', label: 'Mesh Sources', icon: Layers }, { key: 'mesh_intelligence', label: 'Intelligence', icon: Activity }, { key: 'environmental', label: 'Environmental', icon: Thermometer }, { key: 'dashboard', label: 'Dashboard', icon: LayoutDashboard }, ] // Form components function TextInput({ label, value, onChange, type = 'text', placeholder = '', helper = '' }: { label: string value: string onChange: (v: string) => void type?: string placeholder?: string helper?: string }) { const [showPassword, setShowPassword] = useState(false) const isPassword = type === 'password' return (
onChange(e.target.value)} placeholder={placeholder} className="w-full px-3 py-2 bg-[#0a0e17] border border-[#1e2a3a] rounded text-sm text-slate-200 font-mono focus:outline-none focus:border-accent placeholder-slate-600" /> {isPassword && ( )}
{helper &&

{helper}

}
) } function NumberInput({ label, value, onChange, min, max, step = 1, helper = '' }: { label: string value: number onChange: (v: number) => void min?: number max?: number step?: number helper?: string }) { return (
onChange(Number(e.target.value))} min={min} max={max} step={step} className="w-full px-3 py-2 bg-[#0a0e17] border border-[#1e2a3a] rounded text-sm text-slate-200 font-mono focus:outline-none focus:border-accent" /> {helper &&

{helper}

}
) } function Toggle({ label, checked, onChange, helper = '' }: { label: string checked: boolean onChange: (v: boolean) => void helper?: string }) { return (
{label} {helper &&

{helper}

}
) } function SelectInput({ label, value, onChange, options, helper = '' }: { label: string value: string onChange: (v: string) => void options: { value: string; label: string }[] helper?: string }) { return (
{helper &&

{helper}

}
) } function TextArea({ label, value, onChange, rows = 4, helper = '' }: { label: string value: string onChange: (v: string) => void rows?: number helper?: string }) { return (