[!!!][TASK] Refactor to meshviewer.json

This commit is contained in:
Xaver Maierhofer 2017-10-29 15:11:24 +01:00
parent 7c8456b18a
commit db16ea8375
No known key found for this signature in database
GPG Key ID: 7FDCE23FD2EC9FE8
21 changed files with 382 additions and 410 deletions

View File

@ -16,7 +16,7 @@ define(function () {
} }
function run(d) { 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) { function setRefresh(f) {

View File

@ -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); var n = force.find(e[0], e[1], NODE_RADIUS_SELECT);
if (n !== undefined) { if (n !== undefined) {
router.fullUrl({ node: n.o.node.nodeinfo.node_id }); router.fullUrl({ node: n.o.node_id });
return; return;
} }
@ -121,16 +121,16 @@ define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'd3-timer', 'd3-ease',
forceLink = d3Force.forceLink() forceLink = d3Force.forceLink()
.distance(function (d) { .distance(function (d) {
if (d.o.vpn) { if (d.o.type === 'vpn') {
return 0; return 0;
} }
return 75; return 75;
}) })
.strength(function (d) { .strength(function (d) {
if (d.o.vpn) { if (d.o.type === 'vpn') {
return 0.02; 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() 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) { self.setData = function setData(data) {
intNodes = data.graph.nodes.map(function (d) { intNodes = data.nodes.all.map(function (d) {
var e; var e;
if (d.id in dictNodes) { if (d.node_id in dictNodes) {
e = dictNodes[d.id]; e = dictNodes[d.node_id];
} else { } else {
e = {}; e = {};
dictNodes[d.id] = e; dictNodes[d.node_id] = e;
} }
e.o = d; e.o = d;
@ -211,12 +211,13 @@ define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'd3-timer', 'd3-ease',
return e; return e;
}); });
intLinks = data.graph.links.map(function (d) { intLinks = data.links.map(function (d) {
var e = {}; var e = {};
e.o = d; e.o = d;
e.source = dictNodes[d.source.id]; e.source = dictNodes[d.source.node_id];
e.target = dictNodes[d.target.id]; e.target = dictNodes[d.target.node_id];
e.color = linkScale(1 / d.tq); e.color = linkScale(d.source_tq);
e.color_to = linkScale(d.target_tq);
return e; return e;
}); });
@ -239,10 +240,10 @@ define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'd3-timer', 'd3-ease',
moveTo(function calcToNode() { moveTo(function calcToNode() {
for (var i = 0; i < intNodes.length; i++) { for (var i = 0; i < intNodes.length; i++) {
var n = intNodes[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; 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 [n.x, n.y, (ZOOM_MAX + 1) / 2];
} }
return [0, 0, (ZOOM_MIN + 1) / 2]; return [0, 0, (ZOOM_MIN + 1) / 2];

View File

@ -21,13 +21,13 @@ define(['helper'], function (helper) {
function drawDetailNode(d) { function drawDetailNode(d) {
if (transform.k > 1) { if (transform.k > 1) {
ctx.beginPath(); 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.fillStyle = clientColor;
ctx.fill(); ctx.fill();
ctx.beginPath(); ctx.beginPath();
var name = d.o.node_id; var name = d.o.node_id;
if (d.o.node && d.o.node.nodeinfo) { if (d.o) {
name = d.o.node.nodeinfo.hostname; name = d.o.hostname;
} }
ctx.textAlign = 'center'; ctx.textAlign = 'center';
ctx.fillStyle = labelColor; ctx.fillStyle = labelColor;
@ -36,7 +36,7 @@ define(['helper'], function (helper) {
} }
function drawHighlightNode(d) { 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.arc(d.x, d.y, NODE_RADIUS * 1.5, 0, 2 * Math.PI);
ctx.fillStyle = highlightColor; ctx.fillStyle = highlightColor;
ctx.fill(); ctx.fill();
@ -85,9 +85,13 @@ define(['helper'], function (helper) {
to = drawHighlightLink(d, to); 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.lineTo(to[0], to[1]);
ctx.strokeStyle = d.color; ctx.strokeStyle = grd;
if (d.o.vpn) { if (d.o.type === 'vpn') {
ctx.globalAlpha = 0.2; ctx.globalAlpha = 0.2;
ctx.lineWidth = 1.5; ctx.lineWidth = 1.5;
} else { } else {

View File

@ -80,7 +80,7 @@ function (d3Interpolate, Map, Sidebar, Tabs, Container, Legend, Linklist,
var title = new Title(config); var title = new Title(config);
var header = new Container('header'); 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 tabs = new Tabs();
var overview = new Container(); var overview = new Container();
var legend = new Legend(config, language); var legend = new Legend(config, language);
@ -94,6 +94,7 @@ function (d3Interpolate, Map, Sidebar, Tabs, Container, Legend, Linklist,
fanoutUnfiltered.add(legend); fanoutUnfiltered.add(legend);
fanoutUnfiltered.add(newnodeslist); fanoutUnfiltered.add(newnodeslist);
fanoutUnfiltered.add(lostnodeslist); fanoutUnfiltered.add(lostnodeslist);
fanoutUnfiltered.add(infobox);
fanout.add(nodelist); fanout.add(nodelist);
fanout.add(linklist); fanout.add(linklist);
fanout.add(statistics); fanout.add(statistics);

View File

@ -1,53 +1,76 @@
define(['helper'], function (helper) { define(['helper', 'snabbdom'], function (helper, V) {
'use strict'; 'use strict';
V = V.default;
function showStatImg(o, d, time) { function showStatImg(o, d, time) {
var subst = {}; var subst = {};
subst['{SOURCE_ID}'] = d.source.node_id; 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_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['{TIME}'] = time;
subst['{LOCALE}'] = _.locale(); subst['{LOCALE}'] = _.locale();
return helper.showStat(o, subst); return helper.showStat(V, o, subst);
} }
return function (config, el, router, d) { return function (config, el, router, d, linkScale) {
var h2 = document.createElement('h2'); var self = this;
var a1 = document.createElement('a'); var header = document.createElement('div');
a1.href = router.generateLink({ node: d.source.node_id }); var table = document.createElement('table');
a1.textContent = d.source.node.nodeinfo.hostname; var images = document.createElement('div');
h2.appendChild(a1); el.appendChild(header);
el.appendChild(table);
el.appendChild(images);
var arrow = document.createElement('span'); self.render = function render() {
arrow.classList.add('ion-arrow-right-c'); var children = [];
h2.appendChild(arrow); 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'); header = V.patch(header, V.h('div', headers));
a2.href = router.generateLink({ node: d.target.node_id });
a2.textContent = d.target.node.nodeinfo.hostname;
h2.appendChild(a2);
el.appendChild(h2);
var attributes = document.createElement('table'); children.push(helper.attributeEntry(V, 'node.connectionType', d.type));
attributes.classList.add('attributes'); 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)); var elNew = V.h('table', children);
helper.attributeEntry(attributes, 'node.distance', helper.showDistance(d)); table = V.patch(table, elNew);
var hw1 = helper.dictGet(d.source.node.nodeinfo, ['hardware', 'model']); table.elm.classList.add('attributes');
var hw2 = helper.dictGet(d.target.node.nodeinfo, ['hardware', 'model']);
helper.attributeEntry(attributes, 'node.hardware', hw1 + ' ' + hw2);
el.appendChild(attributes);
if (config.linkInfos) { if (config.linkInfos) {
var time = d.target.node.lastseen.format('DDMMYYYYHmmss'); var time = d.target.lastseen.format('DDMMYYYYHmmss');
var img = [];
config.linkInfos.forEach(function (linkInfo) { config.linkInfos.forEach(function (linkInfo) {
var h4 = document.createElement('h4'); img.push(V.h('h4', linkInfo.name));
h4.textContent = linkInfo.name; img.push(showStatImg(linkInfo, d, time));
el.appendChild(h4);
el.appendChild(showStatImg(linkInfo, d, time));
}); });
images = V.patch(images, V.h('div', img));
} }
}; };
self.setData = function setData(data) {
d = data.links.find(function (a) {
return a.id === d.id;
});
self.render();
};
return self;
};
}); });

View File

@ -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'; 'use strict';
return function (config, sidebar, router) { return function (config, sidebar, router, linkScale) {
var self = this; var self = this;
var el; var el;
var node;
var link;
function destroy() { function destroy() {
if (el && el.parentNode) { if (el && el.parentNode) {
@ -38,12 +40,14 @@ define(['infobox/link', 'infobox/node', 'infobox/location'], function (link, nod
self.gotoNode = function gotoNode(d, gateways) { self.gotoNode = function gotoNode(d, gateways) {
create(); create();
node(config, el, router, d, gateways); node = new Node(config, el, router, d, linkScale, gateways);
node.render();
}; };
self.gotoLink = function gotoLink(d) { self.gotoLink = function gotoLink(d) {
create(); create();
link(config, el, router, d); link = new Link(config, el, router, d, linkScale);
link.render();
}; };
self.gotoLocation = function gotoLocation(d) { self.gotoLocation = function gotoLocation(d) {
@ -51,6 +55,16 @@ define(['infobox/link', 'infobox/node', 'infobox/location'], function (link, nod
location(config, el, router, d); 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; return self;
}; };
}); });

View File

@ -8,35 +8,34 @@ define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
return undefined; return undefined;
} }
return function (el) { return V.h('td',
var a = document.createElement('a'); V.h('a',
a.textContent = Number(d.nodeinfo.location.latitude.toFixed(6)) + ', ' + Number(d.nodeinfo.location.longitude.toFixed(6)); { props: { href: 'geo:' + d.location.latitude + ',' + d.location.longitude } },
a.href = 'geo:' + d.nodeinfo.location.latitude + ',' + d.nodeinfo.location.longitude; Number(d.location.latitude.toFixed(6)) + ', ' + Number(d.location.longitude.toFixed(6))
el.appendChild(a); )
}; );
} }
function showStatus(d) { function showStatus(d) {
return function (el) { return V.h('td',
el.classList.add(d.flags.unseen ? 'unseen' : (d.flags.online ? 'online' : 'offline')); { props: { className: d.is_unseen ? 'unseen' : (d.is_online ? 'online' : 'offline') } },
el.textContent = _.t((d.flags.online ? 'node.lastOnline' : 'node.lastOffline'), { _.t((d.is_online ? 'node.lastOnline' : 'node.lastOffline'), {
time: d.lastseen.fromNow(), time: d.lastseen.fromNow(),
date: d.lastseen.format('DD.MM.YYYY, H:mm:ss') date: d.lastseen.format('DD.MM.YYYY, H:mm:ss')
}); }));
};
} }
function showFirmware(d) { function showFirmware(d) {
return [ return [
helper.dictGet(d.nodeinfo, ['software', 'firmware', 'release']), helper.dictGet(d, ['firmware', 'release']),
helper.dictGet(d.nodeinfo, ['software', 'firmware', 'base']) helper.dictGet(d, ['firmware', 'base'])
].filter(function (n) { ].filter(function (n) {
return n !== null; return n !== null;
}).join(' / ') || undefined; }).join(' / ') || undefined;
} }
function showSite(d, config) { function showSite(d, config) {
var site = helper.dictGet(d.nodeinfo, ['system', 'site_code']); var site = helper.dictGet(d, ['site_code']);
var rt = site; var rt = site;
if (config.siteNames) { if (config.siteNames) {
config.siteNames.forEach(function (t) { config.siteNames.forEach(function (t) {
@ -49,11 +48,11 @@ define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
} }
function showUptime(d) { function showUptime(d) {
if (!('uptime' in d.statistics)) { if (!('uptime' in d)) {
return undefined; return undefined;
} }
return moment.duration(d.statistics.uptime, 'seconds').humanize(); return moment.duration(d.uptime, 'seconds').humanize();
} }
function showFirstseen(d) { function showFirstseen(d) {
@ -65,101 +64,89 @@ define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
} }
function showClients(d) { function showClients(d) {
if (!d.flags.online) { if (!d.is_online) {
return undefined; return undefined;
} }
return function (el) { var clients = [
el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : _.t('none'))); d.clients > 0 ? d.clients : _.t('none'),
el.appendChild(document.createElement('br')); V.h('br')
];
var span = document.createElement('span'); for (var i = 0; i < d.clients; i++) {
span.classList.add('clients'); clients.push(V.h('i', { props: { className: 'ion-person' } }));
span.innerHTML = '<i class="ion-person"></i>'.repeat(d.statistics.clients); }
el.appendChild(span); return V.h('td', clients);
};
} }
function showIPs(d) { function showIPs(d) {
var ips = helper.dictGet(d.nodeinfo, ['network', 'addresses']); var ips = helper.dictGet(d, ['network', 'addresses']);
if (ips === null) { if (ips === null) {
return undefined; return undefined;
} }
ips.sort(); ips.sort();
return function (el) { var string = [];
ips.forEach(function (ip, i) { ips.forEach(function (ip, i) {
var link = !ip.startsWith('fe80:'); var link = !ip.startsWith('fe80:');
if (i > 0) { if (i > 0) {
el.appendChild(document.createElement('br')); string.push(V.h('br'));
} }
if (link) { if (link) {
var a = document.createElement('a'); string.push(V.h('a', { props: { href: 'http://[' + ip + ']/', target: '_blank' } }, ip));
a.href = 'http://[' + ip + ']/';
a.textContent = ip;
el.appendChild(a);
} else { } else {
el.appendChild(document.createTextNode(ip)); string.push(ip);
} }
}); });
}; return V.h('td', string);
} }
function showBar(v, width, warning) { function showBar(v, width, warning) {
var span = document.createElement('span'); return V.h('span',
span.classList.add('bar'); { props: { className: 'bar' + (warning ? ' warning' : '') } },
[
var bar = document.createElement('span'); V.h('span',
bar.style.width = (width * 100) + '%'; {
if (warning) { style: { width: (width * 100) + '%' }
span.classList.add('warning'); }),
} V.h('label', v)
span.appendChild(bar); ]
);
var label = document.createElement('label');
label.textContent = v;
span.appendChild(label);
return span;
} }
function showLoad(d) { function showLoad(d) {
if (!('loadavg' in d.statistics)) { if (!('loadavg' in d)) {
return undefined; return undefined;
} }
return function (el) { var value = d.loadavg.toFixed(2);
var value = d.statistics.loadavg.toFixed(2); var width = d.loadavg % 1;
var width = d.statistics.loadavg % 1;
var warning = false; var warning = false;
if (d.statistics.loadavg >= d.nodeinfo.hardware.nproc) { if (d.loadavg >= d.nproc) {
warning = true; warning = true;
} }
el.appendChild(showBar(value, width, warning)); return showBar(value, width, warning);
};
} }
function showRAM(d) { function showRAM(d) {
if (!('memory_usage' in d.statistics)) { if (!('memory_usage' in d)) {
return undefined; return undefined;
} }
return function (el) { var value = Math.round(d.memory_usage * 100) + ' %';
var value = Math.round(d.statistics.memory_usage * 100) + ' %'; var width = d.memory_usage;
var width = d.statistics.memory_usage;
var warning = false; var warning = false;
if (d.statistics.memory_usage >= 0.8) { if (d.memory_usage >= 0.8) {
warning = true; warning = true;
} }
el.appendChild(showBar(value, width, warning)); return showBar(value, width, warning);
};
} }
function showAutoupdate(d) { function showAutoupdate(d) {
var au = helper.dictGet(d.nodeinfo, ['software', 'autoupdater']); var au = helper.dictGet(d, ['autoupdater']);
if (!au) { if (!au) {
return undefined; return undefined;
} }
@ -169,16 +156,14 @@ define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
function showStatImg(o, d) { function showStatImg(o, d) {
var subst = {}; var subst = {};
subst['{NODE_ID}'] = d.nodeinfo.node_id; subst['{NODE_ID}'] = d.node_id;
subst['{NODE_NAME}'] = d.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_'); subst['{NODE_NAME}'] = d.hostname.replace(/[^a-z0-9\-]/ig, '_');
subst['{TIME}'] = d.lastseen.format('DDMMYYYYHmmss'); subst['{TIME}'] = d.lastseen.format('DDMMYYYYHmmss');
subst['{LOCALE}'] = _.locale(); subst['{LOCALE}'] = _.locale();
return helper.showStat(o, subst); return helper.showStat(V, o, subst);
} }
return function (config, el, router, d, gateways) { return function (config, el, router, d, linkScale, gateways) {
var linkScale = d3Interpolate.interpolate('#F02311', '#04C714');
function renderNeighbourRow(n) { function renderNeighbourRow(n) {
var icons = []; var icons = [];
icons.push(V.h('span', { props: { className: n.incoming ? 'ion-arrow-left-c' : 'ion-arrow-right-c' } })); icons.push(V.h('span', { props: { className: n.incoming ? 'ion-arrow-left-c' : 'ion-arrow-right-c' } }));
@ -189,82 +174,49 @@ define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
var name = V.h('a', { var name = V.h('a', {
props: { props: {
className: 'online', className: 'online',
href: router.generateLink({ node: n.node.nodeinfo.node_id }) href: router.generateLink({ node: n.node.node_id })
}, on: { }, on: {
click: function (e) { 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 td1 = V.h('td', icons);
var td2 = V.h('td', name); var td2 = V.h('td', name);
var td3 = V.h('td', (n.node.statistics.clients ? n.node.statistics.clients.toString() : '0')); var td3 = V.h('td', (n.node.clients ? n.node.clients.toString() : '0'));
var td4 = V.h('td', { style: { color: linkScale(1 / n.link.tq) } }, helper.showTq(n.link)); 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)); var td5 = V.h('td', helper.showDistance(n.link));
return V.h('tr', [td1, td2, td3, td4, td5]); return V.h('tr', [td1, td2, td3, td4, td5]);
} }
var h2 = document.createElement('h2'); var self = this;
h2.textContent = d.nodeinfo.hostname; var header = document.createElement('h2');
el.appendChild(h2); var table = document.createElement('table');
var images = document.createElement('div');
var attributes = document.createElement('table'); var neighbours = document.createElement('h3');
attributes.classList.add('attributes');
helper.attributeEntry(attributes, 'node.status', showStatus(d));
helper.attributeEntry(attributes, 'node.gateway', d.flags.gateway ? 'ja' : null);
helper.attributeEntry(attributes, 'node.coordinates', showGeoURI(d));
if (config.nodeInfobox && config.nodeInfobox.contact) {
helper.attributeEntry(attributes, 'node.contact', helper.dictGet(d.nodeinfo, ['owner', 'contact']));
}
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));
el.appendChild(attributes);
if (d.neighbours.length > 0) {
var h3 = document.createElement('h3');
h3.textContent = _.t('node.link', d.neighbours.length) + ' (' + d.neighbours.length + ')';
el.appendChild(h3);
var headings = [{ var headings = [{
name: '' name: ''
}, { }, {
name: 'node.nodes', name: 'node.nodes',
sort: function (a, b) { sort: function (a, b) {
return a.node.nodeinfo.hostname.localeCompare(b.node.nodeinfo.hostname); return a.node.hostname.localeCompare(b.node.hostname);
}, },
reverse: false reverse: false
}, { }, {
name: 'node.clients', name: 'node.clients',
class: 'ion-people', class: 'ion-people',
sort: function (a, b) { sort: function (a, b) {
return ('clients' in a.node.statistics ? a.node.statistics.clients : -1) - return ('clients' in a.node ? a.node.clients : -1) -
('clients' in b.node.statistics ? b.node.statistics.clients : -1); ('clients' in b.node ? b.node.clients : -1);
}, },
reverse: true reverse: true
}, { }, {
name: 'node.tq', name: 'node.tq',
class: 'ion-connection-bars', class: 'ion-connection-bars',
sort: function (a, b) { sort: function (a, b) {
return a.link.tq - b.link.tq; return a.link.source_tq - b.link.source_tq;
}, },
reverse: true reverse: true
}, { }, {
@ -276,20 +228,68 @@ define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
}, },
reverse: true reverse: true
}]; }];
var tableNeighbour = new SortTable(headings, 1, renderNeighbourRow);
var table = new SortTable(headings, 1, renderNeighbourRow); el.appendChild(header);
table.setData(d.neighbours); el.appendChild(table);
table.el.elm.classList.add('node-links'); el.appendChild(neighbours);
el.appendChild(table.el.elm); el.appendChild(tableNeighbour.el);
el.appendChild(images);
self.render = function render() {
V.patch(header, V.h('h2', d.hostname));
var children = [];
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)));
if (config.nodeInfobox && config.nodeInfobox.contact) {
children.push(helper.attributeEntry(V, 'node.contact', helper.dictGet(d, ['owner', 'contact'])));
}
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 elNew = V.h('table', children);
table = V.patch(table, elNew);
table.elm.classList.add('attributes');
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) { if (config.nodeInfos) {
var img = [];
config.nodeInfos.forEach(function (nodeInfo) { config.nodeInfos.forEach(function (nodeInfo) {
var h4 = document.createElement('h4'); img.push(V.h('h4', nodeInfo.name));
h4.textContent = nodeInfo.name; img.push(showStatImg(nodeInfo, d));
el.appendChild(h4);
el.appendChild(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;
};
}); });

View File

@ -10,10 +10,10 @@ define(['helper'], function (helper) {
var totalNodes = helper.sum(d.nodes.all.map(helper.one)); var totalNodes = helper.sum(d.nodes.all.map(helper.one));
var totalOnlineNodes = helper.sum(d.nodes.all.filter(helper.online).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) { 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) { var totalGateways = helper.sum(d.nodes.all.filter(helper.online).filter(function (n) {
return n.flags.gateway; return n.is_gateway;
}).map(helper.one)); }).map(helper.one));
stats.textContent = _.t('sidebar.nodes', { total: totalNodes, online: totalOnlineNodes }) + ' ' + stats.textContent = _.t('sidebar.nodes', { total: totalNodes, online: totalOnlineNodes }) + ' ' +

View File

@ -2,7 +2,7 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
'use strict'; 'use strict';
function linkName(d) { 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 = [{ var headings = [{
@ -15,7 +15,7 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
name: 'node.tq', name: 'node.tq',
class: 'ion-connection-bars', class: 'ion-connection-bars',
sort: function (a, b) { 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 reverse: true
}, { }, {
@ -44,7 +44,7 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
}, linkName(d))]; }, linkName(d))];
var td1 = V.h('td', td1Content); 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)); var td3 = V.h('td', helper.showDistance(d));
return V.h('tr', [td1, td2, td3]); return V.h('tr', [td1, td2, td3]);
@ -59,7 +59,7 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
}; };
this.setData = function setData(d) { this.setData = function setData(d) {
table.setData(d.graph.links); table.setData(d.links);
}; };
}; };
}); });

View File

@ -4,43 +4,18 @@ define(['moment', 'utils/router', 'leaflet', 'gui', 'helper', 'utils/language'],
return function (config) { return function (config) {
function handleData(data) { function handleData(data) {
var dataNodes = {}; var timestamp;
dataNodes.nodes = []; var nodes = [];
var dataGraph = {}; var links = [];
dataGraph.batadv = {};
dataGraph.batadv.nodes = [];
dataGraph.batadv.links = [];
var gateways = {}; 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) { for (var i = 0; i < data.length; ++i) {
var vererr; nodes = nodes.concat(data[i].nodes);
if (i % 2) { timestamp = data[i].timestamp;
if (data[i].version !== 1) { links = links.concat(data[i].links.filter(function (d) {
vererr = 'Unsupported graph version: ' + data[i].version; return d.source !== undefined;
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;
}
}
var nodes = dataNodes.nodes.filter(function (d) {
return 'firstseen' in d && 'lastseen' in d;
});
nodes.forEach(function (node) { nodes.forEach(function (node) {
node.firstseen = moment.utc(node.firstseen).local(); node.firstseen = moment.utc(node.firstseen).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 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 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) { nodes.forEach(function (d) {
d.neighbours = []; d.neighbours = [];
if (d.flags.gateway && d.nodeinfo.network.mesh) { if (d.is_gateway && d.network.mesh) {
var mesh = d.nodeinfo.network.mesh; var mesh = d.network.mesh;
mesh[Object.keys(mesh)[0]].interfaces.tunnel.forEach(function (mac) { 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) { links.forEach(function (d) {
var ids; var ids;
ids = [d.source.node.nodeinfo.node_id, d.target.node.nodeinfo.node_id]; d.source = nodes.find(function (a) {
d.source.node.neighbours.push({ node: d.target.node, link: d, incoming: false }); return a.node_id === d.source;
d.target.node.neighbours.push({ node: d.source.node, link: d, incoming: true }); });
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('-'); d.id = ids.join('-');
try { try {
d.latlngs = []; 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.source.location.latitude, d.source.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.target.location.latitude, d.target.location.longitude));
d.distance = d.latlngs[0].distanceTo(d.latlngs[1]); d.distance = d.latlngs[0].distanceTo(d.latlngs[1]);
} catch (e) { } catch (e) {
@ -116,20 +67,21 @@ define(['moment', 'utils/router', 'leaflet', 'gui', 'helper', 'utils/language'],
}); });
links.sort(function (a, b) { links.sort(function (a, b) {
return b.tq - a.tq; return b.source_tq - a.source_tq;
}); });
return { return {
now: now, now: now,
timestamp: moment.utc(dataNodes.timestamp).local(), timestamp: moment.utc(timestamp).local(),
nodes: { nodes: {
all: nodes, all: nodes,
new: newnodes, new: newnodes,
lost: lostnodes lost: lostnodes
}, },
graph: {
links: links, links: links,
nodes: graph.nodes graph: {
links: [],
nodes: []
}, },
gateways: gateways gateways: gateways
}; };
@ -146,8 +98,7 @@ define(['moment', 'utils/router', 'leaflet', 'gui', 'helper', 'utils/language'],
for (var i in config.dataPath) { for (var i in config.dataPath) {
if (config.dataPath.hasOwnProperty(i)) { if (config.dataPath.hasOwnProperty(i)) {
urls.push(config.dataPath[i] + 'nodes.json'); urls.push(config.dataPath[i] + 'meshviewer.json');
urls.push(config.dataPath[i] + 'graph.json');
} }
} }

View File

@ -142,8 +142,8 @@ define(['map/clientlayer', 'map/labellayer', 'map/button', 'leaflet'],
var m; var m;
if (highlight !== undefined) { if (highlight !== undefined) {
if (highlight.type === 'node' && nodeDict[highlight.o.nodeinfo.node_id]) { if (highlight.type === 'node' && nodeDict[highlight.o.node_id]) {
m = nodeDict[highlight.o.nodeinfo.node_id]; m = nodeDict[highlight.o.node_id];
m.setStyle({ color: 'orange', weight: 20, fillOpacity: 1, opacity: 0.7, className: 'stroke-first' }); m.setStyle({ color: 'orange', weight: 20, fillOpacity: 1, opacity: 0.7, className: 'stroke-first' });
} else if (highlight.type === 'link' && linkDict[highlight.o.id]) { } else if (highlight.type === 'link' && linkDict[highlight.o.id]) {
m = linkDict[highlight.o.id]; m = linkDict[highlight.o.id];

View File

@ -5,8 +5,8 @@ define(['leaflet', 'rbush', 'helper'],
return L.GridLayer.extend({ return L.GridLayer.extend({
mapRTree: function mapRTree(d) { mapRTree: function mapRTree(d) {
return { return {
minX: d.nodeinfo.location.latitude, minY: d.nodeinfo.location.longitude, minX: d.location.latitude, minY: d.location.longitude,
maxX: d.nodeinfo.location.latitude, maxY: d.nodeinfo.location.longitude, maxX: d.location.latitude, maxY: d.location.longitude,
node: d node: d
}; };
}, },
@ -17,7 +17,7 @@ define(['leaflet', 'rbush', 'helper'],
// pre-calculate start angles // pre-calculate start angles
this.data.all().forEach(function (n) { 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(); this.redraw();
}, },
@ -49,12 +49,12 @@ define(['leaflet', 'rbush', 'helper'],
ctx.beginPath(); ctx.beginPath();
nodes.forEach(function (d) { 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.x -= s.x;
p.y -= s.y; 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)'; ctx.fillStyle = 'rgba(220, 0, 103, 0.7)';

View File

@ -35,14 +35,14 @@ define(['leaflet', 'rbush', 'helper', 'moment'],
return function (d) { return function (d) {
var font = fontSize + 'px ' + bodyStyle.fontFamily; var font = fontSize + 'px ' + bodyStyle.fontFamily;
return { return {
position: L.latLng(d.nodeinfo.location.latitude, d.nodeinfo.location.longitude), position: L.latLng(d.location.latitude, d.location.longitude),
label: d.nodeinfo.hostname, label: d.hostname,
offset: offset, offset: offset,
fillStyle: fillStyle, fillStyle: fillStyle,
height: fontSize * 1.2, height: fontSize * 1.2,
font: font, font: font,
stroke: stroke, 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) { function mkMarker(dict, iconFunc, router) {
return function (d) { 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.resetStyle = function resetStyle() {
m.setStyle(iconFunc(d)); m.setStyle(iconFunc(d));
}; };
m.on('click', function () { 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; return m;
}; };
@ -102,7 +102,7 @@ define(['leaflet', 'rbush', 'helper', 'moment'],
return graph.map(function (d) { return graph.map(function (d) {
var opts = { var opts = {
color: linkScale(1 / d.tq), color: linkScale((d.source_tq + d.target_tq) / 2),
weight: 4, weight: 4,
opacity: 0.5, opacity: 0.5,
dashArray: 'none' dashArray: 'none'
@ -114,7 +114,7 @@ define(['leaflet', 'rbush', 'helper', 'moment'],
line.setStyle(opts); 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 () { line.on('click', function () {
router.fullUrl({ link: d.id }); router.fullUrl({ link: d.id });
}); });
@ -151,7 +151,7 @@ define(['leaflet', 'rbush', 'helper', 'moment'],
groupLines.clearLayers(); 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); groupLines = L.featureGroup(lines).addTo(map);
var nodesOnline = helper.subtract(data.nodes.all.filter(helper.online), data.nodes.new); var nodesOnline = helper.subtract(data.nodes.all.filter(helper.online), data.nodes.new);

View File

@ -3,9 +3,9 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
V = V.default; V = V.default;
function getUptime(now, d) { function getUptime(now, d) {
if (d.flags.online && 'uptime' in d.statistics) { if (d.is_online && 'uptime' in d) {
return Math.round(d.statistics.uptime); return Math.round(d.uptime);
} else if (!d.flags.online && 'lastseen' in d) { } else if (!d.is_online && 'lastseen' in d) {
return Math.round(-(now.unix() - d.lastseen.unix())); return Math.round(-(now.unix() - d.lastseen.unix()));
} }
return 0; return 0;
@ -31,7 +31,7 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
}, { }, {
name: 'node.nodes', name: 'node.nodes',
sort: function (a, b) { sort: function (a, b) {
return a.nodeinfo.hostname.localeCompare(b.nodeinfo.hostname); return a.hostname.localeCompare(b.hostname);
}, },
reverse: false reverse: false
}, { }, {
@ -52,8 +52,8 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
name: 'node.clients', name: 'node.clients',
class: 'ion-people', class: 'ion-people',
sort: function (a, b) { sort: function (a, b) {
return ('clients' in a.statistics ? a.statistics.clients : -1) - return ('clients' in a ? a.clients : -1) -
('clients' in b.statistics ? b.statistics.clients : -1); ('clients' in b ? b.clients : -1);
}, },
reverse: true reverse: true
}]; }];
@ -62,18 +62,18 @@ define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
function renderRow(d) { function renderRow(d) {
var td0Content = []; var td0Content = [];
var td1Content = []; var td1Content = [];
var aClass = ['hostname', d.flags.online ? 'online' : 'offline']; var aClass = ['hostname', d.is_online ? 'online' : 'offline'];
td1Content.push(V.h('a', { td1Content.push(V.h('a', {
props: { props: {
className: aClass.join(' '), className: aClass.join(' '),
href: router.generateLink({ node: d.nodeinfo.node_id }) href: router.generateLink({ node: d.node_id })
}, on: { }, on: {
click: function (e) { 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)) { if (helper.hasLocation(d)) {
td0Content.push(V.h('span', { props: { className: 'icon ion-location' } })); 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 td1 = V.h('td', td1Content);
var td2 = V.h('td', showUptime(d.uptime)); var td2 = V.h('td', showUptime(d.uptime));
var td3 = V.h('td', d.neighbours.length); 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]); return V.h('tr', [td0, td1, td2, td3, td4]);
} }

View File

@ -15,11 +15,6 @@ define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
var gatewayTable; var gatewayTable;
var siteTable; var siteTable;
function showStatGlobal(o) {
return helper.showStat(o);
}
function count(nodes, key, f) { function count(nodes, key, f) {
var dict = {}; var dict = {};
@ -86,19 +81,19 @@ define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
var nodeDict = {}; var nodeDict = {};
data.nodes.all.forEach(function (d) { 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'; return d ? 'online' : 'offline';
}); });
var fwDict = count(nodes, ['nodeinfo', 'software', 'firmware', 'release']); var fwDict = count(nodes, ['firmware', 'release']);
var hwDict = count(nodes, ['nodeinfo', 'hardware', 'model']); var hwDict = count(nodes, ['model']);
var geoDict = count(nodes, ['nodeinfo', 'location'], function (d) { var geoDict = count(nodes, ['location'], function (d) {
return d && d.longitude && d.latitude ? _.t('yes') : _.t('no'); 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) { if (d === null) {
return null; return null;
} else if (d.enabled) { } else if (d.enabled) {
@ -107,7 +102,7 @@ define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
return _.t('node.deactivated'); 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) { for (var mac in data.gateways) {
if (data.gateways.hasOwnProperty(mac) && mac === d) { if (data.gateways.hasOwnProperty(mac) && mac === d) {
d = data.gateways[mac]; d = data.gateways[mac];
@ -117,7 +112,7 @@ define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
return null; return null;
}); });
var siteDict = count(nodes, ['nodeinfo', 'system', 'site_code'], function (d) { var siteDict = count(nodes, ['nodeinfo', 'site_code'], function (d) {
if (config.siteNames) { if (config.siteNames) {
config.siteNames.forEach(function (t) { config.siteNames.forEach(function (t) {
if (d === t.site) { if (d === t.site) {
@ -158,7 +153,6 @@ define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
}; };
self.render = function render(el) { self.render = function render(el) {
var h2;
self.renderSingle(el, 'node.status', statusTable); self.renderSingle(el, 'node.status', statusTable);
self.renderSingle(el, 'node.firmware', fwTable); self.renderSingle(el, 'node.firmware', fwTable);
self.renderSingle(el, 'node.hardware', hwTable); self.renderSingle(el, 'node.hardware', hwTable);
@ -168,12 +162,14 @@ define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
self.renderSingle(el, 'node.site', siteTable); self.renderSingle(el, 'node.site', siteTable);
if (config.globalInfos) { if (config.globalInfos) {
var images = document.createElement('div');
el.appendChild(images);
var img = [];
config.globalInfos.forEach(function (globalInfo) { config.globalInfos.forEach(function (globalInfo) {
h2 = document.createElement('h2'); img.push(V.h('h2', globalInfo.name));
h2.textContent = globalInfo.name; img.push(helper.showStat(V, globalInfo));
el.appendChild(h2);
el.appendChild(showStatGlobal(globalInfo));
}); });
V.patch(images, V.h('div', img));
} }
}; };

View File

@ -38,18 +38,18 @@ define(['moment', 'snabbdom', 'helper'], function (moment, V, helper) {
var td0Content = []; var td0Content = [];
var td1Content = []; var td1Content = [];
var aClass = ['hostname', d.flags.online ? 'online' : 'offline']; var aClass = ['hostname', d.is_online ? 'online' : 'offline'];
td1Content.push(V.h('a', { td1Content.push(V.h('a', {
props: { props: {
className: aClass.join(' '), className: aClass.join(' '),
href: router.generateLink({ node: d.nodeinfo.node_id }) href: router.generateLink({ node: d.node_id })
}, on: { }, on: {
click: function (e) { 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)) { if (helper.hasLocation(d)) {
td0Content.push(V.h('span', { props: { className: 'icon ion-location' } })); td0Content.push(V.h('span', { props: { className: 'icon ion-location' } }));

View File

@ -17,11 +17,11 @@ define(function () {
}; };
this.gotoNode = function gotoNode(d) { this.gotoNode = function gotoNode(d) {
setTitle(d.nodeinfo.hostname); setTitle(d.hostname);
}; };
this.gotoLink = function gotoLink(d) { 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() { this.gotoLocation = function gotoLocation() {

View File

@ -73,30 +73,29 @@ define({
}, },
/* Helpers working with nodes */ /* Helpers working with nodes */
offline: function offline(d) { offline: function offline(d) {
return !d.flags.online; return !d.is_online;
}, },
online: function online(d) { online: function online(d) {
return d.flags.online; return d.is_online;
}, },
hasLocation: function hasLocation(d) { hasLocation: function hasLocation(d) {
return 'location' in d.nodeinfo && return 'location' in d &&
Math.abs(d.nodeinfo.location.latitude) < 90 && Math.abs(d.location.latitude) < 90 &&
Math.abs(d.nodeinfo.location.longitude) < 180; Math.abs(d.location.longitude) < 180;
}, },
subtract: function subtract(a, b) { subtract: function subtract(a, b) {
var ids = {}; var ids = {};
b.forEach(function (d) { b.forEach(function (d) {
ids[d.nodeinfo.node_id] = true; ids[d.node_id] = true;
}); });
return a.filter(function (d) { 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) { 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) { if (value === null || value === undefined) {
return ''; return '';
} }
var tr = document.createElement('tr'); if (typeof value !== 'object') {
var th = document.createElement('th'); value = V.h('td', value);
th.textContent = _.t(label);
tr.appendChild(th);
var td = document.createElement('td');
if (typeof value === 'function') {
value(td);
} else {
td.appendChild(document.createTextNode(value));
} }
tr.appendChild(td); return V.h('tr', [
V.h('th', _.t(label)),
el.appendChild(tr); value
]);
return td;
}, },
showStat: function showStat(o, subst) { showStat: function showStat(V, o, subst) {
var content; var content;
subst = typeof subst !== 'undefined' ? subst : {}; subst = typeof subst !== 'undefined' ? subst : {};
content = document.createElement('img'); content = V.h('img', { attrs: { src: require('helper').listReplace(o.image, subst) } });
content.src = require('helper').listReplace(o.image, subst);
var p = document.createElement('p');
if (o.href) { if (o.href) {
var link = document.createElement('a'); return V.h('p', V.h('a', {
link.target = '_blank'; attrs:
link.href = require('helper').listReplace(o.href, subst); {
link.appendChild(content); href: require('helper').listReplace(o.href, subst),
target: '_blank',
if (o.title) { title: require('helper').listReplace(o.title, subst)
link.title = require('helper').listReplace(o.title, subst);
} }
}, content));
p.appendChild(link);
} else {
p.appendChild(content);
} }
return V.h('p', content);
return p;
}, },
getTileBBox: function getTileBBox(s, map, tileSize, margin) { getTileBBox: function getTileBBox(s, map, tileSize, margin) {

View File

@ -144,10 +144,10 @@ define(['Navigo'], function (Navigo) {
objects.gateways = data.gateways; objects.gateways = data.gateways;
data.nodes.all.forEach(function (d) { 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; objects.links[d.id] = d;
}); });
}; };

View File

@ -6,6 +6,7 @@
"links": "Links", "links": "Links",
"clients": "Clients", "clients": "Clients",
"distance": "Distance", "distance": "Distance",
"connectionType": "Connection type",
"tq": "Transmit quality", "tq": "Transmit quality",
"lastOnline": "online, last message %{time} (%{date})", "lastOnline": "online, last message %{time} (%{date})",
"lastOffline": "offline, last message %{time} (%{date})", "lastOffline": "offline, last message %{time} (%{date})",

View File

@ -58,7 +58,7 @@
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
width: 66%; width: 60%;
} }
} }
} }