Browse Source

Starting to construct the Summary dashboard

Gaël Métais 11 years ago
parent
commit
1570a4ce92
3 changed files with 168 additions and 30 deletions
  1. 23 2
      app/node_views/results.html
  2. 94 28
      app/public/scripts/resultsCtrl.js
  3. 51 0
      app/public/styles/results.css

+ 23 - 2
app/node_views/results.html

@@ -35,6 +35,24 @@
 
 
         <div ng-show="view == 'summary' && !phantomasResults.error" class="summary">
         <div ng-show="view == 'summary' && !phantomasResults.error" class="summary">
             <h2>Summary</h2>
             <h2>Summary</h2>
+            
+            <div class="notations">
+                <div>
+                    <div ng-class="notations.domComplexity">{{notations.domComplexity}}</div>
+                    <div>DOM size</div>
+                </div>
+                <div>
+                    <div ng-class="notations.domManipulations">{{notations.domManipulations}}</div>
+                    <div>DOM read and write Requests</div>
+                </div>
+                <div>
+                    <div ng-class="notations.duplicatedDomQueries">{{notations.duplicatedDomQueries}}</div>
+                    <div>Duplicated DOM queries</div>
+                </div>
+            </div>
+
+
+
             <div>Javascript manipulation time: {{totalJSTime}} ms</div>
             <div>Javascript manipulation time: {{totalJSTime}} ms</div>
             <div>Javascript onDOMReady time: {{phantomasResults.metrics.domContentLoadedEnd - phantomasResults.metrics.domContentLoaded}} ms</div>
             <div>Javascript onDOMReady time: {{phantomasResults.metrics.domContentLoadedEnd - phantomasResults.metrics.domContentLoaded}} ms</div>
             <div>Scripts count: {{phantomasResults.metrics.jsCount}}</div>
             <div>Scripts count: {{phantomasResults.metrics.jsCount}}</div>
@@ -42,6 +60,7 @@
             <div>DOM max depth: {{phantomasResults.metrics.DOMelementMaxDepth}}</div>
             <div>DOM max depth: {{phantomasResults.metrics.DOMelementMaxDepth}}</div>
             <div>DOM queries: {{phantomasResults.metrics.DOMqueries}}</div>
             <div>DOM queries: {{phantomasResults.metrics.DOMqueries}}</div>
             <div>DOM inserts: {{phantomasResults.metrics.DOMinserts}}</div>
             <div>DOM inserts: {{phantomasResults.metrics.DOMinserts}}</div>
+            <div>Duplicated DOM queries: {{phantomasResults.metrics.DOMqueriesDuplicated}}</div>
             <div>Events bound: {{phantomasResults.metrics.eventsBound}}</div>
             <div>Events bound: {{phantomasResults.metrics.eventsBound}}</div>
             <div>document.write() calls: {{phantomasResults.metrics.documentWriteCalls}}</div>
             <div>document.write() calls: {{phantomasResults.metrics.documentWriteCalls}}</div>
             <div>eval calls: {{phantomasResults.metrics.evalCalls}}</div>
             <div>eval calls: {{phantomasResults.metrics.evalCalls}}</div>
@@ -74,6 +93,7 @@
                     <div>Params</div>
                     <div>Params</div>
                     <div><!-- details --></div>
                     <div><!-- details --></div>
                     <div>Duration</div>
                     <div>Duration</div>
+                    <div>Start time</div>
                 </div>
                 </div>
                 <div ng-repeat="node in javascript.children"
                 <div ng-repeat="node in javascript.children"
                      ng-if="(!slowRequestsOn || node.data.time > slowRequestsLimit)
                      ng-if="(!slowRequestsOn || node.data.time > slowRequestsLimit)
@@ -163,20 +183,21 @@
                         <div ng-if="node.data.time > slowRequestsLimit" class="warningIcon" title="Slower than {{slowRequestsLimit}} ms"></div>
                         <div ng-if="node.data.time > slowRequestsLimit" class="warningIcon" title="Slower than {{slowRequestsLimit}} ms"></div>
                     </div>
                     </div>
                     <div class="duration" ng-if="node.data.time == undefined"></div>
                     <div class="duration" ng-if="node.data.time == undefined"></div>
+                    <div class="startTime">{{node.data.timestamp}}</div>
                 </div>
                 </div>
             </div>
             </div>
         </div>
         </div>
 
 
         <div ng-show="view == 'metrics' && !phantomasResults.error" class="metrics">
         <div ng-show="view == 'metrics' && !phantomasResults.error" class="metrics">
             <h2>Metrics from Phantomas report</h2>
             <h2>Metrics from Phantomas report</h2>
-            <p>Phantomas is a web performance metrics collector. You can it find <a href="https://github.com/macbre/phantomas" target="_blank">here</a>.</p>
+            <p><a href="https://github.com/macbre/phantomas" target="_blank">Phantomas</a> is a web performance metrics collector. You can find here the (almost) entire list of metrics from Phantomas.</p>
             
             
             <div ng-repeat="(moduleName, module) in metricsModule">
             <div ng-repeat="(moduleName, module) in metricsModule">
                 <h4>{{moduleName}}</h4>
                 <h4>{{moduleName}}</h4>
                 <div ng-repeat="(metricName, metric) in module" ng-if="phantomasResults.metrics[metricName] >= 0" class="module" id="metric_{{metricName}}">
                 <div ng-repeat="(metricName, metric) in module" ng-if="phantomasResults.metrics[metricName] >= 0" class="module" id="metric_{{metricName}}">
                     <div class="value">
                     <div class="value">
                         {{metricName}}: {{phantomasResults.metrics[metricName]}}
                         {{metricName}}: {{phantomasResults.metrics[metricName]}}
-                        <span ng-if="metric.unit == 'ms' || metric.unit == 'bytes'">{{metric.unit}}</span>
+                        <span ng-if="metric.unit == 'ms' || metric.unit == 'bytes' || metric.unit == '%'">{{metric.unit}}</span>
                     </div>
                     </div>
                     <div class="legend">
                     <div class="legend">
                         {{metric.desc}}
                         {{metric.desc}}

+ 94 - 28
app/public/scripts/resultsCtrl.js

@@ -6,14 +6,41 @@ app.controller('ResultsCtrl', function ($scope) {
     $scope.phantomasMetadata = window._phantomas_metadata.metrics;
     $scope.phantomasMetadata = window._phantomas_metadata.metrics;
 
 
     $scope.view = 'summary';
     $scope.view = 'summary';
-    $scope.slowRequestsOn = false;
-    $scope.slowRequestsLimit = 5;
 
 
-    if ($scope.phantomasResults.offenders && $scope.phantomasResults.offenders.javascriptExecutionTree) {
-        
+    if ($scope.phantomasResults.metrics && $scope.phantomasResults.offenders && $scope.phantomasResults.offenders.javascriptExecutionTree) {
+
         // Get the execution tree from the offenders
         // Get the execution tree from the offenders
         $scope.javascript = JSON.parse($scope.phantomasResults.offenders.javascriptExecutionTree);
         $scope.javascript = JSON.parse($scope.phantomasResults.offenders.javascriptExecutionTree);
-    
+
+        initSummaryView();
+        initExecutionView();
+        initMetricsView();
+
+    }
+
+    $scope.setView = function(viewName) {
+        $scope.view = viewName;
+    };
+
+    $scope.onNodeDetailsClick = function(node) {
+        var isOpen = node.data.showDetails;
+        if (!isOpen) {
+            // Close all other nodes
+            $scope.javascript.children.forEach(function(currentNode) {
+                currentNode.data.showDetails = false;
+            });
+
+            // Parse the backtrace
+            if (!node.data.parsedBacktrace) {
+                node.data.parsedBacktrace = parseBacktrace(node.data.backtrace);
+            }
+
+        }
+        node.data.showDetails = !isOpen;
+    };
+
+    function initSummaryView() {
+
         // Read the main elements of the tree and sum the total time
         // Read the main elements of the tree and sum the total time
         $scope.totalJSTime = 0;
         $scope.totalJSTime = 0;
         treeRunner($scope.javascript, function(node) {
         treeRunner($scope.javascript, function(node) {
@@ -26,10 +53,71 @@ app.controller('ResultsCtrl', function ($scope) {
                 return false;
                 return false;
             }
             }
         });
         });
+
+        $scope.notations = {
+            domComplexity: 'A',
+            domManipulations: 'A',
+            duplicatedDomQueries: 'A'
+        };
+
+        var domComplexityScore = $scope.phantomasResults.metrics.DOMelementsCount;
+        if (domComplexityScore > 500) {
+            $scope.notations.domComplexity = 'B';
+        }
+        if (domComplexityScore > 1000) {
+            $scope.notations.domComplexity = 'C';
+        }
+        if (domComplexityScore > 1500) {
+            $scope.notations.domComplexity = 'D';
+        }
+        if (domComplexityScore > 2000) {
+            $scope.notations.domComplexity = 'E';
+        }
+        if (domComplexityScore > 3000) {
+            $scope.notations.domComplexity = 'F';
+        }
+
+        var domManipulationsScore = $scope.phantomasResults.metrics.DOMinserts + $scope.phantomasResults.metrics.DOMqueries * 0.5 + $scope.totalJSTime;
+        if (domManipulationsScore > 50) {
+            $scope.notations.domManipulations = 'B';
+        }
+        if (domManipulationsScore > 100) {
+            $scope.notations.domManipulations = 'C';
+        }
+        if (domManipulationsScore > 200) {
+            $scope.notations.domManipulations = 'D';
+        }
+        if (domManipulationsScore > 500) {
+            $scope.notations.domManipulations = 'E';
+        }
+        if (domManipulationsScore > 1000) {
+            $scope.notations.domManipulations = 'F';
+        }
+
+        var duplicatedDomQueries = $scope.phantomasResults.metrics.DOMqueriesDuplicated;
+        if (duplicatedDomQueries > 5) {
+            $scope.notations.duplicatedDomQueries = 'B';
+        }
+        if (duplicatedDomQueries > 10) {
+            $scope.notations.duplicatedDomQueries = 'C';
+        }
+        if (duplicatedDomQueries > 20) {
+            $scope.notations.duplicatedDomQueries = 'D';
+        }
+        if (duplicatedDomQueries > 50) {
+            $scope.notations.duplicatedDomQueries = 'E';
+        }
+        if (duplicatedDomQueries > 100) {
+            $scope.notations.duplicatedDomQueries = 'F';
+        }
     }
     }
 
 
-    if ($scope.phantomasResults.metrics && $scope.phantomasResults.offenders) {
+    function initExecutionView() {
+        $scope.slowRequestsOn = false;
+        $scope.slowRequestsLimit = 5;
+    }
 
 
+    function initMetricsView() {
         // Get the Phantomas modules from metadata
         // Get the Phantomas modules from metadata
         $scope.metricsModule = {};
         $scope.metricsModule = {};
         for (var metricName in $scope.phantomasMetadata) {
         for (var metricName in $scope.phantomasMetadata) {
@@ -39,30 +127,8 @@ app.controller('ResultsCtrl', function ($scope) {
             }
             }
             $scope.metricsModule[metric.module][metricName] = metric;
             $scope.metricsModule[metric.module][metricName] = metric;
         }
         }
-
     }
     }
 
 
-    $scope.setView = function(viewName) {
-        $scope.view = viewName;
-    };
-
-    $scope.onNodeDetailsClick = function(node) {
-        var isOpen = node.data.showDetails;
-        if (!isOpen) {
-            // Close all other nodes
-            $scope.javascript.children.forEach(function(currentNode) {
-                currentNode.data.showDetails = false;
-            });
-
-            // Parse the backtrace
-            if (!node.data.parsedBacktrace) {
-                node.data.parsedBacktrace = parseBacktrace(node.data.backtrace);
-            }
-
-        }
-        node.data.showDetails = !isOpen;
-    };
-
     function parseBacktrace(str) {
     function parseBacktrace(str) {
         if (!str) {
         if (!str) {
             return null;
             return null;

+ 51 - 0
app/public/styles/results.css

@@ -40,6 +40,56 @@ h4 {
     text-align: left;
     text-align: left;
 }
 }
 
 
+.notations {
+    display: table;
+    width: 25em;
+    margin: 0 auto;
+    border-spacing: 0.5em;
+}
+.notations > div {
+    display: table-row;
+}
+.notations > div > div {
+    display: table-cell;
+    height: 2.5em;
+    vertical-align: middle;
+    font-weight: bold;
+}
+.notations .A, .notations .B, .notations .C, .notations .D, .notations .E, .notations .F, .notations .NA {
+    width: 2.5em;
+    font-size: 2em;
+    text-align: center;
+    border-radius: 0.5em;
+}
+.notations .A {
+    /* green */
+    background: #00DB61;
+}
+.notations .B {
+    /* green */
+    background: #CAD63D;
+}
+.notations .C {
+    /* yellow */
+    background: #FFD119;
+}
+.notations .D {
+    /* orange */
+    background: #FFA319;
+}
+.notations .E {
+    /* red */
+    background: #FF6600;
+}
+.notations .F {
+    /* red */
+    background: #FF1919;
+}
+.notations .NA {
+    /* Non applicable */
+    background: #CCC;
+}
+
 
 
 .metrics h4 {
 .metrics h4 {
     padding-left: 2em;
     padding-left: 2em;
@@ -155,6 +205,7 @@ input.textFilter {
     right: 3em;
     right: 3em;
     top: -3em;
     top: -3em;
     width: 45em;
     width: 45em;
+    min-height: 1em;
     padding: 0 1em 1em;
     padding: 0 1em 1em;
     background: #fff;
     background: #fff;
     border: 2px solid #f1c40f;
     border: 2px solid #f1c40f;