|
|
@@ -1157,6 +1157,16 @@ function legendSvg() {
|
|
|
|
|
|
// Per-tick state update: flip LED/port/frame/flow classes in place —
|
|
|
// the SVG skeleton survives, so CSS animations keep running.
|
|
|
+// Power policy for fabric ports and their cable flows: a port is green only
|
|
|
+// when its switch reports ON (unknown is tolerated) AND the node is
|
|
|
+// occupied — an HA-OFF switch cannot carry traffic, so all of its ports
|
|
|
+// stay gray even if a node still reports a running container.
|
|
|
+/*TOPOPORT:START*/
|
|
|
+function fabPortOn(swOn, occupied) {
|
|
|
+ return swOn !== false && !!occupied;
|
|
|
+}
|
|
|
+/*TOPOPORT:END*/
|
|
|
+
|
|
|
function topoTick(snap) {
|
|
|
const t = snap.topo;
|
|
|
const ns = {};
|
|
|
@@ -1186,19 +1196,23 @@ function topoTick(snap) {
|
|
|
+ (s.ha === false ? " · plug OFF" : "")
|
|
|
+ (s.containers.length ? " · " + s.containers.map((x) => x.name).join(", ") : "");
|
|
|
}
|
|
|
+ const swStateOf = (ent) => t.states.find((x) => x.entity === ent)?.on;
|
|
|
for (const l of t.links) {
|
|
|
const fl = document.querySelector(`#topo path[data-flow="${CSS.escape(l.kind + "|" + l.a + "|" + l.b)}"]`);
|
|
|
if (!fl) continue;
|
|
|
const B = ns[l.b], A = l.kind === "dac" ? ns[l.a] : null;
|
|
|
fl.classList.toggle("live", l.kind === "10g" ? !!B?.reachable
|
|
|
- : l.kind === "200g" ? !!B?.occupied
|
|
|
+ : l.kind === "200g" ? fabPortOn(swStateOf(l.a), B?.occupied)
|
|
|
: !!(B?.occupied && A?.occupied));
|
|
|
}
|
|
|
for (const name of t.nodes) {
|
|
|
const lp = document.querySelector(`#topo rect[data-lanport="${CSS.escape(name)}"]`);
|
|
|
if (lp) lp.classList.toggle("on", !!ns[name]?.reachable);
|
|
|
const fp = document.querySelector(`#topo rect[data-fabport="${CSS.escape(name)}"]`);
|
|
|
- if (fp) fp.classList.toggle("on", !!ns[name]?.occupied);
|
|
|
+ if (fp) {
|
|
|
+ const swEnt = fp.closest("[data-sw]")?.dataset?.sw;
|
|
|
+ fp.classList.toggle("on", fabPortOn(swStateOf(swEnt), ns[name]?.occupied));
|
|
|
+ }
|
|
|
}
|
|
|
for (const sw of t.switches) {
|
|
|
const st = t.states.find((x) => x.entity === sw.entity);
|