Merge branch 'feature/mesh-intelligence'

This commit is contained in:
Matt Johnson (via Claude) 2026-06-10 03:56:24 +00:00
commit c1df20b871
6 changed files with 108 additions and 68 deletions

View file

@ -19,6 +19,7 @@ export interface MeshHealth {
pillars: { pillars: {
infrastructure: number infrastructure: number
utilization: number utilization: number
coverage: number
behavior: number behavior: number
power: number power: number
} }

View file

@ -696,6 +696,7 @@ export default function Dashboard() {
<div className="mt-6 space-y-3"> <div className="mt-6 space-y-3">
<PillarBar label="Infrastructure" value={health.pillars?.infrastructure ?? 0} /> <PillarBar label="Infrastructure" value={health.pillars?.infrastructure ?? 0} />
<PillarBar label="Utilization" value={health.pillars?.utilization ?? 0} /> <PillarBar label="Utilization" value={health.pillars?.utilization ?? 0} />
<PillarBar label="Coverage" value={health.pillars?.coverage ?? 0} />
<PillarBar label="Behavior" value={health.pillars?.behavior ?? 0} /> <PillarBar label="Behavior" value={health.pillars?.behavior ?? 0} />
<PillarBar label="Power" value={health.pillars?.power ?? 0} /> <PillarBar label="Power" value={health.pillars?.power ?? 0} />
</div> </div>
@ -714,12 +715,48 @@ export default function Dashboard() {
<AlertItem key={i} alert={alert} /> <AlertItem key={i} alert={alert} />
))} ))}
</div> </div>
) : ( ) : (() => {
<div className="flex items-center gap-2 text-slate-500 py-4"> const highSeverityEnv = envEvents
<CheckCircle size={16} className="text-green-500" /> .filter(e => e.severity === 'immediate' || e.severity === 'priority')
<span>No active alerts</span> .sort((a, b) => {
</div> const ord: Record<string, number> = { immediate: 0, priority: 1 }
)} const diff = (ord[a.severity] ?? 2) - (ord[b.severity] ?? 2)
if (diff !== 0) return diff
return (b.fetched_at || 0) - (a.fetched_at || 0)
})
.slice(0, 5)
if (highSeverityEnv.length > 0) {
return (
<div className="space-y-3 max-h-48 overflow-y-auto">
{highSeverityEnv.map((ev, i) => {
const sevStyle = ev.severity === 'immediate'
? { bg: 'bg-red-500/10', border: 'border-red-500', icon: AlertCircle, iconColor: 'text-red-500' }
: { bg: 'bg-amber-500/10', border: 'border-amber-500', icon: AlertTriangle, iconColor: 'text-amber-500' }
const Icon = sevStyle.icon
return (
<div key={ev.event_id || i} className={`p-3 rounded-lg ${sevStyle.bg} border-l-2 ${sevStyle.border} flex items-start gap-3`}>
<Icon size={16} className={sevStyle.iconColor} />
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<span className="px-1.5 py-0.5 rounded text-xs bg-slate-500/20 text-slate-400 border border-slate-500/30 font-mono">ENV</span>
<span className="text-xs text-slate-500">{ev.severity}</span>
</div>
<div className="text-sm text-slate-200 mt-1">{ev.headline}</div>
<div className="text-xs text-slate-500 mt-1">{ev.source} · {new Date(ev.fetched_at * 1000).toLocaleTimeString()}</div>
</div>
</div>
)
})}
</div>
)
}
return (
<div className="flex items-center gap-2 text-slate-500 py-4">
<CheckCircle size={16} className="text-green-500" />
<span>No active alerts</span>
</div>
)
})()}
</div> </div>
{/* Quick Stats */} {/* Quick Stats */}

View file

@ -15,6 +15,7 @@ def _serialize_health_score(score) -> dict:
"tier": score.tier, "tier": score.tier,
"infrastructure": round(score.infrastructure, 1), "infrastructure": round(score.infrastructure, 1),
"utilization": round(score.utilization, 1), "utilization": round(score.utilization, 1),
"coverage": round(score.coverage, 1),
"behavior": round(score.behavior, 1), "behavior": round(score.behavior, 1),
"power": round(score.power, 1), "power": round(score.power, 1),
"infra_online": score.infra_online, "infra_online": score.infra_online,
@ -73,6 +74,7 @@ async def get_health(request: Request):
"pillars": { "pillars": {
"infrastructure": round(score.infrastructure, 1), "infrastructure": round(score.infrastructure, 1),
"utilization": round(score.utilization, 1), "utilization": round(score.utilization, 1),
"coverage": round(score.coverage, 1),
"behavior": round(score.behavior, 1), "behavior": round(score.behavior, 1),
"power": round(score.power, 1), "power": round(score.power, 1),
}, },

View file

@ -8,8 +8,8 @@
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<script type="module" crossorigin src="/assets/index-CM6OazXs.js"></script> <script type="module" crossorigin src="/assets/index-BCcZxs_h.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Dp9XCfH-.css"> <link rel="stylesheet" crossorigin href="/assets/index-BEgceSNC.css">
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>