Mercurial > bugzilla-dashboard
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"> </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 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() {