Completed
Pull Request — develop (#151)
by Xaver
33s
created

node.js ➔ ... ➔ ?!?.filter   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
nc 1
dl 0
loc 3
rs 10
nop 1
1
define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
2
  function (SortTable, V, d3Interpolate, moment, helper) {
3
    'use strict';
4
    V = V.default;
5
6
    function showGeoURI(d) {
7
      if (!helper.hasLocation(d)) {
8
        return undefined;
9
      }
10
11
      return function (el) {
12
        var a = document.createElement('a');
13
        a.textContent = Number(d.nodeinfo.location.latitude.toFixed(6)) + ', ' + Number(d.nodeinfo.location.longitude.toFixed(6));
14
        a.href = 'geo:' + d.nodeinfo.location.latitude + ',' + d.nodeinfo.location.longitude;
15
        el.appendChild(a);
16
      };
17
    }
18
19
    function showStatus(d) {
20
      return function (el) {
21
        el.classList.add(d.flags.unseen ? 'unseen' : (d.flags.online ? 'online' : 'offline'));
22
        el.textContent = _.t((d.flags.online ? 'node.lastOnline' : 'node.lastOffline'), {
23
          time: d.lastseen.fromNow(),
24
          date: d.lastseen.format('DD.MM.YYYY, H:mm:ss')
25
        });
26
      };
27
    }
28
29
    function showFirmware(d) {
30
      return [
31
        helper.dictGet(d.nodeinfo, ['software', 'firmware', 'release']),
32
        helper.dictGet(d.nodeinfo, ['software', 'firmware', 'base'])
33
      ].filter(function (n) {
34
        return n !== null;
35
      }).join(' / ') || undefined;
36
    }
37
38
    function showSite(d, config) {
39
      var site = helper.dictGet(d.nodeinfo, ['system', 'site_code']);
40
      var rt = site;
41
      if (config.siteNames) {
42
        config.siteNames.forEach(function (t) {
43
          if (site === t.site) {
44
            rt = t.name;
45
          }
46
        });
47
      }
48
      return rt;
49
    }
50
51
    function showUptime(d) {
52
      if (!('uptime' in d.statistics)) {
53
        return undefined;
54
      }
55
56
      return moment.duration(d.statistics.uptime, 'seconds').humanize();
57
    }
58
59
    function showFirstseen(d) {
60
      if (!('firstseen' in d)) {
61
        return undefined;
62
      }
63
64
      return d.firstseen.fromNow(true);
65
    }
66
67
    function showClients(d) {
68
      if (!d.flags.online) {
69
        return undefined;
70
      }
71
72
      return function (el) {
73
        el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : _.t('none')));
74
        el.appendChild(document.createElement('br'));
75
76
        var span = document.createElement('span');
77
        span.classList.add('clients');
78
        span.innerHTML = '<i class="ion-person"></i>'.repeat(d.statistics.clients);
79
        el.appendChild(span);
80
      };
81
    }
82
83
    function showIPs(d) {
84
      var ips = helper.dictGet(d.nodeinfo, ['network', 'addresses']);
85
      if (ips === null) {
86
        return undefined;
87
      }
88
89
      ips.sort();
90
91
      return function (el) {
92
        ips.forEach(function (ip, i) {
93
          var link = !ip.startsWith('fe80:');
94
95
          if (i > 0) {
96
            el.appendChild(document.createElement('br'));
97
          }
98
99
          if (link) {
100
            var a = document.createElement('a');
101
            a.href = 'http://[' + ip + ']/';
102
            a.textContent = ip;
103
            el.appendChild(a);
104
          } else {
105
            el.appendChild(document.createTextNode(ip));
106
          }
107
        });
108
      };
109
    }
110
111
    function showBar(v, width, warning) {
112
      var span = document.createElement('span');
113
      span.classList.add('bar');
114
115
      var bar = document.createElement('span');
116
      bar.style.width = (width * 100) + '%';
117
      if (warning) {
118
        span.classList.add('warning');
119
      }
120
      span.appendChild(bar);
121
122
      var label = document.createElement('label');
123
      label.textContent = v;
124
      span.appendChild(label);
125
126
      return span;
127
    }
128
129
    function showLoad(d) {
130
      if (!('loadavg' in d.statistics)) {
131
        return undefined;
132
      }
133
134
      return function (el) {
135
        var value = d.statistics.loadavg.toFixed(2);
136
        var width = d.statistics.loadavg % 1;
137
        var warning = false;
138
        if (d.statistics.loadavg >= d.nodeinfo.hardware.nproc) {
139
          warning = true;
140
        }
141
        el.appendChild(showBar(value, width, warning));
142
      };
143
    }
144
145
    function showRAM(d) {
146
      if (!('memory_usage' in d.statistics)) {
147
        return undefined;
148
      }
149
150
      return function (el) {
151
        var value = Math.round(d.statistics.memory_usage * 100) + ' %';
152
        var width = d.statistics.memory_usage;
153
        var warning = false;
154
        if (d.statistics.memory_usage >= 0.8) {
155
          warning = true;
156
        }
157
        el.appendChild(showBar(value, width, warning));
158
      };
159
    }
160
161
    function showAutoupdate(d) {
162
      var au = helper.dictGet(d.nodeinfo, ['software', 'autoupdater']);
163
      if (!au) {
164
        return undefined;
165
      }
166
167
      return au.enabled ? _.t('node.activated', { branch: au.branch }) : _.t('node.deactivated');
168
    }
169
170
    function showStatImg(o, d) {
171
      var subst = {};
172
      subst['{NODE_ID}'] = d.nodeinfo.node_id;
173
      subst['{NODE_NAME}'] = d.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_');
174
      subst['{TIME}'] = d.lastseen.format('DDMMYYYYHmmss');
175
      subst['{LOCALE}'] = _.locale();
176
      return helper.showStat(o, subst);
177
    }
178
179
    return function (config, el, router, d, gateways) {
180
      var linkScale = d3Interpolate.interpolate('#F02311', '#04C714');
181
182
      function renderNeighbourRow(n) {
183
        var icons = [];
184
        icons.push(V.h('span', { props: { className: n.incoming ? 'ion-arrow-left-c' : 'ion-arrow-right-c' } }));
185
        if (helper.hasLocation(n.node)) {
186
          icons.push(V.h('span', { props: { className: 'ion-location' } }));
187
        }
188
189
        var name = V.h('a', {
190
          props: {
191
            className: 'online',
192
            href: router.generateLink({ node: n.node.nodeinfo.node_id })
193
          }, on: {
194
            click: function (e) {
195
              router.fullUrl({ node: n.node.nodeinfo.node_id }, e);
196
            }
197
          }
198
        }, n.node.nodeinfo.hostname);
199
200
        var td1 = V.h('td', icons);
201
        var td2 = V.h('td', name);
202
        var td3 = V.h('td', (n.node.statistics.clients ? n.node.statistics.clients.toString() : '0'));
203
        var td4 = V.h('td', { style: { color: linkScale(1 / n.link.tq) } }, helper.showTq(n.link));
204
        var td5 = V.h('td', helper.showDistance(n.link));
205
206
        return V.h('tr', [td1, td2, td3, td4, td5]);
207
      }
208
209
      var h2 = document.createElement('h2');
210
      h2.textContent = d.nodeinfo.hostname;
211
      el.appendChild(h2);
212
213
      var attributes = document.createElement('table');
214
      attributes.classList.add('attributes');
215
216
      helper.attributeEntry(attributes, 'node.status', showStatus(d));
217
      helper.attributeEntry(attributes, 'node.gateway', d.flags.gateway ? 'ja' : null);
218
      helper.attributeEntry(attributes, 'node.coordinates', showGeoURI(d));
219
220
      if (config.nodeInfobox && config.nodeInfobox.contact) {
221
        helper.attributeEntry(attributes, 'node.contact', helper.dictGet(d.nodeinfo, ['owner', 'contact']));
222
      }
223
224
      helper.attributeEntry(attributes, 'node.hardware', helper.dictGet(d.nodeinfo, ['hardware', 'model']));
225
      helper.attributeEntry(attributes, 'node.primaryMac', helper.dictGet(d.nodeinfo, ['network', 'mac']));
226
      helper.attributeEntry(attributes, 'node.id', helper.dictGet(d.nodeinfo, ['node_id']));
227
      helper.attributeEntry(attributes, 'node.firmware', showFirmware(d));
228
      helper.attributeEntry(attributes, 'node.site', showSite(d, config));
229
      helper.attributeEntry(attributes, 'node.uptime', showUptime(d));
230
      helper.attributeEntry(attributes, 'node.firstSeen', showFirstseen(d));
231
      if (config.nodeInfobox && config.nodeInfobox.hardwareUsage) {
232
        helper.attributeEntry(attributes, 'node.systemLoad', showLoad(d));
233
        helper.attributeEntry(attributes, 'node.ram', showRAM(d));
234
      }
235
      helper.attributeEntry(attributes, 'node.ipAddresses', showIPs(d));
236
      helper.attributeEntry(attributes, 'node.selectedGateway', gateways[helper.dictGet(d.statistics, ['gateway'])]);
237
      helper.attributeEntry(attributes, 'node.update', showAutoupdate(d));
238
      helper.attributeEntry(attributes, 'node.clients', showClients(d));
239
240
      el.appendChild(attributes);
241
242
      if (d.neighbours.length > 0) {
243
        var h3 = document.createElement('h3');
244
        h3.textContent = _.t('node.link', d.neighbours.length) + ' (' + d.neighbours.length + ')';
245
        el.appendChild(h3);
246
247
        var headings = [{
248
          name: ''
249
        }, {
250
          name: 'node.nodes',
251
          sort: function (a, b) {
252
            return a.node.nodeinfo.hostname.localeCompare(b.node.nodeinfo.hostname);
253
          },
254
          reverse: false
255
        }, {
256
          name: 'node.clients',
257
          class: 'ion-people',
258
          sort: function (a, b) {
259
            return ('clients' in a.node.statistics ? a.node.statistics.clients : -1) -
260
              ('clients' in b.node.statistics ? b.node.statistics.clients : -1);
261
          },
262
          reverse: true
263
        }, {
264
          name: 'node.tq',
265
          class: 'ion-connection-bars',
266
          sort: function (a, b) {
267
            return a.link.tq - b.link.tq;
268
          },
269
          reverse: true
270
        }, {
271
          name: 'node.distance',
272
          class: 'ion-arrow-resize',
273
          sort: function (a, b) {
274
            return (a.link.distance === undefined ? -1 : a.link.distance) -
275
              (b.link.distance === undefined ? -1 : b.link.distance);
276
          },
277
          reverse: true
278
        }];
279
280
        var table = new SortTable(headings, 1, renderNeighbourRow);
281
        table.setData(d.neighbours);
282
        table.el.elm.classList.add('node-links');
283
        el.appendChild(table.el.elm);
284
      }
285
286
      if (config.nodeInfos) {
287
        config.nodeInfos.forEach(function (nodeInfo) {
288
          var h4 = document.createElement('h4');
289
          h4.textContent = nodeInfo.name;
290
          el.appendChild(h4);
291
          el.appendChild(showStatImg(nodeInfo, d));
292
        });
293
      }
294
    };
295
  });
296