|
@@ -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,
|