Merge pull request #12 from amnuts/optimise-filter

Fixes #11
This commit is contained in:
Andrew Collington 2016-02-24 00:33:07 +00:00
commit d9fa5c2533
3 changed files with 62 additions and 34 deletions

View file

@ -6,6 +6,8 @@ A clean and responsive interface for Zend OPcache information, showing statistic
## What's new
Version 2.2.2 brings in optimisations for the file listing when filtering
Version 2.2.1 has the gauges now updating with the real-time pulse and a couple rounding issues fixed
Version 2.2.0 provides the ability to turn on/off the file list (default is on)
@ -37,7 +39,8 @@ $options = [
'refresh_time' => 5, // how often the data will refresh, in seconds
'size_precision' => 2, // Digits after decimal point
'size_space' => false, // have '1MB' or '1 MB' when showing sizes
'charts' => true // show gauge chart or just big numbers
'charts' => true, // show gauge chart or just big numbers
'debounce_rate' => 250 // milliseconds after key press to send keyup event when filtering
];
```

View file

@ -6,7 +6,7 @@
* A simple but effective single-file GUI for the OPcache PHP extension.
*
* @author Andrew Collington, andy@amnuts.com
* @version 2.2.1
* @version 2.2.2
* @link https://github.com/amnuts/opcache-gui
* @license MIT, http://acollington.mit-license.org/
*/
@ -24,7 +24,8 @@ $options = [
'refresh_time' => 5, // how often the data will refresh, in seconds
'size_precision' => 2, // Digits after decimal point
'size_space' => false, // have '1MB' or '1 MB' when showing sizes
'charts' => true // show gauge chart or just big numbers
'charts' => true, // show gauge chart or just big numbers
'debounce_rate' => 250 // milliseconds after key press to send keyup event when filtering
];
/*
@ -47,7 +48,8 @@ class OpCacheService
'refresh_time' => 5,
'size_precision' => 2,
'size_space' => false,
'charts' => true
'charts' => true,
'debounce_rate' => 250
];
private function __construct($options = [])
@ -248,6 +250,8 @@ $opcache = OpCacheService::init($options);
table td { padding: 4px 6px; line-height: 1.4em; vertical-align: top; border-color: #fff; }
table tr:nth-child(odd) { background-color: #EFFEFF; }
table tr:nth-child(even) { background-color: #E0ECEF; }
#filelist table tr { background-color: #EFFEFF; }
#filelist table tr.alternate { background-color: #E0ECEF; }
td.pathname { width: 70%; }
footer { border-top: 1px solid #ccc; padding: 1em 2em; }
footer a { padding: 2em; text-decoration: none; opacity: 0.7; }
@ -371,6 +375,36 @@ $opcache = OpCacheService::init($options);
var canInvalidate = <?php echo json_encode($opcache->canInvalidate()); ?>;
var useCharts = <?php echo json_encode($opcache->getOption('charts')); ?>;
var allowFiles = <?php echo json_encode($opcache->getOption('allow_filelist')); ?>;
var debounce = function(func, wait, immediate) {
var timeout;
wait = wait || 250;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) {
func.apply(context, args);
}
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
func.apply(context, args);
}
};
};
function keyUp(event){
var compare = $('#frmFilter').val().toLowerCase();
$('#filelist').find('table tbody tr').each(function(index){
if ($(this).data('path').indexOf(compare) == -1) {
$(this).addClass('hide');
} else {
$(this).removeClass('hide');
}
});
$('#filelist table tbody').trigger('paint');
};
<?php if ($opcache->getOption('charts')): ?>
var Gauge = function(el, colour) {
@ -449,7 +483,7 @@ $opcache = OpCacheService::init($options);
count_formatted : opstate.overview.readable.num_cached_scripts,
count : opstate.overview.num_cached_scripts
});
$('#frmFilter').trigger('keyup');
keyUp();
}
});
}
@ -472,24 +506,15 @@ $opcache = OpCacheService::init($options);
return false;
});
$(document).on('paint', '#filelist table tbody', function(event, params) {
var trs = $('tr', $(this)).not('.hide');
trs.filter(':odd').css({backgroundColor:'#E0ECEF'})
.end().filter(':even').css({backgroundColor:'#EFFEFF'});
filesObj.setState({showing: trs.length});
});
$('#frmFilter').bind('keyup', function(event){
$('span.pathname').each(function(index){
if ($(this).text().toLowerCase().indexOf($('#frmFilter').val().toLowerCase()) == -1) {
$(this).closest('tr').addClass('hide');
} else {
$(this).closest('tr').removeClass('hide');
}
});
$('#filelist table tbody').trigger('paint');
var trs = $('#filelist').find('tbody tr');
trs.removeClass('alternate');
trs.filter(':not(.hide):odd').addClass('alternate');
filesObj.setState({showing: trs.filter(':not(.hide)').length});
});
$('#frmFilter').bind('keyup', debounce(keyUp, <?php echo $opcache->getOption('debounce_rate'); ?>));
});
var MemoryUsage = React.createClass({displayName: 'MemoryUsage',
var MemoryUsage = React.createClass({displayName: "MemoryUsage",
getInitialState: function() {
return {
memoryUsageGauge : null
@ -508,13 +533,13 @@ $opcache = OpCacheService::init($options);
},
render: function() {
if (this.props.chart == true) {
return(React.createElement("canvas", {id: "memoryUsageCanvas", width: "250", height: "250", 'data-value': this.props.value}));
return(React.createElement("canvas", {id: "memoryUsageCanvas", width: "250", height: "250", "data-value": this.props.value}));
}
return(React.createElement("p", null, React.createElement("span", {className: "large"}, this.props.value), React.createElement("span", null, "%")));
}
});
var HitRate = React.createClass({displayName: 'HitRate',
var HitRate = React.createClass({displayName: "HitRate",
getInitialState: function() {
return {
hitRateGauge : null
@ -533,13 +558,13 @@ $opcache = OpCacheService::init($options);
},
render: function() {
if (this.props.chart == true) {
return(React.createElement("canvas", {id: "hitRateCanvas", width: "250", height: "250", 'data-value': this.props.value}));
return(React.createElement("canvas", {id: "hitRateCanvas", width: "250", height: "250", "data-value": this.props.value}));
}
return(React.createElement("p", null, React.createElement("span", {className: "large"}, this.props.value), React.createElement("span", null, "%")));
}
});
var OverviewCounts = React.createClass({displayName: 'OverviewCounts',
var OverviewCounts = React.createClass({displayName: "OverviewCounts",
getInitialState: function() {
return {
data : opstate.overview,
@ -574,7 +599,7 @@ $opcache = OpCacheService::init($options);
}
});
var GeneralInfo = React.createClass({displayName: 'GeneralInfo',
var GeneralInfo = React.createClass({displayName: "GeneralInfo",
getInitialState: function() {
return {
version : opstate.version,
@ -601,7 +626,7 @@ $opcache = OpCacheService::init($options);
}
});
var Directives = React.createClass({displayName: 'Directives',
var Directives = React.createClass({displayName: "Directives",
getInitialState: function() {
return { data : opstate.directives };
},
@ -638,7 +663,7 @@ $opcache = OpCacheService::init($options);
}
});
var Files = React.createClass({displayName: 'Files',
var Files = React.createClass({displayName: "Files",
getInitialState: function() {
return {
data : opstate.files,
@ -658,17 +683,17 @@ $opcache = OpCacheService::init($options);
},
render: function() {
if (this.state.allowFiles) {
var fileNodes = this.state.data.map(function(file) {
var fileNodes = this.state.data.map(function(file, i) {
var invalidate, invalidated;
if (file.timestamp == 0) {
invalidated = React.createElement("span", null, React.createElement("i", {className: "invalid metainfo"}, " - has been invalidated"));
}
if (canInvalidate) {
invalidate = React.createElement("span", null, ", ", React.createElement("a", {className: "metainfo", href: '?invalidate='
+ file.full_path, 'data-file': file.full_path, onClick: this.handleInvalidate}, "force file invalidation"));
+ file.full_path, "data-file": file.full_path, onClick: this.handleInvalidate}, "force file invalidation"));
}
return (
React.createElement("tr", {key: file.full_path},
React.createElement("tr", {key: file.full_path, "data-path": file.full_path.toLowerCase(), className: i%2?'alternate':''},
React.createElement("td", null,
React.createElement("div", null,
React.createElement("span", {className: "pathname"}, file.full_path), React.createElement("br", null),
@ -699,7 +724,7 @@ $opcache = OpCacheService::init($options);
}
});
var FilesMeta = React.createClass({displayName: 'FilesMeta',
var FilesMeta = React.createClass({displayName: "FilesMeta",
render: function() {
return (
React.createElement("span", {className: "metainfo"},
@ -711,7 +736,7 @@ $opcache = OpCacheService::init($options);
}
});
var FilesListed = React.createClass({displayName: 'FilesListed',
var FilesListed = React.createClass({displayName: "FilesListed",
getInitialState: function() {
return {
formatted : opstate.overview.readable.num_cached_scripts,

View file

@ -167,7 +167,7 @@ var Files = React.createClass({
},
render: function() {
if (this.state.allowFiles) {
var fileNodes = this.state.data.map(function(file) {
var fileNodes = this.state.data.map(function(file, i) {
var invalidate, invalidated;
if (file.timestamp == 0) {
invalidated = <span><i className="invalid metainfo"> - has been invalidated</i></span>;
@ -177,7 +177,7 @@ var Files = React.createClass({
+ file.full_path} data-file={file.full_path} onClick={this.handleInvalidate}>force file invalidation</a></span>;
}
return (
<tr key={file.full_path}>
<tr key={file.full_path} data-path={file.full_path.toLowerCase()} className={i%2?'alternate':''}>
<td>
<div>
<span className="pathname">{file.full_path}</span><br/>