fully functional web snapshots
Costa Tsaousis (ktsaou) committed
Nov 12, 2017 at 20:45 UTC
8bd1e8d54a2e0f73ff3eaa13227d4a9752aac69d
2 files changed
+353
-182
web/dashboard.js
+168
-57
@@ -202,6 +202,9 @@ var NETDATA = window.NETDATA || {};
202
// (blue) (red) (orange) (green) (pink) (brown) (purple) (yellow) (gray)
203
//NETDATA.colors = [ '#5DA5DA', '#F15854', '#FAA43A', '#60BD68', '#F17CB0', '#B2912F', '#B276B2', '#DECF3F', '#4D4D4D' ];
204
205
+ if(typeof netdataSnapshotData === 'undefined')
206
+ netdataSnapshotData = null;
207
+
208
if(typeof netdataShowHelp === 'undefined')
209
netdataShowHelp = true;
210
@@ -999,6 +1002,11 @@ var NETDATA = window.NETDATA || {};
1002
keys: {},
1003
latest: {},
1004
1005
+ globalReset: function() {
1006
+ this.keys = {};
1007
+ this.latest = {};
1008
+ },
1009
+
1010
get: function(state) {
1011
if(typeof state.tmp.__commonMin === 'undefined') {
1012
// get the commonMin setting
@@ -1053,6 +1061,11 @@ var NETDATA = window.NETDATA || {};
1061
keys: {},
1062
latest: {},
1063
1064
+ globalReset: function() {
1065
+ this.keys = {};
1066
+ this.latest = {};
1067
+ },
1068
+
1069
get: function(state) {
1070
if(typeof state.tmp.__commonMax === 'undefined') {
1071
// get the commonMax setting
@@ -1123,6 +1136,10 @@ var NETDATA = window.NETDATA || {};
1136
NETDATA.chartRegistry = {
1137
charts: {},
1138
1139
+ globalReset: function() {
1140
+ this.charts = {};
1141
+ },
1142
+
1143
fixid: function(id) {
1144
return id.replace(/:/g, "_").replace(/\//g, "_");
1145
},
@@ -1157,13 +1174,7 @@ var NETDATA = window.NETDATA || {};
1174
1175
var self = this;
1176
1160
- $.ajax({
1161
- url: host + '/api/v1/charts',
1162
- async: true,
1163
- cache: false,
1164
- xhrFields: { withCredentials: true } // required for the cookie
1165
- })
1166
- .done(function(data) {
1177
+ function fix_data(data, callback) {
1178
if(data !== null) {
1179
var h = NETDATA.chartRegistry.fixid(host);
1180
self.charts[h] = data.charts;
@@ -1175,14 +1186,29 @@ var NETDATA = window.NETDATA || {};
1186
else NETDATA.error(406, host + '/api/v1/charts');
1187
1188
if(typeof callback === 'function')
1178
- return callback(data);
1179
- })
1180
- .fail(function() {
1181
- NETDATA.error(405, host + '/api/v1/charts');
1189
+ callback(data);
1190
+ }
1191
1183
- if(typeof callback === 'function')
1184
- return callback(null);
1185
- });
1192
+ if(netdataSnapshotData !== null) {
1193
+ fix_data(netdataSnapshotData.charts, callback);
1194
+ }
1195
+ else {
1196
+ $.ajax({
1197
+ url: host + '/api/v1/charts',
1198
+ async: true,
1199
+ cache: false,
1200
+ xhrFields: {withCredentials: true} // required for the cookie
1201
+ })
1202
+ .done(function (data) {
1203
+ fix_data(data, callback);
1204
+ })
1205
+ .fail(function () {
1206
+ NETDATA.error(405, host + '/api/v1/charts');
1207
+
1208
+ if (typeof callback === 'function')
1209
+ callback(null);
1210
+ });
1211
+ }
1212
}
1213
};
1214
@@ -1209,6 +1235,15 @@ var NETDATA = window.NETDATA || {};
1235
1236
callback: null,
1237
1238
+ globalReset: function() {
1239
+ this.clearMaster();
1240
+ this.seq = 0;
1241
+ this.master = null;
1242
+ this.force_after_ms = null;
1243
+ this.force_before_ms = null;
1244
+ this.callback = null;
1245
+ },
1246
+
1247
delay: function() {
1248
if(NETDATA.options.debug.globalPanAndZoom === true)
1249
console.log('globalPanAndZoom.delay()');
@@ -1619,6 +1654,11 @@ var NETDATA = window.NETDATA || {};
1654
keys: {}, // keys for data-common-units
1655
latest: {}, // latest selected units for data-common-units
1656
1657
+ globalReset: function() {
1658
+ this.keys = {};
1659
+ this.latest = {};
1660
+ },
1661
+
1662
scalableUnits: {
1663
'kilobits/s': {
1664
'bits/s': 1 / 1000,
@@ -1910,6 +1950,15 @@ var NETDATA = window.NETDATA || {};
1950
slaves: [],
1951
timeout_id: null,
1952
1953
+ globalReset: function() {
1954
+ this.stop();
1955
+ this.state = null;
1956
+ this.dont_sync_before = 0;
1957
+ this.last_t = 0;
1958
+ this.slaves = [];
1959
+ this.timeout_id = null;
1960
+ },
1961
+
1962
active: function() {
1963
return (this.state !== null);
1964
},
@@ -3908,37 +3957,62 @@ var NETDATA = window.NETDATA || {};
3957
return ret;
3958
};
3959
3911
- this.chartURL = function() {
3912
- var after, before, points_multiplier = 1;
3913
- if(NETDATA.globalPanAndZoom.isActive() && NETDATA.globalPanAndZoom.isMaster(this) === false) {
3914
- this.tm.pan_and_zoom_seq = NETDATA.globalPanAndZoom.seq;
3960
+ this.chartDataUniqueID = function() {
3961
+ return this.id + ',' + this.library_name + ',' + this.dimensions + ',' + this.chartURLOptions();
3962
+ };
3963
3916
- after = Math.round(NETDATA.globalPanAndZoom.force_after_ms / 1000);
3917
- before = Math.round(NETDATA.globalPanAndZoom.force_before_ms / 1000);
3918
- this.view_after = after * 1000;
3919
- this.view_before = before * 1000;
3964
+ this.chartURLOptions = function() {
3965
+ var ret = '';
3966
3921
- this.requested_padding = null;
3922
- points_multiplier = 1;
3923
- }
3924
- else if(this.current.force_before_ms !== null && this.current.force_after_ms !== null) {
3925
- this.tm.pan_and_zoom_seq = 0;
3967
+ if(this.override_options !== null)
3968
+ ret = this.override_options.toString();
3969
+ else
3970
+ ret = this.library.options(this);
3971
3927
- before = Math.round(this.current.force_before_ms / 1000);
3928
- after = Math.round(this.current.force_after_ms / 1000);
3929
- this.view_after = after * 1000;
3930
- this.view_before = before * 1000;
3972
+ if(this.append_options !== null)
3973
+ ret += '|' + this.append_options.toString();
3974
3932
- if(NETDATA.options.current.pan_and_zoom_data_padding === true) {
3933
- this.requested_padding = Math.round((before - after) / 2);
3934
- after -= this.requested_padding;
3935
- before += this.requested_padding;
3936
- this.requested_padding *= 1000;
3937
- points_multiplier = 2;
3975
+ ret += '|jsonwrap';
3976
+
3977
+ if(NETDATA.options.current.eliminate_zero_dimensions === true)
3978
+ ret += '|nonzero';
3979
+
3980
+ return ret;
3981
+ };
3982
+
3983
+ this.chartURL = function() {
3984
+ var after, before, points_multiplier = 1;
3985
+ if(NETDATA.globalPanAndZoom.isActive()) {
3986
+ if(this.current.force_before_ms !== null && this.current.force_after_ms !== null) {
3987
+ this.tm.pan_and_zoom_seq = 0;
3988
+
3989
+ before = Math.round(this.current.force_before_ms / 1000);
3990
+ after = Math.round(this.current.force_after_ms / 1000);
3991
+ this.view_after = after * 1000;
3992
+ this.view_before = before * 1000;
3993
+
3994
+ if(NETDATA.options.current.pan_and_zoom_data_padding === true) {
3995
+ this.requested_padding = Math.round((before - after) / 2);
3996
+ after -= this.requested_padding;
3997
+ before += this.requested_padding;
3998
+ this.requested_padding *= 1000;
3999
+ points_multiplier = 2;
4000
+ }
4001
+
4002
+ this.current.force_before_ms = null;
4003
+ this.current.force_after_ms = null;
4004
}
4005
+ else {
4006
+ this.tm.pan_and_zoom_seq = NETDATA.globalPanAndZoom.seq;
4007
+
4008
+ after = Math.round(NETDATA.globalPanAndZoom.force_after_ms / 1000);
4009
+ before = Math.round(NETDATA.globalPanAndZoom.force_before_ms / 1000);
4010
+ this.view_after = after * 1000;
4011
+ this.view_before = before * 1000;
4012
3940
- this.current.force_before_ms = null;
3941
- this.current.force_after_ms = null;
4013
+ this.requested_padding = null;
4014
+ points_multiplier = 1;
4015
+ }
4016
}
4017
else {
4018
this.tm.pan_and_zoom_seq = 0;
@@ -3970,19 +4044,7 @@ var NETDATA = window.NETDATA || {};
4044
this.data_url += "&format=" + this.library.format();
4045
this.data_url += "&points=" + (data_points).toString();
4046
this.data_url += "&group=" + this.method;
3973
-
3974
- if(this.override_options !== null)
3975
- this.data_url += "&options=" + this.override_options.toString();
3976
- else
3977
- this.data_url += "&options=" + this.library.options(this);
3978
-
3979
- this.data_url += '|jsonwrap';
3980
-
3981
- if(NETDATA.options.current.eliminate_zero_dimensions === true)
3982
- this.data_url += '|nonzero';
3983
-
3984
- if(this.append_options !== null)
3985
- this.data_url += '|' + this.append_options.toString();
4047
+ this.data_url += "&options=" + this.chartURLOptions();
4048
4049
if(after)
4050
this.data_url += "&after=" + after.toString();
@@ -4182,18 +4244,41 @@ var NETDATA = window.NETDATA || {};
4244
this.clearSelection();
4245
this.chartURL();
4246
4185
- if(this.debug === true)
4186
- this.log('updating from ' + this.data_url);
4187
-
4247
NETDATA.statistics.refreshes_total++;
4248
NETDATA.statistics.refreshes_active++;
4249
4250
if(NETDATA.statistics.refreshes_active > NETDATA.statistics.refreshes_active_max)
4251
NETDATA.statistics.refreshes_active_max = NETDATA.statistics.refreshes_active;
4252
4253
+ var ok = false;
4254
this.fetching_data = true;
4255
4196
- var ok = false;
4256
+ if(netdataSnapshotData !== null) {
4257
+ var key = this.chartDataUniqueID();
4258
+
4259
+ if(this.debug === true)
4260
+ this.log('updating from snapshot: ' + key);
4261
+
4262
+ if(typeof netdataSnapshotData.data[key] === 'string') {
4263
+ ok = true;
4264
+ this.updateChartWithData(JSON.parse(netdataSnapshotData.data[key]));
4265
+ }
4266
+ else {
4267
+ ok = false;
4268
+ error('data not found in snapshot for key: ' + key);
4269
+ }
4270
+
4271
+ NETDATA.statistics.refreshes_active--;
4272
+ this.fetching_data = false;
4273
+
4274
+ if(typeof callback === 'function')
4275
+ callback(ok, 'snapshot');
4276
+
4277
+ return;
4278
+ }
4279
+
4280
+ if(this.debug === true)
4281
+ this.log('updating from ' + this.data_url);
4282
4283
this.xhr = $.ajax( {
4284
url: this.data_url,
@@ -4208,7 +4293,6 @@ var NETDATA = window.NETDATA || {};
4293
.done(function(data) {
4294
that.xhr = undefined;
4295
that.retries_on_data_failures = 0;
4211
-
4296
ok = true;
4297
4298
if(that.debug === true)
@@ -4898,6 +4982,18 @@ var NETDATA = window.NETDATA || {};
4982
netdataCallback();
4983
};
4984
4985
+ NETDATA.globalReset = function() {
4986
+ NETDATA.globalSelectionSync.globalReset();
4987
+ NETDATA.globalPanAndZoom.globalReset();
4988
+ NETDATA.chartRegistry.globalReset();
4989
+ NETDATA.commonMin.globalReset();
4990
+ NETDATA.commonMax.globalReset();
4991
+ NETDATA.unitsConversion.globalReset();
4992
+ NETDATA.options.targets = null;
4993
+ NETDATA.parseDom();
4994
+ NETDATA.unpause();
4995
+ };
4996
+
4997
// ----------------------------------------------------------------------------------------------------------------
4998
// peity
4999
@@ -5265,6 +5361,12 @@ var NETDATA = window.NETDATA || {};
5361
}
5362
}
5363
5364
+ if(netdataSnapshotData !== null && NETDATA.globalPanAndZoom.isActive() === true && NETDATA.globalPanAndZoom.isMaster(state) === false) {
5365
+ // pan and zoom on snapshots
5366
+ options.dateWindow = [ NETDATA.globalPanAndZoom.force_after_ms, NETDATA.globalPanAndZoom.force_before_ms ];
5367
+ options.isZoomedIgnoreProgrammaticZoom = true;
5368
+ }
5369
+
5370
dygraph.updateOptions(options);
5371
5372
var redraw = false;
@@ -5793,6 +5895,12 @@ var NETDATA = window.NETDATA || {};
5895
}
5896
else state.tmp.dygraph_smooth_eligible = false;
5897
5898
+ if(netdataSnapshotData !== null && NETDATA.globalPanAndZoom.isActive() === true && NETDATA.globalPanAndZoom.isMaster(state) === false) {
5899
+ // pan and zoom on snapshots
5900
+ state.tmp.dygraph_options.dateWindow = [ NETDATA.globalPanAndZoom.force_after_ms, NETDATA.globalPanAndZoom.force_before_ms ];
5901
+ state.tmp.dygraph_options.isZoomedIgnoreProgrammaticZoom = true;
5902
+ }
5903
+
5904
state.tmp.dygraph_instance = new Dygraph(state.element_chart,
5905
data.result.data, state.tmp.dygraph_options);
5906
@@ -7457,6 +7565,9 @@ var NETDATA = window.NETDATA || {};
7565
},
7566
7567
update_forever: function() {
7568
+ if(netdataShowAlarms !== true || netdataSnapshotData !== null)
7569
+ return;
7570
+
7571
NETDATA.alarms.get('active', function(data) {
7572
if(data !== null) {
7573
NETDATA.alarms.current = data;
web/index.html
+185
-125
@@ -471,6 +471,9 @@
471
472
<!-- check which theme to use -->
473
<script type="text/javascript">
474
+ // netdata snapshot data
475
+ var netdataSnapshotData = null;
476
+
477
// enable alarms checking and notifications
478
var netdataShowAlarms = true;
479
@@ -487,7 +490,7 @@
490
hash: '#',
491
theme: null,
492
help: null,
490
- mode: 'live', // 'live', 'print', 'save', 'load'
493
+ mode: 'live', // 'live', 'print'
494
update_always: false,
495
pan_and_zoom: false,
496
after: 0,
@@ -553,6 +556,12 @@
556
urlOptions[booleans[len]] = false;
557
}
558
559
+ if(typeof urlOptions.after === 'string')
560
+ urlOptions.after = parseInt(urlOptions.after);
561
+
562
+ if(typeof urlOptions.before === 'string')
563
+ urlOptions.before = parseInt(urlOptions.before);
564
+
565
if(urlOptions.before > 0 && urlOptions.after > 0) {
566
urlOptions.pan_and_zoom = true;
567
urlOptions.nowelcome = true;
@@ -561,34 +570,29 @@
570
urlOptions.pan_and_zoom = false;
571
572
switch(urlOptions.mode) {
564
- case 'live':
573
case 'print':
566
- case 'load':
567
- case 'save':
574
+ urlOptions.theme = 'white';
575
+ urlOptions.welcome = false;
576
+ urlOptions.help = false;
577
+ urlOptions.show_alarms = false;
578
+
579
+ if(urlOptions.pan_and_zoom === false) {
580
+ urlOptions.pan_and_zoom = true;
581
+ urlOptions.before = Date.now();
582
+ urlOptions.after = urlOptions.before - 600000;
583
+ }
584
+
585
+ netdataShowAlarms = false;
586
+ netdataRegistry = false;
587
+ this_is_demo = false;
588
break;
589
590
+ case 'live':
591
default:
592
urlOptions.mode = 'live';
593
break;
594
}
595
575
- if(urlOptions.mode === 'print') {
576
- urlOptions.theme = 'white';
577
- urlOptions.welcome = false;
578
- urlOptions.help = false;
579
- urlOptions.show_alarms = false;
580
-
581
- if(urlOptions.pan_and_zoom === false) {
582
- urlOptions.pan_and_zoom = true;
583
- urlOptions.before = Date.now();
584
- urlOptions.after = urlOptions.before - 600000;
585
- }
586
-
587
- netdataShowAlarms = false;
588
- netdataRegistry = false;
589
- this_is_demo = false;
590
- }
591
-
596
// console.log(urlOptions);
597
},
598
@@ -623,6 +627,7 @@
627
localStorageTested = true;
628
}
629
catch (e) {
630
+ console.log(e);
631
localStorageTested = false;
632
}
633
}
@@ -638,8 +643,13 @@
643
try {
644
if(localStorageTest() === true)
645
ret = localStorage.getItem(name);
646
+ else
647
+ console.log('localStorage is not available');
648
+ }
649
+ catch(error) {
650
+ console.log(error);
651
+ return null;
652
}
642
- catch(error) {}
653
654
if(typeof ret === 'undefined' || ret === null)
655
return null;
@@ -657,7 +667,9 @@
667
return true;
668
}
669
}
660
- catch(error) {}
670
+ catch(error) {
671
+ console.log(error);
672
+ }
673
674
return false;
675
}
@@ -735,6 +747,25 @@
747
return aa.length - bb.length;
748
}
749
750
+ // --------------------------------------------------------------------
751
+ // saving files to client
752
+
753
+ function saveTextToClient(data, filename) {
754
+ var blob = new Blob( [ data ], {
755
+ type: 'application/octet-stream'
756
+ });
757
+
758
+ var url = URL.createObjectURL( blob );
759
+ var link = document.createElement( 'a' );
760
+ link.setAttribute( 'href', url );
761
+ link.setAttribute( 'download', filename );
762
+ link.click();
763
+ }
764
+
765
+ function saveObjectToClient(data, filename) {
766
+ saveTextToClient(JSON.stringify(data), filename);
767
+ }
768
+
769
// --------------------------------------------------------------------
770
// registry call back to render my-netdata menu
771
@@ -1064,10 +1095,6 @@
1095
data: null,
1096
hostname: 'netdata_server', // will be overwritten by the netdata server
1097
version: 'unknown',
1067
- categories: [],
1068
- categories_idx: {},
1069
- families: [],
1070
- families_idx: {},
1098
hosts: [],
1099
1100
duration: 0, // the default duration of the charts
@@ -1075,7 +1102,7 @@
1102
1103
chartsPerRow: 0,
1104
// chartsMinWidth: 1450,
1078
- chartsHeight: 180
1105
+ chartsHeight: 180,
1106
};
1107
1108
function chartsPerRow(total) {
@@ -1728,6 +1755,9 @@
1755
}
1756
1757
function renderChartsAndMenu(data) {
1758
+ options.menus = {};
1759
+ options.submenu_names = {};
1760
+
1761
var menus = options.menus;
1762
var charts = data.charts;
1763
var m, menu_key;
@@ -2675,6 +2705,7 @@
2705
}
2706
2707
// ----------------------------------------------------------------------------
2708
+ // printing dashboards
2709
2710
function showPageFooter() {
2711
document.getElementById('footer').style.display = 'block';
@@ -2685,8 +2716,8 @@
2716
var url = document.location.origin + document.location.search + '#' + urlOptions.genHash() + ';mode=print';
2717
var width = 990;
2718
var height = screen.height * 90 / 100;
2688
- console.log(url);
2689
- console.log(document.location);
2719
+ //console.log(url);
2720
+ //console.log(document.location);
2721
window.open(url, '', 'width=' + width.toString() + ',height=' + height.toString() + ',menubar=no,toolbar=no,personalbar=no,location=no,resizable=no,scrollbars=yes,status=no,chrome=yes,centerscreen=yes,attention=yes,dialog=yes');
2722
$('#printPreflightModal').modal('hide');
2723
}
@@ -2763,73 +2794,86 @@
2794
$('#printModal').modal('show');
2795
}
2796
2766
- function saveObject(data, filename){
2767
- var blob = new Blob( [ JSON.stringify(data) ], {
2768
- type: 'application/octet-stream'
2769
- });
2797
+ // --------------------------------------------------------------------
2798
+ // loading snapshots
2799
2771
- var url = URL.createObjectURL( blob );
2772
- var link = document.createElement( 'a' );
2773
- link.setAttribute( 'href', url );
2774
- link.setAttribute( 'download', filename );
2775
- link.click();
2800
+ function loadSnapshotModalLog(priority, msg) {
2801
+ document.getElementById('loadSnapshotStatus').className = "alert alert-" + priority;
2802
+ document.getElementById('loadSnapshotStatus').innerHTML = msg;
2803
}
2804
2778
- function loadPage() {
2779
- var files = document.getElementById('loadJSONSelectFiles').files;
2805
+ var tmpSnapshotData = null;
2806
+ function loadSnapshot() {
2807
+ if(tmpSnapshotData === null) {
2808
+ loadSnapshotModalLog('danger', 'no data have been loaded');
2809
+ return;
2810
+ }
2811
+ loadSnapshotModalLog('info', 'Please wait, activating snapshot...');
2812
+
2813
+ netdataShowAlarms === false;
2814
+ netdataRegistry = false;
2815
+
2816
+ document.getElementById('charts_div').innerHTML = '';
2817
+ document.getElementById('sidebar').innerHTML = '';
2818
+ NETDATA.globalReset();
2819
+
2820
+ netdataSnapshotData = tmpSnapshotData;
2821
+ initializeDynamicDashboard(netdataSnapshotData.url);
2822
+
2823
+ $('#loadSnapshotModal').modal('hide');
2824
+ }
2825
+
2826
+ function loadSnapshotPreflight() {
2827
+ var files = document.getElementById('loadSnapshotSelectFiles').files;
2828
if (files.length <= 0) {
2781
- document.getElementById('loadJSONStatus').className = "alert alert-danger";
2782
- document.getElementById('loadJSONStatus').innerHTML = "No file selected";
2829
+ loadSnapshotModalLog('danger', 'No file selected');
2830
return;
2831
}
2832
2786
- document.getElementById('loadJSONStatus').className = "alert alert-info";
2787
- document.getElementById('loadJSONStatus').innerHTML = "Loading file...";
2833
+ loadSnapshotModalLog('info', 'Loading file...');
2834
2835
var fr = new FileReader();
2836
fr.onload = function(e) {
2791
- console.log(e);
2837
+ // console.log(e);
2838
2793
- document.getElementById('loadJSONFilename').innerHTML = files.item(0).name;
2839
+ document.getElementById('loadSnapshotFilename').innerHTML = files.item(0).name;
2840
var result = null;
2841
try {
2842
result = JSON.parse(e.target.result);
2797
- console.log(result);
2798
- document.getElementById('loadJSONHostname').innerHTML = result.charts.hostname;
2799
- document.getElementById('loadJSONNetdataVersion').innerHTML = result.charts.version;
2800
- document.getElementById('loadJSONCharts').innerHTML = result.charts.charts_count.toString() + ' charts / ' + result.charts.dimensions_count.toString() + ' dimensions';
2801
-
2843
+ //console.log(result);
2844
var date_after = new Date(result.after_ms);
2845
var date_before = new Date(result.before_ms);
2804
- console.log(date_after);
2805
- console.log(date_before);
2806
- document.getElementById('loadJSONTimeRange').innerHTML = NETDATA.dateTime.localeDateString(date_after) + ' ' + NETDATA.dateTime.localeTimeString(date_after) + ' to ' + NETDATA.dateTime.localeDateString(date_before) + ' ' + NETDATA.dateTime.localeTimeString(date_before);
2807
- document.getElementById('loadJSONDataResolution').innerHTML = Math.round(result.duration_ms / result.data_points).toString() + ' ms per point, ' + result.data_points.toString() + ' points per dimension';
2808
-
2809
- document.getElementById('loadJSONStatus').className = "alert alert-success";
2810
- document.getElementById('loadJSONStatus').innerHTML = "File loaded, click <b>Import</b> to render it!";
2811
- $('#loadJSONImport').prop('disabled', false);
2812
- $('#loadJSONImport').removeAttr('disabled');
2846
+ document.getElementById('loadSnapshotHostname').innerHTML = '<b>' + result.hostname + '</b>, netdata version <b>' + result.version + '</b>';
2847
+ document.getElementById('loadSnapshotURL').innerHTML = result.url;
2848
+ document.getElementById('loadSnapshotCharts').innerHTML = result.charts.charts_count.toString() + ' charts, ' + result.charts.dimensions_count.toString() + ' dimensions, ' + result.data_points.toString() + ' points per dimension, ' + Math.round(result.duration_ms / result.data_points).toString() + ' ms per point';
2849
+ document.getElementById('loadSnapshotTimeRange').innerHTML = '<b>' + NETDATA.dateTime.localeDateString(date_after) + ' ' + NETDATA.dateTime.localeTimeString(date_after) + '</b> to <b>' + NETDATA.dateTime.localeDateString(date_before) + ' ' + NETDATA.dateTime.localeTimeString(date_before) + '</b>';
2850
+ loadSnapshotModalLog('success', 'File loaded, click <b>Import</b> to render it!');
2851
+ $('#loadSnapshotImport').prop('disabled', false);
2852
+ $('#loadSnapshotImport').removeAttr('disabled');
2853
+
2854
+ tmpSnapshotData = result;
2855
}
2856
catch(e) {
2857
console.log(e);
2816
- document.getElementById('loadJSONStatus').className = "alert alert-danger";
2817
- document.getElementById('loadJSONStatus').innerHTML = "Failed to parse this file!";
2858
+ document.getElementById('loadSnapshotStatus').className = "alert alert-danger";
2859
+ document.getElementById('loadSnapshotStatus').innerHTML = "Failed to parse this file!";
2860
}
2861
}
2862
2863
+ //console.log(files.item(0));
2864
fr.readAsText(files.item(0));
2865
}
2866
2824
- var savePageJSON = '';
2825
- var savePageStop = false;
2826
- function savePageCancel() {
2827
- savePageStop = true;
2867
+ // --------------------------------------------------------------------
2868
+ // saving snapshots
2869
+
2870
+ var saveSnapshotStop = false;
2871
+ function saveSnapshotCancel() {
2872
+ saveSnapshotStop = true;
2873
}
2874
2830
- function savePageStart() {
2831
- savePageStop = false;
2832
- savePageJSON = '';
2875
+ function saveSnapshotStart() {
2876
+ saveSnapshotStop = false;
2877
2878
var save_options = {
2879
stop_updates_when_focus_is_lost: false,
@@ -2852,36 +2896,56 @@
2896
}
2897
}
2898
2855
- var el = document.getElementById('saveModalProgressBar');
2856
- var eltxt = document.getElementById('saveModalProgressBarText');
2899
+ var el = document.getElementById('saveSnapshotModalProgressBar');
2900
+ var eltxt = document.getElementById('saveSnapshotModalProgressBarText');
2901
2858
- var saveJSON = {
2902
+ options.data.charts_by_name = null;
2903
+
2904
+ var saveData = {
2905
+ hostname: options.hostname,
2906
+ version: options.data.version,
2907
after_ms: Date.now() - options.duration * 1000,
2908
before_ms: Date.now(),
2909
duration_ms: options.duration * 1000,
2910
update_every_ms: options.update_every * 1000,
2911
data_points: 0,
2864
- charts: {},
2912
+ url: document.location.origin.toString() + document.location.search.toString(),
2913
+ charts: options.data,
2914
data: {}
2915
+ };
2916
+
2917
+ function pack_api1_v1_chart_data(state) {
2918
+ if(state.library_name === null || state.data === null)
2919
+ return;
2920
+
2921
+ var data = state.data;
2922
+ state.data = null;
2923
+ data.state = null;
2924
+
2925
+ saveData.data[state.chartDataUniqueID()] = JSON.stringify(data);
2926
}
2927
2928
var clearPanAndZoom = false;
2929
if(NETDATA.globalPanAndZoom.isActive() === false) {
2870
- NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], saveJSON.after_ms, saveJSON.before_ms);
2930
+ NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], saveData.after_ms, saveData.before_ms);
2931
clearPanAndZoom = true;
2932
}
2933
2874
- saveJSON.after_ms = NETDATA.globalPanAndZoom.force_after_ms;
2875
- saveJSON.before_ms = NETDATA.globalPanAndZoom.force_before_ms;
2876
- saveJSON.duration_ms = saveJSON.before_ms - saveJSON.after_ms;
2877
- saveJSON.data_points = Math.round((saveJSON.before_ms - saveJSON.after_ms) / saveJSON.update_every_ms);
2934
+ saveData.after_ms = NETDATA.globalPanAndZoom.force_after_ms;
2935
+ saveData.before_ms = NETDATA.globalPanAndZoom.force_before_ms;
2936
+ saveData.duration_ms = saveData.before_ms - saveData.after_ms;
2937
+ saveData.data_points = Math.round((saveData.before_ms - saveData.after_ms) / saveData.update_every_ms);
2938
+ if(saveData.data_points > 10000) {
2939
+ console.log('data points ' + saveData.data_points.toString() + ' is too big - limiting it to 10000');
2940
+ saveData.data_points = 10000;
2941
+ }
2942
2943
var charts_count = 0;
2944
var charts_fetched = 0;
2945
var charts_failed = 0;
2946
2883
- function savePageRestore() {
2884
- $('#saveModal').modal('hide');
2947
+ function saveSnapshotRestore() {
2948
+ $('#saveSnapshotModal').modal('hide');
2949
2950
// restore the options
2951
var x;
@@ -2904,12 +2968,12 @@
2968
2969
NETDATA.pause(function() {
2970
NETDATA.globalSelectionSync.stop();
2907
- NETDATA.options.force_data_points = saveJSON.data_points;
2971
+ NETDATA.options.force_data_points = saveData.data_points;
2972
NETDATA.options.fake_chart_rendering = true;
2973
2974
function update_chart(idx) {
2911
- if(savePageStop === true) {
2912
- savePageRestore();
2975
+ if(saveSnapshotStop === true) {
2976
+ saveSnapshotRestore();
2977
return;
2978
}
2979
@@ -2922,8 +2986,12 @@
2986
setTimeout(function() {
2987
charts_count++;
2988
state.isVisible(true);
2989
+ state.current.force_after_ms = saveData.after_ms;
2990
+ state.current.force_before_ms = saveData.before_ms;
2991
2992
state.updateChart(function(status, reason) {
2993
+ state.current.force_after_ms = null;
2994
+ state.current.force_before_ms = null;
2995
2996
if(status === true) {
2997
charts_fetched++;
@@ -2934,30 +3002,18 @@
3002
state.log('failed to be updated: ' + reason);
3003
}
3004
2937
- // saveJSON.charts[state.id] = state.chart;
2938
- if(state.library_name !== null) {
2939
- var d = state.data;
2940
- state.data = null;
2941
- d.state = undefined;
2942
-
2943
- if (typeof saveJSON.data[state.library_name] === 'undefined')
2944
- saveJSON.data[state.library_name] = {};
2945
-
2946
- saveJSON.data[state.library_name][state.id] = d;
2947
- }
3005
+ pack_api1_v1_chart_data(state);
3006
3007
if (idx > 0) {
3008
update_chart(idx);
3009
}
3010
else {
2953
- // FIXME save it
2954
- saveJSON.charts = options.data;
2955
- saveJSON.charts.charts_by_name = undefined;
3011
+ // save it
3012
+ // console.log(saveData);
3013
+ saveObjectToClient(saveData, 'netdata-dashboard-' + saveData.hostname.toString() + '-' + saveData.after_ms.toString() + '-' + saveData.before_ms.toString() + '.json');
3014
2957
- console.log(saveJSON);
2958
- saveObject(saveJSON, 'netdata-dashboard.json');
2959
-
2960
- savePageRestore();
3015
+ saveSnapshotRestore();
3016
+ saveData = null;
3017
}
3018
})
3019
}, 0);
@@ -2967,6 +3023,9 @@
3023
});
3024
}
3025
3026
+ // --------------------------------------------------------------------
3027
+ // activate netdata on the page
3028
+
3029
function finalizePage() {
3030
// resize all charts - without starting the background thread
3031
// this has to be done while NETDATA is paused
@@ -3170,8 +3229,8 @@
3229
//else console.log('el.find(): not found');
3230
});
3231
3173
- $('#saveModal').on('shown.bs.modal', savePageStart);
3174
- $('#saveModal').on('hide.bs.modal', savePageCancel);
3232
+ $('#saveSnapshotModal').on('shown.bs.modal', saveSnapshotStart);
3233
+ $('#saveSnapshotModal').on('hide.bs.modal', saveSnapshotCancel);
3234
3235
showPageFooter();
3236
@@ -3490,6 +3549,7 @@
3549
3550
// our entry point
3551
// var netdataStarted = performance.now();
3552
+
3553
var netdataCallback = initializeDynamicDashboard;
3554
3555
</script>
@@ -3543,8 +3603,8 @@
3603
<li><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank" title="netdata on github"><i class="fa fa-github"></i></a></li>
3604
<li><a href="https://twitter.com/linuxnetdata" class="btn" target="_blank" title="netdata on twitter"><i class="fa fa-twitter" aria-hidden="true"></i></a></li>
3605
<li><a href="https://www.facebook.com/linuxnetdata/" class="btn" target="_blank" title="netdata on facebook"><i class="fa fa-facebook-official" aria-hidden="true"></i></a></li>
3546
- <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#loadModal" title="load a saved dashboard"><i class="fa fa-upload"></i> <span class="hidden-sm hidden-md">Load</span></a></li>
3547
- <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#saveModal" title="save this dashboard as JSON"><i class="fa fa-download"></i> <span class="hidden-sm hidden-md">Save</span></a></li>
3606
+ <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#loadSnapshotModal" title="load a saved dashboard"><i class="fa fa-upload"></i> <span class="hidden-sm hidden-md">Load</span></a></li>
3607
+ <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#saveSnapshotModal" title="save this dashboard as JSON"><i class="fa fa-download"></i> <span class="hidden-sm hidden-md">Save</span></a></li>
3608
<li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#printPreflightModal" title="print this dashboard"><i class="fa fa-print"></i> <span class="hidden-sm hidden-md">Print</span></a></li>
3609
<li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#helpModal" title="dashboard help"><i class="fa fa-question-circle"></i> <span class="hidden-sm hidden-md">Help</span></a></li>
3610
<li class="dropdown hidden-sm hidden-md hidden-lg">
@@ -3690,7 +3750,7 @@
3750
Please wait while we initialize and render all the charts on the dashboard.
3751
<div class="progress progress-striped active" style="height: 2em !important;">
3752
<div id="printModalProgressBar" class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="min-width: 2em;">
3693
- <span id="printModalProgressBarText" style="padding-top: 4px; font-size: 1.2em; text-align: center; width: 100%; position: absolute; display: block; color: black;"></span>
3753
+ <span id="printModalProgressBarText" style="padding-left: 10px; padding-top: 4px; font-size: 1.2em; text-align: left; width: 100%; position: absolute; display: block; color: black;"></span>
3754
</div>
3755
</div>
3756
The print dialog will appear as soon as we finish rendering the page.
@@ -3701,66 +3761,66 @@
3761
</div>
3762
</div>
3763
3704
- <div class="modal fade" id="loadModal" tabindex="-1" role="dialog" aria-labelledby="loadModalLabel">
3764
+ <div class="modal fade" id="loadSnapshotModal" tabindex="-1" role="dialog" aria-labelledby="loadSnapshotModalLabel">
3765
<div class="modal-dialog modal-lg" role="document">
3766
<div class="modal-content">
3767
<div class="modal-header">
3768
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
3709
- <h4 class="modal-title" id="loadModalLabel">Load a netdata dashboard snapshot...</h4>
3769
+ <h4 class="modal-title" id="loadSnapshotModalLabel">Load a netdata snapshot</h4>
3770
</div>
3771
<div class="modal-body">
3772
<p>
3713
- netdata can load JSON snapshots of netdata dashboards.<br/>
3773
+ netdata can save and load JSON snapshots of netdata dashboards.<br/>
3774
Any netdata can load a saved snapshot of the dashboard of any other netdata.
3775
</p>
3776
<p>
3777
<label class="btn btn-default">
3778
Select a netdata saved JSON file to load
3719
- <input type="file" id="loadJSONSelectFiles" value="Import" style="display: none;"
3720
- onchange="loadPage();">
3779
+ <input type="file" id="loadSnapshotSelectFiles" value="Import" style="display: none;"
3780
+ onchange="loadSnapshotPreflight();">
3781
</label>
3782
</p>
3723
- <div id="loadJSONStatus" class="alert alert-info" role="alert">
3783
+ <div id="loadSnapshotStatus" class="alert alert-info" role="alert">
3784
Click the button above to select the file to load, then click <b>Import</b> to render it.
3785
</div>
3786
<p>
3787
<table class="table">
3788
<tbody>
3729
- <tr><th>Filename</th><td id="loadJSONFilename"></td></tr>
3730
- <tr><th>Hostname</th><td id="loadJSONHostname"></td></tr>
3731
- <tr><th>Netdata Version</th><td id="loadJSONNetdataVersion"></td></tr>
3732
- <tr><th>Time Range</th><td id="loadJSONTimeRange"></td></tr>
3733
- <tr><th>Charts</th><td id="loadJSONCharts"></td></tr>
3734
- <tr><th>Data Resolution</th><td id="loadJSONDataResolution"></td></tr>
3789
+ <tr><th>Filename</th><td id="loadSnapshotFilename"></td></tr>
3790
+ <tr><th>Hostname</th><td id="loadSnapshotHostname"></td></tr>
3791
+ <tr><th>Origin URL</th><td id="loadSnapshotURL"></td></tr>
3792
+ <tr><th>Time Range</th><td id="loadSnapshotTimeRange"></td></tr>
3793
+ <tr><th>Charts</th><td id="loadSnapshotCharts"></td></tr>
3794
</tbody>
3795
</table>
3796
</p>
3797
</div>
3798
<div class="modal-footer">
3740
- <button id="loadJSONImport" type="button" class="btn btn-success btn-disabled" disabled>Import</button>
3799
+ <a id="loadSnapshotImport" href="#" onclick="loadSnapshot(); return false;" type="button" class="btn btn-success btn-disabled" disabled>Import</a>
3800
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
3801
</div>
3802
</div>
3803
</div>
3804
</div>
3805
3747
- <div class="modal fade" id="saveModal" tabindex="-1" role="dialog" aria-labelledby="saveModalLabel" data-keyboard="false" data-backdrop="static">
3806
+ <div class="modal fade" id="saveSnapshotModal" tabindex="-1" role="dialog" aria-labelledby="saveSnapshotModalLabel" data-keyboard="false" data-backdrop="static">
3807
<div class="modal-dialog modal-lg" role="document">
3808
<div class="modal-content">
3809
<div class="modal-header">
3810
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
3752
- <h4 class="modal-title" id="saveModalLabel">Preparing save file...</h4>
3811
+ <h4 class="modal-title" id="saveSnapshotModalLabel">Preparing netdata dashboard snapshot...</h4>
3812
</div>
3813
<div class="modal-body">
3814
Please wait while we collect all the dashboard data...
3815
<div class="progress progress-striped active" style="height: 2em !important;">
3757
- <div id="saveModalProgressBar" class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="min-width: 2em;">
3758
- <span id="saveModalProgressBarText" style="padding-top: 4px; font-size: 1.2em; text-align: center; width: 100%; position: absolute; display: block;"></span>
3816
+ <div id="saveSnapshotModalProgressBar" class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="min-width: 2em;">
3817
+ <span id="saveSnapshotModalProgressBarText" style="padding-left: 10px; padding-top: 4px; font-size: 1.2em; text-align: left; width: 100%; position: absolute; display: block;"></span>
3818
</div>
3819
</div>
3820
The save dialog will appear once we have collected all data.
3821
</div>
3822
<div class="modal-footer">
3823
+ <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
3824
</div>
3825
</div>
3826
</div>
@@ -4635,6 +4695,6 @@
4695
</div>
4696
</div>
4697
</div>
4638
- <script type="text/javascript" src="dashboard.js?v20171112-13"></script>
4698
+ <script type="text/javascript" src="dashboard.js?v20171112-20"></script>
4699
</body>
4700
</html>