From 9369bd684f78efe9ea63056319fcf3713a4c9458 Mon Sep 17 00:00:00 2001 From: zvx-echo6 Date: Wed, 13 May 2026 09:55:03 -0600 Subject: [PATCH] feat(config): add comprehensive field documentation with info buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add helper text and info (?) buttons to every field in Config.tsx - Add section descriptions at the top of each config section - Battery thresholds now show voltage equivalents (e.g., "30% ≈ 3.60V") - NWS severity dropdown shows descriptions per option - Alert rules grouped by category with full explanations - Add InfoButton popover component for detailed field documentation - Add info buttons to Environment.tsx RF propagation panels - VOLTAGE_MAP and getVoltageApprox helper for Li-ion voltage lookup Researched defaults and descriptions include: - Li-ion voltage curve (4.20V=100%, 3.60V=30%, 3.50V=15%, 3.40V=7%) - LoRa channel utilization (firmware throttles at 25%, issues at 50%) - Packet flood detection (normal 1-5/min, suspicious >10/min) - NWS severity levels with actionable descriptions - Tropospheric ducting M-units/km refractivity gradients - NOAA Space Weather R/S/G scales Co-Authored-By: Claude Opus 4.5 --- dashboard-frontend/src/pages/Config.tsx | 1210 +++++++++++++++--- dashboard-frontend/src/pages/Environment.tsx | 56 +- 2 files changed, 1088 insertions(+), 178 deletions(-) diff --git a/dashboard-frontend/src/pages/Config.tsx b/dashboard-frontend/src/pages/Config.tsx index 06f981d..0246dd6 100644 --- a/dashboard-frontend/src/pages/Config.tsx +++ b/dashboard-frontend/src/pages/Config.tsx @@ -1,12 +1,91 @@ -import { useState, useEffect, useCallback } from 'react' +import { useState, useEffect, useCallback, useRef } 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 + Check, X, Eye as EyeIcon, EyeOff, HelpCircle } from 'lucide-react' +// Voltage lookup for Li-ion battery percentages +const VOLTAGE_MAP: Record = { + 100: '4.20V', + 90: '4.10V', + 80: '4.00V', + 70: '3.90V', + 60: '3.80V', + 50: '3.70V', + 40: '3.65V', + 30: '3.60V', + 20: '3.55V', + 15: '3.50V', + 10: '3.45V', + 7: '3.40V', + 5: '3.38V', + 0: '3.30V', +} + +function getVoltageApprox(percent: number): string { + const keys = Object.keys(VOLTAGE_MAP).map(Number).sort((a, b) => b - a) + for (const key of keys) { + if (percent >= key) return VOLTAGE_MAP[key] + } + return '3.30V' +} + +// Section descriptions +const SECTION_DESCRIPTIONS: Record = { + bot: 'Configure the bot identity and basic behavior settings for the Meshtastic AI assistant.', + connection: 'Set up how the bot connects to your Meshtastic device — via serial port or TCP network connection.', + response: 'Control message timing and length limits. Delays help avoid channel congestion; length limits fit LoRa constraints.', + history: 'Manage conversation history storage. Messages are stored in SQLite for context and analytics.', + memory: 'Memory optimization summarizes old conversations to reduce token usage while preserving context.', + context: 'Passive context lets the bot observe channel traffic to understand ongoing conversations without being directly addressed.', + commands: 'Configure slash commands that users can send to trigger specific bot actions.', + llm: 'Configure the LLM backend (OpenAI, Anthropic, Google) and model settings for AI responses.', + weather: 'Set up weather providers for the !wx command. Open-Meteo is free; wttr.in has rate limits.', + meshmonitor: 'Connect to MeshMonitor for real-time mesh network telemetry and node information.', + knowledge: 'RAG (Retrieval-Augmented Generation) knowledge base for answering questions from your documents.', + mesh_sources: 'Connect to mesh visualization tools (MeshView, MeshMonitor) to aggregate node data.', + mesh_intelligence: 'Mesh Intelligence monitors network health, detects outages, and generates alerts.', + environmental: 'Environmental data feeds for weather alerts, space weather, fires, and avalanche conditions.', + dashboard: 'Configure the web dashboard server settings.', +} + +// Info button component with popover +function InfoButton({ info }: { info: string }) { + const [show, setShow] = useState(false) + const ref = useRef(null) + + useEffect(() => { + function handleClickOutside(e: MouseEvent) { + if (ref.current && !ref.current.contains(e.target as Node)) { + setShow(false) + } + } + document.addEventListener('mousedown', handleClickOutside) + return () => document.removeEventListener('mousedown', handleClickOutside) + }, []) + + return ( +
+ + {show && ( +
+ {info} +
+ )} +
+ ) +} + // Types for config sections interface BotConfig { name: string @@ -226,20 +305,24 @@ const SECTIONS: { key: SectionKey; label: string; icon: typeof Settings }[] = [ ] // Form components -function TextInput({ label, value, onChange, type = 'text', placeholder = '', helper = '' }: { +function TextInput({ label, value, onChange, type = 'text', placeholder = '', helper = '', info = '' }: { label: string value: string onChange: (v: string) => void type?: string placeholder?: string helper?: string + info?: string }) { const [showPassword, setShowPassword] = useState(false) const isPassword = type === 'password' return (
- +
void @@ -271,10 +354,15 @@ function NumberInput({ label, value, onChange, min, max, step = 1, helper = '' } max?: number step?: number helper?: string + info?: string + suffix?: string }) { return (
- + void helper?: string + info?: string }) { return (
- {label} + + {label} + {info && } + {helper &&

{helper}

}