changeset 47:0b71df72ebe1

integrated dashboard into main.html.
author Atul Varma <avarma@mozilla.com>
date Sat, 24 Apr 2010 20:24:54 -0700
parents 1531c2a29e87
children b86cf631e753
files css/main.css js/modules/app.js js/modules/cache.js main.html
diffstat 4 files changed, 245 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/css/main.css	Sat Apr 24 19:16:58 2010 -0700
+++ b/css/main.css	Sat Apr 24 20:24:54 2010 -0700
@@ -46,6 +46,10 @@
     margin: 10em auto;
 }
 
+#reports {
+    padding-top: 1em;
+}
+
 #reports .container {
     display: table;
 }
--- a/js/modules/app.js	Sat Apr 24 19:16:58 2010 -0700
+++ b/js/modules/app.js	Sat Apr 24 20:24:54 2010 -0700
@@ -93,9 +93,195 @@
         $("#login").fadeOut();
       });
 
+    require("app/ui/dashboard").init();
     require("app/login").set($("#login .username").val(),
                              $("#login .password").val());
     if (!require("app/login").isLoggedIn())
       $("#login").fadeIn();
   };
 };
+
+Require.modules["app/ui/dashboard"] = function(exports, require) {
+  var $ = require("jQuery");
+  var cache = require("cache");
+  var dateUtils = require("date-utils");
+  var bugzilla = require("bugzilla");
+  var window = require("window");
+
+  function sortByLastChanged(bugs) {
+    var lctimes = {};
+
+    bugs.forEach(
+      function(bug) {
+        lctimes[bug.id] = dateUtils.dateFromISO8601(bug.last_change_time);
+      });
+
+    function compare(a, b) {
+      var alc = lctimes[a.id];
+      var blc = lctimes[b.id];
+
+      if (alc < blc)
+        return -1;
+      if (alc > blc)
+        return 1;
+      return 0;
+    }
+
+    bugs.sort(compare);
+  }
+
+  function updatePrettyDates(query) {
+    query.find(".last-changed").each(
+      function() {
+        var lcTime = $(this).attr("data-last-change");
+        $(this).text(dateUtils.prettyDate(lcTime));
+      });
+  }
+
+  const PRETTY_DATE_UPDATE_INTERVAL = 1000 * 60;
+
+  window.setInterval(function() { updatePrettyDates($("#reports")); },
+                     PRETTY_DATE_UPDATE_INTERVAL);
+
+  function showBugs(query, bugs) {
+    var table = $("#templates .bugs").clone();
+    var rowTemplate = table.find(".bug-row").remove();
+    sortByLastChanged(bugs);
+    bugs.reverse();
+    bugs.forEach(
+      function(bug) {
+        var row = rowTemplate.clone();
+        row.attr("id", "bug-id-" + bug.id);
+        row.find(".summary").text(bug.summary);
+        row.addClass("status-" + bug.status);
+        if (bug.priority != "--") {
+          row.addClass(bug.priority);
+          row.addClass(bug.severity);
+        }
+        row.find(".last-changed").attr("data-last-change",
+                                       bug.last_change_time);
+
+        row.click(
+          function onClick() {
+            window.open(bugzilla.getShowBugURL(bug.id));
+          });
+
+        row.hover(
+          function onIn() {
+            var tooltip = $("#templates .bug-tooltip").clone();
+            tooltip.find(".priority").text(bug.priority);
+            // TODO: Show more information in tooltip.
+            $(this).append(tooltip);
+          },
+          function onOut() {
+            $(this).find(".bug-tooltip").remove();
+          });
+
+        table.append(row);
+      });
+    updatePrettyDates(table);
+    query.find(".bugs").remove();
+    query.append(table);
+    table.hide();
+    removeDuplicateBugs();
+    table.fadeIn();
+  }
+
+  // Remove duplicate bugs, preferring the first listing of a bug in
+  // the DOM to later ones. This is b/c the reports further down the
+  // page are the less "interesting" ones, and we want to capture
+  // the most "interesting" part of each bug.
+  function removeDuplicateBugs() {
+    var visited = {};
+    $("#reports .bug-row").each(
+      function() {
+        var id = $(this).attr("id");
+        if (id in visited)
+          $(this).remove();
+        else
+          visited[id] = true;
+      });
+  }
+
+  function report(selector, searchTerms) {
+    var newTerms = {__proto__: defaults};
+    for (name in searchTerms)
+      newTerms[name.replace(/_DOT_/g, ".")] = searchTerms[name];
+
+    var cached = cache.get(selector);
+    if (cached)
+      showBugs($(selector), cached);
+    
+    $(selector).find("h2").addClass("loading");
+    
+    bugzilla.search(newTerms,
+                    function(response) {
+                      cache.set(selector, response.bugs);
+                      showBugs($(selector), response.bugs);
+                      $(selector).find("h2").removeClass("loading");
+                    });
+  }
+
+  function timeAgo(ms) {
+    var now = new Date();
+    var then = new Date(now - ms);
+    return dateUtils.dateToISO8601(then);
+  }
+
+  const MS_PER_HOUR = 1000 * 60 * 60;
+  const MS_PER_DAY =  MS_PER_HOUR * 24;
+  const MS_PER_WEEK = MS_PER_DAY * 7;
+
+  var defaults = {
+    changed_after: timeAgo(MS_PER_WEEK * 14)
+  };
+
+  function update(myUsername) {
+    report("#assigned-bugs",
+           {status: ["NEW", "UNCONFIRMED", "ASSIGNED", "REOPENED"],
+            email1: myUsername,
+            email1_type: "equals",
+            email1_assigned_to: 1});
+
+    report("#fixed-bugs",
+           {resolution: ["FIXED"],
+            changed_after: timeAgo(MS_PER_WEEK),
+            email1: myUsername,
+            email1_type: "equals",
+            email1_assigned_to: 1,
+            email1_reporter: 1,
+            email1_cc: 1});
+
+    report("#code-reviews",
+           {status: ["NEW", "UNCONFIRMED", "ASSIGNED", "REOPENED"],
+            flag_DOT_requestee: myUsername});
+
+    report("#reported-bugs",
+           {status: ["NEW", "UNCONFIRMED", "ASSIGNED", "REOPENED"],
+            email1: myUsername,
+            email1_type: "equals",
+            email1_reporter: 1,
+            email2: myUsername,
+            email2_type: "not_equals",
+            email2_assigned_to: 1});
+
+    report("#cc-bugs",
+           {status: ["NEW", "UNCONFIRMED", "ASSIGNED", "REOPENED"],
+            email1: myUsername,
+            email1_type: "equals",
+            email1_cc: 1,
+            email2: myUsername,
+            email2_type: "not_equals",
+            email2_assigned_to: 1,
+            email2_reporter: 1});
+  };
+
+  exports.init = function init() {
+    require("app/login").whenChanged(
+      function changeSearchCriteria(user) {
+        if (user.isLoggedIn) {
+          update(user.username);
+        }
+      });
+  };
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/js/modules/cache.js	Sat Apr 24 20:24:54 2010 -0700
@@ -0,0 +1,10 @@
+Require.modules["cache"] = function(exports) {
+  var cache = {};
+
+  exports.set = function set(key, value) {
+    cache[key] = value;
+  };
+  exports.get = function get(key) {
+    return cache[key];
+  };
+};
--- a/main.html	Sat Apr 24 19:16:58 2010 -0700
+++ b/main.html	Sat Apr 24 20:24:54 2010 -0700
@@ -16,7 +16,14 @@
   </ul>
 </div>
 <div id="loading-screen" class="loading">&nbsp;</div>
-<div id="reports">
+<div id="reports" class="requires-login hide-while-loading">
+  <div class="container">
+    <div id="code-reviews"><h2>My Things To Review</h2></div>
+    <div id="assigned-bugs"><h2>My Assigned Bugs</h2></div>
+    <div id="reported-bugs"><h2>My Reported Bugs</h2></div>
+    <div id="cc-bugs"><h2>My CC'd Bugs</h2></div>
+    <div id="fixed-bugs"><h2>Recently Fixed Bugs</h2></div>
+  </div>
 </div>
 <div id="login" class="dialog">
   <div class="content">
@@ -40,18 +47,52 @@
   </form>
   </div>
 </div>
+<div id="templates">
+  <div class="bug-tooltip">
+    <div>
+      <span class="priority"></span>
+      <span class="severity"></span>
+    </div>
+    <div>
+      <span class="product"></span>
+      <span class="component"></span>
+    </div>
+    <div>Created <span class="age"></span></div>
+  </div>
+  <table class="bugs">
+    <tr class="header">
+      <th>Summary</th>
+      <th>Last&nbsp;Changed</th>
+    </tr>
+    <tr class="bug-row">
+      <td class="summary"></td>
+      <td class="last-changed"></td>
+    </tr>
+  </table>
+</div>
 </body>
 <!-- Base Scripts -->
 <script src="js/jquery.js"></script>
 <script src="js/require.js"></script>
+<script src="js/bugzilla.js"></script>
 <script>
 $(window).ready(function() {
-  var moduleScripts = [
-    "js/modules/app.js"
+  var moduleScriptNames = [
+    "app",
+    "date-utils",
+    "cache"
   ];
 
+  var moduleScripts = [];
+
+  moduleScriptNames.forEach(function(name) {
+    moduleScripts.push("js/modules/" + name + ".js");
+  });
+
   var customModuleExports = {
-    jQuery: jQuery
+    jQuery: jQuery,
+    bugzilla: Bugzilla,
+    window: window
   };
 
   Require.preload(document, moduleScripts, function whenLoaded() {