diff options
17 files changed, 589 insertions, 773 deletions
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" ] %] <script type="text/javascript"> <!-- + PD = {}; [%# Set up severities list for proper sorting %] PD.severities = new Array(); [% sort_count = 0 %] @@ -96,7 +113,7 @@ [% bug_link = bug_link_closed %] [% END %] -<div class="yui-skin-sam"> +<div class="yui3-skin-sam"> <a name="top"></a> <form action="page.cgi" method="get"> diff --git a/extensions/ProductDashboard/template/en/default/pages/productdashboard/components.html.tmpl b/extensions/ProductDashboard/template/en/default/pages/productdashboard/components.html.tmpl index 0d2ac5e6f..8f3703770 100644 --- a/extensions/ProductDashboard/template/en/default/pages/productdashboard/components.html.tmpl +++ b/extensions/ProductDashboard/template/en/default/pages/productdashboard/components.html.tmpl @@ -8,259 +8,139 @@ [% IF summary.keys %] - <h3>Summary for [% summary.type FILTER html %]: [% summary.value FILTER html %]</h3> +<h3>Summary for [% summary.type FILTER html %]: [% summary.value FILTER html %]</h3> - <style> - .yui-skin-sam .yui-dt table {width:100%;} - </style> - - <script type="text/javascript"> - <!-- - PD.options = { - paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) - }; - PD.column_defs = [ - { key:"id", label:"ID", sortable:true, sortOptions:{ sortFunction: PD.sortBugIdLinks } }, - { key:"bug_status", label:"Status", sortable:true }, - { key:"version", label:"Version", sortable:true }, - { key:"component", label:"Component", sortable:true }, - { key:"bug_severity", label:"Severity", sortable:true, sortOptions:{ sortFunction: PD.sortBugSeverity } }, - { key:"Summary", label:"Summary", sortable:false }, - ]; - PD.fields = [ - { key:"id" }, - { key:"bug_status" }, - { key:"version" }, - { key:"component" }, - { key:"bug_severity" }, - { key:"Summary" } - ]; +<script> +<!-- + // Past due bugs [% IF user.is_timetracker %] - PD.addStatListener("past_due", "past_due_table", PD.column_defs, PD.fields, PD.options); + PD.past_due = [ + [% FOREACH bug = summary.past_due %] + { + 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 %] + ]; [% END %] - PD.addStatListener("updated_recently", "updated_recently_table", PD.column_defs, PD.fields, PD.options); - --> - </script> - [% IF user.is_timetracker %] - <p> - <a href="#past_due">Past Due</a> | - <a href="#updated_recently">Updated Recently</a> - </p> + // 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 %] + ]; +--> +</script> + +[% IF user.is_timetracker %] + <p> + <a href="#past_due">Past Due</a> | + <a href="#updated_recently">Updated Recently</a> + </p> +[% END %] - <div class="yui-skin-sam"> +<div class="yui3-skin-sam"> - [% IF user.is_timetracker %] - <a name="past_due"></a> - <b>[% summary.past_due.size FILTER html %] Past Due [% terms.Bugs %]</b> (deadline is before today's date) - (<a href="[% bug_link FILTER html %]&[% summary.type FILTER uri %]=[% summary.value FILTER uri %]&field0-0-0=deadline&type0-0-0=lessthan&value0-0-0=[% summary.timestamp FILTER uri %]&order=deadline">full list</a>) - <div id="past_due"> - <table id="past_due_table" cellspacing="3" cellpadding="0" border="0" width="100%"> - <thead> - <tr bgcolor="#CCCCCC"> - [% FOREACH column = [ "ID", "Status", "Version", "Component", "Severity" "Summary" ] %] - <th>[% column FILTER html %]</th> - [% END %] - </tr> - </thead> - <tbody> - [% FOREACH bug = summary.past_due %] - [% count = loop.count() %] - <tr class="[%+ count % 2 == 1 ? "bz_row_odd" : "bz_row_even" -%]"> - <td align="center"><a href="[% urlbase FILTER none %]show_bug.cgi?id=[% bug.id FILTER uri %]"> - [% bug.id FILTER html %]</a></td> - <td align="center">[% bug.status FILTER html %]</td> - <td align="center">[% bug.version FILTER html %]</td> - <td align="center">[% bug.component FILTER html %]</td> - <td align="center">[% bug.severity FILTER html %]</td> - <td>[% bug.summary FILTER html %]</td> - </tr> - [% END %] - </tbody> - </table> - </div> - <br> - [% END %] + [% IF user.is_timetracker %] + <a name="past_due"></a> + <b>[% summary.past_due.size FILTER html %] Past Due [% terms.Bugs %]</b> (deadline is before today's date) + (<a href="[% bug_link FILTER html %]&[% summary.type FILTER uri %]=[% summary.value FILTER uri %]&field0-0-0=deadline&type0-0-0=lessthan&value0-0-0=[% summary.timestamp FILTER uri %]&order=deadline">full list</a>) + <div id="past_due"></div> + <br> + [% END %] - <a name="updated_recently"></a> - <b>[% summary.updated_recently.size FILTER html %] Most Recently Updated [% terms.Bugs %]</b> - [% IF user.is_timetracker %](<a href="#top">back to top</a>)[% END %] - (<a href="[% bug_link FILTER html %]&[% summary.type FILTER uri %]=[% summary.value FILTER uri %]&order=changeddate DESC">full list</a>) - <div id="updated_recently"> - <table id="updated_recently_table" cellspacing="3" cellpadding="0" border="0" width="100%"> - <thead> - <tr bgcolor="#CCCCCC"> - [% FOREACH column = [ "ID", "Status", "Version", "Component", "Severity" "Summary" ] %] - <th>[% column FILTER html %]</th> - [% END %] - </tr> - </thead> - <tbody> - [% FOREACH bug = summary.updated_recently %] - [% count = loop.count() %] - <tr class="[%+ count % 2 == 1 ? "bz_row_odd" : "bz_row_even" -%]"> - <td align="center"><a href="[% urlbase FILTER none %]show_bug.cgi?id=[% bug.id FILTER uri %]"> - [% bug.id FILTER html %]</a></td> - <td align="center">[% bug.status FILTER html %]</td> - <td align="center">[% bug.version FILTER html %]</td> - <td align="center">[% bug.component FILTER html %]</td> - <td align="center">[% bug.severity FILTER html %]</td> - <td>[% bug.summary FILTER html %]</td> - </tr> - [% END %] - </tbody> - </table> - </div> - </div> + <a name="updated_recently"></a> + <b>[% summary.updated_recently.size FILTER html %] Most Recently Updated [% terms.Bugs %]</b> + [% IF user.is_timetracker %](<a href="#top">back to top</a>)[% END %] + (<a href="[% bug_link FILTER html %]&[% summary.type FILTER uri %]=[% summary.value FILTER uri %]&order=changeddate DESC">full list</a>) + <div id="updated_recently"></div> +</div> [% ELSE %] - <script type="text/javascript"> - <!-- - PD.column_defs = [ - { key:"name", label:"Name", sortable:true }, - { key:"count", label:"Count", sortable:true }, - { key:"percentage", label:"Percentage", sortable:false }, - { key:"bug_list", label:"[% terms.Bug %] List", sortable:false } - ]; - PD.fields = [ - { key:"name" }, - { key:"count", parser:"number" }, - { key:"percentage" }, - { key:"bug_list" } +<script type="text/javascript"> +<!-- + PD.product_name = '[% product.name FILTER js %]'; + PD.bug_status = '[% bug_status FILTER js %]'; + + // Component counts + PD.component_counts = [ + [% FOREACH col = by_component %] + { + name: "[% col.0 FILTER js %]", + count: [% col.1 || 0 FILTER js %], + percentage: [% col.2 || 0 FILTER js %], + link: '<a href="[% bug_link FILTER html %]&component=[% col.0 FILTER uri %]">Link</a>' + }, + [% END %] ]; - PD.addStatListener("component_counts", "component_counts_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); - PD.addStatListener("version_counts", "version_counts_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); - PD.addStatListener("milestone_counts", "milestone_counts_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); - --> - </script> - - [% summary_url = "page.cgi?id=productdashboard.html&product=$url_filtered_product&bug_status=$url_filtered_status&tab=components" %] - - <h3>[% terms.Bug %] counts per component, version and milestone.</h3> - - <p> - <a href="#component">Component</a> | - <a href="#version">Version</a> | - <a href="#milestone">Milestone</a> - </p> - <p>Click on a value to show a list of most recently updated [% terms.bugs %].</p> + // 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: '<a href="[% bug_link FILTER html %]&version=[% col.0 FILTER uri %]">Link</a>' + }, + [% END %] + ]; - <div class="yui-skin-sam"> - <a name="component"></a> - <b>Component</b> - <div id="component_counts"> - <table id="component_counts_table" border="0" cellspacing="3" cellpadding="0"> - <thead> - <tr> - <th>Name</th> - <th>Count</th> - <th>Percentage</th> - <th>[% terms.Bug %] List</th> - </tr> - </thead> - <tbody> - [% FOREACH col = by_component %] - <tr> - <td> - <a href="[% summary_url FILTER none %]&component=[% col.0 FILTER uri %]"> - [% col.0 FILTER html %]</a> - </td> - <td align="right"> - [% col.1 FILTER html %] - </td> - <td width="70%"> - [% INCLUDE bar_graph count = col.1 %] - </td> - <td> - <a href="[% bug_link FILTER html %]&component=[% col.0 FILTER uri %]">View</a> - </td> - </tr> + [% 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: '<a href="[% bug_link FILTER html %]&target_milestone=[% col.0 FILTER uri %]">Link</a>' + }, [% END %] - </tbody> - </table> - </div> + ]; + [% END %] +--> +</script> + +<h3>[% terms.Bug %] counts per component, version and milestone.</h3> + +<p> + <a href="#component">Component</a> | + <a href="#version">Version</a> | + <a href="#milestone">Milestone</a> +</p> + +<p>Click on a value to show a list of most recently updated [% terms.bugs %].</p> + +<div class="yui3-skin-sam"> + <a name="component"></a> + <b>Component</b> + <div id="component_counts"></div> + <br> + <a name="version"></a> + <b>Version</b> + (<a href="#top">back to top</a>) + <div id="version_counts"></div> + [% IF Param('usetargetmilestone') %] <br> - <a name="version"></a> - <b>Version</b> + <a name="milestone"></a> + <b>Milestone</b> (<a href="#top">back to top</a>) - <div id="version_counts"> - <table id="version_counts_table" border="0" cellspacing="3" cellpadding="0"> - <thead> - <tr> - <th>Name</th> - <th>Count</th> - <th>Percentage</th> - <th>[% terms.Bug %] List</th> - </tr> - </thead> - <tbody> - [% FOREACH col = by_version %] - <tr> - <td> - <a href="[% summary_url FILTER none %]&version=[% col.0 FILTER uri %]"> - [% col.0 FILTER html %]</a> - </td> - <td align="right"> - [% col.1 FILTER html %] - </td> - <td width="70%"> - [% INCLUDE bar_graph count = col.1 %] - </td> - <td> - <a href="[% bug_link FILTER html %]&version=[% col.0 FILTER uri %]">View</a> - </td> - </tr> - [% END %] - </tbody> - </table> - </div> - - [% IF Param('usetargetmilestone') %] - <br> - <a name="milestone"></a> - <b>Milestone</b> - (<a href="#top">back to top</a>) - <div id="milestone_counts"> - <table id="milestone_counts_table" border="0" cellspacing="3" cellpadding="0"> - <thead> - <tr> - <th>Name</th> - <th>Count</th> - <th>Percentage</th> - <th>[% terms.Bug %] List</th> - </tr> - </thead> - <tbody> - [% FOREACH col = by_milestone %] - <tr> - <td> - <a href="[% summary_url FILTER none %]&target_milestone=[% col.0 FILTER uri %]"> - [% col.0 FILTER html %]</a> - </td> - <td align="right"> - [% col.1 FILTER html %] - </td> - <td width="70%"> - [% INCLUDE bar_graph count = col.1 %] - </td> - <td> - <a href="[% bug_link FILTER html %]&target_milestone=[% col.0 FILTER uri %]">View</a> - </td> - </tr> - [% END %] - </tbody> - </table> - </div> - [% END %] - </div> + <div id="milestone_counts"></div> + [% END %] +</div> [% 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. #%] -<style> - .yui-skin-sam .yui-dt table {width:100%;} -</style> - <script type="text/javascript"> -<!-- -PD.column_defs = [ - { key:"id", label:"ID", sortable:true, sortOptions:{ sortFunction: PD.sortBugIdLinks } }, - { key:"count", label:"Count", sortable:true }, - { key:"bug_status", label:"Status", sortable:true }, - { key:"version", label:"Version", sortable:true }, - { key:"component", label:"Component", sortable:true }, - { key:"bug_severity", label:"Severity", sortable:true, sortOptions:{ sortFunction: PD.sortBugSeverity } }, - { key:"Summary", label:"Summary", sortable:false }, -]; -PD.fields = [ - { key:"id" }, - { key:"count", parser:"number" }, - { key:"bug_status" }, - { key:"version" }, - { key:"component" }, - { key:"bug_severity" }, - { key:"Summary" } -]; -PD.addStatListener("duplicate_counts", "duplicate_counts_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); ---> + PD.duplicates = [ + [% FOREACH bug = by_duplicate %] + { + id: '[% bug.id FILTER js %]', + count: '[% bug.dupe_count FILTER js %]', + 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 %] + ]; </script> <h3>Most duplicated [% terms.bugs %]</h3> [% IF by_duplicate.size %] <b>[% by_duplicate.size FILTER html %] [% terms.Bugs %] Found</b> - <div class="yui-skin-sam"> - <div id="duplicate_counts"> - <table id="duplicate_counts_table" cellspacing="3" cellpadding="0" border="0" width="100%"> - <thead> - <tr bgcolor="#CCCCCC"> - [% FOREACH column = [ "ID", "Dupe Count", "Status", "Version" - "Component", "Severity" "Summary" ] %] - - <th>[% column FILTER html %]</th> - [% END %] - </tr> - </thead> - <tbody> - [% FOREACH bug = by_duplicate %] - [% count = loop.count() %] - <tr class="[%+ count % 2 == 1 ? "bz_row_odd" : "bz_row_even" -%]"> - <td align="center"><a href="[% urlbase FILTER none %]show_bug.cgi?id=[% bug.id FILTER uri %]"> - [% bug.id FILTER html %]</a></td> - <td align="center">[% bug.dupe_count FILTER html %]</td> - <td align="center">[% bug.status FILTER html %]</td> - <td align="center">[% bug.version FILTER html %]</td> - <td align="center">[% bug.component FILTER html %]</td> - <td align="center">[% bug.severity FILTER html %]</td> - <td>[% bug.summary FILTER html %]</td> - </tr> - [% END %] - </tbody> - </table> - </div> + <div class="yui3-skin-sam"> + <div id="duplicates"></div> </div> [% ELSE %] <b>No duplicate [% terms.bugs %] found.</b> 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 @@ </style> <script type="text/javascript"> -<!-- -PD.column_defs = [ - { key:"id", label:"ID", sortable:true, sortOptions:{ sortFunction: PD.sortBugIdLinks } }, - { key:"count", label:"Count", sortable:true }, - { key:"bug_status", label:"Status", sortable:true }, - { key:"version", label:"Version", sortable:true }, - { key:"component", label:"Component", sortable:true }, - { key:"bug_severity", label:"Severity", sortable:true, sortOptions:{ sortFunction: PD.sortBugSeverity } }, - { key:"Summary", label:"Summary", sortable:false }, -]; -PD.fields = [ - { key:"id" }, - { key:"count", parser:"number" }, - { key:"bug_status" }, - { key:"version" }, - { key:"component" }, - { key:"bug_severity" }, - { key:"Summary" } -]; -PD.addStatListener("popularity_counts", "popularity_counts_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); ---> + PD.popularity = [ + [% FOREACH bug = by_popularity %] + { + id: '[% bug.id FILTER js %]', + count: '[% bug.votes FILTER js %]', + 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 %] + ]; </script> <h3>Most voted on [% terms.bugs %]</h3> [% IF by_popularity.size %] <b>[% by_popularity.size FILTER html %] [% terms.Bugs %] Found</b> - <div class="yui-skin-sam"> - <div id="popularity_counts"> - <table id="popularity_counts_table" cellspacing="3" cellpadding="0" border="0" width="100%"> - <thead> - <tr bgcolor="#CCCCCC"> - [% FOREACH column = [ "ID", "Count", "Status", "Version" - "Component", "Severity" "Summary" ] %] - - <th>[% column FILTER html %]</th> - [% END %] - </tr> - </thead> - <tbody> - [% FOREACH bug = by_popularity %] - [% count = loop.count() %] - <tr class="[%+ count % 2 == 1 ? "bz_row_odd" : "bz_row_even" -%]"> - <td align="center"><a href="[% urlbase FILTER none %]show_bug.cgi?id=[% bug.id FILTER uri %]"> - [% bug.id FILTER html %]</a></td> - <td align="center">[% bug.votes FILTER html %]</td> - <td align="center">[% bug.status FILTER html %]</td> - <td align="center">[% bug.version FILTER html %]</td> - <td align="center">[% bug.component FILTER html %]</td> - <td align="center">[% bug.severity FILTER html %]</td> - <td>[% bug.summary FILTER html %]</td> - </tr> - [% END %] - </tbody> - </table> - </div> + <div class="yui3-skin-sam"> + <div id="popularity"></div> </div> [% ELSE %] <b>No [% terms.bugs %] found.</b> 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. #%] -<style> - .yui-skin-sam .yui-dt table {width:100%;} -</style> - <script type="text/javascript"> -<!-- -PD.column_defs = [ - { key:"id", label:"ID", sortable:true, sortOptions:{ sortFunction: PD.sortBugIdLinks } }, - { key:"bug_status", label:"Status", sortable:true }, - { key:"version", label:"Version", sortable:true }, - { key:"component", label:"Component", sortable:true }, - { key:"bug_severity", label:"Severity", sortable:true, sortOptions:{ sortFunction: PD.sortBugSeverity } }, - { key:"Summary", label:"Summary", sortable:false }, -]; -PD.fields = [ - { key:"id" }, - { key:"bug_status" }, - { key:"version" }, - { key:"component" }, - { key:"bug_severity" }, - { key:"Summary" } -]; -PD.addStatListener("recently_opened", "recently_opened_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); + PD.recents = {}; + + // Recently opened bugs + PD.recents.opened = [ + [% FOREACH bug = recently_opened %] + { + id: '[% bug.id FILTER js %]', + 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 %] + ]; -PD.addStatListener("recently_closed", "recently_closed_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); ---> + // Recently closed bugs + PD.recents.closed = [ + [% FOREACH bug = recently_closed %] + { + id: '[% bug.id FILTER js %]', + 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 %] + ]; </script> <h3>Most recently opened and closed [% terms.bugs %]</h3> @@ -50,7 +50,7 @@ PD.addStatListener("recently_closed", "recently_closed_table", <button type="button" class="calendar_button" id="button_calendar_date_from" onclick="showCalendar('date_from')"> - <span>Calendar</span> + <span>Calendar</span> </button> <span id="con_calendar_date_from"></span> to @@ -60,7 +60,7 @@ PD.addStatListener("recently_closed", "recently_closed_table", <button type="button" class="calendar_button" id="button_calendar_date_to" onclick="showCalendar('date_to')"> - <span>Calendar</span> + <span>Calendar</span> </button> <span id="con_calendar_date_to"></span> <script type="text/javascript"> @@ -78,58 +78,10 @@ PD.addStatListener("recently_closed", "recently_closed_table", <div class="yui-skin-sam"> <a name="recently_opened"></a> <b>[% recently_opened.size FILTER html %] Recently Opened [% terms.Bugs %]</b> - <div id="recently_opened"> - <table id="recently_opened_table" cellspacing="3" cellpadding="0" border="0" width="100%"> - <thead> - <tr bgcolor="#CCCCCC"> - [% FOREACH column = [ "ID", "Status", "Version", "Component", "Severity" "Summary" ] %] - <th>[% column FILTER html %]</th> - [% END %] - </tr> - </thead> - <tbody> - [% FOREACH bug = recently_opened %] - [% count = loop.count() %] - <tr class="[%+ count % 2 == 1 ? "bz_row_odd" : "bz_row_even" -%]"> - <td align="center"><a href="[% urlbase FILTER none %]show_bug.cgi?id=[% bug.id FILTER uri %]"> - [% bug.id FILTER html %]</a></td> - <td align="center">[% bug.status FILTER html %]</td> - <td align="center">[% bug.version FILTER html %]</td> - <td align="center">[% bug.component FILTER html %]</td> - <td align="center">[% bug.severity FILTER html %]</td> - <td>[% bug.summary FILTER html %]</td> - </tr> - [% END %] - </tbody> - </table> - </div> + <div id="recently_opened"></div> <br> <a name="recently_closed"></a> <b>[% recently_closed.size FILTER html %] Recently Closed [% terms.Bugs %]</b> (<a href="#top">back to top</a>) - <div id="recently_closed"> - <table id="recently_closed_table" cellspacing="3" cellpadding="0" border="0" width="100%"> - <thead> - <tr bgcolor="#CCCCCC"> - [% FOREACH column = [ "ID", "Status", "Version", "Component", "Severity" "Summary" ] %] - <th>[% column FILTER html %]</th> - [% END %] - </tr> - </thead> - <tbody> - [% FOREACH bug = recently_closed %] - [% count = loop.count() %] - <tr class="[%+ count % 2 == 1 ? "bz_row_odd" : "bz_row_even" -%]"> - <td align="center"><a href="[% urlbase FILTER none %]show_bug.cgi?id=[% bug.id FILTER uri %]"> - [% bug.id FILTER html %]</a></td> - <td align="center">[% bug.status FILTER html %]</td> - <td align="center">[% bug.version FILTER html %]</td> - <td align="center">[% bug.component FILTER html %]</td> - <td align="center">[% bug.severity FILTER html %]</td> - <td>[% bug.summary FILTER html %]</td> - </tr> - [% END %] - </tbody> - </table> - </div> + <div id="recently_closed"></div> </div> diff --git a/extensions/ProductDashboard/template/en/default/pages/productdashboard/roadmap.html.tmpl b/extensions/ProductDashboard/template/en/default/pages/productdashboard/roadmap.html.tmpl index 1597b7a36..48f96499d 100644 --- a/extensions/ProductDashboard/template/en/default/pages/productdashboard/roadmap.html.tmpl +++ b/extensions/ProductDashboard/template/en/default/pages/productdashboard/roadmap.html.tmpl @@ -8,50 +8,20 @@ <script type="text/javascript"> <!-- -PD.column_defs = [ - { key:"milestone", label:"Milestone", sortable:true }, - { key:"percentage complete", label:"Percentage Complete", sortable:false }, - { key:"links", label:"Links", sortable:false }, -]; -PD.fields = [ - { key:"milestone" }, - { key:"percentage complete" }, - { key:"links" } -]; -PD.addStatListener("bug_milestones", "bug_milestones_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); + PD.roadmap = [ + [% FOREACH milestone = by_roadmap %] + { + name: '[% milestone.name FILTER js %]', + percentage: '[% milestone.percentage FILTER js %]', + link: '<a href="[% milestone.link_closed FILTER html %]">[% milestone.closed_bugs FILTER html %]</a> of <a href="[% milestone.link_total FILTER html %]"> [% milestone.total_bugs FILTER html %]</a> bugs have been closed', + }, + [% END %] + ]; --> </script> <h3>Percentage of [% terms.bug %] closure per milestone</h3> -<div class="yui-skin-sam"> -<div id="bug_milestones"> - <table id="bug_milestones_table" border="0" cellspacing="3" cellpadding="0"> - <thead> - <tr> - <th>Milestone</th> - <th>Percentage Complete</th> - <th>Links</th> - </tr> - </thead> - <tbody> - [% FOREACH milestone = by_roadmap %] - <tr> - <td>[% milestone.name FILTER html %]</td> - <td width="70%"> - [% INCLUDE bar_graph count = milestone.closed_bugs full_bug_count = milestone.total_bugs %] - </td> - <td> - <a href="[% milestone.link_closed FILTER html %]"> - [% milestone.closed_bugs FILTER html %]</a> of - <a href="[% milestone.link_total FILTER html %]"> - [% milestone.total_bugs FILTER html %]</a> bugs have been closed - </td> - </tr> - [% END %] - </tbody> - </table> - </div> +<div class="yui3-skin-sam"> + <div id="bug_milestones"></div> </div> 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. #%] -<script type="text/javascript"> -<!-- -PD.column_defs = [ - { key:"name", label:"Name", sortable:true }, - { key:"count", label:"Count", sortable:true }, - { key:"percentage", label:"Percentage", sortable:false } -]; -PD.fields = [ - { key:"name" }, - { key:"count", parser:"number" }, - { key:"percentage" } -]; -PD.addStatListener("bug_counts", "bug_counts_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); -PD.addStatListener("status_counts", "status_counts_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); -PD.addStatListener("priority_counts", "priority_counts_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); -PD.addStatListener("severity_counts", "severity_counts_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); -PD.addStatListener("assignee_counts", "assignee_counts_table", - PD.column_defs, PD.fields, - { paginator: new YAHOO.widget.Paginator({ rowsPerPage: 25, alwaysVisible: false }) }); ---> +<script> + PD.summary = {}; + + // Bug counts + PD.summary.bug_counts = [ + { + name: "Total [% terms.Bugs %]", + count: [% total_bugs || 0 FILTER js %], + percentage: 100, + link: '<a href="[% bug_link_all FILTER js %]">Link</a>', + }, + { + name: "Open [% terms.Bugs %]", + count: [% total_open_bugs || 0 FILTER js %], + percentage: [% open_bugs_percentage FILTER js %], + link: '<a href="[% bug_link_open FILTER js %]">Link</a>', + }, + { + name: "Closed [% terms.Bugs %]", + count: [% total_closed_bugs || 0 FILTER js %], + percentage: [% closed_bugs_percentage FILTER js %], + link: '<a href="[% bug_link_closed FILTER js %]">Link</a>', + } + ]; + + // Status counts + PD.summary.status_counts = [ + [% FOREACH col = by_status %] + [% NEXT IF col.0 == 'CLOSED' %] + { + name: "[% col.0 FILTER js %]", + count: [% col.1 || 0 FILTER js %], + percentage: [% col.2 || 0 FILTER js %], + link: '<a href="[% bug_link_all FILTER js %]&bug_status=[% col.0 FILTER uri FILTER js %]">Link</a>' + }, + [% END %] + ]; + + // Priority counts + PD.summary.priority_counts = [ + [% FOREACH col = by_priority %] + { + name: "[% col.0 FILTER js %]", + count: [% col.1 || 0 FILTER js %], + percentage: [% col.2 || 0 FILTER js %], + link: '<a href="[% bug_link_all FILTER js %]&priority=[% col.0 FILTER uri FILTER js %]">Link</a>' + }, + [% END %] + ]; + + // Severity counts + PD.summary.severity_counts = [ + [% FOREACH col = by_severity %] + { + name: "[% col.0 FILTER js %]", + count: [% col.1 || 0 FILTER js %], + percentage: [% col.2 || 0 FILTER js %], + link: '<a href="[% bug_link_all FILTER js %]&bug_severity=[% col.0 FILTER uri FILTER js %]">Link</a>' + }, + [% END %] + ]; + + // Assignee counts + PD.summary.assignee_counts = [ + [% FOREACH col = by_assignee %] + { + name: "[% IF user.id %][% col.0.email FILTER js %][% ELSE %][% col.0.realname || 'No Name' FILTER js %][% END %]", + count: [% col.1 || 0 FILTER js %], + percentage: [% col.2 || 0 FILTER js %], + link: '[% IF user.id %]<a href="[% bug_link FILTER js %]&emailassigned_to1=1&emailtype1=exact&email1=[% col.0.email FILTER uri FILTER js %]">Link</a>[% END %]' + }, + [% END %] + ]; </script> <h3>Summary of [% terms.bug %] counts</h3> @@ -50,168 +95,28 @@ PD.addStatListener("assignee_counts", "assignee_counts_table", <a href="#assignee">Assignee</a> </p> -<div class="yui-skin-sam"> +<div class="yui3-skin-sam"> <a name="counts"></a> <b>[% terms.Bug %] Counts</b> - <div id="bug_counts"> - <table id="bug_counts_table" border="0" cellspacing="3" cellpadding="0"> - <thead> - <tr> - <th>Name</th> - <th>Count</th> - <th>Percentage</th> - </tr> - </thead> - <tbody> - <tr> - <td><a href="[% bug_link_all FILTER html %]">Total [% terms.Bugs %]</a></td> - <td>[% total_bugs FILTER html %]</td> - <td> </td> - </tr> - <tr> - <td><a href="[% bug_link_open FILTER html %]">Open [% terms.Bugs %]</a></td> - <td>[% total_open_bugs FILTER html %]</td> - <td width="70%"> - [% INCLUDE bar_graph count = total_open_bugs full_bug_count = total_bugs %] - </td> - </tr> - <tr> - <td><a href="[% bug_link_closed FILTER html %]">Closed [% terms.Bugs %]</a></td> - <td>[% total_closed_bugs FILTER html %]</td> - <td width="70%"> - [% INCLUDE bar_graph count = total_closed_bugs full_bug_count = total_bugs %] - </td> - </tr> - </tbody> - </table> - </div> + <div id="bug_counts"></div> <br> <a name="status"></a> <b>Status</b> (<a href="#top">back to top</a>) - <div id="status_counts"> - <table id="status_counts_table" border="0" cellspacing="3" cellpadding="0"> - <thead> - <tr> - <th>Name</th> - <th>Count</th> - <th>Percentage</th> - </tr> - </thead> - <tbody> - [% FOREACH col = by_status %] - [% NEXT IF col.0 == 'CLOSED' %] - <tr> - <td> - <a href="[% bug_link_all FILTER html %]&bug_status=[% col.0 FILTER uri %]"> - [% col.0 FILTER html %]</a> - </td> - <td> - [% col.1 FILTER html %] - </td> - <td width="70%"> - [% INCLUDE bar_graph count = col.1 %] - </td> - </tr> - [% END %] - </tbody> - </table> - </div> + <div id="status_counts"></div> <br> <a name="priority"></a> <b>Priority</b> (<a href="#top">back to top</a>) - <div id="priority_counts"> - <table id="priority_counts_table" border="0" cellspacing="3" cellpadding="0"> - <thead> - <tr> - <th>Name</th> - <th>Count</th> - <th>Percentage</th> - </tr> - </thead> - </tbody> - [% FOREACH col = by_priority %] - <tr> - <td> - <a href="[% bug_link FILTER html %]&priority=[% col.0 FILTER uri %]"> - [% col.0 FILTER html %]</a> - </td> - <td> - [% col.1 FILTER html %] - </td> - <td width="70%"> - [% INCLUDE bar_graph count = col.1 %] - </td> - </tr> - [% END %] - </tbody> - </table> - </div> + <div id="priority_counts"></div> <br> <a name="severity"></a> <b>Severity</b> (<a href="#top">back to top</a>) - <div id="severity_counts"> - <table id="severity_counts_table" border="0" cellspacing="3" cellpadding="0"> - <thead> - <tr> - <th>Name</th> - <th>Count</th> - <th>Percentage</th> - </tr> - </thead> - <tbody> - [% FOREACH col = by_severity %] - <tr> - <td> - <a href="[% bug_link FILTER html %]&bug_severity=[% col.0 FILTER uri %]"> - [% col.0 FILTER html %]</a> - </td> - <td align="right"> - [% col.1 FILTER html %] - </td> - <td width="70%"> - [% INCLUDE bar_graph count = col.1 %] - </td> - </tr> - [% END %] - </tbody> - </table> - </div> + <div id="severity_counts"></div> <br> <a name="assignee"></a> <b>Assignee</b> (<a href="#top">back to top</a>) - <div id="assignee_counts"> - <table id="assignee_counts_table" border="0" cellspacing="3" cellpadding="0"> - <thead> - <tr> - <th>Name</th> - <th>Count</th> - <th>Percentage</th> - </tr> - </thead> - <tbody> - [% FOREACH col = by_assignee %] - <tr> - <td> - [% IF user.id %] - <a href="[% bug_link FILTER html %]&emailassigned_to1=1&emailtype1=exact&email1=[% col.0.email FILTER uri %]"> - [% col.0.email FILTER html %]</a> - [% ELSE %] - [% col.0.realname || "No Name" FILTER html %] - [% END %] - </td> - <td> - [% col.1 FILTER html %] - </td> - <td width="70%"> - [% INCLUDE bar_graph count = col.1 %] - </td> - </tr> - [% END %] - </tbody> - </table> - </div> + <div id="assignee_counts"></div> </div> 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: '<a href="show_bug.cgi?id={value}" target="_blank">{value}</a>' }, + { 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 = '<a href="page.cgi?id=productdashboard.html&product=' + + encodeURIComponent(PD.product_name) + '&bug_status=' + + encodeURIComponent(PD.bug_status) + '&tab=components'; + + var columns = [ + { key:"name", label:"Name", sortable:true, allowHTML: true, + formatter: summary_url + '&component={value}">{value}</a>' }, + { key:"count", label:"Count", sortable:true }, + { key:"percentage", label:"Percentage", sortable:false, allowHTML: true, + formatter: '<div class="percentage"><div class="bar" style="width:{value}%"></div><div class="percent">{value}%</div></div>' }, + { 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}</a>'; + 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}</a>'; + 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: '<a href="show_bug.cgi?id={value}" target="_blank">{value}</a>' }, + { 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: '<a href="show_bug.cgi?id={value}" target="_blank">{value}</a>' }, + { 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: '<a href="show_bug.cgi?id={value}" target="_blank">{value}</a>' }, + { 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: '<div class="percentage"><div class="bar" style="width:{value}%"></div><div class="percent">{value}%</div></div>' }, + { 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: '<div class="percentage"><div class="bar" style="width:{value}%"></div><div class="percent">{value}%</div></div>' }, + { 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%; +} |