|
@@ -44,6 +44,9 @@
|
|
|
|
|
|
|
|
function el(id) { return document.getElementById(id); }
|
|
function el(id) { return document.getElementById(id); }
|
|
|
function t(k, d) { return (T[k] != null) ? T[k] : (d != null ? d : k); }
|
|
function t(k, d) { return (T[k] != null) ? T[k] : (d != null ? d : k); }
|
|
|
|
|
+ // PoE is a capability flag written by the collector's SNMP probe. The
|
|
|
|
|
+ // lightning mark is display-only, like the topology itself.
|
|
|
|
|
+ function poePrefix(n) { return (n && n.poe) ? '\u26A1\uFE0F ' : ''; }
|
|
|
|
|
|
|
|
/* ---------------- name parsing / grouping ---------------- */
|
|
/* ---------------- name parsing / grouping ---------------- */
|
|
|
function parseName(name) {
|
|
function parseName(name) {
|
|
@@ -77,16 +80,18 @@
|
|
|
if (p.floor) { var loc = p.floor + 'F' + (p.cab || '') + (p.u ? '-' + p.u + 'U' : ''); l1.push(loc); }
|
|
if (p.floor) { var loc = p.floor + 'F' + (p.cab || '') + (p.u ? '-' + p.u + 'U' : ''); l1.push(loc); }
|
|
|
if (p.role) l2.push(p.role);
|
|
if (p.role) l2.push(p.role);
|
|
|
l2.push(n.ip);
|
|
l2.push(n.ip);
|
|
|
- return l1.join(' · ') + '\n' + l2.join(' · ');
|
|
|
|
|
|
|
+ return poePrefix(n) + l1.join(' · ') + '\n' + l2.join(' · ');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function detailLabel(n) {
|
|
function detailLabel(n) {
|
|
|
|
|
+ var pre = poePrefix(n);
|
|
|
var s = labelFor(n);
|
|
var s = labelFor(n);
|
|
|
|
|
+ if (pre && s.indexOf(pre) === 0) s = s.slice(pre.length);
|
|
|
if (viewGroup) {
|
|
if (viewGroup) {
|
|
|
var p = viewGroup + ' · ';
|
|
var p = viewGroup + ' · ';
|
|
|
if (s.indexOf(p) === 0) s = s.substring(p.length);
|
|
if (s.indexOf(p) === 0) s = s.substring(p.length);
|
|
|
}
|
|
}
|
|
|
- return s;
|
|
|
|
|
|
|
+ return pre + s;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function rowLabel(n) {
|
|
function rowLabel(n) {
|
|
@@ -95,14 +100,16 @@
|
|
|
if (viewGroup) {
|
|
if (viewGroup) {
|
|
|
try { s = s.replace(new RegExp('^' + viewGroup + '-', 'i'), ''); } catch (e) {}
|
|
try { s = s.replace(new RegExp('^' + viewGroup + '-', 'i'), ''); } catch (e) {}
|
|
|
}
|
|
}
|
|
|
- return s;
|
|
|
|
|
|
|
+ return poePrefix(n) + s;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function rootLabel(n) {
|
|
function rootLabel(n) {
|
|
|
|
|
+ var pre = poePrefix(n);
|
|
|
var s = rowLabel(n);
|
|
var s = rowLabel(n);
|
|
|
|
|
+ if (pre && s.indexOf(pre) === 0) s = s.slice(pre.length);
|
|
|
var m = /^(.+?)-(SURVE|OFFICE|OTHER)-(Dist|Access)-(.+)$/i.exec(s);
|
|
var m = /^(.+?)-(SURVE|OFFICE|OTHER)-(Dist|Access)-(.+)$/i.exec(s);
|
|
|
- if (m) return m[2].toUpperCase() + ' · ' + m[1] + '\n' + m[3] + ' · ' + m[4];
|
|
|
|
|
- return s;
|
|
|
|
|
|
|
+ if (m) return pre + m[2].toUpperCase() + ' · ' + m[1] + '\n' + m[3] + ' · ' + m[4];
|
|
|
|
|
+ return pre + s;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function expandLabel(tpl, m) {
|
|
function expandLabel(tpl, m) {
|
|
@@ -622,10 +629,14 @@
|
|
|
|
|
|
|
|
function switchLabel(n, role, netKey) {
|
|
function switchLabel(n, role, netKey) {
|
|
|
var g = groupOf(n).label;
|
|
var g = groupOf(n).label;
|
|
|
- if (role === 'core') return roleName('core') + ' · ' + (netKey || rawNetOf(n)) + ' · ' + (n.ip || '');
|
|
|
|
|
- if (role === 'main') return roleName('main') + ' · ' + g + ' · ' + (n.ip || '');
|
|
|
|
|
- var loc = shortLoc(n);
|
|
|
|
|
- return [g, loc, roleName(role)].filter(Boolean).join(' · ') + ' · ' + (n.ip || '');
|
|
|
|
|
|
|
+ var s;
|
|
|
|
|
+ if (role === 'core') s = roleName('core') + ' · ' + (netKey || rawNetOf(n)) + ' · ' + (n.ip || '');
|
|
|
|
|
+ else if (role === 'main') s = roleName('main') + ' · ' + g + ' · ' + (n.ip || '');
|
|
|
|
|
+ else {
|
|
|
|
|
+ var loc = shortLoc(n);
|
|
|
|
|
+ s = [g, loc, roleName(role)].filter(Boolean).join(' · ') + ' · ' + (n.ip || '');
|
|
|
|
|
+ }
|
|
|
|
|
+ return poePrefix(n) + s;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// A workshop is the physical area served by one distribution switch, not
|
|
// A workshop is the physical area served by one distribution switch, not
|
|
@@ -929,6 +940,16 @@
|
|
|
if (s >= 1000) return 2.6;
|
|
if (s >= 1000) return 2.6;
|
|
|
return 1.8;
|
|
return 1.8;
|
|
|
}
|
|
}
|
|
|
|
|
+ // Animation speed (pixels per 60Hz frame) by link rate. The visible
|
|
|
|
|
+ // flow is only an overlay; the protocol/display link itself never changes.
|
|
|
|
|
+ function flowRate(speed) {
|
|
|
|
|
+ var s = parseFloat(speed) || 0;
|
|
|
|
|
+ if (s >= 20000) return 4.6;
|
|
|
|
|
+ if (s >= 10000) return 3.4;
|
|
|
|
|
+ if (s >= 1000) return 2.0;
|
|
|
|
|
+ if (s > 0) return 0.9;
|
|
|
|
|
+ return 0.6;
|
|
|
|
|
+ }
|
|
|
function speedText(speed) {
|
|
function speedText(speed) {
|
|
|
var s = parseFloat(speed) || 0;
|
|
var s = parseFloat(speed) || 0;
|
|
|
if (!s) return '?';
|
|
if (!s) return '?';
|
|
@@ -1079,6 +1100,15 @@
|
|
|
'source-endpoint': '0% 50%', 'target-endpoint': '0% 50%',
|
|
'source-endpoint': '0% 50%', 'target-endpoint': '0% 50%',
|
|
|
'target-arrow-shape': 'none', 'z-index-compare': 'manual', 'z-index': 1
|
|
'target-arrow-shape': 'none', 'z-index-compare': 'manual', 'z-index': 1
|
|
|
}},
|
|
}},
|
|
|
|
|
+ // Moving data-flow overlay. The base line keeps its speed colour; this
|
|
|
|
|
+ // thin dashed line runs on top and is animated downstream (core -> leaf).
|
|
|
|
|
+ {selector: 'edge[type="flow"]', style: {
|
|
|
|
|
+ 'width': 'data(fw)', 'line-color': d ? '#EDFFFC' : '#0E4B46',
|
|
|
|
|
+ 'line-style': 'dashed', 'line-dash-pattern': [4, 10], 'line-dash-offset': 0,
|
|
|
|
|
+ 'opacity': d ? 0.68 : 0.52, 'curve-style': 'straight',
|
|
|
|
|
+ 'source-endpoint': '0% 50%', 'target-endpoint': '0% 50%',
|
|
|
|
|
+ 'target-arrow-shape': 'none', 'events': 'no', 'z-index-compare': 'manual', 'z-index': 3
|
|
|
|
|
+ }},
|
|
|
{selector: 'edge[type="term"]', style: {
|
|
{selector: 'edge[type="term"]', style: {
|
|
|
'width': 0.7, 'line-color': d ? '#3b4a5e' : '#c5cfdb', 'opacity': 0.55,
|
|
'width': 0.7, 'line-color': d ? '#3b4a5e' : '#c5cfdb', 'opacity': 0.55,
|
|
|
'curve-style': 'bezier', 'z-index-compare': 'manual', 'z-index': 11
|
|
'curve-style': 'bezier', 'z-index-compare': 'manual', 'z-index': 11
|
|
@@ -1147,6 +1177,34 @@
|
|
|
if (keepView) { cy.zoom(z); cy.pan(p); }
|
|
if (keepView) { cy.zoom(z); cy.pan(p); }
|
|
|
else { initialView(); }
|
|
else { initialView(); }
|
|
|
}
|
|
}
|
|
|
|
|
+ startFlow();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Data-flow animation. Each flow overlay has its own rate (link speed), so
|
|
|
|
|
+ // a 10G/20G link visibly moves faster than a 100M/1G link. This only
|
|
|
|
|
+ // changes the visual dash phase; no topology/state is touched.
|
|
|
|
|
+ var flowRaf = null, flowLast = 0;
|
|
|
|
|
+ function startFlow() {
|
|
|
|
|
+ if (flowRaf != null) return;
|
|
|
|
|
+ flowRaf = requestAnimationFrame(flowTick);
|
|
|
|
|
+ }
|
|
|
|
|
+ function flowTick(ts) {
|
|
|
|
|
+ if (!cy) { flowRaf = null; return; }
|
|
|
|
|
+ var dt = flowLast ? Math.min(80, ts - flowLast) : 16;
|
|
|
|
|
+ flowLast = ts;
|
|
|
|
|
+ if (!document.hidden) {
|
|
|
|
|
+ cy.batch(function () {
|
|
|
|
|
+ cy.edges('[type="flow"]').forEach(function (e) {
|
|
|
|
|
+ var rate = parseFloat(e.data('flowRate')) || 0.6;
|
|
|
|
|
+ var off = (e.scratch('flowOffset') || 0) - rate * dt / 16;
|
|
|
|
|
+ off = off % 14;
|
|
|
|
|
+ if (off < 0) off += 14;
|
|
|
|
|
+ e.scratch('flowOffset', off);
|
|
|
|
|
+ e.style('line-dash-offset', off);
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ flowRaf = requestAnimationFrame(flowTick);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function fitGroup(label) {
|
|
function fitGroup(label) {
|
|
@@ -1215,6 +1273,7 @@
|
|
|
id: n.id, type: 'switch', name: n.name, ip: n.ip, tier: n.tier, depth: n.depth, hostid: n.hostid, oper: n.oper,
|
|
id: n.id, type: 'switch', name: n.name, ip: n.ip, tier: n.tier, depth: n.depth, hostid: n.hostid, oper: n.oper,
|
|
|
offline: !!(n.offline || n.oper === 'down'), last_online: n.last_online,
|
|
offline: !!(n.offline || n.oper === 'down'), last_online: n.last_online,
|
|
|
maxsev: n.maxsev, alarms: n.alarms || [], term_online: n.term_online, term_offline: 0, latency_ms: n.latency_ms,
|
|
maxsev: n.maxsev, alarms: n.alarms || [], term_online: n.term_online, term_offline: 0, latency_ms: n.latency_ms,
|
|
|
|
|
+ poe: !!n.poe,
|
|
|
label: switchLabel(n, p.role, p.net), tw: p.w - 12, bg: bg, bd: bd, w: p.w, h: p.h,
|
|
label: switchLabel(n, p.role, p.net), tw: p.w - 12, bg: bg, bd: bd, w: p.w, h: p.h,
|
|
|
group: p.group + ' · ' + netLabel(p.net), blockGroup: p.group, net: p.net, role: p.role
|
|
group: p.group + ' · ' + netLabel(p.net), blockGroup: p.group, net: p.net, role: p.role
|
|
|
}, position: {x: p.x, y: p.y}, classes: cls.join(' ')});
|
|
}, position: {x: p.x, y: p.y}, classes: cls.join(' ')});
|
|
@@ -1238,6 +1297,17 @@
|
|
|
speed: e.speed, state: e.state, a_port: e.a_port, b_port: e.b_port,
|
|
speed: e.speed, state: e.state, a_port: e.a_port, b_port: e.b_port,
|
|
|
color: col, ls: (e.state && e.state !== 'up') ? 'dashed' : 'solid', w: Math.min(4, speedWidth(e.speed))
|
|
color: col, ls: (e.state && e.state !== 'up') ? 'dashed' : 'solid', w: Math.min(4, speedWidth(e.speed))
|
|
|
}});
|
|
}});
|
|
|
|
|
+ if (e.state === 'up') {
|
|
|
|
|
+ var from = e.source, to = e.target;
|
|
|
|
|
+ var sd = parseInt(ps.node && ps.node.depth, 10), td = parseInt(pt.node && pt.node.depth, 10);
|
|
|
|
|
+ if (td < sd || (td === sd && pt.y < ps.y)) { from = e.target; to = e.source; }
|
|
|
|
|
+ var fsp = (from === e.source) ? sp : tp, ftp = (to === e.source) ? sp : tp;
|
|
|
|
|
+ els.push({group: 'edges', data: {
|
|
|
|
|
+ id: 'f_' + i, type: 'flow', source: fsp, target: ftp, p: e.source, c: e.target,
|
|
|
|
|
+ speed: e.speed, state: e.state, a_port: e.a_port, b_port: e.b_port,
|
|
|
|
|
+ flowRate: flowRate(e.speed), fw: Math.max(0.9, Math.min(1.5, speedWidth(e.speed) * 0.35))
|
|
|
|
|
+ }});
|
|
|
|
|
+ }
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
if (showTerm) addTerminals(L, byId, els);
|
|
if (showTerm) addTerminals(L, byId, els);
|
|
@@ -1374,6 +1444,7 @@
|
|
|
id: n.id, type: 'switch', name: n.name, ip: n.ip, tier: tier, depth: n.depth,
|
|
id: n.id, type: 'switch', name: n.name, ip: n.ip, tier: tier, depth: n.depth,
|
|
|
hostid: n.hostid, oper: n.oper, maxsev: n.maxsev, alarms: n.alarms || [],
|
|
hostid: n.hostid, oper: n.oper, maxsev: n.maxsev, alarms: n.alarms || [],
|
|
|
term_online: n.term_online, term_offline: n.term_offline, latency_ms: n.latency_ms,
|
|
term_online: n.term_online, term_offline: n.term_offline, latency_ms: n.latency_ms,
|
|
|
|
|
+ poe: !!n.poe,
|
|
|
label: isRoot ? rootLabel(n) : rowLabel(n), tw: isRoot ? 150 : 360,
|
|
label: isRoot ? rootLabel(n) : rowLabel(n), tw: isRoot ? 150 : 360,
|
|
|
bg: bg, bd: isRoot ? bd : '#25501e',
|
|
bg: bg, bd: isRoot ? bd : '#25501e',
|
|
|
w: isRoot ? 170 : 380, h: isRoot ? 50 : 24, group: viewGroup
|
|
w: isRoot ? 170 : 380, h: isRoot ? 50 : 24, group: viewGroup
|
|
@@ -1396,6 +1467,13 @@
|
|
|
color: speedColor(e.speed, e.state), ls: (e.state && e.state !== 'up') ? 'dashed' : 'solid',
|
|
color: speedColor(e.speed, e.state), ls: (e.state && e.state !== 'up') ? 'dashed' : 'solid',
|
|
|
w: Math.min(2.4, speedWidth(e.speed))
|
|
w: Math.min(2.4, speedWidth(e.speed))
|
|
|
}, classes: 'detail'});
|
|
}, classes: 'detail'});
|
|
|
|
|
+ if (e.state === 'up') {
|
|
|
|
|
+ els.push({group: 'edges', data: {
|
|
|
|
|
+ id: 'f_' + i, type: 'flow', source: sp, target: tp, p: root.id, c: childId,
|
|
|
|
|
+ speed: e.speed, state: e.state, a_port: e.a_port, b_port: e.b_port,
|
|
|
|
|
+ flowRate: flowRate(e.speed), fw: Math.max(0.9, Math.min(1.4, speedWidth(e.speed) * 0.35))
|
|
|
|
|
+ }});
|
|
|
|
|
+ }
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -1405,6 +1483,18 @@
|
|
|
color: speedColor(e.speed, e.state), ls: (e.state && e.state !== 'up') ? 'dashed' : 'solid',
|
|
color: speedColor(e.speed, e.state), ls: (e.state && e.state !== 'up') ? 'dashed' : 'solid',
|
|
|
w: Math.min(2.4, speedWidth(e.speed))
|
|
w: Math.min(2.4, speedWidth(e.speed))
|
|
|
}, classes: 'detail'});
|
|
}, classes: 'detail'});
|
|
|
|
|
+ if (e.state === 'up') {
|
|
|
|
|
+ var from = e.source, to = e.target;
|
|
|
|
|
+ var ap = D.pos[e.source], bp = D.pos[e.target], po = D.parentOf || {};
|
|
|
|
|
+ if (po[e.source] === e.target) { from = e.target; to = e.source; }
|
|
|
|
|
+ else if (po[e.target] === e.source) { from = e.source; to = e.target; }
|
|
|
|
|
+ else if (ap && bp && bp.y < ap.y) { from = e.target; to = e.source; }
|
|
|
|
|
+ els.push({group: 'edges', data: {
|
|
|
|
|
+ id: 'f_' + i, type: 'flow', source: from, target: to, p: e.source, c: e.target,
|
|
|
|
|
+ speed: e.speed, state: e.state, a_port: e.a_port, b_port: e.b_port,
|
|
|
|
|
+ flowRate: flowRate(e.speed), fw: Math.max(0.9, Math.min(1.4, speedWidth(e.speed) * 0.35))
|
|
|
|
|
+ }});
|
|
|
|
|
+ }
|
|
|
});
|
|
});
|
|
|
if (showTerm) {
|
|
if (showTerm) {
|
|
|
var bySw = {};
|
|
var bySw = {};
|
|
@@ -1518,7 +1608,7 @@
|
|
|
var roleTxt = role === 'dist' ? t('l2.dist', 'Distribution') : t('l2.access', 'Access');
|
|
var roleTxt = role === 'dist' ? t('l2.dist', 'Distribution') : t('l2.access', 'Access');
|
|
|
h += '<div class="off-row sw-row" data-id="' + esc(n.id) + '">' +
|
|
h += '<div class="off-row sw-row" data-id="' + esc(n.id) + '">' +
|
|
|
'<span class="term-dot" style="background:#C0392B"></span>' +
|
|
'<span class="term-dot" style="background:#C0392B"></span>' +
|
|
|
- '<div class="off-main"><div class="off-mac">' + esc(n.name || n.ip) + '</div>' +
|
|
|
|
|
|
|
+ '<div class="off-main"><div class="off-mac">' + esc(poePrefix(n) + (n.name || n.ip)) + '</div>' +
|
|
|
'<div class="off-sub">' + esc(roleTxt) + ' · ' + esc(n.ip || '') +
|
|
'<div class="off-sub">' + esc(roleTxt) + ' · ' + esc(n.ip || '') +
|
|
|
' · ' + t('l2.last_online', 'last online') + ': ' + esc(fmtTs(n.last_online)) + '</div></div></div>';
|
|
' · ' + t('l2.last_online', 'last online') + ': ' + esc(fmtTs(n.last_online)) + '</div></div></div>';
|
|
|
});
|
|
});
|
|
@@ -1635,10 +1725,14 @@
|
|
|
var btn = el('l2-export'), oldText = btn ? btn.textContent : '';
|
|
var btn = el('l2-export'), oldText = btn ? btn.textContent : '';
|
|
|
if (btn) { btn.disabled = true; btn.textContent = t('l2.exporting', '正在导出…'); }
|
|
if (btn) { btn.disabled = true; btn.textContent = t('l2.exporting', '正在导出…'); }
|
|
|
var wasDark = dark;
|
|
var wasDark = dark;
|
|
|
|
|
+ var flowEdges = cy.edges('[type="flow"]');
|
|
|
try {
|
|
try {
|
|
|
// The exported file must always be the day palette, even when the
|
|
// The exported file must always be the day palette, even when the
|
|
|
- // operator is currently using Zabbix dark mode.
|
|
|
|
|
|
|
+ // operator is currently using Zabbix dark mode. The moving flow
|
|
|
|
|
+ // overlay is transient screen decoration, so keep the exported static
|
|
|
|
|
+ // diagram on solid speed-coloured links.
|
|
|
cy.elements().removeClass('hl dim pathhl');
|
|
cy.elements().removeClass('hl dim pathhl');
|
|
|
|
|
+ flowEdges.style('display', 'none');
|
|
|
cy.style(styleFor(false));
|
|
cy.style(styleFor(false));
|
|
|
if (typeof cy.forceRender === 'function') cy.forceRender();
|
|
if (typeof cy.forceRender === 'function') cy.forceRender();
|
|
|
var data = cy.png({full: true, scale: 1, maxWidth: 2600, maxHeight: 18000, bg: '#ffffff'});
|
|
var data = cy.png({full: true, scale: 1, maxWidth: 2600, maxHeight: 18000, bg: '#ffffff'});
|
|
@@ -1656,6 +1750,7 @@
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
window.alert(t('l2.export_fail', '导出失败,请重试。'));
|
|
window.alert(t('l2.export_fail', '导出失败,请重试。'));
|
|
|
} finally {
|
|
} finally {
|
|
|
|
|
+ flowEdges.style('display', 'element');
|
|
|
cy.style(styleFor(wasDark));
|
|
cy.style(styleFor(wasDark));
|
|
|
if (typeof cy.forceRender === 'function') cy.forceRender();
|
|
if (typeof cy.forceRender === 'function') cy.forceRender();
|
|
|
if (btn) { btn.disabled = false; btn.textContent = oldText; }
|
|
if (btn) { btn.disabled = false; btn.textContent = oldText; }
|
|
@@ -1754,6 +1849,7 @@
|
|
|
});
|
|
});
|
|
|
nodes.removeClass('dim').addClass('pathhl');
|
|
nodes.removeClass('dim').addClass('pathhl');
|
|
|
var edges = cy.edges().filter(function (e) {
|
|
var edges = cy.edges().filter(function (e) {
|
|
|
|
|
+ if (e.data('type') === 'flow') return false;
|
|
|
var p = e.data('p'), c = e.data('c');
|
|
var p = e.data('p'), c = e.data('c');
|
|
|
return p && c && (up.edges[p + '|' + c] || up.edges[c + '|' + p]);
|
|
return p && c && (up.edges[p + '|' + c] || up.edges[c + '|' + p]);
|
|
|
});
|
|
});
|
|
@@ -1768,7 +1864,7 @@
|
|
|
var sev = (d.maxsev != null && d.maxsev >= 0) ? ('<span style="color:' + SEV_COLORS[d.maxsev] + '">● ' + SEV_NAMES[d.maxsev] + '</span>') : '—';
|
|
var sev = (d.maxsev != null && d.maxsev >= 0) ? ('<span style="color:' + SEV_COLORS[d.maxsev] + '">● ' + SEV_NAMES[d.maxsev] + '</span>') : '—';
|
|
|
var lat = (d.latency_ms != null) ? (d.latency_ms + ' ms') : '—';
|
|
var lat = (d.latency_ms != null) ? (d.latency_ms + ' ms') : '—';
|
|
|
var stat = (d.offline || d.oper === 'down') ? ('<span style="color:#E45959">' + esc(t('l2.offline', 'Offline')) + '</span>') : esc(d.oper || 'up');
|
|
var stat = (d.offline || d.oper === 'down') ? ('<span style="color:#E45959">' + esc(t('l2.offline', 'Offline')) + '</span>') : esc(d.oper || 'up');
|
|
|
- var html = '<b>' + esc(d.name) + '</b><br>' + esc(d.ip) + ' · ' + esc(d.group || '') + '<br>' +
|
|
|
|
|
|
|
+ var html = '<b>' + esc(poePrefix({poe: d.poe}) + d.name) + '</b><br>' + esc(d.ip) + ' · ' + esc(d.group || '') + '<br>' +
|
|
|
'Tier: ' + esc(d.tier) + ' · ' + stat + '<br>' +
|
|
'Tier: ' + esc(d.tier) + ' · ' + stat + '<br>' +
|
|
|
'Latency: ' + lat + '<br>' +
|
|
'Latency: ' + lat + '<br>' +
|
|
|
'Terminals: ' + (d.term_online || 0) + '<br>' +
|
|
'Terminals: ' + (d.term_online || 0) + '<br>' +
|
|
@@ -1833,7 +1929,7 @@
|
|
|
/* ---------------- search ---------------- */
|
|
/* ---------------- search ---------------- */
|
|
|
function buildIndex(snap) {
|
|
function buildIndex(snap) {
|
|
|
var idx = [];
|
|
var idx = [];
|
|
|
- (snap.nodes || []).forEach(function (n) { idx.push({id: n.id, label: n.name, sub: n.ip, kind: 'sw'}); });
|
|
|
|
|
|
|
+ (snap.nodes || []).forEach(function (n) { idx.push({id: n.id, label: poePrefix(n) + n.name, sub: n.ip, kind: 'sw'}); });
|
|
|
(snap.terminals || []).forEach(function (tm) {
|
|
(snap.terminals || []).forEach(function (tm) {
|
|
|
if (!terminalOnline(tm)) return;
|
|
if (!terminalOnline(tm)) return;
|
|
|
idx.push({id: 't_' + tm.mac, label: tm.mac, sub: (tm.ip || '') + ' · ' + speedText(tm.speed) + ' · ' + (tm.sw_name || ''), kind: 'term', mac: tm.mac});
|
|
idx.push({id: 't_' + tm.mac, label: tm.mac, sub: (tm.ip || '') + ' · ' + speedText(tm.speed) + ' · ' + (tm.sw_name || ''), kind: 'term', mac: tm.mac});
|