@cryptotaxi247 / netdata-1 / commits / 5f7899070

Small updates to dash.html (#7757)

* dash.html docs and styling improvements * Fixing whitespace * Futher whitespace fixing * Finally fixed whitespace * Tabs to spaces * Fix Netdata capitalization Co-Authored-By: Joel Hans <joel.g.hans@gmail.com> * Fix Netdata capitalization Co-Authored-By: Joel Hans <joel.g.hans@gmail.com> Co-authored-by: Joel Hans <joel.g.hans@gmail.com>

Thomas Anderson committed Jan 27, 2020 at 17:52 UTC 5f7899070197b5d6e7c3c72f8ece271470aeeb81
2 files changed +738 -721
web/gui/custom/README.md
+25 -15
@@ -16,7 +16,7 @@ source](../demo.html)**.
16
17 You should also look at the [custom dashboard
18 template](https://my-netdata.io/dashboard.html), which contains samples of all
19 -supported charts. The code is [here](../dashboard.html).
19 +supported charts. The code is [here](../dashboard.html).
20
21 If you plan to put the dashboard on TV, check out [tv.html](../tv.html). Here's
22 is a screenshot of it, monitoring two servers on the same page:
@@ -65,7 +65,11 @@ header:
65
66 ## Dash (Multi-Host Dashboard)
67
68 -`dash-example.html` is an all-in-one page that automatically fetches graphs from all your hosts. Just add your graphs and charts (or use the defaults) one time using the `dash-*` syntax and it will be automatically replicated for all of your hosts; showing alarms and graphs for all your hosts on **one page!**
68 +`dash-example.html` is an all-in-one page that automatically fetches graphs from all your hosts. Just add your graphs and charts (or use the defaults) one time using the `dash-*` syntax, and your selections will be automatically replicated for all of your hosts; showing alarms and graphs for all your hosts on **one page!**
69 +
70 +__**Dash will only work if you have implemented netdata streaming using `stream.conf`**__
71 +
72 +`dash-example.html` was created as an experiment to demonstrate the capabilities of netdata in a multi-host environment. If you desire more features, submit a pull request or check out Netdata Cloud!
73
74 ### Configure Dash
75
@@ -74,29 +78,31 @@ First, rename the file so it doesn't get overwritten. For instance, with a webro
78 cp /usr/share/netdata/web/dash-example.html /usr/share/netdata/web/dash.html
79 ```
80
77 -Change the following line in `dash.html` to reflect your URLs. The second URL is used if you access your netdata dashboard from a reverse proxy. The reverse proxy URL is optional, if it is not set then both will use the netdata host URL.
81 +Find and change the following line in `dash.html` to reflect your Netdata URLs. The second URL is only used if you access your Netdata dashboard through a reverse proxy. The reverse proxy URL is optional; if it is not set then both will use the Netdata host URL.
82
83 ```js
84 /*
85 * TUTORIAL: Change this to the URL of your netdata host
86 * If you use netdata behind a reverse proxy, add a second parameter for the reverse proxy url like so:
83 -* new Dash('http://localhost:19999', 'https://my-domain.com/stats');
87 +* new Dash('http://localhost:19999', 'https://my-domain.com/stats');
88 */
89 var dash = new Dash('http://localhost:19999');
90 ```
91
88 -If you want to change the graphs or styling to fit your needs, just add an element to the page as shown. child divs will be generated to create your graph/chart:
92 +### The `dash-*` Syntax
93 +
94 +If you want to change the graphs or styling to fit your needs, just add an element to the page as shown. Child divs will be generated to create your graph/chart:
95 ```
90 -<div class="dash-graph" <---- Use class dash-graph for line graphs, etc
91 - data-dash-netdata="system.cpu" <---- REQUIRED: Use data-dash-netdata to set the data source
92 - data-dygraph-valuerange="[0, 100]"> <---- OPTIONAL: This overrides the default config. Any other data-* attributes will
93 -</div> be added to the generated div, so you can set any desired options here
96 +<div class="dash-graph" <---- Use class dash-graph for line graphs, etc
97 + data-dash-netdata="system.cpu" <---- REQUIRED: Use data-dash-netdata to set the data source
98 + data-dygraph-valuerange="[0, 100]"> <---- OPTIONAL: This overrides the default config. Any other data-* attributes will
99 +</div> be added to the generated div, so you can set any desired options here
100
95 -<div class="dash-chart" <---- Use class dash-chart for pie charts, etc. CHARTS ARE SQUARE
96 - data-dash-netdata="system.io" <---- REQUIRED: Use data-dash-netdata to set the data source
97 - data-dimensions="in" <---- Use this to override or append default options
98 - data-title="Disk Read" <---- Use this to override or append default options
99 - data-common-units="dash.io"> <---- Use this to override or append default options
101 +<div class="dash-chart" <---- Use class dash-chart for pie charts, etc. CHARTS ARE SQUARE
102 + data-dash-netdata="system.io" <---- REQUIRED: Use data-dash-netdata to set the data source
103 + data-dimensions="in" <---- Use this to override or append default options
104 + data-title="Disk Read" <---- Use this to override or append default options
105 + data-common-units="dash.io"> <---- Use this to override or append default options
106 </div>
107 ```
108
@@ -104,7 +110,7 @@ To change the sizes of graphs and charts, find the `Dash.options` object in `das
110 ```js
111 /*
112 * TUTORIAL: Change your graph/chart dimensions here. Host columns will automatically adjust.
107 -* Charts are square! Their width is the same as their height.
113 +* Charts are square! Their width is the same as their height.
114 */
115 this.options = {
116 graph_width: '40em',
@@ -115,6 +121,10 @@ this.options = {
121
122 To change the display order of your hosts, which is saved in localStorage, click the settings gear in the lower right corner
123
124 +We hope you like it!
125 +
126 +---
127 +
128
129 ## dashboard.js
130
web/gui/dash-example.html
+713 -706
@@ -1,104 +1,106 @@
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 - <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5 - <meta charset="utf-8">
6 - <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
7 - <meta name="viewport" content="width=device-width, initial-scale=1">
8 - <meta name="apple-mobile-web-app-capable" content="yes">
9 - <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
4 + <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5 + <meta charset="utf-8">
6 + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
7 + <meta name="viewport" content="width=device-width, initial-scale=1">
8 + <meta name="apple-mobile-web-app-capable" content="yes">
9 + <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
10 </head>
11 <body>
12 - <div id="alarms" class="collapsed">
13 - <div class="alarm-collapse-button" onclick="dash.toggle_alarm_collapse()">&rsaquo;</div>
14 - <span class="alarm-count"></span>
15 - <h1>Alarms</h1>
16 - <div class="alarm-host-list"></div>
17 - <div class="settings-button" onclick="dash.reorder_hosts()">&#9881;</div>
18 - </div>
19 - <div id="dash">
20 - <div class="netdata-host-stats-container template">
21 - <div class="drag-anchor"></div>
22 - <div class="netdata-host-name">host</div>
23 - <div class="netdata-host-stats">
24 - <div class="dash-graph"
25 - data-dash-netdata="system.cpu"
26 - data-dygraph-valuerange="[0, 100]">
27 - </div>
28 - <div class="dash-graph"
29 - data-dash-netdata="system.load">
30 - </div>
31 - <div class="dash-graph"
32 - data-dash-netdata="system.ram">
33 - </div>
34 - <div class="dash-graph"
35 - data-dash-netdata="system.net">
36 - </div>
37 - <div class="dash-graph"
38 - data-dash-netdata="system.processes">
39 - </div>
40 - <div class="dash-graph"
41 - data-dash-netdata="apps.cpu">
42 - </div>
43 - <div class="dash-graph"
44 - data-dash-netdata="apps.mem">
45 - </div>
46 - <div class="dash-charts">
47 - <div class="dash-chart"
48 - data-dash-netdata="system.io"
49 - data-dimensions="in"
50 - data-title="Disk Read"
51 - data-common-units="dash.io">
52 - </div>
53 - <div class="dash-chart"
54 - data-dash-netdata="system.io"
55 - data-dimensions="out"
56 - data-title="Disk Write"
57 - data-common-units="dash.io">
58 - </div>
59 - <div class="dash-chart"
60 - data-dash-netdata="system.cpu"
61 - data-chart-library="gauge"
62 - data-title="CPU"
63 - data-units="%"
64 - data-gauge-max-value="100"
65 - data-colors="#22AA99"
66 - data-gauge-stroke-color="#373B40">
67 - </div>
68 - <div class="dash-chart"
69 - data-dash-netdata="system.net"
70 - data-dimensions="received"
71 - data-title="Net Inbound"
72 - data-common-units="dash.net">
73 - </div>
74 - <div class="dash-chart"
75 - data-dash-netdata="system.net"
76 - data-dimensions="sent"
77 - data-title="Net Outbound"
78 - data-common-units="dash.net">
79 - </div>
80 - <div class="dash-chart"
81 - data-dash-netdata="system.ram"
82 - data-dimensions="used|buffers|active|wired"
83 - data-append-options="percentage"
84 - data-title="Used RAM"
85 - data-units="%"
86 - data-easypiechart-max-value="100"
87 - data-colors="#EE9911">
88 - </div>
89 - </div>
90 - </div>
91 - </div>
92 - </div>
12 + <div id="alarms" class="collapsed">
13 + <div class="alarm-collapse-button" onclick="dash.toggle_alarm_collapse()">&rsaquo;</div>
14 + <span class="alarm-count"></span>
15 + <h1>Alarms</h1>
16 + <div class="alarm-host-list"></div>
17 + <div class="settings-button" onclick="dash.reorder_hosts()">&#9881;&#xFE0E;</div>
18 + </div>
19 + <div id="dash">
20 + <div class="netdata-host-stats-container template">
21 + <div class="netdata-host-name">host</div>
22 + <div class="netdata-host-stats">
23 + <div class="dash-graph"
24 + data-dash-netdata="system.cpu"
25 + data-dygraph-valuerange="[0, 100]">
26 + </div>
27 + <div class="dash-graph"
28 + data-dash-netdata="system.load">
29 + </div>
30 + <div class="dash-graph"
31 + data-dash-netdata="system.ram">
32 + </div>
33 + <div class="dash-graph"
34 + data-dash-netdata="disk_space._">
35 + </div>
36 + <div class="dash-graph"
37 + data-dash-netdata="system.net">
38 + </div>
39 + <div class="dash-graph"
40 + data-dash-netdata="system.processes">
41 + </div>
42 + <div class="dash-graph"
43 + data-dash-netdata="apps.cpu">
44 + </div>
45 + <div class="dash-graph"
46 + data-dash-netdata="apps.mem">
47 + </div>
48 + <div class="dash-charts">
49 + <div class="dash-chart"
50 + data-dash-netdata="system.io"
51 + data-dimensions="in"
52 + data-title="Disk Read"
53 + data-common-units="dash.io">
54 + </div>
55 + <div class="dash-chart"
56 + data-dash-netdata="system.io"
57 + data-dimensions="out"
58 + data-title="Disk Write"
59 + data-common-units="dash.io">
60 + </div>
61 + <div class="dash-chart"
62 + data-dash-netdata="system.cpu"
63 + data-chart-library="gauge"
64 + data-title="CPU"
65 + data-units="%"
66 + data-gauge-max-value="100"
67 + data-colors="#22AA99"
68 + data-gauge-stroke-color="#373B40">
69 + </div>
70 + <div class="dash-chart"
71 + data-dash-netdata="system.net"
72 + data-dimensions="received"
73 + data-title="Net Inbound"
74 + data-common-units="dash.net">
75 + </div>
76 + <div class="dash-chart"
77 + data-dash-netdata="system.net"
78 + data-dimensions="sent"
79 + data-title="Net Outbound"
80 + data-common-units="dash.net">
81 + </div>
82 + <div class="dash-chart"
83 + data-dash-netdata="system.ram"
84 + data-dimensions="used|buffers|active|wired"
85 + data-append-options="percentage"
86 + data-title="Used RAM"
87 + data-units="%"
88 + data-easypiechart-max-value="100"
89 + data-colors="#EE9911">
90 + </div>
91 + </div>
92 + </div>
93 + </div>
94 + </div>
95 </body>
96 <script
95 - src="https://code.jquery.com/jquery-3.4.1.min.js"
96 - integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
97 - crossorigin="anonymous">
97 + src="https://code.jquery.com/jquery-3.4.1.min.js"
98 + integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
99 + crossorigin="anonymous">
100 </script>
101 <script type="text/javascript">
102 class PickNSort {
101 - // PickNSort.js
103 + // PickNSort.js
104
105 constructor (dark) {
106 this.items = [];
@@ -294,6 +296,9 @@ class PickNSort {
296 }
297
298 add_css_to_page (dark) {
299 + /*
300 + * TUTORIAL: Change your theme colors here. Not sure how well it will work...
301 + */
302 var light_theme = {
303 windowbg: "#FFF",
304 itembg: "#F4F4F4",
@@ -304,10 +309,10 @@ class PickNSort {
309 itembg: "#333",
310 itemcolor: "#DBDBDB"
311 }
312 +
313 var current_theme = (dark) ? dark_theme : light_theme;
308 - $("<style>")
309 - .prop("type", "text/css")
310 - .html(`
314 +
315 + var css_string = `
316 #picknsort-container {
317 position: fixed;
318 z-index: 9999 !important;
@@ -390,624 +395,626 @@ class PickNSort {
395 padding: 0em 0.5em;
396 height: calc(100% - 0.2em);
397 }
393 - `).appendTo("head");
398 + ` // End multiline string
399 +
400 +
401 + $("<style>")
402 + .prop("type", "text/css")
403 + .html(css_string).appendTo("head");
404 }
405 }
406 </script>
407 <script type="text/javascript">
398 - // Dash JS
399 -
400 - function picknsort_setup () {
401 - if (localStorage.getItem('netdata_ordered_hosts')) {
402 - picknsort.last_output = JSON.parse(localStorage.getItem('netdata_ordered_hosts'));
403 - } else {
404 - picknsort.last_output = {
405 - enabled: dash.netdata_info.mirrored_hosts,
406 - disabled: []
407 - }
408 - }
409 - }
410 -
411 - class Dash {
412 - constructor (base_url, link_base_url) {
413 - this.base_url = base_url; // URL of netdata host, with port
414 - this.link_base_url = link_base_url || base_url; // Reverse proxy URL (Optional)
415 - this.current_alarms = {};
416 - this.new_alarms = {};
417 - this.first_build = true;
418 - /*
419 - * TUTORIAL: Change your graph/chart dimensions here. Host columns will automatically adjust.
420 - * Charts are square! Their width is the same as their height.
421 - */
422 - this.options = {
423 - graph_width: '40em',
424 - graph_height: '20em',
425 - chart_width: '10em' // Charts are square
426 - };
427 -
428 - this.init();
429 - }
430 -
431 - reorder_hosts () {
432 - picknsort.popup(dash.update_ordered_hosts, dash.find_new_hosts);
433 - }
434 -
435 - get_enabled_hosts () {
436 - try {
437 - return JSON.parse(localStorage.getItem('netdata_ordered_hosts')).enabled
438 - } catch (e) {
439 - return this.netdata_info.mirrored_hosts;
440 - }
441 - }
442 -
443 - get_ordered_hosts () {
444 - try {
445 - return JSON.parse(localStorage.getItem('netdata_ordered_hosts'));
446 - } catch (e) {
447 - return null;
448 - }
449 - }
450 -
451 - set_ordered_hosts (hosts) {
452 - localStorage.setItem('netdata_ordered_hosts', JSON.stringify(hosts));
453 - location.reload();
454 - }
455 -
456 - update_ordered_hosts (enabled, disabled) {
457 - if (enabled === null && disabled === null) {
458 - return;
459 - }
460 - dash.set_ordered_hosts({
461 - enabled: enabled,
462 - disabled: disabled
463 - });
464 - }
465 -
466 - find_new_hosts () {
467 - var newhosts = dash.netdata_info.mirrored_hosts.slice();
468 - var currenthosts = dash.get_ordered_hosts();
469 -
470 - for (var i=0,len=currenthosts.enabled.length; i<len; i++) {
471 - var found = newhosts.indexOf(currenthosts.enabled[i]);
472 -
473 - if (found > -1) {
474 - newhosts.splice(found, 1);
475 - } else {
476 - currenthosts.enabled.splice(i, 1);
477 - }
478 - }
479 -
480 - for (var i=0,len=currenthosts.disabled.length; i<len; i++) {
481 - var found = newhosts.indexOf(currenthosts.disabled[i]);
482 -
483 - if (found > -1) {
484 - newhosts.splice(found, 1);
485 - } else {
486 - currenthosts.enabled.splice(i, 1);
487 - }
488 - }
489 -
490 - for (var i=0,len=newhosts.length; i<len; i++) {
491 - currenthosts.enabled.push(newhosts[i]);
492 - }
493 -
494 - dash.set_ordered_hosts(currenthosts);
495 - }
496 -
497 - get_host_url (hostname, link) {
498 - var base = ( link ) ? this.link_base_url : this.base_url;
499 - return (hostname) ? base + '/host/' + hostname : base;
500 - }
501 -
502 - get_api_url (hostname) {
503 - return this.get_host_url(hostname) + '/api/v1'
504 - }
505 -
506 -
507 - init () {
508 - var that = this;
509 - $.get(this.get_api_url() + '/info', function (data) {
510 - that.netdata_info = data;
511 - picknsort_setup()
512 - that.build();
513 - });
514 - }
515 -
516 - digest () {
517 - this.fetch_active_alarms();
518 - this.fix_layout_errors();
519 - }
520 -
521 - build () {
522 - // Fix vertically misaligned stats on load error
523 - $('.dash-graph').css({
524 - height: this.options.graph_height,
525 - width: this.options.graph_width
526 - });
527 - $('.dash-chart').css({
528 - height: this.options.chart_width, // Charts are square
529 - width: this.options.chart_width
530 - });
531 -
532 - // Fix chart alignment
533 - $('.netdata-host-stats-container').css({
534 - width: 'calc(' + this.options.graph_width + ' + (2 * ' + $('.netdata-host-stats-container').css('padding-left') + '))'
535 - });
536 -
537 - var $template = $('.netdata-host-stats-container').first();
538 -
539 - var hosts = this.get_enabled_hosts();
540 -
541 - for (var i=0, len=hosts.length; i<len; i++) {
542 - var hostname = hosts[i];
543 - $('#alarms .alarm-host-list').append('<div class="host-alarms ' + hostname + '"><a target="_blank" href="' + this.get_host_url(hostname, true) + '/"><h2>' + hostname + '</h2></a></div>');
544 -
545 - $template.clone().removeClass('template').appendTo('#dash');
546 - var $newest = $('.netdata-host-stats-container').last();
547 - this.build_stats($newest, hostname);
548 - }
549 -
550 -
551 - if (this.first_build === true) {
552 - this.remove_template_elements();
553 - this.first_build = false;
554 - }
555 - }
556 -
557 - build_stats ($hoststats, hostname) {
558 - var that = this;
559 -
560 - $hoststats.find('.netdata-host-stats .dash-graph').each(function () {
561 - that.build_graph($(this), hostname);
562 - });
563 -
564 - $hoststats.find('.netdata-host-stats .dash-chart').each(function () {
565 - that.build_chart($(this), hostname);
566 - });
567 -
568 - $hoststats.find('.netdata-host-name').html('<a target="_blank" href="' + that.get_host_url(hostname, true) + '/">' + hostname + '</a>');
569 - }
570 -
571 - build_graph ($wrapper, hostname) {
572 - var that = this;
573 - var $graph = $('<div>', {
574 - // Defaults
575 - 'data-netdata': $wrapper.attr('data-dash-netdata'),
576 - 'data-host': that.get_host_url(hostname),
577 - 'data-before': '0',
578 - 'data-after': '-540',
579 - 'role': 'application',
580 - 'data-width': that.options.graph_width,
581 - 'data-height': that.options.graph_height
582 - });
583 -
584 - $.each($wrapper[0].attributes, function (key, node) {
585 - if ( node.name.match(/^data-(?!dash).*/ ) ) {
586 - $graph.attr(node.name, node.value);
587 - }
588 - });
589 -
590 - $graph.appendTo($wrapper);
591 - }
592 -
593 - build_chart ($wrapper, hostname) {
594 - var that = this;
595 - var $graph = $('<div>', {
596 - // Defaults
597 - 'data-netdata': $wrapper.attr('data-dash-netdata'),
598 - 'data-host': that.get_host_url(hostname),
599 - 'data-before': '0',
600 - 'data-after': '-540',
601 - 'data-points': '540',
602 - 'role': 'application',
603 - 'data-width': that.options.chart_width,
604 - 'data-title': ' ',
605 - 'data-easypiechart-trackcolor': "#373B40",
606 - 'data-chart-library': 'easypiechart'
607 -
608 - })
609 -
610 - $.each($wrapper[0].attributes, function (key, node) {
611 - if ( node.name.match(/^data-(?!dash).*/ ) ) {
612 - $graph.attr(node.name, node.value);
613 - }
614 - });
615 -
616 - $graph.appendTo($wrapper);
617 - }
618 -
619 - all_alarms_are_warnings () {
620 - var out = true;
621 - $.each(this.current_alarms, function (host, alarms) {
622 - if (out === false) {
623 - return false; // Maximum efficiency
624 - }
625 - $.each(alarms, function (name, data) {
626 - if (data.status != "WARNING") {
627 - out = false;
628 - return false;
629 - }
630 - });
631 - });
632 - return out;
633 - }
634 -
635 - update_alarm_count () {
636 - console.log(this.all_alarms_are_warnings());
637 - var count = $('img.alarm-badge').length;
638 - $('.alarm-count').text($('img.alarm-badge').length);
639 - $('.alarm-count').removeClass('no-alarms warnings-only');
640 - if ( count === 0 ) {
641 - $('.alarm-count').addClass('no-alarms');
642 - return
643 - }
644 - if (this.all_alarms_are_warnings()) {
645 - $('.alarm-count').addClass('warnings-only');
646 - }
647 - }
648 -
649 - fetch_active_alarms () {
650 - var that = this;
651 - console.log("Getting alarms...");
652 - var hosts = this.get_enabled_hosts();
653 - for (var i=0, len=hosts.length; i<len; i++) {
654 - var hostname = hosts[i];
655 -
656 - $.get(this.get_api_url(hostname) + '/alarms', function (data) {
657 - that.new_alarms[ data.hostname ] = data.alarms;
658 - if ( Object.keys(that.new_alarms).length === len ) {
659 - // All responses received
660 - if ( that.check_new_current_alarms() ) {
661 - console.log("No alarm changes detected... Refreshing images.");
662 - that.new_alarms = {};
663 - that.refresh_alarm_images();
664 - return;
665 - }
666 -
667 - that.current_alarms = that.new_alarms;
668 - that.new_alarms = {};
669 - that.draw_alarms();
670 - that.update_alarm_count();
671 - }
672 - });
673 - }
674 - }
675 -
676 - toggle_alarm_collapse () {
677 - $('#alarms').toggleClass('collapsed');
678 - }
679 -
680 - check_new_current_alarms () {
681 - // Create arrays of property names
682 - var a = this.current_alarms;
683 - var b = this.new_alarms;
684 - var aProps = Object.keys(a);
685 - var bProps = Object.keys(b);
686 -
687 - // If number of properties is different,
688 - // objects are not equivalent
689 - if (aProps.length != bProps.length) {
690 - return false;
691 - }
692 -
693 - for (var i = 0; i < aProps.length; i++) {
694 - var propName = aProps[i];
695 - var aa = a[propName];
696 - var aaProps = Object.keys(aa);
697 - var bb = b[propName];
698 - var bbProps = Object.keys(bb);
699 -
700 - if (aaProps.length != bbProps.length) {
701 - return false;
702 - }
703 -
704 - for (var n = 0, len=aaProps.length; i < len; i++) {
705 - if ( bb[aaProps[n]] === undefined ) {
706 - return false;
707 - }
708 - }
709 - }
710 -
711 - // If we made it this far, objects
712 - // are considered equivalent
713 - return true;
714 - }
715 -
716 - refresh_alarm_images () {
717 - // Use Math.random() to "reload" the image
718 - $('.alarm-badge').each(function () {
719 - var old_src = $(this).attr('src').replace(/&rand=.*/g, "");
720 - $(this).attr('src', old_src + "&rand=" + Math.random());
721 - });
722 - }
723 -
724 - draw_alarms () {
725 - var that = this;
726 - console.log("Drawing...", that.current_alarms);
727 - $.each(that.current_alarms, function(hostname, alarms) {
728 - $('#alarms .host-alarms.' + hostname + ' .alarm-badge').remove();
729 - $.each(alarms, function (index, alarm) {
730 - that.draw_alarm(hostname, alarm);
731 - })
732 - });
733 - }
734 -
735 - draw_alarm (hostname, alarm) {
736 - var queryStr = '/badge.svg?alarm=' + alarm.name + '&chart=' + alarm.chart
737 - $('<img />', {
738 - src: this.get_api_url(hostname) + queryStr,
739 - class: 'alarm-badge'
740 - }).appendTo($('#alarms .host-alarms.' + hostname));
741 - }
742 -
743 - remove_template_elements () {
744 - $('.netdata-host-stats-container').first().remove();
745 - }
746 -
747 - fix_layout_errors () {
748 - $('.dash-graph:contains("chart not found")').html('<div class="loading-error">Not found</div>');
749 - $('.dash-chart:contains("chart not found")').html('<div class="loading-error">Not found</div>');
750 - }
751 - }
752 -
753 - /*
754 - * TUTORIAL: Change this to the URL of your netdata host
755 - * If you use netdata behind a reverse proxy, add a second parameter for the reverse proxy url like so:
756 - * new Dash('http://localhost:19999', 'https://my-domain.com/stats');
757 - */
758 - var dash = new Dash('http://localhost:19999');
759 -
760 - var picknsort = new PickNSort(true);
761 -
762 - // Import dashboard.js
763 - $.getScript(dash.base_url + '/dashboard.js', function() {
764 - console.log("Loaded dashboard.js");
765 - setTimeout(function () {
766 - $('#alarms').css("visibility", "visible");
767 - }, 400);
768 - });
769 -
770 - setInterval(function () {
771 - dash.digest();
772 - }, 6 * 1000);
408 + // Dash JS
409 +
410 + function picknsort_setup () {
411 + if (localStorage.getItem('netdata_ordered_hosts')) {
412 + picknsort.last_output = JSON.parse(localStorage.getItem('netdata_ordered_hosts'));
413 + } else {
414 + picknsort.last_output = {
415 + enabled: dash.netdata_info.mirrored_hosts,
416 + disabled: []
417 + }
418 + }
419 + }
420 +
421 + class Dash {
422 + constructor (base_url, link_base_url) {
423 + this.base_url = base_url; // URL of netdata host, with port
424 + this.link_base_url = link_base_url || base_url; // Reverse proxy URL (Optional)
425 + this.current_alarms = {};
426 + this.new_alarms = {};
427 + this.first_build = true;
428 + /*
429 + * TUTORIAL: Change your graph/chart dimensions here. Host columns will automatically adjust.
430 + * Charts are square! Their width is the same as their height.
431 + */
432 + this.options = {
433 + graph_width: '40em',
434 + graph_height: '20em',
435 + chart_width: '10em' // Charts are square
436 + };
437 +
438 + this.init();
439 + }
440 +
441 + reorder_hosts () {
442 + picknsort.popup(dash.update_ordered_hosts, dash.find_new_hosts);
443 + }
444 +
445 + get_enabled_hosts () {
446 + try {
447 + return JSON.parse(localStorage.getItem('netdata_ordered_hosts')).enabled
448 + } catch (e) {
449 + return this.netdata_info.mirrored_hosts;
450 + }
451 + }
452 +
453 + get_ordered_hosts () {
454 + try {
455 + return JSON.parse(localStorage.getItem('netdata_ordered_hosts'));
456 + } catch (e) {
457 + return null;
458 + }
459 + }
460 +
461 + set_ordered_hosts (hosts) {
462 + localStorage.setItem('netdata_ordered_hosts', JSON.stringify(hosts));
463 + location.reload();
464 + }
465 +
466 + update_ordered_hosts (enabled, disabled) {
467 + if (enabled === null && disabled === null) {
468 + return;
469 + }
470 + dash.set_ordered_hosts({
471 + enabled: enabled,
472 + disabled: disabled
473 + });
474 + }
475 +
476 + find_new_hosts () {
477 + var newhosts = dash.netdata_info.mirrored_hosts.slice();
478 + var currenthosts = dash.get_ordered_hosts();
479 +
480 + for (var i=0,len=currenthosts.enabled.length; i<len; i++) {
481 + var found = newhosts.indexOf(currenthosts.enabled[i]);
482 +
483 + if (found > -1) {
484 + newhosts.splice(found, 1);
485 + } else {
486 + currenthosts.enabled.splice(i, 1);
487 + }
488 + }
489 +
490 + for (var i=0,len=currenthosts.disabled.length; i<len; i++) {
491 + var found = newhosts.indexOf(currenthosts.disabled[i]);
492 +
493 + if (found > -1) {
494 + newhosts.splice(found, 1);
495 + } else {
496 + currenthosts.enabled.splice(i, 1);
497 + }
498 + }
499 +
500 + for (var i=0,len=newhosts.length; i<len; i++) {
501 + currenthosts.enabled.push(newhosts[i]);
502 + }
503 +
504 + dash.set_ordered_hosts(currenthosts);
505 + }
506 +
507 + get_host_url (hostname, link) {
508 + var base = ( link ) ? this.link_base_url : this.base_url;
509 + return (hostname) ? base + '/host/' + hostname : base;
510 + }
511 +
512 + get_api_url (hostname) {
513 + return this.get_host_url(hostname) + '/api/v1'
514 + }
515 +
516 +
517 + init () {
518 + var that = this;
519 + $.get(this.get_api_url() + '/info', function (data) {
520 + that.netdata_info = data;
521 + picknsort_setup()
522 + that.build();
523 + });
524 + }
525 +
526 + digest () {
527 + this.fetch_active_alarms();
528 + this.fix_layout_errors();
529 + }
530 +
531 + build () {
532 + // Fix vertically misaligned stats on load error
533 + $('.dash-graph').css({
534 + height: this.options.graph_height,
535 + width: this.options.graph_width
536 + });
537 + $('.dash-chart').css({
538 + height: this.options.chart_width, // Charts are square
539 + width: this.options.chart_width
540 + });
541 +
542 + // Fix chart alignment
543 + $('.netdata-host-stats-container').css({
544 + width: 'calc(' + this.options.graph_width + ' + (2 * ' + $('.netdata-host-stats-container').css('padding-left') + '))'
545 + });
546 +
547 + var $template = $('.netdata-host-stats-container').first();
548 +
549 + var hosts = this.get_enabled_hosts();
550 +
551 + for (var i=0, len=hosts.length; i<len; i++) {
552 + var hostname = hosts[i];
553 + $('#alarms .alarm-host-list').append('<div class="host-alarms ' + hostname + '"><a target="_blank" href="' + this.get_host_url(hostname, true) + '/"><h2>' + hostname + '</h2></a></div>');
554 +
555 + $template.clone().removeClass('template').appendTo('#dash');
556 + var $newest = $('.netdata-host-stats-container').last();
557 + this.build_stats($newest, hostname);
558 + }
559 +
560 +
561 + if (this.first_build === true) {
562 + this.remove_template_elements();
563 + this.first_build = false;
564 + }
565 + }
566 +
567 + build_stats ($hoststats, hostname) {
568 + var that = this;
569 +
570 + $hoststats.find('.netdata-host-stats .dash-graph').each(function () {
571 + that.build_graph($(this), hostname);
572 + });
573 +
574 + $hoststats.find('.netdata-host-stats .dash-chart').each(function () {
575 + that.build_chart($(this), hostname);
576 + });
577 +
578 + $hoststats.find('.netdata-host-name').html('<a target="_blank" href="' + that.get_host_url(hostname, true) + '/">' + hostname + '</a>');
579 + }
580 +
581 + build_graph ($wrapper, hostname) {
582 + var that = this;
583 + var $graph = $('<div>', {
584 + // Defaults
585 + 'data-netdata': $wrapper.attr('data-dash-netdata'),
586 + 'data-host': that.get_host_url(hostname),
587 + 'data-before': '0',
588 + 'data-after': '-540',
589 + 'role': 'application',
590 + 'data-width': that.options.graph_width,
591 + 'data-height': that.options.graph_height
592 + });
593 +
594 + $.each($wrapper[0].attributes, function (key, node) {
595 + if ( node.name.match(/^data-(?!dash).*/ ) ) {
596 + $graph.attr(node.name, node.value);
597 + }
598 + });
599 +
600 + $graph.appendTo($wrapper);
601 + }
602 +
603 + build_chart ($wrapper, hostname) {
604 + var that = this;
605 + var $graph = $('<div>', {
606 + // Defaults
607 + 'data-netdata': $wrapper.attr('data-dash-netdata'),
608 + 'data-host': that.get_host_url(hostname),
609 + 'data-before': '0',
610 + 'data-after': '-540',
611 + 'data-points': '540',
612 + 'role': 'application',
613 + 'data-width': that.options.chart_width,
614 + 'data-title': ' ',
615 + 'data-easypiechart-trackcolor': "#373B40",
616 + 'data-chart-library': 'easypiechart'
617 +
618 + })
619 +
620 + $.each($wrapper[0].attributes, function (key, node) {
621 + if ( node.name.match(/^data-(?!dash).*/ ) ) {
622 + $graph.attr(node.name, node.value);
623 + }
624 + });
625 +
626 + $graph.appendTo($wrapper);
627 + }
628 +
629 + all_alarms_are_warnings () {
630 + var out = true;
631 + $.each(this.current_alarms, function (host, alarms) {
632 + if (out === false) {
633 + return false; // Maximum efficiency
634 + }
635 + $.each(alarms, function (name, data) {
636 + if (data.status != "WARNING") {
637 + out = false;
638 + return false;
639 + }
640 + });
641 + });
642 + return out;
643 + }
644 +
645 + update_alarm_count () {
646 + console.log(this.all_alarms_are_warnings());
647 + var count = $('img.alarm-badge').length;
648 + $('.alarm-count').text($('img.alarm-badge').length);
649 + $('.alarm-count').removeClass('no-alarms warnings-only');
650 + if ( count === 0 ) {
651 + $('.alarm-count').addClass('no-alarms');
652 + return
653 + }
654 + if (this.all_alarms_are_warnings()) {
655 + $('.alarm-count').addClass('warnings-only');
656 + }
657 + }
658 +
659 + fetch_active_alarms () {
660 + var that = this;
661 + console.log("Getting alarms...");
662 + var hosts = this.get_enabled_hosts();
663 + for (var i=0, len=hosts.length; i<len; i++) {
664 + var hostname = hosts[i];
665 +
666 + $.get(this.get_api_url(hostname) + '/alarms', function (data) {
667 + that.new_alarms[ data.hostname ] = data.alarms;
668 + if ( Object.keys(that.new_alarms).length === len ) {
669 + // All responses received
670 + if ( that.check_new_current_alarms() ) {
671 + console.log("No alarm changes detected... Refreshing images.");
672 + that.new_alarms = {};
673 + that.refresh_alarm_images();
674 + return;
675 + }
676 +
677 + that.current_alarms = that.new_alarms;
678 + that.new_alarms = {};
679 + that.draw_alarms();
680 + that.update_alarm_count();
681 + }
682 + });
683 + }
684 + }
685 +
686 + toggle_alarm_collapse () {
687 + $('#alarms').toggleClass('collapsed');
688 + }
689 +
690 + check_new_current_alarms () {
691 + // Create arrays of property names
692 + var a = this.current_alarms;
693 + var b = this.new_alarms;
694 + var aProps = Object.keys(a);
695 + var bProps = Object.keys(b);
696 +
697 + // If number of properties is different,
698 + // objects are not equivalent
699 + if (aProps.length != bProps.length) {
700 + return false;
701 + }
702 +
703 + for (var i = 0; i < aProps.length; i++) {
704 + var propName = aProps[i];
705 + var aa = a[propName];
706 + var aaProps = Object.keys(aa);
707 + var bb = b[propName];
708 + var bbProps = Object.keys(bb);
709 +
710 + if (aaProps.length != bbProps.length) {
711 + return false;
712 + }
713 +
714 + for (var n = 0, len=aaProps.length; i < len; i++) {
715 + if ( bb[aaProps[n]] === undefined ) {
716 + return false;
717 + }
718 + }
719 + }
720 +
721 + // If we made it this far, objects
722 + // are considered equivalent
723 + return true;
724 + }
725 +
726 + refresh_alarm_images () {
727 + // Use Math.random() to "reload" the image
728 + $('.alarm-badge').each(function () {
729 + var old_src = $(this).attr('src').replace(/&rand=.*/g, "");
730 + $(this).attr('src', old_src + "&rand=" + Math.random());
731 + });
732 + }
733 +
734 + draw_alarms () {
735 + var that = this;
736 + console.log("Drawing...", that.current_alarms);
737 + $.each(that.current_alarms, function(hostname, alarms) {
738 + $('#alarms .host-alarms.' + hostname + ' .alarm-badge').remove();
739 + $.each(alarms, function (index, alarm) {
740 + that.draw_alarm(hostname, alarm);
741 + })
742 + });
743 + }
744 +
745 + draw_alarm (hostname, alarm) {
746 + var queryStr = '/badge.svg?alarm=' + alarm.name + '&chart=' + alarm.chart
747 + $('<img />', {
748 + src: this.get_api_url(hostname) + queryStr,
749 + class: 'alarm-badge'
750 + }).appendTo($('#alarms .host-alarms.' + hostname));
751 + }
752 +
753 + remove_template_elements () {
754 + $('.netdata-host-stats-container').first().remove();
755 + }
756 +
757 + fix_layout_errors () {
758 + $('.dash-graph:contains("chart not found")').html('<div class="loading-error">Not found</div>');
759 + $('.dash-chart:contains("chart not found")').html('<div class="loading-error">Not found</div>');
760 + }
761 + }
762 +
763 + /*
764 + * TUTORIAL: Change this to the URL of your netdata host
765 + * If you use netdata behind a reverse proxy, add a second parameter for the reverse proxy url like so:
766 + * new Dash('http://localhost:19999', 'https://my-domain.com/stats');
767 + */
768 + var dash = new Dash('http://localhost:19999');
769 +
770 + var picknsort = new PickNSort(true);
771 +
772 + // Import dashboard.js
773 + $.getScript(dash.base_url + '/dashboard.js', function() {
774 + console.log("Loaded dashboard.js");
775 + setTimeout(function () {
776 + $('#alarms').css("visibility", "visible");
777 + }, 400);
778 + });
779 +
780 + setInterval(function () {
781 + dash.digest();
782 + }, 6 * 1000);
783
784 </script>
785 <style type="text/css">
776 - body {
777 - background-color: #272b30;
778 - }
779 -
780 - a, a:hover {
781 - color: #AAA !important;
782 - }
783 -
784 - #dash {
785 - overflow: scroll;
786 - width: 100vw;
787 - white-space: nowrap;
788 - height: 100vh;
789 -
790 - }
791 -
792 - #alarms {
793 - display: block;
794 - z-index: 9999;
795 - position: fixed;
796 - right: 0;
797 - top: 0;
798 - bottom: 0;
799 - background-color: #111;
800 - width: 23em;
801 - padding: 1em;
802 - color: #AAA;
803 - box-shadow: 0 0 3em #060606;
804 - border: solid 1px #2d2d2d;
805 - visibility: hidden;
806 - }
807 -
808 -
809 -
810 - #alarms h1 {
811 - text-align: center;
812 - margin: 0;
813 - margin-bottom: 0.5em;
814 - margin-top: -0.1em;
815 - font-size: 2em;
816 - }
817 -
818 - #alarms h2 {
819 - font-size: 1.5em;
820 - }
821 -
822 - #alarms .alarm-collapse-button {
823 - position: absolute;
824 - top: 0;
825 - left: 0;
826 - width: 0.9em;
827 - height: 0.9em;
828 - font-size: 4em;
829 - line-height: 0.8;
830 - background: #111;
831 - text-align: center;
832 - cursor: default;
833 - }
834 -
835 - #alarms .alarm-collapse-button:hover {
836 - background: #000;
837 - }
838 -
839 - #alarms.collapsed {
840 - width: 4em;
841 - }
842 -
843 - #alarms.collapsed .alarm-collapse-button {
844 - position: fixed;
845 - left: auto;
846 - right: 0;
847 - top: 0;
848 - bottom: 0;
849 - width: 4em;
850 - height: 100vh;
851 - opacity: 0;
852 - z-index: 9999;
853 - }
854 -
855 - #alarms.collapsed h1 {
856 - transform: rotate(-90deg);
857 - position: absolute;
858 - left: -9.1em;
859 - top: 4em;
860 - width: 20em;
861 - }
862 -
863 - #alarms .alarm-host-list {
864 - margin-top: 1em;
865 - height: 100%;
866 - overflow-y: scroll;
867 - scrollbar-width: thin;
868 - }
869 -
870 - #alarms.collapsed .alarm-host-list {
871 - display: none;
872 - }
873 -
874 -
875 -
876 - #alarms .host-alarms {
877 - background: #1d1d1d;
878 - margin-bottom: 1em;
879 - padding: 0.2em 1em;
880 - padding-bottom: 1.5em;
881 - border-top: 1px solid;
882 - position: relative;
883 - }
884 -
885 - .host-alarms a:last-child:after {
886 - position: absolute;
887 - display: block;
888 - content: 'no alarms';
889 - width: 6em;
890 - height: 1em;
891 - right: 0;
892 - top: 2em;
893 - color: #646464;
894 - }
895 -
896 - #alarms .host-alarms img.alarm-badge {
897 - margin: .25em;
898 - height: 1.2em;
899 - }
900 -
901 - #alarms .alarm-count {
902 - width: 1.5em;
903 - height: 1.5em;
904 - text-align: center;
905 - position: absolute;
906 - right: 0.5em;
907 - top: 0.5em;
908 - font-size: 1.5em;
909 - background: #6f1515;
910 - border-radius: 50%;
911 - }
912 -
913 - #alarms .alarm-count:empty {
914 - background: #333;
915 - }
916 -
917 - #alarms .no-alarms {
918 - background: #156f15;
919 - color: rgba(0,0,0,0);
920 - }
921 -
922 - #alarms .warnings-only {
923 - background: #f48041;
924 - color: #EEE;
925 - }
926 -
927 - .settings-button {
928 - position: absolute;
929 - bottom: 0;
930 - right: 0;
931 - font-size: 3em;
932 - width: 1.3em;
933 - height: 1.3em;
934 - z-index: 9999;
935 - text-align: center;
936 - line-height: 1.2;
937 - cursor: default;
938 - }
939 -
940 - .settings-button:hover {
941 - background: #424242;
942 - }
943 -
944 - .drag-anchor {
945 - position: absolute;
946 - top: 0;
947 - left: 0;
948 - width: 100%;
949 - height: 2em;
950 - background: #111;
951 -
952 - }
953 -
954 - .netdata-host-name {
955 - font-size: 3em;
956 - color: #FFF;
957 - text-align: center;
958 - white-space: nowrap;
959 - }
960 -
961 - .netdata-host-stats-container {
962 - position: relative;
963 - margin: 0 1em;
964 - padding: 3em 2em;
965 - display: inline-block;
966 - text-align: center;
967 - color: #CCC;
968 - background: #232323;
969 - }
970 -
971 - .netdata-host-stats-container:last-of-type {
972 - margin-right: 27em;
973 - }
974 -
975 - .netdata-host-stats {
976 -
977 - }
978 -
979 - .netdata-message {
980 - }
981 -
982 - .dash-graph {
983 - margin-bottom: 1em;
984 - }
985 -
986 - .netdata-legend-resize-handler {
987 - display: none
988 - }
989 -
990 - .dash-charts {
991 - white-space: normal;
992 - margin: 2em 0;
993 - }
994 -
995 - .dash-chart {
996 - display: inline-block;
997 - vertical-align: top;
998 - }
999 -
1000 - .easyPieChartLabel {
1001 - color: #FFF;
1002 - }
1003 -
1004 - .loading-error {
1005 - padding-top: 2em;
1006 - font-size: 2em;
1007 - }
1008 -
1009 - .netdata-legend-value, .netdata-legend-toolbox, .netdata-legend-toolbox-button, .netdata-legend-resize-handler {
1010 - background: initial;
1011 - }
786 + body {
787 + background-color: #272b30;
788 + }
789 +
790 + a, a:hover {
791 + color: #AAA !important;
792 + }
793 +
794 + #dash {
795 + overflow: scroll;
796 + width: 100vw;
797 + white-space: nowrap;
798 + height: 100vh;
799 +
800 + }
801 +
802 + #alarms {
803 + display: block;
804 + z-index: 9999;
805 + position: fixed;
806 + right: 0;
807 + top: 0;
808 + bottom: 0;
809 + background-color: #111;
810 + width: 23em;
811 + padding: 1em;
812 + color: #AAA;
813 + box-shadow: 0 0 3em #060606;
814 + border: solid 1px #2d2d2d;
815 + visibility: hidden;
816 + }
817 +
818 +
819 +
820 + #alarms h1 {
821 + text-align: center;
822 + margin: 0;
823 + margin-bottom: 0.5em;
824 + margin-top: -0.1em;
825 + font-size: 2em;
826 + }
827 +
828 + #alarms h2 {
829 + font-size: 1.5em;
830 + }
831 +
832 + #alarms .alarm-collapse-button {
833 + position: absolute;
834 + top: 0;
835 + left: 0;
836 + width: 0.9em;
837 + height: 0.9em;
838 + font-size: 4em;
839 + line-height: 0.8;
840 + background: #111;
841 + text-align: center;
842 + cursor: default;
843 + }
844 +
845 + #alarms .alarm-collapse-button:hover {
846 + background: #000;
847 + }
848 +
849 + #alarms.collapsed {
850 + width: 4em;
851 + }
852 +
853 + #alarms.collapsed .alarm-collapse-button {
854 + position: fixed;
855 + left: auto;
856 + right: 0;
857 + top: 0;
858 + bottom: 0;
859 + width: 4em;
860 + height: 100vh;
861 + opacity: 0;
862 + z-index: 9999;
863 + }
864 +
865 + #alarms.collapsed h1 {
866 + transform: rotate(-90deg);
867 + position: absolute;
868 + left: -9.1em;
869 + top: 4em;
870 + width: 20em;
871 + }
872 +
873 + #alarms .alarm-host-list {
874 + margin-top: 1em;
875 + height: 100%;
876 + overflow-y: scroll;
877 + scrollbar-width: thin;
878 + }
879 +
880 + #alarms.collapsed .alarm-host-list {
881 + display: none;
882 + }
883 +
884 +
885 +
886 + #alarms .host-alarms {
887 + background: #1d1d1d;
888 + margin-bottom: 1em;
889 + padding: 0.2em 1em;
890 + padding-bottom: 1.5em;
891 + border-top: 1px solid;
892 + position: relative;
893 + }
894 +
895 + .host-alarms a:last-child:after {
896 + position: absolute;
897 + display: block;
898 + content: 'no alarms';
899 + width: 6em;
900 + height: 1em;
901 + right: 0;
902 + top: 2em;
903 + color: #646464;
904 + }
905 +
906 + #alarms .host-alarms img.alarm-badge {
907 + margin: .25em;
908 + height: 1.2em;
909 + }
910 +
911 + #alarms .alarm-count {
912 + width: 1.5em;
913 + height: 1.5em;
914 + text-align: center;
915 + position: absolute;
916 + right: 0.5em;
917 + top: 0.5em;
918 + font-size: 1.5em;
919 + background: #6f1515;
920 + border-radius: 50%;
921 + }
922 +
923 + #alarms .alarm-count:empty {
924 + background: #333;
925 + }
926 +
927 + #alarms .no-alarms {
928 + background: #156f15;
929 + color: rgba(0,0,0,0);
930 + }
931 +
932 + #alarms .warnings-only {
933 + background: #f48041;
934 + color: #EEE;
935 + }
936 +
937 + .settings-button {
938 + position: absolute;
939 + bottom: 0;
940 + right: 0;
941 + font-size: 3em;
942 + width: 1.3em;
943 + height: 1.3em;
944 + z-index: 9999;
945 + text-align: center;
946 + line-height: 1.2;
947 + cursor: default;
948 + }
949 +
950 + .settings-button:hover {
951 + background: #424242;
952 + }
953 +
954 + .netdata-host-name {
955 + font-size: 3em;
956 + color: #FFF;
957 + text-align: center;
958 + white-space: nowrap;
959 + background: inherit;
960 + position: sticky;
961 + top: 0;
962 + z-index: 9998;
963 + box-shadow: 0 0.5em 1em #232323;
964 + margin-bottom: 0.5em;
965 + border-bottom: solid 0.1em #AAA;
966 + }
967 +
968 + .netdata-host-stats-container {
969 + position: relative;
970 + margin: 0 1em;
971 + padding: 1em 2em;
972 + display: inline-block;
973 + text-align: center;
974 + color: #CCC;
975 + background: #232323;
976 + }
977 +
978 + .netdata-host-stats-container:last-of-type {
979 + margin-right: 27em;
980 + }
981 +
982 + .netdata-host-stats {
983 +
984 + }
985 +
986 + .netdata-message {
987 + }
988 +
989 + .dash-graph {
990 + margin-bottom: 1em;
991 + }
992 +
993 + .netdata-legend-resize-handler {
994 + display: none
995 + }
996 +
997 + .dash-charts {
998 + white-space: normal;
999 + margin: 2em 0;
1000 + }
1001 +
1002 + .dash-chart {
1003 + display: inline-block;
1004 + vertical-align: top;
1005 + }
1006 +
1007 + .easyPieChartLabel {
1008 + color: #FFF;
1009 + }
1010 +
1011 + .loading-error {
1012 + padding-top: 2em;
1013 + font-size: 2em;
1014 + }
1015 +
1016 + .netdata-legend-value, .netdata-legend-toolbox, .netdata-legend-toolbox-button, .netdata-legend-resize-handler {
1017 + background: initial;
1018 + }
1019 </style>
1020 </html>