From e3b051b686c16ead5f8b63206940b885532e1c95 Mon Sep 17 00:00:00 2001 From: Dave Lawrence Date: Thu, 3 Jan 2013 17:24:56 -0500 Subject: More ProductDashboard work --- extensions/ProductDashboard/Extension.pm | 12 +- extensions/ProductDashboard/lib/Queries.pm | 66 ++-- .../en/default/pages/productdashboard.html.tmpl | 25 +- .../pages/productdashboard/components.html.tmpl | 354 +++++++-------------- .../pages/productdashboard/duplicates.html.tmpl | 71 +---- .../pages/productdashboard/popularity.html.tmpl | 67 +--- .../pages/productdashboard/recents.html.tmpl | 112 ++----- .../pages/productdashboard/roadmap.html.tmpl | 52 +-- .../pages/productdashboard/summary.html.tmpl | 253 +++++---------- extensions/ProductDashboard/web/js/components.js | 75 +++++ extensions/ProductDashboard/web/js/duplicates.js | 28 ++ extensions/ProductDashboard/web/js/popularity.js | 28 ++ .../ProductDashboard/web/js/productdashboard.js | 98 ------ extensions/ProductDashboard/web/js/recents.js | 32 ++ extensions/ProductDashboard/web/js/roadmap.js | 24 ++ extensions/ProductDashboard/web/js/summary.js | 45 +++ .../web/styles/productdashboard.css | 20 ++ 17 files changed, 589 insertions(+), 773 deletions(-) create mode 100644 extensions/ProductDashboard/web/js/components.js create mode 100644 extensions/ProductDashboard/web/js/duplicates.js create mode 100644 extensions/ProductDashboard/web/js/popularity.js delete mode 100644 extensions/ProductDashboard/web/js/productdashboard.js create mode 100644 extensions/ProductDashboard/web/js/recents.js create mode 100644 extensions/ProductDashboard/web/js/roadmap.js create mode 100644 extensions/ProductDashboard/web/js/summary.js (limited to 'extensions') diff --git a/extensions/ProductDashboard/Extension.pm b/extensions/ProductDashboard/Extension.pm index 8ccc897ed..57192f195 100644 --- a/extensions/ProductDashboard/Extension.pm +++ b/extensions/ProductDashboard/Extension.pm @@ -108,10 +108,13 @@ sub _page_dashboard { $vars->{'total_closed_bugs'} = total_closed_bugs($product); $vars->{'severities'} = get_legal_field_values('bug_severity'); + $vars->{'open_bugs_percentage'} = int($vars->{'total_open_bugs'} / $vars->{'total_bugs'} * 100); + $vars->{'closed_bugs_percentage'} = int($vars->{'total_closed_bugs'} / $vars->{'total_bugs'} * 100); + if ($current_tab_name eq 'summary') { $vars->{'by_priority'} = by_priority($product, $bug_status); $vars->{'by_severity'} = by_severity($product, $bug_status); - $vars->{'by_assignee'} = by_assignee($product, $bug_status); + $vars->{'by_assignee'} = by_assignee($product, $bug_status, 50); $vars->{'by_status'} = by_status($product, $bug_status); } @@ -173,11 +176,14 @@ sub _page_dashboard { $milestone_stats{'name'} = $milestone->name; $milestone_stats{'total_bugs'} = total_bug_milestone($product, $milestone); $milestone_stats{'open_bugs'} = bug_milestone_by_status($product, $milestone, 'open'); - $milestone_stats{'closed_bugs'} = bug_milestone_by_status($product, $milestone, 'closed'); + $milestone_stats{'closed_bugs'} = bug_milestone_by_status($product, $milestone, 'closed'); $milestone_stats{'link_total'} = bug_milestone_link_total($product, $milestone); $milestone_stats{'link_open'} = bug_milestone_link_open($product, $milestone); $milestone_stats{'link_closed'} = bug_milestone_link_closed($product, $milestone); - push (@{$vars->{by_roadmap}}, \%milestone_stats); + $milestone_stats{'percentage'} = $milestone_stats{'total_bugs'} + ? int(($milestone_stats{'closed_bugs'} / $milestone_stats{'total_bugs'}) * 100) + : 0; + push (@{$vars->{'by_roadmap'}}, \%milestone_stats); } } } diff --git a/extensions/ProductDashboard/lib/Queries.pm b/extensions/ProductDashboard/lib/Queries.pm index 9c3d91539..fe5d04977 100644 --- a/extensions/ProductDashboard/lib/Queries.pm +++ b/extensions/ProductDashboard/lib/Queries.pm @@ -66,7 +66,7 @@ sub total_closed_bugs { return $dbh->selectrow_array("SELECT COUNT(bug_id) FROM bugs - WHERE bug_status IN ('CLOSED') + WHERE bug_status IN (" . join(',', quoted_closed_states()) . ") AND product_id = ?", undef, $product->id); } @@ -96,12 +96,14 @@ sub by_version { $extra = "AND bugs.bug_status IN (" . join(',', quoted_open_states()) . ")" if $bug_status eq 'open'; $extra = "AND bugs.bug_status IN (" . join(',', quoted_closed_states()) . ")" if $bug_status eq 'closed'; - return $dbh->selectall_arrayref("SELECT version, COUNT(bug_id) + return $dbh->selectall_arrayref("SELECT version, COUNT(bug_id), + ROUND(((COUNT(bugs.bug_id) / ( SELECT COUNT(*) FROM bugs WHERE bugs.product_id = ? $extra)) * 100)) FROM bugs WHERE product_id = ? $extra GROUP BY version - ORDER BY COUNT(bug_id) DESC", undef, $product->id); + ORDER BY COUNT(bug_id) DESC", + undef, $product->id, $product->id); } sub by_milestone { @@ -112,12 +114,14 @@ sub by_milestone { $extra = "AND bugs.bug_status IN (" . join(',', quoted_open_states()) . ")" if $bug_status eq 'open'; $extra = "AND bugs.bug_status IN (" . join(',', quoted_closed_states()) . ")" if $bug_status eq 'closed'; - return $dbh->selectall_arrayref("SELECT target_milestone, COUNT(bug_id) + return $dbh->selectall_arrayref("SELECT target_milestone, COUNT(bug_id), + ROUND(((COUNT(bugs.bug_id) / ( SELECT COUNT(*) FROM bugs WHERE bugs.product_id = ? $extra)) * 100)) FROM bugs WHERE product_id = ? $extra GROUP BY target_milestone - ORDER BY COUNT(bug_id) DESC", undef, $product->id); + ORDER BY COUNT(bug_id) DESC", + undef, $product->id, $product->id); } sub by_priority { @@ -128,12 +132,14 @@ sub by_priority { $extra = "AND bugs.bug_status IN (" . join(',', quoted_open_states()) . ")" if $bug_status eq 'open'; $extra = "AND bugs.bug_status IN (" . join(',', quoted_closed_states()) . ")" if $bug_status eq 'closed'; - return $dbh->selectall_arrayref("SELECT priority, COUNT(bug_id) + return $dbh->selectall_arrayref("SELECT priority, COUNT(bug_id), + ROUND(((COUNT(bugs.bug_id) / ( SELECT COUNT(*) FROM bugs WHERE bugs.product_id = ? $extra)) * 100)) FROM bugs WHERE product_id = ? $extra GROUP BY priority - ORDER BY COUNT(bug_id) DESC", undef, $product->id); + ORDER BY COUNT(bug_id) DESC", + undef, $product->id, $product->id); } sub by_severity { @@ -144,12 +150,14 @@ sub by_severity { $extra = "AND bugs.bug_status IN (" . join(',', quoted_open_states()) . ")" if $bug_status eq 'open'; $extra = "AND bugs.bug_status IN (" . join(',', quoted_closed_states()) . ")" if $bug_status eq 'closed'; - return $dbh->selectall_arrayref("SELECT bug_severity, COUNT(bug_id) + return $dbh->selectall_arrayref("SELECT bug_severity, COUNT(bug_id), + ROUND(((COUNT(bugs.bug_id) / ( SELECT COUNT(*) FROM bugs WHERE bugs.product_id = ? $extra)) * 100)) FROM bugs WHERE product_id = ? $extra GROUP BY bug_severity - ORDER BY COUNT(bug_id) DESC", undef, $product->id); + ORDER BY COUNT(bug_id) DESC", + undef, $product->id, $product->id); } sub by_component { @@ -160,12 +168,14 @@ sub by_component { $extra = "AND bugs.bug_status IN (" . join(',', quoted_open_states()) . ")" if $bug_status eq 'open'; $extra = "AND bugs.bug_status IN (" . join(',', quoted_closed_states()) . ")" if $bug_status eq 'closed'; - return $dbh->selectall_arrayref("SELECT components.name, COUNT(bugs.bug_id) + return $dbh->selectall_arrayref("SELECT components.name, COUNT(bugs.bug_id), + ROUND(((COUNT(bugs.bug_id) / ( SELECT COUNT(*) FROM bugs WHERE bugs.product_id = ? $extra)) * 100)) FROM bugs INNER JOIN components ON bugs.component_id = components.id WHERE bugs.product_id = ? $extra GROUP BY components.name - ORDER BY COUNT(bugs.bug_id) DESC", undef, $product->id); + ORDER BY COUNT(bugs.bug_id) DESC", + undef, $product->id, $product->id); } sub by_value_summary { @@ -225,20 +235,21 @@ sub by_assignee { my $dbh = Bugzilla->dbh; my $extra; - $limit = detaint_natural($limit) ? $dbh->sql_limit($limit) : ""; + $limit = ($limit && detaint_natural($limit)) ? $dbh->sql_limit($limit) : ""; $extra = "AND bugs.bug_status IN (" . join(',', quoted_open_states()) . ")" if $bug_status eq 'open'; $extra = "AND bugs.bug_status IN (" . join(',', quoted_closed_states()) . ")" if $bug_status eq 'closed'; - my @result = map { [ Bugzilla::User->new($_->[0]), $_->[1] ] } - @{$dbh->selectall_arrayref("SELECT bugs.assigned_to AS userid, COUNT(bugs.bug_id) + my @result = map { [ Bugzilla::User->new($_->[0]), $_->[1], $_->[2] ] } + @{$dbh->selectall_arrayref("SELECT bugs.assigned_to AS userid, COUNT(bugs.bug_id), + ROUND(((COUNT(bugs.bug_id) / ( SELECT COUNT(*) FROM bugs WHERE bugs.product_id = ? $extra)) * 100)) FROM bugs, profiles WHERE bugs.product_id = ? AND bugs.assigned_to = profiles.userid $extra GROUP BY profiles.login_name ORDER BY COUNT(bugs.bug_id) DESC $limit", - undef, $product->id)}; + undef, $product->id, $product->id)}; return \@result; } @@ -251,12 +262,14 @@ sub by_status { $extra = "AND bugs.bug_status IN (" . join(',', quoted_open_states()) . ")" if $bug_status eq 'open'; $extra = "AND bugs.bug_status IN (" . join(',', quoted_closed_states()) . ")" if $bug_status eq 'closed'; - return $dbh->selectall_arrayref("SELECT bugs.bug_status, COUNT(bugs.bug_id) + return $dbh->selectall_arrayref("SELECT bugs.bug_status, COUNT(bugs.bug_id), + ROUND(((COUNT(bugs.bug_id) / ( SELECT COUNT(*) FROM bugs WHERE bugs.product_id = ? $extra)) * 100)) FROM bugs WHERE bugs.product_id = ? $extra GROUP BY bugs.bug_status - ORDER BY COUNT(bugs.bug_id) DESC", undef, $product->id); + ORDER BY COUNT(bugs.bug_id) DESC", + undef, $product->id, $product->id); } sub total_bug_milestone { @@ -267,10 +280,7 @@ sub total_bug_milestone { FROM bugs WHERE target_milestone = ? AND product_id = ?", - undef, - $milestone->name, - $product->id); - + undef, $milestone->name, $product->id); } sub bug_milestone_by_status { @@ -294,7 +304,7 @@ sub bug_milestone_by_status { sub by_duplicate { my ($product, $bug_status, $limit) = @_; my $dbh = Bugzilla->dbh; - $limit = detaint_natural($limit) ? $dbh->sql_limit($limit) : ""; + $limit = ($limit && detaint_natural($limit)) ? $dbh->sql_limit($limit) : ""; my $extra; $extra = "AND bugs.bug_status IN (" . join(',', quoted_open_states()) . ")" if $bug_status eq 'open'; @@ -324,7 +334,7 @@ sub by_duplicate { sub by_popularity { my ($product, $bug_status, $limit) = @_; my $dbh = Bugzilla->dbh; - $limit = detaint_natural($limit) ? $dbh->sql_limit($limit) : ""; + $limit = ($limit && detaint_natural($limit)) ? $dbh->sql_limit($limit) : ""; my $extra; $extra = "AND bugs.bug_status IN (" . join(',', quoted_open_states()) . ")" if $bug_status eq 'open'; @@ -359,7 +369,7 @@ sub recently_opened { my $date_to = $params->{'date_to'}; $days ||= 7; - $limit = detaint_natural($limit) ? $dbh->sql_limit($limit) : ""; + $limit = ($limit && detaint_natural($limit)) ? $dbh->sql_limit($limit) : ""; my @values = ($product->id); @@ -375,7 +385,7 @@ sub recently_opened { push(@values, trick_taint($date_from), trick_taint($date_to)); } else { - $date_part = "AND bugs.creation_ts >= NOW() - " . $dbh->sql_to_days('?'); + $date_part = "AND bugs.creation_ts >= CURRENT_DATE() - INTERVAL ? DAY"; push(@values, $days); } @@ -407,7 +417,7 @@ sub recently_closed { my $date_to = $params->{'date_to'}; $days ||= 7; - $limit = detaint_natural($limit) ? $dbh->sql_limit($limit) : ""; + $limit = ($limit && detaint_natural($limit)) ? $dbh->sql_limit($limit) : ""; my @values = ($product->id); @@ -419,11 +429,11 @@ sub recently_closed { validate_date($date_to) || ThrowUserError('illegal_date', { date => $date_to, format => 'YYYY-MM-DD' }); - $date_part = "AND bugs.creation_ts >= ? AND bugs.creation_ts <= ?"; + $date_part = "AND bugs_activity.bug_when >= ? AND bugs_activity.bug_when <= ?"; push(@values, trick_taint($date_from), trick_taint($date_to)); } else { - $date_part = "AND bugs.creation_ts >= NOW() - " . $dbh->sql_to_days('?'); + $date_part = "AND bugs_activity.bug_when >= CURRENT_DATE() - INTERVAL ? DAY"; push(@values, $days); } diff --git a/extensions/ProductDashboard/template/en/default/pages/productdashboard.html.tmpl b/extensions/ProductDashboard/template/en/default/pages/productdashboard.html.tmpl index daf0ea6df..6ae515f34 100644 --- a/extensions/ProductDashboard/template/en/default/pages/productdashboard.html.tmpl +++ b/extensions/ProductDashboard/template/en/default/pages/productdashboard.html.tmpl @@ -8,19 +8,36 @@ [% PROCESS global/variables.none.tmpl %] +[% javascript_urls = [ "js/util.js", "js/field.js" ] %] + +[% IF current_tab_name == 'summary' %] + [% javascript_urls.push("extensions/ProductDashboard/web/js/summary.js") %] + [% ELSIF current_tab_name == 'recents' %] + [% yui = [ "calendar" ] %] + [% javascript_urls.push("js/field.js") %] + [% javascript_urls.push("js/util.js") %] + [% javascript_urls.push("extensions/ProductDashboard/web/js/recents.js") %] +[% ELSIF current_tab_name == 'components' %] + [% javascript_urls.push("extensions/ProductDashboard/web/js/components.js") %] +[% ELSIF current_tab_name == 'duplicates' %] + [% javascript_urls.push("extensions/ProductDashboard/web/js/duplicates.js") %] +[% ELSIF current_tab_name == 'popularity' %] + [% javascript_urls.push("extensions/ProductDashboard/web/js/popularity.js") %] +[% ELSIF current_tab_name == 'roadmap' && Param('usetargetmilestone') %] + [% javascript_urls.push("extensions/ProductDashboard/web/js/roadmap.js") %] +[% END %] + [% filtered_product = product.name FILTER html %] [% PROCESS global/header.html.tmpl title = "Product Dashboard: $filtered_product" style_urls = [ "skins/standard/buglist.css", "js/yui/assets/skins/sam/paginator.css", "extensions/ProductDashboard/web/styles/productdashboard.css" ] - yui = [ "datatable", "paginator", "calendar" ] - javascript_urls = [ "js/util.js", "js/field.js", - "extensions/ProductDashboard/web/js/productdashboard.js" ] %] - [% IF user.is_timetracker %] -

- Past Due | - Updated Recently -

+ // Bugs updated recently + PD.updated_recently = [ + [% FOREACH bug = summary.updated_recently %] + { + id: '[% bug.id FILTER js %]', + bug_status: '[% bug.status FILTER js %]', + version: '[% bug.version FILTER js %]', + component: '[% bug.component FILTER js %]', + severity: '[% bug.severity FILTER js %]', + summary: '[% bug.summary FILTER js %]' + }, [% END %] + ]; +--> + + +[% IF user.is_timetracker %] +

+ Past Due | + Updated Recently +

+[% END %] -
+
- [% IF user.is_timetracker %] - - [% summary.past_due.size FILTER html %] Past Due [% terms.Bugs %] (deadline is before today's date) - (full list) -
- - - - [% FOREACH column = [ "ID", "Status", "Version", "Component", "Severity" "Summary" ] %] - - [% END %] - - - - [% FOREACH bug = summary.past_due %] - [% count = loop.count() %] - - - - - - - - - [% END %] - -
[% column FILTER html %]
- [% bug.id FILTER html %][% bug.status FILTER html %][% bug.version FILTER html %][% bug.component FILTER html %][% bug.severity FILTER html %][% bug.summary FILTER html %]
-
-
- [% END %] + [% IF user.is_timetracker %] + + [% summary.past_due.size FILTER html %] Past Due [% terms.Bugs %] (deadline is before today's date) + (full list) +
+
+ [% END %] - - [% summary.updated_recently.size FILTER html %] Most Recently Updated [% terms.Bugs %] - [% IF user.is_timetracker %](back to top)[% END %] - (full list) -
- - - - [% FOREACH column = [ "ID", "Status", "Version", "Component", "Severity" "Summary" ] %] - - [% END %] - - - - [% FOREACH bug = summary.updated_recently %] - [% count = loop.count() %] - - - - - - - - - [% END %] - -
[% column FILTER html %]
- [% bug.id FILTER html %][% bug.status FILTER html %][% bug.version FILTER html %][% bug.component FILTER html %][% bug.severity FILTER html %][% bug.summary FILTER html %]
-
-
+ + [% summary.updated_recently.size FILTER html %] Most Recently Updated [% terms.Bugs %] + [% IF user.is_timetracker %](back to top)[% END %] + (full list) +
+
[% ELSE %] - - - [% summary_url = "page.cgi?id=productdashboard.html&product=$url_filtered_product&bug_status=$url_filtered_status&tab=components" %] - -

[% terms.Bug %] counts per component, version and milestone.

- -

- Component | - Version | - Milestone -

-

Click on a value to show a list of most recently updated [% terms.bugs %].

+ // Version counts + PD.version_counts = [ + [% FOREACH col = by_version %] + { + name: "[% col.0 FILTER js %]", + count: [% col.1 || 0 FILTER js %], + percentage: [% col.2 || 0 FILTER js %], + link: 'Link' + }, + [% END %] + ]; -
- - Component -
- - - - - - - - - - - [% FOREACH col = by_component %] - - - - - - + [% IF Param('usetargetmilestone') %] + // Milestone counts + PD.milestone_counts = [ + [% FOREACH col = by_milestone %] + { + name: "[% col.0 FILTER js %]", + count: [% col.1 || 0 FILTER js %], + percentage: [% col.2 || 0 FILTER js %], + link: 'Link' + }, [% END %] - -
NameCountPercentage[% terms.Bug %] List
- - [% col.0 FILTER html %] - - [% col.1 FILTER html %] - - [% INCLUDE bar_graph count = col.1 %] - - View -
-
+ ]; + [% END %] +--> + + +

[% terms.Bug %] counts per component, version and milestone.

+ +

+ Component | + Version | + Milestone +

+ +

Click on a value to show a list of most recently updated [% terms.bugs %].

+ +
+ + Component +
+
+ + Version + (back to top) +
+ [% IF Param('usetargetmilestone') %]
- - Version + + Milestone (back to top) -
- - - - - - - - - - - [% FOREACH col = by_version %] - - - - - - - [% END %] - -
NameCountPercentage[% terms.Bug %] List
- - [% col.0 FILTER html %] - - [% col.1 FILTER html %] - - [% INCLUDE bar_graph count = col.1 %] - - View -
-
- - [% IF Param('usetargetmilestone') %] -
- - Milestone - (back to top) -
- - - - - - - - - - - [% FOREACH col = by_milestone %] - - - - - - - [% END %] - -
NameCountPercentage[% terms.Bug %] List
- - [% col.0 FILTER html %] - - [% col.1 FILTER html %] - - [% INCLUDE bar_graph count = col.1 %] - - View -
-
- [% END %] -
+
+ [% END %] +
[% END %] diff --git a/extensions/ProductDashboard/template/en/default/pages/productdashboard/duplicates.html.tmpl b/extensions/ProductDashboard/template/en/default/pages/productdashboard/duplicates.html.tmpl index bf1cdaeb1..585cdc829 100644 --- a/extensions/ProductDashboard/template/en/default/pages/productdashboard/duplicates.html.tmpl +++ b/extensions/ProductDashboard/template/en/default/pages/productdashboard/duplicates.html.tmpl @@ -6,69 +6,28 @@ # defined by the Mozilla Public License, v. 2.0. #%] - -

Most duplicated [% terms.bugs %]

[% IF by_duplicate.size %] [% by_duplicate.size FILTER html %] [% terms.Bugs %] Found -
-
- - - - [% FOREACH column = [ "ID", "Dupe Count", "Status", "Version" - "Component", "Severity" "Summary" ] %] - - - [% END %] - - - - [% FOREACH bug = by_duplicate %] - [% count = loop.count() %] - - - - - - - - - - [% END %] - -
[% column FILTER html %]
- [% bug.id FILTER html %][% bug.dupe_count FILTER html %][% bug.status FILTER html %][% bug.version FILTER html %][% bug.component FILTER html %][% bug.severity FILTER html %][% bug.summary FILTER html %]
-
+
+
[% ELSE %] No duplicate [% terms.bugs %] found. diff --git a/extensions/ProductDashboard/template/en/default/pages/productdashboard/popularity.html.tmpl b/extensions/ProductDashboard/template/en/default/pages/productdashboard/popularity.html.tmpl index 5ecad3426..933f26c81 100644 --- a/extensions/ProductDashboard/template/en/default/pages/productdashboard/popularity.html.tmpl +++ b/extensions/ProductDashboard/template/en/default/pages/productdashboard/popularity.html.tmpl @@ -11,64 +11,27 @@

Most voted on [% terms.bugs %]

[% IF by_popularity.size %] [% by_popularity.size FILTER html %] [% terms.Bugs %] Found -
-
- - - - [% FOREACH column = [ "ID", "Count", "Status", "Version" - "Component", "Severity" "Summary" ] %] - - - [% END %] - - - - [% FOREACH bug = by_popularity %] - [% count = loop.count() %] - - - - - - - - - - [% END %] - -
[% column FILTER html %]
- [% bug.id FILTER html %][% bug.votes FILTER html %][% bug.status FILTER html %][% bug.version FILTER html %][% bug.component FILTER html %][% bug.severity FILTER html %][% bug.summary FILTER html %]
-
+
+
[% ELSE %] No [% terms.bugs %] found. diff --git a/extensions/ProductDashboard/template/en/default/pages/productdashboard/recents.html.tmpl b/extensions/ProductDashboard/template/en/default/pages/productdashboard/recents.html.tmpl index 919a7da97..18227aec2 100644 --- a/extensions/ProductDashboard/template/en/default/pages/productdashboard/recents.html.tmpl +++ b/extensions/ProductDashboard/template/en/default/pages/productdashboard/recents.html.tmpl @@ -6,36 +6,36 @@ # defined by the Mozilla Public License, v. 2.0. #%] - -

Most recently opened and closed [% terms.bugs %]

@@ -50,7 +50,7 @@ PD.addStatListener("recently_closed", "recently_closed_table", to @@ -60,7 +60,7 @@ PD.addStatListener("recently_closed", "recently_closed_table",

Percentage of [% terms.bug %] closure per milestone

-
-
- - - - - - - - - - [% FOREACH milestone = by_roadmap %] - - - - - - [% END %] - -
MilestonePercentage CompleteLinks
[% milestone.name FILTER html %] - [% INCLUDE bar_graph count = milestone.closed_bugs full_bug_count = milestone.total_bugs %] - - - [% milestone.closed_bugs FILTER html %] of  - - [% milestone.total_bugs FILTER html %] bugs have been closed -
-
+
+
diff --git a/extensions/ProductDashboard/template/en/default/pages/productdashboard/summary.html.tmpl b/extensions/ProductDashboard/template/en/default/pages/productdashboard/summary.html.tmpl index a7398c823..e454ee8e8 100644 --- a/extensions/ProductDashboard/template/en/default/pages/productdashboard/summary.html.tmpl +++ b/extensions/ProductDashboard/template/en/default/pages/productdashboard/summary.html.tmpl @@ -6,34 +6,79 @@ # defined by the Mozilla Public License, v. 2.0. #%] -

Summary of [% terms.bug %] counts

@@ -50,168 +95,28 @@ PD.addStatListener("assignee_counts", "assignee_counts_table", Assignee

-
+
[% terms.Bug %] Counts -
- - - - - - - - - - - - - - - - - - - - - - - - - -
NameCountPercentage
Total [% terms.Bugs %][% total_bugs FILTER html %] 
Open [% terms.Bugs %][% total_open_bugs FILTER html %] - [% INCLUDE bar_graph count = total_open_bugs full_bug_count = total_bugs %] -
Closed [% terms.Bugs %][% total_closed_bugs FILTER html %] - [% INCLUDE bar_graph count = total_closed_bugs full_bug_count = total_bugs %] -
-
+

Status (back to top) -
- - - - - - - - - - [% FOREACH col = by_status %] - [% NEXT IF col.0 == 'CLOSED' %] - - - - - - [% END %] - -
NameCountPercentage
- - [% col.0 FILTER html %] - - [% col.1 FILTER html %] - - [% INCLUDE bar_graph count = col.1 %] -
-
+

Priority (back to top) -
- - - - - - - - - - [% FOREACH col = by_priority %] - - - - - - [% END %] - -
NameCountPercentage
- - [% col.0 FILTER html %] - - [% col.1 FILTER html %] - - [% INCLUDE bar_graph count = col.1 %] -
-
+

Severity (back to top) -
- - - - - - - - - - [% FOREACH col = by_severity %] - - - - - - [% END %] - -
NameCountPercentage
- - [% col.0 FILTER html %] - - [% col.1 FILTER html %] - - [% INCLUDE bar_graph count = col.1 %] -
-
+

Assignee (back to top) -
- - - - - - - - - - [% FOREACH col = by_assignee %] - - - - - - [% END %] - -
NameCountPercentage
- [% IF user.id %] - - [% col.0.email FILTER html %] - [% ELSE %] - [% col.0.realname || "No Name" FILTER html %] - [% END %] - - [% col.1 FILTER html %] - - [% INCLUDE bar_graph count = col.1 %] -
-
+
diff --git a/extensions/ProductDashboard/web/js/components.js b/extensions/ProductDashboard/web/js/components.js new file mode 100644 index 000000000..538b15457 --- /dev/null +++ b/extensions/ProductDashboard/web/js/components.js @@ -0,0 +1,75 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is "Incompatible With Secondary Licenses", as + * defined by the Mozilla Public License, v. 2.0. + */ + +YUI({ + base: 'js/yui3/', + combine: false +}).use("datatable", "datatable-sort", function(Y) { + if (typeof PD.updated_recently != 'undefined') { + var columns = [ + { key:"id", label:"ID", sortable:true, allowHTML: true, + formatter: '{value}' }, + { key:"bug_status", label:"Status", sortable:true }, + { key:"version", label:"Version", sortable:true }, + { key:"component", label:"Component", sortable:true }, + { key:"severity", label:"Severity", sortable:true }, + { key:"summary", label:"Summary", sortable:false }, + ]; + + var updatedRecentlyDataTable = new Y.DataTable({ + columns: columns, + data: PD.updated_recently + }); + updatedRecentlyDataTable.render("#updated_recently"); + + if (typeof PD.past_due != 'undefined') { + var pastDueDataTable = new Y.DataTable({ + columns: columns, + data: PD.past_due + }); + pastDueDataTable.render('#past_due'); + } + } + + if (typeof PD.component_counts != 'undefined') { + var summary_url = '{value}' }, + { key:"count", label:"Count", sortable:true }, + { key:"percentage", label:"Percentage", sortable:false, allowHTML: true, + formatter: '
{value}%
' }, + { key:"link", label:"Link", sortable:false, allowHTML: true } + ]; + + var componentsDataTable = new Y.DataTable({ + columns: columns, + data: PD.component_counts + }); + componentsDataTable.render("#component_counts"); + + columns[0].formatter = summary_url + '&version={value}">{value}'; + var versionsDataTable = new Y.DataTable({ + columns: columns, + data: PD.version_counts + }); + versionsDataTable.render('#version_counts'); + + if (typeof PD.milestone_counts != 'undefined') { + columns[0].formatter = summary_url + '&target_milestone={value}">{value}'; + var milestonesDataTable = new Y.DataTable({ + columns: columns, + data: PD.milestone_counts + }); + milestonesDataTable.render('#milestone_counts'); + } + } +}); diff --git a/extensions/ProductDashboard/web/js/duplicates.js b/extensions/ProductDashboard/web/js/duplicates.js new file mode 100644 index 000000000..5e3193a65 --- /dev/null +++ b/extensions/ProductDashboard/web/js/duplicates.js @@ -0,0 +1,28 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is "Incompatible With Secondary Licenses", as + * defined by the Mozilla Public License, v. 2.0. + */ + +YUI({ + base: 'js/yui3/', + combine: false +}).use("datatable", "datatable-sort", function (Y) { + var column_defs = [ + { key:"id", label:"ID", sortable:true, allowHTML: true, + formatter: '{value}' }, + { key:"count", label:"Count", sortable:true }, + { key:"status", label:"Status", sortable:true }, + { key:"version", label:"Version", sortable:true }, + { key:"component", label:"Component", sortable:true }, + { key:"severity", label:"Severity", sortable:true }, + { key:"summary", label:"Summary", sortable:false }, + ]; + + var duplicatesDataTable = new Y.DataTable({ + columns: column_defs, + data: PD.duplicates + }).render('#duplicates'); +}); diff --git a/extensions/ProductDashboard/web/js/popularity.js b/extensions/ProductDashboard/web/js/popularity.js new file mode 100644 index 000000000..b78b67867 --- /dev/null +++ b/extensions/ProductDashboard/web/js/popularity.js @@ -0,0 +1,28 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is "Incompatible With Secondary Licenses", as + * defined by the Mozilla Public License, v. 2.0. + */ + +YUI({ + base: 'js/yui3/', + combine: false +}).use("datatable", "datatable-sort", function (Y) { + var column_defs = [ + { key:"id", label:"ID", sortable:true, allowHTML: true, + formatter: '{value}' }, + { key:"count", label:"Count", sortable:true }, + { key:"status", label:"Status", sortable:true }, + { key:"version", label:"Version", sortable:true }, + { key:"component", label:"Component", sortable:true }, + { key:"severity", label:"Severity", sortable:true }, + { key:"summary", label:"Summary", sortable:false }, + ]; + + var popularityDataTable = new Y.DataTable({ + columns: column_defs, + data: PD.popularity + }).render('#popularity'); +}); diff --git a/extensions/ProductDashboard/web/js/productdashboard.js b/extensions/ProductDashboard/web/js/productdashboard.js deleted file mode 100644 index 56bc451ff..000000000 --- a/extensions/ProductDashboard/web/js/productdashboard.js +++ /dev/null @@ -1,98 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This Source Code Form is "Incompatible With Secondary Licenses", as - * defined by the Mozilla Public License, v. 2.0. - */ - -YAHOO.namespace('ProductDashboard'); - -var PD = YAHOO.ProductDashboard; - -PD.addStatListener = function (div_name, table_name, column_defs, fields, options) { - YAHOO.util.Event.addListener(window, "load", function() { - YAHOO.example.StatsFromMarkup = new function() { - this.myDataSource = new YAHOO.util.DataSource(YAHOO.util.Dom.get(table_name)); - this.myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE; - this.myDataSource.responseSchema = { fields:fields }; - this.myDataTable = new YAHOO.widget.DataTable(div_name, column_defs, this.myDataSource, options); - this.myDataTable.subscribe("rowMouseoverEvent", this.myDataTable.onEventHighlightRow); - this.myDataTable.subscribe("rowMouseoutEvent", this.myDataTable.onEventUnhighlightRow); - }; - }); -} - -// Custom sort handler to sort by bug id inside an anchor tag -PD.sortBugIdLinks = function (a, b, desc) { - // Deal with empty values - if (!YAHOO.lang.isValue(a)) { - return (!YAHOO.lang.isValue(b)) ? 0 : 1; - } - else if(!YAHOO.lang.isValue(b)) { - return -1; - } - // Now we need to pull out the ID text and convert to Numbers - // First we do 'a' - var container = document.createElement("bug_id_link"); - container.innerHTML = a.getData("id"); - var anchors = container.getElementsByTagName("a"); - var text = anchors[0].textContent; - if (text === undefined) text = anchors[0].innerText; - var new_a = new Number(text); - // Then we do 'b' - container.innerHTML = b.getData("id"); - anchors = container.getElementsByTagName("a"); - text = anchors[0].textContent; - if (text == undefined) text = anchors[0].innerText; - var new_b = new Number(text); - - if (!desc) { - return YAHOO.util.Sort.compare(new_a, new_b); - } - else { - return YAHOO.util.Sort.compare(new_b, new_a); - } -} - -// Custom sort handler for bug severities -PD.sortBugSeverity = function (a, b, desc) { - // Deal with empty values - if (!YAHOO.lang.isValue(a)) { - return (!YAHOO.lang.isValue(b)) ? 0 : 1; - } - else if(!YAHOO.lang.isValue(b)) { - return -1; - } - - var new_a = new Number(severities[YAHOO.lang.trim(a.getData('bug_severity'))]); - var new_b = new Number(severities[YAHOO.lang.trim(b.getData('bug_severity'))]); - - if (!desc) { - return YAHOO.util.Sort.compare(new_a, new_b); - } - else { - return YAHOO.util.Sort.compare(new_b, new_a); - } -} - -// Custom sort handler for bug priorities -PD.sortBugPriority = function (a, b, desc) { - // Deal with empty values - if (!YAHOO.lang.isValue(a)) { - return (!YAHOO.lang.isValue(b)) ? 0 : 1; - } - else if(!YAHOO.lang.isValue(b)) { - return -1; - } - - var new_a = new Number(priorities[YAHOO.lang.trim(a.getData('priority'))]); - var new_b = new Number(priorities[YAHOO.lang.trim(b.getData('priority'))]); - - if (!desc) { - return YAHOO.util.Sort.compare(new_a, new_b); - } - else { - return YAHOO.util.Sort.compare(new_b, new_a); - } -} diff --git a/extensions/ProductDashboard/web/js/recents.js b/extensions/ProductDashboard/web/js/recents.js new file mode 100644 index 000000000..84e1758b6 --- /dev/null +++ b/extensions/ProductDashboard/web/js/recents.js @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is "Incompatible With Secondary Licenses", as + * defined by the Mozilla Public License, v. 2.0. + */ + +YUI({ + base: 'js/yui3/', + combine: false +}).use("datatable", "datatable-sort", function (Y) { + var column_defs = [ + { key:"id", label:"ID", sortable:true, allowHTML: true, + formatter: '{value}' }, + { key:"status", label:"Status", sortable:true }, + { key:"version", label:"Version", sortable:true }, + { key:"component", label:"Component", sortable:true }, + { key:"severity", label:"Severity", sortable:true }, + { key:"summary", label:"Summary", sortable:false }, + ]; + + var recentlyOpenedDataTable = new Y.DataTable({ + columns: column_defs, + data: PD.recents.opened + }).render('#recently_opened'); + + var recentlyClosedDataTable = new Y.DataTable({ + columns: column_defs, + data: PD.recents.closed + }).render('#recently_closed'); +}); diff --git a/extensions/ProductDashboard/web/js/roadmap.js b/extensions/ProductDashboard/web/js/roadmap.js new file mode 100644 index 000000000..1bef5b091 --- /dev/null +++ b/extensions/ProductDashboard/web/js/roadmap.js @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is "Incompatible With Secondary Licenses", as + * defined by the Mozilla Public License, v. 2.0. + */ + +YUI({ + base: 'js/yui3/', + combine: false +}).use("datatable", "datatable-sort", function (Y) { + var column_defs = [ + { key: 'name', label: 'Name', sortable: true }, + { key: 'percentage', label: 'Percentage', sortable: false, allowHTML: true, + formatter: '
{value}%
' }, + { key: 'link', label: 'Links', allowHTML: true, sortable: false } + ]; + + var roadmapDataTable = new Y.DataTable({ + columns: column_defs, + data: PD.roadmap, + }).render('#bug_milestones'); +}); diff --git a/extensions/ProductDashboard/web/js/summary.js b/extensions/ProductDashboard/web/js/summary.js new file mode 100644 index 000000000..59d000d7b --- /dev/null +++ b/extensions/ProductDashboard/web/js/summary.js @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is "Incompatible With Secondary Licenses", as + * defined by the Mozilla Public License, v. 2.0. + */ + +YUI({ + base: 'js/yui3/', + combine: false +}).use("datatable", "datatable-sort", function (Y) { + var column_defs = [ + { key: 'name', label: 'Name', sortable: true }, + { key: 'count', label: 'Count', sortable: true }, + { key: 'percentage', label: 'Percentage', sortable: true, allowHTML: true, + formatter: '
{value}%
' }, + { key: 'link', label: 'Link', allowHTML: true } + ]; + + var bugsCountDataTable = new Y.DataTable({ + columns: column_defs, + data: PD.summary.bug_counts + }).render('#bug_counts'); + + var statusCountsDataTable = new Y.DataTable({ + columns: column_defs, + data: PD.summary.status_counts + }).render('#status_counts'); + + var priorityCountsDataTable = new Y.DataTable({ + columns: column_defs, + data: PD.summary.priority_counts + }).render('#priority_counts'); + + var severityCountsDataTable = new Y.DataTable({ + columns: column_defs, + data: PD.summary.severity_counts + }).render('#severity_counts'); + + var assigneeCountsDataTable = new Y.DataTable({ + columns: column_defs, + data: PD.summary.assignee_counts + }).render('#assignee_counts'); +}); diff --git a/extensions/ProductDashboard/web/styles/productdashboard.css b/extensions/ProductDashboard/web/styles/productdashboard.css index 1e821fa11..c0c45cf38 100644 --- a/extensions/ProductDashboard/web/styles/productdashboard.css +++ b/extensions/ProductDashboard/web/styles/productdashboard.css @@ -23,3 +23,23 @@ padding-bottom: 5px; margin-bottom: 10px; } + +.percentage { + position:relative; + width: 200px; + border: 1px solid rgb(203, 203, 203); + position: relative; + padding: 3px; +} + +.bar{ + background-color: #00ff00; + height: 20px; +} + +.percent{ + position: absolute; + display: inline-block; + top: 3px; + left: 48%; +} -- cgit v1.2.3-24-g4f1b