From 841395dd16f470e3c051a0a4fff5b91efc983c30 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 May 2021 14:33:27 +0200 Subject: Adding upstream version 1.31.0. Signed-off-by: Daniel Baumann --- web/gui/dashboard.js | 10377 ------------------------------------------------- 1 file changed, 10377 deletions(-) delete mode 100644 web/gui/dashboard.js (limited to 'web/gui/dashboard.js') diff --git a/web/gui/dashboard.js b/web/gui/dashboard.js deleted file mode 100644 index 53e9090b1..000000000 --- a/web/gui/dashboard.js +++ /dev/null @@ -1,10377 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later - -// DO NOT EDIT: This file is automatically generated from the source files in src/ - -// ---------------------------------------------------------------------------- -// You can set the following variables before loading this script: - -// 'use strict'; - -/*global netdataNoDygraphs *//* boolean, disable dygraph charts - * (default: false) */ -/*global netdataNoSparklines *//* boolean, disable sparkline charts - * (default: false) */ -/*global netdataNoPeitys *//* boolean, disable peity charts - * (default: false) */ -/*global netdataNoGoogleCharts *//* boolean, disable google charts - * (default: false) */ -/*global netdataNoMorris *//* boolean, disable morris charts - * (default: false) */ -/*global netdataNoEasyPieChart *//* boolean, disable easypiechart charts - * (default: false) */ -/*global netdataNoGauge *//* boolean, disable gauge.js charts - * (default: false) */ -/*global netdataNoD3 *//* boolean, disable d3 charts - * (default: false) */ -/*global netdataNoC3 *//* boolean, disable c3 charts - * (default: false) */ -/*global netdataNoD3pie *//* boolean, disable d3pie charts - * (default: false) */ -/*global netdataNoBootstrap *//* boolean, disable bootstrap - disables help too - * (default: false) */ -/*global netdataNoFontAwesome *//* boolean, disable fontawesome (do not load it) - * (default: false) */ -/*global netdataIcons *//* object, overwrite netdata fontawesome icons - * (default: null) */ -/*global netdataDontStart *//* boolean, do not start the thread to process the charts - * (default: false) */ -/*global netdataErrorCallback *//* function, callback to be called when the dashboard encounters an error - * (default: null) */ -/*global netdataRegistry:true *//* boolean, use the netdata registry - * (default: false) */ -/*global netdataNoRegistry *//* boolean, included only for compatibility with existing custom dashboard - * (obsolete - do not use this any more) */ -/*global netdataRegistryCallback *//* function, callback that will be invoked with one param: the URLs from the registry - * (default: null) */ -/*global netdataShowHelp:true *//* boolean, disable charts help - * (default: true) */ -/*global netdataShowAlarms:true *//* boolean, enable alarms checks and notifications - * (default: false) */ -/*global netdataRegistryAfterMs:true *//* ms, delay registry use at started - * (default: 1500) */ -/*global netdataCallback *//* function, callback to be called when netdata is ready to start - * (default: null) - * netdata will be running while this is called - * (call NETDATA.pause to stop it) */ -/*global netdataPrepCallback *//* function, callback to be called before netdata does anything else - * (default: null) */ -/*global netdataServer *//* string, the URL of the netdata server to use - * (default: the URL the page is hosted at) */ -/*global netdataServerStatic *//* string, the URL of the netdata server to use for static files - * (default: netdataServer) */ -/*global netdataSnapshotData *//* object, a netdata snapshot loaded - * (default: null) */ -/*global netdataAlarmsRecipients *//* array, an array of alarm recipients to show notifications for - * (default: null) */ -/*global netdataAlarmsRemember *//* boolen, keep our position in the alarm log at browser local storage - * (default: true) */ -/*global netdataAlarmsActiveCallback *//* function, a hook for the alarm logs - * (default: undefined) */ -/*global netdataAlarmsNotifCallback *//* function, a hook for alarm notifications - * (default: undefined) */ -/*global netdataIntersectionObserver *//* boolean, enable or disable the use of intersection observer - * (default: true) */ -/*global netdataCheckXSS *//* boolean, enable or disable checking for XSS issues - * (default: false) */ - -// ---------------------------------------------------------------------------- -// global namespace - -// Should stay var! -var NETDATA = window.NETDATA || {}; - -(function(window, document, $, undefined) { - -// *** src/dashboard.js/utils.js - -NETDATA.name2id = function (s) { - return s - .replace(/ /g, '_') - .replace(/:/g, '_') - .replace(/\(/g, '_') - .replace(/\)/g, '_') - .replace(/\./g, '_') - .replace(/\//g, '_'); -}; - -NETDATA.encodeURIComponent = function (s) { - if (typeof(s) === 'string') { - return encodeURIComponent(s); - } - - return s; -}; - -/// A heuristic for detecting slow devices. -let isSlowDeviceResult = undefined; -const isSlowDevice = function () { - if (!isSlowDeviceResult) { - return isSlowDeviceResult; - } - - try { - let ua = navigator.userAgent.toLowerCase(); - - let iOS = /ipad|iphone|ipod/.test(ua) && !window.MSStream; - let android = /android/.test(ua) && !window.MSStream; - isSlowDeviceResult = (iOS || android); - } catch (e) { - isSlowDeviceResult = false; - } - - return isSlowDeviceResult; -}; - -NETDATA.guid = function () { - function s4() { - return Math.floor((1 + Math.random()) * 0x10000) - .toString(16) - .substring(1); - } - - return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); -}; - -NETDATA.zeropad = function (x) { - if (x > -10 && x < 10) { - return '0' + x.toString(); - } else { - return x.toString(); - } -}; - -NETDATA.seconds4human = function (seconds, options) { - let defaultOptions = { - now: 'now', - space: ' ', - negative_suffix: 'ago', - day: 'day', - days: 'days', - hour: 'hour', - hours: 'hours', - minute: 'min', - minutes: 'mins', - second: 'sec', - seconds: 'secs', - and: 'and' - }; - - if (typeof options !== 'object') { - options = defaultOptions; - } else { - for (var x in defaultOptions) { - if (typeof options[x] !== 'string') { - options[x] = defaultOptions[x]; - } - } - } - - if (typeof seconds === 'string') { - seconds = parseInt(seconds, 10); - } - - if (seconds === 0) { - return options.now; - } - - let suffix = ''; - if (seconds < 0) { - seconds = -seconds; - if (options.negative_suffix !== '') { - suffix = options.space + options.negative_suffix; - } - } - - let days = Math.floor(seconds / 86400); - seconds -= (days * 86400); - - let hours = Math.floor(seconds / 3600); - seconds -= (hours * 3600); - - let minutes = Math.floor(seconds / 60); - seconds -= (minutes * 60); - - let strings = []; - - if (days > 1) { - strings.push(days.toString() + options.space + options.days); - } else if (days === 1) { - strings.push(days.toString() + options.space + options.day); - } - - if (hours > 1) { - strings.push(hours.toString() + options.space + options.hours); - } else if (hours === 1) { - strings.push(hours.toString() + options.space + options.hour); - } - - if (minutes > 1) { - strings.push(minutes.toString() + options.space + options.minutes); - } else if (minutes === 1) { - strings.push(minutes.toString() + options.space + options.minute); - } - - if (seconds > 1) { - strings.push(Math.floor(seconds).toString() + options.space + options.seconds); - } else if (seconds === 1) { - strings.push(Math.floor(seconds).toString() + options.space + options.second); - } - - if (strings.length === 1) { - return strings.pop() + suffix; - } - - let last = strings.pop(); - return strings.join(", ") + " " + options.and + " " + last + suffix; -}; - -// ---------------------------------------------------------------------------------------------------------------- -// element data attributes - -NETDATA.dataAttribute = function (element, attribute, def) { - let key = 'data-' + attribute.toString(); - if (element.hasAttribute(key)) { - let data = element.getAttribute(key); - - if (data === 'true') { - return true; - } - if (data === 'false') { - return false; - } - if (data === 'null') { - return null; - } - - // Only convert to a number if it doesn't change the string - if (data === +data + '') { - return +data; - } - - if (/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/.test(data)) { - return JSON.parse(data); - } - - return data; - } else { - return def; - } -}; - -NETDATA.dataAttributeBoolean = function (element, attribute, def) { - let value = NETDATA.dataAttribute(element, attribute, def); - - if (value === true || value === false) // gmosx: Love this :) - { - return value; - } - - if (typeof(value) === 'string') { - if (value === 'yes' || value === 'on') { - return true; - } - - if (value === '' || value === 'no' || value === 'off' || value === 'null') { - return false; - } - - return def; - } - - if (typeof(value) === 'number') { - return value !== 0; - } - - return def; -}; - -// ---------------------------------------------------------------------------------------------------------------- -// fast numbers formatting - -NETDATA.fastNumberFormat = { - formattersFixed: [], - formattersZeroBased: [], - - // this is the fastest and the preferred - getIntlNumberFormat: function (min, max) { - let key = max; - if (min === max) { - if (typeof this.formattersFixed[key] === 'undefined') { - this.formattersFixed[key] = new Intl.NumberFormat(undefined, { - // style: 'decimal', - // minimumIntegerDigits: 1, - // minimumSignificantDigits: 1, - // maximumSignificantDigits: 1, - useGrouping: true, - minimumFractionDigits: min, - maximumFractionDigits: max - }); - } - - return this.formattersFixed[key]; - } else if (min === 0) { - if (typeof this.formattersZeroBased[key] === 'undefined') { - this.formattersZeroBased[key] = new Intl.NumberFormat(undefined, { - // style: 'decimal', - // minimumIntegerDigits: 1, - // minimumSignificantDigits: 1, - // maximumSignificantDigits: 1, - useGrouping: true, - minimumFractionDigits: min, - maximumFractionDigits: max - }); - } - - return this.formattersZeroBased[key]; - } else { - // this is never used - // it is added just for completeness - return new Intl.NumberFormat(undefined, { - // style: 'decimal', - // minimumIntegerDigits: 1, - // minimumSignificantDigits: 1, - // maximumSignificantDigits: 1, - useGrouping: true, - minimumFractionDigits: min, - maximumFractionDigits: max - }); - } - }, - - // this respects locale - getLocaleString: function (min, max) { - let key = max; - if (min === max) { - if (typeof this.formattersFixed[key] === 'undefined') { - this.formattersFixed[key] = { - format: function (value) { - return value.toLocaleString(undefined, { - // style: 'decimal', - // minimumIntegerDigits: 1, - // minimumSignificantDigits: 1, - // maximumSignificantDigits: 1, - useGrouping: true, - minimumFractionDigits: min, - maximumFractionDigits: max - }); - } - }; - } - - return this.formattersFixed[key]; - } else if (min === 0) { - if (typeof this.formattersZeroBased[key] === 'undefined') { - this.formattersZeroBased[key] = { - format: function (value) { - return value.toLocaleString(undefined, { - // style: 'decimal', - // minimumIntegerDigits: 1, - // minimumSignificantDigits: 1, - // maximumSignificantDigits: 1, - useGrouping: true, - minimumFractionDigits: min, - maximumFractionDigits: max - }); - } - }; - } - - return this.formattersZeroBased[key]; - } else { - return { - format: function (value) { - return value.toLocaleString(undefined, { - // style: 'decimal', - // minimumIntegerDigits: 1, - // minimumSignificantDigits: 1, - // maximumSignificantDigits: 1, - useGrouping: true, - minimumFractionDigits: min, - maximumFractionDigits: max - }); - } - }; - } - }, - - // the fallback - getFixed: function (min, max) { - let key = max; - if (min === max) { - if (typeof this.formattersFixed[key] === 'undefined') { - this.formattersFixed[key] = { - format: function (value) { - if (value === 0) { - return "0"; - } - return value.toFixed(max); - } - }; - } - - return this.formattersFixed[key]; - } else if (min === 0) { - if (typeof this.formattersZeroBased[key] === 'undefined') { - this.formattersZeroBased[key] = { - format: function (value) { - if (value === 0) { - return "0"; - } - return value.toFixed(max); - } - }; - } - - return this.formattersZeroBased[key]; - } else { - return { - format: function (value) { - if (value === 0) { - return "0"; - } - return value.toFixed(max); - } - }; - } - }, - - testIntlNumberFormat: function () { - let value = 1.12345; - let e1 = "1.12", e2 = "1,12"; - let s = ""; - - try { - let x = new Intl.NumberFormat(undefined, { - useGrouping: true, - minimumFractionDigits: 2, - maximumFractionDigits: 2 - }); - - s = x.format(value); - } catch (e) { - s = ""; - } - - // console.log('NumberFormat: ', s); - return (s === e1 || s === e2); - }, - - testLocaleString: function () { - let value = 1.12345; - let e1 = "1.12", e2 = "1,12"; - let s = ""; - - try { - s = value.toLocaleString(undefined, { - useGrouping: true, - minimumFractionDigits: 2, - maximumFractionDigits: 2 - }); - } catch (e) { - s = ""; - } - - // console.log('localeString: ', s); - return (s === e1 || s === e2); - }, - - // on first run we decide which formatter to use - get: function (min, max) { - if (this.testIntlNumberFormat()) { - // console.log('numberformat'); - this.get = this.getIntlNumberFormat; - } else if (this.testLocaleString()) { - // console.log('localestring'); - this.get = this.getLocaleString; - } else { - // console.log('fixed'); - this.get = this.getFixed; - } - return this.get(min, max); - } -}; - -// ---------------------------------------------------------------------------------------------------------------- -// Detect the netdata server - -// http://stackoverflow.com/questions/984510/what-is-my-script-src-url -// http://stackoverflow.com/questions/6941533/get-protocol-domain-and-port-from-url -NETDATA._scriptSource = function () { - let script = null; - - if (typeof document.currentScript !== 'undefined') { - script = document.currentScript; - } else { - const all_scripts = document.getElementsByTagName('script'); - script = all_scripts[all_scripts.length - 1]; - } - - if (typeof script.getAttribute.length !== 'undefined') { - script = script.src; - } else { - script = script.getAttribute('src', -1); - } - - return script; -}; - -// *** src/dashboard.js/server-detection.js - -if (typeof netdataServer !== 'undefined') { - NETDATA.serverDefault = netdataServer; -} else { - let s = NETDATA._scriptSource(); - if (s) { - NETDATA.serverDefault = s.replace(/\/dashboard.js(\?.*)?$/g, ""); - } else { - console.log('WARNING: Cannot detect the URL of the netdata server.'); - NETDATA.serverDefault = null; - } -} - -if (NETDATA.serverDefault === null) { - NETDATA.serverDefault = ''; -} else if (NETDATA.serverDefault.slice(-1) !== '/') { - NETDATA.serverDefault += '/'; -} - -if (typeof netdataServerStatic !== 'undefined' && netdataServerStatic !== null && netdataServerStatic !== '') { - NETDATA.serverStatic = netdataServerStatic; - if (NETDATA.serverStatic.slice(-1) !== '/') { - NETDATA.serverStatic += '/'; - } -} else { - NETDATA.serverStatic = NETDATA.serverDefault; -} - -// *** src/dashboard.js/dependencies.js - -// default URLs for all the external files we need -// make them RELATIVE so that the whole thing can also be -// installed under a web server -NETDATA.jQuery = NETDATA.serverStatic + 'lib/jquery-2.2.4.min.js'; -NETDATA.peity_js = NETDATA.serverStatic + 'lib/jquery.peity-3.2.0.min.js'; -NETDATA.sparkline_js = NETDATA.serverStatic + 'lib/jquery.sparkline-2.1.2.min.js'; -NETDATA.easypiechart_js = NETDATA.serverStatic + 'lib/jquery.easypiechart-97b5824.min.js'; -NETDATA.gauge_js = NETDATA.serverStatic + 'lib/gauge-1.3.2.min.js'; -NETDATA.dygraph_js = NETDATA.serverStatic + 'lib/dygraph-c91c859.min.js'; -NETDATA.dygraph_smooth_js = NETDATA.serverStatic + 'lib/dygraph-smooth-plotter-c91c859.js'; -// NETDATA.raphael_js = NETDATA.serverStatic + 'lib/raphael-2.2.4-min.js'; -// NETDATA.c3_js = NETDATA.serverStatic + 'lib/c3-0.4.18.min.js'; -// NETDATA.c3_css = NETDATA.serverStatic + 'css/c3-0.4.18.min.css'; -NETDATA.d3pie_js = NETDATA.serverStatic + 'lib/d3pie-0.2.1-netdata-3.js'; -NETDATA.d3_js = NETDATA.serverStatic + 'lib/d3-4.12.2.min.js'; -// NETDATA.morris_js = NETDATA.serverStatic + 'lib/morris-0.5.1.min.js'; -// NETDATA.morris_css = NETDATA.serverStatic + 'css/morris-0.5.1.css'; -NETDATA.google_js = 'https://www.google.com/jsapi'; -// Error Handling - -NETDATA.errorCodes = { - 100: {message: "Cannot load chart library", alert: true}, - 101: {message: "Cannot load jQuery", alert: true}, - 402: {message: "Chart library not found", alert: false}, - 403: {message: "Chart library not enabled/is failed", alert: false}, - 404: {message: "Chart not found", alert: false}, - 405: {message: "Cannot download charts index from server", alert: true}, - 406: {message: "Invalid charts index downloaded from server", alert: true}, - 407: {message: "Cannot HELLO netdata server", alert: false}, - 408: {message: "Netdata servers sent invalid response to HELLO", alert: false}, - 409: {message: "Cannot ACCESS netdata registry", alert: false}, - 410: {message: "Netdata registry ACCESS failed", alert: false}, - 411: {message: "Netdata registry server send invalid response to DELETE ", alert: false}, - 412: {message: "Netdata registry DELETE failed", alert: false}, - 413: {message: "Netdata registry server send invalid response to SWITCH ", alert: false}, - 414: {message: "Netdata registry SWITCH failed", alert: false}, - 415: {message: "Netdata alarms download failed", alert: false}, - 416: {message: "Netdata alarms log download failed", alert: false}, - 417: {message: "Netdata registry server send invalid response to SEARCH ", alert: false}, - 418: {message: "Netdata registry SEARCH failed", alert: false} -}; - -NETDATA.errorLast = { - code: 0, - message: "", - datetime: 0 -}; - -NETDATA.error = function (code, msg) { - NETDATA.errorLast.code = code; - NETDATA.errorLast.message = msg; - NETDATA.errorLast.datetime = Date.now(); - - console.log("ERROR " + code + ": " + NETDATA.errorCodes[code].message + ": " + msg); - - let ret = true; - if (typeof netdataErrorCallback === 'function') { - ret = netdataErrorCallback('system', code, msg); - } - - if (ret && NETDATA.errorCodes[code].alert) { - alert("ERROR " + code + ": " + NETDATA.errorCodes[code].message + ": " + msg); - } -}; - -NETDATA.errorReset = function () { - NETDATA.errorLast.code = 0; - NETDATA.errorLast.message = "You are doing fine!"; - NETDATA.errorLast.datetime = 0; -}; -// *** src/dashboard.js/compatibility.js - -// Compatibility fixes. - -// fix IE issue with console -if (!window.console) { - window.console = { - log: function () { - } - }; -} - -// if string.endsWith is not defined, define it -if (typeof String.prototype.endsWith !== 'function') { - String.prototype.endsWith = function (s) { - if (s.length > this.length) { - return false; - } - return this.slice(-s.length) === s; - }; -} - -// if string.startsWith is not defined, define it -if (typeof String.prototype.startsWith !== 'function') { - String.prototype.startsWith = function (s) { - if (s.length > this.length) { - return false; - } - return this.slice(s.length) === s; - }; -} -// ---------------------------------------------------------------------------------------------------------------- -// XSS checks - -NETDATA.xss = { - enabled: (typeof netdataCheckXSS === 'undefined') ? false : netdataCheckXSS, - enabled_for_data: (typeof netdataCheckXSS === 'undefined') ? false : netdataCheckXSS, - - string: function (s) { - return s.toString() - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); - }, - - object: function (name, obj, ignore_regex) { - if (typeof ignore_regex !== 'undefined' && ignore_regex.test(name)) { - // console.log('XSS: ignoring "' + name + '"'); - return obj; - } - - switch (typeof(obj)) { - case 'string': - const ret = this.string(obj); - if (ret !== obj) { - console.log('XSS protection changed string ' + name + ' from "' + obj + '" to "' + ret + '"'); - } - return ret; - - case 'object': - if (obj === null) { - return obj; - } - - if (Array.isArray(obj)) { - // console.log('checking array "' + name + '"'); - - let len = obj.length; - while (len--) { - obj[len] = this.object(name + '[' + len + ']', obj[len], ignore_regex); - } - } else { - // console.log('checking object "' + name + '"'); - - for (var i in obj) { - if (obj.hasOwnProperty(i) === false) { - continue; - } - if (this.string(i) !== i) { - console.log('XSS protection removed invalid object member "' + name + '.' + i + '"'); - delete obj[i]; - } else { - obj[i] = this.object(name + '.' + i, obj[i], ignore_regex); - } - } - } - return obj; - - default: - return obj; - } - }, - - checkOptional: function (name, obj, ignore_regex) { - if (this.enabled) { - //console.log('XSS: checking optional "' + name + '"...'); - return this.object(name, obj, ignore_regex); - } - return obj; - }, - - checkAlways: function (name, obj, ignore_regex) { - //console.log('XSS: checking always "' + name + '"...'); - return this.object(name, obj, ignore_regex); - }, - - checkData: function (name, obj, ignore_regex) { - if (this.enabled_for_data) { - //console.log('XSS: checking data "' + name + '"...'); - return this.object(name, obj, ignore_regex); - } - return obj; - } -}; -NETDATA.colorHex2Rgb = function (hex) { - // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") - let shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; - hex = hex.replace(shorthandRegex, function (m, r, g, b) { - return r + r + g + g + b + b; - }); - - let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); - return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; -}; - -NETDATA.colorLuminance = function (hex, lum) { - // validate hex string - hex = String(hex).replace(/[^0-9a-f]/gi, ''); - if (hex.length < 6) { - hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; - } - - lum = lum || 0; - - // convert to decimal and change luminosity - let rgb = "#"; - for (let i = 0; i < 3; i++) { - let c = parseInt(hex.substr(i * 2, 2), 16); - c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16); - rgb += ("00" + c).substr(c.length); - } - - return rgb; -}; -NETDATA.unitsConversion = { - keys: {}, // keys for data-common-units - latest: {}, // latest selected units for data-common-units - - globalReset: function () { - this.keys = {}; - this.latest = {}; - }, - - scalableUnits: { - 'packets/s': { - 'pps': 1, - 'Kpps': 1000, - 'Mpps': 1000000 - }, - 'pps': { - 'pps': 1, - 'Kpps': 1000, - 'Mpps': 1000000 - }, - 'kilobits/s': { - 'bits/s': 1 / 1000, - 'kilobits/s': 1, - 'megabits/s': 1000, - 'gigabits/s': 1000000, - 'terabits/s': 1000000000 - }, - 'bytes/s': { - 'bytes/s': 1, - 'kilobytes/s': 1024, - 'megabytes/s': 1024 * 1024, - 'gigabytes/s': 1024 * 1024 * 1024, - 'terabytes/s': 1024 * 1024 * 1024 * 1024 - }, - 'kilobytes/s': { - 'bytes/s': 1 / 1024, - 'kilobytes/s': 1, - 'megabytes/s': 1024, - 'gigabytes/s': 1024 * 1024, - 'terabytes/s': 1024 * 1024 * 1024 - }, - 'B/s': { - 'B/s': 1, - 'KiB/s': 1024, - 'MiB/s': 1024 * 1024, - 'GiB/s': 1024 * 1024 * 1024, - 'TiB/s': 1024 * 1024 * 1024 * 1024 - }, - 'KB/s': { - 'B/s': 1 / 1024, - 'KB/s': 1, - 'MB/s': 1024, - 'GB/s': 1024 * 1024, - 'TB/s': 1024 * 1024 * 1024 - }, - 'KiB/s': { - 'B/s': 1 / 1024, - 'KiB/s': 1, - 'MiB/s': 1024, - 'GiB/s': 1024 * 1024, - 'TiB/s': 1024 * 1024 * 1024 - }, - 'B': { - 'B': 1, - 'KiB': 1024, - 'MiB': 1024 * 1024, - 'GiB': 1024 * 1024 * 1024, - 'TiB': 1024 * 1024 * 1024 * 1024, - 'PiB': 1024 * 1024 * 1024 * 1024 * 1024 - }, - 'KB': { - 'B': 1 / 1024, - 'KB': 1, - 'MB': 1024, - 'GB': 1024 * 1024, - 'TB': 1024 * 1024 * 1024 - }, - 'KiB': { - 'B': 1 / 1024, - 'KiB': 1, - 'MiB': 1024, - 'GiB': 1024 * 1024, - 'TiB': 1024 * 1024 * 1024 - }, - 'MB': { - 'B': 1 / (1024 * 1024), - 'KB': 1 / 1024, - 'MB': 1, - 'GB': 1024, - 'TB': 1024 * 1024, - 'PB': 1024 * 1024 * 1024 - }, - 'MiB': { - 'B': 1 / (1024 * 1024), - 'KiB': 1 / 1024, - 'MiB': 1, - 'GiB': 1024, - 'TiB': 1024 * 1024, - 'PiB': 1024 * 1024 * 1024 - }, - 'GB': { - 'B': 1 / (1024 * 1024 * 1024), - 'KB': 1 / (1024 * 1024), - 'MB': 1 / 1024, - 'GB': 1, - 'TB': 1024, - 'PB': 1024 * 1024, - 'EB': 1024 * 1024 * 1024 - }, - 'GiB': { - 'B': 1 / (1024 * 1024 * 1024), - 'KiB': 1 / (1024 * 1024), - 'MiB': 1 / 1024, - 'GiB': 1, - 'TiB': 1024, - 'PiB': 1024 * 1024, - 'EiB': 1024 * 1024 * 1024 - }, - 'num': { - 'num': 1, - 'num (K)': 1000, - 'num (M)': 1000000, - 'num (G)': 1000000000, - 'num (T)': 1000000000000 - } - /* - 'milliseconds': { - 'seconds': 1000 - }, - 'seconds': { - 'milliseconds': 0.001, - 'seconds': 1, - 'minutes': 60, - 'hours': 3600, - 'days': 86400 - } - */ - }, - - convertibleUnits: { - 'Celsius': { - 'Fahrenheit': { - check: function (max) { - void(max); - return NETDATA.options.current.temperature === 'fahrenheit'; - }, - convert: function (value) { - return value * 9 / 5 + 32; - } - } - }, - 'celsius': { - 'fahrenheit': { - check: function (max) { - void(max); - return NETDATA.options.current.temperature === 'fahrenheit'; - }, - convert: function (value) { - return value * 9 / 5 + 32; - } - } - }, - 'seconds': { - 'time': { - check: function (max) { - void(max); - return NETDATA.options.current.seconds_as_time; - }, - convert: function (seconds) { - return NETDATA.unitsConversion.seconds2time(seconds); - } - } - }, - 'milliseconds': { - 'milliseconds': { - check: function (max) { - return NETDATA.options.current.seconds_as_time && max < 1000; - }, - convert: function (milliseconds) { - let tms = Math.round(milliseconds * 10); - milliseconds = Math.floor(tms / 10); - - tms -= milliseconds * 10; - - return (milliseconds).toString() + '.' + tms.toString(); - } - }, - 'seconds': { - check: function (max) { - return NETDATA.options.current.seconds_as_time && max >= 1000 && max < 60000; - }, - convert: function (milliseconds) { - milliseconds = Math.round(milliseconds); - - let seconds = Math.floor(milliseconds / 1000); - milliseconds -= seconds * 1000; - - milliseconds = Math.round(milliseconds / 10); - - return seconds.toString() + '.' - + NETDATA.zeropad(milliseconds); - } - }, - 'M:SS.ms': { - check: function (max) { - return NETDATA.options.current.seconds_as_time && max >= 60000; - }, - convert: function (milliseconds) { - milliseconds = Math.round(milliseconds); - - let minutes = Math.floor(milliseconds / 60000); - milliseconds -= minutes * 60000; - - let seconds = Math.floor(milliseconds / 1000); - milliseconds -= seconds * 1000; - - milliseconds = Math.round(milliseconds / 10); - - return minutes.toString() + ':' - + NETDATA.zeropad(seconds) + '.' - + NETDATA.zeropad(milliseconds); - } - } - }, - 'nanoseconds': { - 'nanoseconds': { - check: function (max) { - return NETDATA.options.current.seconds_as_time && max < 1000; - }, - convert: function (nanoseconds) { - let tms = Math.round(nanoseconds * 10); - nanoseconds = Math.floor(tms / 10); - - tms -= nanoseconds * 10; - - return (nanoseconds).toString() + '.' + tms.toString(); - } - }, - 'microseconds': { - check: function (max) { - return NETDATA.options.current.seconds_as_time - && max >= 1000 && max < 1000 * 1000; - }, - convert: function (nanoseconds) { - nanoseconds = Math.round(nanoseconds); - - let microseconds = Math.floor(nanoseconds / 1000); - nanoseconds -= microseconds * 1000; - - nanoseconds = Math.round(nanoseconds / 10 ); - - return microseconds.toString() + '.' - + NETDATA.zeropad(nanoseconds); - } - }, - 'milliseconds': { - check: function (max) { - return NETDATA.options.current.seconds_as_time - && max >= 1000 * 1000 && max < 1000 * 1000 * 1000; - }, - convert: function (nanoseconds) { - nanoseconds = Math.round(nanoseconds); - - let milliseconds = Math.floor(nanoseconds / 1000 / 1000); - nanoseconds -= milliseconds * 1000 * 1000; - - nanoseconds = Math.round(nanoseconds / 1000 / 10); - - return milliseconds.toString() + '.' - + NETDATA.zeropad(nanoseconds); - } - }, - 'seconds': { - check: function (max) { - return NETDATA.options.current.seconds_as_time - && max >= 1000 * 1000 * 1000; - }, - convert: function (nanoseconds) { - nanoseconds = Math.round(nanoseconds); - - let seconds = Math.floor(nanoseconds / 1000 / 1000 / 1000); - nanoseconds -= seconds * 1000 * 1000 * 1000; - - nanoseconds = Math.round(nanoseconds / 1000 / 1000 / 10); - - return seconds.toString() + '.' - + NETDATA.zeropad(nanoseconds); - } - }, - } - }, - - seconds2time: function (seconds) { - seconds = Math.abs(seconds); - - let days = Math.floor(seconds / 86400); - seconds -= days * 86400; - - let hours = Math.floor(seconds / 3600); - seconds -= hours * 3600; - - let minutes = Math.floor(seconds / 60); - seconds -= minutes * 60; - - seconds = Math.round(seconds); - - let ms_txt = ''; - /* - let ms = seconds - Math.floor(seconds); - seconds -= ms; - ms = Math.round(ms * 1000); - - if (ms > 1) { - if (ms < 10) - ms_txt = '.00' + ms.toString(); - else if (ms < 100) - ms_txt = '.0' + ms.toString(); - else - ms_txt = '.' + ms.toString(); - } - */ - - return ((days > 0) ? days.toString() + 'd:' : '').toString() - + NETDATA.zeropad(hours) + ':' - + NETDATA.zeropad(minutes) + ':' - + NETDATA.zeropad(seconds) - + ms_txt; - }, - - // get a function that converts the units - // + every time units are switched call the callback - get: function (uuid, min, max, units, desired_units, common_units_name, switch_units_callback) { - // validate the parameters - if (typeof units === 'undefined') { - units = 'undefined'; - } - - // check if we support units conversion - if (typeof this.scalableUnits[units] === 'undefined' && typeof this.convertibleUnits[units] === 'undefined') { - // we can't convert these units - //console.log('DEBUG: ' + uuid.toString() + ' can\'t convert units: ' + units.toString()); - return function (value) { - return value; - }; - } - - // check if the caller wants the original units - if (typeof desired_units === 'undefined' || desired_units === null || desired_units === 'original' || desired_units === units) { - //console.log('DEBUG: ' + uuid.toString() + ' original units wanted'); - switch_units_callback(units); - return function (value) { - return value; - }; - } - - // now we know we can convert the units - // and the caller wants some kind of conversion - - let tunits = null; - let tdivider = 0; - - if (typeof this.scalableUnits[units] !== 'undefined') { - // units that can be scaled - // we decide a divider - - // console.log('NETDATA.unitsConversion.get(' + units.toString() + ', ' + desired_units.toString() + ', function()) decide divider with min = ' + min.toString() + ', max = ' + max.toString()); - - if (desired_units === 'auto') { - // the caller wants to auto-scale the units - - // find the absolute maximum value that is rendered on the chart - // based on this we decide the scale - min = Math.abs(min); - max = Math.abs(max); - if (min > max) { - max = min; - } - - // find the smallest scale that provides integers - // for (x in this.scalableUnits[units]) { - // if (this.scalableUnits[units].hasOwnProperty(x)) { - // let m = this.scalableUnits[units][x]; - // if (m <= max && m > tdivider) { - // tunits = x; - // tdivider = m; - // } - // } - // } - const sunit = this.scalableUnits[units]; - for (var x of Object.keys(sunit)) { - let m = sunit[x]; - if (m <= max && m > tdivider) { - tunits = x; - tdivider = m; - } - } - - if (tunits === null || tdivider <= 0) { - // we couldn't find one - //console.log('DEBUG: ' + uuid.toString() + ' cannot find an auto-scaling candidate for units: ' + units.toString() + ' (max: ' + max.toString() + ')'); - switch_units_callback(units); - return function (value) { - return value; - }; - } - - if (typeof common_units_name === 'string' && typeof uuid === 'string') { - // the caller wants several charts to have the same units - // data-common-units - - let common_units_key = common_units_name + '-' + units; - - // add our divider into the list of keys - let t = this.keys[common_units_key]; - if (typeof t === 'undefined') { - this.keys[common_units_key] = {}; - t = this.keys[common_units_key]; - } - t[uuid] = { - units: tunits, - divider: tdivider - }; - - // find the max divider of all charts - let common_units = t[uuid]; - for (var x in t) { - if (t.hasOwnProperty(x) && t[x].divider > common_units.divider) { - common_units = t[x]; - } - } - - // save our common_max to the latest keys - let latest = this.latest[common_units_key]; - if (typeof latest === 'undefined') { - this.latest[common_units_key] = {}; - latest = this.latest[common_units_key]; - } - latest.units = common_units.units; - latest.divider = common_units.divider; - - tunits = latest.units; - tdivider = latest.divider; - - //console.log('DEBUG: ' + uuid.toString() + ' converted units: ' + units.toString() + ' to units: ' + tunits.toString() + ' with divider ' + tdivider.toString() + ', common-units=' + common_units_name.toString() + ((t[uuid].divider !== tdivider)?' USED COMMON, mine was ' + t[uuid].units:' set common').toString()); - - // apply it to this chart - switch_units_callback(tunits); - return function (value) { - if (tdivider !== latest.divider) { - // another chart switched our common units - // we should switch them too - //console.log('DEBUG: ' + uuid + ' switching units due to a common-units change, from ' + tunits.toString() + ' to ' + latest.units.toString()); - tunits = latest.units; - tdivider = latest.divider; - switch_units_callback(tunits); - } - - return value / tdivider; - }; - } else { - // the caller did not give data-common-units - // this chart auto-scales independently of all others - //console.log('DEBUG: ' + uuid.toString() + ' converted units: ' + units.toString() + ' to units: ' + tunits.toString() + ' with divider ' + tdivider.toString() + ', autonomously'); - - switch_units_callback(tunits); - return function (value) { - return value / tdivider; - }; - } - } else { - // the caller wants specific units - - if (typeof this.scalableUnits[units][desired_units] !== 'undefined') { - // all good, set the new units - tdivider = this.scalableUnits[units][desired_units]; - // console.log('DEBUG: ' + uuid.toString() + ' converted units: ' + units.toString() + ' to units: ' + desired_units.toString() + ' with divider ' + tdivider.toString() + ', by reference'); - switch_units_callback(desired_units); - return function (value) { - return value / tdivider; - }; - } else { - // oops! switch back to original units - console.log('Units conversion from ' + units.toString() + ' to ' + desired_units.toString() + ' is not supported.'); - switch_units_callback(units); - return function (value) { - return value; - }; - } - } - } else if (typeof this.convertibleUnits[units] !== 'undefined') { - // units that can be converted - if (desired_units === 'auto') { - for (var x in this.convertibleUnits[units]) { - if (this.convertibleUnits[units].hasOwnProperty(x)) { - if (this.convertibleUnits[units][x].check(max)) { - //console.log('DEBUG: ' + uuid.toString() + ' converting ' + units.toString() + ' to: ' + x.toString()); - switch_units_callback(x); - return this.convertibleUnits[units][x].convert; - } - } - } - - // none checked ok - //console.log('DEBUG: ' + uuid.toString() + ' no conversion available for ' + units.toString() + ' to: ' + desired_units.toString()); - switch_units_callback(units); - return function (value) { - return value; - }; - } else if (typeof this.convertibleUnits[units][desired_units] !== 'undefined') { - switch_units_callback(desired_units); - return this.convertibleUnits[units][desired_units].convert; - } else { - console.log('Units conversion from ' + units.toString() + ' to ' + desired_units.toString() + ' is not supported.'); - switch_units_callback(units); - return function (value) { - return value; - }; - } - } else { - // hm... did we forget to implement the new type? - console.log(`Unmatched unit conversion method for units ${units.toString()}`); - switch_units_callback(units); - return function (value) { - return value; - }; - } - } -}; - -NETDATA.icons = { - left: '', - reset: '', - right: '', - zoomIn: '', - zoomOut: '', - resize: '', - lineChart: '', - areaChart: '', - noChart: '', - loading: '', - noData: '' -}; - -if (typeof netdataIcons === 'object') { - // for (let icon in NETDATA.icons) { - // if (NETDATA.icons.hasOwnProperty(icon) && typeof(netdataIcons[icon]) === 'string') - // NETDATA.icons[icon] = netdataIcons[icon]; - // } - for (var icon of Object.keys(NETDATA.icons)) { - if (typeof(netdataIcons[icon]) === 'string') { - NETDATA.icons[icon] = netdataIcons[icon] - } - } -} - -if (typeof netdataSnapshotData === 'undefined') { - netdataSnapshotData = null; -} - -if (typeof netdataShowHelp === 'undefined') { - netdataShowHelp = true; -} - -if (typeof netdataShowAlarms === 'undefined') { - netdataShowAlarms = false; -} - -if (typeof netdataRegistryAfterMs !== 'number' || netdataRegistryAfterMs < 0) { - netdataRegistryAfterMs = 0; // 1500; -} - -if (typeof netdataRegistry === 'undefined') { - // backward compatibility - netdataRegistry = (typeof netdataNoRegistry !== 'undefined' && netdataNoRegistry === false); -} - -if (netdataRegistry === false && typeof netdataRegistryCallback === 'function') { - netdataRegistry = true; -} - -// ---------------------------------------------------------------------------------------------------------------- -// the defaults for all charts - -// if the user does not specify any of these, the following will be used - -NETDATA.chartDefaults = { - width: '100%', // the chart width - can be null - height: '100%', // the chart height - can be null - min_width: null, // the chart minimum width - can be null - library: 'dygraph', // the graphing library to use - method: 'average', // the grouping method - before: 0, // panning - after: -600, // panning - pixels_per_point: 1, // the detail of the chart - fill_luminance: 0.8 // luminance of colors in solid areas -}; - -// ---------------------------------------------------------------------------------------------------------------- -// global options - -NETDATA.options = { - pauseCallback: null, // a callback when we are really paused - - pause: false, // when enabled we don't auto-refresh the charts - - targets: [], // an array of all the state objects that are - // currently active (independently of their - // viewport visibility) - - updated_dom: true, // when true, the DOM has been updated with - // new elements we have to check. - - auto_refresher_fast_weight: 0, // this is the current time in ms, spent - // rendering charts continuously. - // used with .current.fast_render_timeframe - - page_is_visible: true, // when true, this page is visible - - auto_refresher_stop_until: 0, // timestamp in ms - used internally, to stop the - // auto-refresher for some time (when a chart is - // performing pan or zoom, we need to stop refreshing - // all other charts, to have the maximum speed for - // rendering the chart that is panned or zoomed). - // Used with .current.global_pan_sync_time - - on_scroll_refresher_stop_until: 0, // timestamp in ms - used to stop evaluating - // charts for some time, after a page scroll - - last_page_resize: Date.now(), // the timestamp of the last resize request - - last_page_scroll: 0, // the timestamp the last time the page was scrolled - - browser_timezone: 'unknown', // timezone detected by javascript - server_timezone: 'unknown', // timezone reported by the server - - force_data_points: 0, // force the number of points to be returned for charts - fake_chart_rendering: false, // when set to true, the dashboard will download data but will not render the charts - - passive_events: null, // true if the browser supports passive events - - // the current profile - // we may have many... - current: { - units: 'auto', // can be 'auto' or 'original' - temperature: 'celsius', // can be 'celsius' or 'fahrenheit' - seconds_as_time: true, // show seconds as DDd:HH:MM:SS ? - timezone: 'default', // the timezone to use, or 'default' - user_set_server_timezone: 'default', // as set by the user on the dashboard - - legend_toolbox: true, // show the legend toolbox on charts - resize_charts: true, // show the resize handler on charts - - pixels_per_point: isSlowDevice() ? 5 : 1, // the minimum pixels per point for all charts - // increase this to speed javascript up - // each chart library has its own limit too - // the max of this and the chart library is used - // the final is calculated every time, so a change - // here will have immediate effect on the next chart - // update - - idle_between_charts: 100, // ms - how much time to wait between chart updates - - fast_render_timeframe: 200, // ms - render continuously until this time of continuous - // rendering has been reached - // this setting is used to make it render e.g. 10 - // charts at once, sleep idle_between_charts time - // and continue for another 10 charts. - - idle_between_loops: 500, // ms - if all charts have been updated, wait this - // time before starting again. - - idle_parallel_loops: 100, // ms - the time between parallel refresher updates - - idle_lost_focus: 500, // ms - when the window does not have focus, check - // if focus has been regained, every this time - - global_pan_sync_time: 300, // ms - when you pan or zoom a chart, the background - // auto-refreshing of charts is paused for this amount - // of time - - sync_selection_delay: 400, // ms - when you pan or zoom a chart, wait this amount - // of time before setting up synchronized selections - // on hover. - - sync_selection: true, // enable or disable selection sync - - pan_and_zoom_delay: 50, // when panning or zooming, how ofter to update the chart - - sync_pan_and_zoom: true, // enable or disable pan and zoom sync - - pan_and_zoom_data_padding: true, // fetch more data for the master chart when panning or zooming - - update_only_visible: true, // enable or disable visibility management / used for printing - - parallel_refresher: !isSlowDevice(), // enable parallel refresh of charts - - concurrent_refreshes: true, // when parallel_refresher is enabled, sync also the charts - - destroy_on_hide: isSlowDevice(), // destroy charts when they are not visible - - show_help: netdataShowHelp, // when enabled the charts will show some help - show_help_delay_show_ms: 500, - show_help_delay_hide_ms: 0, - - eliminate_zero_dimensions: true, // do not show dimensions with just zeros - - stop_updates_when_focus_is_lost: true, // boolean - shall we stop auto-refreshes when document does not have user focus - stop_updates_while_resizing: 1000, // ms - time to stop auto-refreshes while resizing the charts - - double_click_speed: 500, // ms - time between clicks / taps to detect double click/tap - - smooth_plot: !isSlowDevice(), // enable smooth plot, where possible - - color_fill_opacity_line: 1.0, - color_fill_opacity_area: 0.2, - color_fill_opacity_stacked: 0.8, - - pan_and_zoom_factor: 0.25, // the increment when panning and zooming with the toolbox - pan_and_zoom_factor_multiplier_control: 2.0, - pan_and_zoom_factor_multiplier_shift: 3.0, - pan_and_zoom_factor_multiplier_alt: 4.0, - - abort_ajax_on_scroll: false, // kill pending ajax page scroll - async_on_scroll: false, // sync/async onscroll handler - onscroll_worker_duration_threshold: 30, // time in ms, for async scroll handler - - retries_on_data_failures: 3, // how many retries to make if we can't fetch chart data from the server - - setOptionCallback: function () { - } - }, - - debug: { - show_boxes: false, - main_loop: false, - focus: false, - visibility: false, - chart_data_url: false, - chart_errors: true, // remember to set it to false before merging - chart_timing: false, - chart_calls: false, - libraries: false, - dygraph: false, - globalSelectionSync: false, - globalPanAndZoom: false - } -}; - -NETDATA.statistics = { - refreshes_total: 0, - refreshes_active: 0, - refreshes_active_max: 0 -}; - -// local storage options - -NETDATA.localStorage = { - default: {}, - current: {}, - callback: {} // only used for resetting back to defaults -}; - -NETDATA.localStorageTested = -1; -NETDATA.localStorageTest = function () { - if (NETDATA.localStorageTested !== -1) { - return NETDATA.localStorageTested; - } - - if (typeof Storage !== "undefined" && typeof localStorage === 'object') { - let test = 'test'; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - NETDATA.localStorageTested = true; - } catch (e) { - NETDATA.localStorageTested = false; - } - } else { - NETDATA.localStorageTested = false; - } - - return NETDATA.localStorageTested; -}; - -NETDATA.localStorageGet = function (key, def, callback) { - let ret = def; - - if (typeof NETDATA.localStorage.default[key.toString()] === 'undefined') { - NETDATA.localStorage.default[key.toString()] = def; - NETDATA.localStorage.callback[key.toString()] = callback; - } - - if (NETDATA.localStorageTest()) { - try { - // console.log('localStorage: loading "' + key.toString() + '"'); - ret = localStorage.getItem(key.toString()); - // console.log('netdata loaded: ' + key.toString() + ' = ' + ret.toString()); - if (ret === null || ret === 'undefined') { - // console.log('localStorage: cannot load it, saving "' + key.toString() + '" with value "' + JSON.stringify(def) + '"'); - localStorage.setItem(key.toString(), JSON.stringify(def)); - ret = def; - } else { - // console.log('localStorage: got "' + key.toString() + '" with value "' + ret + '"'); - ret = JSON.parse(ret); - // console.log('localStorage: loaded "' + key.toString() + '" as value ' + ret + ' of type ' + typeof(ret)); - } - } catch (error) { - console.log('localStorage: failed to read "' + key.toString() + '", using default: "' + def.toString() + '"'); - ret = def; - } - } - - if (typeof ret === 'undefined' || ret === 'undefined') { - console.log('localStorage: LOADED UNDEFINED "' + key.toString() + '" as value ' + ret + ' of type ' + typeof(ret)); - ret = def; - } - - NETDATA.localStorage.current[key.toString()] = ret; - return ret; -}; - -NETDATA.localStorageSet = function (key, value, callback) { - if (typeof value === 'undefined' || value === 'undefined') { - console.log('localStorage: ATTEMPT TO SET UNDEFINED "' + key.toString() + '" as value ' + value + ' of type ' + typeof(value)); - } - - if (typeof NETDATA.localStorage.default[key.toString()] === 'undefined') { - NETDATA.localStorage.default[key.toString()] = value; - NETDATA.localStorage.current[key.toString()] = value; - NETDATA.localStorage.callback[key.toString()] = callback; - } - - if (NETDATA.localStorageTest()) { - // console.log('localStorage: saving "' + key.toString() + '" with value "' + JSON.stringify(value) + '"'); - try { - localStorage.setItem(key.toString(), JSON.stringify(value)); - } catch (e) { - console.log('localStorage: failed to save "' + key.toString() + '" with value: "' + value.toString() + '"'); - } - } - - NETDATA.localStorage.current[key.toString()] = value; - return value; -}; - -NETDATA.localStorageGetRecursive = function (obj, prefix, callback) { - let keys = Object.keys(obj); - let len = keys.length; - while (len--) { - let i = keys[len]; - - if (typeof obj[i] === 'object') { - //console.log('object ' + prefix + '.' + i.toString()); - NETDATA.localStorageGetRecursive(obj[i], prefix + '.' + i.toString(), callback); - continue; - } - - obj[i] = NETDATA.localStorageGet(prefix + '.' + i.toString(), obj[i], callback); - } -}; - -NETDATA.setOption = function (key, value) { - if (key.toString() === 'setOptionCallback') { - if (typeof NETDATA.options.current.setOptionCallback === 'function') { - NETDATA.options.current[key.toString()] = value; - NETDATA.options.current.setOptionCallback(); - } - } else if (NETDATA.options.current[key.toString()] !== value) { - let name = 'options.' + key.toString(); - - if (typeof NETDATA.localStorage.default[name.toString()] === 'undefined') { - console.log('localStorage: setOption() on unsaved option: "' + name.toString() + '", value: ' + value); - } - - //console.log(NETDATA.localStorage); - //console.log('setOption: setting "' + key.toString() + '" to "' + value + '" of type ' + typeof(value) + ' original type ' + typeof(NETDATA.options.current[key.toString()])); - //console.log(NETDATA.options); - NETDATA.options.current[key.toString()] = NETDATA.localStorageSet(name.toString(), value, null); - - if (typeof NETDATA.options.current.setOptionCallback === 'function') { - NETDATA.options.current.setOptionCallback(); - } - } - - return true; -}; - -NETDATA.getOption = function (key) { - return NETDATA.options.current[key.toString()]; -}; - -// read settings from local storage -NETDATA.localStorageGetRecursive(NETDATA.options.current, 'options', null); - -// always start with this option enabled. -NETDATA.setOption('stop_updates_when_focus_is_lost', true); - -NETDATA.resetOptions = function () { - let keys = Object.keys(NETDATA.localStorage.default); - let len = keys.length; - - while (len--) { - let i = keys[len]; - let a = i.split('.'); - - if (a[0] === 'options') { - if (a[1] === 'setOptionCallback') { - continue; - } - if (typeof NETDATA.localStorage.default[i] === 'undefined') { - continue; - } - if (NETDATA.options.current[i] === NETDATA.localStorage.default[i]) { - continue; - } - - NETDATA.setOption(a[1], NETDATA.localStorage.default[i]); - } else if (a[0] === 'chart_heights') { - if (typeof NETDATA.localStorage.callback[i] === 'function' && typeof NETDATA.localStorage.default[i] !== 'undefined') { - NETDATA.localStorage.callback[i](NETDATA.localStorage.default[i]); - } - } - } - - NETDATA.dateTime.init(NETDATA.options.current.timezone); -}; - -// *** src/dashboard.js/timeout.js - -// TODO: Better name needed - -NETDATA.timeout = { - // by default, these are just wrappers to setTimeout() / clearTimeout() - - step: function (callback) { - return window.setTimeout(callback, 1000 / 60); - }, - - set: function (callback, delay) { - return window.setTimeout(callback, delay); - }, - - clear: function (id) { - return window.clearTimeout(id); - }, - - init: function () { - let custom = true; - - if (window.requestAnimationFrame) { - this.step = function (callback) { - return window.requestAnimationFrame(callback); - }; - - this.clear = function (handle) { - return window.cancelAnimationFrame(handle.value); - }; - // } else if (window.webkitRequestAnimationFrame) { - // this.step = function (callback) { - // return window.webkitRequestAnimationFrame(callback); - // }; - - // if (window.webkitCancelAnimationFrame) { - // this.clear = function (handle) { - // return window.webkitCancelAnimationFrame(handle.value); - // }; - // } else if (window.webkitCancelRequestAnimationFrame) { - // this.clear = function (handle) { - // return window.webkitCancelRequestAnimationFrame(handle.value); - // }; - // } - // } else if (window.mozRequestAnimationFrame) { - // this.step = function (callback) { - // return window.mozRequestAnimationFrame(callback); - // }; - - // this.clear = function (handle) { - // return window.mozCancelRequestAnimationFrame(handle.value); - // }; - // } else if (window.oRequestAnimationFrame) { - // this.step = function (callback) { - // return window.oRequestAnimationFrame(callback); - // }; - - // this.clear = function (handle) { - // return window.oCancelRequestAnimationFrame(handle.value); - // }; - // } else if (window.msRequestAnimationFrame) { - // this.step = function (callback) { - // return window.msRequestAnimationFrame(callback); - // }; - - // this.clear = function (handle) { - // return window.msCancelRequestAnimationFrame(handle.value); - // }; - } else { - custom = false; - } - - if (custom) { - // we have installed custom .step() / .clear() functions - // overwrite the .set() too - - this.set = function (callback, delay) { - let start = Date.now(), - handle = new Object(); - - const loop = () => { - let current = Date.now(), - delta = current - start; - - if (delta >= delay) { - callback.call(); - } else { - handle.value = this.step(loop); - } - } - - handle.value = this.step(loop); - return handle; - }; - } - } -}; - -NETDATA.timeout.init(); -// Codacy declarations -/* global netdataTheme */ - -NETDATA.themes = { - white: { - bootstrap_css: NETDATA.serverStatic + 'css/bootstrap-3.3.7.css', - dashboard_css: NETDATA.serverStatic + 'dashboard.css?v20190902-0', - background: '#FFFFFF', - foreground: '#000000', - grid: '#F0F0F0', - axis: '#F0F0F0', - highlight: '#F5F5F5', - colors: ['#3366CC', '#DC3912', '#109618', '#FF9900', '#990099', '#DD4477', - '#3B3EAC', '#66AA00', '#0099C6', '#B82E2E', '#AAAA11', '#5574A6', - '#994499', '#22AA99', '#6633CC', '#E67300', '#316395', '#8B0707', - '#329262', '#3B3EAC'], - easypiechart_track: '#f0f0f0', - easypiechart_scale: '#dfe0e0', - gauge_pointer: '#C0C0C0', - gauge_stroke: '#F0F0F0', - gauge_gradient: false, - d3pie: { - title: '#333333', - subtitle: '#666666', - footer: '#888888', - other: '#aaaaaa', - mainlabel: '#333333', - percentage: '#dddddd', - value: '#aaaa22', - tooltip_bg: '#000000', - tooltip_fg: '#efefef', - segment_stroke: "#ffffff", - gradient_color: '#000000' - } - }, - slate: { - bootstrap_css: NETDATA.serverStatic + 'css/bootstrap-slate-flat-3.3.7.css?v20161229-1', - dashboard_css: NETDATA.serverStatic + 'dashboard.slate.css?v20190902-0', - background: '#272b30', - foreground: '#C8C8C8', - grid: '#283236', - axis: '#283236', - highlight: '#383838', - /* colors: [ '#55bb33', '#ff2222', '#0099C6', '#faa11b', '#adbce0', '#DDDD00', - '#4178ba', '#f58122', '#a5cc39', '#f58667', '#f5ef89', '#cf93c0', - '#a5d18a', '#b8539d', '#3954a3', '#c8a9cf', '#c7de8a', '#fad20a', - '#a6a479', '#a66da8' ], - */ - colors: ['#66AA00', '#FE3912', '#3366CC', '#D66300', '#0099C6', '#DDDD00', - '#5054e6', '#EE9911', '#BB44CC', '#e45757', '#ef0aef', '#CC7700', - '#22AA99', '#109618', '#905bfd', '#f54882', '#4381bf', '#ff3737', - '#329262', '#3B3EFF'], - easypiechart_track: '#373b40', - easypiechart_scale: '#373b40', - gauge_pointer: '#474b50', - gauge_stroke: '#373b40', - gauge_gradient: false, - d3pie: { - title: '#C8C8C8', - subtitle: '#283236', - footer: '#283236', - other: '#283236', - mainlabel: '#C8C8C8', - percentage: '#dddddd', - value: '#cccc44', - tooltip_bg: '#272b30', - tooltip_fg: '#C8C8C8', - segment_stroke: "#283236", - gradient_color: '#000000' - } - } -}; - -if (typeof netdataTheme !== 'undefined' && typeof NETDATA.themes[netdataTheme] !== 'undefined') { - NETDATA.themes.current = NETDATA.themes[netdataTheme]; -} else { - NETDATA.themes.current = NETDATA.themes.white; -} - -NETDATA.colors = NETDATA.themes.current.colors; - -// these are the colors Google Charts are using -// we have them here to attempt emulate their look and feel on the other chart libraries -// http://there4.io/2012/05/02/google-chart-color-list/ -//NETDATA.colors = [ '#3366CC', '#DC3912', '#FF9900', '#109618', '#990099', '#3B3EAC', '#0099C6', -// '#DD4477', '#66AA00', '#B82E2E', '#316395', '#994499', '#22AA99', '#AAAA11', -// '#6633CC', '#E67300', '#8B0707', '#329262', '#5574A6', '#3B3EAC' ]; - -// an alternative set -// http://www.mulinblog.com/a-color-palette-optimized-for-data-visualization/ -// (blue) (red) (orange) (green) (pink) (brown) (purple) (yellow) (gray) -//NETDATA.colors = [ '#5DA5DA', '#F15854', '#FAA43A', '#60BD68', '#F17CB0', '#B2912F', '#B276B2', '#DECF3F', '#4D4D4D' ]; -// dygraph - -// Codacy declarations -/* global smoothPlotter */ -/* global Dygraph */ - -NETDATA.dygraph = { - smooth: false -}; - -NETDATA.dygraphToolboxPanAndZoom = function (state, after, before) { - if (after < state.netdata_first) { - after = state.netdata_first; - } - - if (before > state.netdata_last) { - before = state.netdata_last; - } - - state.setMode('zoom'); - NETDATA.globalSelectionSync.stop(); - NETDATA.globalSelectionSync.delay(); - state.tmp.dygraph_user_action = true; - state.tmp.dygraph_force_zoom = true; - // state.log('toolboxPanAndZoom'); - state.updateChartPanOrZoom(after, before); - NETDATA.globalPanAndZoom.setMaster(state, after, before); -}; - -NETDATA.dygraphSetSelection = function (state, t) { - if (typeof state.tmp.dygraph_instance !== 'undefined') { - let r = state.calculateRowForTime(t); - if (r !== -1) { - state.tmp.dygraph_instance.setSelection(r); - return true; - } else { - state.tmp.dygraph_instance.clearSelection(); - state.legendShowUndefined(); - } - } - - return false; -}; - -NETDATA.dygraphClearSelection = function (state) { - if (typeof state.tmp.dygraph_instance !== 'undefined') { - state.tmp.dygraph_instance.clearSelection(); - } - return true; -}; - -NETDATA.dygraphSmoothInitialize = function (callback) { - $.ajax({ - url: NETDATA.dygraph_smooth_js, - cache: true, - dataType: "script", - xhrFields: {withCredentials: true} // required for the cookie - }) - .done(function () { - NETDATA.dygraph.smooth = true; - smoothPlotter.smoothing = 0.3; - }) - .fail(function () { - NETDATA.dygraph.smooth = false; - }) - .always(function () { - if (typeof callback === "function") { - return callback(); - } - }); -}; - -NETDATA.dygraphInitialize = function (callback) { - if (typeof netdataNoDygraphs === 'undefined' || !netdataNoDygraphs) { - $.ajax({ - url: NETDATA.dygraph_js, - cache: true, - dataType: "script", - xhrFields: {withCredentials: true} // required for the cookie - }) - .done(function () { - NETDATA.registerChartLibrary('dygraph', NETDATA.dygraph_js); - }) - .fail(function () { - NETDATA.chartLibraries.dygraph.enabled = false; - NETDATA.error(100, NETDATA.dygraph_js); - }) - .always(function () { - if (NETDATA.chartLibraries.dygraph.enabled && NETDATA.options.current.smooth_plot) { - NETDATA.dygraphSmoothInitialize(callback); - } else if (typeof callback === "function") { - return callback(); - } - }); - } else { - NETDATA.chartLibraries.dygraph.enabled = false; - if (typeof callback === "function") { - return callback(); - } - } -}; - -NETDATA.dygraphChartUpdate = function (state, data) { - let dygraph = state.tmp.dygraph_instance; - - if (typeof dygraph === 'undefined') { - return NETDATA.dygraphChartCreate(state, data); - } - - // when the chart is not visible, and hidden - // if there is a window resize, dygraph detects - // its element size as 0x0. - // this will make it re-appear properly - - if (state.tm.last_unhidden > state.tmp.dygraph_last_rendered) { - dygraph.resize(); - } - - let options = { - file: data.result.data, - colors: state.chartColors(), - labels: data.result.labels, - //labelsDivWidth: state.chartWidth() - 70, - includeZero: state.tmp.dygraph_include_zero, - visibility: state.dimensions_visibility.selected2BooleanArray(state.data.dimension_names) - }; - - if (state.tmp.dygraph_chart_type === 'stacked') { - if (options.includeZero && state.dimensions_visibility.countSelected() < options.visibility.length) { - options.includeZero = 0; - } - } - - if (!NETDATA.chartLibraries.dygraph.isSparkline(state)) { - options.ylabel = state.units_current; // (state.units_desired === 'auto')?"":state.units_current; - } - - if (state.tmp.dygraph_force_zoom) { - if (NETDATA.options.debug.dygraph || state.debug) { - state.log('dygraphChartUpdate() forced zoom update'); - } - - options.dateWindow = (state.requested_padding !== null) ? [state.view_after, state.view_before] : null; - //options.isZoomedIgnoreProgrammaticZoom = true; - state.tmp.dygraph_force_zoom = false; - } else if (state.current.name !== 'auto') { - if (NETDATA.options.debug.dygraph || state.debug) { - state.log('dygraphChartUpdate() loose update'); - } - } else { - if (NETDATA.options.debug.dygraph || state.debug) { - state.log('dygraphChartUpdate() strict update'); - } - - options.dateWindow = (state.requested_padding !== null) ? [state.view_after, state.view_before] : null; - //options.isZoomedIgnoreProgrammaticZoom = true; - } - - options.valueRange = state.tmp.dygraph_options.valueRange; - - let oldMax = null, oldMin = null; - if (state.tmp.__commonMin !== null) { - state.data.min = state.tmp.dygraph_instance.axes_[0].extremeRange[0]; - oldMin = options.valueRange[0] = NETDATA.commonMin.get(state); - } - if (state.tmp.__commonMax !== null) { - state.data.max = state.tmp.dygraph_instance.axes_[0].extremeRange[1]; - oldMax = options.valueRange[1] = NETDATA.commonMax.get(state); - } - - if (state.tmp.dygraph_smooth_eligible) { - if ((NETDATA.options.current.smooth_plot && state.tmp.dygraph_options.plotter !== smoothPlotter) - || (NETDATA.options.current.smooth_plot === false && state.tmp.dygraph_options.plotter === smoothPlotter)) { - NETDATA.dygraphChartCreate(state, data); - return; - } - } - - if (netdataSnapshotData !== null && NETDATA.globalPanAndZoom.isActive() && NETDATA.globalPanAndZoom.isMaster(state) === false) { - // pan and zoom on snapshots - options.dateWindow = [NETDATA.globalPanAndZoom.force_after_ms, NETDATA.globalPanAndZoom.force_before_ms]; - //options.isZoomedIgnoreProgrammaticZoom = true; - } - - if (NETDATA.chartLibraries.dygraph.isLogScale(state)) { - if (Array.isArray(options.valueRange) && options.valueRange[0] <= 0) { - options.valueRange[0] = null; - } - } - - dygraph.updateOptions(options); - - let redraw = false; - if (oldMin !== null && oldMin > state.tmp.dygraph_instance.axes_[0].extremeRange[0]) { - state.data.min = state.tmp.dygraph_instance.axes_[0].extremeRange[0]; - options.valueRange[0] = NETDATA.commonMin.get(state); - redraw = true; - } - if (oldMax !== null && oldMax < state.tmp.dygraph_instance.axes_[0].extremeRange[1]) { - state.data.max = state.tmp.dygraph_instance.axes_[0].extremeRange[1]; - options.valueRange[1] = NETDATA.commonMax.get(state); - redraw = true; - } - - if (redraw) { - // state.log('forcing redraw to adapt to common- min/max'); - dygraph.updateOptions(options); - } - - state.tmp.dygraph_last_rendered = Date.now(); - return true; -}; - -NETDATA.dygraphChartCreate = function (state, data) { - if (NETDATA.options.debug.dygraph || state.debug) { - state.log('dygraphChartCreate()'); - } - - state.tmp.dygraph_chart_type = NETDATA.dataAttribute(state.element, 'dygraph-type', state.chart.chart_type); - if (state.tmp.dygraph_chart_type === 'stacked' && data.dimensions === 1) { - state.tmp.dygraph_chart_type = 'area'; - } - if (state.tmp.dygraph_chart_type === 'stacked' && NETDATA.chartLibraries.dygraph.isLogScale(state)) { - state.tmp.dygraph_chart_type = 'area'; - } - - let highlightCircleSize = NETDATA.chartLibraries.dygraph.isSparkline(state) ? 3 : 4; - - let smooth = NETDATA.dygraph.smooth - ? (NETDATA.dataAttributeBoolean(state.element, 'dygraph-smooth', (state.tmp.dygraph_chart_type === 'line' && NETDATA.chartLibraries.dygraph.isSparkline(state) === false))) - : false; - - state.tmp.dygraph_include_zero = NETDATA.dataAttribute(state.element, 'dygraph-includezero', (state.tmp.dygraph_chart_type === 'stacked')); - let drawAxis = NETDATA.dataAttributeBoolean(state.element, 'dygraph-drawaxis', true); - - state.tmp.dygraph_options = { - colors: NETDATA.dataAttribute(state.element, 'dygraph-colors', state.chartColors()), - - // leave a few pixels empty on the right of the chart - rightGap: NETDATA.dataAttribute(state.element, 'dygraph-rightgap', 5), - showRangeSelector: NETDATA.dataAttributeBoolean(state.element, 'dygraph-showrangeselector', false), - showRoller: NETDATA.dataAttributeBoolean(state.element, 'dygraph-showroller', false), - title: NETDATA.dataAttribute(state.element, 'dygraph-title', state.title), - titleHeight: NETDATA.dataAttribute(state.element, 'dygraph-titleheight', 19), - legend: NETDATA.dataAttribute(state.element, 'dygraph-legend', 'always'), // we need this to get selection events - labels: data.result.labels, - labelsDiv: NETDATA.dataAttribute(state.element, 'dygraph-labelsdiv', state.element_legend_childs.hidden), - //labelsDivStyles: NETDATA.dataAttribute(state.element, 'dygraph-labelsdivstyles', { 'fontSize':'1px' }), - //labelsDivWidth: NETDATA.dataAttribute(state.element, 'dygraph-labelsdivwidth', state.chartWidth() - 70), - labelsSeparateLines: NETDATA.dataAttributeBoolean(state.element, 'dygraph-labelsseparatelines', true), - labelsShowZeroValues: NETDATA.chartLibraries.dygraph.isLogScale(state) ? false : NETDATA.dataAttributeBoolean(state.element, 'dygraph-labelsshowzerovalues', true), - labelsKMB: false, - labelsKMG2: false, - showLabelsOnHighlight: NETDATA.dataAttributeBoolean(state.element, 'dygraph-showlabelsonhighlight', true), - hideOverlayOnMouseOut: NETDATA.dataAttributeBoolean(state.element, 'dygraph-hideoverlayonmouseout', true), - includeZero: state.tmp.dygraph_include_zero, - xRangePad: NETDATA.dataAttribute(state.element, 'dygraph-xrangepad', 0), - yRangePad: NETDATA.dataAttribute(state.element, 'dygraph-yrangepad', 1), - valueRange: NETDATA.dataAttribute(state.element, 'dygraph-valuerange', [null, null]), - ylabel: state.units_current, // (state.units_desired === 'auto')?"":state.units_current, - yLabelWidth: NETDATA.dataAttribute(state.element, 'dygraph-ylabelwidth', 12), - - // the function to plot the chart - plotter: null, - - // The width of the lines connecting data points. - // This can be used to increase the contrast or some graphs. - strokeWidth: NETDATA.dataAttribute(state.element, 'dygraph-strokewidth', ((state.tmp.dygraph_chart_type === 'stacked') ? 0.1 : ((smooth === true) ? 1.5 : 0.7))), - strokePattern: NETDATA.dataAttribute(state.element, 'dygraph-strokepattern', undefined), - - // The size of the dot to draw on each point in pixels (see drawPoints). - // A dot is always drawn when a point is "isolated", - // i.e. there is a missing point on either side of it. - // This also controls the size of those dots. - drawPoints: NETDATA.dataAttributeBoolean(state.element, 'dygraph-drawpoints', false), - - // Draw points at the edges of gaps in the data. - // This improves visibility of small data segments or other data irregularities. - drawGapEdgePoints: NETDATA.dataAttributeBoolean(state.element, 'dygraph-drawgapedgepoints', true), - connectSeparatedPoints: NETDATA.chartLibraries.dygraph.isLogScale(state) ? false : NETDATA.dataAttributeBoolean(state.element, 'dygraph-connectseparatedpoints', false), - pointSize: NETDATA.dataAttribute(state.element, 'dygraph-pointsize', 1), - - // enabling this makes the chart with little square lines - stepPlot: NETDATA.dataAttributeBoolean(state.element, 'dygraph-stepplot', false), - - // Draw a border around graph lines to make crossing lines more easily - // distinguishable. Useful for graphs with many lines. - strokeBorderColor: NETDATA.dataAttribute(state.element, 'dygraph-strokebordercolor', NETDATA.themes.current.background), - strokeBorderWidth: NETDATA.dataAttribute(state.element, 'dygraph-strokeborderwidth', (state.tmp.dygraph_chart_type === 'stacked') ? 0.0 : 0.0), - fillGraph: NETDATA.dataAttribute(state.element, 'dygraph-fillgraph', (state.tmp.dygraph_chart_type === 'area' || state.tmp.dygraph_chart_type === 'stacked')), - fillAlpha: NETDATA.dataAttribute(state.element, 'dygraph-fillalpha', - ((state.tmp.dygraph_chart_type === 'stacked') - ? NETDATA.options.current.color_fill_opacity_stacked - : NETDATA.options.current.color_fill_opacity_area) - ), - stackedGraph: NETDATA.dataAttribute(state.element, 'dygraph-stackedgraph', (state.tmp.dygraph_chart_type === 'stacked')), - stackedGraphNaNFill: NETDATA.dataAttribute(state.element, 'dygraph-stackedgraphnanfill', 'none'), - drawAxis: drawAxis, - axisLabelFontSize: NETDATA.dataAttribute(state.element, 'dygraph-axislabelfontsize', 10), - axisLineColor: NETDATA.dataAttribute(state.element, 'dygraph-axislinecolor', NETDATA.themes.current.axis), - axisLineWidth: NETDATA.dataAttribute(state.element, 'dygraph-axislinewidth', 1.0), - drawGrid: NETDATA.dataAttributeBoolean(state.element, 'dygraph-drawgrid', true), - gridLinePattern: NETDATA.dataAttribute(state.element, 'dygraph-gridlinepattern', null), - gridLineWidth: NETDATA.dataAttribute(state.element, 'dygraph-gridlinewidth', 1.0), - gridLineColor: NETDATA.dataAttribute(state.element, 'dygraph-gridlinecolor', NETDATA.themes.current.grid), - maxNumberWidth: NETDATA.dataAttribute(state.element, 'dygraph-maxnumberwidth', 8), - sigFigs: NETDATA.dataAttribute(state.element, 'dygraph-sigfigs', null), - digitsAfterDecimal: NETDATA.dataAttribute(state.element, 'dygraph-digitsafterdecimal', 2), - valueFormatter: NETDATA.dataAttribute(state.element, 'dygraph-valueformatter', undefined), - highlightCircleSize: NETDATA.dataAttribute(state.element, 'dygraph-highlightcirclesize', highlightCircleSize), - highlightSeriesOpts: NETDATA.dataAttribute(state.element, 'dygraph-highlightseriesopts', null), // TOO SLOW: { strokeWidth: 1.5 }, - highlightSeriesBackgroundAlpha: NETDATA.dataAttribute(state.element, 'dygraph-highlightseriesbackgroundalpha', null), // TOO SLOW: (state.tmp.dygraph_chart_type === 'stacked')?0.7:0.5, - pointClickCallback: NETDATA.dataAttribute(state.element, 'dygraph-pointclickcallback', undefined), - visibility: state.dimensions_visibility.selected2BooleanArray(state.data.dimension_names), - logscale: NETDATA.chartLibraries.dygraph.isLogScale(state) ? 'y' : undefined, - - // Expects a string in the format ":