feat(web): show MazeNET decky running count + roll into dashboard
MazeNET header now reports '{running}/{total} DECKIES RUNNING' so
operators can see per-topology runtime status at a glance.
Dashboard ACTIVE DECKIES counters used to reflect only the fleet state
file; TopologyDecky rows (MazeNET deployments) are now added in —
deployed_deckies = fleet + all topology rows, active_deckies = fleet
(no runtime field) + topology rows whose state is 'running'.
This commit is contained in:
@@ -349,15 +349,27 @@ class SQLModelRepository(BaseRepository):
|
|||||||
select(func.count(func.distinct(Log.attacker_ip)))
|
select(func.count(func.distinct(Log.attacker_ip)))
|
||||||
)
|
)
|
||||||
).scalar() or 0
|
).scalar() or 0
|
||||||
|
topo_total = (
|
||||||
|
await session.execute(select(func.count()).select_from(TopologyDecky))
|
||||||
|
).scalar() or 0
|
||||||
|
topo_running = (
|
||||||
|
await session.execute(
|
||||||
|
select(func.count())
|
||||||
|
.select_from(TopologyDecky)
|
||||||
|
.where(TopologyDecky.state == "running")
|
||||||
|
)
|
||||||
|
).scalar() or 0
|
||||||
|
|
||||||
_state = await asyncio.to_thread(load_state)
|
_state = await asyncio.to_thread(load_state)
|
||||||
deployed_deckies = len(_state[0].deckies) if _state else 0
|
fleet_deckies = len(_state[0].deckies) if _state else 0
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"total_logs": total_logs,
|
"total_logs": total_logs,
|
||||||
"unique_attackers": unique_attackers,
|
"unique_attackers": unique_attackers,
|
||||||
"active_deckies": deployed_deckies,
|
# Fleet state file doesn't track per-decky runtime; treat all
|
||||||
"deployed_deckies": deployed_deckies,
|
# fleet rows as active and add MazeNET running rows on top.
|
||||||
|
"active_deckies": fleet_deckies + topo_running,
|
||||||
|
"deployed_deckies": fleet_deckies + topo_total,
|
||||||
}
|
}
|
||||||
|
|
||||||
async def get_deckies(self) -> List[dict]:
|
async def get_deckies(self) -> List[dict]:
|
||||||
|
|||||||
@@ -529,6 +529,8 @@ const MazeNET: React.FC = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const canDeploy = topoStatus === 'pending' && nets.length > 0;
|
const canDeploy = topoStatus === 'pending' && nets.length > 0;
|
||||||
|
const deckyNodes = nodes.filter((n) => n.kind === 'decky');
|
||||||
|
const runningDeckies = deckyNodes.filter((n) => n.status === 'active').length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="maze-page">
|
<div className="maze-page">
|
||||||
@@ -537,7 +539,8 @@ const MazeNET: React.FC = () => {
|
|||||||
<h1>MAZENET · {topoName || topologyId}</h1>
|
<h1>MAZENET · {topoName || topologyId}</h1>
|
||||||
<div className="maze-page-sub">
|
<div className="maze-page-sub">
|
||||||
NETWORK OF NETWORKS · {topoStatus.toUpperCase()} · v{topoVersion} ·{' '}
|
NETWORK OF NETWORKS · {topoStatus.toUpperCase()} · v{topoVersion} ·{' '}
|
||||||
{nets.length} NETS · {nodes.length} NODES · {edges.length} PATHS
|
{nets.length} NETS · {nodes.length} NODES · {edges.length} PATHS ·{' '}
|
||||||
|
{runningDeckies}/{deckyNodes.length} DECKIES RUNNING
|
||||||
{streamEnabled && (
|
{streamEnabled && (
|
||||||
<span className="alert-text" style={{ color: streamLive ? undefined : 'var(--fg-dim)' }}>
|
<span className="alert-text" style={{ color: streamLive ? undefined : 'var(--fg-dim)' }}>
|
||||||
{' '}· {streamLive ? 'LIVE' : 'CONNECTING…'}
|
{' '}· {streamLive ? 'LIVE' : 'CONNECTING…'}
|
||||||
|
|||||||
Reference in New Issue
Block a user