Browse Source

Interned strings information now only shows if it's present. (#27)

The panels have been split into their own react components so that the interned strings panel doesn't have to be rendered if the data is not available.  So style rule tweaks were made as a result of the panel change.
Andrew Collington 8 years ago
parent
commit
9ae6980879
3 changed files with 665 additions and 155 deletions
  1. 1 0
      .gitignore
  2. 584 131
      index.php
  3. 80 24
      src/status.jsx

+ 1 - 0
.gitignore

@@ -1,3 +1,4 @@
 /status.js
+/src/status.js
 /.idea
 /.module-cache

+ 584 - 131
index.php

@@ -187,10 +187,7 @@ class OpCacheService
                     'blacklist_miss'     => number_format($status['opcache_statistics']['blacklist_misses']),
                     'num_cached_keys'    => number_format($status['opcache_statistics']['num_cached_keys']),
                     'max_cached_keys'    => number_format($status['opcache_statistics']['max_cached_keys']),
-                    'buffer_size'        => $this->size($status['interned_strings_usage']['buffer_size']),
-                    'strings_used_memory'=> $this->size($status['interned_strings_usage']['used_memory']),
-                    'strings_free_memory'=> $this->size($status['interned_strings_usage']['free_memory']),
-                    'number_of_strings'  => number_format($status['interned_strings_usage']['number_of_strings']),
+                    'interned'           => null,
                     'start_time'         => date('Y-m-d H:i:s', $status['opcache_statistics']['start_time']),
                     'last_restart_time'  => ($status['opcache_statistics']['last_restart_time'] == 0
                             ? 'never'
@@ -199,6 +196,15 @@ class OpCacheService
                 ]
             ]
         );
+        
+        if (!empty($status['interned_strings_usage'])) {
+            $overview['readable']['interned'] = [
+                'buffer_size' => $this->size($status['interned_strings_usage']['buffer_size']),
+                'strings_used_memory' => $this->size($status['interned_strings_usage']['used_memory']),
+                'strings_free_memory' => $this->size($status['interned_strings_usage']['free_memory']),
+                'number_of_strings' => number_format($status['interned_strings_usage']['number_of_strings'])
+            ];
+        }
 
         $directives = [];
         ksort($config['directives']);
@@ -284,8 +290,8 @@ $opcache = OpCacheService::init($options);
         #counts > div > div > p span.large { color: #6ca6ef; font-size: 80pt; margin: 0; padding: 0; text-align: center; }
         #info { margin-right: 280px; }
         #frmFilter { width: 520px; }
-        #moreinfo { padding: 10px; }
-        #moreinfo > p { text-align: left !important; line-height: 180%; }
+        .moreinfo > div { padding: 10px; }
+        .moreinfo > div > p { margin: 0; line-height: 1.75em; }
         .metainfo { font-size: 80%; }
         .hide { display: none; }
         #toggleRealtime.pulse::before {
@@ -529,133 +535,483 @@ $opcache = OpCacheService::init($options);
         $('#frmFilter').bind('keyup', debounce(keyUp, <?php echo $opcache->getOption('debounce_rate'); ?>));
     });
 
-    var MemoryUsage = React.createClass({displayName: "MemoryUsage",
-        getInitialState: function() {
+    var MemoryUsageGraph = React.createClass({
+        getInitialState: function () {
             return {
-                memoryUsageGauge : null
+                memoryUsageGauge: null
             };
         },
-        componentDidMount: function() {
+        componentDidMount: function () {
             if (this.props.chart) {
                 this.state.memoryUsageGauge = new Gauge('#memoryUsageCanvas');
                 this.state.memoryUsageGauge.setValue(this.props.value);
             }
         },
-        componentDidUpdate: function() {
+        componentDidUpdate: function () {
             if (this.state.memoryUsageGauge != null) {
                 this.state.memoryUsageGauge.setValue(this.props.value);
             }
         },
-        render: function() {
+        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, "%")));
+            return React.createElement(
+                "p",
+                null,
+                React.createElement(
+                    "span",
+                    { className: "large" },
+                    this.props.value
+                ),
+                React.createElement(
+                    "span",
+                    null,
+                    "%"
+                )
+            );
         }
     });
 
-    var HitRate = React.createClass({displayName: "HitRate",
-        getInitialState: function() {
+    var HitRateGraph = React.createClass({
+        getInitialState: function () {
             return {
-                hitRateGauge : null
+                hitRateGauge: null
             };
         },
-        componentDidMount: function() {
+        componentDidMount: function () {
             if (this.props.chart) {
                 this.state.hitRateGauge = new Gauge('#hitRateCanvas');
-                this.state.hitRateGauge.setValue(this.props.value)
+                this.state.hitRateGauge.setValue(this.props.value);
             }
         },
-        componentDidUpdate: function() {
+        componentDidUpdate: function () {
             if (this.state.hitRateGauge != null) {
                 this.state.hitRateGauge.setValue(this.props.value);
             }
         },
-        render: function() {
+        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, "%")));
+            return React.createElement(
+                "p",
+                null,
+                React.createElement(
+                    "span",
+                    { className: "large" },
+                    this.props.value
+                ),
+                React.createElement(
+                    "span",
+                    null,
+                    "%"
+                )
+            );
+        }
+    });
+
+    var MemoryUsagePanel = React.createClass({
+        render: function () {
+            return React.createElement(
+                "div",
+                { className: "moreinfo" },
+                React.createElement(
+                    "h3",
+                    null,
+                    "memory usage"
+                ),
+                React.createElement(
+                    "div",
+                    null,
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "total memory:"
+                        ),
+                        " ",
+                        this.props.total
+                    ),
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "used memory:"
+                        ),
+                        " ",
+                        this.props.used
+                    ),
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "free memory:"
+                        ),
+                        " ",
+                        this.props.free
+                    ),
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "wasted memory:"
+                        ),
+                        " ",
+                        this.props.wasted,
+                        " (",
+                        this.props.wastedPercent,
+                        "%)"
+                    )
+                )
+            );
         }
     });
 
-    var OverviewCounts = React.createClass({displayName: "OverviewCounts",
-        getInitialState: function() {
+    var StatisticsPanel = React.createClass({
+        render: function () {
+            return React.createElement(
+                "div",
+                { className: "moreinfo" },
+                React.createElement(
+                    "h3",
+                    null,
+                    "opcache statistics"
+                ),
+                React.createElement(
+                    "div",
+                    null,
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "number of cached files:"
+                        ),
+                        " ",
+                        this.props.num_cached_scripts
+                    ),
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "number of hits:"
+                        ),
+                        " ",
+                        this.props.hits
+                    ),
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "number of misses:"
+                        ),
+                        " ",
+                        this.props.misses
+                    ),
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "blacklist misses:"
+                        ),
+                        " ",
+                        this.props.blacklist_miss
+                    ),
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "number of cached keys:"
+                        ),
+                        " ",
+                        this.props.num_cached_keys
+                    ),
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "max cached keys:"
+                        ),
+                        " ",
+                        this.props.max_cached_keys
+                    )
+                )
+            );
+        }
+    });
+
+    var InternedStringsPanel = React.createClass({
+        render: function () {
+            return React.createElement(
+                "div",
+                { className: "moreinfo" },
+                React.createElement(
+                    "h3",
+                    null,
+                    "interned strings usage"
+                ),
+                React.createElement(
+                    "div",
+                    null,
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "buffer size:"
+                        ),
+                        " ",
+                        this.props.buffer_size
+                    ),
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "used memory:"
+                        ),
+                        " ",
+                        this.props.strings_used_memory
+                    ),
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "free memory:"
+                        ),
+                        " ",
+                        this.props.strings_free_memory
+                    ),
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(
+                            "b",
+                            null,
+                            "number of strings:"
+                        ),
+                        " ",
+                        this.props.number_of_strings
+                    )
+                )
+            );
+        }
+    });
+
+    var OverviewCounts = React.createClass({
+        getInitialState: function () {
             return {
-                data  : opstate.overview,
-                chart : useCharts
+                data: opstate.overview,
+                chart: useCharts
             };
         },
-        render: function() {
-            return (
-                React.createElement("div", null,
-                    React.createElement("div", null,
-                        React.createElement("h3", null, "memory usage"),
-                        React.createElement("p", null, React.createElement(MemoryUsage, {chart: this.state.chart, value: this.state.data.used_memory_percentage}))
+        render: function () {
+            var interned = this.state.data.readable.interned != null ? React.createElement(InternedStringsPanel, {
+                buffer_size: this.state.data.readable.interned.buffer_size,
+                strings_used_memory: this.state.data.readable.interned.strings_used_memory,
+                strings_free_memory: this.state.data.readable.interned.strings_free_memory,
+                number_of_strings: this.state.data.readable.interned.number_of_strings
+            }) : '';
+            return React.createElement(
+                "div",
+                null,
+                React.createElement(
+                    "div",
+                    null,
+                    React.createElement(
+                        "h3",
+                        null,
+                        "memory"
                     ),
-                    React.createElement("div", null,
-                        React.createElement("h3", null, "hit rate"),
-                        React.createElement("p", null, React.createElement(HitRate, {chart: this.state.chart, value: this.state.data.hit_rate_percentage}))
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(MemoryUsageGraph, { chart: this.state.chart, value: this.state.data.used_memory_percentage })
+                    )
+                ),
+                React.createElement(
+                    "div",
+                    null,
+                    React.createElement(
+                        "h3",
+                        null,
+                        "hit rate"
                     ),
-                    React.createElement("div", {id: "moreinfo"},
-                        React.createElement("h3", null, "memory usage"),
-                        React.createElement("p", null, React.createElement("b", null, "total memory:"), " ", this.state.data.readable.total_memory),
-                        React.createElement("p", null, React.createElement("b", null, "used memory:"), " ", this.state.data.readable.used_memory),
-                        React.createElement("p", null, React.createElement("b", null, "free memory:"), " ", this.state.data.readable.free_memory),
-                        React.createElement("p", null, React.createElement("b", null, "wasted memory:"), " ", this.state.data.readable.wasted_memory, " (", this.state.data.wasted_percentage, "%)"),
-                        React.createElement("h3", null, "opcache statistics"),
-                        React.createElement("p", null, React.createElement("b", null, "number of cached files:"), " ", this.state.data.readable.num_cached_scripts),
-                        React.createElement("p", null, React.createElement("b", null, "number of hits:"), " ", this.state.data.readable.hits),
-                        React.createElement("p", null, React.createElement("b", null, "number of misses:"), " ", this.state.data.readable.misses),
-                        React.createElement("p", null, React.createElement("b", null, "blacklist misses:"), " ", this.state.data.readable.blacklist_miss),
-                        React.createElement("p", null, React.createElement("b", null, "number of cached keys:"), " ", this.state.data.readable.num_cached_keys),
-                        React.createElement("p", null, React.createElement("b", null, "max cached keys:"), " ", this.state.data.readable.max_cached_keys),
-                        React.createElement("h3", null, "interned strings usage"),
-                        React.createElement("p", null, React.createElement("b", null, "buffer size:"), " ", this.state.data.readable.buffer_size),
-                        React.createElement("p", null, React.createElement("b", null, "used memory:"), " ", this.state.data.readable.strings_used_memory),
-                        React.createElement("p", null, React.createElement("b", null, "free memory:"), " ", this.state.data.readable.strings_free_memory),
-                        React.createElement("p", null, React.createElement("b", null, "number of strings:"), " ", this.state.data.readable.number_of_strings)
+                    React.createElement(
+                        "p",
+                        null,
+                        React.createElement(HitRateGraph, { chart: this.state.chart, value: this.state.data.hit_rate_percentage })
                     )
-                )
+                ),
+                React.createElement(MemoryUsagePanel, {
+                    total: this.state.data.readable.total_memory,
+                    used: this.state.data.readable.used_memory,
+                    free: this.state.data.readable.free_memory,
+                    wasted: this.state.data.readable.wasted_memory,
+                    wastedPercent: this.state.data.wasted_percentage
+                }),
+                React.createElement(StatisticsPanel, {
+                    num_cached_scripts: this.state.data.readable.num_cached_scripts,
+                    hits: this.state.data.readable.hits,
+                    misses: this.state.data.readable.misses,
+                    blacklist_miss: this.state.data.readable.blacklist_miss,
+                    num_cached_keys: this.state.data.readable.num_cached_keys,
+                    max_cached_keys: this.state.data.readable.max_cached_keys
+                }),
+                interned
             );
         }
     });
 
-    var GeneralInfo = React.createClass({displayName: "GeneralInfo",
-        getInitialState: function() {
+    var GeneralInfo = React.createClass({
+        getInitialState: function () {
             return {
-                version : opstate.version,
-                start : opstate.overview.readable.start_time,
-                reset : opstate.overview.readable.last_restart_time
+                version: opstate.version,
+                start: opstate.overview.readable.start_time,
+                reset: opstate.overview.readable.last_restart_time
             };
         },
-        render: function() {
-            return (
-                React.createElement("table", null,
-                    React.createElement("thead", null,
-                        React.createElement("tr", null, React.createElement("th", {colSpan: "2"}, "General info"))
+        render: function () {
+            return React.createElement(
+                "table",
+                null,
+                React.createElement(
+                    "thead",
+                    null,
+                    React.createElement(
+                        "tr",
+                        null,
+                        React.createElement(
+                            "th",
+                            { colSpan: "2" },
+                            "General info"
+                        )
+                    )
+                ),
+                React.createElement(
+                    "tbody",
+                    null,
+                    React.createElement(
+                        "tr",
+                        null,
+                        React.createElement(
+                            "td",
+                            null,
+                            "Zend OPcache"
+                        ),
+                        React.createElement(
+                            "td",
+                            null,
+                            this.state.version.version
+                        )
+                    ),
+                    React.createElement(
+                        "tr",
+                        null,
+                        React.createElement(
+                            "td",
+                            null,
+                            "PHP"
+                        ),
+                        React.createElement(
+                            "td",
+                            null,
+                            this.state.version.php
+                        )
                     ),
-                    React.createElement("tbody", null,
-                        React.createElement("tr", null, React.createElement("td", null, "Zend OPcache"), React.createElement("td", null, this.state.version.version)),
-                        React.createElement("tr", null, React.createElement("td", null, "PHP"), React.createElement("td", null, this.state.version.php)),
-                        React.createElement("tr", null, React.createElement("td", null, "Host"), React.createElement("td", null, this.state.version.host)),
-                        React.createElement("tr", null, React.createElement("td", null, "Server Software"), React.createElement("td", null, this.state.version.server)),
-                        React.createElement("tr", null, React.createElement("td", null, "Start time"), React.createElement("td", null, this.state.start)),
-                        React.createElement("tr", null, React.createElement("td", null, "Last reset"), React.createElement("td", null, this.state.reset))
+                    React.createElement(
+                        "tr",
+                        null,
+                        React.createElement(
+                            "td",
+                            null,
+                            "Host"
+                        ),
+                        React.createElement(
+                            "td",
+                            null,
+                            this.state.version.host
+                        )
+                    ),
+                    React.createElement(
+                        "tr",
+                        null,
+                        React.createElement(
+                            "td",
+                            null,
+                            "Server Software"
+                        ),
+                        React.createElement(
+                            "td",
+                            null,
+                            this.state.version.server
+                        )
+                    ),
+                    React.createElement(
+                        "tr",
+                        null,
+                        React.createElement(
+                            "td",
+                            null,
+                            "Start time"
+                        ),
+                        React.createElement(
+                            "td",
+                            null,
+                            this.state.start
+                        )
+                    ),
+                    React.createElement(
+                        "tr",
+                        null,
+                        React.createElement(
+                            "td",
+                            null,
+                            "Last reset"
+                        ),
+                        React.createElement(
+                            "td",
+                            null,
+                            this.state.reset
+                        )
                     )
                 )
             );
         }
     });
 
-    var Directives = React.createClass({displayName: "Directives",
-        getInitialState: function() {
-            return { data : opstate.directives };
+    var Directives = React.createClass({
+        getInitialState: function () {
+            return { data: opstate.directives };
         },
-        render: function() {
-            var directiveNodes = this.state.data.map(function(directive) {
-                var map = { 'opcache.':'', '_':' ' };
-                var dShow = directive.k.replace(/opcache\.|_/gi, function(matched){
+        render: function () {
+            var directiveNodes = this.state.data.map(function (directive) {
+                var map = { 'opcache.': '', '_': ' ' };
+                var dShow = directive.k.replace(/opcache\.|_/gi, function (matched) {
                     return map[matched];
                 });
                 var vShow;
@@ -666,77 +1022,141 @@ $opcache = OpCacheService::init($options);
                 } else {
                     vShow = directive.v;
                 }
-                return (
-                    React.createElement("tr", {key: directive.k},
-                        React.createElement("td", {title: 'View ' + directive.k + ' manual entry'}, React.createElement("a", {href: 'http://php.net/manual/en/opcache.configuration.php#ini.'
-                        + (directive.k).replace(/_/g,'-'), target: "_blank"}, dShow)),
-                        React.createElement("td", null, vShow)
+                return React.createElement(
+                    "tr",
+                    { key: directive.k },
+                    React.createElement(
+                        "td",
+                        { title: 'View ' + directive.k + ' manual entry' },
+                        React.createElement(
+                            "a",
+                            { href: 'http://php.net/manual/en/opcache.configuration.php#ini.' + directive.k.replace(/_/g, '-'), target: "_blank" },
+                            dShow
+                        )
+                    ),
+                    React.createElement(
+                        "td",
+                        null,
+                        vShow
                     )
                 );
             });
-            return (
-                React.createElement("table", null,
-                    React.createElement("thead", null,
-                        React.createElement("tr", null, React.createElement("th", {colSpan: "2"}, "Directives"))
-                    ),
-                    React.createElement("tbody", null, directiveNodes)
+            return React.createElement(
+                "table",
+                null,
+                React.createElement(
+                    "thead",
+                    null,
+                    React.createElement(
+                        "tr",
+                        null,
+                        React.createElement(
+                            "th",
+                            { colSpan: "2" },
+                            "Directives"
+                        )
+                    )
+                ),
+                React.createElement(
+                    "tbody",
+                    null,
+                    directiveNodes
                 )
             );
         }
     });
 
-    var Files = React.createClass({displayName: "Files",
-        getInitialState: function() {
+    var Files = React.createClass({
+        getInitialState: function () {
             return {
-                data : opstate.files,
+                data: opstate.files,
                 showing: null,
                 allowFiles: allowFiles
             };
         },
-        handleInvalidate: function(e) {
+        handleInvalidate: function (e) {
             e.preventDefault();
             if (realtime) {
-                $.get('#', { invalidate: e.currentTarget.getAttribute('data-file') }, function(data) {
+                $.get('#', { invalidate: e.currentTarget.getAttribute('data-file') }, function (data) {
                     console.log('success: ' + data.success);
                 }, 'json');
             } else {
                 window.location.href = e.currentTarget.href;
             }
         },
-        render: function() {
+        render: function () {
             if (this.state.allowFiles) {
-                var fileNodes = this.state.data.map(function(file, i) {
+                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"));
+                        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"));
+                        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"
+                            )
+                        );
                     }
-                    return (
-                        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),
-                                    React.createElement(FilesMeta, {data: [file.readable.hits, file.readable.memory_consumption, file.last_used]}),
-                                    invalidate,
-                                    invalidated
-                                )
+                    return 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),
+                                React.createElement(FilesMeta, { data: [file.readable.hits, file.readable.memory_consumption, file.last_used] }),
+                                invalidate,
+                                invalidated
                             )
                         )
                     );
                 }.bind(this));
-                return (
-                    React.createElement("div", null,
-                        React.createElement(FilesListed, {showing: this.state.showing}),
-                        React.createElement("table", null,
-                            React.createElement("thead", null,
-                                React.createElement("tr", null,
-                                    React.createElement("th", null, "Script")
+                return React.createElement(
+                    "div",
+                    null,
+                    React.createElement(FilesListed, { showing: this.state.showing }),
+                    React.createElement(
+                        "table",
+                        null,
+                        React.createElement(
+                            "thead",
+                            null,
+                            React.createElement(
+                                "tr",
+                                null,
+                                React.createElement(
+                                    "th",
+                                    null,
+                                    "Script"
                                 )
-                            ),
-                            React.createElement("tbody", null, fileNodes)
+                            )
+                        ),
+                        React.createElement(
+                            "tbody",
+                            null,
+                            fileNodes
                         )
                     )
                 );
@@ -746,31 +1166,64 @@ $opcache = OpCacheService::init($options);
         }
     });
 
-    var FilesMeta = React.createClass({displayName: "FilesMeta",
-        render: function() {
-            return (
-                React.createElement("span", {className: "metainfo"},
-                    React.createElement("b", null, "hits: "), React.createElement("span", null, this.props.data[0], ", "),
-                    React.createElement("b", null, "memory: "), React.createElement("span", null, this.props.data[1], ", "),
-                    React.createElement("b", null, "last used: "), React.createElement("span", null, this.props.data[2])
+    var FilesMeta = React.createClass({
+        render: function () {
+            return React.createElement(
+                "span",
+                { className: "metainfo" },
+                React.createElement(
+                    "b",
+                    null,
+                    "hits: "
+                ),
+                React.createElement(
+                    "span",
+                    null,
+                    this.props.data[0],
+                    ", "
+                ),
+                React.createElement(
+                    "b",
+                    null,
+                    "memory: "
+                ),
+                React.createElement(
+                    "span",
+                    null,
+                    this.props.data[1],
+                    ", "
+                ),
+                React.createElement(
+                    "b",
+                    null,
+                    "last used: "
+                ),
+                React.createElement(
+                    "span",
+                    null,
+                    this.props.data[2]
                 )
             );
         }
     });
 
-    var FilesListed = React.createClass({displayName: "FilesListed",
-        getInitialState: function() {
+    var FilesListed = React.createClass({
+        getInitialState: function () {
             return {
-                formatted : opstate.overview.readable.num_cached_scripts,
-                total     : opstate.overview.num_cached_scripts
+                formatted: opstate.overview.readable.num_cached_scripts,
+                total: opstate.overview.num_cached_scripts
             };
         },
-        render: function() {
+        render: function () {
             var display = this.state.formatted + ' file' + (this.state.total == 1 ? '' : 's') + ' cached';
             if (this.props.showing !== null && this.props.showing != this.state.total) {
                 display += ', ' + this.props.showing + ' showing due to filter';
             }
-            return (React.createElement("h3", null, display));
+            return React.createElement(
+                "h3",
+                null,
+                display
+            );
         }
     });
 

+ 80 - 24
src/status.jsx

@@ -1,4 +1,4 @@
-var MemoryUsage = React.createClass({
+var MemoryUsageGraph = React.createClass({
     getInitialState: function() {
         return {
             memoryUsageGauge : null
@@ -23,7 +23,7 @@ var MemoryUsage = React.createClass({
     }
 });
 
-var HitRate = React.createClass({
+var HitRateGraph = React.createClass({
     getInitialState: function() {
         return {
             hitRateGauge : null
@@ -48,6 +48,56 @@ var HitRate = React.createClass({
     }
 });
 
+var MemoryUsagePanel = React.createClass({
+    render: function() {
+        return (
+            <div className="moreinfo">
+                <h3>memory usage</h3>
+                <div>
+                    <p><b>total memory:</b> {this.props.total}</p>
+                    <p><b>used memory:</b> {this.props.used}</p>
+                    <p><b>free memory:</b> {this.props.free}</p>
+                    <p><b>wasted memory:</b> {this.props.wasted} ({this.props.wastedPercent}%)</p>
+                </div>
+            </div>
+        );
+    }
+});
+
+var StatisticsPanel = React.createClass({
+    render: function() {
+        return (
+            <div className="moreinfo">
+                <h3>opcache statistics</h3>
+                <div>
+                    <p><b>number of cached files:</b> {this.props.num_cached_scripts}</p>
+                    <p><b>number of hits:</b> {this.props.hits}</p>
+                    <p><b>number of misses:</b> {this.props.misses}</p>
+                    <p><b>blacklist misses:</b> {this.props.blacklist_miss}</p>
+                    <p><b>number of cached keys:</b> {this.props.num_cached_keys}</p>
+                    <p><b>max cached keys:</b> {this.props.max_cached_keys}</p>
+                </div>
+            </div>
+        );
+    }
+});
+
+var InternedStringsPanel = React.createClass({
+    render: function() {
+        return (
+            <div className="moreinfo">
+                <h3>interned strings usage</h3>
+                <div>
+                    <p><b>buffer size:</b> {this.props.buffer_size}</p>
+                    <p><b>used memory:</b> {this.props.strings_used_memory}</p>
+                    <p><b>free memory:</b> {this.props.strings_free_memory}</p>
+                    <p><b>number of strings:</b> {this.props.number_of_strings}</p>
+                </div>
+            </div>
+        );
+    }
+});
+
 var OverviewCounts = React.createClass({
     getInitialState: function() {
         return {
@@ -56,35 +106,41 @@ var OverviewCounts = React.createClass({
         };
     },
     render: function() {
+        var interned = (this.state.data.readable.interned != null 
+            ? <InternedStringsPanel
+                    buffer_size={this.state.data.readable.interned.buffer_size}
+                    strings_used_memory={this.state.data.readable.interned.strings_used_memory}
+                    strings_free_memory={this.state.data.readable.interned.strings_free_memory}
+                    number_of_strings={this.state.data.readable.interned.number_of_strings}
+              /> 
+            : ''
+        );
         return (
             <div>
                 <div>
-                    <h3>memory usage</h3>
-                    <p><MemoryUsage chart={this.state.chart} value={this.state.data.used_memory_percentage} /></p>
+                    <h3>memory</h3>
+                    <p><MemoryUsageGraph chart={this.state.chart} value={this.state.data.used_memory_percentage} /></p>
                 </div>
                 <div>
                     <h3>hit rate</h3>
-                    <p><HitRate chart={this.state.chart} value={this.state.data.hit_rate_percentage} /></p>
-                </div>
-                <div id="moreinfo">
-                    <h3>memory usage</h3>
-                    <p><b>total memory:</b> {this.state.data.readable.total_memory}</p>
-                    <p><b>used memory:</b> {this.state.data.readable.used_memory}</p>
-                    <p><b>free memory:</b> {this.state.data.readable.free_memory}</p>
-                    <p><b>wasted memory:</b> {this.state.data.readable.wasted_memory} ({this.state.data.wasted_percentage}%)</p>
-                    <h3>opcache statistics</h3>
-                    <p><b>number of cached files:</b> {this.state.data.readable.num_cached_scripts}</p>
-                    <p><b>number of hits:</b> {this.state.data.readable.hits}</p>
-                    <p><b>number of misses:</b> {this.state.data.readable.misses}</p>
-                    <p><b>blacklist misses:</b> {this.state.data.readable.blacklist_miss}</p>
-                    <p><b>number of cached keys:</b> {this.state.data.readable.num_cached_keys}</p>
-                    <p><b>max cached keys:</b> {this.state.data.readable.max_cached_keys}</p>
-                    <h3>interned strings usage</h3>
-                    <p><b>buffer size:</b> {this.state.data.readable.buffer_size}</p>
-                    <p><b>used memory:</b> {this.state.data.readable.strings_used_memory}</p>
-                    <p><b>free memory:</b> {this.state.data.readable.strings_free_memory}</p>
-                    <p><b>number of strings:</b> {this.state.data.readable.number_of_strings}</p>
+                    <p><HitRateGraph chart={this.state.chart} value={this.state.data.hit_rate_percentage} /></p>
                 </div>
+                <MemoryUsagePanel
+                    total={this.state.data.readable.total_memory}
+                    used={this.state.data.readable.used_memory}
+                    free={this.state.data.readable.free_memory}
+                    wasted={this.state.data.readable.wasted_memory}
+                    wastedPercent={this.state.data.wasted_percentage}
+                />
+                <StatisticsPanel
+                    num_cached_scripts={this.state.data.readable.num_cached_scripts}
+                    hits={this.state.data.readable.hits}
+                    misses={this.state.data.readable.misses}
+                    blacklist_miss={this.state.data.readable.blacklist_miss}
+                    num_cached_keys={this.state.data.readable.num_cached_keys}
+                    max_cached_keys={this.state.data.readable.max_cached_keys}
+                />
+                {interned}
             </div>
         );
     }