@cryptotaxi247 / netdata-1 / commits / 4721ed4f1

Support for aggregate node view (#5902)

* Introduce sign-in banner * Show/hide sign-in banner * Improvements * Fixed banner for white theme. * Preliminary work on integrating console with agent * Updated console * Fetch js and css from cloud #431 * Minor * Fixed for better console embedding * Fixed a problem with the Makefile * Minor * Dynamically generate index fragment based on cloudBaseURL * Relative path to console * Added cache-busters * Add Nodes view access * Improved console/index.html * Fixes in console/index * Version bump * Removed extraneous react import (thanks Nicolas) * Use netdataNoBootstrap * Use white theme * Touch agent API call (updates lastseen timestamp) * Revert to API version 1 * Move touch to init cloud * Remove logs * Updated js file href * Nodes view on unsigned redirect * Revert yellow color * Remove comment * Beta color update * Move styles to CSS * Cloud console link fix * Remove cloudBaseUrl * Use local dashboard.js, duh! * Added GoogleTagManager * Remove duplicate dashboard.js * Analytics fix Analytics fix

George Moschovitis committed May 15, 2019 at 16:50 UTC 4721ed4f14d1ec71af201922bb9fda112e14974a
8 files changed +250 -100
.gitignore
+1
@@ -130,6 +130,7 @@ cmake_install.cmake
130 .jetbrains*
131
132 .DS_Store
133 +webcopylocal*
134
135 contrib/debian/changelog
136
web/gui/Makefile.am
+11
@@ -69,6 +69,17 @@ dist_web_DATA = \
69 version.txt \
70 $(NULL)
71
72 +
73 +webconsoledir=$(webdir)/console
74 +dist_webconsole_DATA = \
75 + console/index.html \
76 + $(NULL)
77 +
78 +webstaticdir=$(webdir)/static/img
79 +dist_webstatic_DATA = \
80 + static/img/netdata-logomark.svg \
81 + $(NULL)
82 +
83 weblibdir=$(webdir)/lib
84 dist_weblib_DATA = \
85 lib/bootstrap-3.3.7.min.js \
web/gui/console/index.html new
+72
@@ -0,0 +1,72 @@
1 +<!DOCTYPE html>
2 +<html>
3 +
4 +<head>
5 + <title>Netdata Console</title>
6 + <meta name="application-name" content="netdata" />
7 + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
8 + <meta charset="utf-8" />
9 + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
10 + <meta name="viewport" content="width=device-width, initial-scale=1" />
11 + <meta name="apple-mobile-web-app-capable" content="yes" />
12 + <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
13 + <link rel="icon" href="/favicon.ico" />
14 + <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
15 + <!-- Google Tag Manager -->
16 + <script>(function (w, d, s, l, i) {
17 + w[l] = w[l] || []; w[l].push({
18 + 'gtm.start':
19 + new Date().getTime(), event: 'gtm.js'
20 + }); var f = d.getElementsByTagName(s)[0],
21 + j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src =
22 + 'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f);
23 + })(window, document, 'script', 'dataLayer', 'GTM-N6CBMJD');
24 + googleTagManager = window.dataLayer || [];
25 + </script>
26 + <!-- End Google Tag Manager -->
27 + <script>
28 + function loadJSFile(filename) {
29 + const s = document.createElement("script")
30 + s.setAttribute("type", "text/javascript")
31 + s.setAttribute("src", filename)
32 + document.getElementsByTagName("head")[0].appendChild(s)
33 + }
34 +
35 + function loadCSSFile(filename) {
36 + const l = document.createElement("link")
37 + l.setAttribute("rel", "stylesheet")
38 + l.setAttribute("type", "text/css")
39 + l.setAttribute("href", filename)
40 + document.getElementsByTagName("head")[0].appendChild(l)
41 + }
42 +
43 + var cloudBaseURL = localStorage.getItem("cloud.baseURL") || "https://netdata.cloud"
44 +
45 + loadCSSFile(`${cloudBaseURL}/static/console/main.css?v=4`)
46 + </script>
47 +</head>
48 +
49 +<body class="mdc-theme--background mdc-typography">
50 + <!-- Google Tag Manager (noscript) -->
51 + <noscript>
52 + <iframe src="https://www.googletagmanager.com/ns.html?id=GTM-N6CBMJD" height="0" width="0"
53 + style="display:none;visibility:hidden"></iframe>
54 + </noscript>
55 + <!-- End Google Tag Manager (noscript) -->
56 + <main id="app" class="console-app" data-host="agent"></main>
57 + <script>
58 + const main = document.getElementById("app")
59 + main.setAttribute("data-static-base-url", cloudBaseURL)
60 + main.setAttribute("data-api-base-url", cloudBaseURL)
61 + main.setAttribute("data-api-base-url-v2", cloudBaseURL)
62 +
63 + loadJSFile(`${cloudBaseURL}/static/console/main.js?v=4`)
64 + </script>
65 + <script>
66 + var netdataTheme = "white"
67 + var netdataNoBootstrap = true
68 + </script>
69 + <script type="text/javascript" src="/dashboard.js?v20190515"></script>
70 +</body>
71 +
72 +</html>
web/gui/index.html
+1
@@ -124,6 +124,7 @@
124 </div>
125 <nav class="collapse navbar-collapse navbar-right" role="navigation">
126 <ul class="nav navbar-nav">
127 + <li title="Nodes view" data-toggle="tooltip" data-placement="bottom"><a onclick="openAuthenticatedUrl('console/index.html');" class="btn" target="_blank"><i class="fas fa-tv"></i>&nbsp;<span class="hidden-sm hidden-md">Nodes<sup class="beta"> beta</sup></span></a></li>
128 <li id="alarmsButton" title="check the health monitoring alarms and their log" data-toggle="tooltip" data-placement="bottom"><a href="#" class="btn" data-toggle="modal" data-target="#alarmsModal"><i class="fas fa-bell"></i>&nbsp;<span class="hidden-sm hidden-md">Alarms&nbsp;</span><span id="alarms_count_badge" class="badge"></span></a></li>
129 <li title="change dashboard settings" data-toggle="tooltip" data-placement="bottom"><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal"><i class="fas fa-cog"></i>&nbsp;<span class="hidden-sm hidden-md">Settings</span></a></li>
130 <li title="check for netdata updates<br/>you should keep your netdata updated" data-toggle="tooltip" data-placement="bottom" class="hidden-sm" id="updateButton"><a href="#" class="btn" data-toggle="modal" data-target="#updateModal"><i class="fas fa-cloud-download-alt"></i> <span class="hidden-sm hidden-md">Update </span><span id="update_badge" class="badge"></span></a></li>
web/gui/main.css
+4
@@ -713,3 +713,7 @@ body.modal-open {
713 margin-left: 5px;
714 color: #17CE8A;
715 }
716 +
717 +.beta {
718 + color:#FFCC00;
719 +}
web/gui/main.js
+155 -100
@@ -258,7 +258,7 @@ var urlOptions = {
258
259 $('.highlight-tooltip').tooltip({
260 html: true,
261 - delay: {show: 500, hide: 0},
261 + delay: { show: 500, hide: 0 },
262 container: 'body'
263 });
264 } else {
@@ -588,20 +588,20 @@ function renderMachines(machinesArray) {
588 const alternateUrlItems = (
589 `<div class="agent-alternate-urls agent-${machine.guid} collapsed">
590 ${machine.alternate_urls.reduce((str, url) => {
591 - if (url === maskedURL) {
592 - return str
593 - }
591 + if (url === maskedURL) {
592 + return str
593 + }
594
595 - return str + (
596 - `<div class="agent-item agent-item--alternate">
595 + return str + (
596 + `<div class="agent-item agent-item--alternate">
597 <div></div>
598 <a href="${url}" title="${url}">${truncateString(url, 64)}</a>
599 <a href="#" onclick="deleteRegistryModalHandler('${machine.guid}', '${machine.name}', '${url}'); return false;">
600 <i class="fas fa-trash" style="color: #777;"></i>
601 </a>
602 </div>`
603 - )
604 - },
603 + )
604 + },
605 ''
606 )}
607 </div>`
@@ -650,14 +650,14 @@ function renderMachines(machinesArray) {
650 html += `<div class="info-item">Demo netdata nodes</div>`;
651
652 const demoServers = [
653 - {url: "//london.netdata.rocks/default.html", title: "UK - London (DigitalOcean.com)"},
654 - {url: "//newyork.netdata.rocks/default.html", title: "US - New York (DigitalOcean.com)"},
655 - {url: "//sanfrancisco.netdata.rocks/default.html", title: "US - San Francisco (DigitalOcean.com)"},
656 - {url: "//atlanta.netdata.rocks/default.html", title: "US - Atlanta (CDN77.com)"},
657 - {url: "//frankfurt.netdata.rocks/default.html", title: "Germany - Frankfurt (DigitalOcean.com)"},
658 - {url: "//toronto.netdata.rocks/default.html", title: "Canada - Toronto (DigitalOcean.com)"},
659 - {url: "//singapore.netdata.rocks/default.html", title: "Japan - Singapore (DigitalOcean.com)"},
660 - {url: "//bangalore.netdata.rocks/default.html", title: "India - Bangalore (DigitalOcean.com)"},
653 + { url: "//london.netdata.rocks/default.html", title: "UK - London (DigitalOcean.com)" },
654 + { url: "//newyork.netdata.rocks/default.html", title: "US - New York (DigitalOcean.com)" },
655 + { url: "//sanfrancisco.netdata.rocks/default.html", title: "US - San Francisco (DigitalOcean.com)" },
656 + { url: "//atlanta.netdata.rocks/default.html", title: "US - Atlanta (CDN77.com)" },
657 + { url: "//frankfurt.netdata.rocks/default.html", title: "Germany - Frankfurt (DigitalOcean.com)" },
658 + { url: "//toronto.netdata.rocks/default.html", title: "Canada - Toronto (DigitalOcean.com)" },
659 + { url: "//singapore.netdata.rocks/default.html", title: "Japan - Singapore (DigitalOcean.com)" },
660 + { url: "//bangalore.netdata.rocks/default.html", title: "India - Bangalore (DigitalOcean.com)" },
661
662 ]
663
@@ -704,6 +704,14 @@ function restrictMyNetdataMenu() {
704 </div>`);
705 }
706
707 +function openAuthenticatedUrl(url) {
708 + if (isSignedIn()) {
709 + window.open(url);
710 + } else {
711 + window.open(`${NETDATA.registry.cloudBaseURL}/account/sign-in-agent?id=${NETDATA.registry.machine_guid}&name=${encodeURIComponent(NETDATA.registry.hostname)}&origin=${encodeURIComponent(window.location.origin + "/")}`);
712 + }
713 +}
714 +
715 function renderMyNetdataMenu(machinesArray) {
716 const el = document.getElementById('my-netdata-dropdown-content');
717 el.classList.add(`theme-${netdataTheme}`);
@@ -766,6 +774,11 @@ function renderMyNetdataMenu(machinesArray) {
774 if (!isSignedIn()) {
775 html += (
776 `<div class="agent-item">
777 + <i class="fas fa-tv"></i>
778 + <a onClick="openAuthenticatedUrl('console/index.html');" target="_blank">Nodes<sup class="beta"> beta</sup></a>
779 + <div></div>
780 + </div>
781 + <div class="agent-item">
782 <i class="fas fa-cog""></i>
783 <a href="#" onclick="switchRegistryModalHandler(); return false;">Switch Identity</a>
784 <div></div>
@@ -779,6 +792,11 @@ function renderMyNetdataMenu(machinesArray) {
792 } else {
793 html += (
794 `<div class="agent-item">
795 + <i class="fas fa-tv"></i>
796 + <a onclick="openAuthenticatedUrl('console/index.html');" target="_blank">Nodes<sup class="beta"> beta</sup></a>
797 + <div></div>
798 + </div>
799 + <div class="agent-item">
800 <i class="fas fa-sync"></i>
801 <a href="#" onclick="showSyncModal(); return false">Synchronize with netdata.cloud</a>
802 <div></div>
@@ -991,7 +1009,7 @@ function notifyForSwitchRegistry() {
1009 }
1010 }
1011
994 -var deleteRegistryGuid = null;
1012 +var deleteRegistryGuid = null;
1013 var deleteRegistryUrl = null;
1014
1015 function deleteRegistryModalHandler(guid, name, url) {
@@ -1004,7 +1022,7 @@ function deleteRegistryModalHandler(guid, name, url) {
1022 document.getElementById('deleteRegistryServerName2').innerHTML = name;
1023 document.getElementById('deleteRegistryServerURL').innerHTML = url;
1024 document.getElementById('deleteRegistryResponse').innerHTML = '';
1007 -
1025 +
1026 $('#deleteRegistryModal').modal('show');
1027 }
1028
@@ -1027,7 +1045,7 @@ function notifyForDeleteRegistry() {
1045 deleteRegistryUrl = null;
1046 $('#deleteRegistryModal').modal('hide');
1047 NETDATA.registry.init();
1030 - });
1048 + });
1049 });
1050 } else {
1051 NETDATA.registry.delete(deleteRegistryUrl, function (result) {
@@ -1038,7 +1056,7 @@ function notifyForDeleteRegistry() {
1056 } else {
1057 responseEl.innerHTML = "<b>Sorry, this command was rejected by the registry server!</b>";
1058 }
1041 - });
1059 + });
1060 }
1061 }
1062 }
@@ -1119,7 +1137,7 @@ function scrollToId(hash) {
1137 var offset = $('#' + hash).offset();
1138 if (typeof offset !== 'undefined') {
1139 //console.log('scrolling to ' + hash + ' at ' + offset.top.toString());
1122 - $('html, body').animate({scrollTop: offset.top - 30}, 0);
1140 + $('html, body').animate({ scrollTop: offset.top - 30 }, 0);
1141 }
1142 }
1143
@@ -1171,7 +1189,7 @@ var netdataDashboard = {
1189 }
1190
1191 if (typeof this.sparklines_registry[key] === 'undefined') {
1174 - this.sparklines_registry[key] = {count: 1};
1192 + this.sparklines_registry[key] = { count: 1 };
1193 } else {
1194 this.sparklines_registry[key].count++;
1195 }
@@ -1772,7 +1790,7 @@ function renderPage(menus, data) {
1790
1791 sidebar += '<li class="" style="padding-top:15px;"><a href="https://github.com/netdata/netdata/blob/master/docs/Add-more-charts-to-netdata.md#add-more-charts-to-netdata" target="_blank"><i class="fas fa-plus"></i> add more charts</a></li>';
1792 sidebar += '<li class=""><a href="https://github.com/netdata/netdata/tree/master/health#Health-monitoring" target="_blank"><i class="fas fa-plus"></i> add more alarms</a></li>';
1775 - sidebar += '<li class="" style="margin:20px;color:#666;"><small>netdata on <b>' + data.hostname.toString() + '</b>, collects every ' + ((data.update_every === 1) ? 'second' : data.update_every.toString() + ' seconds') + ' <b>' + data.dimensions_count.toLocaleString() + '</b> metrics, presented as <b>' + data.charts_count.toLocaleString() + '</b> charts and monitored by <b>' + data.alarms_count.toLocaleString() + '</b> alarms, using ' + Math.round(data.rrd_memory_bytes / 1024 / 1024).toLocaleString() + ' MB of memory for ' + NETDATA.seconds4human(data.update_every * data.history, {space: '&nbsp;'}) + ' of real-time history.<br/>&nbsp;<br/><b>netdata</b><br/>' + data.version.toString() + '</small></li>';
1793 + sidebar += '<li class="" style="margin:20px;color:#666;"><small>netdata on <b>' + data.hostname.toString() + '</b>, collects every ' + ((data.update_every === 1) ? 'second' : data.update_every.toString() + ' seconds') + ' <b>' + data.dimensions_count.toLocaleString() + '</b> metrics, presented as <b>' + data.charts_count.toLocaleString() + '</b> charts and monitored by <b>' + data.alarms_count.toLocaleString() + '</b> alarms, using ' + Math.round(data.rrd_memory_bytes / 1024 / 1024).toLocaleString() + ' MB of memory for ' + NETDATA.seconds4human(data.update_every * data.history, { space: '&nbsp;' }) + ' of real-time history.<br/>&nbsp;<br/><b>netdata</b><br/>' + data.version.toString() + '</small></li>';
1794 sidebar += '</ul>';
1795 div.innerHTML = html;
1796 document.getElementById('sidebar').innerHTML = sidebar;
@@ -1886,7 +1904,7 @@ function loadJs(url, callback) {
1904 url: url,
1905 cache: true,
1906 dataType: "script",
1889 - xhrFields: {withCredentials: true} // required for the cookie
1907 + xhrFields: { withCredentials: true } // required for the cookie
1908 })
1909 .fail(function () {
1910 alert('Cannot load required JS library: ' + url);
@@ -1988,8 +2006,8 @@ function alarmsUpdateModal() {
2006 if (data === null) {
2007 document.getElementById('alarms_active').innerHTML =
2008 document.getElementById('alarms_all').innerHTML =
1991 - document.getElementById('alarms_log').innerHTML =
1992 - 'failed to load alarm data!';
2009 + document.getElementById('alarms_log').innerHTML =
2010 + 'failed to load alarm data!';
2011 return;
2012 }
2013
@@ -2039,7 +2057,7 @@ function alarmsUpdateModal() {
2057
2058 return '<code>' + alarm.lookup_method + '</code> '
2059 + dimensions + ', of chart <code>' + alarm.chart + '</code>'
2042 - + ', starting <code>' + NETDATA.seconds4human(alarm.lookup_after + alarm.lookup_before, {space: '&nbsp;'}) + '</code> and up to <code>' + NETDATA.seconds4human(alarm.lookup_before, {space: '&nbsp;'}) + '</code>'
2060 + + ', starting <code>' + NETDATA.seconds4human(alarm.lookup_after + alarm.lookup_before, { space: '&nbsp;' }) + '</code> and up to <code>' + NETDATA.seconds4human(alarm.lookup_before, { space: '&nbsp;' }) + '</code>'
2061 + ((alarm.lookup_options) ? (', with options <code>' + alarm.lookup_options.replace(/ /g, ',&nbsp;') + '</code>') : '')
2062 + '.';
2063 }
@@ -2115,9 +2133,9 @@ function alarmsUpdateModal() {
2133 }
2134
2135 html += '<tr><td width="10%" style="text-align:right">check&nbsp;every</td><td>' + NETDATA.seconds4human(alarm.update_every, {
2118 - space: '&nbsp;',
2119 - negative_suffix: ''
2120 - }) + '</td></tr>'
2136 + space: '&nbsp;',
2137 + negative_suffix: ''
2138 + }) + '</td></tr>'
2139 + ((has_alarm === true) ? ('<tr><td width="10%" style="text-align:right">execute</td><td><span style="font-family: monospace;">' + alarm.exec + '</span>' + delay + '</td></tr>') : '')
2140 + '<tr><td width="10%" style="text-align:right">source</td><td><span style="font-family: monospace;">' + alarm.source + '</span></td></tr>'
2141 + '</table></td></tr>';
@@ -2162,7 +2180,7 @@ function alarmsUpdateModal() {
2180 // not found - this should never happen!
2181 if (typeof chart === 'undefined') {
2182 console.log('WARNING: alarm ' + x + ' is linked to chart ' + alarm.chart + ', which is not found in the list of chart got from the server.');
2165 - chart = {priority: 9999999};
2183 + chart = { priority: 9999999 };
2184 }
2185 else if (typeof chart.menu !== 'undefined' && typeof chart.submenu !== 'undefined')
2186 // the family based on the chart
@@ -2299,16 +2317,16 @@ function alarmsUpdateModal() {
2317
2318 switch (row.status) {
2319 case 'CRITICAL':
2302 - return {classes: 'danger'};
2320 + return { classes: 'danger' };
2321 break;
2322 case 'WARNING':
2305 - return {classes: 'warning'};
2323 + return { classes: 'warning' };
2324 break;
2325 case 'UNDEFINED':
2308 - return {classes: 'info'};
2326 + return { classes: 'info' };
2327 break;
2328 case 'CLEAR':
2311 - return {classes: 'success'};
2329 + return { classes: 'success' };
2330 break;
2331 }
2332 return {};
@@ -2496,7 +2514,7 @@ function alarmsUpdateModal() {
2514 formatter: function (value, row, index) {
2515 void (row);
2516 void (index);
2499 - return NETDATA.seconds4human(value, {negative_suffix: '', space: ' ', now: 'no time'});
2517 + return NETDATA.seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
2518 },
2519 align: 'center',
2520 valign: 'middle',
@@ -2510,7 +2528,7 @@ function alarmsUpdateModal() {
2528 formatter: function (value, row, index) {
2529 void (row);
2530 void (index);
2513 - return NETDATA.seconds4human(value, {negative_suffix: '', space: ' ', now: 'no time'});
2531 + return NETDATA.seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
2532 },
2533 align: 'center',
2534 valign: 'middle',
@@ -2642,7 +2660,7 @@ function alarmsUpdateModal() {
2660 void (row);
2661 void (index);
2662
2645 - return NETDATA.seconds4human(value, {negative_suffix: '', space: ' ', now: 'no time'});
2663 + return NETDATA.seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
2664 },
2665 align: 'center',
2666 valign: 'middle',
@@ -2846,32 +2864,32 @@ function versionsMatch(v1, v2) {
2864 if (v1 == v2) {
2865 return true;
2866 } else {
2849 - let s1=v1.split('.');
2850 - let s2=v2.split('.');
2867 + let s1 = v1.split('.');
2868 + let s2 = v2.split('.');
2869 // Check major version
2852 - let n1 = parseInt(s1[0].substring(1,2),10);
2853 - let n2 = parseInt(s2[0].substring(1,2), 10);
2854 - if ( n1 < n2 ) return false;
2855 - else if ( n1 > n2 ) return true;
2870 + let n1 = parseInt(s1[0].substring(1, 2), 10);
2871 + let n2 = parseInt(s2[0].substring(1, 2), 10);
2872 + if (n1 < n2) return false;
2873 + else if (n1 > n2) return true;
2874
2875 // Check minor version
2858 - n1 = parseInt(s1[1],10);
2859 - n2 = parseInt(s2[1],10);
2860 - if ( n1 < n2 ) return false;
2861 - else if ( n1 > n2 ) return true;
2876 + n1 = parseInt(s1[1], 10);
2877 + n2 = parseInt(s2[1], 10);
2878 + if (n1 < n2) return false;
2879 + else if (n1 > n2) return true;
2880
2881 // Split patch: format could be e.g. 0-22-nightly
2864 - s1=s1[2].split('-');
2865 - s2=s2[2].split('-');
2882 + s1 = s1[2].split('-');
2883 + s2 = s2[2].split('-');
2884
2867 - n1 = parseInt(s1[0],10);
2868 - n2 = parseInt(s2[0],10);
2869 - if ( n1 < n2 ) return false;
2870 - else if ( n1 > n2 ) return true;
2885 + n1 = parseInt(s1[0], 10);
2886 + n2 = parseInt(s2[0], 10);
2887 + if (n1 < n2) return false;
2888 + else if (n1 > n2) return true;
2889
2872 - n1 = (s1.length > 1) ? parseInt(s1[1],10) : 0;
2873 - n2 = (s2.length > 1) ? parseInt(s2[1],10) : 0;
2874 - if ( n1 < n2 ) return false;
2890 + n1 = (s1.length > 1) ? parseInt(s1[1], 10) : 0;
2891 + n2 = (s2.length > 1) ? parseInt(s2[1], 10) : 0;
2892 + if (n1 < n2) return false;
2893 else return true;
2894 }
2895 }
@@ -3119,7 +3137,7 @@ var snapshotOptions = {
3137 bytes_per_point_disk: 1.9,
3138
3139 compress: function (s) {
3122 - return btoa(pako.deflate(s, {to: 'string'}));
3140 + return btoa(pako.deflate(s, { to: 'string' }));
3141 },
3142
3143 compressed_length: function (s) {
@@ -3127,7 +3145,7 @@ var snapshotOptions = {
3145 },
3146
3147 uncompress: function (s) {
3130 - return pako.inflate(atob(s), {to: 'string'});
3148 + return pako.inflate(atob(s), { to: 'string' });
3149 }
3150 },
3151
@@ -3136,7 +3154,7 @@ var snapshotOptions = {
3154 bytes_per_point_disk: 3.2,
3155
3156 compress: function (s) {
3139 - return pako.deflate(s, {to: 'string'});
3157 + return pako.deflate(s, { to: 'string' });
3158 },
3159
3160 compressed_length: function (s) {
@@ -3144,7 +3162,7 @@ var snapshotOptions = {
3162 },
3163
3164 uncompress: function (s) {
3147 - return pako.inflate(s, {to: 'string'});
3165 + return pako.inflate(s, { to: 'string' });
3166 }
3167 },
3168
@@ -3937,7 +3955,7 @@ function enableTooltipsAndPopovers() {
3955 animated: 'fade',
3956 trigger: 'hover',
3957 html: true,
3940 - delay: {show: 500, hide: 0},
3958 + delay: { show: 500, hide: 0 },
3959 container: 'body'
3960 });
3961 $('[data-toggle="popover"]').popover();
@@ -4015,7 +4033,7 @@ function runOnceOnDashboardWithjQuery() {
4033
4034 // scroll to the position we had open before the modal
4035 $('html, body')
4018 - .animate({scrollTop: scrollPos}, 0);
4036 + .animate({ scrollTop: scrollPos }, 0);
4037
4038 // unpause netdata, if we paused it
4039 if (netdata_paused_on_modal === true) {
@@ -4181,8 +4199,8 @@ function runOnceOnDashboardWithjQuery() {
4199 .on('hidden.bs.modal', function () {
4200 document.getElementById('alarms_active').innerHTML =
4201 document.getElementById('alarms_all').innerHTML =
4184 - document.getElementById('alarms_log').innerHTML =
4185 - 'loading...';
4202 + document.getElementById('alarms_log').innerHTML =
4203 + 'loading...';
4204 });
4205
4206 // ------------------------------------------------------------------------
@@ -4232,7 +4250,7 @@ function runOnceOnDashboardWithjQuery() {
4250 if ($this.hasClass('less')) {
4251 $this.removeClass('less');
4252 $this.html(config.moreText);
4235 - $this.parent().prev().animate({'height': '0' + '%'}, 0, function () {
4253 + $this.parent().prev().animate({ 'height': '0' + '%' }, 0, function () {
4254 $this.parent().prev().prev().show();
4255 }).hide(0, function () {
4256 config.onLess();
@@ -4240,7 +4258,7 @@ function runOnceOnDashboardWithjQuery() {
4258 } else {
4259 $this.addClass('less');
4260 $this.html(config.lessText);
4243 - $this.parent().prev().animate({'height': '100' + '%'}, 0, function () {
4261 + $this.parent().prev().animate({ 'height': '100' + '%' }, 0, function () {
4262 $this.parent().prev().prev().hide();
4263 }).show(0, function () {
4264 config.onMore();
@@ -4563,7 +4581,7 @@ function getCloudAccountAgents() {
4581 if (!isSignedIn()) {
4582 return [];
4583 }
4566 -
4584 +
4585 return fetch(
4586 `${NETDATA.registry.cloudBaseURL}/api/v1/accounts/${cloudAccountID}/agents`,
4587 {
@@ -4573,7 +4591,7 @@ function getCloudAccountAgents() {
4591 "Authorization": `Bearer ${cloudToken}`
4592 }
4593 }
4576 - ).then((response) => {
4594 + ).then((response) => {
4595 if (!response.ok) {
4596 throw Error("Cannot fetch known accounts");
4597 }
@@ -4599,6 +4617,36 @@ function getCloudAccountAgents() {
4617 });
4618 }
4619
4620 +/** Updates the lastAccessTime and accessCount properties of the agent for the account. */
4621 +function touchAgent() {
4622 + if (!isSignedIn()) {
4623 + return [];
4624 + }
4625 +
4626 + const touchUrl = `${NETDATA.registry.cloudBaseURL}/api/v1/agents/${NETDATA.registry.machine_guid}/touch?account_id=${cloudAccountID}`;
4627 + return fetch(
4628 + touchUrl,
4629 + {
4630 + method: "post",
4631 + body: "",
4632 + mode: "cors",
4633 + headers: {
4634 + "Authorization": `Bearer ${cloudToken}`
4635 + }
4636 + }
4637 + ).then((response) => {
4638 + if (!response.ok) {
4639 + throw Error("Cannot touch agent" + JSON.stringify(response));
4640 + }
4641 + return response.json();
4642 + }).then((payload) => {
4643 +
4644 + }).catch(function (error) {
4645 + console.log(error);
4646 + return null;
4647 + });
4648 +}
4649 +
4650 // https://github.com/netdata/hub/issues/128
4651 function postCloudAccountAgents(agentsToSync) {
4652 if (!isSignedIn()) {
@@ -4622,7 +4670,7 @@ function postCloudAccountAgents(agentsToSync) {
4670 "agents": agents,
4671 "merge": false,
4672 };
4625 -
4673 +
4674 return fetch(
4675 `${NETDATA.registry.cloudBaseURL}/api/v1/accounts/${cloudAccountID}/agents`,
4676 {
@@ -4650,7 +4698,7 @@ function postCloudAccountAgents(agentsToSync) {
4698 "url": a.urls[0],
4699 "alternate_urls": a.urls
4700 }
4653 - })
4701 + })
4702 });
4703 }
4704
@@ -4727,7 +4775,7 @@ function updateMyNetdataAfterFilterChange() {
4775
4776 if (options.hosts.length > 1) {
4777 const streamedEl = document.getElementById("my-netdata-menu-streamed")
4730 - streamedEl.innerHTML = renderStreamedHosts(options);
4778 + streamedEl.innerHTML = renderStreamedHosts(options);
4779 }
4780 }
4781
@@ -4742,7 +4790,7 @@ function myNetdataFilterDidChange(e) {
4790 const inputEl = e.target;
4791 setTimeout(() => {
4792 myNetdataMenuFilterValue = inputEl.value;
4745 - updateMyNetdataAfterFilterChange();
4793 + updateMyNetdataAfterFilterChange();
4794 }, 1);
4795 }
4796
@@ -4753,9 +4801,9 @@ function myNetdataFilterClearDidClick(e) {
4801 const inputEl = document.getElementById("my-netdata-menu-filter-input");
4802 inputEl.value = "";
4803 myNetdataMenuFilterValue = "";
4756 -
4757 - updateMyNetdataAfterFilterChange();
4758 -
4804 +
4805 + updateMyNetdataAfterFilterChange();
4806 +
4807 inputEl.focus();
4808 }
4809
@@ -4792,12 +4840,18 @@ function renderAccountUI() {
4840 container.removeAttribute("title");
4841 container.removeAttribute("data-original-title");
4842 container.removeAttribute("data-placement");
4843 + // <a href="/console/index.html#/charts/${NETDATA.registry.machine_guid}" target="_blank" class="btn">
4844 container.innerHTML = (
4845 `<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span id="amc-account-name"></span> <strong class="caret"></strong></a>
4797 - <ul id="cloud-menu" class="dropdown-menu scrollable-menu inpagemenu" role="menu">
4798 - <li>
4799 - <a href="#" class="btn" onclick="signOutDidClick(event); return false">
4800 - <i class="fas fa-sign-out-alt"></i>&nbsp;&nbsp;<span class="hidden-sm hidden-md">Sign Out</span>
4846 + <ul id="cloud-menu" class="dropdown-menu scrollable-menu inpagemenu" role="menu">
4847 + <li>
4848 + <a onclick="openAuthenticatedUrl('console/index.html');" target="_blank" class="btn">
4849 + <i class="fas fa-tv"></i>&nbsp;&nbsp;<span class="hidden-sm hidden-md">Nodes<sup class="beta"> beta</sup></span>
4850 + </a>
4851 + </li>
4852 + <li>
4853 + <a href="#" class="btn" onclick="signOutDidClick(event); return false">
4854 + <i class="fas fa-sign-out-alt"></i>&nbsp;&nbsp;<span class="hidden-sm hidden-md">Sign Out</span>
4855 </a>
4856 </li>
4857 </ul>`
@@ -4841,7 +4895,7 @@ function handleSignInMessage(e) {
4895 }
4896
4897 function handleSignOutMessage(e) {
4844 - clearCloudVariables();
4898 + clearCloudVariables();
4899 renderAccountUI();
4900 renderMyNetdataMenu(registryAgents);
4901 }
@@ -4915,17 +4969,17 @@ function explicitlySyncAgents() {
4969 $("#syncRegistryModal").modal("hide");
4970
4971 const json = localStorage.getItem("cloud.sync");
4918 - const sync = json ? JSON.parse(json): {};
4972 + const sync = json ? JSON.parse(json) : {};
4973 delete sync[cloudAccountID];
4974 localStorage.setItem("cloud.sync", JSON.stringify(sync));
4921 -
4975 +
4976 NETDATA.registry.init();
4977 }
4978
4979 function syncAgents(callback) {
4980 const json = localStorage.getItem("cloud.sync");
4927 - const sync = json ? JSON.parse(json): {};
4928 -
4981 + const sync = json ? JSON.parse(json) : {};
4982 +
4983 const currentAgent = {
4984 guid: NETDATA.registry.machine_guid,
4985 name: NETDATA.registry.hostname,
@@ -4933,30 +4987,30 @@ function syncAgents(callback) {
4987 alternate_urls: [NETDATA.serverDefault],
4988 }
4989
4936 - const localAgents = sync[cloudAccountID]
4937 - ? [currentAgent]
4990 + const localAgents = sync[cloudAccountID]
4991 + ? [currentAgent]
4992 : registryAgents.concat([currentAgent]);
4939 -
4993 +
4994 console.log("Checking if sync is needed.", localAgents);
4995
4996 const agentsToSync = mergeAgents(cloudAgents, localAgents);
4997
4944 - if ((!sync[cloudAccountID]) || agentsToSync) {
4998 + if ((!sync[cloudAccountID]) || agentsToSync) {
4999 sync[cloudAccountID] = new Date().getTime();
5000 localStorage.setItem("cloud.sync", JSON.stringify(sync));
5001 }
5002
5003 if (agentsToSync) {
5004 console.log("Synchronizing with netdata.cloud.");
4951 -
5005 +
5006 postCloudAccountAgents(agentsToSync).then((agents) => {
5007 // TODO: clear syncTime on error!
5008 cloudAgents = agents;
5009 callback(cloudAgents);
5010 });
5011
4958 - return
4959 - }
5012 + return
5013 + }
5014
5015 callback(cloudAgents);
5016 }
@@ -4995,6 +5049,7 @@ function initCloud() {
5049 cloudSSOInit();
5050 }
5051
5052 + touchAgent();
5053 renderAccountUI();
5054 }
5055
@@ -5004,7 +5059,7 @@ function netdataRegistryCallback(machinesArray) {
5059
5060 initCloud();
5061
5007 - registryAgents = machinesArray;
5062 + registryAgents = machinesArray;
5063
5064 if (isSignedIn()) {
5065 // We call getCloudAccountAgents() here because it requires that
@@ -5015,17 +5070,17 @@ function netdataRegistryCallback(machinesArray) {
5070 errorMyNetdataMenu();
5071 return;
5072 }
5018 - cloudAgents = agents;
5073 + cloudAgents = agents;
5074 syncAgents((agents) => {
5075 const agentsMap = {}
5076 for (const agent of agents) {
5077 agentsMap[agent.guid] = agent;
5078 }
5024 -
5079 +
5080 NETDATA.registry.machines = agentsMap;
5081 NETDATA.registry.machines_array = agents;
5027 -
5028 - renderMyNetdataMenu(agents);
5082 +
5083 + renderMyNetdataMenu(agents);
5084 });
5085 });
5086 } else {
@@ -5044,15 +5099,15 @@ function tryFastInitCloud() {
5099 NETDATA.registry.cloudBaseURL = baseURL;
5100 NETDATA.registry.machine_guid = agentID;
5101 NETDATA.registry.isCloudEnabled = true;
5047 -
5102 +
5103 initCloud();
5104 }
5105 }
5106
5107 function initializeApp() {
5053 - window.addEventListener("message", handleMessage, false);
5108 + window.addEventListener("message", handleMessage, false);
5109
5055 -// tryFastInitCloud();
5110 + // tryFastInitCloud();
5111 }
5112
5113 if (document.readyState === "complete") {
web/gui/static/img/netdata-logomark.svg new
+3
@@ -0,0 +1,3 @@
1 +<svg width="1723" height="1723" viewBox="0 0 1723 1723" fill="none" xmlns="http://www.w3.org/2000/svg">
2 +<path fill-rule="evenodd" clip-rule="evenodd" d="M0.628784 849.678C0.628784 473.909 235.042 153.621 563.766 30.7914C701.438 19.0613 843.892 50.2449 970.557 129.297C1052.47 180.42 1119.71 246.528 1170.96 321.982C1161.21 207.568 1122.97 96.4678 1058.94 0.187012C1220.56 38.587 1364.64 123.126 1476.91 239.343C1518.34 297.634 1548.55 365.545 1563.67 440.489C1578.54 514.244 1577.35 587.545 1562.5 656.661C1601.04 613.105 1632.22 563.24 1654.63 509.251C1698.41 613.852 1722.63 728.899 1722.63 849.678C1722.63 1331.55 1337.15 1722.19 861.629 1722.19C386.112 1722.19 0.628784 1331.55 0.628784 849.678ZM1178.87 1369.04C1286.71 1369.04 1374.13 1280.45 1374.13 1171.17C1374.13 1061.88 1286.71 973.293 1178.87 973.293C1071.03 973.293 983.603 1061.88 983.603 1171.17C983.603 1280.45 1071.03 1369.04 1178.87 1369.04Z" fill="#00C853"/>
3 +</svg>
web/gui/static/static/img/netdata-logomark.svg new
+3
@@ -0,0 +1,3 @@
1 +<svg width="1723" height="1723" viewBox="0 0 1723 1723" fill="none" xmlns="http://www.w3.org/2000/svg">
2 +<path fill-rule="evenodd" clip-rule="evenodd" d="M0.628784 849.678C0.628784 473.909 235.042 153.621 563.766 30.7914C701.438 19.0613 843.892 50.2449 970.557 129.297C1052.47 180.42 1119.71 246.528 1170.96 321.982C1161.21 207.568 1122.97 96.4678 1058.94 0.187012C1220.56 38.587 1364.64 123.126 1476.91 239.343C1518.34 297.634 1548.55 365.545 1563.67 440.489C1578.54 514.244 1577.35 587.545 1562.5 656.661C1601.04 613.105 1632.22 563.24 1654.63 509.251C1698.41 613.852 1722.63 728.899 1722.63 849.678C1722.63 1331.55 1337.15 1722.19 861.629 1722.19C386.112 1722.19 0.628784 1331.55 0.628784 849.678ZM1178.87 1369.04C1286.71 1369.04 1374.13 1280.45 1374.13 1171.17C1374.13 1061.88 1286.71 973.293 1178.87 973.293C1071.03 973.293 983.603 1061.88 983.603 1171.17C983.603 1280.45 1071.03 1369.04 1178.87 1369.04Z" fill="#00C853"/>
3 +</svg>