[!!!][TASK] Refactor to meshviewer.json
This commit is contained in:
parent
7c8456b18a
commit
db16ea8375
@ -16,7 +16,7 @@ define(function () {
|
||||
}
|
||||
|
||||
function run(d) {
|
||||
return (d.nodeinfo !== undefined ? d.nodeinfo.hostname.toLowerCase().includes(input.value.toLowerCase()) : '');
|
||||
return (d !== undefined ? d.hostname.toLowerCase().includes(input.value.toLowerCase()) : '');
|
||||
}
|
||||
|
||||
function setRefresh(f) {
|
||||
|
@ -82,7 +82,7 @@ define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'd3-timer', 'd3-ease',
|
||||
var n = force.find(e[0], e[1], NODE_RADIUS_SELECT);
|
||||
|
||||
if (n !== undefined) {
|
||||
router.fullUrl({ node: n.o.node.nodeinfo.node_id });
|
||||
router.fullUrl({ node: n.o.node_id });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -121,16 +121,16 @@ define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'd3-timer', 'd3-ease',
|
||||
|
||||
forceLink = d3Force.forceLink()
|
||||
.distance(function (d) {
|
||||
if (d.o.vpn) {
|
||||
if (d.o.type === 'vpn') {
|
||||
return 0;
|
||||
}
|
||||
return 75;
|
||||
})
|
||||
.strength(function (d) {
|
||||
if (d.o.vpn) {
|
||||
if (d.o.type === 'vpn') {
|
||||
return 0.02;
|
||||
}
|
||||
return Math.max(0.5, 1 / d.o.tq);
|
||||
return Math.max(0.5, d.o.source_tq);
|
||||
});
|
||||
|
||||
var zoom = d3Zoom.zoom()
|
||||
@ -197,13 +197,13 @@ define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'd3-timer', 'd3-ease',
|
||||
});
|
||||
|
||||
self.setData = function setData(data) {
|
||||
intNodes = data.graph.nodes.map(function (d) {
|
||||
intNodes = data.nodes.all.map(function (d) {
|
||||
var e;
|
||||
if (d.id in dictNodes) {
|
||||
e = dictNodes[d.id];
|
||||
if (d.node_id in dictNodes) {
|
||||
e = dictNodes[d.node_id];
|
||||
} else {
|
||||
e = {};
|
||||
dictNodes[d.id] = e;
|
||||
dictNodes[d.node_id] = e;
|
||||
}
|
||||
|
||||
e.o = d;
|
||||
@ -211,12 +211,13 @@ define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'd3-timer', 'd3-ease',
|
||||
return e;
|
||||
});
|
||||
|
||||
intLinks = data.graph.links.map(function (d) {
|
||||
intLinks = data.links.map(function (d) {
|
||||
var e = {};
|
||||
e.o = d;
|
||||
e.source = dictNodes[d.source.id];
|
||||
e.target = dictNodes[d.target.id];
|
||||
e.color = linkScale(1 / d.tq);
|
||||
e.source = dictNodes[d.source.node_id];
|
||||
e.target = dictNodes[d.target.node_id];
|
||||
e.color = linkScale(d.source_tq);
|
||||
e.color_to = linkScale(d.target_tq);
|
||||
|
||||
return e;
|
||||
});
|
||||
@ -239,10 +240,10 @@ define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'd3-timer', 'd3-ease',
|
||||
moveTo(function calcToNode() {
|
||||
for (var i = 0; i < intNodes.length; i++) {
|
||||
var n = intNodes[i];
|
||||
if (n.o.node.nodeinfo.node_id !== d.nodeinfo.node_id) {
|
||||
if (n.o.node_id !== d.node_id) {
|
||||
continue;
|
||||
}
|
||||
draw.setHighlight({ type: 'node', o: n.o.node });
|
||||
draw.setHighlight({ type: 'node', o: n.o });
|
||||
return [n.x, n.y, (ZOOM_MAX + 1) / 2];
|
||||
}
|
||||
return [0, 0, (ZOOM_MIN + 1) / 2];
|
||||
|
@ -21,13 +21,13 @@ define(['helper'], function (helper) {
|
||||
function drawDetailNode(d) {
|
||||
if (transform.k > 1) {
|
||||
ctx.beginPath();
|
||||
helper.positionClients(ctx, d, Math.PI, d.o.node.statistics.clients, 15);
|
||||
helper.positionClients(ctx, d, Math.PI, d.o.clients, 15);
|
||||
ctx.fillStyle = clientColor;
|
||||
ctx.fill();
|
||||
ctx.beginPath();
|
||||
var name = d.o.node_id;
|
||||
if (d.o.node && d.o.node.nodeinfo) {
|
||||
name = d.o.node.nodeinfo.hostname;
|
||||
if (d.o) {
|
||||
name = d.o.hostname;
|
||||
}
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillStyle = labelColor;
|
||||
@ -36,7 +36,7 @@ define(['helper'], function (helper) {
|
||||
}
|
||||
|
||||
function drawHighlightNode(d) {
|
||||
if (highlight && highlight.type === 'node' && d.o.node === highlight.o) {
|
||||
if (highlight && highlight.type === 'node' && d.o === highlight.o) {
|
||||
ctx.arc(d.x, d.y, NODE_RADIUS * 1.5, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = highlightColor;
|
||||
ctx.fill();
|
||||
@ -76,7 +76,7 @@ define(['helper'], function (helper) {
|
||||
var zero = transform.invert([0, 0]);
|
||||
var area = transform.invert([width, height]);
|
||||
if (d.source.x < zero[0] && d.target.x < zero[0] || d.source.y < zero[1] && d.target.y < zero[1] ||
|
||||
d.source.x > area[0] && d.target.x > area[0] || d.source.y > area[1] && d.target.y > area[1]) {
|
||||
d.source.x > area[0] && d.target.x > area[0] || d.source.y > area[1] && d.target.y > area[1]) {
|
||||
return;
|
||||
}
|
||||
ctx.beginPath();
|
||||
@ -85,9 +85,13 @@ define(['helper'], function (helper) {
|
||||
|
||||
to = drawHighlightLink(d, to);
|
||||
|
||||
var grd = ctx.createLinearGradient(d.source.x, d.source.y, d.target.x, d.target.y);
|
||||
grd.addColorStop(0.45, d.color);
|
||||
grd.addColorStop(0.55, d.color_to);
|
||||
|
||||
ctx.lineTo(to[0], to[1]);
|
||||
ctx.strokeStyle = d.color;
|
||||
if (d.o.vpn) {
|
||||
ctx.strokeStyle = grd;
|
||||
if (d.o.type === 'vpn') {
|
||||
ctx.globalAlpha = 0.2;
|
||||
ctx.lineWidth = 1.5;
|
||||
} else {
|
||||
|
@ -80,7 +80,7 @@ function (d3Interpolate, Map, Sidebar, Tabs, Container, Legend, Linklist,
|
||||
var title = new Title(config);
|
||||
|
||||
var header = new Container('header');
|
||||
var infobox = new Infobox(config, sidebar, router);
|
||||
var infobox = new Infobox(config, sidebar, router, linkScale);
|
||||
var tabs = new Tabs();
|
||||
var overview = new Container();
|
||||
var legend = new Legend(config, language);
|
||||
@ -94,6 +94,7 @@ function (d3Interpolate, Map, Sidebar, Tabs, Container, Legend, Linklist,
|
||||
fanoutUnfiltered.add(legend);
|
||||
fanoutUnfiltered.add(newnodeslist);
|
||||
fanoutUnfiltered.add(lostnodeslist);
|
||||
fanoutUnfiltered.add(infobox);
|
||||
fanout.add(nodelist);
|
||||
fanout.add(linklist);
|
||||
fanout.add(statistics);
|
||||
|
@ -1,53 +1,76 @@
|
||||
define(['helper'], function (helper) {
|
||||
define(['helper', 'snabbdom'], function (helper, V) {
|
||||
'use strict';
|
||||
V = V.default;
|
||||
|
||||
function showStatImg(o, d, time) {
|
||||
var subst = {};
|
||||
subst['{SOURCE_ID}'] = d.source.node_id;
|
||||
subst['{SOURCE_NAME}'] = d.source.node.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_');
|
||||
subst['{SOURCE_NAME}'] = d.source.hostname.replace(/[^a-z0-9\-]/ig, '_');
|
||||
subst['{TARGET_ID}'] = d.target.node_id;
|
||||
subst['{TARGET_NAME}'] = d.target.node.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_');
|
||||
subst['{TARGET_NAME}'] = d.target.hostname.replace(/[^a-z0-9\-]/ig, '_');
|
||||
subst['{TIME}'] = time;
|
||||
subst['{LOCALE}'] = _.locale();
|
||||
return helper.showStat(o, subst);
|
||||
return helper.showStat(V, o, subst);
|
||||
}
|
||||
|
||||
return function (config, el, router, d) {
|
||||
var h2 = document.createElement('h2');
|
||||
var a1 = document.createElement('a');
|
||||
a1.href = router.generateLink({ node: d.source.node_id });
|
||||
a1.textContent = d.source.node.nodeinfo.hostname;
|
||||
h2.appendChild(a1);
|
||||
return function (config, el, router, d, linkScale) {
|
||||
var self = this;
|
||||
var header = document.createElement('div');
|
||||
var table = document.createElement('table');
|
||||
var images = document.createElement('div');
|
||||
el.appendChild(header);
|
||||
el.appendChild(table);
|
||||
el.appendChild(images);
|
||||
|
||||
var arrow = document.createElement('span');
|
||||
arrow.classList.add('ion-arrow-right-c');
|
||||
h2.appendChild(arrow);
|
||||
self.render = function render() {
|
||||
var children = [];
|
||||
var headers = [];
|
||||
headers.push(V.h('h2', [
|
||||
V.h('a', {
|
||||
props: { href: router.generateLink({ node: d.source.node_id }) }
|
||||
}, d.source.hostname),
|
||||
V.h('span', ' - '),
|
||||
V.h('a', {
|
||||
props: { href: router.generateLink({ node: d.target.node_id }) }
|
||||
}, d.target.hostname)
|
||||
]));
|
||||
|
||||
var a2 = document.createElement('a');
|
||||
a2.href = router.generateLink({ node: d.target.node_id });
|
||||
a2.textContent = d.target.node.nodeinfo.hostname;
|
||||
h2.appendChild(a2);
|
||||
el.appendChild(h2);
|
||||
header = V.patch(header, V.h('div', headers));
|
||||
|
||||
var attributes = document.createElement('table');
|
||||
attributes.classList.add('attributes');
|
||||
children.push(helper.attributeEntry(V, 'node.connectionType', d.type));
|
||||
children.push(helper.attributeEntry(V, 'node.tq', V.h('span',
|
||||
{
|
||||
style:
|
||||
{
|
||||
color: linkScale((d.source_tq + d.target_tq) / 2)
|
||||
}
|
||||
}, helper.showTq(d.source_tq) + ' - ' + helper.showTq(d.target_tq))));
|
||||
children.push(helper.attributeEntry(V, 'node.distance', helper.showDistance(d)));
|
||||
children.push(helper.attributeEntry(V, 'node.hardware',
|
||||
helper.dictGet(d.source, ['model']) + ' – ' + helper.dictGet(d.target, ['model']))
|
||||
);
|
||||
|
||||
helper.attributeEntry(attributes, 'node.tq', helper.showTq(d));
|
||||
helper.attributeEntry(attributes, 'node.distance', helper.showDistance(d));
|
||||
var hw1 = helper.dictGet(d.source.node.nodeinfo, ['hardware', 'model']);
|
||||
var hw2 = helper.dictGet(d.target.node.nodeinfo, ['hardware', 'model']);
|
||||
helper.attributeEntry(attributes, 'node.hardware', hw1 + ' – ' + hw2);
|
||||
var elNew = V.h('table', children);
|
||||
table = V.patch(table, elNew);
|
||||
table.elm.classList.add('attributes');
|
||||
|
||||
el.appendChild(attributes);
|
||||
if (config.linkInfos) {
|
||||
var time = d.target.lastseen.format('DDMMYYYYHmmss');
|
||||
var img = [];
|
||||
config.linkInfos.forEach(function (linkInfo) {
|
||||
img.push(V.h('h4', linkInfo.name));
|
||||
img.push(showStatImg(linkInfo, d, time));
|
||||
});
|
||||
images = V.patch(images, V.h('div', img));
|
||||
}
|
||||
};
|
||||
|
||||
if (config.linkInfos) {
|
||||
var time = d.target.node.lastseen.format('DDMMYYYYHmmss');
|
||||
config.linkInfos.forEach(function (linkInfo) {
|
||||
var h4 = document.createElement('h4');
|
||||
h4.textContent = linkInfo.name;
|
||||
el.appendChild(h4);
|
||||
el.appendChild(showStatImg(linkInfo, d, time));
|
||||
self.setData = function setData(data) {
|
||||
d = data.links.find(function (a) {
|
||||
return a.id === d.id;
|
||||
});
|
||||
}
|
||||
self.render();
|
||||
};
|
||||
return self;
|
||||
};
|
||||
});
|
||||
|
@ -1,9 +1,11 @@
|
||||
define(['infobox/link', 'infobox/node', 'infobox/location'], function (link, node, location) {
|
||||
define(['infobox/link', 'infobox/node', 'infobox/location'], function (Link, Node, location) {
|
||||
'use strict';
|
||||
|
||||
return function (config, sidebar, router) {
|
||||
return function (config, sidebar, router, linkScale) {
|
||||
var self = this;
|
||||
var el;
|
||||
var node;
|
||||
var link;
|
||||
|
||||
function destroy() {
|
||||
if (el && el.parentNode) {
|
||||
@ -38,12 +40,14 @@ define(['infobox/link', 'infobox/node', 'infobox/location'], function (link, nod
|
||||
|
||||
self.gotoNode = function gotoNode(d, gateways) {
|
||||
create();
|
||||
node(config, el, router, d, gateways);
|
||||
node = new Node(config, el, router, d, linkScale, gateways);
|
||||
node.render();
|
||||
};
|
||||
|
||||
self.gotoLink = function gotoLink(d) {
|
||||
create();
|
||||
link(config, el, router, d);
|
||||
link = new Link(config, el, router, d, linkScale);
|
||||
link.render();
|
||||
};
|
||||
|
||||
self.gotoLocation = function gotoLocation(d) {
|
||||
@ -51,6 +55,16 @@ define(['infobox/link', 'infobox/node', 'infobox/location'], function (link, nod
|
||||
location(config, el, router, d);
|
||||
};
|
||||
|
||||
self.setData = function setData(d) {
|
||||
if (typeof node === 'object') {
|
||||
node.setData(d);
|
||||
}
|
||||
if (typeof link === 'object') {
|
||||
link.setData(d);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return self;
|
||||
};
|
||||
});
|
||||
|
@ -8,35 +8,34 @@ define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return function (el) {
|
||||
var a = document.createElement('a');
|
||||
a.textContent = Number(d.nodeinfo.location.latitude.toFixed(6)) + ', ' + Number(d.nodeinfo.location.longitude.toFixed(6));
|
||||
a.href = 'geo:' + d.nodeinfo.location.latitude + ',' + d.nodeinfo.location.longitude;
|
||||
el.appendChild(a);
|
||||
};
|
||||
return V.h('td',
|
||||
V.h('a',
|
||||
{ props: { href: 'geo:' + d.location.latitude + ',' + d.location.longitude } },
|
||||
Number(d.location.latitude.toFixed(6)) + ', ' + Number(d.location.longitude.toFixed(6))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function showStatus(d) {
|
||||
return function (el) {
|
||||
el.classList.add(d.flags.unseen ? 'unseen' : (d.flags.online ? 'online' : 'offline'));
|
||||
el.textContent = _.t((d.flags.online ? 'node.lastOnline' : 'node.lastOffline'), {
|
||||
return V.h('td',
|
||||
{ props: { className: d.is_unseen ? 'unseen' : (d.is_online ? 'online' : 'offline') } },
|
||||
_.t((d.is_online ? 'node.lastOnline' : 'node.lastOffline'), {
|
||||
time: d.lastseen.fromNow(),
|
||||
date: d.lastseen.format('DD.MM.YYYY, H:mm:ss')
|
||||
});
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
||||
function showFirmware(d) {
|
||||
return [
|
||||
helper.dictGet(d.nodeinfo, ['software', 'firmware', 'release']),
|
||||
helper.dictGet(d.nodeinfo, ['software', 'firmware', 'base'])
|
||||
helper.dictGet(d, ['firmware', 'release']),
|
||||
helper.dictGet(d, ['firmware', 'base'])
|
||||
].filter(function (n) {
|
||||
return n !== null;
|
||||
}).join(' / ') || undefined;
|
||||
}
|
||||
|
||||
function showSite(d, config) {
|
||||
var site = helper.dictGet(d.nodeinfo, ['system', 'site_code']);
|
||||
var site = helper.dictGet(d, ['site_code']);
|
||||
var rt = site;
|
||||
if (config.siteNames) {
|
||||
config.siteNames.forEach(function (t) {
|
||||
@ -49,11 +48,11 @@ define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
|
||||
}
|
||||
|
||||
function showUptime(d) {
|
||||
if (!('uptime' in d.statistics)) {
|
||||
if (!('uptime' in d)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return moment.duration(d.statistics.uptime, 'seconds').humanize();
|
||||
return moment.duration(d.uptime, 'seconds').humanize();
|
||||
}
|
||||
|
||||
function showFirstseen(d) {
|
||||
@ -65,101 +64,89 @@ define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
|
||||
}
|
||||
|
||||
function showClients(d) {
|
||||
if (!d.flags.online) {
|
||||
if (!d.is_online) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return function (el) {
|
||||
el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : _.t('none')));
|
||||
el.appendChild(document.createElement('br'));
|
||||
var clients = [
|
||||
d.clients > 0 ? d.clients : _.t('none'),
|
||||
V.h('br')
|
||||
];
|
||||
|
||||
var span = document.createElement('span');
|
||||
span.classList.add('clients');
|
||||
span.innerHTML = '<i class="ion-person"></i>'.repeat(d.statistics.clients);
|
||||
el.appendChild(span);
|
||||
};
|
||||
for (var i = 0; i < d.clients; i++) {
|
||||
clients.push(V.h('i', { props: { className: 'ion-person' } }));
|
||||
}
|
||||
return V.h('td', clients);
|
||||
}
|
||||
|
||||
function showIPs(d) {
|
||||
var ips = helper.dictGet(d.nodeinfo, ['network', 'addresses']);
|
||||
var ips = helper.dictGet(d, ['network', 'addresses']);
|
||||
if (ips === null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
ips.sort();
|
||||
|
||||
return function (el) {
|
||||
ips.forEach(function (ip, i) {
|
||||
var link = !ip.startsWith('fe80:');
|
||||
var string = [];
|
||||
ips.forEach(function (ip, i) {
|
||||
var link = !ip.startsWith('fe80:');
|
||||
|
||||
if (i > 0) {
|
||||
el.appendChild(document.createElement('br'));
|
||||
}
|
||||
if (i > 0) {
|
||||
string.push(V.h('br'));
|
||||
}
|
||||
|
||||
if (link) {
|
||||
var a = document.createElement('a');
|
||||
a.href = 'http://[' + ip + ']/';
|
||||
a.textContent = ip;
|
||||
el.appendChild(a);
|
||||
} else {
|
||||
el.appendChild(document.createTextNode(ip));
|
||||
}
|
||||
});
|
||||
};
|
||||
if (link) {
|
||||
string.push(V.h('a', { props: { href: 'http://[' + ip + ']/', target: '_blank' } }, ip));
|
||||
} else {
|
||||
string.push(ip);
|
||||
}
|
||||
});
|
||||
return V.h('td', string);
|
||||
}
|
||||
|
||||
function showBar(v, width, warning) {
|
||||
var span = document.createElement('span');
|
||||
span.classList.add('bar');
|
||||
|
||||
var bar = document.createElement('span');
|
||||
bar.style.width = (width * 100) + '%';
|
||||
if (warning) {
|
||||
span.classList.add('warning');
|
||||
}
|
||||
span.appendChild(bar);
|
||||
|
||||
var label = document.createElement('label');
|
||||
label.textContent = v;
|
||||
span.appendChild(label);
|
||||
|
||||
return span;
|
||||
return V.h('span',
|
||||
{ props: { className: 'bar' + (warning ? ' warning' : '') } },
|
||||
[
|
||||
V.h('span',
|
||||
{
|
||||
style: { width: (width * 100) + '%' }
|
||||
}),
|
||||
V.h('label', v)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function showLoad(d) {
|
||||
if (!('loadavg' in d.statistics)) {
|
||||
if (!('loadavg' in d)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return function (el) {
|
||||
var value = d.statistics.loadavg.toFixed(2);
|
||||
var width = d.statistics.loadavg % 1;
|
||||
var warning = false;
|
||||
if (d.statistics.loadavg >= d.nodeinfo.hardware.nproc) {
|
||||
warning = true;
|
||||
}
|
||||
el.appendChild(showBar(value, width, warning));
|
||||
};
|
||||
var value = d.loadavg.toFixed(2);
|
||||
var width = d.loadavg % 1;
|
||||
var warning = false;
|
||||
if (d.loadavg >= d.nproc) {
|
||||
warning = true;
|
||||
}
|
||||
return showBar(value, width, warning);
|
||||
}
|
||||
|
||||
function showRAM(d) {
|
||||
if (!('memory_usage' in d.statistics)) {
|
||||
if (!('memory_usage' in d)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return function (el) {
|
||||
var value = Math.round(d.statistics.memory_usage * 100) + ' %';
|
||||
var width = d.statistics.memory_usage;
|
||||
var warning = false;
|
||||
if (d.statistics.memory_usage >= 0.8) {
|
||||
warning = true;
|
||||
}
|
||||
el.appendChild(showBar(value, width, warning));
|
||||
};
|
||||
var value = Math.round(d.memory_usage * 100) + ' %';
|
||||
var width = d.memory_usage;
|
||||
var warning = false;
|
||||
if (d.memory_usage >= 0.8) {
|
||||
warning = true;
|
||||
}
|
||||
return showBar(value, width, warning);
|
||||
}
|
||||
|
||||
function showAutoupdate(d) {
|
||||
var au = helper.dictGet(d.nodeinfo, ['software', 'autoupdater']);
|
||||
var au = helper.dictGet(d, ['autoupdater']);
|
||||
if (!au) {
|
||||
return undefined;
|
||||
}
|
||||
@ -169,16 +156,14 @@ define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
|
||||
|
||||
function showStatImg(o, d) {
|
||||
var subst = {};
|
||||
subst['{NODE_ID}'] = d.nodeinfo.node_id;
|
||||
subst['{NODE_NAME}'] = d.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_');
|
||||
subst['{NODE_ID}'] = d.node_id;
|
||||
subst['{NODE_NAME}'] = d.hostname.replace(/[^a-z0-9\-]/ig, '_');
|
||||
subst['{TIME}'] = d.lastseen.format('DDMMYYYYHmmss');
|
||||
subst['{LOCALE}'] = _.locale();
|
||||
return helper.showStat(o, subst);
|
||||
return helper.showStat(V, o, subst);
|
||||
}
|
||||
|
||||
return function (config, el, router, d, gateways) {
|
||||
var linkScale = d3Interpolate.interpolate('#F02311', '#04C714');
|
||||
|
||||
return function (config, el, router, d, linkScale, gateways) {
|
||||
function renderNeighbourRow(n) {
|
||||
var icons = [];
|
||||
icons.push(V.h('span', { props: { className: n.incoming ? 'ion-arrow-left-c' : 'ion-arrow-right-c' } }));
|
||||
@ -189,107 +174,122 @@ define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
|
||||
var name = V.h('a', {
|
||||
props: {
|
||||
className: 'online',
|
||||
href: router.generateLink({ node: n.node.nodeinfo.node_id })
|
||||
href: router.generateLink({ node: n.node.node_id })
|
||||
}, on: {
|
||||
click: function (e) {
|
||||
router.fullUrl({ node: n.node.nodeinfo.node_id }, e);
|
||||
router.fullUrl({ node: n.node.node_id }, e);
|
||||
}
|
||||
}
|
||||
}, n.node.nodeinfo.hostname);
|
||||
}, n.node.hostname);
|
||||
|
||||
var td1 = V.h('td', icons);
|
||||
var td2 = V.h('td', name);
|
||||
var td3 = V.h('td', (n.node.statistics.clients ? n.node.statistics.clients.toString() : '0'));
|
||||
var td4 = V.h('td', { style: { color: linkScale(1 / n.link.tq) } }, helper.showTq(n.link));
|
||||
var td3 = V.h('td', (n.node.clients ? n.node.clients.toString() : '0'));
|
||||
var td4 = V.h('td', { style: { color: linkScale((n.link.source_tq + n.link.target_tq) / 2) } }, helper.showTq(n.link.source_tq) + ' - ' + helper.showTq(n.link.target_tq));
|
||||
var td5 = V.h('td', helper.showDistance(n.link));
|
||||
|
||||
return V.h('tr', [td1, td2, td3, td4, td5]);
|
||||
}
|
||||
|
||||
var h2 = document.createElement('h2');
|
||||
h2.textContent = d.nodeinfo.hostname;
|
||||
el.appendChild(h2);
|
||||
var self = this;
|
||||
var header = document.createElement('h2');
|
||||
var table = document.createElement('table');
|
||||
var images = document.createElement('div');
|
||||
var neighbours = document.createElement('h3');
|
||||
var headings = [{
|
||||
name: ''
|
||||
}, {
|
||||
name: 'node.nodes',
|
||||
sort: function (a, b) {
|
||||
return a.node.hostname.localeCompare(b.node.hostname);
|
||||
},
|
||||
reverse: false
|
||||
}, {
|
||||
name: 'node.clients',
|
||||
class: 'ion-people',
|
||||
sort: function (a, b) {
|
||||
return ('clients' in a.node ? a.node.clients : -1) -
|
||||
('clients' in b.node ? b.node.clients : -1);
|
||||
},
|
||||
reverse: true
|
||||
}, {
|
||||
name: 'node.tq',
|
||||
class: 'ion-connection-bars',
|
||||
sort: function (a, b) {
|
||||
return a.link.source_tq - b.link.source_tq;
|
||||
},
|
||||
reverse: true
|
||||
}, {
|
||||
name: 'node.distance',
|
||||
class: 'ion-arrow-resize',
|
||||
sort: function (a, b) {
|
||||
return (a.link.distance === undefined ? -1 : a.link.distance) -
|
||||
(b.link.distance === undefined ? -1 : b.link.distance);
|
||||
},
|
||||
reverse: true
|
||||
}];
|
||||
var tableNeighbour = new SortTable(headings, 1, renderNeighbourRow);
|
||||
|
||||
var attributes = document.createElement('table');
|
||||
attributes.classList.add('attributes');
|
||||
el.appendChild(header);
|
||||
el.appendChild(table);
|
||||
el.appendChild(neighbours);
|
||||
el.appendChild(tableNeighbour.el);
|
||||
el.appendChild(images);
|
||||
|
||||
helper.attributeEntry(attributes, 'node.status', showStatus(d));
|
||||
helper.attributeEntry(attributes, 'node.gateway', d.flags.gateway ? 'ja' : null);
|
||||
helper.attributeEntry(attributes, 'node.coordinates', showGeoURI(d));
|
||||
self.render = function render() {
|
||||
V.patch(header, V.h('h2', d.hostname));
|
||||
|
||||
if (config.nodeInfobox && config.nodeInfobox.contact) {
|
||||
helper.attributeEntry(attributes, 'node.contact', helper.dictGet(d.nodeinfo, ['owner', 'contact']));
|
||||
}
|
||||
var children = [];
|
||||
|
||||
helper.attributeEntry(attributes, 'node.hardware', helper.dictGet(d.nodeinfo, ['hardware', 'model']));
|
||||
helper.attributeEntry(attributes, 'node.primaryMac', helper.dictGet(d.nodeinfo, ['network', 'mac']));
|
||||
helper.attributeEntry(attributes, 'node.id', helper.dictGet(d.nodeinfo, ['node_id']));
|
||||
helper.attributeEntry(attributes, 'node.firmware', showFirmware(d));
|
||||
helper.attributeEntry(attributes, 'node.site', showSite(d, config));
|
||||
helper.attributeEntry(attributes, 'node.uptime', showUptime(d));
|
||||
helper.attributeEntry(attributes, 'node.firstSeen', showFirstseen(d));
|
||||
if (config.nodeInfobox && config.nodeInfobox.hardwareUsage) {
|
||||
helper.attributeEntry(attributes, 'node.systemLoad', showLoad(d));
|
||||
helper.attributeEntry(attributes, 'node.ram', showRAM(d));
|
||||
}
|
||||
helper.attributeEntry(attributes, 'node.ipAddresses', showIPs(d));
|
||||
helper.attributeEntry(attributes, 'node.selectedGateway', gateways[helper.dictGet(d.statistics, ['gateway'])]);
|
||||
helper.attributeEntry(attributes, 'node.update', showAutoupdate(d));
|
||||
helper.attributeEntry(attributes, 'node.clients', showClients(d));
|
||||
children.push(helper.attributeEntry(V, 'node.status', showStatus(d)));
|
||||
children.push(helper.attributeEntry(V, 'node.gateway', d.is_gateway ? 'ja' : null));
|
||||
children.push(helper.attributeEntry(V, 'node.coordinates', showGeoURI(d)));
|
||||
|
||||
el.appendChild(attributes);
|
||||
if (config.nodeInfobox && config.nodeInfobox.contact) {
|
||||
children.push(helper.attributeEntry(V, 'node.contact', helper.dictGet(d, ['owner', 'contact'])));
|
||||
}
|
||||
|
||||
if (d.neighbours.length > 0) {
|
||||
var h3 = document.createElement('h3');
|
||||
h3.textContent = _.t('node.link', d.neighbours.length) + ' (' + d.neighbours.length + ')';
|
||||
el.appendChild(h3);
|
||||
children.push(helper.attributeEntry(V, 'node.hardware', helper.dictGet(d, ['model'])));
|
||||
children.push(helper.attributeEntry(V, 'node.primaryMac', helper.dictGet(d, ['network', 'mac'])));
|
||||
children.push(helper.attributeEntry(V, 'node.firmware', showFirmware(d)));
|
||||
children.push(helper.attributeEntry(V, 'node.site', showSite(d, config)));
|
||||
children.push(helper.attributeEntry(V, 'node.uptime', showUptime(d)));
|
||||
children.push(helper.attributeEntry(V, 'node.firstSeen', showFirstseen(d)));
|
||||
if (config.nodeInfobox && config.nodeInfobox.hardwareUsage) {
|
||||
children.push(helper.attributeEntry(V, 'node.systemLoad', showLoad(d)));
|
||||
children.push(helper.attributeEntry(V, 'node.ram', showRAM(d)));
|
||||
}
|
||||
children.push(helper.attributeEntry(V, 'node.ipAddresses', showIPs(d)));
|
||||
children.push(helper.attributeEntry(V, 'node.selectedGateway', gateways[helper.dictGet(d, ['gateway'])]));
|
||||
children.push(helper.attributeEntry(V, 'node.update', showAutoupdate(d)));
|
||||
children.push(helper.attributeEntry(V, 'node.clients', showClients(d)));
|
||||
|
||||
var headings = [{
|
||||
name: ''
|
||||
}, {
|
||||
name: 'node.nodes',
|
||||
sort: function (a, b) {
|
||||
return a.node.nodeinfo.hostname.localeCompare(b.node.nodeinfo.hostname);
|
||||
},
|
||||
reverse: false
|
||||
}, {
|
||||
name: 'node.clients',
|
||||
class: 'ion-people',
|
||||
sort: function (a, b) {
|
||||
return ('clients' in a.node.statistics ? a.node.statistics.clients : -1) -
|
||||
('clients' in b.node.statistics ? b.node.statistics.clients : -1);
|
||||
},
|
||||
reverse: true
|
||||
}, {
|
||||
name: 'node.tq',
|
||||
class: 'ion-connection-bars',
|
||||
sort: function (a, b) {
|
||||
return a.link.tq - b.link.tq;
|
||||
},
|
||||
reverse: true
|
||||
}, {
|
||||
name: 'node.distance',
|
||||
class: 'ion-arrow-resize',
|
||||
sort: function (a, b) {
|
||||
return (a.link.distance === undefined ? -1 : a.link.distance) -
|
||||
(b.link.distance === undefined ? -1 : b.link.distance);
|
||||
},
|
||||
reverse: true
|
||||
}];
|
||||
var elNew = V.h('table', children);
|
||||
table = V.patch(table, elNew);
|
||||
table.elm.classList.add('attributes');
|
||||
|
||||
var table = new SortTable(headings, 1, renderNeighbourRow);
|
||||
table.setData(d.neighbours);
|
||||
table.el.elm.classList.add('node-links');
|
||||
el.appendChild(table.el.elm);
|
||||
}
|
||||
V.patch(neighbours, V.h('h3', _.t('node.link', d.neighbours.length) + ' (' + d.neighbours.length + ')'));
|
||||
if (d.neighbours.length > 0) {
|
||||
tableNeighbour.setData(d.neighbours);
|
||||
tableNeighbour.el.elm.classList.add('node-links');
|
||||
}
|
||||
|
||||
if (config.nodeInfos) {
|
||||
config.nodeInfos.forEach(function (nodeInfo) {
|
||||
var h4 = document.createElement('h4');
|
||||
h4.textContent = nodeInfo.name;
|
||||
el.appendChild(h4);
|
||||
el.appendChild(showStatImg(nodeInfo, d));
|
||||
if (config.nodeInfos) {
|
||||
var img = [];
|
||||
config.nodeInfos.forEach(function (nodeInfo) {
|
||||
img.push(V.h('h4', nodeInfo.name));
|
||||
img.push(showStatImg(nodeInfo, d));
|
||||
});
|
||||
images = V.patch(images, V.h('div', img));
|
||||
}
|
||||
};
|
||||
|
||||
self.setData = function setData(data) {
|
||||
d = data.nodes.all.find(function (a) {
|
||||
return a.node_id === d.node_id;
|
||||
});
|
||||
}
|
||||
self.render();
|
||||
};
|
||||
return self;
|
||||
};
|
||||
});
|
||||
|
@ -10,10 +10,10 @@ define(['helper'], function (helper) {
|
||||
var totalNodes = helper.sum(d.nodes.all.map(helper.one));
|
||||
var totalOnlineNodes = helper.sum(d.nodes.all.filter(helper.online).map(helper.one));
|
||||
var totalClients = helper.sum(d.nodes.all.filter(helper.online).map(function (n) {
|
||||
return n.statistics.clients ? n.statistics.clients : 0;
|
||||
return n.clients ? n.clients : 0;
|
||||
}));
|
||||
var totalGateways = helper.sum(d.nodes.all.filter(helper.online).filter(function (n) {
|
||||
return n.flags.gateway;
|
||||
return n.is_gateway;
|
||||
}).map(helper.one));
|
||||
|
||||
stats.textContent = _.t('sidebar.nodes', { total: totalNodes, online: totalOnlineNodes }) + ' ' +
|
||||
|
@ -2,7 +2,7 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
|
||||
'use strict';
|
||||
|
||||
function linkName(d) {
|
||||
return (d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + ' – ' + d.target.node.nodeinfo.hostname;
|
||||
return (d.source ? d.source.hostname : d.source.id) + ' – ' + d.target.hostname;
|
||||
}
|
||||
|
||||
var headings = [{
|
||||
@ -15,7 +15,7 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
|
||||
name: 'node.tq',
|
||||
class: 'ion-connection-bars',
|
||||
sort: function (a, b) {
|
||||
return a.tq - b.tq;
|
||||
return (a.source_tq + a.target_tq) / 2 - (b.source_tq + b.target_tq) / 2;
|
||||
},
|
||||
reverse: true
|
||||
}, {
|
||||
@ -44,7 +44,7 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
|
||||
}, linkName(d))];
|
||||
|
||||
var td1 = V.h('td', td1Content);
|
||||
var td2 = V.h('td', { style: { color: linkScale(1 / d.tq) } }, helper.showTq(d));
|
||||
var td2 = V.h('td', { style: { color: linkScale((d.source_tq + d.target_tq) / 2) } }, helper.showTq(d.source_tq) + ' - ' + helper.showTq(d.target_tq));
|
||||
var td3 = V.h('td', helper.showDistance(d));
|
||||
|
||||
return V.h('tr', [td1, td2, td3]);
|
||||
@ -59,7 +59,7 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
|
||||
};
|
||||
|
||||
this.setData = function setData(d) {
|
||||
table.setData(d.graph.links);
|
||||
table.setData(d.links);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
109
lib/main.js
109
lib/main.js
@ -4,44 +4,19 @@ define(['moment', 'utils/router', 'leaflet', 'gui', 'helper', 'utils/language'],
|
||||
|
||||
return function (config) {
|
||||
function handleData(data) {
|
||||
var dataNodes = {};
|
||||
dataNodes.nodes = [];
|
||||
var dataGraph = {};
|
||||
dataGraph.batadv = {};
|
||||
dataGraph.batadv.nodes = [];
|
||||
dataGraph.batadv.links = [];
|
||||
var timestamp;
|
||||
var nodes = [];
|
||||
var links = [];
|
||||
var gateways = {};
|
||||
|
||||
function rearrangeLinks(d) {
|
||||
d.source += dataGraph.batadv.nodes.length;
|
||||
d.target += dataGraph.batadv.nodes.length;
|
||||
}
|
||||
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
var vererr;
|
||||
if (i % 2) {
|
||||
if (data[i].version !== 1) {
|
||||
vererr = 'Unsupported graph version: ' + data[i].version;
|
||||
console.error(vererr); // silent fail
|
||||
} else {
|
||||
data[i].batadv.links.forEach(rearrangeLinks);
|
||||
dataGraph.batadv.nodes = dataGraph.batadv.nodes.concat(data[i].batadv.nodes);
|
||||
dataGraph.batadv.links = dataGraph.batadv.links.concat(data[i].batadv.links);
|
||||
dataGraph.timestamp = data[i].timestamp;
|
||||
}
|
||||
} else if (data[i].version !== 2) {
|
||||
vererr = 'Unsupported nodes version: ' + data[i].version;
|
||||
console.error(vererr); // silent fail
|
||||
} else {
|
||||
dataNodes.nodes = dataNodes.nodes.concat(data[i].nodes);
|
||||
dataNodes.timestamp = data[i].timestamp;
|
||||
}
|
||||
nodes = nodes.concat(data[i].nodes);
|
||||
timestamp = data[i].timestamp;
|
||||
links = links.concat(data[i].links.filter(function (d) {
|
||||
return d.source !== undefined;
|
||||
}));
|
||||
}
|
||||
|
||||
var nodes = dataNodes.nodes.filter(function (d) {
|
||||
return 'firstseen' in d && 'lastseen' in d;
|
||||
});
|
||||
|
||||
nodes.forEach(function (node) {
|
||||
node.firstseen = moment.utc(node.firstseen).local();
|
||||
node.lastseen = moment.utc(node.lastseen).local();
|
||||
@ -53,44 +28,12 @@ define(['moment', 'utils/router', 'leaflet', 'gui', 'helper', 'utils/language'],
|
||||
var newnodes = helper.limit('firstseen', age, helper.sortByKey('firstseen', nodes).filter(helper.online));
|
||||
var lostnodes = helper.limit('lastseen', age, helper.sortByKey('lastseen', nodes).filter(helper.offline));
|
||||
|
||||
var graphnodes = {};
|
||||
|
||||
dataNodes.nodes.forEach(function (d) {
|
||||
graphnodes[d.nodeinfo.node_id] = d;
|
||||
});
|
||||
|
||||
var graph = dataGraph.batadv;
|
||||
|
||||
graph.nodes.forEach(function (d) {
|
||||
if (d.node_id in graphnodes) {
|
||||
d.node = graphnodes[d.node_id];
|
||||
if (d.unseen) {
|
||||
d.node.flags.online = true;
|
||||
d.node.flags.unseen = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
graph.links.forEach(function (d) {
|
||||
d.source = graph.nodes[d.source];
|
||||
|
||||
if (graph.nodes[d.target].node) {
|
||||
d.target = graph.nodes[d.target];
|
||||
} else {
|
||||
d.target = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
var links = graph.links.filter(function (d) {
|
||||
return d.target !== undefined;
|
||||
});
|
||||
|
||||
nodes.forEach(function (d) {
|
||||
d.neighbours = [];
|
||||
if (d.flags.gateway && d.nodeinfo.network.mesh) {
|
||||
var mesh = d.nodeinfo.network.mesh;
|
||||
if (d.is_gateway && d.network.mesh) {
|
||||
var mesh = d.network.mesh;
|
||||
mesh[Object.keys(mesh)[0]].interfaces.tunnel.forEach(function (mac) {
|
||||
gateways[mac] = d.nodeinfo.hostname;
|
||||
gateways[mac] = d.hostname;
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -98,16 +41,24 @@ define(['moment', 'utils/router', 'leaflet', 'gui', 'helper', 'utils/language'],
|
||||
links.forEach(function (d) {
|
||||
var ids;
|
||||
|
||||
ids = [d.source.node.nodeinfo.node_id, d.target.node.nodeinfo.node_id];
|
||||
d.source.node.neighbours.push({ node: d.target.node, link: d, incoming: false });
|
||||
d.target.node.neighbours.push({ node: d.source.node, link: d, incoming: true });
|
||||
d.source = nodes.find(function (a) {
|
||||
return a.node_id === d.source;
|
||||
});
|
||||
|
||||
d.target = nodes.find(function (a) {
|
||||
return a.node_id === d.target;
|
||||
});
|
||||
|
||||
ids = [d.source.node_id, d.target.node_id];
|
||||
d.source.neighbours.push({ node: d.target, link: d, incoming: false });
|
||||
d.target.neighbours.push({ node: d.source, link: d, incoming: true });
|
||||
|
||||
d.id = ids.join('-');
|
||||
|
||||
try {
|
||||
d.latlngs = [];
|
||||
d.latlngs.push(L.latLng(d.source.node.nodeinfo.location.latitude, d.source.node.nodeinfo.location.longitude));
|
||||
d.latlngs.push(L.latLng(d.target.node.nodeinfo.location.latitude, d.target.node.nodeinfo.location.longitude));
|
||||
d.latlngs.push(L.latLng(d.source.location.latitude, d.source.location.longitude));
|
||||
d.latlngs.push(L.latLng(d.target.location.latitude, d.target.location.longitude));
|
||||
|
||||
d.distance = d.latlngs[0].distanceTo(d.latlngs[1]);
|
||||
} catch (e) {
|
||||
@ -116,20 +67,21 @@ define(['moment', 'utils/router', 'leaflet', 'gui', 'helper', 'utils/language'],
|
||||
});
|
||||
|
||||
links.sort(function (a, b) {
|
||||
return b.tq - a.tq;
|
||||
return b.source_tq - a.source_tq;
|
||||
});
|
||||
|
||||
return {
|
||||
now: now,
|
||||
timestamp: moment.utc(dataNodes.timestamp).local(),
|
||||
timestamp: moment.utc(timestamp).local(),
|
||||
nodes: {
|
||||
all: nodes,
|
||||
new: newnodes,
|
||||
lost: lostnodes
|
||||
},
|
||||
links: links,
|
||||
graph: {
|
||||
links: links,
|
||||
nodes: graph.nodes
|
||||
links: [],
|
||||
nodes: []
|
||||
},
|
||||
gateways: gateways
|
||||
};
|
||||
@ -146,8 +98,7 @@ define(['moment', 'utils/router', 'leaflet', 'gui', 'helper', 'utils/language'],
|
||||
|
||||
for (var i in config.dataPath) {
|
||||
if (config.dataPath.hasOwnProperty(i)) {
|
||||
urls.push(config.dataPath[i] + 'nodes.json');
|
||||
urls.push(config.dataPath[i] + 'graph.json');
|
||||
urls.push(config.dataPath[i] + 'meshviewer.json');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,8 +142,8 @@ define(['map/clientlayer', 'map/labellayer', 'map/button', 'leaflet'],
|
||||
var m;
|
||||
|
||||
if (highlight !== undefined) {
|
||||
if (highlight.type === 'node' && nodeDict[highlight.o.nodeinfo.node_id]) {
|
||||
m = nodeDict[highlight.o.nodeinfo.node_id];
|
||||
if (highlight.type === 'node' && nodeDict[highlight.o.node_id]) {
|
||||
m = nodeDict[highlight.o.node_id];
|
||||
m.setStyle({ color: 'orange', weight: 20, fillOpacity: 1, opacity: 0.7, className: 'stroke-first' });
|
||||
} else if (highlight.type === 'link' && linkDict[highlight.o.id]) {
|
||||
m = linkDict[highlight.o.id];
|
||||
|
@ -5,8 +5,8 @@ define(['leaflet', 'rbush', 'helper'],
|
||||
return L.GridLayer.extend({
|
||||
mapRTree: function mapRTree(d) {
|
||||
return {
|
||||
minX: d.nodeinfo.location.latitude, minY: d.nodeinfo.location.longitude,
|
||||
maxX: d.nodeinfo.location.latitude, maxY: d.nodeinfo.location.longitude,
|
||||
minX: d.location.latitude, minY: d.location.longitude,
|
||||
maxX: d.location.latitude, maxY: d.location.longitude,
|
||||
node: d
|
||||
};
|
||||
},
|
||||
@ -17,7 +17,7 @@ define(['leaflet', 'rbush', 'helper'],
|
||||
|
||||
// pre-calculate start angles
|
||||
this.data.all().forEach(function (n) {
|
||||
n.startAngle = (parseInt(n.node.nodeinfo.node_id.substr(10, 2), 16) / 255) * 2 * Math.PI;
|
||||
n.startAngle = (parseInt(n.node.node_id.substr(10, 2), 16) / 255) * 2 * Math.PI;
|
||||
});
|
||||
this.redraw();
|
||||
},
|
||||
@ -49,12 +49,12 @@ define(['leaflet', 'rbush', 'helper'],
|
||||
|
||||
ctx.beginPath();
|
||||
nodes.forEach(function (d) {
|
||||
var p = map.project([d.node.nodeinfo.location.latitude, d.node.nodeinfo.location.longitude]);
|
||||
var p = map.project([d.node.location.latitude, d.node.location.longitude]);
|
||||
|
||||
p.x -= s.x;
|
||||
p.y -= s.y;
|
||||
|
||||
helper.positionClients(ctx, p, d.startAngle, d.node.statistics.clients, startDistance);
|
||||
helper.positionClients(ctx, p, d.startAngle, d.node.clients, startDistance);
|
||||
});
|
||||
|
||||
ctx.fillStyle = 'rgba(220, 0, 103, 0.7)';
|
||||
|
@ -35,14 +35,14 @@ define(['leaflet', 'rbush', 'helper', 'moment'],
|
||||
return function (d) {
|
||||
var font = fontSize + 'px ' + bodyStyle.fontFamily;
|
||||
return {
|
||||
position: L.latLng(d.nodeinfo.location.latitude, d.nodeinfo.location.longitude),
|
||||
label: d.nodeinfo.hostname,
|
||||
position: L.latLng(d.location.latitude, d.location.longitude),
|
||||
label: d.hostname,
|
||||
offset: offset,
|
||||
fillStyle: fillStyle,
|
||||
height: fontSize * 1.2,
|
||||
font: font,
|
||||
stroke: stroke,
|
||||
width: measureText(font, d.nodeinfo.hostname).width
|
||||
width: measureText(font, d.hostname).width
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -78,18 +78,18 @@ define(['leaflet', 'rbush', 'helper', 'moment'],
|
||||
|
||||
function mkMarker(dict, iconFunc, router) {
|
||||
return function (d) {
|
||||
var m = L.circleMarker([d.nodeinfo.location.latitude, d.nodeinfo.location.longitude], iconFunc(d));
|
||||
var m = L.circleMarker([d.location.latitude, d.location.longitude], iconFunc(d));
|
||||
|
||||
m.resetStyle = function resetStyle() {
|
||||
m.setStyle(iconFunc(d));
|
||||
};
|
||||
|
||||
m.on('click', function () {
|
||||
router.fullUrl({ node: d.nodeinfo.node_id });
|
||||
router.fullUrl({ node: d.node_id });
|
||||
});
|
||||
m.bindTooltip(d.nodeinfo.hostname);
|
||||
m.bindTooltip(d.hostname);
|
||||
|
||||
dict[d.nodeinfo.node_id] = m;
|
||||
dict[d.node_id] = m;
|
||||
|
||||
return m;
|
||||
};
|
||||
@ -102,7 +102,7 @@ define(['leaflet', 'rbush', 'helper', 'moment'],
|
||||
|
||||
return graph.map(function (d) {
|
||||
var opts = {
|
||||
color: linkScale(1 / d.tq),
|
||||
color: linkScale((d.source_tq + d.target_tq) / 2),
|
||||
weight: 4,
|
||||
opacity: 0.5,
|
||||
dashArray: 'none'
|
||||
@ -114,7 +114,7 @@ define(['leaflet', 'rbush', 'helper', 'moment'],
|
||||
line.setStyle(opts);
|
||||
};
|
||||
|
||||
line.bindTooltip(d.source.node.nodeinfo.hostname + ' – ' + d.target.node.nodeinfo.hostname + '<br><strong>' + helper.showDistance(d) + ' / ' + helper.showTq(d) + '</strong>');
|
||||
line.bindTooltip(d.source.hostname + ' – ' + d.target.hostname + '<br><strong>' + helper.showDistance(d) + ' / ' + helper.showTq(d.source_tq) + ' - ' + helper.showTq(d.target_tq) + '</strong>');
|
||||
line.on('click', function () {
|
||||
router.fullUrl({ link: d.id });
|
||||
});
|
||||
@ -151,7 +151,7 @@ define(['leaflet', 'rbush', 'helper', 'moment'],
|
||||
groupLines.clearLayers();
|
||||
}
|
||||
|
||||
var lines = addLinksToMap(linkDict, linkScale, data.graph.links, router);
|
||||
var lines = addLinksToMap(linkDict, linkScale, data.links, router);
|
||||
groupLines = L.featureGroup(lines).addTo(map);
|
||||
|
||||
var nodesOnline = helper.subtract(data.nodes.all.filter(helper.online), data.nodes.new);
|
||||
|
@ -3,9 +3,9 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
|
||||
V = V.default;
|
||||
|
||||
function getUptime(now, d) {
|
||||
if (d.flags.online && 'uptime' in d.statistics) {
|
||||
return Math.round(d.statistics.uptime);
|
||||
} else if (!d.flags.online && 'lastseen' in d) {
|
||||
if (d.is_online && 'uptime' in d) {
|
||||
return Math.round(d.uptime);
|
||||
} else if (!d.is_online && 'lastseen' in d) {
|
||||
return Math.round(-(now.unix() - d.lastseen.unix()));
|
||||
}
|
||||
return 0;
|
||||
@ -31,7 +31,7 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
|
||||
}, {
|
||||
name: 'node.nodes',
|
||||
sort: function (a, b) {
|
||||
return a.nodeinfo.hostname.localeCompare(b.nodeinfo.hostname);
|
||||
return a.hostname.localeCompare(b.hostname);
|
||||
},
|
||||
reverse: false
|
||||
}, {
|
||||
@ -52,8 +52,8 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
|
||||
name: 'node.clients',
|
||||
class: 'ion-people',
|
||||
sort: function (a, b) {
|
||||
return ('clients' in a.statistics ? a.statistics.clients : -1) -
|
||||
('clients' in b.statistics ? b.statistics.clients : -1);
|
||||
return ('clients' in a ? a.clients : -1) -
|
||||
('clients' in b ? b.clients : -1);
|
||||
},
|
||||
reverse: true
|
||||
}];
|
||||
@ -62,18 +62,18 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
|
||||
function renderRow(d) {
|
||||
var td0Content = [];
|
||||
var td1Content = [];
|
||||
var aClass = ['hostname', d.flags.online ? 'online' : 'offline'];
|
||||
var aClass = ['hostname', d.is_online ? 'online' : 'offline'];
|
||||
|
||||
td1Content.push(V.h('a', {
|
||||
props: {
|
||||
className: aClass.join(' '),
|
||||
href: router.generateLink({ node: d.nodeinfo.node_id })
|
||||
href: router.generateLink({ node: d.node_id })
|
||||
}, on: {
|
||||
click: function (e) {
|
||||
router.fullUrl({ node: d.nodeinfo.node_id }, e);
|
||||
router.fullUrl({ node: d.node_id }, e);
|
||||
}
|
||||
}
|
||||
}, d.nodeinfo.hostname));
|
||||
}, d.hostname));
|
||||
|
||||
if (helper.hasLocation(d)) {
|
||||
td0Content.push(V.h('span', { props: { className: 'icon ion-location' } }));
|
||||
@ -83,7 +83,7 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
|
||||
var td1 = V.h('td', td1Content);
|
||||
var td2 = V.h('td', showUptime(d.uptime));
|
||||
var td3 = V.h('td', d.neighbours.length);
|
||||
var td4 = V.h('td', Number('clients' in d.statistics ? d.statistics.clients : 0).toFixed(0));
|
||||
var td4 = V.h('td', Number('clients' in d ? d.clients : 0).toFixed(0));
|
||||
|
||||
return V.h('tr', [td0, td1, td2, td3, td4]);
|
||||
}
|
||||
|
@ -15,11 +15,6 @@ define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
|
||||
var gatewayTable;
|
||||
var siteTable;
|
||||
|
||||
|
||||
function showStatGlobal(o) {
|
||||
return helper.showStat(o);
|
||||
}
|
||||
|
||||
function count(nodes, key, f) {
|
||||
var dict = {};
|
||||
|
||||
@ -86,19 +81,19 @@ define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
|
||||
var nodeDict = {};
|
||||
|
||||
data.nodes.all.forEach(function (d) {
|
||||
nodeDict[d.nodeinfo.node_id] = d;
|
||||
nodeDict[d.node_id] = d;
|
||||
});
|
||||
|
||||
var statusDict = count(nodes, ['flags', 'online'], function (d) {
|
||||
var statusDict = count(nodes, ['is_online'], function (d) {
|
||||
return d ? 'online' : 'offline';
|
||||
});
|
||||
var fwDict = count(nodes, ['nodeinfo', 'software', 'firmware', 'release']);
|
||||
var hwDict = count(nodes, ['nodeinfo', 'hardware', 'model']);
|
||||
var geoDict = count(nodes, ['nodeinfo', 'location'], function (d) {
|
||||
var fwDict = count(nodes, ['firmware', 'release']);
|
||||
var hwDict = count(nodes, ['model']);
|
||||
var geoDict = count(nodes, ['location'], function (d) {
|
||||
return d && d.longitude && d.latitude ? _.t('yes') : _.t('no');
|
||||
});
|
||||
|
||||
var autoDict = count(nodes, ['nodeinfo', 'software', 'autoupdater'], function (d) {
|
||||
var autoDict = count(nodes, ['autoupdater'], function (d) {
|
||||
if (d === null) {
|
||||
return null;
|
||||
} else if (d.enabled) {
|
||||
@ -107,7 +102,7 @@ define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
|
||||
return _.t('node.deactivated');
|
||||
});
|
||||
|
||||
var gatewayDict = count(nodes, ['statistics', 'gateway'], function (d) {
|
||||
var gatewayDict = count(nodes, ['is_gateway'], function (d) {
|
||||
for (var mac in data.gateways) {
|
||||
if (data.gateways.hasOwnProperty(mac) && mac === d) {
|
||||
d = data.gateways[mac];
|
||||
@ -117,7 +112,7 @@ define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
|
||||
return null;
|
||||
});
|
||||
|
||||
var siteDict = count(nodes, ['nodeinfo', 'system', 'site_code'], function (d) {
|
||||
var siteDict = count(nodes, ['nodeinfo', 'site_code'], function (d) {
|
||||
if (config.siteNames) {
|
||||
config.siteNames.forEach(function (t) {
|
||||
if (d === t.site) {
|
||||
@ -158,7 +153,6 @@ define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
|
||||
};
|
||||
|
||||
self.render = function render(el) {
|
||||
var h2;
|
||||
self.renderSingle(el, 'node.status', statusTable);
|
||||
self.renderSingle(el, 'node.firmware', fwTable);
|
||||
self.renderSingle(el, 'node.hardware', hwTable);
|
||||
@ -168,12 +162,14 @@ define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
|
||||
self.renderSingle(el, 'node.site', siteTable);
|
||||
|
||||
if (config.globalInfos) {
|
||||
var images = document.createElement('div');
|
||||
el.appendChild(images);
|
||||
var img = [];
|
||||
config.globalInfos.forEach(function (globalInfo) {
|
||||
h2 = document.createElement('h2');
|
||||
h2.textContent = globalInfo.name;
|
||||
el.appendChild(h2);
|
||||
el.appendChild(showStatGlobal(globalInfo));
|
||||
img.push(V.h('h2', globalInfo.name));
|
||||
img.push(helper.showStat(V, globalInfo));
|
||||
});
|
||||
V.patch(images, V.h('div', img));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -38,18 +38,18 @@ define(['moment', 'snabbdom', 'helper'], function (moment, V, helper) {
|
||||
var td0Content = [];
|
||||
var td1Content = [];
|
||||
|
||||
var aClass = ['hostname', d.flags.online ? 'online' : 'offline'];
|
||||
var aClass = ['hostname', d.is_online ? 'online' : 'offline'];
|
||||
|
||||
td1Content.push(V.h('a', {
|
||||
props: {
|
||||
className: aClass.join(' '),
|
||||
href: router.generateLink({ node: d.nodeinfo.node_id })
|
||||
href: router.generateLink({ node: d.node_id })
|
||||
}, on: {
|
||||
click: function (e) {
|
||||
router.fullUrl({ node: d.nodeinfo.node_id }, e);
|
||||
router.fullUrl({ node: d.node_id }, e);
|
||||
}
|
||||
}
|
||||
}, d.nodeinfo.hostname));
|
||||
}, d.hostname));
|
||||
|
||||
if (helper.hasLocation(d)) {
|
||||
td0Content.push(V.h('span', { props: { className: 'icon ion-location' } }));
|
||||
|
@ -17,11 +17,11 @@ define(function () {
|
||||
};
|
||||
|
||||
this.gotoNode = function gotoNode(d) {
|
||||
setTitle(d.nodeinfo.hostname);
|
||||
setTitle(d.hostname);
|
||||
};
|
||||
|
||||
this.gotoLink = function gotoLink(d) {
|
||||
setTitle((d.source.node ? d.source.node.nodeinfo.hostname : d.source.id) + ' \u21D4 ' + d.target.node.nodeinfo.hostname);
|
||||
setTitle((d.source ? d.source.hostname : d.source.id) + ' \u21D4 ' + d.target.hostname);
|
||||
};
|
||||
|
||||
this.gotoLocation = function gotoLocation() {
|
||||
|
@ -73,30 +73,29 @@ define({
|
||||
},
|
||||
|
||||
/* Helpers working with nodes */
|
||||
|
||||
offline: function offline(d) {
|
||||
return !d.flags.online;
|
||||
return !d.is_online;
|
||||
},
|
||||
|
||||
online: function online(d) {
|
||||
return d.flags.online;
|
||||
return d.is_online;
|
||||
},
|
||||
|
||||
hasLocation: function hasLocation(d) {
|
||||
return 'location' in d.nodeinfo &&
|
||||
Math.abs(d.nodeinfo.location.latitude) < 90 &&
|
||||
Math.abs(d.nodeinfo.location.longitude) < 180;
|
||||
return 'location' in d &&
|
||||
Math.abs(d.location.latitude) < 90 &&
|
||||
Math.abs(d.location.longitude) < 180;
|
||||
},
|
||||
|
||||
subtract: function subtract(a, b) {
|
||||
var ids = {};
|
||||
|
||||
b.forEach(function (d) {
|
||||
ids[d.nodeinfo.node_id] = true;
|
||||
ids[d.node_id] = true;
|
||||
});
|
||||
|
||||
return a.filter(function (d) {
|
||||
return !(d.nodeinfo.node_id in ids);
|
||||
return !(d.node_id in ids);
|
||||
});
|
||||
},
|
||||
|
||||
@ -111,59 +110,41 @@ define({
|
||||
},
|
||||
|
||||
showTq: function showTq(d) {
|
||||
return (1 / d.tq * 100).toFixed(0) + '%';
|
||||
return (d * 100).toFixed(0) + '%';
|
||||
},
|
||||
|
||||
attributeEntry: function attributeEntry(el, label, value) {
|
||||
attributeEntry: function attributeEntry(V, label, value) {
|
||||
if (value === null || value === undefined) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var tr = document.createElement('tr');
|
||||
var th = document.createElement('th');
|
||||
th.textContent = _.t(label);
|
||||
tr.appendChild(th);
|
||||
|
||||
var td = document.createElement('td');
|
||||
|
||||
if (typeof value === 'function') {
|
||||
value(td);
|
||||
} else {
|
||||
td.appendChild(document.createTextNode(value));
|
||||
if (typeof value !== 'object') {
|
||||
value = V.h('td', value);
|
||||
}
|
||||
|
||||
tr.appendChild(td);
|
||||
|
||||
el.appendChild(tr);
|
||||
|
||||
return td;
|
||||
return V.h('tr', [
|
||||
V.h('th', _.t(label)),
|
||||
value
|
||||
]);
|
||||
},
|
||||
|
||||
showStat: function showStat(o, subst) {
|
||||
showStat: function showStat(V, o, subst) {
|
||||
var content;
|
||||
subst = typeof subst !== 'undefined' ? subst : {};
|
||||
|
||||
content = document.createElement('img');
|
||||
content.src = require('helper').listReplace(o.image, subst);
|
||||
|
||||
var p = document.createElement('p');
|
||||
content = V.h('img', { attrs: { src: require('helper').listReplace(o.image, subst) } });
|
||||
|
||||
if (o.href) {
|
||||
var link = document.createElement('a');
|
||||
link.target = '_blank';
|
||||
link.href = require('helper').listReplace(o.href, subst);
|
||||
link.appendChild(content);
|
||||
|
||||
if (o.title) {
|
||||
link.title = require('helper').listReplace(o.title, subst);
|
||||
}
|
||||
|
||||
p.appendChild(link);
|
||||
} else {
|
||||
p.appendChild(content);
|
||||
return V.h('p', V.h('a', {
|
||||
attrs:
|
||||
{
|
||||
href: require('helper').listReplace(o.href, subst),
|
||||
target: '_blank',
|
||||
title: require('helper').listReplace(o.title, subst)
|
||||
}
|
||||
}, content));
|
||||
}
|
||||
|
||||
return p;
|
||||
return V.h('p', content);
|
||||
},
|
||||
|
||||
getTileBBox: function getTileBBox(s, map, tileSize, margin) {
|
||||
|
@ -144,10 +144,10 @@ define(['Navigo'], function (Navigo) {
|
||||
objects.gateways = data.gateways;
|
||||
|
||||
data.nodes.all.forEach(function (d) {
|
||||
objects.nodes[d.nodeinfo.node_id] = d;
|
||||
objects.nodes[d.node_id] = d;
|
||||
});
|
||||
|
||||
data.graph.links.forEach(function (d) {
|
||||
data.links.forEach(function (d) {
|
||||
objects.links[d.id] = d;
|
||||
});
|
||||
};
|
||||
|
@ -6,6 +6,7 @@
|
||||
"links": "Links",
|
||||
"clients": "Clients",
|
||||
"distance": "Distance",
|
||||
"connectionType": "Connection type",
|
||||
"tq": "Transmit quality",
|
||||
"lastOnline": "online, last message %{time} (%{date})",
|
||||
"lastOffline": "offline, last message %{time} (%{date})",
|
||||
|
@ -58,7 +58,7 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 66%;
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user