DEV Community

linou518
linou518

Posted on

Fitting 22 Nodes on One Screen: Refactoring the Dashboard Node Management UI

Fitting 22 Nodes on One Screen: Refactoring the Dashboard Node Management UI

Real experience: 2026-03-21, improving a homelab management dashboard

Background: The Node Count Doubled

Our homelab quietly grew to 22 machines — Raspberry Pis, GMK mini PCs, a Mac mini, dedicated infrastructure boxes. The management UI was originally designed for about 10 nodes, and it had become a scrolling nightmare.

The expansion happened in one push: 10 new GMK mini PCs joined the fleet as agent01 through agent10 with sequential IPs. On top of that, a Mac mini had its IP reassigned and one node got renamed. The dashboard's "Node Management" page had node master data hardcoded in two places — server-side (Flask) and client-side (Vanilla JS). Both were stale.

What I Did

1. Syncing Master Data

Node definitions lived in two places: NODES_REGISTRY in server.py and getLocalNodeData() in the frontend JavaScript. Maintaining both manually is painful, but I kept it simple this time and just updated both.

Changes:

  • Reflected node renames
  • Added the dedicated gateway node
  • Added all 10 new agent nodes
  • Updated NODE_ORDER array to the full 22-node sequence
# Excerpt from server.py (IPs omitted)
NODES_REGISTRY = {
    "node-a":   {"gatewayPort": 18789, "agents": ["main-agent"]},
    "node-b":   {"gatewayPort": 18789, "agents": ["sub-agent"]},
    "infra":    {"gatewayPort": 18788, "agents": ["shadow"]},
    "agent01":  {"gatewayPort": 18789,
                 "agents": ["aws-expert", "gcp-expert", "snowflake-expert"]},
    # ... all 22 nodes
}
Enter fullscreen mode Exit fullscreen mode

2. Collapsible Action Buttons

Each node card had 9 action buttons (restart, status check, agent management, etc.) permanently visible. With 22 cards, the buttons alone filled the screen.

The fix: accordion-style collapsing. One click expands the action area.

function nmToggleActions(nodeId) {
    const body = document.querySelector(`#node-${nodeId} .nm-actions-body`);
    const toggle = document.querySelector(`#node-${nodeId} .nm-actions-toggle`);
    const isOpen = body.classList.contains('open');
    body.classList.toggle('open', !isOpen);
    toggle.textContent = isOpen ? '⚙️ Actions ▼' : '⚙️ Actions ▲';
}
Enter fullscreen mode Exit fullscreen mode

CSS is dead simple:

.nm-actions-body {
    display: none;
}
.nm-actions-body.open {
    display: block;
}
Enter fullscreen mode Exit fullscreen mode

Clean card grid by default, action UI on demand.

Reflections

"Don't keep data in two places" is one of those truths everyone knows but nobody fixes until it bites them. Today it bit me. Manually syncing 22 nodes across two files was tedious.

The proper solution is a single /api/nodes endpoint on the server, with the frontend fetching from it. I scoped this round to "just make it work" but plan to refactor next time.

The collapsible UI was pure HTML class toggling — no libraries. Vanilla JS handles this perfectly fine, and fewer dependencies means easier maintenance.

Summary

  • 22 nodes now fit on one screen without scrolling ✅
  • Action buttons collapse into accordions ✅
  • Dual master data is acknowledged tech debt

A homelab dashboard is unglamorous but it's something you look at every day. Small UX improvements compound. "See all 22 nodes without scrolling" sounds trivial, but fixing it changes how the whole thing feels.

Top comments (0)