diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2018-11-07 12:19:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2018-11-07 12:20:17 +0000 |
commit | a64a253794ac64cb40befee54db53bde17dd0d49 (patch) | |
tree | c1024acc5f6e508814b944d99f112259bb28b1be /web/gui/index.html | |
parent | New upstream version 1.10.0+dfsg (diff) | |
download | netdata-2dec20452b290c484d509f7ac9a29b38cf690223.tar.xz netdata-2dec20452b290c484d509f7ac9a29b38cf690223.zip |
New upstream version 1.11.0+dfsgupstream/1.11.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'web/gui/index.html')
-rw-r--r-- | web/gui/index.html | 5791 |
1 files changed, 5791 insertions, 0 deletions
diff --git a/web/gui/index.html b/web/gui/index.html new file mode 100644 index 000000000..0a01b1df9 --- /dev/null +++ b/web/gui/index.html @@ -0,0 +1,5791 @@ +<!DOCTYPE html> +<!-- SPDX-License-Identifier: GPL-3.0-or-later --> +<html lang="en"> +<head> + <title>netdata dashboard</title> + <meta name="application-name" content="netdata"> + + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <meta name="apple-mobile-web-app-capable" content="yes"> + <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> + <meta name="author" content="costa@tsaousis.gr"> + + <!-- <link rel="shortcut icon" href="images/seo-performance-multi-size.ico"> --> + + <!-- <link rel="apple-touch-icon" href="images/seo-performance-72.png"> --> + <!-- <link rel="apple-touch-icon" sizes="72x72" href="images/seo-performance-72.png"> --> + <!-- <link rel="apple-touch-icon" sizes="114x114" href="images/seo-performance-114.png"> --> + + <!-- <link rel="icon" type="image/png" sizes="512x512" href="images/seo-performance-512.png"> --> + <!-- <link rel="icon" type="image/png" sizes="256x256" href="images/seo-performance-256.png"> --> + <!-- <link rel="icon" type="image/png" sizes="128x128" href="images/seo-performance-128.png"> --> + <!-- <link rel="icon" type="image/png" sizes="64x64" href="images/seo-performance-64.png"> --> + <!-- <link rel="icon" type="image/png" sizes="48x48" href="images/seo-performance-48.png"> --> + <!-- <link rel="icon" type="image/png" sizes="24x24" href="images/seo-performance-24.png"> --> + <!-- <link rel="icon" type="image/png" sizes="16x16" href="images/seo-performance-16.png"> --> + <!-- <link rel="icon" type="image/png" sizes="32x32" href="images/seo-performance-32.png"> --> + + <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACNklEQVRYhcXXv2tUQRAH8M+FEIJISBHCIWIhIQSUILERi4AiiqCggiIiomAjlhaC4j+ghYWISgqNohZaCBZBC8Ei8QdEUCutFBsxCBqDYkgci/cunkfuJffjJQPD8mZm5/vd2WV2HzlJ0Bs8CvrywsgCHwy+BpGOg0sJfjj4nYKX9FdwKG9gwZlgtgK8pLOpPxfw1mCoCnClDgWtzQTvCEYWCV7SkWAlFBoEb8dlDKBF8t2bMWUSH/AHr3CiEfz5CPUusPJLkRCdk5ZqyeqUrQv4R7E5TwK7M3zTeIKduRAIitiWEfIY69GdCwGcRFuG/xqONRkzkaA7+J5x+MaDtWmHvJ4HgeEM8Nn0bridfv9HoOFyBAdwJCPkqqTzHWwUaz7wgeBHxupfBKuCj2W25mxBsCGYyAB/FxTT27HcPlyep64tCLbjKbqqhLzBlgKfF8pVE4FgRXABI+ioEnYfOyzcFWsCbg+OV+xlpU4ER4O+4HVwL51b3xYEXcGu4Ao+YQhr5gmdxHmsQyfG0b/YxbWmLfRWmnxa0s06VbTMCpnBS9zFzQKTwR5cXCzwHIE02Sl8wSZsRI/kgLVJqjSd+t9LVjiG1diPszhdK3A5gR48k5zYMTwscC59sfT799CYKvA8EttbSeXgTr3gJQKl91kR+yTlvyG5uUbLYh9gb+ovltkb6qYtNSRo3kOygsBSzGlKsubf43USWLYK5CLLXoFWyU/CtzLbVDpW2n+m40yN9ukqdvAX9ac/EIgOapcAAAAASUVORK5CYII="> + + <link rel="mask-icon" href="images/netdata.svg" color="red" /> + + <meta property="og:locale" content="en_US" /> + <meta property="og:url" content="https://my-netdata.io" /> + <meta property="og:type" content="website" /> + <meta property="og:site_name" content="netdata"/> + <meta property="og:title" content="Get control of your Linux Servers. Simple. Effective. Awesome." /> + <meta property="og:description" content="Unparalleled insights, in real-time, of everything happening on your Linux systems and applications, with stunning, interactive web dashboards and powerful performance and health alarms." /> + <meta property="og:image" content="https://cloud.githubusercontent.com/assets/2662304/22945737/e98cd0c6-f2fd-11e6-96f1-5501934b0955.png" /> + <meta property="og:image:type" content="image/png" /> + <meta property="fb:app_id" content="1200089276712916" /> + + <meta name="twitter:card" content="summary" /> + <meta name="twitter:site" content="@linuxnetdata" /> + <meta name="twitter:title" content="Get control of your Linux Servers. Simple. Effective. Awesome." /> + <meta name="twitter:description" content="Unparalleled insights, in real-time, of everything happening on your Linux systems and applications, with stunning, interactive web dashboards and powerful performance and health alarms." /> + <meta name="twitter:image" content="https://cloud.githubusercontent.com/assets/2662304/14092712/93b039ea-f551-11e5-822c-beadbf2b2a2e.gif" /> + + <style> + + /* force the vertical window scrollbar */ + html { + overflow-y: scroll; + } + + /* prevent body from hiding under the navbar */ + body { + padding-top: 50px; + } + + .loadOverlay { + position: absolute; + top: 0px; + left: 0px; + width: 100%; + height:100%; + z-index: 2000; + font-size: 10vh; + font-family: sans-serif; + padding: 40vh 0 40vh 0; + font-weight: bold; + text-align: center; + } + + .navbar-highlight { + display: none; + position: fixed; + margin-top: 5px; + height: 26px; + width: 100%; + text-align: center; + overflow: hidden; + z-index: 30; + pointer-events: none !important; + } + + .navbar-highlight-content { + position: relative; + display: inline-block; + margin: 0 auto; + height: 26px; + min-width: 500px; + background-color:rgba(0, 0, 0, 0.7); + padding-top: 2px; + padding-bottom: 2px; + padding-left: 15px; + padding-right: 15px; + border-radius:10px; + color: lightgrey; + pointer-events: auto !important; + } + + .navbar-highlight-bar { + cursor: pointer; + } + .navbar-highlight-button-right { + cursor: pointer; + padding-left: 10px; + } + + .modal-wide .modal-dialog { + width: 80%; + } + + /* fix # anchors scrolling under the navbar + https://github.com/twbs/bootstrap/issues/1768#issuecomment-46519033 + */ + h1 { + position: relative; + z-index: -1; + } + h2 { + position: relative; + z-index: -2; + } + h1:before, h2:before { + display: block; + content: " "; + margin-top: -70px; + height: 70px; + visibility: hidden; + } + + .p { + display: block; + margin-top: 15px; + } + + .option-row, + .option-control { + vertical-align: top; + padding: 10px; + padding-top: 30px; + padding-left: 30px; + } + + .option-info { + padding: 10px; + } + + .dashboard-submenu-info { + display: block; + margin-top: 10px; + } + + .dashboard-context-info { + display: block; + margin-top: 10px; + } + + #masthead h1 { + /*font-size: 30px;*/ + line-height: 1; + padding-top: 30px; + } + + #masthead .well { + margin-top:4%; + } + + /* fix the navbar shifting when a modal is open */ + /* https://github.com/twbs/bootstrap/issues/14040#issuecomment-159891033 */ + body.modal-open{ + width: 100% !important; + padding-right: 0 !important; +/* overflow-y: scroll !important; */ +/* position: fixed !important;*/ + overflow: visible; + } + + /* make accordion use the whole header bar for expand/collapse */ + .panel-title a { + display: block; + padding: 10px 15px; + margin: -10px -15px; + } + + /* + * Side navigation + * + * Scrollspy and affixed enhanced navigation to highlight sections and secondary + * sections of docs content. + */ + + .affix { + position: static; + top: 70px !important; + /*width: 220px;*/ + } + + .affix-top { + /*width: 220px;*/ + } + + .dashboard-sidebar { + max-height: calc(100% - 70px) !important; + overflow-y: auto; + /*width: 220px !important;*/ + } + + /* By default it's not affixed in mobile views, so undo that */ + .dashboard-sidebar.affix { + position: static; + } + + @media (min-width: 768px) { + .dashboard-sidebar { + padding-left: 20px; + } + } + + /* First level of nav */ + .dashboard-sidenav { + margin-top: 20px; + margin-bottom: 20px; + } + + /* All levels of nav */ + .dashboard-sidebar .nav > li > a { + display: block; + padding: 4px 20px; + font-size: 13px; + font-weight: 500; + color: #767676; + } + .dashboard-sidebar .nav > li > a > .svg-inline--fa { + width: 20px; + text-align: center; + } + .dashboard-sidebar .nav > li > a:hover, + .dashboard-sidebar .nav > li > a:focus { + padding-left: 19px; + color: #563d7c; + text-decoration: none; + background-color: transparent; + border-left: 1px solid #563d7c; + } + .dashboard-sidebar .nav > .active > a, + .dashboard-sidebar .nav > .active:hover > a, + .dashboard-sidebar .nav > .active:focus > a { + padding-left: 18px; + font-weight: bold; + color: #563d7c; + background-color: transparent; + border-left: 2px solid #563d7c; + } + + /* Nav: second level (shown on .active) */ + .dashboard-sidebar .nav .nav { + display: none; /* Hide by default, but at >768px, show it */ + padding-bottom: 10px; + } + .dashboard-sidebar .nav .nav > li > a { + padding-top: 1px; + padding-bottom: 1px; + padding-left: 30px; + font-size: 12px; + font-weight: normal; + } + .dashboard-sidebar .nav .nav > li > a:hover, + .dashboard-sidebar .nav .nav > li > a:focus { + padding-left: 29px; + } + .dashboard-sidebar .nav .nav > .active > a, + .dashboard-sidebar .nav .nav > .active:hover > a, + .dashboard-sidebar .nav .nav > .active:focus > a { + padding-left: 28px; + font-weight: 500; + } + + .dropdown-menu { + min-width: 200px; + } + .dropdown-menu.columns-2 { + margin: 0; + padding: 0; + width: 400px; + } + .dropdown-menu li a { + padding: 5px 15px; + font-weight: 300; + } + .dropdown-menu.multi-column { + overflow-x: hidden; + } + .multi-column-dropdown { + list-style: none; + padding: 0; + } + .multi-column-dropdown li a { + display: block; + clear: both; + line-height: 1.428571429; + white-space: normal; + } + .multi-column-dropdown li a:hover { + text-decoration: none; + color: #f5f5f5; + background-color: #262626; + } + .scrollable-menu { + height: auto; + max-height: 80vh; + overflow-x: hidden; + } + .scrollable-menu-50 { + height: auto; + max-height: 50vh; + overflow-x: hidden; + } + + /* Back to top (hidden on mobile) */ + .back-to-top, + .dashboard-theme-toggle { + display: none; + padding: 4px 10px; + margin-top: 10px; + margin-left: 10px; + font-size: 12px; + font-weight: 500; + color: #999; + } + .back-to-top:hover, + .dashboard-theme-toggle:hover { + color: #563d7c; + text-decoration: none; + } + .dashboard-theme-toggle { + margin-top: 0; + } + + .container { + width: calc(100% - 20px) !important; + } + + .charts-body { + display: inline-block; + width: 100%; + } + + .sidebar-body { + position: absolute; + display: none; + } + + .dashboard-section-container { + display: block; + width: 100%; + page-break-before: auto; + page-break-after: auto; + page-break-inside: auto; + } + + .dashboard-print-row { + display: block; + width: 100%; + page-break-before: auto; + page-break-after: auto; + page-break-inside: avoid; + } + + .netdata-chartblock-container { + display: inline-block; + } + + /* https://github.com/seiyria/bootstrap-slider/issues/746 */ + .tooltip { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + + @media print { + body { + overflow: visible !important; + -webkit-print-color-adjust: exact; + page-break-inside: auto; + page-break-before: auto; + page-break-after: auto; + } + + .dashboard-section { + page-break-inside: auto; + page-break-before: auto; + page-break-after: auto; + } + + .dashboard-subsection { + page-break-before: avoid; + page-break-after: auto; + page-break-inside: auto; + } + + .charts-body { + padding-left: 0%; + padding-right: 0%; + display: block; + page-break-inside: auto; + page-break-before: auto; + page-break-after: auto; + } + + .back-to-top, + .dashboard-theme-toggle { + display: block; + } + } + + @media (min-width: 768px) { + .charts-body { + padding-left: 0%; + padding-right: 0%; + } + + .back-to-top, + .dashboard-theme-toggle { + display: block; + } + } + + /* Show and affix the side nav when space allows it */ + @media (min-width: 992px) { + .container { + padding-left: 0% !important; + } + + .charts-body { + width: calc(100% - 213px) !important; + padding-left: 1% !important; + padding-right: 0% !important; + } + + .sidebar-body { + display: inline-block !important; + width: 213px !important; + } + + .dashboard-sidebar .nav > .active > ul { + display: block; + } + + /* Widen the fixed sidebar */ + .dashboard-sidebar.affix, + .dashboard-sidebar.affix-top, + .dashboard-sidebar.affix-bottom { + width: 213px !important; + } + .dashboard-sidebar.affix { + position: fixed; /* Undo the static from mobile first approach */ + top: 20px; + } + .dashboard-sidebar.affix-bottom { + position: absolute; /* Undo the static from mobile first approach */ + } + .dashboard-sidebar.affix-bottom .dashboard-sidenav, + .dashboard-sidebar.affix .dashboard-sidenav { + margin-top: 0; + margin-bottom: 0; + } + } + + @media (min-width: 1200px) { + .container { + padding-left: 2% !important; + } + + .charts-body { + width: calc(100% - 233px) !important; + padding-left: 1% !important; + padding-right: 1% !important; + } + + .sidebar-body { + display: inline-block !important; + width: 233px !important; + } + + /* Widen the fixed sidebar again */ + .dashboard-sidebar.affix, + .dashboard-sidebar.affix-top, + .dashboard-sidebar.affix-bottom { + width: 233px !important; + } + } + + @media (min-width: 1360px) { + .container { + padding-left: 3% !important; + } + + .charts-body { + width: calc(100% - 263px) !important; + padding-left: 1% !important; + padding-right: 2% !important; + } + + .sidebar-body { + display: inline-block !important; + width: 263px !important; + } + + /* Widen the fixed sidebar again */ + .dashboard-sidebar.affix, + .dashboard-sidebar.affix-top, + .dashboard-sidebar.affix-bottom { + width: 263px !important; + } + } + + .action-button { + position: relative; + display: inline-block; + color: gray; + cursor: pointer; + margin: 0 auto; + width: 30px; + height: 30px; + font-size: 25px; + } + + .ripple { + position: relative; + /*overflow: hidden;*/ + transform: translate3d(0, 0, 0) + } + + .ripple:after { + content: ""; + display: block; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + pointer-events: none; + background-image: radial-gradient(circle, #000 10%, transparent 10.01%); + background-repeat: no-repeat; + background-position: 50%; + transform: scale(18, 18); /* the size of the ripple */ + opacity: 0; + transition: transform .5s, opacity 1s + } + + .ripple:active:after { + transform: scale(0, 0); + opacity: .2; + transition: 0s + } + </style> + + <!-- check which theme to use --> + <script type="text/javascript"> + // netdata snapshot data + var netdataSnapshotData = null; + + // enable alarms checking and notifications + var netdataShowAlarms = true; + + // enable registry updates + var netdataRegistry = true; + + // forward definition only - not used here + var netdataServer = undefined; + var netdataServerStatic = undefined; + var netdataCheckXSS = undefined; + + // control the welcome modal and analytics + var this_is_demo = null; + + function escapeUserInputHTML(s) { + return s.toString() + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/"/g, '"') + .replace(/#/g, '#') + .replace(/'/g, ''') + .replace(/\(/g,'(') + .replace(/\)/g,')') + .replace(/\//g,'/'); + } + + function verifyURL(s) { + if(typeof(s) === 'string' && (s.startsWith('http://') || s.startsWith('https://'))) + return s + .replace(/'/g, '%22') + .replace(/"/g, '%27') + .replace(/\)/g, '%28') + .replace(/\(/g, '%29'); + + console.log('invalid URL detected:'); + console.log(s); + return 'javascript:alert("invalid url");'; + } + + // -------------------------------------------------------------------- + // urlOptions + + var urlOptions = { + hash: '#', + theme: null, + help: null, + mode: 'live', // 'live', 'print' + update_always: false, + pan_and_zoom: false, + server: null, + after: 0, + before: 0, + highlight: false, + highlight_after: 0, + highlight_before: 0, + nowelcome: false, + show_alarms: false, + chart: null, + family: null, + alarm: null, + alarm_unique_id: 0, + alarm_id: 0, + alarm_event_id: 0, + + hasProperty: function(property) { + // console.log('checking property ' + property + ' of type ' + typeof(this[property])); + return typeof this[property] !== 'undefined'; + }, + + genHash: function(forReload) { + var hash = urlOptions.hash; + + if(urlOptions.pan_and_zoom === true) { + hash += ';after=' + urlOptions.after.toString() + + ';before=' + urlOptions.before.toString(); + } + + if(urlOptions.highlight === true) { + hash += ';highlight_after=' + urlOptions.highlight_after.toString() + + ';highlight_before=' + urlOptions.highlight_before.toString(); + } + + if(urlOptions.theme !== null) + hash += ';theme=' + urlOptions.theme.toString(); + + if(urlOptions.help !== null) + hash += ';help=' + urlOptions.help.toString(); + + if(urlOptions.update_always === true) + hash += ';update_always=true'; + + if(forReload === true && urlOptions.server !== null) + hash += ';server=' + urlOptions.server.toString(); + + if(urlOptions.mode !== 'live') + hash += ';mode=' + urlOptions.mode; + + return hash; + }, + + parseHash: function() { + var variables = document.location.hash.split(';'); + var len = variables.length; + while(len--) { + if(len !== 0) { + var p = variables[len].split('='); + if(urlOptions.hasProperty(p[0]) && typeof p[1] !== 'undefined') + urlOptions[p[0]] = decodeURIComponent(p[1]); + } + else { + if(variables[len].length > 0) + urlOptions.hash = variables[len]; + } + } + + var booleans = [ 'nowelcome', 'show_alarms', 'update_always' ]; + len = booleans.length; + while(len--) { + if(urlOptions[booleans[len]] === 'true' || urlOptions[booleans[len]] === true || urlOptions[booleans[len]] === '1' || urlOptions[booleans[len]] === 1) + urlOptions[booleans[len]] = true; + else + urlOptions[booleans[len]] = false; + } + + var numeric = [ 'after', 'before', 'highlight_after', 'highlight_before' ]; + len = numeric.length; + while(len--) { + if(typeof urlOptions[numeric[len]] === 'string') { + try { + urlOptions[numeric[len]] = parseInt(urlOptions[numeric[len]]); + } + catch(e) { + console.log('failed to parse URL hash parameter ' + numeric[len]); + urlOptions[numeric[len]] = 0; + } + } + } + + if(urlOptions.server !== null && urlOptions.server !== '') { + netdataServerStatic = document.location.origin.toString() + document.location.pathname.toString(); + netdataServer = urlOptions.server; + netdataCheckXSS = true; + } + else + urlOptions.server = null; + + if(urlOptions.before > 0 && urlOptions.after > 0) { + urlOptions.pan_and_zoom = true; + urlOptions.nowelcome = true; + } + else + urlOptions.pan_and_zoom = false; + + if(urlOptions.highlight_before > 0 && urlOptions.highlight_after > 0) { + urlOptions.highlight = true; + } + else + urlOptions.highlight = false; + + switch(urlOptions.mode) { + case 'print': + urlOptions.theme = 'white'; + urlOptions.welcome = false; + urlOptions.help = false; + urlOptions.show_alarms = false; + + if(urlOptions.pan_and_zoom === false) { + urlOptions.pan_and_zoom = true; + urlOptions.before = Date.now(); + urlOptions.after = urlOptions.before - 600000; + } + + netdataShowAlarms = false; + netdataRegistry = false; + this_is_demo = false; + break; + + case 'live': + default: + urlOptions.mode = 'live'; + break; + } + + // console.log(urlOptions); + }, + + hashUpdate: function() { + history.replaceState(null, '', urlOptions.genHash(true)); + }, + + netdataPanAndZoomCallback: function(status, after, before) { + //console.log(1); + //console.log(new Error().stack); + + if(netdataSnapshotData === null) { + urlOptions.pan_and_zoom = status; + urlOptions.after = after; + urlOptions.before = before; + urlOptions.hashUpdate(); + } + }, + + netdataHighlightCallback: function(status, after, before) { + //console.log(2); + //console.log(new Error().stack); + + if(status === true && (after === null || before === null || after <= 0 || before <= 0 || after >= before)) { + status = false; + after = 0; + before = 0; + } + + if(netdataSnapshotData === null) + urlOptions.highlight = status; + else + urlOptions.highlight = false; + + urlOptions.highlight_after = Math.round(after); + urlOptions.highlight_before = Math.round(before); + urlOptions.hashUpdate(); + + var show_eye = NETDATA.globalChartUnderlay.hasViewport(); + + if(status === true && after > 0 && before > 0 && after < before) { + var d1 = NETDATA.dateTime.localeDateString(after); + var d2 = NETDATA.dateTime.localeDateString(before); + if(d1 === d2) d2 = ''; + document.getElementById('navbar-highlight-content').innerHTML = + ((show_eye === true)?'<span class="navbar-highlight-bar highlight-tooltip" onclick="urlOptions.showHighlight();" title="restore the highlighted view" data-toggle="tooltip" data-placement="bottom">':'<span>').toString() + + 'highlighted time-frame' + + ' <b>' + d1 + ' <code>' + NETDATA.dateTime.localeTimeString(after) + '</code></b> to ' + + ' <b>' + d2 + ' <code>' + NETDATA.dateTime.localeTimeString(before) + '</code></b>, ' + + 'duration <b>' + NETDATA.seconds4human(Math.round((before - after) / 1000)) + '</b>' + + '</span>' + + '<span class="navbar-highlight-button-right highlight-tooltip" onclick="urlOptions.clearHighlight();" title="clear the highlighted time-frame" data-toggle="tooltip" data-placement="bottom"><i class="fas fa-times"></i></span>'; + + $('.navbar-highlight').show(); + + $('.highlight-tooltip').tooltip({ + html: true, + delay: {show: 500, hide: 0}, + container: 'body' + }); + } + else + $('.navbar-highlight').hide(); + }, + + clearHighlight: function() { + NETDATA.globalChartUnderlay.clear(); + + if(NETDATA.globalPanAndZoom.isActive() === true) + NETDATA.globalPanAndZoom.clearMaster(); + }, + + showHighlight: function() { + NETDATA.globalChartUnderlay.focus(); + } + }; + + urlOptions.parseHash(); + + // -------------------------------------------------------------------- + // check options that should be processed before loading netdata.js + + var localStorageTested = -1; + function localStorageTest() { + if(localStorageTested !== -1) + return localStorageTested; + + if(typeof Storage !== "undefined" && typeof localStorage === 'object') { + var test = 'test'; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + localStorageTested = true; + } + catch (e) { + console.log(e); + localStorageTested = false; + } + } + else + localStorageTested = false; + + return localStorageTested; + } + + function loadLocalStorage(name) { + var ret = null; + + try { + if(localStorageTest() === true) + ret = localStorage.getItem(name); + else + console.log('localStorage is not available'); + } + catch(error) { + console.log(error); + return null; + } + + if(typeof ret === 'undefined' || ret === null) + return null; + + // console.log('loaded: ' + name.toString() + ' = ' + ret.toString()); + + return ret; + } + + function saveLocalStorage(name, value) { + // console.log('saving: ' + name.toString() + ' = ' + value.toString()); + try { + if(localStorageTest() === true) { + localStorage.setItem(name, value.toString()); + return true; + } + } + catch(error) { + console.log(error); + } + + return false; + } + + function getTheme(def) { + if(urlOptions.mode === 'print') + return 'white'; + + var ret = loadLocalStorage('netdataTheme'); + if(typeof ret === 'undefined' || ret === null || ret === 'undefined') + return def; + else + return ret; + } + + function setTheme(theme) { + if(urlOptions.mode === 'print') return false; + + if(theme === netdataTheme) return false; + return saveLocalStorage('netdataTheme', theme); + } + + var netdataTheme = getTheme('slate'); + var netdataShowHelp = true; + + if(urlOptions.theme !== null) { + setTheme(urlOptions.theme); + netdataTheme = urlOptions.theme; + } + else + urlOptions.theme = netdataTheme; + + if(urlOptions.help !== null) { + saveLocalStorage('options.show_help', urlOptions.help); + netdataShowHelp = urlOptions.help; + } + else { + urlOptions.help = loadLocalStorage('options.show_help'); + } + + // -------------------------------------------------------------------- + // natural sorting + // http://www.davekoelle.com/files/alphanum.js - LGPL + + function naturalSortChunkify(t) { + var tz = []; + var x = 0, y = -1, n = 0, i, j; + + while (i = (j = t.charAt(x++)).charCodeAt(0)) { + var m = (i >= 48 && i <= 57); + if (m !== n) { + tz[++y] = ""; + n = m; + } + tz[y] += j; + } + + return tz; + } + + function naturalSortCompare(a, b) { + var aa = naturalSortChunkify(a.toLowerCase()); + var bb = naturalSortChunkify(b.toLowerCase()); + + for (var x = 0; aa[x] && bb[x]; x++) { + if (aa[x] !== bb[x]) { + var c = Number(aa[x]), d = Number(bb[x]); + if (c.toString() === aa[x] && d.toString() === bb[x]) + return c - d; + else + return (aa[x] > bb[x]) ? 1 : -1; + } + } + + return aa.length - bb.length; + } + + // -------------------------------------------------------------------- + // saving files to client + + function saveTextToClient(data, filename) { + var blob = new Blob( [ data ], { + type: 'application/octet-stream' + }); + + var url = URL.createObjectURL( blob ); + var link = document.createElement( 'a' ); + link.setAttribute( 'href', url ); + link.setAttribute( 'download', filename ); + + var el = document.getElementById('hiddenDownloadLinks'); + el.innerHTML = ''; + el.appendChild(link); + + setTimeout(function(){ + el.removeChild(link); + URL.revokeObjectURL(url); + }, 60); + + link.click(); + } + + function saveObjectToClient(data, filename) { + saveTextToClient(JSON.stringify(data), filename); + } + + // -------------------------------------------------------------------- + // registry call back to render my-netdata menu + + var netdataRegistryCallback = function(machines_array) { + var el = ''; + var a1 = ''; + var found = 0, hosted = 0; + var len, i, url, hostname, icon; + + if(options.hosts.length > 1) { + // there are mirrored hosts here + + el += '<li><a href="#" onClick="return false;" style="color: #666;" target="_blank">databases available on this host</a></li>'; + a1 += '<li><a href="#" onClick="return false;"><i class="fas fa-info-circle" style="color: #666;"></i></a></li>'; + + var base = document.location.origin.toString() + document.location.pathname.toString(); + if(base.endsWith("/host/" + options.hostname + "/")) + base = base.substring(0, base.length - ("/host/" + options.hostname + "/").toString().length); + + if(base.endsWith("/")) + base = base.substring(0, base.length - 1); + + var master = options.hosts[0].hostname; + var sorted = options.hosts.sort(function(a, b) { + if(a.hostname === master) return -1; + return naturalSortCompare(a.hostname, b.hostname); + }); + + i = 0; + len = sorted.length; + while(len--) { + hostname = sorted[i].hostname; + if(hostname === master) { + url = base + "/"; + icon = "home"; + } + else { + url = base + "/host/" + hostname + "/"; + icon = "window-restore"; + } + + el += '<li id="registry_server_hosted_' + len.toString() + '"><a class="registry_link" href="' + url + '#" onClick="return gotoHostedModalHandler(\'' + url + '\');">' + hostname + '</a></li>'; + a1 += '<li id="registry_action_hosted_' + len.toString() + '"><a class="registry_link" href="' + url + '#" onClick="return gotoHostedModalHandler(\'' + url + '\');"><i class="fas fa-' + icon + '" style="color: #999;"></i></a></li>'; + hosted++; + i++; + } + + el += '<li role="separator" class="divider"></li>'; + a1 += '<li role="separator" class="divider"></li>'; + } + + if(machines_array === null) { + var ret = loadLocalStorage("registryCallback"); + if(typeof ret !== 'undefined' && ret !== null) { + machines_array = JSON.parse(ret); + console.log("failed to contact the registry - loaded registry data from browser local storage"); + } + } + + if(machines_array) { + saveLocalStorage("registryCallback", JSON.stringify(machines_array)); + + var machines = machines_array.sort(function (a, b) { + return naturalSortCompare(a.name, b.name); + }); + + i = 0; + len = machines.length; + while(len--) { + var u = machines[i++]; + found++; + el += '<li id="registry_server_' + u.guid + '"><a class="registry_link" href="' + u.url + '#" onClick="return gotoServerModalHandler(\'' + u.guid + '\');">' + u.name + '</a></li>'; + a1 += '<li id="registry_action_' + u.guid + '"><a href="#" onclick="deleteRegistryModalHandler(\'' + u.guid + '\',\'' + u.name + '\',\'' + u.url + '\'); return false;"><i class="fas fa-trash" style="color: #999;"></i></a></li>'; + } + } + + if(!found) { + if(machines) + el += '<li><a href="https://github.com/netdata/netdata/wiki/mynetdata-menu-item" style="color: #666;" target="_blank">your netdata server list is empty...</a></li>'; + else + el += '<li><a href="https://github.com/netdata/netdata/wiki/mynetdata-menu-item" style="color: #666;" target="_blank">failed to contact the registry...</a></li>'; + + a1 += '<li><a href="#" onClick="return false;"> </a></li>'; + + el += '<li role="separator" class="divider"></li>' + + '<li><a href="//london.netdata.rocks/default.html">UK - London (DigitalOcean.com)</a></li>' + + '<li><a href="//newyork.netdata.rocks/default.html">US - New York (DigitalOcean.com)</a></li>' + + '<li><a href="//sanfrancisco.netdata.rocks/default.html">US - San Francisco (DigitalOcean.com)</a></li>' + + '<li><a href="//atlanta.netdata.rocks/default.html">US - Atlanta (CDN77.com)</a></li>' + + '<li><a href="//frankfurt.netdata.rocks/default.html">Germany - Frankfurt (DigitalOcean.com)</a></li>' + + '<li><a href="//toronto.netdata.rocks/default.html">Canada - Toronto (DigitalOcean.com)</a></li>' + + '<li><a href="//singapore.netdata.rocks/default.html">Japan - Singapore (DigitalOcean.com)</a></li>' + + '<li><a href="//bangalore.netdata.rocks/default.html">India - Bangalore (DigitalOcean.com)</a></li>'; + a1 += '<li role="separator" class="divider"></li>' + + '<li><a href="#"> </a></li>' + + '<li><a href="#"> </a></li>'+ + '<li><a href="#"> </a></li>'+ + '<li><a href="#"> </a></li>'+ + '<li><a href="#"> </a></li>'+ + '<li><a href="#"> </a></li>'+ + '<li><a href="#"> </a></li>'+ + '<li><a href="#"> </a></li>'; + } + + el += '<li role="separator" class="divider"></li>'; + a1 += '<li role="separator" class="divider"></li>'; + + el += '<li><a href="https://github.com/netdata/netdata/wiki/mynetdata-menu-item" style="color: #999;" target="_blank">What is this?</a></li>'; + a1 += '<li><a href="#" style="color: #999;" onclick="switchRegistryModalHandler(); return false;"><i class="fas fa-cog" style="color: #999;"></i></a></li>'; + + document.getElementById('mynetdata_servers').innerHTML = el; + document.getElementById('mynetdata_servers2').innerHTML = el; + document.getElementById('mynetdata_actions1').innerHTML = a1; + + gotoServerInit(); + }; + + function isdemo() { + if(this_is_demo !== null) return this_is_demo; + this_is_demo = false; + + try { + if(typeof document.location.hostname === 'string') { + if(document.location.hostname.endsWith('.my-netdata.io') || + document.location.hostname.endsWith('.mynetdata.io') || + document.location.hostname.endsWith('.netdata.rocks') || + document.location.hostname.endsWith('.netdata.ai') || + document.location.hostname.endsWith('.netdata.live') || + document.location.hostname.endsWith('.firehol.org') || + document.location.hostname.endsWith('.netdata.online') || + document.location.hostname.endsWith('.netdata.cloud')) + this_is_demo = true; + } + } + catch(error) {} + return this_is_demo; + } + + function netdataURL(url, forReload) { + if(typeof url === 'undefined') + // url = document.location.toString(); + url = ''; + + if(url.indexOf('#') !== -1) + url = url.substring(0, url.indexOf('#')); + + var hash = urlOptions.genHash(forReload); + + // console.log('netdataURL: ' + url + hash); + + return url + hash; + } + + function netdataReload(url) { + document.location = verifyURL(netdataURL(url, true)); + + // since we play with hash + // this is needed to reload the page + location.reload(); + } + + function gotoHostedModalHandler(url) { + document.location = verifyURL(url + urlOptions.genHash()); + return false; + } + + var gotoServerValidateRemaining = 0; + var gotoServerMiddleClick = false; + var gotoServerStop = false; + function gotoServerValidateUrl(id, guid, url) { + var penalty = 0; + var error = 'failed'; + + if(document.location.toString().startsWith('http://') && url.toString().startsWith('https://')) + // we penalize https only if the current url is http + // to allow the user walk through all its servers. + penalty = 500; + + else if(document.location.toString().startsWith('https://') && url.toString().startsWith('http://')) + error = 'can\'t check'; + + var finalURL = netdataURL(url); + + setTimeout(function() { + document.getElementById('gotoServerList').innerHTML += '<tr><td style="padding-left: 20px;"><a href="' + verifyURL(finalURL) + '" target="_blank">' + escapeUserInputHTML(url) + '</a></td><td style="padding-left: 30px;"><code id="' + guid + '-' + id + '-status">checking...</code></td></tr>'; + + NETDATA.registry.hello(url, function(data) { + if(typeof data !== 'undefined' && data !== null && typeof data.machine_guid === 'string' && data.machine_guid === guid) { + // console.log('OK ' + id + ' URL: ' + url); + document.getElementById(guid + '-' + id + '-status').innerHTML = "OK"; + + if(!gotoServerStop) { + gotoServerStop = true; + + if(gotoServerMiddleClick) { + window.open(verifyURL(finalURL), '_blank'); + gotoServerMiddleClick = false; + document.getElementById('gotoServerResponse').innerHTML = '<b>Opening new window to ' + NETDATA.registry.machines[guid].name + '<br/><a href="' + verifyURL(finalURL) + '">' + escapeUserInputHTML(url) + '</a></b><br/>(check your pop-up blocker if it fails)'; + } + else { + document.getElementById('gotoServerResponse').innerHTML += 'found it! It is at:<br/><small>' + escapeUserInputHTML(url) + '</small>'; + document.location = verifyURL(finalURL); + } + } + } + else { + if(typeof data !== 'undefined' && data !== null && typeof data.machine_guid === 'string' && data.machine_guid !== guid) + error = 'wrong machine'; + + document.getElementById(guid + '-' + id + '-status').innerHTML = error; + gotoServerValidateRemaining--; + if(gotoServerValidateRemaining <= 0) { + gotoServerMiddleClick = false; + document.getElementById('gotoServerResponse').innerHTML = '<b>Sorry! I cannot find any operational URL for this server</b>'; + } + } + }); + }, (id * 50) + penalty); + } + + function gotoServerModalHandler(guid) { + // console.log('goto server: ' + guid); + + gotoServerStop = false; + var checked = {}; + var len = NETDATA.registry.machines[guid].alternate_urls.length; + var count = 0; + + document.getElementById('gotoServerResponse').innerHTML = ''; + document.getElementById('gotoServerList').innerHTML = ''; + document.getElementById('gotoServerName').innerHTML = NETDATA.registry.machines[guid].name; + $('#gotoServerModal').modal('show'); + + gotoServerValidateRemaining = len; + while(len--) { + var url = NETDATA.registry.machines[guid].alternate_urls[len]; + checked[url] = true; + gotoServerValidateUrl(count++, guid, url); + } + + setTimeout(function() { + if(gotoServerStop === false) { + document.getElementById('gotoServerResponse').innerHTML = '<b>Added all the known URLs for this machine.</b>'; + NETDATA.registry.search(guid, function(data) { + // console.log(data); + len = data.urls.length; + while(len--) { + var url = data.urls[len][1]; + // console.log(url); + if(typeof checked[url] === 'undefined') { + gotoServerValidateRemaining++; + checked[url] = true; + gotoServerValidateUrl(count++, guid, url); + } + } + }); + } + }, 2000); + return false; + } + + function gotoServerInit() { + $(".registry_link").on('click', function(e) { + if(e.which === 2) { + e.preventDefault(); + gotoServerMiddleClick = true; + } + else { + gotoServerMiddleClick = false; + } + + return true; + }); + } + + function switchRegistryModalHandler() { + document.getElementById('switchRegistryPersonGUID').value = NETDATA.registry.person_guid; + document.getElementById('switchRegistryURL').innerHTML = NETDATA.registry.server; + document.getElementById('switchRegistryResponse').innerHTML = ''; + $('#switchRegistryModal').modal('show'); + } + + function notifyForSwitchRegistry() { + var n = document.getElementById('switchRegistryPersonGUID').value; + + if(n !== '' && n.length === 36) { + NETDATA.registry.switch(n, function(result) { + if(result !== null) { + $('#switchRegistryModal').modal('hide'); + NETDATA.registry.init(); + } + else { + document.getElementById('switchRegistryResponse').innerHTML = "<b>Sorry! The registry rejected your request.</b>"; + } + }); + } + else + document.getElementById('switchRegistryResponse').innerHTML = "<b>The ID you have entered is not a GUID.</b>"; + } + + var deleteRegistryUrl = null; + function deleteRegistryModalHandler(guid, name, url) { + void(guid); + + deleteRegistryUrl = url; + document.getElementById('deleteRegistryServerName').innerHTML = name; + document.getElementById('deleteRegistryServerName2').innerHTML = name; + document.getElementById('deleteRegistryServerURL').innerHTML = url; + document.getElementById('deleteRegistryResponse').innerHTML = ''; + $('#deleteRegistryModal').modal('show'); + } + + function notifyForDeleteRegistry() { + if(deleteRegistryUrl) { + NETDATA.registry.delete(deleteRegistryUrl, function(result) { + if(result !== null) { + deleteRegistryUrl = null; + $('#deleteRegistryModal').modal('hide'); + NETDATA.registry.init(); + } + else { + document.getElementById('deleteRegistryResponse').innerHTML = "<b>Sorry! this command was rejected by the registry server.</b>"; + } + }); + } + } + + var options = { + menus: {}, + submenu_names: {}, + data: null, + hostname: 'netdata_server', // will be overwritten by the netdata server + version: 'unknown', + hosts: [], + + duration: 0, // the default duration of the charts + update_every: 1, + + chartsPerRow: 0, + // chartsMinWidth: 1450, + chartsHeight: 180, + }; + + function chartsPerRow(total) { + void(total); + + if(options.chartsPerRow === 0) { + return 1; + //var width = Math.floor(total / options.chartsMinWidth); + //if(width === 0) width = 1; + //return width; + } + else return options.chartsPerRow; + } + + function prioritySort(a, b) { + if(a.priority < b.priority) return -1; + if(a.priority > b.priority) return 1; + return naturalSortCompare(a.name, b.name); + } + + function sortObjectByPriority(object) { + var idx = {}; + var sorted = []; + + for(var i in object) { + if(!object.hasOwnProperty(i)) continue; + + if(typeof idx[i] === 'undefined') { + idx[i] = object[i]; + sorted.push(i); + } + } + + sorted.sort(function(a, b) { + if(idx[a].priority < idx[b].priority) return -1; + if(idx[a].priority > idx[b].priority) return 1; + return naturalSortCompare(a, b); + }); + + return sorted; + } + + + // ---------------------------------------------------------------------------- + // scroll to a section, without changing the browser history + + function scrollToId(hash) { + if(hash && hash !== '' && document.getElementById(hash) !== null) { + var offset = $('#' + hash).offset(); + if(typeof offset !== 'undefined') { + //console.log('scrolling to ' + hash + ' at ' + offset.top.toString()); + $('html, body').animate({scrollTop: offset.top - 30}, 0); + } + } + + // we must return false to prevent the default action + return false; + } + + // ---------------------------------------------------------------------------- + + // user editable information + var customDashboard = { + menu: {}, + submenu: {}, + context: {} + }; + + // netdata standard information + var netdataDashboard = { + sparklines_registry: {}, + os: 'unknown', + + menu: {}, + submenu: {}, + context: {}, + + // generate a sparkline + // used in the documentation + sparkline: function (prefix, chart, dimension, units, suffix) { + if(options.data === null || typeof options.data.charts === 'undefined') + return ''; + + if(typeof options.data.charts[chart] === 'undefined') + return ''; + + if(typeof options.data.charts[chart].dimensions === 'undefined') + return ''; + + if(typeof options.data.charts[chart].dimensions[dimension] === 'undefined') + return ''; + + var key = chart + '.' + dimension; + + if(typeof units === 'undefined') + units = ''; + + if(typeof this.sparklines_registry[key] === 'undefined') + this.sparklines_registry[key] = { count: 1 }; + else + this.sparklines_registry[key].count++; + + key = key + '.' + this.sparklines_registry[key].count; + + return prefix + '<div class="netdata-container" data-netdata="' + chart + '" data-after="-120" data-width="25%" data-height="15px" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-dimensions="' + dimension + '" data-show-value-of-' + dimension + '-at="' + key + '"></div> (<span id="' + key + '" style="display: inline-block; min-width: 50px; text-align: right;">X</span>' + units + ')' + suffix; + }, + + gaugeChart: function(title, width, dimensions, colors) { + if(typeof colors === 'undefined') + colors = ''; + + if(typeof dimensions === 'undefined') + dimensions = ''; + + return '<div class="netdata-container" data-netdata="CHART_UNIQUE_ID"' + + ' data-dimensions="' + dimensions + '"' + + ' data-chart-library="gauge"' + + ' data-gauge-adjust="width"' + + ' data-title="' + title + '"' + + ' data-width="' + width + '"' + + ' data-before="0"' + + ' data-after="-CHART_DURATION"' + + ' data-points="CHART_DURATION"' + + ' data-colors="' + colors + '"' + + ' role="application"></div>'; + }, + + anyAttribute: function(obj, attr, key, def) { + if(typeof(obj[key]) !== 'undefined') { + var x = obj[key][attr]; + + if(typeof(x) === 'undefined') + return def; + + if(typeof(x) === 'function') { + return x(netdataDashboard.os); + } + + return x; + } + + return def; + }, + + menuTitle: function(chart) { + if(typeof chart.menu_pattern !== 'undefined') { + return (this.anyAttribute(this.menu, 'title', chart.menu_pattern, chart.menu_pattern).toString() + + ' ' + chart.type.slice(-(chart.type.length - chart.menu_pattern.length - 1)).toString()).replace(/_/g, ' '); + } + + return (this.anyAttribute(this.menu, 'title', chart.menu, chart.menu)).toString().replace(/_/g, ' '); + }, + + menuIcon: function(chart) { + if(typeof chart.menu_pattern !== 'undefined') + return this.anyAttribute(this.menu, 'icon', chart.menu_pattern, '<i class="fas fa-puzzle-piece"></i>').toString(); + + return this.anyAttribute(this.menu, 'icon', chart.menu, '<i class="fas fa-puzzle-piece"></i>'); + }, + + menuInfo: function(chart) { + if(typeof chart.menu_pattern !== 'undefined') + return this.anyAttribute(this.menu, 'info', chart.menu_pattern, null); + + return this.anyAttribute(this.menu, 'info', chart.menu, null); + }, + + menuHeight: function(chart) { + if(typeof chart.menu_pattern !== 'undefined') + return this.anyAttribute(this.menu, 'height', chart.menu_pattern, 1.0); + + return this.anyAttribute(this.menu, 'height', chart.menu, 1.0); + }, + + submenuTitle: function(menu, submenu) { + var key = menu + '.' + submenu; + // console.log(key); + var title = this.anyAttribute(this.submenu, 'title', key, submenu).toString().replace(/_/g, ' '); + if(title.length > 28) { + var a = title.substring(0, 13); + var b = title.substring(title.length - 12, title.length); + return a + '...' + b; + } + return title; + }, + + submenuInfo: function(menu, submenu) { + var key = menu + '.' + submenu; + return this.anyAttribute(this.submenu, 'info', key, null); + }, + + submenuHeight: function(menu, submenu, relative) { + var key = menu + '.' + submenu; + return this.anyAttribute(this.submenu, 'height', key, 1.0) * relative; + }, + + contextInfo: function(id) { + var x = this.anyAttribute(this.context, 'info', id, null); + + if(x !== null) + return '<div class="shorten dashboard-context-info netdata-chart-alignment" role="document">' + x + '</div>'; + else + return ''; + }, + + contextValueRange: function(id) { + if(typeof this.context[id] !== 'undefined' && typeof this.context[id].valueRange !== 'undefined') + return this.context[id].valueRange; + else + return '[null, null]'; + }, + + contextHeight: function(id, def) { + if(typeof this.context[id] !== 'undefined' && typeof this.context[id].height !== 'undefined') + return def * this.context[id].height; + else + return def; + }, + + contextDecimalDigits: function(id, def) { + if(typeof this.context[id] !== 'undefined' && typeof this.context[id].decimalDigits !== 'undefined') + return this.context[id].decimalDigits; + else + return def; + } + }; + + // ---------------------------------------------------------------------------- + + // enrich the data structure returned by netdata + // to reflect our menu system and content + // TODO: this is a shame - we should fix charts naming (issue #807) + function enrichChartData(chart) { + var parts = chart.type.split('_'); + var tmp = parts[0]; + + switch(tmp) { + case 'ap': + case 'net': + case 'disk': + case 'statsd': + chart.menu = tmp; + break; + + case 'apache': + chart.menu = chart.type; + if(parts.length > 2 && parts[1] === 'cache') + chart.menu_pattern = tmp + '_' + parts[1]; + else if(parts.length > 1) + chart.menu_pattern = tmp; + break; + + case 'bind': + chart.menu = chart.type; + if(parts.length > 2 && parts[1] === 'rndc') + chart.menu_pattern = tmp + '_' + parts[1]; + else if(parts.length > 1) + chart.menu_pattern = tmp; + break; + + case 'cgroup': + chart.menu = chart.type; + if(chart.id.match(/.*[\._\/-:]qemu[\._\/-:]*/) || chart.id.match(/.*[\._\/-:]kvm[\._\/-:]*/)) + chart.menu_pattern = 'cgqemu'; + else + chart.menu_pattern = 'cgroup'; + break; + + case 'go': + chart.menu = chart.type; + if(parts.length > 2 && parts[1] === 'expvar') + chart.menu_pattern = tmp + '_' + parts[1]; + else if(parts.length > 1) + chart.menu_pattern = tmp; + break; + + case 'isc': + chart.menu = chart.type; + if(parts.length > 2 && parts[1] === 'dhcpd') + chart.menu_pattern = tmp + '_' + parts[1]; + else if(parts.length > 1) + chart.menu_pattern = tmp; + break; + + case 'ovpn': + chart.menu = chart.type; + if(parts.length > 3 && parts[1] === 'status' && parts[2] === 'log') + chart.menu_pattern = tmp + '_' + parts[1]; + else if(parts.length > 1) + chart.menu_pattern = tmp; + break; + + case 'smartd': + case 'web': + chart.menu = chart.type; + if(parts.length > 2 && parts[1] === 'log') + chart.menu_pattern = tmp + '_' + parts[1]; + else if(parts.length > 1) + chart.menu_pattern = tmp; + break; + + case 'tc': + chart.menu = tmp; + + // find a name for this device from fireqos info + // we strip '_(in|out)' or '(in|out)_' + if(chart.context === 'tc.qos' && (typeof options.submenu_names[chart.family] === 'undefined' || options.submenu_names[chart.family] === chart.family)) { + var n = chart.name.split('.')[1]; + if(n.endsWith('_in')) + options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_in')); + else if(n.endsWith('_out')) + options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_out')); + else if(n.startsWith('in_')) + options.submenu_names[chart.family] = n.slice(3, n.length); + else if(n.startsWith('out_')) + options.submenu_names[chart.family] = n.slice(4, n.length); + else + options.submenu_names[chart.family] = n; + } + + // increase the priority of IFB devices + // to have inbound appear before outbound + if(chart.id.match(/.*-ifb$/)) + chart.priority--; + + break; + + default: + chart.menu = chart.type; + if(parts.length > 1) + chart.menu_pattern = tmp; + break; + } + + chart.submenu = chart.family; + } + + // ---------------------------------------------------------------------------- + + function headMain(os, charts, duration) { + void(os); + + if(urlOptions.mode === 'print') + return ''; + + var head = ''; + + if(typeof charts['system.swap'] !== 'undefined') + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.swap"' + + ' data-dimensions="used"' + + ' data-append-options="percentage"' + + ' data-chart-library="easypiechart"' + + ' data-title="Used Swap"' + + ' data-units="%"' + + ' data-easypiechart-max-value="100"' + + ' data-width="9%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-colors="#DD4400"' + + ' role="application"></div>'; + + if(typeof charts['system.io'] !== 'undefined') { + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.io"' + + ' data-dimensions="in"' + + ' data-chart-library="easypiechart"' + + ' data-title="Disk Read"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.io.mainhead"' + + ' role="application"></div>'; + + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.io"' + + ' data-dimensions="out"' + + ' data-chart-library="easypiechart"' + + ' data-title="Disk Write"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.io.mainhead"' + + ' role="application"></div>'; + } + else if(typeof charts['system.pgpgio'] !== 'undefined') { + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.pgpgio"' + + ' data-dimensions="in"' + + ' data-chart-library="easypiechart"' + + ' data-title="Disk Read"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.pgpgio.mainhead"' + + ' role="application"></div>'; + + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.pgpgio"' + + ' data-dimensions="out"' + + ' data-chart-library="easypiechart"' + + ' data-title="Disk Write"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.pgpgio.mainhead"' + + ' role="application"></div>'; + } + + if(typeof charts['system.cpu'] !== 'undefined') + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.cpu"' + + ' data-chart-library="gauge"' + + ' data-title="CPU"' + + ' data-units="%"' + + ' data-gauge-max-value="100"' + + ' data-width="20%"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-colors="' + NETDATA.colors[12] + '"' + + ' role="application"></div>'; + + if(typeof charts['system.net'] !== 'undefined') { + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.net"' + + ' data-dimensions="received"' + + ' data-chart-library="easypiechart"' + + ' data-title="Net Inbound"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.net.mainhead"' + + ' role="application"></div>'; + + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.net"' + + ' data-dimensions="sent"' + + ' data-chart-library="easypiechart"' + + ' data-title="Net Outbound"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.net.mainhead"' + + ' role="application"></div>'; + } + else if(typeof charts['system.ip'] !== 'undefined') { + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.ip"' + + ' data-dimensions="received"' + + ' data-chart-library="easypiechart"' + + ' data-title="IP Inbound"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.ip.mainhead"' + + ' role="application"></div>'; + + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.ip"' + + ' data-dimensions="sent"' + + ' data-chart-library="easypiechart"' + + ' data-title="IP Outbound"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.ip.mainhead"' + + ' role="application"></div>'; + } + else if(typeof charts['system.ipv4'] !== 'undefined') { + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.ipv4"' + + ' data-dimensions="received"' + + ' data-chart-library="easypiechart"' + + ' data-title="IPv4 Inbound"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.ipv4.mainhead"' + + ' role="application"></div>'; + + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.ipv4"' + + ' data-dimensions="sent"' + + ' data-chart-library="easypiechart"' + + ' data-title="IPv4 Outbound"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.ipv4.mainhead"' + + ' role="application"></div>'; + } + else if(typeof charts['system.ipv6'] !== 'undefined') { + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.ipv6"' + + ' data-dimensions="received"' + + ' data-chart-library="easypiechart"' + + ' data-title="IPv6 Inbound"' + + ' data-units="kbps"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.ipv6.mainhead"' + + ' role="application"></div>'; + + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.ipv6"' + + ' data-dimensions="sent"' + + ' data-chart-library="easypiechart"' + + ' data-title="IPv6 Outbound"' + + ' data-units="kbps"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.ipv6.mainhead"' + + ' role="application"></div>'; + } + + if(typeof charts['system.ram'] !== 'undefined') + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.ram"' + + ' data-dimensions="used|buffers|active|wired"' // active and wired are FreeBSD stats + + ' data-append-options="percentage"' + + ' data-chart-library="easypiechart"' + + ' data-title="Used RAM"' + + ' data-units="%"' + + ' data-easypiechart-max-value="100"' + + ' data-width="9%"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-colors="' + NETDATA.colors[7] + '"' + + ' role="application"></div>'; + + return head; + } + + function generateHeadCharts(type, chart, duration) { + if(urlOptions.mode === 'print') + return ''; + + var head = ''; + var hcharts = netdataDashboard.anyAttribute(netdataDashboard.context, type, chart.context, []); + if(hcharts.length > 0) { + var hi = 0, hlen = hcharts.length; + while(hi < hlen) { + if(typeof hcharts[hi] === 'function') + head += hcharts[hi](netdataDashboard.os, chart.id).replace(/CHART_DURATION/g, duration.toString()).replace(/CHART_UNIQUE_ID/g, chart.id); + else + head += hcharts[hi].replace(/CHART_DURATION/g, duration.toString()).replace(/CHART_UNIQUE_ID/g, chart.id); + hi++; + } + } + return head; + } + + function renderPage(menus, data) { + var div = document.getElementById('charts_div'); + var pcent_width = Math.floor(100 / chartsPerRow($(div).width())); + + // find the proper duration for per-second updates + var duration = Math.round(($(div).width() * pcent_width / 100 * data.update_every / 3) / 60) * 60; + options.duration = duration; + options.update_every = data.update_every; + + var html = ''; + var sidebar = '<ul class="nav dashboard-sidenav" data-spy="affix" id="sidebar_ul">'; + var mainhead = headMain(netdataDashboard.os, data.charts, duration); + + // sort the menus + var main = sortObjectByPriority(menus); + var i = 0, len = main.length; + while(i < len) { + var menu = main[i++]; + + // generate an entry at the main menu + + var menuid = NETDATA.name2id('menu_' + menu); + sidebar += '<li class=""><a href="#' + menuid + '" onClick="return scrollToId(\'' + menuid + '\');">' + menus[menu].icon + ' ' + menus[menu].title + '</a><ul class="nav">'; + html += '<div role="section" class="dashboard-section"><div role="sectionhead"><h1 id="' + menuid + '" role="heading">' + menus[menu].icon + ' ' + menus[menu].title + '</h1></div><div role="section" class="dashboard-subsection">'; + + if(menus[menu].info !== null) + html += menus[menu].info; + + // console.log(' >> ' + menu + ' (' + menus[menu].priority + '): ' + menus[menu].title); + + var shtml = ''; + var mhead = '<div class="netdata-chart-row">' + mainhead; + mainhead = ''; + + // sort the submenus of this menu + var sub = sortObjectByPriority(menus[menu].submenus); + var si = 0, slen = sub.length; + while(si < slen) { + var submenu = sub[si++]; + + // generate an entry at the submenu + var submenuid = NETDATA.name2id('menu_' + menu + '_submenu_' + submenu); + sidebar += '<li class><a href="#' + submenuid + '" onClick="return scrollToId(\'' + submenuid + '\');">' + menus[menu].submenus[submenu].title + '</a></li>'; + shtml += '<div role="section" class="dashboard-section-container" id="' + submenuid + '"><h2 id="' + submenuid + '" class="netdata-chart-alignment" role="heading">' + menus[menu].submenus[submenu].title + '</h2>'; + + if(menus[menu].submenus[submenu].info !== null) + shtml += '<div class="dashboard-submenu-info netdata-chart-alignment" role="document">' + menus[menu].submenus[submenu].info + '</div>'; + + var head = '<div class="netdata-chart-row">'; + var chtml = ''; + + // console.log(' \------- ' + submenu + ' (' + menus[menu].submenus[submenu].priority + '): ' + menus[menu].submenus[submenu].title); + + // sort the charts in this submenu of this menu + menus[menu].submenus[submenu].charts.sort(prioritySort); + var ci = 0, clen = menus[menu].submenus[submenu].charts.length; + while(ci < clen) { + var chart = menus[menu].submenus[submenu].charts[ci++]; + + // generate the submenu heading charts + mhead += generateHeadCharts('mainheads', chart, duration); + head += generateHeadCharts('heads', chart, duration); + + function chartCommonMin(family, context, units) { + var x = netdataDashboard.anyAttribute(netdataDashboard.context, 'commonMin', context, undefined); + if(typeof x !== 'undefined') + return ' data-common-min="' + family + '/' + context + '/' + units + '"'; + else + return ''; + } + + function chartCommonMax(family, context, units) { + var x = netdataDashboard.anyAttribute(netdataDashboard.context, 'commonMax', context, undefined); + if(typeof x !== 'undefined') + return ' data-common-max="' + family + '/' + context + '/' + units + '"'; + else + return ''; + } + + // generate the chart + if(urlOptions.mode === 'print') + chtml += '<div role="row" class="dashboard-print-row">'; + + chtml += '<div class="netdata-chartblock-container" style="width: ' + pcent_width.toString() + '%;">' + netdataDashboard.contextInfo(chart.context) + '<div class="netdata-container" id="chart_' + NETDATA.name2id(chart.id) + '" data-netdata="' + chart.id + '"' + + ' data-width="100%"' + + ' data-height="' + netdataDashboard.contextHeight(chart.context, options.chartsHeight).toString() + 'px"' + + ' data-dygraph-valuerange="' + netdataDashboard.contextValueRange(chart.context) + '"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-id="' + NETDATA.name2id(options.hostname + '/' + chart.id) + '"' + + ' data-colors="' + netdataDashboard.anyAttribute(netdataDashboard.context, 'colors', chart.context, '') + '"' + + ' data-decimal-digits="' + netdataDashboard.contextDecimalDigits(chart.context, -1) + '"' + + chartCommonMin(chart.family, chart.context, chart.units) + + chartCommonMax(chart.family, chart.context, chart.units) + + ' role="application"></div></div>'; + + if(urlOptions.mode === 'print') + chtml += '</div>'; + + // console.log(' \------- ' + chart.id + ' (' + chart.priority + '): ' + chart.context + ' height: ' + menus[menu].submenus[submenu].height); + } + + head += '</div>'; + shtml += head + chtml + '</div>'; + } + + mhead += '</div>'; + sidebar += '</ul></li>'; + html += mhead + shtml + '</div></div><hr role="separator"/>'; + } + + sidebar += '<li class="" style="padding-top:15px;"><a href="https://github.com/netdata/netdata/wiki/Add-more-charts-to-netdata" target="_blank"><i class="fas fa-plus"></i> add more charts</a></li>'; + sidebar += '<li class=""><a href="https://github.com/netdata/netdata/wiki/Add-more-alarms-to-netdata" target="_blank"><i class="fas fa-plus"></i> add more alarms</a></li>'; + 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: ' ' }) + ' of real-time history.<br/> <br/><b>netdata</b><br/>v' + data.version.toString() +'</small></li>'; + sidebar += '</ul>'; + div.innerHTML = html; + document.getElementById('sidebar').innerHTML = sidebar; + + if(urlOptions.highlight === true) + NETDATA.globalChartUnderlay.init(null + , urlOptions.highlight_after + , urlOptions.highlight_before + , (urlOptions.after > 0) ? urlOptions.after : null + , (urlOptions.before > 0) ? urlOptions.before : null + ); + else + NETDATA.globalChartUnderlay.clear(); + + if(urlOptions.mode === 'print') + printPage(); + else + finalizePage(); + } + + function renderChartsAndMenu(data) { + options.menus = {}; + options.submenu_names = {}; + + var menus = options.menus; + var charts = data.charts; + var m, menu_key; + + for(var c in charts) { + if(!charts.hasOwnProperty(c)) continue; + + var chart = charts[c]; + enrichChartData(chart); + m = chart.menu; + + // create the menu + if(typeof menus[m] === 'undefined') { + menus[m] = { + menu_pattern: chart.menu_pattern, + priority: chart.priority, + submenus: {}, + title: netdataDashboard.menuTitle(chart), + icon: netdataDashboard.menuIcon(chart), + info: netdataDashboard.menuInfo(chart), + height: netdataDashboard.menuHeight(chart) * options.chartsHeight + }; + } + else { + if(typeof(menus[m].menu_pattern) === 'undefined') + menus[m].menu_pattern = chart.menu_pattern; + + if(chart.priority < menus[m].priority) + menus[m].priority = chart.priority; + } + + menu_key = (typeof(menus[m].menu_pattern) !== 'undefined')?menus[m].menu_pattern:m; + + // create the submenu + if(typeof menus[m].submenus[chart.submenu] === 'undefined') { + menus[m].submenus[chart.submenu] = { + priority: chart.priority, + charts: [], + title: null, + info: netdataDashboard.submenuInfo(menu_key, chart.submenu), + height: netdataDashboard.submenuHeight(menu_key, chart.submenu, menus[m].height) + }; + } + else { + if (chart.priority < menus[m].submenus[chart.submenu].priority) + menus[m].submenus[chart.submenu].priority = chart.priority; + } + + // index the chart in the menu/submenu + menus[m].submenus[chart.submenu].charts.push(chart); + } + + // propagate the descriptive subname given to QoS + // to all the other submenus with the same name + for(m in menus) { + if(!menus.hasOwnProperty(m)) continue; + + for(var s in menus[m].submenus) { + if(!menus[m].submenus.hasOwnProperty(s)) continue; + + // set the family using a name + if(typeof options.submenu_names[s] !== 'undefined') { + menus[m].submenus[s].title = s + ' (' + options.submenu_names[s] + ')'; + } + else { + menu_key = (typeof(menus[m].menu_pattern) !== 'undefined')?menus[m].menu_pattern:m; + menus[m].submenus[s].title = netdataDashboard.submenuTitle(menu_key, s); + } + } + } + + renderPage(menus, data); + } + + // ---------------------------------------------------------------------------- + + function loadJs(url, callback) { + $.ajax({ + url: url, + cache: true, + dataType: "script", + xhrFields: { withCredentials: true } // required for the cookie + }) + .fail(function() { + alert('Cannot load required JS library: ' + url); + }) + .always(function() { + if(typeof callback === 'function') + callback(); + }) + } + + var clipboardLoaded = false; + function loadClipboard(callback) { + if(clipboardLoaded === false) { + clipboardLoaded = true; + loadJs('lib/clipboard-polyfill-be05dad.js', callback); + } + else callback(); + } + + var bootstrapTableLoaded = false; + function loadBootstrapTable(callback) { + if(bootstrapTableLoaded === false) { + bootstrapTableLoaded = true; + loadJs('lib/bootstrap-table-1.11.0.min.js', function() { + loadJs('lib/bootstrap-table-export-1.11.0.min.js', function() { + loadJs('lib/tableExport-1.6.0.min.js', callback); + }) + }); + } + else callback(); + } + + var bootstrapSliderLoaded = false; + function loadBootstrapSlider(callback) { + if(bootstrapSliderLoaded === false) { + bootstrapSliderLoaded = true; + loadJs('lib/bootstrap-slider-10.0.0.min.js', function() { + NETDATA._loadCSS('css/bootstrap-slider-10.0.0.min.css'); + callback(); + }); + } + else callback(); + } + + var lzStringLoaded = false; + function loadLzString(callback) { + if(lzStringLoaded === false) { + lzStringLoaded = true; + loadJs('lib/lz-string-1.4.4.min.js', callback); + } + else callback(); + } + + var pakoLoaded = false; + function loadPako(callback) { + if(pakoLoaded === false) { + pakoLoaded = true; + loadJs('lib/pako-1.0.6.min.js', callback); + } + else callback(); + } + + // ---------------------------------------------------------------------------- + + function clipboardCopy(text) { + clipboard.writeText(text); + } + function clipboardCopyBadgeEmbed(url) { + clipboard.writeText('<embed src="' + url + '" type="image/svg+xml" height="20"/>'); + } + + + // ---------------------------------------------------------------------------- + + function alarmsUpdateModal() { + var active = '<h3>Raised Alarms</h3><table class="table">'; + var all = '<h3>All Running Alarms</h3><div class="panel-group" id="alarms_all_accordion" role="tablist" aria-multiselectable="true">'; + var footer = '<hr/><a href="https://github.com/netdata/netdata/wiki/Generating-Badges" target="_blank">netdata badges</a> refresh automatically. Their color indicates the state of the alarm: <span style="color: #e05d44"><b> red </b></span> is critical, <span style="color:#fe7d37"><b> orange </b></span> is warning, <span style="color: #4c1"><b> bright green </b></span> is ok, <span style="color: #9f9f9f"><b> light grey </b></span> is undefined (i.e. no data or no status), <span style="color: #000"><b> black </b></span> is not initialized. You can copy and paste their URLs to embed them in any web page.<br/>netdata can send notifications for these alarms. Check <a href="https://github.com/netdata/netdata/blob/master/conf.d/health_alarm_notify.conf">this configuration file</a> for more information.'; + + loadClipboard(function() {}); + + NETDATA.alarms.get('all', function(data) { + options.alarm_families = []; + + alarmsCallback(data); + + if(data === null) { + document.getElementById('alarms_active').innerHTML = + document.getElementById('alarms_all').innerHTML = + document.getElementById('alarms_log').innerHTML = + 'failed to load alarm data!'; + return; + } + + function alarmid4human(id) { + if(id === 0) + return '-'; + + return id.toString(); + } + + function timestamp4human(timestamp, space) { + if(timestamp === 0) + return '-'; + + if(typeof space === 'undefined') + space = ' '; + + var t = new Date(timestamp * 1000); + var now = new Date(); + + if(t.toDateString() === now.toDateString()) + return t.toLocaleTimeString(); + + return t.toLocaleDateString() + space + t.toLocaleTimeString(); + } + + function alarm_lookup_explain(alarm, chart) { + var dimensions = ' of all values '; + + if(chart.dimensions.length > 1) + dimensions = ' of the sum of all dimensions '; + + if(typeof alarm.lookup_dimensions !== 'undefined') { + var d = alarm.lookup_dimensions.replace(/|/g, ','); + var x = d.split(','); + if(x.length > 1) + dimensions = 'of the sum of dimensions <code>' + alarm.lookup_dimensions + '</code> '; + else + dimensions = 'of all values of dimension <code>' + alarm.lookup_dimensions + '</code> '; + } + + return '<code>' + alarm.lookup_method + '</code> ' + + dimensions + ', of chart <code>' + alarm.chart + '</code>' + + ', starting <code>' + NETDATA.seconds4human(alarm.lookup_after + alarm.lookup_before, { space: ' ' }) + '</code> and up to <code>' + NETDATA.seconds4human(alarm.lookup_before, { space: ' ' }) + '</code>' + + ((alarm.lookup_options)?(', with options <code>' + alarm.lookup_options.replace(/ /g, ', ') + '</code>'):'') + + '.'; + } + + function alarm_to_html(alarm, full) { + var chart = options.data.charts[alarm.chart]; + if(typeof(chart) === 'undefined') { + chart = options.data.charts_by_name[alarm.chart]; + if (typeof(chart) === 'undefined') { + // this means the charts loaded are incomplete + // probably netdata was restarted and more alarms + // are now available. + console.log('Cannot find chart ' + alarm.chart + ', you probably need to refresh the page.'); + return ''; + } + } + + var has_alarm = (typeof alarm.warn !== 'undefined' || typeof alarm.crit !== 'undefined'); + var badge_url = NETDATA.alarms.server + '/api/v1/badge.svg?chart=' + alarm.chart + '&alarm=' + alarm.name + '&refresh=auto'; + + var action_buttons = '<br/> <br/>role: <b>' + alarm.recipient + '</b><br/> <br/>' + + '<div class="action-button ripple" title="click to scroll the dashboard to the chart of this alarm" data-toggle="tooltip" data-placement="bottom" onClick="scrollToChartAfterHidingModal(\'' + alarm.chart + '\'); $(\'#alarmsModal\').modal(\'hide\'); return false;"><i class="fab fa-periscope"></i></div>' + + '<div class="action-button ripple" title="click to copy to the clipboard the URL of this badge" data-toggle="tooltip" data-placement="bottom" onClick="clipboardCopy(\'' + badge_url + '\'); return false;"><i class="far fa-copy"></i></div>' + + '<div class="action-button ripple" title="click to copy to the clipboard an auto-refreshing <code>embed</code> html element for this badge" data-toggle="tooltip" data-placement="bottom" onClick="clipboardCopyBadgeEmbed(\'' + badge_url + '\'); return false;"><i class="fas fa-copy"></i></div>'; + + var html = '<tr><td class="text-center" style="vertical-align:middle" width="40%"><b>' + alarm.chart + '</b><br/> <br/><embed src="' + badge_url + '" type="image/svg+xml" height="20"/><br/> <br/><span style="font-size: 18px">' + alarm.info + '</span>' + action_buttons + '</td>' + + '<td><table class="table">' + + ((typeof alarm.warn !== 'undefined')?('<tr><td width="10%" style="text-align:right">warning when</td><td><span style="font-family: monospace; color:#fe7d37; font-weight: bold;">' + alarm.warn + '</span></td></tr>'):'') + + ((typeof alarm.crit !== 'undefined')?('<tr><td width="10%" style="text-align:right">critical when</td><td><span style="font-family: monospace; color: #e05d44; font-weight: bold;">' + alarm.crit + '</span></td></tr>'):''); + + if(full === true) { + var units = chart.units; + if(units === '%') units = '%'; + + html += ((typeof alarm.lookup_after !== 'undefined')?('<tr><td width="10%" style="text-align:right">db lookup</td><td>' + alarm_lookup_explain(alarm, chart) + '</td></tr>'):'') + + ((typeof alarm.calc !== 'undefined')?('<tr><td width="10%" style="text-align:right">calculation</td><td><span style="font-family: monospace;">' + alarm.calc + '</span></td></tr>'):'') + + ((chart.green !== null)?('<tr><td width="10%" style="text-align:right">green threshold</td><td><code>' + chart.green + ' ' + units + '</code></td></tr>'):'') + + ((chart.red !== null)?('<tr><td width="10%" style="text-align:right">red threshold</td><td><code>' + chart.red + ' ' + units + '</code></td></tr>'):''); + } + + var delay = ''; + if((alarm.delay_up_duration > 0 || alarm.delay_down_duration > 0) && alarm.delay_multiplier !== 0 && alarm.delay_max_duration > 0) { + if(alarm.delay_up_duration === alarm.delay_down_duration) { + delay += '<small><br/>hysteresis ' + NETDATA.seconds4human(alarm.delay_up_duration, { space: ' ', negative_suffix: '' }); + } + else { + delay = '<small><br/>hysteresis '; + if(alarm.delay_up_duration > 0) { + delay += 'on escalation <code>' + NETDATA.seconds4human(alarm.delay_up_duration, { space: ' ', negative_suffix: '' }) + '</code>, '; + } + if(alarm.delay_down_duration > 0) { + delay += 'on recovery <code>' + NETDATA.seconds4human(alarm.delay_down_duration, { space: ' ', negative_suffix: '' }) + '</code>, '; + } + } + if(alarm.delay_multiplier !== 1.0) { + delay += 'multiplied by <code>' + alarm.delay_multiplier.toString() + '</code>'; + delay += ', up to <code>' + NETDATA.seconds4human(alarm.delay_max_duration, { space: ' ', negative_suffix: '' }) + '</code>'; + } + delay += '</small>'; + } + + html += '<tr><td width="10%" style="text-align:right">check every</td><td>' + NETDATA.seconds4human(alarm.update_every, { space: ' ', negative_suffix: '' }) + '</td></tr>' + + ((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>'):'') + + '<tr><td width="10%" style="text-align:right">source</td><td><span style="font-family: monospace;">' + alarm.source + '</span></td></tr>' + + '</table></td></tr>'; + + return html; + } + + function alarm_family_show(id) { + var html = '<table class="table">'; + var family = options.alarm_families[id]; + var len = family.arr.length; + while(len--) { + var alarm = family.arr[len]; + html += alarm_to_html(alarm, true); + } + html += '</table>'; + + $('#alarm_all_' + id.toString()).html(html); + enableTooltipsAndPopovers(); + } + + // find the proper family of each alarm + var x, family, alarm; + var count_active = 0; + var count_all = 0; + var families = {}; + var families_sort = []; + for(x in data.alarms) { + if(!data.alarms.hasOwnProperty(x)) continue; + + alarm = data.alarms[x]; + family = alarm.family; + + // find the chart + var chart = options.data.charts[alarm.chart]; + if(typeof chart === 'undefined') + chart = options.data.charts_by_name[alarm.chart]; + + // not found - this should never happen! + if(typeof chart === 'undefined') { + console.log('WARNING: alarm ' + x + ' is linked to chart ' + alarm.chart + ', which is not found in the list of chart got from the server.'); + chart = { priority: 9999999 }; + } + else if(typeof chart.menu !== 'undefined' && typeof chart.submenu !== 'undefined') + // the family based on the chart + family = chart.menu + ' - ' + chart.submenu; + + if(typeof families[family] === 'undefined') { + families[family] = { + name: family, + arr: [], + priority: chart.priority + }; + + families_sort.push(families[family]); + } + + if(chart.priority < families[family].priority) + families[family].priority = chart.priority; + + families[family].arr.unshift(alarm); + } + + // sort the families, like the dashboard menu does + var families_sorted = families_sort.sort(function (a, b) { + if (a.priority < b.priority) return -1; + if (a.priority > b.priority) return 1; + return naturalSortCompare(a.name, b.name); + }); + + var i = 0; + var fc = 0; + var len = families_sorted.length; + while(len--) { + family = families_sorted[i++].name; + var active_family_added = false; + var expanded = 'true'; + var collapsed = ''; + var cin = 'in'; + + if(fc !== 0) { + all += "</table></div></div></div>"; + expanded = 'false'; + collapsed = 'class="collapsed"'; + cin = ''; + } + + all += '<div class="panel panel-default"><div class="panel-heading" role="tab" id="alarm_all_heading_' + fc.toString() + '"><h4 class="panel-title"><a ' + collapsed + ' role="button" data-toggle="collapse" data-parent="#alarms_all_accordion" href="#alarm_all_' + fc.toString() + '" aria-expanded="' + expanded + '" aria-controls="alarm_all_' + fc.toString() + '">' + family.toString() + '</a></h4></div><div id="alarm_all_' + fc.toString() + '" class="panel-collapse collapse ' + cin + '" role="tabpanel" aria-labelledby="alarm_all_heading_' + fc.toString() + '" data-alarm-id="' + fc.toString() + '"><div class="panel-body" id="alarm_all_body_' + fc.toString() + '">'; + + options.alarm_families[fc] = families[family]; + + fc++; + + var arr = families[family].arr; + var c = arr.length; + while(c--) { + alarm = arr[c]; + if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL') { + if(!active_family_added) { + active_family_added = true; + active += '<tr><th class="text-center" colspan="2"><h4>' + family + '</h4></th></tr>'; + } + count_active++; + active += alarm_to_html(alarm, true); + } + + count_all++; + } + } + active += "</table>"; + if(families_sorted.length > 0) all += "</div></div></div>"; + all += "</div>"; + + if(!count_active) + active += '<div style="width:100%; height: 100px; text-align: center;"><span style="font-size: 50px;"><i class="fas fa-thumbs-up"></i></span><br/>Everything is normal. No raised alarms.</div>'; + else + active += footer; + + if(!count_all) + all += "<h4>No alarms are running in this system.</h4>"; + else + all += footer; + + document.getElementById('alarms_active').innerHTML = active; + document.getElementById('alarms_all').innerHTML = all; + enableTooltipsAndPopovers(); + + if(families_sorted.length > 0) alarm_family_show(0); + + // register bootstrap events + var $accordion = $('#alarms_all_accordion'); + $accordion.on('show.bs.collapse', function (d) { + var target = $(d.target); + var id = $(target).data('alarm-id'); + alarm_family_show(id); + }); + $accordion.on('hidden.bs.collapse', function (d) { + var target = $(d.target); + var id = $(target).data('alarm-id'); + $('#alarm_all_' + id.toString()).html(''); + }); + + document.getElementById('alarms_log').innerHTML = '<h3>Alarm Log</h3><table id="alarms_log_table"></table>'; + + loadBootstrapTable(function () { + $('#alarms_log_table').bootstrapTable({ + url: NETDATA.alarms.server + '/api/v1/alarm_log?all', + cache: false, + pagination: true, + pageSize: 10, + showPaginationSwitch: false, + search: true, + searchTimeOut: 300, + searchAlign: 'left', + showColumns: true, + showExport: true, + exportDataType: 'basic', + exportOptions: { + fileName: 'netdata_alarm_log' + }, + rowStyle: function(row, index) { + void(index); + + switch(row.status) { + case 'CRITICAL' : return { classes: 'danger' }; break; + case 'WARNING' : return { classes: 'warning' }; break; + case 'UNDEFINED': return { classes: 'info' }; break; + case 'CLEAR' : return { classes: 'success' }; break; + } + return {}; + }, + showFooter: false, + showHeader: true, + showRefresh: true, + showToggle: false, + sortable: true, + silentSort: false, + columns: [ + { + field: 'when', + title: 'Event Date', + valign: 'middle', + titleTooltip: 'The date and time the even took place', + formatter: function(value, row, index) { void(row); void(index); return timestamp4human(value, ' '); }, + align: 'center', + switchable: false, + sortable: true + }, + { + field: 'hostname', + title: 'Host', + valign: 'middle', + titleTooltip: 'The host that generated this event', + align: 'center', + visible: false, + sortable: true + }, + { + field: 'unique_id', + title: 'Unique ID', + titleTooltip: 'The host unique ID for this event', + formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'alarm_id', + title: 'Alarm ID', + titleTooltip: 'The ID of the alarm that generated this event', + formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'alarm_event_id', + title: 'Alarm Event ID', + titleTooltip: 'The incremental ID of this event for the given alarm', + formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'chart', + title: 'Chart', + titleTooltip: 'The chart the alarm is attached to', + align: 'center', + valign: 'middle', + switchable: false, + sortable: true + }, + { + field: 'family', + title: 'Family', + titleTooltip: 'The family of the chart the alarm is attached to', + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'name', + title: 'Alarm', + titleTooltip: 'The alarm name that generated this event', + formatter: function(value, row, index) { + void(row); + void(index); + return value.toString().replace(/_/g, ' '); + }, + align: 'center', + valign: 'middle', + switchable: false, + sortable: true + }, + { + field: 'value_string', + title: 'Friendly Value', + titleTooltip: 'The value of the alarm, that triggered this event', + align: 'right', + valign: 'middle', + sortable: true + }, + { + field: 'old_value_string', + title: 'Friendly Old Value', + titleTooltip: 'The value of the alarm, just before this event', + align: 'right', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'old_value', + title: 'Old Value', + titleTooltip: 'The value of the alarm, just before this event', + formatter: function(value, row, index) { + void(row); + void(index); + return ((value !== null)?Math.round(value * 100) / 100:'NaN').toString(); + }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'value', + title: 'Value', + titleTooltip: 'The value of the alarm, that triggered this event', + formatter: function(value, row, index) { + void(row); + void(index); + return ((value !== null)?Math.round(value * 100) / 100:'NaN').toString(); + }, + align: 'right', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'units', + title: 'Units', + titleTooltip: 'The units of the value of the alarm', + align: 'left', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'old_status', + title: 'Old Status', + titleTooltip: 'The status of the alarm, just before this event', + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'status', + title: 'Status', + titleTooltip: 'The status of the alarm, that was set due to this event', + align: 'center', + valign: 'middle', + switchable: false, + sortable: true + }, + { + field: 'duration', + title: 'Last Duration', + titleTooltip: 'The duration the alarm was at its previous state, just before this event', + formatter: function(value, row, index) { + void(row); + void(index); + return NETDATA.seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); + }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'non_clear_duration', + title: 'Raised Duration', + titleTooltip: 'The duration the alarm was raised, just before this event', + formatter: function(value, row, index) { + void(row); + void(index); + return NETDATA.seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); + }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'recipient', + title: 'Recipient', + titleTooltip: 'The recipient of this event', + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'processed', + title: 'Processed Status', + titleTooltip: 'True when this event is processed', + formatter: function(value, row, index) { + void(row); + void(index); + + if(value === true) + return 'DONE'; + else + return 'PENDING'; + }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'updated', + title: 'Updated Status', + titleTooltip: 'True when this event has been updated by another event', + formatter: function(value, row, index) { + void(row); + void(index); + + if(value === true) + return 'UPDATED'; + else + return 'CURRENT'; + }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'updated_by_id', + title: 'Updated By ID', + titleTooltip: 'The unique ID of the event that obsoleted this one', + formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'updates_id', + title: 'Updates ID', + titleTooltip: 'The unique ID of the event obsoleted because of this event', + formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'exec', + title: 'Script', + titleTooltip: 'The script to handle the event notification', + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'exec_run', + title: 'Script Run At', + titleTooltip: 'The date and time the script has been ran', + formatter: function(value, row, index) { void(row); void(index); return timestamp4human(value, ' '); }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'exec_code', + title: 'Script Return Value', + titleTooltip: 'The return code of the script', + formatter: function(value, row, index) { + void(row); + void(index); + + if(value === 0) + return 'OK (returned 0)'; + else + return 'FAILED (with code ' + value.toString() + ')'; + }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'delay', + title: 'Script Delay', + titleTooltip: 'The hysteresis of the notification', + formatter: function(value, row, index) { + void(row); + void(index); + + return NETDATA.seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); + }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'delay_up_to_timestamp', + title: 'Script Delay Run At', + titleTooltip: 'The date and time the script should be run, after hysteresis', + formatter: function(value, row, index) { void(row); void(index); return timestamp4human(value, ' '); }, + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'info', + title: 'Description', + titleTooltip: 'A short description of the alarm', + align: 'center', + valign: 'middle', + visible: false, + sortable: true + }, + { + field: 'source', + title: 'Alarm Source', + titleTooltip: 'The source of configuration of the alarm', + align: 'center', + valign: 'middle', + visible: false, + sortable: true + } + ] + }); + // console.log($('#alarms_log_table').bootstrapTable('getOptions')); + }); + }); + } + + function alarmsCallback(data) { + var count = 0, x; + for(x in data.alarms) { + if(!data.alarms.hasOwnProperty(x)) continue; + + var alarm = data.alarms[x]; + if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL') + count++; + } + + if(count > 0) + document.getElementById('alarms_count_badge').innerHTML = count.toString(); + else + document.getElementById('alarms_count_badge').innerHTML = ''; + } + + function initializeDynamicDashboardWithData(data) { + if(data !== null) { + options.hostname = data.hostname; + options.data = data; + options.version = data.version; + netdataDashboard.os = data.os; + + if(typeof data.hosts !=='undefined') + options.hosts = data.hosts; + + // update the dashboard hostname + document.getElementById('hostname').innerHTML = options.hostname + ((netdataSnapshotData !== null)?' (snap)':'').toString(); + document.getElementById('hostname').href = NETDATA.serverDefault; + document.getElementById('netdataVersion').innerHTML = options.version; + + if(netdataSnapshotData !== null) { + $('#alarmsButton').hide(); + $('#updateButton').hide(); + // $('#loadButton').hide(); + $('#saveButton').hide(); + $('#printButton').hide(); + } + + // update the dashboard title + document.title = options.hostname + ' netdata dashboard'; + + // close the splash screen + $("#loadOverlay").css("display","none"); + + // create a chart_by_name index + data.charts_by_name = {}; + var charts = data.charts; + var x; + for(x in charts) { + if(!charts.hasOwnProperty(x)) continue; + + var chart = charts[x]; + data.charts_by_name[chart.name] = chart; + } + + // render all charts + renderChartsAndMenu(data); + } + } + + // an object to keep initilization configuration + // needed due to the async nature of the XSS modal + var initializeConfig = { + url: null, + custom_info: true, + }; + + function loadCustomDashboardInfo(url, callback) { + loadJs(url, function () { + $.extend(true, netdataDashboard, customDashboard); + callback(); + }); + } + + function initializeChartsAndCustomInfo() { + NETDATA.alarms.callback = alarmsCallback; + + // download all the charts the server knows + NETDATA.chartRegistry.downloadAll(initializeConfig.url, function(data) { + if(data !== null) { + if (initializeConfig.custom_info === true && typeof data.custom_info !== 'undefined' && data.custom_info !== "" && netdataSnapshotData === null) { + //console.log('loading custom dashboard decorations from server ' + initializeConfig.url); + loadCustomDashboardInfo(NETDATA.serverDefault + data.custom_info, function () { + initializeDynamicDashboardWithData(data); + }); + } + else { + //console.log('not loading custom dashboard decorations from server ' + initializeConfig.url); + initializeDynamicDashboardWithData(data); + } + } + }); + } + + function xssModalDisableXss() { + //console.log('disabling xss checks'); + NETDATA.xss.enabled = false; + NETDATA.xss.enabled_for_data = false; + initializeConfig.custom_info = true; + initializeChartsAndCustomInfo(); + return false; + } + + function xssModalKeepXss() { + //console.log('keeping xss checks'); + NETDATA.xss.enabled = true; + NETDATA.xss.enabled_for_data = true; + initializeConfig.custom_info = false; + initializeChartsAndCustomInfo(); + return false; + } + + function initializeDynamicDashboard(netdata_url) { + if(typeof netdata_url === 'undefined' || netdata_url === null) + netdata_url = NETDATA.serverDefault; + + initializeConfig.url = netdata_url; + + // initialize clickable alarms + NETDATA.alarms.chart_div_offset = -50; + NETDATA.alarms.chart_div_id_prefix = 'chart_'; + NETDATA.alarms.chart_div_animation_duration = 0; + + NETDATA.pause(function() { + if(typeof netdataCheckXSS !== 'undefined' && netdataCheckXSS === true) { + //$("#loadOverlay").css("display","none"); + document.getElementById('netdataXssModalServer').innerText = initializeConfig.url; + $('#xssModal').modal('show'); + } + else { + initializeChartsAndCustomInfo(); + } + }); + } + + // ---------------------------------------------------------------------------- + + function versionLog(msg) { + document.getElementById('versionCheckLog').innerHTML = msg; + } + + function getNetdataCommitIdFromVersion() { + var s = options.version.split('-'); + + if(s.length !== 3) return null; + if(s[2][0] === 'g') { + var v = s[2].split('_')[0].substring(1, 8); + if(v.length === 7) { + versionLog('Installed git commit id of netdata is ' + v); + document.getElementById('netdataCommitId').innerHTML = v; + return v; + } + } + return null; + } + + function getNetdataCommitId(force, callback) { + versionLog('Downloading installed git commit id from netdata...'); + + $.ajax({ + url: 'version.txt', + async: true, + cache: false, + xhrFields: { withCredentials: true } // required for the cookie + }) + .done(function(data) { + data = data.replace(/(\r\n|\n|\r| |\t)/gm,""); + + var c = getNetdataCommitIdFromVersion(); + if(c !== null && data.length === 40 && data.substring(0, 7) !== c) { + versionLog('Installed files commit id and internal netdata git commit id do not match'); + data = c; + } + + if(data.length >= 7) { + versionLog('Installed git commit id of netdata is ' + data); + document.getElementById('netdataCommitId').innerHTML = data.substring(0, 7); + callback(data); + } + }) + .fail(function() { + versionLog('Failed to download installed git commit id from netdata!'); + + if(force === true) { + var c = getNetdataCommitIdFromVersion(); + if(c === null) versionLog('Cannot find the git commit id of netdata.'); + callback(c); + } + else + callback(null); + }); + } + + function getGithubLatestCommit(callback) { + versionLog('Downloading latest git commit id info from github...'); + + $.ajax({ + url: 'https://api.github.com/repos/netdata/netdata/commits', + async: true, + cache: false + }) + .done(function(data) { + versionLog('Latest git commit id from github is ' + data[0].sha); + callback(data[0].sha); + }) + .fail(function() { + versionLog('Failed to download installed git commit id from github!'); + callback(null); + }); + } + + function checkForUpdate(force, callback) { + getNetdataCommitId(force, function(sha1) { + if(sha1 === null) callback(null, null); + + getGithubLatestCommit(function(sha2) { + callback(sha1, sha2); + }); + }); + + return null; + } + + function notifyForUpdate(force) { + versionLog('<p>checking for updates...</p>'); + + var now = Date.now(); + + if(typeof force === 'undefined' || force !== true) { + var last = loadLocalStorage('last_update_check'); + + if(typeof last === 'string') + last = parseInt(last); + else + last = 0; + + if(now - last < 3600000 * 8) { + // no need to check it - too soon + return; + } + } + + checkForUpdate(force, function(sha1, sha2) { + var save = false; + + if(sha1 === null) { + save = false; + versionLog('<p><big>Failed to get your netdata git commit id!</big></p><p>You can always get the latest netdata from <a href="https://github.com/netdata/netdata" target="_blank">its github page</a>.</p>'); + } + else if(sha2 === null) { + save = false; + versionLog('<p><big>Failed to get the latest git commit id from github.</big></p><p>You can always get the latest netdata from <a href="https://github.com/netdata/netdata" target="_blank">its github page</a>.</p>'); + } + else if(sha1 === sha2) { + save = true; + versionLog('<p><big>You already have the latest netdata!</big></p><p>No update yet?<br/>Probably, we need some motivation to keep going on!</p><p>If you haven\'t already, <a href="https://github.com/netdata/netdata" target="_blank">give netdata a <b><i class="fas fa-star"></i></b> at its github page</a>.</p>'); + } + else { + save = true; + var compare = 'https://github.com/netdata/netdata/compare/' + sha1.toString() + '...' + sha2.toString(); + + versionLog('<p><big><strong>New version of netdata available!</strong></big></p><p>Latest commit: <b><code>' + sha2.substring(0, 7).toString() + '</code></b></p><p><a href="' + compare + '" target="_blank">Click here for the changes log</a> since your installed version, and<br/><a href="https://github.com/netdata/netdata/wiki/Updating-Netdata" target="_blank">click here for directions on updating</a> your netdata installation.</p><p>We suggest to review the changes log for new features you may be interested, or important bug fixes you may need.<br/>Keeping your netdata updated, is generally a good idea.</p>'); + + document.getElementById('update_badge').innerHTML = '!'; + } + + if(save) + saveLocalStorage('last_update_check', now.toString()); + }); + } + + // ---------------------------------------------------------------------------- + // printing dashboards + + function showPageFooter() { + document.getElementById('footer').style.display = 'block'; + } + + + function printPreflight() { + var url = document.location.origin.toString() + document.location.pathname.toString() + document.location.search.toString() + urlOptions.genHash() + ';mode=print'; + var width = 990; + var height = screen.height * 90 / 100; + //console.log(url); + //console.log(document.location); + window.open(url, '', 'width=' + width.toString() + ',height=' + height.toString() + ',menubar=no,toolbar=no,personalbar=no,location=no,resizable=no,scrollbars=yes,status=no,chrome=yes,centerscreen=yes,attention=yes,dialog=yes'); + $('#printPreflightModal').modal('hide'); + } + + function printPage() { + var print_is_rendering = true; + + $('#printModal').on('hide.bs.modal', function(e) { + if(print_is_rendering === true) { + e.preventDefault(); + return false; + } + + return true; + }); + + $('#printModal').on('show.bs.modal', function() { + var print_options = { + stop_updates_when_focus_is_lost: false, + update_only_visible: false, + sync_selection: false, + eliminate_zero_dimensions: false, + pan_and_zoom_data_padding: false, + show_help: false, + legend_toolbox: false, + resize_charts: false, + pixels_per_point: 1 + }; + + var x; + for(x in print_options) { + if (print_options.hasOwnProperty(x)) + NETDATA.options.current[x] = print_options[x]; + } + + NETDATA.parseDom(); + showPageFooter(); + + NETDATA.globalSelectionSync.stop(); + NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], urlOptions.after, urlOptions.before); + // NETDATA.onresize(); + + var el = document.getElementById('printModalProgressBar'); + var eltxt = document.getElementById('printModalProgressBarText'); + + function update_chart(idx) { + var state = NETDATA.options.targets[--idx]; + + var pcent = (NETDATA.options.targets.length - idx) * 100 / NETDATA.options.targets.length; + $(el).css('width', pcent+'%').attr('aria-valuenow', pcent); + eltxt.innerText = Math.round(pcent).toString() + '%, ' + state.id; + + setTimeout(function() { + state.updateChart(function () { + NETDATA.options.targets[idx].resizeForPrint(); + + if (idx > 0) { + update_chart(idx); + } + else { + print_is_rendering = false; + $('#printModal').modal('hide'); + window.print(); + window.close(); + } + }) + }, 0); + } + + print_is_rendering = true; + update_chart(NETDATA.options.targets.length); + }); + + $('#printModal').modal('show'); + } + + // -------------------------------------------------------------------- + + function jsonStringifyFn(obj) { + return JSON.stringify(obj, function (key, value) { + return (typeof value === 'function' ) ? value.toString() : value; + }); + } + + function jsonParseFn(str) { + return JSON.parse(str, function (key, value) { + if (typeof value != 'string') return value; + return ( value.substring(0, 8) == 'function') ? eval('(' + value + ')') : value; + }); + } + + // -------------------------------------------------------------------- + + var snapshotOptions = { + bytes_per_chart: 2048, + compressionDefault: 'pako.deflate.base64', + + compressions: { + 'none': { + bytes_per_point_memory: 5.2, + bytes_per_point_disk: 5.6, + + compress: function (s) { + return s; + }, + + compressed_length: function (s) { + return s.length; + }, + + uncompress: function (s) { + return s; + } + }, + + 'pako.deflate.base64': { + bytes_per_point_memory: 1.8, + bytes_per_point_disk: 1.9, + + compress: function (s) { + return btoa(pako.deflate(s, { to: 'string' })); + }, + + compressed_length: function (s) { + return s.length; + }, + + uncompress: function (s) { + return pako.inflate(atob(s), {to: 'string'}); + } + }, + + 'pako.deflate': { + bytes_per_point_memory: 1.4, + bytes_per_point_disk: 3.2, + + compress: function (s) { + return pako.deflate(s, { to: 'string' }); + }, + + compressed_length: function (s) { + return s.length; + }, + + uncompress: function (s) { + return pako.inflate(s, {to: 'string'}); + } + }, + + 'lzstring.utf16': { + bytes_per_point_memory: 1.7, + bytes_per_point_disk: 2.6, + + compress: function (s) { + return LZString.compressToUTF16(s); + }, + + compressed_length: function (s) { + return s.length * 2; + }, + + uncompress: function (s) { + return LZString.decompressFromUTF16(s); + } + }, + + 'lzstring.base64': { + bytes_per_point_memory: 2.1, + bytes_per_point_disk: 2.3, + + compress: function (s) { + return LZString.compressToBase64(s); + }, + + compressed_length: function (s) { + return s.length; + }, + + uncompress: function (s) { + return LZString.decompressFromBase64(s); + } + }, + + 'lzstring.uri': { + bytes_per_point_memory: 2.1, + bytes_per_point_disk: 2.3, + + compress: function (s) { + return LZString.compressToEncodedURIComponent(s); + }, + + compressed_length: function (s) { + return s.length; + }, + + uncompress: function (s) { + return LZString.decompressFromEncodedURIComponent(s); + } + } + } + }; + + // -------------------------------------------------------------------- + // loading snapshots + + function loadSnapshotModalLog(priority, msg) { + document.getElementById('loadSnapshotStatus').className = "alert alert-" + priority; + document.getElementById('loadSnapshotStatus').innerHTML = msg; + } + + var tmpSnapshotData = null; + function loadSnapshot() { + $('#loadSnapshotImport').addClass('disabled'); + + if(tmpSnapshotData === null) { + loadSnapshotPreflightEmpty(); + loadSnapshotModalLog('danger', 'no data have been loaded'); + return; + } + + loadPako(function() { + loadLzString(function () { + loadSnapshotModalLog('info', 'Please wait, activating snapshot...'); + $('#loadSnapshotModal').modal('hide'); + + netdataShowAlarms = false; + netdataRegistry = false; + netdataServer = tmpSnapshotData.server; + NETDATA.serverDefault = netdataServer; + + document.getElementById('charts_div').innerHTML = ''; + document.getElementById('sidebar').innerHTML = ''; + NETDATA.globalReset(); + + if (typeof tmpSnapshotData.hash !== 'undefined') + urlOptions.hash = tmpSnapshotData.hash; + else + urlOptions.hash = '#'; + + if (typeof tmpSnapshotData.info !== 'undefined') { + var info = jsonParseFn(tmpSnapshotData.info); + if (typeof info.menu !== 'undefined') + netdataDashboard.menu = info.menu; + + if (typeof info.submenu !== 'undefined') + netdataDashboard.submenu = info.submenu; + + if (typeof info.context !== 'undefined') + netdataDashboard.context = info.context; + } + + if (typeof tmpSnapshotData.compression !== 'string') + tmpSnapshotData.compression = 'none'; + + if (typeof snapshotOptions.compressions[tmpSnapshotData.compression] === 'undefined') { + alert('unknown compression method: ' + tmpSnapshotData.compression); + tmpSnapshotData.compression = 'none'; + } + + tmpSnapshotData.uncompress = snapshotOptions.compressions[tmpSnapshotData.compression].uncompress; + netdataSnapshotData = tmpSnapshotData; + + urlOptions.after = tmpSnapshotData.after_ms; + urlOptions.before = tmpSnapshotData.before_ms; + + if( typeof tmpSnapshotData.highlight_after_ms !== 'undefined' + && tmpSnapshotData.highlight_after_ms !== null + && tmpSnapshotData.highlight_after_ms > 0 + && typeof tmpSnapshotData.highlight_before_ms !== 'undefined' + && tmpSnapshotData.highlight_before_ms !== null + && tmpSnapshotData.highlight_before_ms > 0 + ) { + urlOptions.highlight_after = tmpSnapshotData.highlight_after_ms; + urlOptions.highlight_before = tmpSnapshotData.highlight_before_ms; + urlOptions.highlight = true; + } + else { + urlOptions.highlight_after = 0; + urlOptions.highlight_before = 0; + urlOptions.highlight = false; + } + + netdataCheckXSS = false; // disable the modal - this does not affect XSS checks, since dashboard.js is already loaded + NETDATA.xss.enabled = true; // we should not do any remote requests, but if we do, check them + NETDATA.xss.enabled_for_data = true; // check also snapshot data - that have been excluded from the initial check, due to compression + loadSnapshotPreflightEmpty(); + initializeDynamicDashboard(); + }); + }); + }; + + + function loadSnapshotPreflightFile(file) { + var filename = NETDATA.xss.string(file.name); + var fr = new FileReader(); + fr.onload = function(e) { + document.getElementById('loadSnapshotFilename').innerHTML = filename; + var result = null; + try { + result = NETDATA.xss.checkAlways('snapshot', JSON.parse(e.target.result), /^(snapshot\.info|snapshot\.data)$/); + + //console.log(result); + var date_after = new Date(result.after_ms); + var date_before = new Date(result.before_ms); + + if (typeof result.charts_ok === 'undefined') + result.charts_ok = 'unknown'; + + if (typeof result.charts_failed === 'undefined') + result.charts_failed = 0; + + if (typeof result.compression === 'undefined') + result.compression = 'none'; + + if (typeof result.data_size === 'undefined') + result.data_size = 0; + + document.getElementById('loadSnapshotFilename').innerHTML = '<code>' + filename + '</code>'; + document.getElementById('loadSnapshotHostname').innerHTML = '<b>' + result.hostname + '</b>, netdata version: <b>' + result.netdata_version.toString() + '</b>'; + document.getElementById('loadSnapshotURL').innerHTML = result.url; + document.getElementById('loadSnapshotCharts').innerHTML = result.charts.charts_count.toString() + ' charts, ' + result.charts.dimensions_count.toString() + ' dimensions, ' + result.data_points.toString() + ' points per dimension, ' + Math.round(result.duration_ms / result.data_points).toString() + ' ms per point'; + document.getElementById('loadSnapshotInfo').innerHTML = 'version: <b>' + result.snapshot_version.toString() + '</b>, includes <b>' + result.charts_ok.toString() + '</b> unique chart data queries ' + ((result.charts_failed > 0) ? ('<b>' + result.charts_failed.toString() + '</b> failed') : '').toString() + ', compressed with <code>' + result.compression.toString() + '</code>, data size ' + (Math.round(result.data_size * 100 / 1024 / 1024) / 100).toString() + ' MB'; + document.getElementById('loadSnapshotTimeRange').innerHTML = '<b>' + NETDATA.dateTime.localeDateString(date_after) + ' ' + NETDATA.dateTime.localeTimeString(date_after) + '</b> to <b>' + NETDATA.dateTime.localeDateString(date_before) + ' ' + NETDATA.dateTime.localeTimeString(date_before) + '</b>'; + document.getElementById('loadSnapshotComments').innerHTML = ((result.comments) ? result.comments : '').toString(); + loadSnapshotModalLog('success', 'File loaded, click <b>Import</b> to render it!'); + $('#loadSnapshotImport').removeClass('disabled'); + + tmpSnapshotData = result; + } + catch (e) { + console.log(e); + document.getElementById('loadSnapshotStatus').className = "alert alert-danger"; + document.getElementById('loadSnapshotStatus').innerHTML = "Failed to parse this file!"; + $('#loadSnapshotImport').addClass('disabled'); + } + } + + //console.log(file); + fr.readAsText(file); + }; + + function loadSnapshotPreflightEmpty() { + document.getElementById('loadSnapshotFilename').innerHTML = ''; + document.getElementById('loadSnapshotHostname').innerHTML = ''; + document.getElementById('loadSnapshotURL').innerHTML = ''; + document.getElementById('loadSnapshotCharts').innerHTML = ''; + document.getElementById('loadSnapshotInfo').innerHTML = ''; + document.getElementById('loadSnapshotTimeRange').innerHTML = ''; + document.getElementById('loadSnapshotComments').innerHTML = ''; + loadSnapshotModalLog('success', 'Browse for a snapshot file (or drag it and drop it here), then click <b>Import</b> to render it.'); + $('#loadSnapshotImport').addClass('disabled'); + }; + + var loadSnapshotDragAndDropInitialized = false; + function loadSnapshotDragAndDropSetup() { + if(loadSnapshotDragAndDropInitialized === false) { + loadSnapshotDragAndDropInitialized = true; + $('#loadSnapshotDragAndDrop') + .on('drag dragstart dragend dragover dragenter dragleave drop', function (e) { + e.preventDefault(); + e.stopPropagation(); + }) + .on('drop', function (e) { + if(e.originalEvent.dataTransfer.files.length) { + loadSnapshotPreflightFile(e.originalEvent.dataTransfer.files.item(0)); + } + else { + loadSnapshotPreflightEmpty(); + loadSnapshotModalLog('danger', 'No file selected'); + } + }); + } + }; + + function loadSnapshotPreflight() { + var files = document.getElementById('loadSnapshotSelectFiles').files; + if (files.length <= 0) { + loadSnapshotPreflightEmpty(); + loadSnapshotModalLog('danger', 'No file selected'); + return; + } + + loadSnapshotModalLog('info', 'Loading file...'); + + loadSnapshotPreflightFile(files.item(0)); + } + + // -------------------------------------------------------------------- + // saving snapshots + + var saveSnapshotStop = false; + function saveSnapshotCancel() { + saveSnapshotStop = true; + } + + var saveSnapshotModalInitialized = false; + function saveSnapshotModalSetup() { + if(saveSnapshotModalInitialized === false) { + saveSnapshotModalInitialized = true; + $('#saveSnapshotModal') + .on('hide.bs.modal', saveSnapshotCancel) + .on('show.bs.modal', saveSnapshotModalInit) + .on('shown.bs.modal', function() { + $('#saveSnapshotResolutionSlider').find(".slider-handle:first").attr("tabindex", 1); + document.getElementById('saveSnapshotComments').focus(); + }); + } + }; + + function saveSnapshotModalLog(priority, msg) { + document.getElementById('saveSnapshotStatus').className = "alert alert-" + priority; + document.getElementById('saveSnapshotStatus').innerHTML = msg; + } + + function saveSnapshotModalShowExpectedSize() { + var points = Math.round(saveSnapshotViewDuration / saveSnapshotSelectedSecondsPerPoint); + var priority = 'info'; + var msg = 'A moderate snapshot.'; + + var sizemb = Math.round( + (options.data.charts_count * snapshotOptions.bytes_per_chart + + options.data.dimensions_count * points * snapshotOptions.compressions[saveSnapshotCompression].bytes_per_point_disk) + * 10 / 1024 / 1024) / 10; + + var memmb = Math.round( + (options.data.charts_count * snapshotOptions.bytes_per_chart + + options.data.dimensions_count * points * snapshotOptions.compressions[saveSnapshotCompression].bytes_per_point_memory) + * 10 / 1024 / 1024) / 10; + + if(sizemb < 10) { + priority = 'success'; + msg = 'A nice small snapshot!'; + } + if(sizemb > 50) { + priority = 'warning'; + msg = 'Will stress your browser...'; + } + if(sizemb > 100) { + priority = 'danger'; + msg = 'Hm... good luck...'; + } + + saveSnapshotModalLog(priority, 'The snapshot will have ' + points.toString() + ' points per dimension. Expected size on disk ' + sizemb + ' MB, at browser memory ' + memmb + ' MB.<br/>' + msg); + } + + var saveSnapshotCompression = snapshotOptions.compressionDefault; + function saveSnapshotSetCompression(name) { + saveSnapshotCompression = name; + document.getElementById('saveSnapshotCompressionName').innerHTML = saveSnapshotCompression; + saveSnapshotModalShowExpectedSize(); + } + + var saveSnapshotSlider = null; + var saveSnapshotSelectedSecondsPerPoint = 1; + var saveSnapshotViewDuration = 1; + function saveSnapshotModalInit() { + $('#saveSnapshotModalProgressSection').hide(); + $('#saveSnapshotResolutionRadio').show(); + saveSnapshotModalLog('info', 'Select resolution and click <b>Save</b>'); + $('#saveSnapshotExport').removeClass('disabled'); + + loadBootstrapSlider(function() { + saveSnapshotViewDuration = options.duration; + var start_ms = Math.round(Date.now() - saveSnapshotViewDuration * 1000); + + if(NETDATA.globalPanAndZoom.isActive() === true) { + saveSnapshotViewDuration = Math.round((NETDATA.globalPanAndZoom.force_before_ms - NETDATA.globalPanAndZoom.force_after_ms) / 1000); + start_ms = NETDATA.globalPanAndZoom.force_after_ms; + } + + var start_date = new Date(start_ms); + var yyyymmddhhssmm = start_date.getFullYear() + NETDATA.zeropad(start_date.getMonth() + 1) + NETDATA.zeropad(start_date.getDate()) + '-' + NETDATA.zeropad(start_date.getHours()) + NETDATA.zeropad(start_date.getMinutes()) + NETDATA.zeropad(start_date.getSeconds()); + + document.getElementById('saveSnapshotFilename').value = 'netdata-' + options.hostname.toString() + '-' + yyyymmddhhssmm.toString() + '-' + saveSnapshotViewDuration.toString() + '.snapshot'; + saveSnapshotSetCompression(saveSnapshotCompression); + + var min = options.update_every; + var max = Math.round(saveSnapshotViewDuration / 100); + + if(NETDATA.globalPanAndZoom.isActive() === false) + max = Math.round(saveSnapshotViewDuration / 50); + + var view = Math.round(saveSnapshotViewDuration / Math.round($(document.getElementById('charts_div')).width() / 2)); + + // console.log('view duration: ' + saveSnapshotViewDuration + ', min: ' + min + ', max: ' + max + ', view: ' + view); + + if(max < 10) max = 10; + if(max < min) max = min; + if(view < min) view = min; + if(view > max) view = max; + + if(saveSnapshotSlider !== null) + saveSnapshotSlider.destroy(); + + saveSnapshotSlider = new Slider('#saveSnapshotResolutionSlider', { + ticks: [ min, view, max ], + min: min, + max: max, + step: options.update_every, + value: view, + scale: (max > 100)?'logarithmic':'linear', + tooltip: 'always', + formatter: function(value) { + if(value < 1) + value = 1; + + if(value < options.data.update_every) + value = options.data.update_every; + + saveSnapshotSelectedSecondsPerPoint = value; + saveSnapshotModalShowExpectedSize(); + + var seconds = ' seconds '; + if(value === 1) + seconds = ' second '; + + return value + seconds + 'per point' + ((value === options.data.update_every)?', server default':'').toString(); + } + }); + }); + } + + function saveSnapshot() { + loadPako(function () { + loadLzString(function () { + saveSnapshotStop = false; + $('#saveSnapshotModalProgressSection').show(); + $('#saveSnapshotResolutionRadio').hide(); + $('#saveSnapshotExport').addClass('disabled'); + + var filename = document.getElementById('saveSnapshotFilename').value; + // console.log(filename); + saveSnapshotModalLog('info', 'Generating snapshot as <code>' + filename.toString() + '</code>'); + + var save_options = { + stop_updates_when_focus_is_lost: false, + update_only_visible: false, + sync_selection: false, + eliminate_zero_dimensions: true, + pan_and_zoom_data_padding: false, + show_help: false, + legend_toolbox: false, + resize_charts: false, + pixels_per_point: 1 + }; + var backedup_options = {}; + + var x; + for (x in save_options) { + if (save_options.hasOwnProperty(x)) { + backedup_options[x] = NETDATA.options.current[x]; + NETDATA.options.current[x] = save_options[x]; + } + } + + var el = document.getElementById('saveSnapshotModalProgressBar'); + var eltxt = document.getElementById('saveSnapshotModalProgressBarText'); + + options.data.charts_by_name = null; + + var saveData = { + hostname: options.hostname, + server: NETDATA.serverDefault, + netdata_version: options.data.version, + snapshot_version: 1, + after_ms: Date.now() - options.duration * 1000, + before_ms: Date.now(), + highlight_after_ms: urlOptions.highlight_after, + highlight_before_ms: urlOptions.highlight_before, + duration_ms: options.duration * 1000, + update_every_ms: options.update_every * 1000, + data_points: 0, + url: ((urlOptions.server !== null) ? urlOptions.server : document.location.origin.toString() + document.location.pathname.toString() + document.location.search.toString()).toString(), + comments: document.getElementById('saveSnapshotComments').value.toString(), + hash: urlOptions.hash, + charts: options.data, + info: jsonStringifyFn({ + menu: netdataDashboard.menu, + submenu: netdataDashboard.submenu, + context: netdataDashboard.context + }), + charts_ok: 0, + charts_failed: 0, + compression: saveSnapshotCompression, + data_size: 0, + data: {} + }; + + if(typeof snapshotOptions.compressions[saveData.compression] === 'undefined') { + alert('unknown compression method: ' + saveData.compression); + saveData.compression = 'none'; + } + + var compress = snapshotOptions.compressions[saveData.compression].compress; + var compressed_length = snapshotOptions.compressions[saveData.compression].compressed_length; + + function pack_api1_v1_chart_data(state) { + if (state.library_name === null || state.data === null) + return; + + var data = state.data; + state.data = null; + data.state = null; + var str = JSON.stringify(data); + + if (typeof str === 'string') { + var cstr = compress(str); + saveData.data[state.chartDataUniqueID()] = cstr; + return compressed_length(cstr); + } + else + return 0; + } + + var clearPanAndZoom = false; + if (NETDATA.globalPanAndZoom.isActive() === false) { + NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], saveData.after_ms, saveData.before_ms); + clearPanAndZoom = true; + } + + saveData.after_ms = NETDATA.globalPanAndZoom.force_after_ms; + saveData.before_ms = NETDATA.globalPanAndZoom.force_before_ms; + saveData.duration_ms = saveData.before_ms - saveData.after_ms; + saveData.data_points = Math.round((saveData.before_ms - saveData.after_ms) / (saveSnapshotSelectedSecondsPerPoint * 1000)); + saveSnapshotModalLog('info', 'Generating snapshot with ' + saveData.data_points.toString() + ' data points per dimension...'); + + var charts_count = 0; + var charts_ok = 0; + var charts_failed = 0; + + function saveSnapshotRestore() { + $('#saveSnapshotModal').modal('hide'); + + // restore the options + var x; + for (x in backedup_options) { + if (backedup_options.hasOwnProperty(x)) + NETDATA.options.current[x] = backedup_options[x]; + } + + $(el).css('width', '0%').attr('aria-valuenow', 0); + eltxt.innerText = '0%'; + + if (clearPanAndZoom) + NETDATA.globalPanAndZoom.clearMaster(); + + NETDATA.options.force_data_points = 0; + NETDATA.options.fake_chart_rendering = false; + NETDATA.onscroll_updater_enabled = true; + NETDATA.onresize(); + NETDATA.unpause(); + + $('#saveSnapshotExport').removeClass('disabled'); + } + + NETDATA.globalSelectionSync.stop(); + NETDATA.options.force_data_points = saveData.data_points; + NETDATA.options.fake_chart_rendering = true; + NETDATA.onscroll_updater_enabled = false; + NETDATA.abort_all_refreshes(); + + var size = 0; + var info = ' Resolution: <b>' + saveSnapshotSelectedSecondsPerPoint.toString() + ((saveSnapshotSelectedSecondsPerPoint === 1)?' second ':' seconds ').toString() + 'per point</b>.'; + + function update_chart(idx) { + if (saveSnapshotStop === true) { + saveSnapshotModalLog('info', 'Cancelled!'); + saveSnapshotRestore(); + return; + } + + var state = NETDATA.options.targets[--idx]; + + var pcent = (NETDATA.options.targets.length - idx) * 100 / NETDATA.options.targets.length; + $(el).css('width', pcent + '%').attr('aria-valuenow', pcent); + eltxt.innerText = Math.round(pcent).toString() + '%, ' + state.id; + + setTimeout(function () { + charts_count++; + state.isVisible(true); + state.current.force_after_ms = saveData.after_ms; + state.current.force_before_ms = saveData.before_ms; + + state.updateChart(function (status, reason) { + state.current.force_after_ms = null; + state.current.force_before_ms = null; + + if (status === true) { + charts_ok++; + // state.log('ok'); + size += pack_api1_v1_chart_data(state); + } + else { + charts_failed++; + state.log('failed to be updated: ' + reason); + } + + saveSnapshotModalLog((charts_failed) ? 'danger' : 'info', 'Generated snapshot data size <b>' + (Math.round(size * 100 / 1024 / 1024) / 100).toString() + ' MB</b>. ' + ((charts_failed) ? (charts_failed.toString() + ' charts have failed to be downloaded') : '').toString() + info); + + if (idx > 0) { + update_chart(idx); + } + else { + saveData.charts_ok = charts_ok; + saveData.charts_failed = charts_failed; + saveData.data_size = size; + // console.log(saveData.compression + ': ' + (size / (options.data.dimensions_count * Math.round(saveSnapshotViewDuration / saveSnapshotSelectedSecondsPerPoint))).toString()); + + // save it + // console.log(saveData); + saveObjectToClient(saveData, filename); + + if (charts_failed > 0) + alert(charts_failed.toString() + ' failed to be downloaded'); + + saveSnapshotRestore(); + saveData = null; + } + }) + }, 0); + } + + update_chart(NETDATA.options.targets.length); + }); + }); + } + + // -------------------------------------------------------------------- + // activate netdata on the page + + function dashboardSettingsSetup() { + var update_options_modal = function() { + // console.log('update_options_modal'); + + var sync_option = function(option) { + var self = $('#' + option); + + if(self.prop('checked') !== NETDATA.getOption(option)) { + // console.log('switching ' + option.toString()); + self.bootstrapToggle(NETDATA.getOption(option)?'on':'off'); + } + }; + + var theme_sync_option = function(option) { + var self = $('#' + option); + + self.bootstrapToggle(netdataTheme === 'slate'?'on':'off'); + }; + var units_sync_option = function(option) { + var self = $('#' + option); + + if(self.prop('checked') !== (NETDATA.getOption('units') === 'auto')) { + self.bootstrapToggle(NETDATA.getOption('units') === 'auto' ? 'on' : 'off'); + } + + if(self.prop('checked') === true) { + $('#settingsLocaleTempRow').show(); + $('#settingsLocaleTimeRow').show(); + } + else { + $('#settingsLocaleTempRow').hide(); + $('#settingsLocaleTimeRow').hide(); + } + }; + var temp_sync_option = function(option) { + var self = $('#' + option); + + if(self.prop('checked') !== (NETDATA.getOption('temperature') === 'celsius')) { + self.bootstrapToggle(NETDATA.getOption('temperature') === 'celsius' ? 'on' : 'off'); + } + }; + var timezone_sync_option = function(option) { + var self = $('#' + option); + + document.getElementById('browser_timezone').innerText = NETDATA.options.browser_timezone; + document.getElementById('server_timezone').innerText = NETDATA.options.server_timezone; + document.getElementById('current_timezone').innerText = (NETDATA.options.current.timezone === 'default')?'unset, using browser default':NETDATA.options.current.timezone; + + if(self.prop('checked') === NETDATA.dateTime.using_timezone) { + self.bootstrapToggle(NETDATA.dateTime.using_timezone ? 'off' : 'on'); + } + }; + + sync_option('eliminate_zero_dimensions'); + sync_option('destroy_on_hide'); + sync_option('async_on_scroll'); + sync_option('parallel_refresher'); + sync_option('concurrent_refreshes'); + sync_option('sync_selection'); + sync_option('sync_pan_and_zoom'); + sync_option('stop_updates_when_focus_is_lost'); + sync_option('smooth_plot'); + sync_option('pan_and_zoom_data_padding'); + sync_option('show_help'); + sync_option('seconds_as_time'); + theme_sync_option('netdata_theme_control'); + units_sync_option('units_conversion'); + temp_sync_option('units_temp'); + timezone_sync_option('local_timezone'); + + if(NETDATA.getOption('parallel_refresher') === false) { + $('#concurrent_refreshes_row').hide(); + } + else { + $('#concurrent_refreshes_row').show(); + } + }; + NETDATA.setOption('setOptionCallback', update_options_modal); + + // handle options changes + $('#eliminate_zero_dimensions').change(function() { NETDATA.setOption('eliminate_zero_dimensions', $(this).prop('checked')); }); + $('#destroy_on_hide').change(function() { NETDATA.setOption('destroy_on_hide', $(this).prop('checked')); }); + $('#async_on_scroll').change(function() { NETDATA.setOption('async_on_scroll', $(this).prop('checked')); }); + $('#parallel_refresher').change(function() { NETDATA.setOption('parallel_refresher', $(this).prop('checked')); }); + $('#concurrent_refreshes').change(function() { NETDATA.setOption('concurrent_refreshes', $(this).prop('checked')); }); + $('#sync_selection').change(function() { NETDATA.setOption('sync_selection', $(this).prop('checked')); }); + $('#sync_pan_and_zoom').change(function() { NETDATA.setOption('sync_pan_and_zoom', $(this).prop('checked')); }); + $('#stop_updates_when_focus_is_lost').change(function() { + urlOptions.update_always = !$(this).prop('checked'); + urlOptions.hashUpdate(); + + NETDATA.setOption('stop_updates_when_focus_is_lost', !urlOptions.update_always); + }); + $('#smooth_plot').change(function() { NETDATA.setOption('smooth_plot', $(this).prop('checked')); }); + $('#pan_and_zoom_data_padding').change(function() { NETDATA.setOption('pan_and_zoom_data_padding', $(this).prop('checked')); }); + $('#seconds_as_time').change(function() { NETDATA.setOption('seconds_as_time', $(this).prop('checked')); }); + $('#local_timezone').change(function() { + if($(this).prop('checked')) + selected_server_timezone('default', true); + else + selected_server_timezone('default', false); + }); + + + $('#units_conversion').change(function() { + NETDATA.setOption('units', $(this).prop('checked')?'auto':'original'); + }); + $('#units_temp').change(function() { + NETDATA.setOption('temperature', $(this).prop('checked')?'celsius':'fahrenheit'); + }); + + $('#show_help').change(function() { + urlOptions.help = $(this).prop('checked'); + urlOptions.hashUpdate(); + + NETDATA.setOption('show_help', urlOptions.help); + netdataReload(); + }); + + // this has to be the last + // it reloads the page + $('#netdata_theme_control').change(function() { + urlOptions.theme = $(this).prop('checked')?'slate':'white'; + urlOptions.hashUpdate(); + + if(setTheme(urlOptions.theme)) + netdataReload(); + }); + } + + function scrollDashboardTo() { + if(netdataSnapshotData !== null && typeof netdataSnapshotData.hash !== 'undefined') { + //console.log(netdataSnapshotData.hash); + scrollToId(netdataSnapshotData.hash.replace('#','')); + } + else { + // check if we have to jump to a specific section + scrollToId(urlOptions.hash.replace('#', '')); + + if (urlOptions.chart !== null) { + NETDATA.alarms.scrollToChart(urlOptions.chart); + //urlOptions.hash = '#' + NETDATA.name2id('menu_' + charts[c].menu + '_submenu_' + charts[c].submenu); + //urlOptions.hash = '#chart_' + NETDATA.name2id(urlOptions.chart); + //console.log('hash = ' + urlOptions.hash); + } + } + } + + var modalHiddenCallback = null; + function scrollToChartAfterHidingModal(chart) { + modalHiddenCallback = function() { + NETDATA.alarms.scrollToChart(chart); + }; + } + + // ---------------------------------------------------------------------------- + + function enableTooltipsAndPopovers() { + $('[data-toggle="tooltip"]').tooltip({ + animated: 'fade', + trigger: 'hover', + html: true, + delay: {show: 500, hide: 0}, + container: 'body' + }); + $('[data-toggle="popover"]').popover(); + } + + // ---------------------------------------------------------------------------- + + var runOnceOnDashboardLastRun = 0; + function runOnceOnDashboardWithjQuery() { + if(runOnceOnDashboardLastRun !== 0) { + scrollDashboardTo(); + + // restore the scrollspy at the proper position + $(document.body).scrollspy('refresh'); + $(document.body).scrollspy('process'); + + return; + } + + runOnceOnDashboardLastRun = Date.now(); + + // ------------------------------------------------------------------------ + // bootstrap modals + + // prevent bootstrap modals from scrolling the page + // maintains the current scroll position + // https://stackoverflow.com/a/34754029/4525767 + + var scrollPos = 0; + var modal_depth = 0; // how many modals are currently open + var modal_shown = false; // set to true, if a modal is shown + var netdata_paused_on_modal = false; // set to true, if the modal paused netdata + var scrollspyOffset = $(window).height() / 3; // will be updated below - the offset of scrollspy to select an item + + $('.modal') + .on('show.bs.modal', function () { + if(modal_depth === 0) { + scrollPos = window.scrollY; + + $('body').css({ + overflow: 'hidden', + position: 'fixed', + top: -scrollPos + }); + + modal_shown = true; + + if (NETDATA.options.pauseCallback === null) { + NETDATA.pause(function () {}); + netdata_paused_on_modal = true; + } + else + netdata_paused_on_modal = false; + } + + modal_depth++; + //console.log(urlOptions.after); + + }) + .on('hide.bs.modal', function () { + + modal_depth--; + + if(modal_depth <= 0) { + modal_depth = 0; + + $('body') + .css({ + overflow: '', + position: '', + top: '' + }); + + // scroll to the position we had open before the modal + $('html, body') + .animate({scrollTop: scrollPos}, 0); + + // unpause netdata, if we paused it + if (netdata_paused_on_modal === true) { + NETDATA.unpause(); + netdata_paused_on_modal = false; + } + + // restore the scrollspy at the proper position + $(document.body).scrollspy('process'); + } + //console.log(urlOptions.after); + }) + .on('hidden.bs.modal', function () { + if(modal_depth === 0) + modal_shown = false; + + if(typeof modalHiddenCallback === 'function') + modalHiddenCallback(); + + modalHiddenCallback = null; + //console.log(urlOptions.after); + }); + + // ------------------------------------------------------------------------ + // sidebar / affix + + $('#sidebar') + .affix({ + offset: { + top: (isdemo())?150:0, + bottom: 0 + } + }) + .on('affixed.bs.affix', function() { + // fix scrolling of very long affix lists + // http://stackoverflow.com/questions/21691585/bootstrap-3-1-0-affix-too-long + + $(this).removeAttr('style'); + }) + .on( 'affix-top.bs.affix', function() { + // fix bootstrap affix click bug + // https://stackoverflow.com/a/37847981/4525767 + + if(modal_shown) return false; + }) + .on('activate.bs.scrollspy', function (e) { + // change the URL based on the current position of the screen + + if(modal_shown === false) { + var el = $(e.target); + var hash = el.find('a').attr('href'); + if (typeof hash === 'string' && hash.substring(0, 1) === '#' && urlOptions.hash.startsWith(hash + '_submenu_') === false) { + urlOptions.hash = hash; + urlOptions.hashUpdate(); + } + } + }); + + Ps.initialize(document.getElementById('sidebar'), { + wheelSpeed: 0.5, + wheelPropagation: true, + swipePropagation: true, + minScrollbarLength: null, + maxScrollbarLength: null, + useBothWheelAxes: false, + suppressScrollX: true, + suppressScrollY: false, + scrollXMarginOffset: 0, + scrollYMarginOffset: 0, + theme: 'default' + }); + + + // ------------------------------------------------------------------------ + // scrollspy + + if(scrollspyOffset > 250) scrollspyOffset = 250; + if(scrollspyOffset < 75) scrollspyOffset = 75; + document.body.setAttribute('data-offset', scrollspyOffset); + + // scroll the dashboard, before activating the scrollspy, so that our + // hash will not be updated before we got the chance to scroll to it + scrollDashboardTo(); + + $(document.body).scrollspy({ + target: '#sidebar', + offset: scrollspyOffset // controls the diff of the <hX> element to the top, to select it + }); + + + // ------------------------------------------------------------------------ + // my-netdata menu + + Ps.initialize(document.getElementById('myNetdataDropdownUL'), { + wheelSpeed: 1, + wheelPropagation: false, + swipePropagation: false, + minScrollbarLength: null, + maxScrollbarLength: null, + useBothWheelAxes: false, + suppressScrollX: true, + suppressScrollY: false, + scrollXMarginOffset: 0, + scrollYMarginOffset: 0, + theme: 'default' + }); + + $('#myNetdataDropdownParent') + .on('show.bs.dropdown', function () { + var hash = urlOptions.genHash(); + $('.registry_link').each(function(idx) { + this.setAttribute('href', this.getAttribute("href").replace(/#.*$/, hash)); + }); + + NETDATA.pause(function() {}); + }) + .on('shown.bs.dropdown', function () { + Ps.update(document.getElementById('myNetdataDropdownUL')); + }) + .on('hidden.bs.dropdown', function () { + NETDATA.unpause(); + }); + + + $('#deleteRegistryModal') + .on('hidden.bs.modal', function() { + deleteRegistryGuid = null; + }); + + + // ------------------------------------------------------------------------ + // update modal + + $('#updateModal') + .on('show.bs.modal', function() { + versionLog('checking, please wait...'); + }) + .on('shown.bs.modal', function() { + notifyForUpdate(true); + }); + + + // ------------------------------------------------------------------------ + // alarms modal + + $('#alarmsModal') + .on('shown.bs.modal', function() { + alarmsUpdateModal(); + }) + .on('hidden.bs.modal', function() { + document.getElementById('alarms_active').innerHTML = + document.getElementById('alarms_all').innerHTML = + document.getElementById('alarms_log').innerHTML = + 'loading...'; + }); + + + // ------------------------------------------------------------------------ + + dashboardSettingsSetup(); + loadSnapshotDragAndDropSetup(); + saveSnapshotModalSetup(); + showPageFooter(); + + + // ------------------------------------------------------------------------ + // https://github.com/viralpatel/jquery.shorten/blob/master/src/jquery.shorten.js + + $.fn.shorten = function(settings) { + "use strict"; + + var config = { + showChars: 750, + minHideChars: 10, + ellipsesText: "...", + moreText: '<i class="fas fa-expand"></i> show more information', + lessText: '<i class="fas fa-compress"></i> show less information', + onLess: function() { NETDATA.onscroll(); }, + onMore: function() { NETDATA.onscroll(); }, + errMsg: null, + force: false + }; + + if (settings) { + $.extend(config, settings); + } + + if ($(this).data('jquery.shorten') && !config.force) { + return false; + } + $(this).data('jquery.shorten', true); + + $(document).off("click", '.morelink'); + + $(document).on({ + click: function() { + + var $this = $(this); + if ($this.hasClass('less')) { + $this.removeClass('less'); + $this.html(config.moreText); + $this.parent().prev().animate({'height':'0'+'%'}, 0, function () { $this.parent().prev().prev().show(); }).hide(0, function() { + config.onLess(); + }); + + } else { + $this.addClass('less'); + $this.html(config.lessText); + $this.parent().prev().animate({'height':'100'+'%'}, 0, function () { $this.parent().prev().prev().hide(); }).show(0, function() { + config.onMore(); + }); + } + return false; + } + }, '.morelink'); + + return this.each(function() { + var $this = $(this); + + var content = $this.html(); + var contentlen = $this.text().length; + if (contentlen > config.showChars + config.minHideChars) { + var c = content.substr(0, config.showChars); + if (c.indexOf('<') >= 0) // If there's HTML don't want to cut it + { + var inTag = false; // I'm in a tag? + var bag = ''; // Put the characters to be shown here + var countChars = 0; // Current bag size + var openTags = []; // Stack for opened tags, so I can close them later + var tagName = null; + + for (var i = 0, r = 0; r <= config.showChars; i++) { + if (content[i] === '<' && !inTag) { + inTag = true; + + // This could be "tag" or "/tag" + tagName = content.substring(i + 1, content.indexOf('>', i)); + + // If its a closing tag + if (tagName[0] === '/') { + + + if (tagName !== ('/' + openTags[0])) { + config.errMsg = 'ERROR en HTML: the top of the stack should be the tag that closes'; + } else { + openTags.shift(); // Pops the last tag from the open tag stack (the tag is closed in the retult HTML!) + } + + } else { + // There are some nasty tags that don't have a close tag like <br/> + if (tagName.toLowerCase() !== 'br') { + openTags.unshift(tagName); // Add to start the name of the tag that opens + } + } + } + if (inTag && content[i] === '>') { + inTag = false; + } + + if (inTag) { bag += content.charAt(i); } // Add tag name chars to the result + else { + r++; + if (countChars <= config.showChars) { + bag += content.charAt(i); // Fix to ie 7 not allowing you to reference string characters using the [] + countChars++; + } else // Now I have the characters needed + { + if (openTags.length > 0) // I have unclosed tags + { + //console.log('They were open tags'); + //console.log(openTags); + for (var j = 0; j < openTags.length; j++) { + //console.log('Cierro tag ' + openTags[j]); + bag += '</' + openTags[j] + '>'; // Close all tags that were opened + + // You could shift the tag from the stack to check if you end with an empty stack, that means you have closed all open tags + } + break; + } + } + } + } + c = $('<div/>').html(bag + '<span class="ellip">' + config.ellipsesText + '</span>').html(); + }else{ + c+=config.ellipsesText; + } + + var html = '<div class="shortcontent">' + c + + '</div><div class="allcontent">' + content + + '</div><span><a href="javascript://nop/" class="morelink">' + config.moreText + '</a></span>'; + + $this.html(html); + $this.find(".allcontent").hide(); // Hide all text + $('.shortcontent p:last', $this).css('margin-bottom', 0); //Remove bottom margin on last paragraph as it's likely shortened + } + }); + }; + } + + function finalizePage() { + // resize all charts - without starting the background thread + // this has to be done while NETDATA is paused + // if we ommit this, the affix menu will be wrong, since all + // the Dom elements are initially zero-sized + NETDATA.parseDom(); + + // ------------------------------------------------------------------------ + + NETDATA.globalPanAndZoom.callback = null; + NETDATA.globalChartUnderlay.callback = null; + + if(urlOptions.pan_and_zoom === true && NETDATA.options.targets.length > 0) + NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], urlOptions.after, urlOptions.before); + + // callback for us to track PanAndZoom operations + NETDATA.globalPanAndZoom.callback = urlOptions.netdataPanAndZoomCallback; + NETDATA.globalChartUnderlay.callback = urlOptions.netdataHighlightCallback; + + // ------------------------------------------------------------------------ + + // let it run (update the charts) + NETDATA.unpause(); + + runOnceOnDashboardWithjQuery(); + $(".shorten").shorten(); + enableTooltipsAndPopovers(); + + if(isdemo()) { + // do not to give errors on netdata demo servers for 60 seconds + NETDATA.options.current.retries_on_data_failures = 60; + + if(urlOptions.nowelcome !== true) { + setTimeout(function() { + $('#welcomeModal').modal(); + }, 1000); + } + + // google analytics when this is used for the home page of the demo sites + // this does not run on user's installations + setTimeout(function() { + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); + + ga('create', 'UA-64295674-3', 'auto'); + ga('send', 'pageview'); + }, 2000); + } + else notifyForUpdate(); + + if(urlOptions.show_alarms === true) + setTimeout(function() { $('#alarmsModal').modal('show'); }, 1000); + + NETDATA.onresizeCallback = function() { + Ps.update(document.getElementById('sidebar')); + Ps.update(document.getElementById('myNetdataDropdownUL')); + }; + NETDATA.onresizeCallback(); + + if(netdataSnapshotData !== null) { + NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], netdataSnapshotData.after_ms, netdataSnapshotData.before_ms); + } + + // var netdataEnded = performance.now(); + // console.log('start up time: ' + (netdataEnded - netdataStarted).toString() + ' ms'); + } + + function resetDashboardOptions() { + var help = NETDATA.options.current.show_help; + + NETDATA.resetOptions(); + if(setTheme('slate')) + netdataReload(); + + if(help !== NETDATA.options.current.show_help) + netdataReload(); + } + + // callback to add the dashboard info to the + // parallel javascript downloader in netdata + var netdataPrepCallback = function() { + NETDATA.requiredCSS.push({ + url: NETDATA.serverStatic + 'css/bootstrap-toggle-2.2.2.min.css', + isAlreadyLoaded: function() { return false; } + }); + + NETDATA.requiredJs.push({ + url: NETDATA.serverStatic + 'lib/bootstrap-toggle-2.2.2.min.js', + isAlreadyLoaded: function() { return false; } + }); + + NETDATA.requiredJs.push({ + url: NETDATA.serverStatic + 'dashboard_info.js?v20181019-1', + async: false, + isAlreadyLoaded: function() { return false; } + }); + + if(isdemo()) { + document.getElementById('masthead').style.display = 'block'; + } + else { + if(urlOptions.update_always === true) + NETDATA.setOption('stop_updates_when_focus_is_lost', !urlOptions.update_always); + } + }; + + var selected_server_timezone = function(timezone, status) { + //console.log('called with timezone: ' + timezone + ", status: " + ((typeof status === 'undefined')?'undefined':status).toString()); + + // clear the error + document.getElementById('timezone_error_message').innerHTML = ''; + + if (typeof status === 'undefined') { + // the user selected a timezone from the menu + + NETDATA.setOption('user_set_server_timezone', timezone); + + if (NETDATA.dateTime.init(timezone) === false) { + NETDATA.dateTime.init(); + + if(!$('#local_timezone').prop('checked')) + $('#local_timezone').bootstrapToggle('on'); + + document.getElementById('timezone_error_message').innerHTML = 'Ooops! That timezone was not accepted by your browser. Please open a github issue to help us fix it.'; + NETDATA.setOption('user_set_server_timezone', NETDATA.options.server_timezone); + } + else { + if($('#local_timezone').prop('checked')) + $('#local_timezone').bootstrapToggle('off'); + } + } + else if (status === true) { + // the user wants the browser default timezone to be activated + + NETDATA.dateTime.init(); + } + else { + // the user wants the server default timezone to be activated + //console.log('found ' + NETDATA.options.current.user_set_server_timezone); + + if (NETDATA.options.current.user_set_server_timezone === 'default') + NETDATA.options.current.user_set_server_timezone = NETDATA.options.server_timezone; + + timezone = NETDATA.options.current.user_set_server_timezone; + + if (NETDATA.dateTime.init(timezone) === false) { + NETDATA.dateTime.init(); + + if(!$('#local_timezone').prop('checked')) + $('#local_timezone').bootstrapToggle('on'); + + document.getElementById('timezone_error_message').innerHTML = 'Sorry. The timezone "' + timezone.toString() + '" is not accepted by your browser. Please select one from the list.'; + NETDATA.setOption('user_set_server_timezone', NETDATA.options.server_timezone); + } + } + + document.getElementById('current_timezone').innerText = (NETDATA.options.current.timezone === 'default')?'unset, using browser default':NETDATA.options.current.timezone; + return false; + }; + + // our entry point + // var netdataStarted = performance.now(); + + var netdataCallback = initializeDynamicDashboard; + </script> +</head> + +<body data-spy="scroll" data-target="#sidebar" data-offset="100"> + <div id="loadOverlay" class="loadOverlay" style="background-color: #888; color: #888;"> + netdata<br/><div style="font-size: 3vh;">Real-time performance monitoring, done right!</div> + </div> + <script type="text/javascript"> + // change the loadOverlay colors ASAP to match the theme + document.getElementById('loadOverlay').style = (urlOptions.theme === 'slate')?"background-color:#272b30; color: #373b40;":"background-color:#fff; color: #ddd;"; + </script> + <nav class="navbar navbar-default navbar-fixed-top" role="banner"> + <div class="container"> + <nav id="mynetdata_nav" class="collapse navbar-collapse navbar-left hidden-sm hidden-xs" role="navigation" style="padding-right: 20px;"> + <ul class="nav navbar-nav"> + <li class="dropdown" id="myNetdataDropdownParent" title="your other netdata servers" data-toggle="tooltip" data-placement="right"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown">my-netdata <strong class="caret"></strong></a> + <ul class="dropdown-menu scrollable-menu inpagemenu multi-column columns-2" role="menu" id="myNetdataDropdownUL"> + <div class="row"> + <div class="col-sm-6" style="width: 85%; padding-right: 0;"> + <ul id="mynetdata_servers" class="multi-column-dropdown"> + <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li> + </ul> + </div> + <div class="col-sm-3 hidden-xs" style="width: 15%; padding-left: 0;"> + <ul id="mynetdata_actions1" class="multi-column-dropdown"> + <li style="color: #999;"> </li> + </ul> + </div> + </div> + </ul> + </li> + </ul> + </nav> + <div class="navbar-header"> + <button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".navbar-collapse"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a href="/" class="navbar-brand" id="hostname" title="server hostname<br/>click it to reload the dashboard" data-toggle="tooltip" data-placement="bottom">netdata</a> + </div> + <nav class="collapse navbar-collapse navbar-right" role="navigation"> + <ul class="nav navbar-nav"> + <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> <span class="hidden-sm hidden-md">Alarms </span><span id="alarms_count_badge" class="badge"></span></a></li> + <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> <span class="hidden-sm hidden-md">Settings</span></a></li> + <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> + <li title="the netdata wiki home at github<br/>remember to <b>give netdata a <i class="fas fa-star"></i></b> !" data-toggle="tooltip" data-placement="bottom" class="hidden-sm hidden-md"><a href="https://github.com/netdata/netdata/wiki" class="btn" target="_blank"><i class="fab fa-github"></i></a></li> + <li title="follow netdata on twitter" data-toggle="tooltip" data-placement="bottom" class="hidden-sm hidden-md"><a href="https://twitter.com/linuxnetdata" class="btn" target="_blank"><i class="fab fa-twitter"></i></a></li> + <li title="like netdata on facebook" data-toggle="tooltip" data-placement="bottom" class="hidden-sm hidden-md"><a href="https://www.facebook.com/linuxnetdata/" class="btn" target="_blank"><i class="fab fa-facebook"></i></a></li> + <li title="import / load a netdata snapshot" data-toggle="tooltip" data-placement="bottom" id="loadButton"><a href="#" class="btn" data-toggle="modal" data-target="#loadSnapshotModal"><i class="fas fa-download"></i> <span class="hidden-sm hidden-md hidden-lg">Import</span></a></li> + <li title="export / save a netdata snapshot" data-toggle="tooltip" data-placement="bottom" id="saveButton"><a href="#" class="btn" data-toggle="modal" data-target="#saveSnapshotModal"><i class="fas fa-upload"></i> <span class="hidden-sm hidden-md hidden-lg">Export</span></a></li> + <li title="print this dashboard to PDF" data-toggle="tooltip" data-placement="bottom" id="printButton"><a href="#" class="btn" data-toggle="modal" data-target="#printPreflightModal"><i class="fas fa-print"></i> <span class="hidden-sm hidden-md hidden-lg">Print</span></a></li> + <li title="get help on using the charts" data-toggle="tooltip" data-placement="bottom" class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#helpModal"><i class="fas fa-question-circle"></i> <span class="hidden-sm hidden-md">Help</span></a></li> + <li class="dropdown hidden-sm hidden-md hidden-lg"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown">my-netdata <strong class="caret"></strong></a> + <ul id="mynetdata_servers2" class="dropdown-menu scrollable-menu inpagemenu" role="menu"> + <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li> + </ul> + </li> + </ul> + </nav> + </div> + </nav> + <div class="navbar-highlight"> + <div id="navbar-highlight-content" class="navbar-highlight-content"></div> + </div> + + <div id="masthead" style="display: none;"> + <div class="container"> + <div class="row"> + <div class="col-md-7"> + <h1>Netdata + <p class="lead">Real-time performance monitoring, in the greatest possible detail</p> + </h1> + </div> + <div class="col-md-5"> + <div class="well well-lg"> + <div class="row"> + <div class="col-md-6"> + <b>Drag</b> charts to pan. + <b>Shift + wheel</b> on them, to zoom in and out. + <b>Double-click</b> on them, to reset. + <b>Hover</b> on them too! + </div> + <div class="col-md-6"> + <div class="netdata-container" data-netdata="system.intr" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-dygraph-type="line" data-dygraph-strokewidth="3" data-dygraph-smooth="true" data-dygraph-highlightcirclesize="6" data-after="-90" data-height="60px" data-colors="#C66"></div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + + <div class="container"> + <div class="row"> + <div class="charts-body" role="main"> + <div id="charts_div"></div> + </div> + <div class="sidebar-body hidden-xs hidden-sm hidden-print" id="sidebar-body" role="complementary"> + <nav class="dashboard-sidebar hidden-print hidden-xs hidden-sm" id="sidebar" role="menu"></nav> + </div> + </div> + </div> + + <div id="footer" class="container" style="display: none;"> + <div class="row"> + <div class="col-md-10" role="main"> + <div class="p"> + <big><a href="https://github.com/netdata/netdata/wiki" target="_blank">netdata</a></big><br/> + <i class="fas fa-copyright"></i> Copyright 2016-2018, <a href="mailto:costa@tsaousis.gr">Costa Tsaousis</a>.<br/> + Released under <a href="http://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GPL v3 or later</a>.<br/> + </div> + <div class="p"> + <small> + <a href="https://github.com/netdata/netdata/wiki" target="_blank">netdata</a> uses the following third party tools on this dashboard: + + <i class="fas fa-circle"></i> The excellent <a href="http://dygraphs.com/" target="_blank">Dygraphs.com</a> web chart library, + <i class="fas fa-copyright"></i> Copyright 2009, Dan Vanderkam, <a href="http://dygraphs.com/legal.html" target="_blank">MIT License</a> + + <i class="fas fa-circle"></i> <a href="https://rendro.github.io/easy-pie-chart/" target="_blank">Easy Pie Chart</a> web chart library, + <i class="fas fa-copyright"></i> Copyright 2013, Robert Fleischmann, <a href="https://github.com/rendro/easy-pie-chart/blob/master/LICENSE" target="_blank">MIT License</a> + + <i class="fas fa-circle"></i> <a href="http://bernii.github.io/gauge.js/" target="_blank">Gauge.js</a> web chart library, + <i class="fas fa-copyright"></i> Copyright, Bernard Kobos, <a href="http://bernii.github.io/gauge.js/" target="_blank">MIT License</a> + + <i class="fas fa-circle"></i> <a href="https://github.com/benkeen/d3pie" target="_blank">d3pie</a> web chart library, + <i class="fas fa-copyright"></i> Copyright 2014-2015 Benjamin Keen, <a href="https://github.com/benkeen/d3pie/blob/master/LICENSE" target="_blank">MIT License</a> + + <i class="fas fa-circle"></i> <a href="http://d3js.org/" target="_blank">D3</a> web graphics library, + <i class="fas fa-copyright"></i> Copyright 2015 Mike Bostock, <a href="http://opensource.org/licenses/BSD-3-Clause" target="_blank">BSD License</a> + + <i class="fas fa-circle"></i> <a href="https://jquery.org/" target="_blank">jQuery</a>, + <i class="fas fa-copyright"></i> Copyright 2015, jQuery Foundation, <a href="https://jquery.org/license/" target="_blank">MIT License</a> + + <i class="fas fa-circle"></i> <a href="http://getbootstrap.com/getting-started/" target="_blank">Bootstrap</a>, + <i class="fas fa-copyright"></i> Copyright 2015, Twitter, <a href="http://getbootstrap.com/getting-started/#license-faqs" target="_blank">MIT License</a> + + <i class="fas fa-circle"></i> <a href="http://www.bootstraptoggle.com/" target="_blank">Bootstrap Toggle</a>, + <i class="fas fa-copyright"></i> Copyright 2011-2014 Min Hur, The New York Times Company, <a href="https://github.com/minhur/bootstrap-toggle/blob/master/LICENSE" target="_blank">MIT License</a> + + <i class="fas fa-circle"></i> <a href="http://seiyria.com/bootstrap-slider/" target="_blank">Bootstrap-slider</a>, + <i class="fas fa-copyright"></i> Copyright 2017 Kyle Kemp, Rohit Kalkur, and contributors, <a href="https://github.com/seiyria/bootstrap-slider/blob/master/LICENSE.md" target="_blank">MIT License</a> + + <i class="fas fa-circle"></i> <a href="https://github.com/noraesae/perfect-scrollbar" target="_blank">perfect-scrollbar</a>, + <i class="fas fa-copyright"></i> Copyright 2016, Hyunje Alex Jun and other contributors, <a href="https://github.com/noraesae/perfect-scrollbar/blob/master/LICENSE" target="_blank">MIT License</a> + + <i class="fas fa-circle"></i> <a href="https://fortawesome.github.io/Font-Awesome/" target="_blank">FontAwesome</a>, + <i class="fas fa-copyright"></i> Created by Dave Gandy, Font: <a href="http://scripts.sil.org/OFL" target="_blank">SIL OFL 1.1 License</a>, CSS: <a href="http://opensource.org/licenses/mit-license.html" target="_blank">MIT License</a> + + <i class="fas fa-circle"></i> <a href="http://www.iconsdb.com/soylent-red-icons/seo-performance-icon.html" target="_blank">IconsDB.com Icons</a>, Icons provided as CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. + + <i class="fas fa-circle"></i> <a href="http://bootstrap-table.wenzhixin.net.cn/" target="_blank">bootstrap-table</a>, + <i class="fas fa-copyright"></i> Copyright 2012-2016 Zhixin Wen, <a href="https://github.com/wenzhixin/bootstrap-table/blob/master/LICENSE" target="_blank">MIT License</a> + + <i class="fas fa-circle"></i> <a href="https://github.com/hhurz/tableExport.jquery.plugin" target="_blank">tableExport.jquery.plugin</a>, + <i class="fas fa-copyright"></i> Copyright 2015,2016 hhurz, <a href="http://rawgit.com/hhurz/tableExport.jquery.plugin/master/tableExport.js" target="_blank">MIT License</a> + + </small> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="xssModal" tabindex="-1" role="dialog" aria-labelledby="xssModalLabel" data-keyboard="false" data-backdrop="static" style="z-index: 3000"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title" id="xssModalLabel">XSS Protection</h4> + </div> + <div class="modal-body"> + <p> + This dashboard is about to render data from server: + </p> + <p style="font-size: 1.25em;"> + <code id="netdataXssModalServer"></code> + </p> + <p> + To protect your privacy, the dashboard will <b>check all data transferred</b> for cross site scripting (XSS). + <br/>This is CPU intensive, so your browser might be a bit slower. + </p> + <p> + If you <b>trust</b> the remote server, you can disable XSS protection.<br/> + In this case, any remote dashboard decoration code (javascript) will also run. + </p> + <p> + If you <b>don't trust</b> the remote server, you should keep the protection on.<br/> + The dashboard will run slower and remote dashboard decoration code will not run, but better be safe than sorry... + </p> + </div> + <div class="modal-footer"> + <a href="#" onclick="return xssModalKeepXss();" type="button" class="btn btn-success" data-dismiss="modal">Keep protecting me</a> + <a href="#" onclick="return xssModalDisableXss();" type="button" class="btn btn-danger" data-dismiss="modal">I don't need this, the server is mine</a> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="printPreflightModal" tabindex="-1" role="dialog" aria-labelledby="printPreflightModalLabel"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="printPreflightModalLabel">Print this netdata dashboard</h4> + </div> + <div class="modal-body"> + <p> + netdata dashboards cannot be captured, since we are lazy loading and hiding all but the visible charts. + <br/> + To capture the whole page with all the charts rendered, a new browser window will pop-up that will render all the charts at once. + The new browser window will maintain the current pan and zoom settings of the charts. So, align the charts before proceeding. + </p> + <p> + <small> + This process will put some CPU and memory pressure on your browser.<br/> + For the netdata server, we will sequencially download all the charts, to avoid congesting network and server resources.<br/> + <b>Please, do not print netdata dashboards on paper!</b> + </small> + </p> + </div> + <div class="modal-footer"> + <a href="#" onclick="printPreflight(); return false;" type="button" class="btn btn-default">Print</a> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="printModal" tabindex="-1" role="dialog" aria-labelledby="printModalLabel" data-keyboard="false" data-backdrop="static"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="printModalLabel">Preparing dashboard for printing...</h4> + </div> + <div class="modal-body"> + Please wait while we initialize and render all the charts on the dashboard. + <div class="progress progress-striped active" style="height: 2em !important;"> + <div id="printModalProgressBar" class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="min-width: 2em;"> + <span id="printModalProgressBarText" style="padding-left: 10px; padding-top: 4px; font-size: 1.2em; text-align: left; width: 100%; position: absolute; display: block; color: black;"></span> + </div> + </div> + The print dialog will appear as soon as we finish rendering the page. + </div> + <div class="modal-footer"> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="loadSnapshotModal" tabindex="-1" role="dialog" aria-labelledby="loadSnapshotModalLabel"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="loadSnapshotModalLabel">Import a netdata snapshot</h4> + </div> + <div id="loadSnapshotDragAndDrop" class="modal-body"> + <p> + netdata can export and import dashboard snapshots. + Any netdata can import the snapshot of any other netdata. + The snapshots are not uploaded to a server. They are handled entirely by your web browser, on your computer. + </p> + <p style="text-align: center;"> + <label class="btn btn-default"> + Click here to select the netdata snapshot file to import + <input type="file" id="loadSnapshotSelectFiles" value="Import" style="display: none;" + onchange="loadSnapshotPreflight();"> + </label> + </p> + <div id="loadSnapshotStatus" class="alert alert-info" role="alert"> + Browse for a snapshot file (or drag it and drop it here), then click <b>Import</b> to render it. + </div> + <p> + <table class="table"> + <tbody> + <tr><th>Filename</th><td id="loadSnapshotFilename"></td></tr> + <tr><th>Hostname</th><td id="loadSnapshotHostname"></td></tr> + <tr><th>Origin URL</th><td id="loadSnapshotURL"></td></tr> + <tr><th>Charts Info</th><td id="loadSnapshotCharts"></td></tr> + <tr><th>Snapshot Info</th><td id="loadSnapshotInfo"></td></tr> + <tr><th>Time Range</th><td id="loadSnapshotTimeRange"></td></tr> + <tr><th>Comments</th><td id="loadSnapshotComments"></td></tr> + </tbody> + </table> + </p> + </div> + <div class="modal-footer"> + <span style="display: inline-block; padding-right: 20px;">Snapshot files contain both data and javascript code. Make sure <b>you trust the files</b> you import!</span> + <a id="loadSnapshotImport" href="#" onclick="loadSnapshot(); return false;" type="button" class="btn btn-success disabled">Import</a> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="saveSnapshotModal" tabindex="-1" role="dialog" aria-labelledby="saveSnapshotModalLabel" data-keyboard="false" data-backdrop="static"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="saveSnapshotModalLabel">Export a snapshot</h4> + </div> + <div class="modal-body"> + <div id="saveSnapshotModalProgressSection" hidden> + Please wait while we collect all the dashboard data... + <div class="progress progress-striped active" style="height: 2em !important;"> + <div id="saveSnapshotModalProgressBar" class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="min-width: 2em;"> + <span id="saveSnapshotModalProgressBarText" style="padding-left: 10px; padding-top: 4px; font-size: 1.2em; text-align: left; width: 100%; position: absolute; display: block;"></span> + </div> + </div> + </div> + + <div id="saveSnapshotResolutionRadio" style="text-align: center;"> + Select the desired resolution of the snapshot. This is the <b>seconds of data per point</b>. + <br/> + + <br/> + + <br/> + <input id="saveSnapshotResolutionSlider" data-slider-id='saveSnapshotResolutionSlider' type="text" style="width: 80%;" tabindex="0"/> + <br/> <br/> + <div class="input-group"> + <span class="input-group-addon" id="sizing-saveSnapshotFilename" style="width: 100px;">Filename</span> + <input id="saveSnapshotFilename" class="form-control" placeholder="Filename of the generated snapshot" aria-describedby="sizing-saveSnapshotFilename" tabindex="2"/> + <div class="input-group-btn"> + <div class="input-group-btn"> + <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span id="saveSnapshotCompressionName">Compression</span> <span class="caret"></span></button> + <ul class="dropdown-menu dropdown-menu-right"> + <li class="disabled"><a href="#" class="disabled">Select Compression</a></li> + <li role="separator" class="divider"></li> + <li><a href="#" onclick="saveSnapshotSetCompression('none'); return false;">uncompressed</a></li> + <li role="separator" class="divider"></li> + <li><a href="#" onclick="saveSnapshotSetCompression('pako.deflate'); return false;">pako.deflate (gzip, binary)</a></li> + <li><a href="#" onclick="saveSnapshotSetCompression('pako.deflate.base64'); return false;">pako.deflate.base64 (gzip, ascii)</a></li> + <li role="separator" class="divider"></li> + <li><a href="#" onclick="saveSnapshotSetCompression('lzstring.uri'); return false;">lzstring.uri (LZ, ascii)</a></li> + <li><a href="#" onclick="saveSnapshotSetCompression('lzstring.utf16'); return false;">lzstring.utf16 (LZ, utf16)</a></li> + <li><a href="#" onclick="saveSnapshotSetCompression('lzstring.base64'); return false;">lzstring.base64 (LZ, ascii)</a></li> + </ul> + </div><!-- /btn-group --> + </div> + </div> + <div class="input-group" style="padding-top: 10px; width: 100%"> + <span class="input-group-addon" id="sizing-saveSnapshotComments" style="width: 100px;">Comments</span> + <input id="saveSnapshotComments" class="form-control" placeholder="Any comments about this snapshot?" aria-describedby="sizing-saveSnapshotComments" tabindex="3"/> + </div> + </div> + + + <div id="saveSnapshotStatus" class="alert alert-info" role="alert"> + Select snaphost resolution. This controls the size the snapshot file. + </div> + <p> + The generated snapshot will include all charts of this dashboard, <b>for the visible timeframe</b>, so align, pan and zoom the charts as needed. + The scroll position of the dashboard will also be saved. + The snapshot will be downloaded as a file, to your computer, that can be imported back into any netdata dashboard (no need to import it back on this server). + </p> + <p> + <small> + Snapshot files include all the information of the dashboard, including the URL of the origin server, its netdata unique ID, etc. + So, if you share the snapshot file with third parties, they will be able to access the origin server, if this server is exposed on the internet. + <br/> + Snapshots are handled entirely by the web browser. The netdata servers are not aware of them. + </small> + </p> + </div> + <div class="modal-footer"> + <a id="saveSnapshotExport" href="#" onclick="saveSnapshot(); return false;" type="button" class="btn btn-success" tabindex="4">Export</a> + <button type="button" class="btn btn-default" data-dismiss="modal" tabindex="5">Cancel</button> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="welcomeModal" tabindex="-1" role="dialog" aria-labelledby="welcomeModalLabel"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="welcomeModalLabel">Welcome to the world of netdata</h4> + </div> + <div class="modal-body"> + <div class="p"> + <div style="width: 100%; text-align: center; padding-top: 10px; padding-bottom: 10px; font-size: 18px;"> + if there is a metric for something, we want it visualised<br/> + and we want this visualisation to be <strong>real-time</strong>, <strong>efficient</strong> and <strong>awesome</strong> + </div> + </div> + <div class="p"> + <b><a href="https://github.com/netdata/netdata/wiki" target="_blank">netdata</a></b> + is a new way to monitor your systems and applications, to get <strong>real-time insights</strong> + of what is really happening and what affects performance. + It is carefully optimised to be a real-time system, without interfering in any way, + to the core function of your systems. + </div> + <div class="p"> + <b><a href="https://github.com/netdata/netdata/wiki" target="_blank">netdata</a></b> + has been designed to monitor <strong>massive amounts of metrics, per server, per second</strong>. + When installed, it might come up with 1k to 3k metrics, but we have been testing it with 100k + metrics, all collected per second, and still the cpu utilisation remained negligible. + <br/> + We have also tried to give each metric, a meaning, a context. + We have grouped and categorized all metrics into meaningful charts, providing a + better understanding of the underlying technologies and mechanisms. + </div> + <div class="p"> + <b><a href="https://github.com/netdata/netdata/wiki" target="_blank">netdata</a></b> is free, + open-source software. If you decide to use it, + <strong><a href="https://github.com/netdata/netdata/wiki/a-github-star-is-important" target="_blank">it is important to give netdata a star at GitHub</a></strong>. + </div> + <div class="p"> + Enjoy real-time performance monitoring! + </div> + <div class="p"> + Costa Tsaousis + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="helpModal" tabindex="-1" role="dialog" aria-labelledby="helpModalLabel"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="helpModalLabel">Dashboard Help</h4> + </div> + <div class="modal-body"> + + <h4>Dygraphs (line, area and stacked area charts)</h4> + + <!-- Nav tabs --> + <ul class="nav nav-tabs" role="tablist"> + <li role="presentation" class="active"><a href="#help_mouse" aria-controls="help_mouse" role="tab" data-toggle="tab">Mouse Interface</a></li> + <li role="presentation"><a href="#help_touch" aria-controls="help_touch" role="tab" data-toggle="tab">Touch Interface</a></li> + </ul> + + <!-- Tab panes --> + <div class="tab-content"> + <div role="tabpanel" class="tab-pane active" id="help_mouse"> + <div class="p"> + <h4>Mouse Over / Hover</h4> + Mouse over on a chart to show, at its legend, the values for the timestamp under the mouse (the chart will also highlight the point at the chart). + <br/> + All the other visible charts will also show and highlight their values for the same timestamp. + </div> + <hr/> + <div class="p"> + <h4>Drag Chart Contents</h4> + Drag the contents of a chart, by pressing the left mouse button and moving the mouse, to pan it horizontally. + <br/> + All the charts will follow soon after you let the chart alone (this little delay is by design: it speeds up your browser and lets you focus on what you are exploring). + <br/> + Once a chart is panned, auto refreshing stops for all charts. To enable it again, <b>double click</b> a panned chart. + </div> + <hr/> + <div class="p"> + <h4>Double Click</h4> + Double Click a chart to reset all the charts to their default auto-refreshing state. + </div> + <hr/> + <div class="p"> + <h4>SHIFT + Drag</h4> + While pressing the <code>SHIFT</code> key, press the left mouse button on the contents of a chart and move the mouse to select an area, to zoom in. The other charts will follow too. Zooming is performed in two phases: + <ul> + <li>The already loaded chart contents are zoomed (low resolution)</li> + <li>New data are transferred from the netdata server, to refresh the chart with possibly more detail.</li> + </ul> + Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart. + </div> + <hr/> + <div class="p"> + <h4>Highlight Timeframe</h4> + While pressing the <code>ALT</code> key, press the left mouse button on the contents of a chart and move the mouse to select an area. The selected are will be highlighted on all charts. + </div> + <hr/> + <div class="p"> + <h4>SHIFT + Mouse Wheel</h4> + While pressing the <code>SHIFT</code> key and the mouse pointer is over the contents of a chart, scroll the mouse wheel to zoom in or out. This kind of zooming is aligned to center below the mouse pointer. The other charts will follow too. + <br/> + Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart. + </div> + <hr/> + <div class="p"> + <h4>Legend Operations</h4> + Click on the label or value of a dimension, will select / un-select this dimension. + <br/> + You can press any of the SHIFT or CONTROL keys and then click on legend labels or values, to select / un-select multiple dimensions. + </div> + </div> + <div role="tabpanel" class="tab-pane" id="help_touch"> + <div class="p"> + <h4>Single Tap</h4> + Single Tap on the contents of a chart to show, at its legend, the values for the timestamp tapped (the chart will also highlight the point at the chart). + <br/> + All the other visible charts will also show and highlight their values for the same timestamp. + </div> + <hr/> + <div class="p"> + <h4>Drag Chart Contents</h4> + Touch and Drag the contents of a chart to pan it horizontally. + <br/> + All the charts will follow soon after you let the chart alone (this little delay is by design: it speeds up your browser and lets you focus on what you are exploring). + <br/> + Once a chart is panned, auto refreshing stops for all charts. To enable it again, <b>double tap</b> a panned chart. + </div> + <hr/> + <div class="p"> + <h4>Double Tap</h4> + Double tap a chart to reset all the charts to their default auto-refreshing state. + </div> + <hr/> + <div class="p"> + <h4>Zoom <small>(does not work on firefox and IE/Edge)</small></h4> + With two fingers, zoom in or out. + <br/> + Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart. + </div> + <hr/> + <div class="p"> + <h4>Legend Operations</h4> + Tap on the label or value of a dimension, will select / un-select this dimension. + </div> + </div> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="alarmsModal" tabindex="-1" role="dialog" aria-labelledby="alarmsModalLabel"> + <div class="modal-dialog modal-lg" role="document" style="display: table;"> <!-- allow the modal to expand horizontally --> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="alarmsModalLabel">netdata alarms</h4> + </div> + <div class="modal-body"> + <!-- Nav tabs --> + <ul class="nav nav-tabs" role="tablist"> + <li role="presentation" class="active"><a href="#alarms_active" aria-controls="alarms_active" role="tab" data-toggle="tab">Active</a></li> + <li role="presentation"><a href="#alarms_all" aria-controls="alarms_all" role="tab" data-toggle="tab">All</a></li> + <li role="presentation"><a href="#alarms_log" aria-controls="alarms_log" role="tab" data-toggle="tab">Log</a></li> + </ul> + + <!-- Tab panes --> + <div class="tab-content"> + <div role="tabpanel" class="tab-pane active" id="alarms_active"> + loading... + </div> + <div role="tabpanel" class="tab-pane" id="alarms_all"> + loading... + </div> + <div role="tabpanel" class="tab-pane" id="alarms_log"> + loading... + </div> + </div> + </div> + <div class="modal-footer"> + <!-- <a href="#" onclick="alarmsUpdateModal(); return false;" type="button" class="btn btn-default">Update</a> --> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="optionsModal" tabindex="-1" role="dialog" aria-labelledby="optionsModalLabel"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="optionsModalLabel">netdata dashboard options</h4> + </div> + <div class="modal-body"> + <center> + <small style="color: #BBBBBB;">These are browser settings. Each viewer has its own. They do not affect the operation of your netdata server. + <br/> + Settings take effect immediately and are saved permanently to browser local storage (except the refresh on focus / always option). + <br/> + To reset all options (including charts sizes) to their defaults, click <a href="#" onclick="resetDashboardOptions(); return false;">here</a>.</small> + </center> + <div style="padding: 10px;"></div> + + <!-- Nav tabs --> + <ul class="nav nav-tabs" role="tablist"> + <li role="presentation" class="active"><a href="#settings_performance" aria-controls="settings_performance" role="tab" data-toggle="tab">Performance</a></li> + <li role="presentation"><a href="#settings_sync" aria-controls="settings_sync" role="tab" data-toggle="tab">Synchronization</a></li> + <li role="presentation"><a href="#settings_visual" aria-controls="settings_visual" role="tab" data-toggle="tab">Visual</a></li> + <li role="presentation"><a href="#settings_locale" aria-controls="settings_locale" role="tab" data-toggle="tab">Locale</a></li> + </ul> + + <!-- Tab panes --> + <div class="tab-content"> + <div role="tabpanel" class="tab-pane active" id="settings_performance"> + <form id="optionsForm1" method="get" class="form-horizontal"> + <div class="form-group"> + <table> + <tr class="option-row"> + <td class="option-control"><input id="stop_updates_when_focus_is_lost" type="checkbox" checked data-toggle="toggle" data-offstyle="danger" data-onstyle="success" data-on="On Focus" data-off="Always" data-width="110px"></td> + <td class="option-info"><strong>When to refresh the charts?</strong><br/> + <small>When set to <b>On Focus</b>, the charts will stop being updated if the page / tab does not have the focus of the user. When set to <b>Always</b>, the charts will always be refreshed. Set it to <b>On Focus</b> it to lower the CPU requirements of the browser (and extend the battery of laptops and tablets) when this page does not have your focus. Set to <b>Always</b> to work on another window (i.e. change the settings of something) and have the charts auto-refresh in this window.</small> + </td> + </tr> + <tr class="option-row"> + <td class="option-control"> + <input id="eliminate_zero_dimensions" type="checkbox" checked data-toggle="toggle" data-on="Non Zero" data-off="All" data-width="110px"> + </td> + <td class="option-info"><strong>Which dimensions to show?</strong><br/> + <small>When set to <b>Non Zero</b>, dimensions that have all their values (within the current view) set to zero will not be transferred from the netdata server (except if all dimensions of the chart are zero, in which case this setting does nothing - all dimensions are transferred and shown). When set to <b>All</b>, all dimensions will always be shown. Set it to <b>Non Zero</b> to lower the data transferred between netdata and your browser, lower the CPU requirements of your browser (fewer lines to draw) and increase the focus on the legends (fewer entries at the legends).</small> + </td> + </tr> + <tr class="option-row"> + <td class="option-control"><input id="destroy_on_hide" type="checkbox" data-toggle="toggle" data-on="Destroy" data-off="Hide" data-width="110px"></td> + <td class="option-info"><strong>How to handle hidden charts?</strong><br/> + <small>When set to <b>Destroy</b>, charts that are not in the current viewport of the browser (are above, or below the visible area of the page), will be destroyed and re-created if and when they become visible again. When set to <b>Hide</b>, the not-visible charts will be just hidden, to simplify the DOM and speed up your browser. Set it to <b>Destroy</b>, to lower the memory requirements of your browser. Set it to <b>Hide</b> for faster restoration of charts on page scrolling.</small> + </td> + </tr> + <tr class="option-row"> + <td class="option-control"><input id="async_on_scroll" type="checkbox" data-toggle="toggle" data-on="Async" data-off="Sync" data-width="110px"></td> + <td class="option-info"><strong>Page scroll handling?</strong><br/> + <small>When set to <b>Sync</b>, charts will be examined for their visibility immediately after scrolling. On slow computers this may impact the smoothness of page scrolling. To update the page when scrolling ends, set it to <b>Async</b>. Set it to <b>Sync</b> for immediate chart updates when scrolling. Set it to <b>Async</b> for smoother page scrolling on slower computers.</small> + </td> + </tr> + </table> + </div> + </form> + </div> + <div role="tabpanel" class="tab-pane" id="settings_sync"> + <form id="optionsForm2" method="get" class="form-horizontal"> + <div class="form-group"> + <table> + <tr class="option-row"> + <td class="option-control"><input id="parallel_refresher" type="checkbox" checked data-toggle="toggle" data-on="Parallel" data-off="Sequential" data-width="110px"></td> + <td class="option-info"><strong>Which chart refresh policy to use?</strong><br/> + <small>When set to <b>parallel</b>, visible charts are refreshed in parallel (all queries are sent to netdata server in parallel) and are rendered asynchronously. When set to <b>sequential</b> charts are refreshed one after another. Set it to parallel if your browser can cope with it (most modern browsers do), set it to sequential if you work on an older/slower computer.</small> + </td> + </tr> + <tr class="option-row" id="concurrent_refreshes_row"> + <td class="option-control"><input id="concurrent_refreshes" type="checkbox" checked data-toggle="toggle" data-on="Resync" data-off="Best Effort" data-width="110px"></td> + <td class="option-info"><strong>Shall we re-sync chart refreshes?</strong><br/> + <small>When set to <b>Resync</b>, the dashboard will attempt to re-synchronize all the charts so that they are refreshed concurrently. When set to <b>Best Effort</b>, each chart may be refreshed with a little time difference to the others. Normally, the dashboard starts refreshing them in parallel, but depending on the speed of your computer and the network latencies, charts start having a slight time difference. Setting this to <b>Resync</b> will attempt to re-synchronize the charts on every update. Setting it to <b>Best Effort</b> may lower the pressure on your browser and the network.</small> + </td> + </tr> + <tr class="option-row"> + <td class="option-control"><input id="sync_selection" type="checkbox" checked data-toggle="toggle" data-on="Sync" data-off="Don't Sync" data-onstyle="success" data-offstyle="danger" data-width="110px"></td> + <td class="option-info"><strong>Sync hover selection on all charts?</strong><br/> + <small>When enabled, a selection on one chart will automatically select the same time on all other visible charts and the legends of all visible charts will be updated to show the selected values. When disabled, only the chart getting the user's attention will be selected. Enable it to get better insights of the data. Disable it if you are on a very slow computer that cannot actually do it.</small> + </td> + </tr> + <tr class="option-row"> + <td class="option-control"><input id="sync_pan_and_zoom" type="checkbox" checked data-toggle="toggle" data-on="Sync" data-off="Don't Sync" data-onstyle="success" data-offstyle="danger" data-width="110px"></td> + <td class="option-info"><strong>Sync pan and zoom on all charts?</strong><br/> + <small>When enabled, pan and zoom operations on a chart will be replicated to all charts (even the ones that are not currently visible - of course only when they will become visible). When disabled, pan and zoom operations will not be propagated to other charts.</small> + </td> + </tr> + </table> + </div> + </form> + </div> + <div role="tabpanel" class="tab-pane" id="settings_visual"> + <form id="optionsForm3" method="get" class="form-horizontal"> + <div class="form-group"> + <table> + <tr class="option-row"> + <td class="option-control"><input id="netdata_theme_control" type="checkbox" checked data-toggle="toggle" data-offstyle="danger" data-onstyle="success" data-on="Dark" data-off="White" data-width="110px"></td> + <td class="option-info"><strong>Which theme to use?</strong><br/> + <small>Netdata comes with two themes: <b>Dark</b> (the default) and <b>White</b>. + <br/> + <b>Switching this will reload the dashboard</b>. + </small> + </td> + </tr> + <tr class="option-row"> + <td class="option-control"><input id="show_help" type="checkbox" checked data-toggle="toggle" data-on="Help Me" data-off="No Help" data-width="110px"></td> + <td class="option-info"><strong>Do you need help?</strong><br/> + <small>Netdata can show some help in some areas to help you use the dashboard. If all these balloons bother you, disable them using this switch. + <br/> + <b>Switching this will reload the dashboard</b>. + </small> + </td> + </tr> + <tr class="option-row"> + <td class="option-control"><input id="pan_and_zoom_data_padding" type="checkbox" checked data-toggle="toggle" data-on="Pad" data-off="Don't Pad" data-width="110px"></td> + <td class="option-info"><strong>Enable data padding when panning and zooming?</strong><br/> + <small>When set to <b>Pad</b> the charts will be padded with more data, both before and after the visible area, thus giving the impression the whole database is loaded. This padding will happen only after the first pan or zoom operation on the chart (initially all charts have only the visible data). When set to <b>Don't Pad</b> only the visible data will be transfered from the netdata server, even after the first pan and zoom operation.</small> + </td> + </tr> + <tr class="option-row"> + <td class="option-control"><input id="smooth_plot" type="checkbox" checked data-toggle="toggle" data-on="Smooth" data-off="Rough" data-width="110px"></td> + <td class="option-info"><strong>Enable Bézier lines on charts?</strong><br/> + <small>When set to <b>Smooth</b> the charts libraries that support it, will plot smooth curves instead of simple straight lines to connect the points. + <br/> + Keep in mind <a href="http://dygraphs.com" target="_blank">dygraphs</a>, the main charting library in netdata dashboards, can only smooth line charts. It cannot smooth area or stacked charts. When set to <b>Rough</b>, this setting can lower the CPU resources consumed by your browser.</small> + </td> + </tr> + </table> + </div> + </form> + </div> + <div role="tabpanel" class="tab-pane" id="settings_locale"> + <form id="optionsForm4" method="get" class="form-horizontal"> + <div class="form-group"> + <table> + <tr class="option-row"> + <td colspan="2" align="center"> + <small> + <b>These settings are applied gradually, as charts are updated. To force them, refresh the dashboard now</b>. + </small> + </td> + </tr> + <tr class="option-row"> + <td class="option-control"><input id="units_conversion" type="checkbox" checked data-toggle="toggle" data-on="Scale Units" data-off="Fixed Units" data-onstyle="success" data-width="110px"></td> + <td class="option-info"><strong>Enable auto-scaling of select units?</strong><br/> + <small>When set to <b>Scale Units</b> the values shown will dynamically be scaled (e.g. 1000 kilobits will be shown as 1 megabit). + Netdata can auto-scale these original units: <code>kilobits/s</code>, <code>kilobytes/s</code>, <code>KB/s</code>, + <code>KB</code>, <code>MB</code>, and <code>GB</code>. + When set to <b>Fixed Units</b> all the values will be rendered using the original units maintained by the netdata server. + </small> + </td> + </tr> + <tr id="settingsLocaleTempRow" class="option-row"> + <td class="option-control"><input id="units_temp" type="checkbox" checked data-toggle="toggle" data-on="Celsius" data-off="Fahrenheit" data-width="110px"></td> + <td class="option-info"><strong>Which units to use for temperatures?</strong><br/> + <small>Set the temperature units of the dashboard. + </small> + </td> + </tr> + <tr id="settingsLocaleTimeRow" class="option-row"> + <td class="option-control"><input id="seconds_as_time" type="checkbox" checked data-toggle="toggle" data-on="Time" data-off="Seconds" data-onstyle="success" data-width="110px"></td> + <td class="option-info"><strong>Convert seconds to time?</strong><br/> + <small>When set to <b>Time</b>, charts that present <code>seconds</code> will show <code>DDd:HH:MM:SS</code>. + When set to <b>Seconds</b>, the raw number of seconds will be presented. + </small> + </td> + </tr> + <tr class="option-row"> + <td class="option-control"><input id="local_timezone" type="checkbox" checked data-toggle="toggle" data-on="Your Time" data-off="Server Time" data-onstyle="success" data-offstyle="danger" data-width="110px"></td> + <td class="option-info"><strong>Show browser local time or server time?</strong><br/> + <small>When set to <b>Your Time</b>, the charts will use your browser local time. When set to <b>Server Time</b> the charts will use the server time. + <br/> + Set it to <b>Your Time</b> to have a common time-reference, no matter where the server is and which time zone it uses (all your dashboards will report your local time). + Set it to <b>Server Time</b> when you need to compare netdata charts with server log files. + <br/> + Your browser time zone is: <b><span id="browser_timezone">-</span></b>.<br/> + The server reported timezone is: <b><span id="server_timezone">-</span></b> (you can set this in netdata.conf <code>[global].timezone</code>).<br/> + The current time zone on the dashboard is: <b><span id="current_timezone">-</span></b>. + <br/> + <div class="dropup"> + <button class="btn btn-default dropdown-toggle" type="button" id="dropdownTimeZone" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> + Select Server Time Zone + <span class="caret"></span> + </button> + <ul class="dropdown-menu scrollable-menu-50" aria-labelledby="dropdownTimeZone"> + <li><a href=# onclick="return selected_server_timezone('UTC');">Universal Time Coordinated (UTC)</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Abidjan');">Africa/Abidjan</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Accra');">Africa/Accra</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Algiers');">Africa/Algiers</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Bissau');">Africa/Bissau</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Cairo');">Africa/Cairo</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Casablanca');">Africa/Casablanca</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Ceuta');">Africa/Ceuta</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/El_Aaiun');">Africa/El_Aaiun</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Johannesburg');">Africa/Johannesburg</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Khartoum');">Africa/Khartoum</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Lagos');">Africa/Lagos</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Maputo');">Africa/Maputo</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Monrovia');">Africa/Monrovia</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Nairobi');">Africa/Nairobi</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Ndjamena');">Africa/Ndjamena</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Tripoli');">Africa/Tripoli</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Tunis');">Africa/Tunis</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Windhoek');">Africa/Windhoek</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Adak');">America/Adak</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Anchorage');">America/Anchorage</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Araguaina');">America/Araguaina</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Buenos_Aires');">America/Argentina/Buenos_Aires</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Catamarca');">America/Argentina/Catamarca</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Cordoba');">America/Argentina/Cordoba</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Jujuy');">America/Argentina/Jujuy</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/La_Rioja');">America/Argentina/La_Rioja</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Mendoza');">America/Argentina/Mendoza</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Rio_Gallegos');">America/Argentina/Rio_Gallegos</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Salta');">America/Argentina/Salta</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/San_Juan');">America/Argentina/San_Juan</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/San_Luis');">America/Argentina/San_Luis</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Tucuman');">America/Argentina/Tucuman</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Ushuaia');">America/Argentina/Ushuaia</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Asuncion');">America/Asuncion</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Atikokan');">America/Atikokan</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Bahia');">America/Bahia</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Bahia_Banderas');">America/Bahia_Banderas</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Barbados');">America/Barbados</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Belem');">America/Belem</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Belize');">America/Belize</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Blanc-Sablon');">America/Blanc-Sablon</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Boa_Vista');">America/Boa_Vista</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Bogota');">America/Bogota</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Boise');">America/Boise</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Cambridge_Bay');">America/Cambridge_Bay</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Campo_Grande');">America/Campo_Grande</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Cancun');">America/Cancun</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Caracas');">America/Caracas</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Cayenne');">America/Cayenne</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Chicago');">America/Chicago</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Chihuahua');">America/Chihuahua</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Costa_Rica');">America/Costa_Rica</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Creston');">America/Creston</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Cuiaba');">America/Cuiaba</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Curacao');">America/Curacao</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Danmarkshavn');">America/Danmarkshavn</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Dawson');">America/Dawson</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Dawson_Creek');">America/Dawson_Creek</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Denver');">America/Denver</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Detroit');">America/Detroit</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Edmonton');">America/Edmonton</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Eirunepe');">America/Eirunepe</a></li> + <li><a href=# onclick="return selected_server_timezone('America/El_Salvador');">America/El_Salvador</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Fortaleza');">America/Fortaleza</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Fort_Nelson');">America/Fort_Nelson</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Glace_Bay');">America/Glace_Bay</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Godthab');">America/Godthab</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Goose_Bay');">America/Goose_Bay</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Grand_Turk');">America/Grand_Turk</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Guatemala');">America/Guatemala</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Guayaquil');">America/Guayaquil</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Guyana');">America/Guyana</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Halifax');">America/Halifax</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Havana');">America/Havana</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Hermosillo');">America/Hermosillo</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Indianapolis');">America/Indiana/Indianapolis</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Knox');">America/Indiana/Knox</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Marengo');">America/Indiana/Marengo</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Petersburg');">America/Indiana/Petersburg</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Tell_City');">America/Indiana/Tell_City</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Vevay');">America/Indiana/Vevay</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Vincennes');">America/Indiana/Vincennes</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Winamac');">America/Indiana/Winamac</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Inuvik');">America/Inuvik</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Iqaluit');">America/Iqaluit</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Jamaica');">America/Jamaica</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Juneau');">America/Juneau</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Kentucky/Louisville');">America/Kentucky/Louisville</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Kentucky/Monticello');">America/Kentucky/Monticello</a></li> + <li><a href=# onclick="return selected_server_timezone('America/La_Paz');">America/La_Paz</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Lima');">America/Lima</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Los_Angeles');">America/Los_Angeles</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Maceio');">America/Maceio</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Managua');">America/Managua</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Manaus');">America/Manaus</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Martinique');">America/Martinique</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Matamoros');">America/Matamoros</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Mazatlan');">America/Mazatlan</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Menominee');">America/Menominee</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Merida');">America/Merida</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Metlakatla');">America/Metlakatla</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Mexico_City');">America/Mexico_City</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Miquelon');">America/Miquelon</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Moncton');">America/Moncton</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Monterrey');">America/Monterrey</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Montevideo');">America/Montevideo</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Nassau');">America/Nassau</a></li> + <li><a href=# onclick="return selected_server_timezone('America/New_York');">America/New_York</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Nipigon');">America/Nipigon</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Nome');">America/Nome</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Noronha');">America/Noronha</a></li> + <li><a href=# onclick="return selected_server_timezone('America/North_Dakota/Beulah');">America/North_Dakota/Beulah</a></li> + <li><a href=# onclick="return selected_server_timezone('America/North_Dakota/Center');">America/North_Dakota/Center</a></li> + <li><a href=# onclick="return selected_server_timezone('America/North_Dakota/New_Salem');">America/North_Dakota/New_Salem</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Ojinaga');">America/Ojinaga</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Panama');">America/Panama</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Pangnirtung');">America/Pangnirtung</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Paramaribo');">America/Paramaribo</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Phoenix');">America/Phoenix</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Port-au-Prince');">America/Port-au-Prince</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Port_of_Spain');">America/Port_of_Spain</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Porto_Velho');">America/Porto_Velho</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Puerto_Rico');">America/Puerto_Rico</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Punta_Arenas');">America/Punta_Arenas</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Rainy_River');">America/Rainy_River</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Rankin_Inlet');">America/Rankin_Inlet</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Recife');">America/Recife</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Regina');">America/Regina</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Resolute');">America/Resolute</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Rio_Branco');">America/Rio_Branco</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Santarem');">America/Santarem</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Santiago');">America/Santiago</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Santo_Domingo');">America/Santo_Domingo</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Sao_Paulo');">America/Sao_Paulo</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Scoresbysund');">America/Scoresbysund</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Sitka');">America/Sitka</a></li> + <li><a href=# onclick="return selected_server_timezone('America/St_Johns');">America/St_Johns</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Swift_Current');">America/Swift_Current</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Tegucigalpa');">America/Tegucigalpa</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Thule');">America/Thule</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Thunder_Bay');">America/Thunder_Bay</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Tijuana');">America/Tijuana</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Toronto');">America/Toronto</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Vancouver');">America/Vancouver</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Whitehorse');">America/Whitehorse</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Winnipeg');">America/Winnipeg</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Yakutat');">America/Yakutat</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Yellowknife');">America/Yellowknife</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Casey');">Antarctica/Casey</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Davis');">Antarctica/Davis</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/DumontDUrville');">Antarctica/DumontDUrville</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Macquarie');">Antarctica/Macquarie</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Mawson');">Antarctica/Mawson</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Palmer');">Antarctica/Palmer</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Rothera');">Antarctica/Rothera</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Syowa');">Antarctica/Syowa</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Troll');">Antarctica/Troll</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Vostok');">Antarctica/Vostok</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Almaty');">Asia/Almaty</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Amman');">Asia/Amman</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Anadyr');">Asia/Anadyr</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Aqtau');">Asia/Aqtau</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Aqtobe');">Asia/Aqtobe</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Ashgabat');">Asia/Ashgabat</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Atyrau');">Asia/Atyrau</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Baghdad');">Asia/Baghdad</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Baku');">Asia/Baku</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Bangkok');">Asia/Bangkok</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Barnaul');">Asia/Barnaul</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Beirut');">Asia/Beirut</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Bishkek');">Asia/Bishkek</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Brunei');">Asia/Brunei</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Chita');">Asia/Chita</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Choibalsan');">Asia/Choibalsan</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Colombo');">Asia/Colombo</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Damascus');">Asia/Damascus</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Dhaka');">Asia/Dhaka</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Dili');">Asia/Dili</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Dubai');">Asia/Dubai</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Dushanbe');">Asia/Dushanbe</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Famagusta');">Asia/Famagusta</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Gaza');">Asia/Gaza</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Hebron');">Asia/Hebron</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Ho_Chi_Minh');">Asia/Ho_Chi_Minh</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Hong_Kong');">Asia/Hong_Kong</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Hovd');">Asia/Hovd</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Irkutsk');">Asia/Irkutsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Jakarta');">Asia/Jakarta</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Jayapura');">Asia/Jayapura</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Jerusalem');">Asia/Jerusalem</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Kabul');">Asia/Kabul</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Kamchatka');">Asia/Kamchatka</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Karachi');">Asia/Karachi</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Kathmandu');">Asia/Kathmandu</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Khandyga');">Asia/Khandyga</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Kolkata');">Asia/Kolkata</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Krasnoyarsk');">Asia/Krasnoyarsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Kuala_Lumpur');">Asia/Kuala_Lumpur</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Kuching');">Asia/Kuching</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Macau');">Asia/Macau</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Magadan');">Asia/Magadan</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Makassar');">Asia/Makassar</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Manila');">Asia/Manila</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Nicosia');">Asia/Nicosia</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Novokuznetsk');">Asia/Novokuznetsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Novosibirsk');">Asia/Novosibirsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Omsk');">Asia/Omsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Oral');">Asia/Oral</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Pontianak');">Asia/Pontianak</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Pyongyang');">Asia/Pyongyang</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Qatar');">Asia/Qatar</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Qyzylorda');">Asia/Qyzylorda</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Riyadh');">Asia/Riyadh</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Sakhalin');">Asia/Sakhalin</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Samarkand');">Asia/Samarkand</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Seoul');">Asia/Seoul</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Shanghai');">Asia/Shanghai</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Singapore');">Asia/Singapore</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Srednekolymsk');">Asia/Srednekolymsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Taipei');">Asia/Taipei</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Tashkent');">Asia/Tashkent</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Tbilisi');">Asia/Tbilisi</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Tehran');">Asia/Tehran</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Thimphu');">Asia/Thimphu</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Tokyo');">Asia/Tokyo</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Tomsk');">Asia/Tomsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Ulaanbaatar');">Asia/Ulaanbaatar</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Urumqi');">Asia/Urumqi</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Ust-Nera');">Asia/Ust-Nera</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Vladivostok');">Asia/Vladivostok</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Yakutsk');">Asia/Yakutsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Yangon');">Asia/Yangon</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Yekaterinburg');">Asia/Yekaterinburg</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Yerevan');">Asia/Yerevan</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Azores');">Atlantic/Azores</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Bermuda');">Atlantic/Bermuda</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Canary');">Atlantic/Canary</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Cape_Verde');">Atlantic/Cape_Verde</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Faroe');">Atlantic/Faroe</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Madeira');">Atlantic/Madeira</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Reykjavik');">Atlantic/Reykjavik</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/South_Georgia');">Atlantic/South_Georgia</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Stanley');">Atlantic/Stanley</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Adelaide');">Australia/Adelaide</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Brisbane');">Australia/Brisbane</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Broken_Hill');">Australia/Broken_Hill</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Currie');">Australia/Currie</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Darwin');">Australia/Darwin</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Eucla');">Australia/Eucla</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Hobart');">Australia/Hobart</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Lindeman');">Australia/Lindeman</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Lord_Howe');">Australia/Lord_Howe</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Melbourne');">Australia/Melbourne</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Perth');">Australia/Perth</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Sydney');">Australia/Sydney</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Amsterdam');">Europe/Amsterdam</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Andorra');">Europe/Andorra</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Astrakhan');">Europe/Astrakhan</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Athens');">Europe/Athens</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Belgrade');">Europe/Belgrade</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Berlin');">Europe/Berlin</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Brussels');">Europe/Brussels</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Bucharest');">Europe/Bucharest</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Budapest');">Europe/Budapest</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Chisinau');">Europe/Chisinau</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Copenhagen');">Europe/Copenhagen</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Dublin');">Europe/Dublin</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Gibraltar');">Europe/Gibraltar</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Helsinki');">Europe/Helsinki</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Istanbul');">Europe/Istanbul</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Kaliningrad');">Europe/Kaliningrad</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Kiev');">Europe/Kiev</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Kirov');">Europe/Kirov</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Lisbon');">Europe/Lisbon</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/London');">Europe/London</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Luxembourg');">Europe/Luxembourg</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Madrid');">Europe/Madrid</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Malta');">Europe/Malta</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Minsk');">Europe/Minsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Monaco');">Europe/Monaco</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Moscow');">Europe/Moscow</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Oslo');">Europe/Oslo</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Paris');">Europe/Paris</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Prague');">Europe/Prague</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Riga');">Europe/Riga</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Rome');">Europe/Rome</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Samara');">Europe/Samara</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Saratov');">Europe/Saratov</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Simferopol');">Europe/Simferopol</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Sofia');">Europe/Sofia</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Stockholm');">Europe/Stockholm</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Tallinn');">Europe/Tallinn</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Tirane');">Europe/Tirane</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Ulyanovsk');">Europe/Ulyanovsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Uzhgorod');">Europe/Uzhgorod</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Vienna');">Europe/Vienna</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Vilnius');">Europe/Vilnius</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Volgograd');">Europe/Volgograd</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Warsaw');">Europe/Warsaw</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Zaporozhye');">Europe/Zaporozhye</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Zurich');">Europe/Zurich</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Chagos');">Indian/Chagos</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Christmas');">Indian/Christmas</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Cocos');">Indian/Cocos</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Kerguelen');">Indian/Kerguelen</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Mahe');">Indian/Mahe</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Maldives');">Indian/Maldives</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Mauritius');">Indian/Mauritius</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Reunion');">Indian/Reunion</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Apia');">Pacific/Apia</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Auckland');">Pacific/Auckland</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Bougainville');">Pacific/Bougainville</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Chatham');">Pacific/Chatham</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Chuuk');">Pacific/Chuuk</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Easter');">Pacific/Easter</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Efate');">Pacific/Efate</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Enderbury');">Pacific/Enderbury</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Fakaofo');">Pacific/Fakaofo</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Fiji');">Pacific/Fiji</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Funafuti');">Pacific/Funafuti</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Galapagos');">Pacific/Galapagos</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Gambier');">Pacific/Gambier</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Guadalcanal');">Pacific/Guadalcanal</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Guam');">Pacific/Guam</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Honolulu');">Pacific/Honolulu</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Kiritimati');">Pacific/Kiritimati</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Kosrae');">Pacific/Kosrae</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Kwajalein');">Pacific/Kwajalein</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Majuro');">Pacific/Majuro</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Marquesas');">Pacific/Marquesas</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Nauru');">Pacific/Nauru</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Niue');">Pacific/Niue</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Norfolk');">Pacific/Norfolk</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Noumea');">Pacific/Noumea</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Pago_Pago');">Pacific/Pago_Pago</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Palau');">Pacific/Palau</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Pitcairn');">Pacific/Pitcairn</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Pohnpei');">Pacific/Pohnpei</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Port_Moresby');">Pacific/Port_Moresby</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Rarotonga');">Pacific/Rarotonga</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Tahiti');">Pacific/Tahiti</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Tarawa');">Pacific/Tarawa</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Tongatapu');">Pacific/Tongatapu</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Wake');">Pacific/Wake</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Wallis');">Pacific/Wallis</a></li> + </ul> + </div> + <b><span id="timezone_error_message"></span></b> + + </small> + </td> + </tr> + </table> + </div> + </form> + </div> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + </div> + </div> + + + <div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-labelledby="updateModalLabel"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="updateModalLabel">Update Check</h4> + </div> + <div class="modal-body"> + Your netdata version: <b><code><span id="netdataVersion">Unknown</span></code></b><br/> + Your netdata commit: <b><code><span id="netdataCommitId">Unknown</span></code></b> + <br/> + <div style="padding: 10px;"></div> + <div id="versionCheckLog">Not checked yet. Please press the Check Now button.</div> + <div> + <hr/> + </div> + <div> + For progress reports and key netdata updates: <strong><a href="https://twitter.com/linuxnetdata" target="_blank">follow netdata on <i class="fab fa-twitter"></i> twitter</a></strong>. + <br/> + You can also <a href="https://www.facebook.com/linuxnetdata/" target="_blank">follow netdata on <i class="fab fa-facebook"></i> facebook</a>, + or <a href="https://github.com/netdata/netdata" target="_blank">watch netdata on <i class="fab fa-github"></i> github</a>. + </div> + </div> + <div class="modal-footer"> + <a href="#" onclick="notifyForUpdate(true); return false;" type="button" class="btn btn-default">Check Now</a> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="deleteRegistryModal" tabindex="-1" role="dialog" aria-labelledby="deleteRegistryModalLabel"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="deleteRegistryModalLabel">Delete <span id="deleteRegistryServerName"></span>?</h4> + </div> + <div class="modal-body"> + You are about to delete, from your personal list of netdata servers, the following server: + <p style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;"> + <b><span id="deleteRegistryServerName2"></span></b> + <br/> + <b><span id="deleteRegistryServerURL"></span></b> + </p> + Are you sure you want to do this? + <br/> + <div style="padding: 10px;"></div> + <small>Keep in mind, this server will be added back if and when you visit it again.</small> + <br/> + <div id="deleteRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-success" data-dismiss="modal">keep it</button> + <a href="#" onclick="notifyForDeleteRegistry(); return false;" type="button" class="btn btn-danger">delete it</a> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="switchRegistryModal" tabindex="-1" role="dialog" aria-labelledby="switchRegistryModalLabel"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="switchRegistryModalLabel">Switch Netdata Registry Identity</h4> + </div> + <div class="modal-body"> + You can copy and paste the following ID to all your browsers (e.g. work and home). + <br/> + All the browsers with the same ID will identify <b>you</b>, so please don't share this with others. + <div style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;"> + <form action="#"> + <input type="text" class="form-control" id="switchRegistryPersonGUID" placeholder="your personal ID" maxlength="36" autocomplete="off" style="text-align: center; font-size: 1.4em;"> + </form> + </div> + Either copy this ID and paste it to another browser, or paste here the ID you have taken from another browser. + <div style="padding-top: 10px;"><small> + Keep in mind that: + <ul> + <li>when you switch ID, your previous ID will be lost forever - this is irreversible.</li> + <li>both IDs (your old and the new) must list this netdata at their personal lists.</li> + <li>both IDs have to be known by the registry: <b><span id="switchRegistryURL"></span></b>.</li> + <li>to get a new ID, just clear your browser cookies.</li> + </ul> + </small></div> + <div id="switchRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-success" data-dismiss="modal">cancel</button> + <a href="#" onclick="notifyForSwitchRegistry(); return false;" type="button" class="btn btn-danger">impersonate</a> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="gotoServerModal" tabindex="-1" role="dialog" aria-labelledby="gotoServerModalLabel"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="gotoServerModalLabel"><span id="gotoServerName"></span></h4> + </div> + <div class="modal-body"> + Checking known URLs for this server... + <div style="padding-top: 20px;"> + <table id="gotoServerList"> + </table> + </div> + <p style="padding-top: 10px;"><small> + Checks may fail if you are viewing an HTTPS page and the server to be checked is HTTP only. + </small></p> + <div id="gotoServerResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + </div> + </div> + <div id="hiddenDownloadLinks" style="display: none;" hidden></div> + <script type="text/javascript" src="dashboard.js?v20181013-2"></script> +</body> +</html> |