diff --git a/extensions/stats/stats.min.js b/extensions/stats/stats.min.js index 6700bbd2a..db8b7b5a0 100644 --- a/extensions/stats/stats.min.js +++ b/extensions/stats/stats.min.js @@ -1 +1 @@ -"use strict";var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};var _slicedToArray=function(){function sliceIterator(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"])_i["return"]();}finally{if(_d)throw _e;}}return _arr;}return function(arr,i){if(Array.isArray(arr)){return arr;}else if(Symbol.iterator in Object(arr)){return sliceIterator(arr,i);}else{throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}();var stats={sys:{error:0,activating:0,requery:null,socket:null,_:{prefix:v___location_prefix,error:connection_error,language:theme_language,convert:{size:Convert.nice_size},chart:Chartist,dayjs:dayjs,locale:{time:config_portable_theme_locale_format_time,offset:function offset(){return get_utc_offset();}},blocked:theme_updating,getHistoryData:function getHistoryData(data){return vars.stats.history;}},selector:{chart:{container:{parent:"live_stats",data:"data-chart"},loader:"data-charts-loader"},collapse:"collapse",dashboard:"system-status",slider:"info-container",piechart:"piechart"},getSocketDefs:function getSocketDefs(){return{session:session.server.data("session-hash"),paused:!this.runRender()?1:0,interval:this.getInterval(),disable:!this.isEnabled()?1:0,shutdown:settings_sysinfo_real_time_shutdown_on_last?1:0};},updateSocket:function updateSocket(){if(this.isEnabled()&&this.socket){var socketData=this.getSocketDefs();this.socket.send(JSON.stringify(socketData));}},graphsCanPreRender:function graphsCanPreRender(){return document.querySelector("["+this.selector.chart.loader+"]")?1:0;},getInterval:function getInterval(){return settings_sysinfo_real_time_run_rate/1000;},getStoredDuration:function getStoredDuration(){return settings_sysinfo_real_time_stored_duration;},runRender:function runRender(){return theme.visibility.get();},isEnabled:function isEnabled(){return settings_sysinfo_real_time_status?1:0;},restart:function restart(){var _this=this;this.shutdown();setTimeout(function(){_this.enable();},this.getInterval()*1000*3);},disable:function disable(){if(this.socket){var socketData=this.getSocketDefs();socketData.paused=1;this.socket.send(JSON.stringify(socketData));}},enable:function enable(){if(this.isEnabled()){if(this.graphsCanPreRender()){this.preRender();}if(this.socket){this.socket.send(JSON.stringify(this.getSocketDefs()));}else{this.activate();}}},shutdown:function shutdown(){if(this.socket){var socketData=this.getSocketDefs();socketData.disable=1;this.socket.send(JSON.stringify(socketData));}},activate:function activate(){if(this.activating++||this._.blocked()||this.socket){return;}$.ajax({context:this,url:this._.prefix+"/stats.cgi",error:function error(){var _this2=this;this.activating=0;if(this.error++>3){return;}!this.requery&&(this.requery=setTimeout(function(){_this2.requery=null;_this2.activate();},this.getInterval()*1000));},success:function success(data){var _this3=this;if(data.success){console.warn("WebSocket connection opened",data);this.socket=new WebSocket(data.socket);this.socket.onopen=function(){_this3.activating=0;console.log("WebSocket connection established",_this3.getSocketDefs());_this3.socket.send(JSON.stringify(_this3.getSocketDefs()));};this.socket.onmessage=function(event){var message=JSON.parse(event.data);_this3.render(message);console.log("Received stats:",message);if(_this3.runRender.last!=_this3.runRender()){_this3.runRender.last=_this3.runRender();_this3.updateSocket();}};this.socket.onclose=function(){console.warn("WebSocket connection closed");setTimeout(function(){_this3.socket=null;_this3.activating=0;_this3.enable();},_this3.getInterval());};}else{this.activating=0;}this.error=0;},dataType:"json"});},preRender:function preRender(){this.render(this._.getHistoryData(),2);},render:function render(data,graphs){var _this4=this;Object.entries(data).map(function(_ref){var _ref2=_slicedToArray(_ref,2),target=_ref2[0],data=_ref2[1];var v=parseInt(data),vo=(typeof data==="undefined"?"undefined":_typeof(data))==="object"?data[data.length-1]:false,vt=vo?vo:v,$pc=$("#"+_this4.selector.dashboard+" ."+_this4.selector.piechart+"[data-charts*=\""+target+"\"]"),$lc=$("."+_this4.selector.slider+" ."+target+"_percent"),$od=$("#"+_this4.selector.dashboard+" span[data-id=\"sysinfo_"+target+"\"], \n ."+_this4.selector.slider+" span[data-data=\""+target+"\"]"),cached=target==="graphs"?graphs?2:_this4.graphsCanPreRender()?2:1:0;if(Number.isInteger(v)){if($pc.length){var piechart=$pc.data("easyPieChart");piechart&&piechart.update(v);}if($lc.length){$lc.find(".bar").attr("style","width:"+v+"%");var $dp=$lc.find(".description"),$lb=$dp.text().split(":")[0];$dp.attr("title",vo).text($lb+": "+v+"% ("+vo+")");}if($od.length){if($od.find("a").length){$od.find("a").text(vt);}else{$od.text(vt);}}}if(cached){var lds=_this4.selector.chart.container.parent+"-"+_this4.selector.collapse,ld=$("#"+lds).find("["+_this4.selector.chart.loader+"]");Object.entries(data).map(function(_ref3){var _ref4=_slicedToArray(_ref3,2),_type=_ref4[0],array=_ref4[1];var options={chart:{type:function type(){return _type==="proc"||_type==="disk"||_type==="net";},bandwidth:function bandwidth(){return _type==="disk"||_type==="net";},fill:function fill(){return this.type()?false:true;},high:function high(){return this.type()?undefined:100;},threshold:function threshold(){return this.type()?-1:50;},height:"100px"}},lg=_this4._.language(_this4.selector.chart.container.parent+"_"+_type),tg=$("#"+lds).find("["+_this4.selector.chart.container.data+"="+_type+"]"),sr=[{name:"series-"+_type,data:array}];if(!tg.length){return;}if(array[0]&&_typeof(array[0].y)==="object"){sr=[];array[0].y.forEach(function(x,i){var data=[];array.forEach(function(n){data.push({data:{x:n.x,y:n.y[i]}});});sr.push({name:"series-"+_type+"-"+i,data:data});});}if(tg[0]&&tg[0].textContent){if(cached===1){var lf=parseInt(_this4.getStoredDuration());if(lf<300||lf>3600){lf=600;}var tdata=sr,cdata=_this4["chart_"+_type].data.series,cdata_start=void 0,cdata_end=void 0,cdata_ready=new Promise(function(resolve){tdata.forEach(function(d,i,a){cdata_start=cdata[i].data[0].x||cdata[i].data[0].data.x;cdata_end=cdata[i].data[cdata[i].data.length-1].x||cdata[i].data[cdata[i].data.length-1].data.x;cdata[i].data.push(d.data[0]);if(cdata_end-cdata_start>lf){cdata[i].data.shift();}if(i===a.length-1){resolve();}});});cdata_ready.then(function(){_this4["chart_"+_type].update({series:cdata});});}}else if(cached===2){_this4["chart_"+_type]=new _this4._.chart.Line(tg[0],{series:sr},{axisX:{type:_this4._.chart.FixedScaleAxis,divisor:12,labelInterpolationFnc:function labelInterpolationFnc(value){return _this4._.dayjs(value*1000).utcOffset(_this4._.locale.offset()).format(_this4._.locale.time);}},height:options.chart.height,showArea:options.chart.fill(),showPoint:!options.chart.fill(),high:options.chart.high(),low:0,fullWidth:true,chartPadding:{left:25},axisY:{onlyInteger:true,labelInterpolationFnc:function labelInterpolationFnc(value){if(options.chart.fill()){return value?value+"%":value;}else if(options.chart.bandwidth(value)){if(_type==="net"){return value?_this4._.convert.size(value,{fixed:0,bits:1,round:1}):value;}return value?_this4._.convert.size(value*1000,{fixed:0,round:1}):value;}else{return value;}}},plugins:[_this4._.chart.plugins.ctAxisTitle({axisY:{axisTitle:lg,axisClass:"ct-axis-title",offset:{x:0,y:9},flipTitle:true}}),_this4._.chart.plugins.ctThreshold({threshold:options.chart.threshold()})]});_this4["chart_"+_type].on("created",function(){return ld.remove();});}});}});}}}; +"use strict";var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};var _slicedToArray=function(){function sliceIterator(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"])_i["return"]();}finally{if(_d)throw _e;}}return _arr;}return function(arr,i){if(Array.isArray(arr)){return arr;}else if(Symbol.iterator in Object(arr)){return sliceIterator(arr,i);}else{throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}();var stats={sys:{error:0,activating:0,requery:null,socket:null,_:{prefix:v___location_prefix,error:connection_error,language:theme_language,convert:{size:Convert.nice_size},chart:Chartist,dayjs:dayjs,locale:{time:config_portable_theme_locale_format_time,offset:function offset(){return get_utc_offset();}},blocked:theme_updating,getHistoryData:function getHistoryData(data){return vars.stats.history;}},selector:{chart:{container:{parent:"live_stats",data:"data-chart"},loader:"data-charts-loader"},collapse:"collapse",dashboard:"system-status",slider:"info-container",piechart:"piechart"},getSocketDefs:function getSocketDefs(){return{session:session.server.data("session-hash"),paused:!this.canRender()?1:0,interval:this.getInterval(),disable:!this.isEnabled()?1:0,shutdown:settings_sysinfo_real_time_shutdown_on_last?1:0};},updateSocket:function updateSocket(){if(this.isEnabled()&&this.socket){var socketData=this.getSocketDefs();this.socket.send(JSON.stringify(socketData));}},graphsCanPreRender:function graphsCanPreRender(){return document.querySelector("["+this.selector.chart.loader+"]")?1:0;},getInterval:function getInterval(){return settings_sysinfo_real_time_run_rate/1000;},getStoredDuration:function getStoredDuration(){return settings_sysinfo_real_time_stored_duration;},getRenderType:function getRenderType(graphs){graphs=graphs.graphs;var hasMultipleDatasets=false;for(var key in graphs){if(graphs.hasOwnProperty(key)&&Array.isArray(graphs[key])){if(graphs[key].length>1){hasMultipleDatasets=true;break;}}}return hasMultipleDatasets?3:null;},canRender:function canRender(){return theme.visibility.get();},isEnabled:function isEnabled(){return settings_sysinfo_real_time_status?1:0;},restart:function restart(){var _this=this;this.shutdown();setTimeout(function(){_this.enable();},this.getInterval()*1000*3);},disable:function disable(){if(this.socket){var socketData=this.getSocketDefs();socketData.paused=1;this.socket.send(JSON.stringify(socketData));}},enable:function enable(){if(this.isEnabled()){if(this.graphsCanPreRender()){this.preRender();}if(this.socket){this.socket.send(JSON.stringify(this.getSocketDefs()));}else{this.activate();}}},shutdown:function shutdown(){if(this.socket){var socketData=this.getSocketDefs();socketData.disable=1;this.socket.send(JSON.stringify(socketData));}},activate:function activate(){if(this.activating++||this._.blocked()||this.socket){return;}$.ajax({context:this,url:this._.prefix+"/stats.cgi",error:function error(){var _this2=this;this.activating=0;if(this.error++>3){return;}!this.requery&&(this.requery=setTimeout(function(){_this2.requery=null;_this2.activate();},this.getInterval()*1000));},success:function success(data){var _this3=this;if(data.success){console.warn("WebSocket connection opened",data);this.socket=new WebSocket(data.socket);this.socket.onopen=function(){_this3.activating=0;console.log("WebSocket connection established",_this3.getSocketDefs());_this3.socket.send(JSON.stringify(_this3.getSocketDefs()));};this.socket.onmessage=function(event){var message=JSON.parse(event.data),renderType=_this3.getRenderType(message);if(_this3.canRender.last!=_this3.canRender()){console.log("Visibility changed",_this3.canRender());_this3.canRender.last=_this3.canRender();_this3.updateSocket();}console.log("Received stats",renderType,message);_this3.render(message,renderType);};this.socket.onclose=function(){console.warn("WebSocket connection closed");setTimeout(function(){_this3.socket=null;_this3.activating=0;_this3.enable();},_this3.getInterval());};}else{this.activating=0;}this.error=0;},dataType:"json"});},preRender:function preRender(){this.render(this._.getHistoryData(),2);},render:function render(data,graphs){var _this4=this;Object.entries(data).map(function(_ref){var _ref2=_slicedToArray(_ref,2),target=_ref2[0],data=_ref2[1];var v=parseInt(data),vo=(typeof data==="undefined"?"undefined":_typeof(data))==="object"?data[data.length-1]:false,vt=vo?vo:v,$pc=$("#"+_this4.selector.dashboard+" ."+_this4.selector.piechart+"[data-charts*=\""+target+"\"]"),$lc=$("."+_this4.selector.slider+" ."+target+"_percent"),$od=$("#"+_this4.selector.dashboard+" span[data-id=\"sysinfo_"+target+"\"], \n ."+_this4.selector.slider+" span[data-data=\""+target+"\"]"),cached=target==="graphs"?graphs?graphs===3?3:2:_this4.graphsCanPreRender()?2:1:0;console.log('Mode',cached);if(Number.isInteger(v)){if($pc.length){var piechart=$pc.data("easyPieChart");piechart&&piechart.update(v);}if($lc.length){$lc.find(".bar").attr("style","width:"+v+"%");var $dp=$lc.find(".description"),$lb=$dp.text().split(":")[0];$dp.attr("title",vo).text($lb+": "+v+"% ("+vo+")");}if($od.length){if($od.find("a").length){$od.find("a").text(vt);}else{$od.text(vt);}}}if(cached){var lds=_this4.selector.chart.container.parent+"-"+_this4.selector.collapse,ld=$("#"+lds).find("["+_this4.selector.chart.loader+"]");Object.entries(data).map(function(_ref3){var _ref4=_slicedToArray(_ref3,2),_type=_ref4[0],array=_ref4[1];var options={chart:{type:function type(){return _type==="proc"||_type==="disk"||_type==="net";},bandwidth:function bandwidth(){return _type==="disk"||_type==="net";},fill:function fill(){return this.type()?false:true;},high:function high(){return this.type()?undefined:100;},threshold:function threshold(){return this.type()?-1:50;},height:"100px"}},lg=_this4._.language(_this4.selector.chart.container.parent+"_"+_type),tg=$("#"+lds).find("["+_this4.selector.chart.container.data+"="+_type+"]"),sr=[{name:"series-"+_type,data:array}];if(!tg.length){return;}if(array[0]&&_typeof(array[0].y)==="object"){sr=[];array[0].y.forEach(function(x,i){var data=[];array.forEach(function(n){data.push({data:{x:n.x,y:n.y[i]}});});sr.push({name:"series-"+_type+"-"+i,data:data});});}if(tg[0]&&tg[0].textContent&&cached!==3){if(cached===1){var lf=parseInt(_this4.getStoredDuration());if(lf<300||lf>3600){lf=600;}var tdata=sr,cdata=_this4["chart_"+_type].data.series,cdata_start=void 0,cdata_end=void 0,cdata_ready=new Promise(function(resolve){tdata.forEach(function(d,i,a){cdata_start=cdata[i].data[0].x||cdata[i].data[0].data.x;cdata_end=cdata[i].data[cdata[i].data.length-1].x||cdata[i].data[cdata[i].data.length-1].data.x;cdata[i].data.push(d.data[0]);if(cdata_end-cdata_start>lf){cdata[i].data.shift();}if(i===a.length-1){resolve();}});});cdata_ready.then(function(){_this4["chart_"+_type].update({series:cdata});});}}else if(cached===2||cached===3){console.warn("Re-drawing chart",_type);_this4["chart_"+_type]=new _this4._.chart.Line(tg[0],{series:sr},{axisX:{type:_this4._.chart.FixedScaleAxis,divisor:12,labelInterpolationFnc:function labelInterpolationFnc(value){return _this4._.dayjs(value*1000).utcOffset(_this4._.locale.offset()).format(_this4._.locale.time);}},height:options.chart.height,showArea:options.chart.fill(),showPoint:!options.chart.fill(),high:options.chart.high(),low:0,fullWidth:true,chartPadding:{left:25},axisY:{onlyInteger:true,labelInterpolationFnc:function labelInterpolationFnc(value){if(options.chart.fill()){return value?value+"%":value;}else if(options.chart.bandwidth(value)){if(_type==="net"){return value?_this4._.convert.size(value,{fixed:0,bits:1,round:1}):value;}return value?_this4._.convert.size(value*1000,{fixed:0,round:1}):value;}else{return value;}}},plugins:[_this4._.chart.plugins.ctAxisTitle({axisY:{axisTitle:lg,axisClass:"ct-axis-title",offset:{x:0,y:9},flipTitle:true}}),_this4._.chart.plugins.ctThreshold({threshold:options.chart.threshold()})]});_this4["chart_"+_type].on("created",function(){return ld.remove();});}});}});}}}; diff --git a/extensions/stats/stats.min.js.gz b/extensions/stats/stats.min.js.gz index cf68adf61..39827dbb5 100644 Binary files a/extensions/stats/stats.min.js.gz and b/extensions/stats/stats.min.js.gz differ diff --git a/extensions/stats/stats.src.js b/extensions/stats/stats.src.js index 9748d573b..26c2c2ca3 100644 --- a/extensions/stats/stats.src.js +++ b/extensions/stats/stats.src.js @@ -58,7 +58,7 @@ const stats = { getSocketDefs: function () { return { session: session.server.data("session-hash"), - paused: !this.runRender() ? 1 : 0, + paused: !this.canRender() ? 1 : 0, interval: this.getInterval(), disable: !this.isEnabled() ? 1 : 0, shutdown: settings_sysinfo_real_time_shutdown_on_last ? 1 : 0, @@ -84,8 +84,24 @@ const stats = { getStoredDuration: function () { return settings_sysinfo_real_time_stored_duration; }, + // Check if the received data has multiple datasets + getRenderType: function(graphs) { + graphs = graphs.graphs; + let hasMultipleDatasets = false; + for (const key in graphs) { + if (graphs.hasOwnProperty(key) && Array.isArray(graphs[key])) { + if (graphs[key].length > 1) { + hasMultipleDatasets = true; + break; + } + } + } + // Received graphs stats have history + // data (3) or a single slice (null) + return hasMultipleDatasets ? 3 : null; + }, // Can we update the stats in the UI? - runRender: function() { + canRender: function() { return theme.visibility.get(); }, // Check if the stats are enabled @@ -172,15 +188,17 @@ const stats = { }; // On socket message this.socket.onmessage = (event) => { - const message = JSON.parse(event.data); - this.render(message); - console.log("Received stats:", message); + const message = JSON.parse(event.data), + renderType = this.getRenderType(message); // Pause stats broadcast for this client // if the tab is not visible - if (this.runRender.last != this.runRender()) { - this.runRender.last = this.runRender(); - this.updateSocket(); + if (this.canRender.last != this.canRender()) { + console.log("Visibility changed", this.canRender()); + this.canRender.last = this.canRender(); + this.updateSocket(); } + console.log("Received stats", renderType, message); + this.render(message, renderType); }; // On socket close this.socket.onclose = () => { @@ -220,7 +238,8 @@ const stats = { $lc = $(`.${this.selector.slider} .${target}_percent`), $od = $(`#${this.selector.dashboard} span[data-id="sysinfo_${target}"], .${this.selector.slider} span[data-data="${target}"]`), - cached = target === "graphs" ? (graphs ? 2 : this.graphsCanPreRender() ? 2 : 1) : 0; + cached = target === "graphs" ? (graphs ? (graphs === 3 ? 3 : 2) : (this.graphsCanPreRender() ? 2 : 1)) : 0; + console.log('Mode', cached); if (Number.isInteger(v)) { // Update pie-charts if ($pc.length) { @@ -309,8 +328,9 @@ const stats = { }); } - // Update series if chart already exist - if (tg[0] && tg[0].textContent) { + // Update series if chart already + // exist unless it's a re-draw + if (tg[0] && tg[0].textContent && cached !== 3) { if (cached === 1) { let lf = parseInt(this.getStoredDuration()); if (lf < 300 || lf > 3600) { @@ -344,8 +364,10 @@ const stats = { } } - // Initialize chart the first time - else if (cached === 2) { + // Initialize chart the first time (2) or fully + // update (3) the chart if it's already drawn + else if (cached === 2 || cached === 3) { + console.warn("Re-drawing chart", type); this[`chart_${type}`] = new this._.chart.Line( tg[0], { diff --git a/stats-lib-funcs.pl b/stats-lib-funcs.pl index 7b3b9f164..16f74d7d7 100644 --- a/stats-lib-funcs.pl +++ b/stats-lib-funcs.pl @@ -144,13 +144,14 @@ sub get_stats_now sub get_stats_history { + my ($noempty) = @_; my $file = "$var_directory/modules/$current_theme". "/real-time-monitoring.json"; my $graphs = jsonify(read_file_contents($file)); # No data yet if (!keys %{$graphs}) { unlink($file); - return get_stats_empty(); + return $noempty ? undef : get_stats_empty(); } # Check if data is right foreach my $k (keys %{$graphs}) { @@ -174,7 +175,8 @@ sub get_stats_history trim_stats_history($graphs); # No data is available anymore if (!keys %{$graphs}) { - return get_stats_empty(); + unlink($file); + return $noempty ? undef : get_stats_empty(); } # Return data return { graphs => $graphs }; diff --git a/stats.pl b/stats.pl index e3e76c22e..6d8177854 100755 --- a/stats.pl +++ b/stats.pl @@ -46,21 +46,60 @@ $serv->shutdown(); return; } + # Has any connection been unpaused? + my $unpaused = grep { + $serv->{'conns'}->{$_}->{'conn'}->{'pausing'} && + !$serv->{'conns'}->{$_}->{'conn'}->{'paused'} } + keys %{$serv->{'conns'}}; + my $stats_history; + # Return full stats for the given user who was unpaused + # to make sure graphs are updated with most recent data + $stats_history = get_stats_history(1) if ($unpaused); # Collect current stats and send them to all connected # clients unless paused for some client my $stats_now = get_stats_now(); + my $stats_now_graphs = $stats_now->{'graphs'}; my $stats_now_json = encode_json($stats_now); foreach my $conn_id (keys %{$serv->{'conns'}}) { my $conn = $serv->{'conns'}->{$conn_id}->{'conn'}; if ($conn->{'verified'} && !$conn->{'paused'}) { + # Unpaused connection needs full stats + if ($conn->{'pausing'}) { + $conn->{'pausing'} = 0; + my $stats_updated; + # Merge stats from both disk data + # and currently cached data + if ($stats_history && $serv->{'stats'}) { + $stats_now->{'graphs'} = + merge_stats($stats_history->{'graphs'}, + $serv->{'stats'}); + $stats_updated++; + # If no cached data then use history + } elsif ($stats_history) { + $stats_now->{'graphs'} = $stats_history->{'graphs'}; + $stats_updated++; + # If no history then use cached data + } elsif ($serv->{'stats'}) { + $stats_updated++; + $stats_now->{'graphs'} = $serv->{'stats'}; + } + # If stats were updated then merge + # them with latest (now) data + if ($stats_updated) { + $stats_now->{'graphs'} = + merge_stats($stats_now->{'graphs'}, + $stats_now_graphs); + } + $stats_now_json = encode_json($stats_now); + } $conn->send_utf8($stats_now_json); } } # Cache stats to server if (!defined($serv->{'stats'})) { - $serv->{'stats'} = $stats_now->{'graphs'}; + $serv->{'stats'} = $stats_now_graphs; } else { - $serv->{'stats'} = merge_stats($serv->{'stats'}, $stats_now->{'graphs'}); + $serv->{'stats'} = merge_stats($serv->{'stats'}, $stats_now_graphs); } # Save stats to history and reset cache if ($serv->{'ticked'}++ % 15 == 0) { @@ -110,6 +149,7 @@ } } # Update connection variables + $conn->{'pausing'} = $conn->{'paused'} // 0; $conn->{'paused'} = $data->{'paused'} // 0; # Update WebSocket server variables $serv->{'interval'} = $data->{'interval'} // 1; diff --git a/theme.info b/theme.info index 958b6111c..8032a92d9 100644 --- a/theme.info +++ b/theme.info @@ -4,7 +4,7 @@ bootstrap=3 spa=1 nomodcall=xnavigation=1 version=21.20-RC4 -mversion=00 +mversion=01 bversion=00 webmin=1 usermin=1 diff --git a/unauthenticated/js/bundle.min.js.gz b/unauthenticated/js/bundle.min.js.gz index 8081a0b5e..5a303e2dd 100644 Binary files a/unauthenticated/js/bundle.min.js.gz and b/unauthenticated/js/bundle.min.js.gz differ