diff --git a/dashboard-frontend/src/pages/Config.tsx b/dashboard-frontend/src/pages/Config.tsx index cfa26f3..6ddc7a6 100644 --- a/dashboard-frontend/src/pages/Config.tsx +++ b/dashboard-frontend/src/pages/Config.tsx @@ -4,7 +4,7 @@ import ChannelPicker from '@/components/ChannelPicker' import { Settings, Bot, Wifi, MessageSquare, Database, Brain, Eye, Terminal, Cpu, Cloud, Radio, BookOpen, Layers, Activity, - Thermometer, LayoutDashboard, Save, RotateCcw, RefreshCw, + LayoutDashboard, Save, RotateCcw, RefreshCw, Plus, Trash2, ChevronDown, ChevronRight, AlertTriangle, Check, X, Eye as EyeIcon, EyeOff, ExternalLink } from 'lucide-react' @@ -233,7 +233,6 @@ const SECTIONS: { key: SectionKey; label: string; icon: typeof Settings }[] = [ { 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 }, ] @@ -281,7 +280,7 @@ const AVAILABLE_COMMANDS = [ ] // US States for dropdown -const US_STATES = [ +export const US_STATES = [ { value: 'US-AL', label: 'Alabama' }, { value: 'US-AK', label: 'Alaska' }, { value: 'US-AZ', label: 'Arizona' }, { value: 'US-AR', label: 'Arkansas' }, { value: 'US-CA', label: 'California' }, { value: 'US-CO', label: 'Colorado' }, @@ -375,7 +374,7 @@ function SectionDescription({ text }: { text: string }) { } // Form components -function TextInput({ label, value, onChange, type = 'text', placeholder = '', helper = '', info = '', infoLink = '' }: { +export function TextInput({ label, value, onChange, type = 'text', placeholder = '', helper = '', info = '', infoLink = '' }: { label: string value: string onChange: (v: string) => void @@ -417,7 +416,7 @@ function TextInput({ label, value, onChange, type = 'text', placeholder = '', he ) } -function NumberInput({ label, value, onChange, min, max, step = 1, helper = '', info = '', infoLink = '' }: { +export function NumberInput({ label, value, onChange, min, max, step = 1, helper = '', info = '', infoLink = '' }: { label: string value: number onChange: (v: number) => void @@ -448,7 +447,7 @@ function NumberInput({ label, value, onChange, min, max, step = 1, helper = '', ) } -function Toggle({ label, checked, onChange, helper = '', info = '', infoLink = '' }: { +export function Toggle({ label, checked, onChange, helper = '', info = '', infoLink = '' }: { label: string checked: boolean onChange: (v: boolean) => void @@ -482,7 +481,7 @@ function Toggle({ label, checked, onChange, helper = '', info = '', infoLink = ' ) } -function SelectInput({ label, value, onChange, options, helper = '', info = '', infoLink = '' }: { +export function SelectInput({ label, value, onChange, options, helper = '', info = '', infoLink = '' }: { label: string value: string onChange: (v: string) => void @@ -537,7 +536,7 @@ function TextArea({ label, value, onChange, rows = 4, helper = '', info = '', in ) } -function ListInput({ label, value, onChange, helper = '', info = '', infoLink = '' }: { +export function ListInput({ label, value, onChange, helper = '', info = '', infoLink = '' }: { label: string value: string[] onChange: (v: string[]) => void @@ -575,7 +574,7 @@ function ListInput({ label, value, onChange, helper = '', info = '', infoLink = ) } -function NumberListInput({ label, value, onChange, helper = '', info = '', infoLink = '' }: { +export function NumberListInput({ label, value, onChange, helper = '', info = '', infoLink = '' }: { label: string value: number[] onChange: (v: number[]) => void @@ -1752,415 +1751,6 @@ function MeshIntelligenceSection({ data, onChange }: { data: MeshIntelligenceCon ) } -function EnvironmentalSection({ data, onChange }: { data: EnvironmentalConfig; onChange: (d: EnvironmentalConfig) => void }) { - return ( -
Solar indices, geomagnetic storms, HF propagation
-VHF/UHF extended range conditions
-Active wildfires from National Interagency Fire Center
-Backcountry avalanche danger ratings
-River and stream water levels
-Traffic flow on monitored corridors
-State DOT road events and closures
-Near real-time thermal anomalies from satellites
-{subtitle}
}- Enable environmental feeds in config.yaml to see weather alerts, - space weather indices, and tropospheric ducting data. -
-Off season - check back in December
-No adapters yet. ADS-B / AIS / satellite passes are planned for v0.5.
+Node/infra telemetry — sourced from the mesh, not an environmental feed.
+s>=80?"#22c55e":s>=60?"#f59e0b":"#ef4444")(t),a=2*Math.PI*45,o=t/100*a;return _.jsx("div",{className:"flex flex-col items-center",children:_.jsxs("svg",{width:"140",height:"140",viewBox:"0 0 100 100",children:[_.jsx("circle",{cx:"50",cy:"50",r:"45",fill:"none",stroke:"#1e2a3a",strokeWidth:"8"}),_.jsx("circle",{cx:"50",cy:"50",r:"45",fill:"none",stroke:i,strokeWidth:"8",strokeLinecap:"round",strokeDasharray:a,strokeDashoffset:a-o,transform:"rotate(-90 50 50)",className:"transition-all duration-500"}),_.jsx("text",{x:"50",y:"46",textAnchor:"middle",className:"fill-slate-100 font-mono text-2xl font-bold",style:{fontSize:"24px"},children:t.toFixed(1)}),_.jsx("text",{x:"50",y:"62",textAnchor:"middle",className:"fill-slate-400 text-xs",style:{fontSize:"10px"},children:r})]})})}function x_({label:e,value:t}){const r=n=>n>=80?"bg-green-500":n>=60?"bg-amber-500":"bg-red-500";return _.jsxs("div",{className:"flex items-center gap-3",children:[_.jsx("div",{className:"w-24 text-xs text-slate-400 truncate",children:e}),_.jsx("div",{className:"flex-1 h-2 bg-border rounded-full overflow-hidden",children:_.jsx("div",{className:`h-full ${r(t)} transition-all duration-300`,style:{width:`${t}%`}})}),_.jsx("div",{className:"w-12 text-right text-xs font-mono text-slate-300",children:t.toFixed(1)})]})}function ZDe({alert:e}){const r=(i=>{switch(i.toLowerCase()){case"critical":case"emergency":case"immediate":return{bg:"bg-red-500/10",border:"border-red-500",icon:_d,iconColor:"text-red-500"};case"warning":case"priority":return{bg:"bg-amber-500/10",border:"border-amber-500",icon:ru,iconColor:"text-amber-500"};case"routine":default:return{bg:"bg-blue-500/10",border:"border-blue-500",icon:bS,iconColor:"text-blue-500"}}})(e.severity),n=r.icon;return _.jsxs("div",{className:`p-3 rounded-lg ${r.bg} border-l-2 ${r.border} flex items-start gap-3`,children:[_.jsx(n,{size:16,className:r.iconColor}),_.jsxs("div",{className:"flex-1 min-w-0",children:[_.jsx("div",{className:"text-sm text-slate-200",children:e.message}),_.jsx("div",{className:"text-xs text-slate-500 mt-1",children:e.timestamp||"Just now"})]})]})}function YDe({source:e}){const t=()=>e.is_loaded?e.last_error?"bg-amber-500":"bg-green-500":"bg-red-500";return _.jsxs("div",{className:"flex items-center gap-3 p-3 rounded-lg bg-bg-hover",children:[_.jsx("div",{className:`w-2 h-2 rounded-full ${t()}`}),_.jsxs("div",{className:"flex-1 min-w-0",children:[_.jsx("div",{className:"text-sm text-slate-200 truncate",children:e.name}),_.jsxs("div",{className:"text-xs text-slate-500",children:[e.node_count," nodes · ",e.type]})]})]})}function b_({icon:e,label:t,value:r,subvalue:n}){return _.jsxs("div",{className:"bg-bg-card border border-border rounded-lg p-4",children:[_.jsxs("div",{className:"flex items-center gap-2 text-slate-400 mb-2",children:[_.jsx(e,{size:14}),_.jsx("span",{className:"text-xs",children:t})]}),_.jsx("div",{className:"font-mono text-xl text-slate-100",children:r}),n&&_.jsx("div",{className:"text-xs text-slate-500 mt-1",children:n})]})}function DA({label:e,value:t}){const r=()=>t===0?"bg-green-500/20 text-green-400 border-green-500/50":t<=2?"bg-amber-500/20 text-amber-400 border-amber-500/50":"bg-red-500/20 text-red-400 border-red-500/50";return _.jsxs("span",{className:`px-2 py-1 rounded text-xs font-mono font-medium border ${r()}`,children:[e,t]})}function rF({label:e,value:t,unit:r,getColor:n}){const i=t!==void 0?n(t):"text-slate-400";return _.jsxs("div",{className:"text-center",children:[_.jsx("div",{className:"text-xs text-slate-500 mb-1",children:e}),_.jsx("div",{className:`font-mono text-3xl font-bold ${i}`,children:(t==null?void 0:t.toFixed(0))??"—"}),r&&_.jsx("div",{className:"text-xs text-slate-500",children:r})]})}function XDe({history:e}){var a;const t=U.useMemo(()=>!e||e.length===0?[]:e.slice(-16).map((o,s)=>({idx:s,value:o.value,time:o.time})),[e]);if(t.length===0)return null;const r=Math.max(...t.map(o=>o.value),5),n=((a=t[t.length-1])==null?void 0:a.value)??0,i=()=>r>5?"kpGradientRed":r>3?"kpGradientAmber":"kpGradientGreen";return _.jsxs("div",{className:"h-20 w-full",children:[_.jsx(eX,{width:"100%",height:"100%",children:_.jsxs(HDe,{data:t,margin:{top:5,right:5,bottom:5,left:5},children:[_.jsxs("defs",{children:[_.jsxs("linearGradient",{id:"kpGradientGreen",x1:"0",y1:"0",x2:"0",y2:"1",children:[_.jsx("stop",{offset:"0%",stopColor:"#22c55e",stopOpacity:.4}),_.jsx("stop",{offset:"100%",stopColor:"#22c55e",stopOpacity:.05})]}),_.jsxs("linearGradient",{id:"kpGradientAmber",x1:"0",y1:"0",x2:"0",y2:"1",children:[_.jsx("stop",{offset:"0%",stopColor:"#f59e0b",stopOpacity:.4}),_.jsx("stop",{offset:"100%",stopColor:"#f59e0b",stopOpacity:.05})]}),_.jsxs("linearGradient",{id:"kpGradientRed",x1:"0",y1:"0",x2:"0",y2:"1",children:[_.jsx("stop",{offset:"0%",stopColor:"#ef4444",stopOpacity:.4}),_.jsx("stop",{offset:"100%",stopColor:"#ef4444",stopOpacity:.05})]})]}),_.jsx(Lv,{domain:[0,Math.ceil(r)],hide:!0}),_.jsx(Pv,{dataKey:"idx",hide:!0}),_.jsx(ny,{y:3,stroke:"#f59e0b",strokeDasharray:"3 3",strokeOpacity:.5}),_.jsx(ny,{y:5,stroke:"#ef4444",strokeDasharray:"3 3",strokeOpacity:.5}),_.jsx(mu,{type:"monotone",dataKey:"value",stroke:n>5?"#ef4444":n>3?"#f59e0b":"#22c55e",fill:`url(#${i()})`,strokeWidth:2})]})}),_.jsxs("div",{className:"flex justify-between text-xs text-slate-600 px-1",children:[_.jsx("span",{children:"48h ago"}),_.jsx("span",{children:"now"})]})]})}function qDe({profile:e}){const t=U.useMemo(()=>!e||e.length===0?[]:[...e].sort((r,n)=>r.height_m-n.height_m).map(r=>({height:r.height_m,M:r.M})),[e]);return t.length===0?null:_.jsxs("div",{className:"h-24 w-full",children:[_.jsx(eX,{width:"100%",height:"100%",children:_.jsxs(WDe,{data:t,margin:{top:5,right:10,bottom:5,left:5},children:[_.jsx(Pv,{dataKey:"M",type:"number",domain:["dataMin - 20","dataMax + 20"],tick:{fontSize:10,fill:"#64748b"},tickLine:!1,axisLine:{stroke:"#334155"}}),_.jsx(Lv,{dataKey:"height",type:"number",domain:[0,"dataMax"],tick:{fontSize:10,fill:"#64748b"},tickLine:!1,axisLine:{stroke:"#334155"},tickFormatter:r=>`${(r/1e3).toFixed(1)}k`}),_.jsx(e0,{type:"monotone",dataKey:"M",stroke:"#3b82f6",strokeWidth:2,dot:{r:3,fill:"#3b82f6"}})]})}),_.jsx("div",{className:"text-center text-xs text-slate-600",children:"M-units vs Height (km)"})]})}function KDe({swpc:e,ducting:t}){const r=a=>a>=120?"text-green-400":a>=80?"text-amber-400":"text-red-400",n=a=>a<=3?"text-green-400":a<=5?"text-amber-400":"text-red-400",i=a=>{if(!a)return null;const o={normal:"bg-green-500/20 text-green-400 border-green-500/50",super_refraction:"bg-amber-500/20 text-amber-400 border-amber-500/50",surface_duct:"bg-blue-500/20 text-blue-400 border-blue-500/50",elevated_duct:"bg-blue-500/20 text-blue-400 border-blue-500/50"},s={normal:"Normal",super_refraction:"Super Refraction",surface_duct:"Surface Duct",elevated_duct:"Elevated Duct"};return _.jsx("span",{className:`px-2 py-1 rounded text-xs font-medium border ${o[a]||o.normal}`,children:s[a]||a})};return _.jsxs("div",{className:"bg-bg-card border border-border rounded-lg p-4 flex flex-col h-full",children:[_.jsxs("h2",{className:"text-sm font-medium text-slate-400 mb-4 flex items-center gap-2",children:[_.jsx(Tm,{size:14}),"RF Propagation"]}),_.jsxs("div",{className:"flex justify-around mb-4",children:[_.jsx(rF,{label:"SFI",value:e==null?void 0:e.sfi,getColor:r}),_.jsx("div",{className:"w-px bg-border"}),_.jsx(rF,{label:"Kp",value:e==null?void 0:e.kp_current,getColor:n})]}),_.jsxs("div",{className:"flex justify-center gap-2 mb-4",children:[_.jsx(DA,{label:"R",value:(e==null?void 0:e.r_scale)??0}),_.jsx(DA,{label:"S",value:(e==null?void 0:e.s_scale)??0}),_.jsx(DA,{label:"G",value:(e==null?void 0:e.g_scale)??0})]}),(e==null?void 0:e.kp_history)&&e.kp_history.length>0&&_.jsxs("div",{className:"mb-4",children:[_.jsx("div",{className:"text-xs text-slate-500 mb-1",children:"Kp Trend (48h)"}),_.jsx(XDe,{history:e.kp_history})]}),_.jsx("div",{className:"border-t border-border my-3"}),_.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[_.jsx(Kc,{size:14,className:"text-slate-400"}),_.jsx("span",{className:"text-xs text-slate-500",children:"Tropospheric"}),i(t==null?void 0:t.condition)]}),(t==null?void 0:t.min_gradient)!==void 0&&_.jsxs("div",{className:"text-xs text-slate-400 font-mono mb-2",children:["dM/dz: ",t.min_gradient.toFixed(1)," M-units/km"]}),(t==null?void 0:t.profile)&&t.profile.length>0&&_.jsx(qDe,{profile:t.profile}),(e==null?void 0:e.active_warnings)&&e.active_warnings.length>0&&_.jsxs("div",{className:"mt-auto pt-3 border-t border-border",children:[_.jsx("div",{className:"text-xs text-slate-500 mb-1",children:"SWPC Alerts"}),_.jsx("div",{className:"flex flex-wrap gap-1",children:e.active_warnings.slice(0,3).map((a,o)=>_.jsx("span",{className:"px-2 py-0.5 rounded text-xs bg-amber-500/20 text-amber-400 border border-amber-500/30 truncate max-w-full",children:a.replace("Space Weather Message Code: ","")},o))})]})]})}const QDe={nws:{icon:Kc,color:"text-blue-400",label:"NWS"},swpc:{icon:kZ,color:"text-yellow-400",label:"SWPC"},ducting:{icon:jo,color:"text-cyan-400",label:"Tropo"},nifc:{icon:ZE,color:"text-orange-400",label:"NIFC"},firms:{icon:SS,color:"text-red-400",label:"FIRMS"},avalanche:{icon:YE,color:"text-slate-300",label:"Avy"},usgs:{icon:SZ,color:"text-blue-300",label:"USGS"},traffic:{icon:GE,color:"text-purple-400",label:"Traffic"},roads:{icon:bZ,color:"text-amber-400",label:"511"}},nF={routine:"bg-blue-500/20 text-blue-400 border-blue-500/30",priority:"bg-amber-500/20 text-amber-400 border-amber-500/30",immediate:"bg-red-600/20 text-red-300 border-red-600/30",info:"bg-blue-500/20 text-blue-400 border-blue-500/30",advisory:"bg-blue-500/20 text-blue-400 border-blue-500/30",moderate:"bg-amber-500/20 text-amber-400 border-amber-500/30",watch:"bg-amber-500/20 text-amber-400 border-amber-500/30",warning:"bg-amber-500/20 text-amber-400 border-amber-500/30",severe:"bg-red-500/20 text-red-400 border-red-500/30",extreme:"bg-red-600/20 text-red-300 border-red-600/30",critical:"bg-red-600/20 text-red-300 border-red-600/30",emergency:"bg-red-700/20 text-red-200 border-red-700/30"};function JDe({event:e,isLocal:t}){var f;const r=QDe[e.source]||{icon:bS,color:"text-slate-400",label:e.source},n=r.icon,i=nF[(f=e.severity)==null?void 0:f.toLowerCase()]||nF.info,a=h=>{const d=new Date(h*1e3),g=new Date().getTime()-d.getTime(),m=Math.floor(g/6e4);return m<1?"just now":m<60?`${m}m ago`:m<1440?`${Math.floor(m/60)}h ago`:d.toLocaleDateString(void 0,{month:"short",day:"numeric"})},o=e.event_type,s=e.area_desc,l=e.description;let u=e.headline;if(o&&s){const h=s.replace(/ County/g,"").split(";")[0];u=`${o} — ${h}`}else o&&(u=o);const c=l?l.split(". ")[0]:null;return _.jsxs("div",{className:`flex items-start gap-2 py-2 border-b border-border/50 last:border-0 ${t?"border-l-2 border-l-blue-500 pl-2 -ml-2":""}`,children:[_.jsx(n,{size:14,className:`mt-0.5 flex-shrink-0 ${r.color}`}),_.jsxs("div",{className:"flex-1 min-w-0",children:[_.jsxs("div",{className:"flex items-center gap-2 mb-0.5",children:[_.jsx("span",{className:`px-1.5 py-0.5 rounded text-xs border ${i}`,children:e.severity||"info"}),t&&_.jsx("span",{className:"px-1.5 py-0.5 rounded text-xs bg-blue-500/20 text-blue-400 border border-blue-500/30",children:"LOCAL"}),_.jsx("span",{className:"text-xs text-slate-500",children:r.label}),_.jsx("span",{className:"text-xs text-slate-600 ml-auto",children:a(e.fetched_at)})]}),_.jsx("div",{className:`text-sm truncate ${t?"text-slate-100":"text-slate-300"}`,children:u}),c&&_.jsx("div",{className:"text-xs text-slate-500 truncate mt-0.5",children:c})]})]})}function eNe({events:e,envStatus:t}){const r={immediate:0,priority:1,routine:2},n=U.useMemo(()=>{const a=new Set;return e.filter(s=>s.event_id?a.has(s.event_id)?!1:(a.add(s.event_id),!0):!0).sort((s,l)=>{var d,v;const u=s.is_local?1:0,c=l.is_local?1:0;if(u!==c)return c-u;const f=r[((d=s.severity)==null?void 0:d.toLowerCase())||"routine"]??2,h=r[((v=l.severity)==null?void 0:v.toLowerCase())||"routine"]??2;return f!==h?f-h:(l.fetched_at||0)-(s.fetched_at||0)})},[e]),i=U.useMemo(()=>{if(!(t!=null&&t.feeds))return null;const a=t.feeds.length,o=t.feeds.filter(c=>c.is_loaded&&!c.last_error).length,s=t.feeds.filter(c=>c.last_error).map(c=>c.source),l=Math.max(...t.feeds.map(c=>c.last_fetch||0)),u=l?Math.floor(Date.now()/1e3-l):null;return{total:a,active:o,errors:s,secAgo:u}},[t]);return _.jsxs("div",{className:"bg-bg-card border border-border rounded-lg p-4 flex flex-col h-full",children:[_.jsxs("h2",{className:"text-sm font-medium text-slate-400 mb-3 flex items-center gap-2",children:[_.jsx(Hy,{size:14}),"Live Event Feed"]}),n.length>0?_.jsx("div",{className:"flex-1 overflow-y-auto max-h-80 pr-1 -mr-1",children:n.map((a,o)=>_.jsx(JDe,{event:a,isLocal:a.is_local},a.event_id||o))}):_.jsx("div",{className:"flex-1 flex items-center justify-center",children:_.jsxs("div",{className:"text-center py-8",children:[_.jsx(WE,{size:24,className:"text-green-500 mx-auto mb-2"}),_.jsx("div",{className:"text-slate-400",children:"No active events"}),_.jsx("div",{className:"text-xs text-slate-500",children:"All clear"})]})}),i&&_.jsxs("div",{className:`text-xs mt-3 pt-3 border-t border-border ${i.errors.length>0?"text-amber-400":"text-slate-500"}`,children:[i.active," of ",i.total," feeds active",i.secAgo!==null&&` · Last update ${i.secAgo}s ago`,i.errors.length>0&&_.jsxs("span",{className:"text-amber-400",children:[" · ",i.errors.join(", "),": error"]})]})]})}function tNe(){var S,T,C,M,P;const[e,t]=U.useState(null),[r,n]=U.useState([]),[i,a]=U.useState([]),[o,s]=U.useState(null),[l,u]=U.useState([]),[c,f]=U.useState(null),[h,d]=U.useState(null),[v,g]=U.useState(!0),[m,y]=U.useState(null),{lastHealth:x,lastMessage:b}=JE();return U.useEffect(()=>{Promise.all([lce(),fce(),EZ(),DZ(),NZ().catch(()=>[]),dce().catch(()=>null),vce().catch(()=>null)]).then(([I,k,E,D,j,N,z])=>{t(I),n(k),a(E),s(D),u(j),f(N),d(z),g(!1),document.title="Dashboard — MeshAI"}).catch(I=>{y(I.message),g(!1),document.title="Dashboard — MeshAI"})},[]),U.useEffect(()=>{x&&t(x)},[x]),U.useEffect(()=>{(b==null?void 0:b.type)==="env_update"&&b.event&&u(I=>{const k=b.event,E=I.filter(D=>D.event_id!==k.event_id);return[k,...E].slice(0,100)})},[b]),v?_.jsx("div",{className:"flex items-center justify-center h-64",children:_.jsx("div",{className:"text-slate-400",children:"Loading..."})}):m?_.jsx("div",{className:"flex items-center justify-center h-64",children:_.jsxs("div",{className:"text-red-400",children:["Error: ",m]})}):_.jsxs("div",{className:"space-y-6",children:[_.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-3 gap-6",children:[_.jsxs("div",{className:"bg-bg-card border border-border rounded-lg p-6",children:[_.jsx("h2",{className:"text-sm font-medium text-slate-400 mb-4",children:"Mesh Health"}),e&&_.jsxs(_.Fragment,{children:[_.jsx(UDe,{health:e}),_.jsxs("div",{className:"mt-6 space-y-3",children:[_.jsx(x_,{label:"Infrastructure",value:((S=e.pillars)==null?void 0:S.infrastructure)??0}),_.jsx(x_,{label:"Utilization",value:((T=e.pillars)==null?void 0:T.utilization)??0}),_.jsx(x_,{label:"Behavior",value:((C=e.pillars)==null?void 0:C.behavior)??0}),_.jsx(x_,{label:"Power",value:((M=e.pillars)==null?void 0:M.power)??0})]})]})]}),_.jsxs("div",{className:"lg:col-span-2 space-y-6",children:[_.jsxs("div",{className:"bg-bg-card border border-border rounded-lg p-6",children:[_.jsx("h2",{className:"text-sm font-medium text-slate-400 mb-4",children:"Active Alerts"}),i.length>0?_.jsx("div",{className:"space-y-3 max-h-48 overflow-y-auto",children:i.map((I,k)=>_.jsx(ZDe,{alert:I},k))}):_.jsxs("div",{className:"flex items-center gap-2 text-slate-500 py-4",children:[_.jsx(WE,{size:16,className:"text-green-500"}),_.jsx("span",{children:"No active alerts"})]})]}),_.jsxs("div",{className:"grid grid-cols-2 lg:grid-cols-4 gap-4",children:[_.jsx(b_,{icon:jo,label:"Nodes Online",value:(e==null?void 0:e.total_nodes)||0,subvalue:`${(e==null?void 0:e.unlocated_count)||0} unlocated`}),_.jsx(b_,{icon:wZ,label:"Infrastructure",value:`${(e==null?void 0:e.infra_online)||0}/${(e==null?void 0:e.infra_total)||0}`,subvalue:(e==null?void 0:e.infra_online)===(e==null?void 0:e.infra_total)?"All online":"Some offline"}),_.jsx(b_,{icon:Hy,label:"Utilization",value:`${((P=e==null?void 0:e.util_percent)==null?void 0:P.toFixed(1))||0}%`,subvalue:`${(e==null?void 0:e.flagged_nodes)||0} flagged`}),_.jsx(b_,{icon:MZ,label:"Regions",value:(e==null?void 0:e.total_regions)||0,subvalue:`${(e==null?void 0:e.battery_warnings)||0} battery warnings`})]})]})]}),_.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-3 gap-6",children:[_.jsxs("div",{className:"bg-bg-card border border-border rounded-lg p-6",children:[_.jsxs("h2",{className:"text-sm font-medium text-slate-400 mb-4",children:["Mesh Sources (",r.length,")"]}),r.length>0?_.jsx("div",{className:"space-y-2",children:r.map((I,k)=>_.jsx(YDe,{source:I},k))}):_.jsx("div",{className:"text-slate-500 py-4",children:"No sources configured"})]}),_.jsx(KDe,{swpc:c,ducting:h}),_.jsx(eNe,{events:l,envStatus:o})]})]})}/*! *****************************************************************************
+Copyright (c) Microsoft Corporation.
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+***************************************************************************** */var Ik=function(e,t){return Ik=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,n){r.__proto__=n}||function(r,n){for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(r[i]=n[i])},Ik(e,t)};function q(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");Ik(e,t);function r(){this.constructor=e}e.prototype=t===null?Object.create(t):(r.prototype=t.prototype,new r)}var zg=function(){return zg=Object.assign||function(t){for(var r,n=1,i=arguments.length;n0&&a[a.length-1])&&(u[0]===6||u[0]===2)){r=0;continue}if(u[0]===3&&(!a||u[1]>a[0]&&u[1]"u"&&typeof self<"u"?nt.worker=!0:!nt.hasGlobalWindow||"Deno"in window||typeof navigator<"u"&&typeof navigator.userAgent=="string"&&navigator.userAgent.indexOf("Node.js")>-1?(nt.node=!0,nt.svgSupported=!0):aNe(navigator.userAgent,nt);function aNe(e,t){var r=t.browser,n=e.match(/Firefox\/([\d.]+)/),i=e.match(/MSIE\s([\d.]+)/)||e.match(/Trident\/.+?rv:(([\d.]+))/),a=e.match(/Edge?\/([\d.]+)/),o=/micromessenger/i.test(e);n&&(r.firefox=!0,r.version=n[1]),i&&(r.ie=!0,r.version=i[1]),a&&(r.edge=!0,r.version=a[1],r.newEdge=+a[1].split(".")[0]>18),o&&(r.weChat=!0),t.svgSupported=typeof SVGRect<"u",t.touchEventsSupported="ontouchstart"in window&&!r.ie&&!r.edge,t.pointerEventsSupported="onpointerdown"in window&&(r.edge||r.ie&&+r.version>=11);var s=t.domSupported=typeof document<"u";if(s){var l=document.documentElement.style;t.transform3dSupported=(r.ie&&"transition"in l||r.edge||"WebKitCSSMatrix"in window&&"m11"in new WebKitCSSMatrix||"MozPerspective"in l)&&!("OTransition"in l),t.transformSupported=t.transform3dSupported||r.ie&&+r.version>=9}}var tN=12,gK="sans-serif",Bs=tN+"px "+gK,oNe=20,sNe=100,lNe="007LLmW'55;N0500LLLLLLLLLL00NNNLzWW\\\\WQb\\0FWLg\\bWb\\WQ\\WrWWQ000CL5LLFLL0LL**F*gLLLL5F0LF\\FFF5.5N";function uNe(e){var t={};if(typeof JSON>"u")return t;for(var r=0;r1&&n&&n.length>1){var a=cF(n)/cF(i);!isFinite(a)&&(a=1),t.pinchScale=a;var o=FNe(n);return t.pinchX=o[0],t.pinchY=o[1],{type:"pinch",target:e[0].target,event:t}}}}};function Wr(){return[1,0,0,1,0,0]}function i0(e){return e[0]=1,e[1]=0,e[2]=0,e[3]=1,e[4]=0,e[5]=0,e}function a0(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e}function Fa(e,t,r){var n=t[0]*r[0]+t[2]*r[1],i=t[1]*r[0]+t[3]*r[1],a=t[0]*r[2]+t[2]*r[3],o=t[1]*r[2]+t[3]*r[3],s=t[0]*r[4]+t[2]*r[5]+t[4],l=t[1]*r[4]+t[3]*r[5]+t[5];return e[0]=n,e[1]=i,e[2]=a,e[3]=o,e[4]=s,e[5]=l,e}function Ua(e,t,r){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4]+r[0],e[5]=t[5]+r[1],e}function qs(e,t,r,n){n===void 0&&(n=[0,0]);var i=t[0],a=t[2],o=t[4],s=t[1],l=t[3],u=t[5],c=Math.sin(r),f=Math.cos(r);return e[0]=i*f+s*c,e[1]=-i*c+s*f,e[2]=a*f+l*c,e[3]=-a*c+f*l,e[4]=f*(o-n[0])+c*(u-n[1])+n[0],e[5]=f*(u-n[1])-c*(o-n[0])+n[1],e}function mT(e,t,r){var n=r[0],i=r[1];return e[0]=t[0]*n,e[1]=t[1]*i,e[2]=t[2]*n,e[3]=t[3]*i,e[4]=t[4]*n,e[5]=t[5]*i,e}function da(e,t){var r=t[0],n=t[2],i=t[4],a=t[1],o=t[3],s=t[5],l=r*o-a*n;return l?(l=1/l,e[0]=o*l,e[1]=-a*l,e[2]=-n*l,e[3]=r*l,e[4]=(n*s-o*i)*l,e[5]=(a*i-r*s)*l,e):null}function MK(e){var t=Wr();return a0(t,e),t}const VNe=Object.freeze(Object.defineProperty({__proto__:null,clone:MK,copy:a0,create:Wr,identity:i0,invert:da,mul:Fa,rotate:qs,scale:mT,translate:Ua},Symbol.toStringTag,{value:"Module"}));var Ie=function(){function e(t,r){this.x=t||0,this.y=r||0}return e.prototype.copy=function(t){return this.x=t.x,this.y=t.y,this},e.prototype.clone=function(){return new e(this.x,this.y)},e.prototype.set=function(t,r){return this.x=t,this.y=r,this},e.prototype.equal=function(t){return t.x===this.x&&t.y===this.y},e.prototype.add=function(t){return this.x+=t.x,this.y+=t.y,this},e.prototype.scale=function(t){this.x*=t,this.y*=t},e.prototype.scaleAndAdd=function(t,r){this.x+=t.x*r,this.y+=t.y*r},e.prototype.sub=function(t){return this.x-=t.x,this.y-=t.y,this},e.prototype.dot=function(t){return this.x*t.x+this.y*t.y},e.prototype.len=function(){return Math.sqrt(this.x*this.x+this.y*this.y)},e.prototype.lenSquare=function(){return this.x*this.x+this.y*this.y},e.prototype.normalize=function(){var t=this.len();return this.x/=t,this.y/=t,this},e.prototype.distance=function(t){var r=this.x-t.x,n=this.y-t.y;return Math.sqrt(r*r+n*n)},e.prototype.distanceSquare=function(t){var r=this.x-t.x,n=this.y-t.y;return r*r+n*n},e.prototype.negate=function(){return this.x=-this.x,this.y=-this.y,this},e.prototype.transform=function(t){if(t){var r=this.x,n=this.y;return this.x=t[0]*r+t[2]*n+t[4],this.y=t[1]*r+t[3]*n+t[5],this}},e.prototype.toArray=function(t){return t[0]=this.x,t[1]=this.y,t},e.prototype.fromArray=function(t){this.x=t[0],this.y=t[1]},e.set=function(t,r,n){t.x=r,t.y=n},e.copy=function(t,r){t.x=r.x,t.y=r.y},e.len=function(t){return Math.sqrt(t.x*t.x+t.y*t.y)},e.lenSquare=function(t){return t.x*t.x+t.y*t.y},e.dot=function(t,r){return t.x*r.x+t.y*r.y},e.add=function(t,r,n){t.x=r.x+n.x,t.y=r.y+n.y},e.sub=function(t,r,n){t.x=r.x-n.x,t.y=r.y-n.y},e.scale=function(t,r,n){t.x=r.x*n,t.y=r.y*n},e.scaleAndAdd=function(t,r,n,i){t.x=r.x+n.x*i,t.y=r.y+n.y*i},e.lerp=function(t,r,n,i){var a=1-i;t.x=a*r.x+i*n.x,t.y=a*r.y+i*n.y},e}(),Cc=Math.min,Fh=Math.max,Bk=Math.abs,fF=["x","y"],GNe=["width","height"],ku=new Ie,Iu=new Ie,Ou=new Ie,Eu=new Ie,xi=PK(),hg=xi.minTv,zk=xi.maxTv,Gg=[0,0],Oe=function(){function e(t,r,n,i){e.set(this,t,r,n,i)}return e.set=function(t,r,n,i,a){return i<0&&(r=r+i,i=-i),a<0&&(n=n+a,a=-a),t.x=r,t.y=n,t.width=i,t.height=a,t},e.prototype.union=function(t){var r=Cc(t.x,this.x),n=Cc(t.y,this.y);isFinite(this.x)&&isFinite(this.width)?this.width=Fh(t.x+t.width,this.x+this.width)-r:this.width=t.width,isFinite(this.y)&&isFinite(this.height)?this.height=Fh(t.y+t.height,this.y+this.height)-n:this.height=t.height,this.x=r,this.y=n},e.prototype.applyTransform=function(t){e.applyTransform(this,this,t)},e.prototype.calculateTransform=function(t){var r=this,n=t.width/r.width,i=t.height/r.height,a=Wr();return Ua(a,a,[-r.x,-r.y]),mT(a,a,[n,i]),Ua(a,a,[t.x,t.y]),a},e.prototype.intersect=function(t,r,n){return e.intersect(this,t,r,n)},e.intersect=function(t,r,n,i){n&&Ie.set(n,0,0);var a=i&&i.outIntersectRect||null,o=i&&i.clamp;if(a&&(a.x=a.y=a.width=a.height=NaN),!t||!r)return!1;t instanceof e||(t=e.set(WNe,t.x,t.y,t.width,t.height)),r instanceof e||(r=e.set(HNe,r.x,r.y,r.width,r.height));var s=!!n;xi.reset(i,s);var l=xi.touchThreshold,u=t.x+l,c=t.x+t.width-l,f=t.y+l,h=t.y+t.height-l,d=r.x+l,v=r.x+r.width-l,g=r.y+l,m=r.y+r.height-l;if(u>c||f>h||d>v||g>m)return!1;var y=!(c0;)o=l,l=(l<<1)+1,l<=0&&(l=s);l>s&&(l=s),o+=i,l+=i}else{for(s=i+1;ls&&(l=s);var u=o;o=i-l,l=i-u}for(o++;o