diff options
author | Fabrice Bellingard <bellingard@gmail.com> | 2011-12-18 17:47:40 +0100 |
---|---|---|
committer | Fabrice Bellingard <bellingard@gmail.com> | 2011-12-19 08:40:38 +0100 |
commit | 97a1d845f94d1bed1b5516a7837a47079959b4a8 (patch) | |
tree | ae4e74fb801d0ef93a909700921eb62222d4f087 /sonar-server/src/main | |
parent | f8f1e54873eef3c3bcae4e9d54de87f9140cc027 (diff) | |
download | sonarqube-97a1d845f94d1bed1b5516a7837a47079959b4a8.tar.gz sonarqube-97a1d845f94d1bed1b5516a7837a47079959b4a8.zip |
SONAR-2662 Create action plans which are a set of manual reviews
- Improve progress bar
- Display the list of reviews in a separate page which is still in
the context of the project
Diffstat (limited to 'sonar-server/src/main')
9 files changed, 243 insertions, 151 deletions
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/project_reviews_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/project_reviews_controller.rb new file mode 100644 index 00000000000..e20078c8392 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/project_reviews_controller.rb @@ -0,0 +1,51 @@ +# +# Sonar, entreprise quality control tool. +# Copyright (C) 2008-2011 SonarSource +# mailto:contact AT sonarsource DOT com +# +# Sonar is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# Sonar is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with Sonar; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 +# + +class ProjectReviewsController < ApplicationController + + SECTION=Navigation::SECTION_RESOURCE + + def index + @project=Project.by_key(params[:projects]) + not_found("Project not found") unless @project + access_denied unless is_admin?(@project) + + found_reviews = Review.search(params) + @reviews = select_authorized(:user, found_reviews, :project) + if found_reviews.size != @reviews.size + @security_exclusions = true + end + + # table pagination + @page_size = 20 + @page_size = params[:page_size].to_i if Api::Utils.is_number?(params[:page_size]) && params[:page_size].to_i > 5 + @total_number = @reviews.size + if @reviews.size > @page_size + @page_id = (params[:page_id] ? params[:page_id].to_i : 1) + @page_count = @reviews.size / @page_size + @page_count += 1 if (@reviews.size % @page_size > 0) + from = (@page_id-1) * @page_size + to = (@page_id*@page_size)-1 + to = @reviews.size-1 if to >= @reviews.size + @reviews = @reviews[from..to] + end + end + +end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/action_plan.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/action_plan.rb index 34e20850ec7..72046216539 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/action_plan.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/action_plan.rb @@ -51,7 +51,7 @@ class ActionPlan < ActiveRecord::Base def progress total_reviews = reviews.size open_reviews = reviews.select{|r| r.open? || r.reopened?}.size - {:total => total_reviews, :open => open_reviews} + {:total => total_reviews, :open => open_reviews, :resolved => total_reviews-open_reviews} end private diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/review.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/review.rb index 1d3740b9405..e7dcdae8766 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/review.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/review.rb @@ -227,7 +227,6 @@ class Review < ActiveRecord::Base conditions=[] values={} - if options['id'].present? conditions << 'id=:id' values[:id]=options['id'].to_i @@ -236,8 +235,7 @@ class Review < ActiveRecord::Base conditions << 'id in (:ids)' values[:ids]=ids.map { |id| id.to_i } else - - + # --- 'review_type' is deprecated since 2.9 --- # Following code just for backward compatibility review_type = options['review_type'] @@ -321,6 +319,15 @@ class Review < ActiveRecord::Base values[:assignees]=assignees.map { |user_id| user_id.to_i } end end + + action_plan_id = options['action_plan_id'] + if action_plan_id + action_plan = ActionPlan.find action_plan_id.to_i, :include => 'reviews' + if action_plan + conditions << 'id in (:ids)' + values[:ids]=action_plan.reviews.map { |r| r.id } + end + end from=options['from'] if from diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/action_plans/_progress.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/action_plans/_progress.html.erb index 9ba9f66dc4a..23bdfa2e52b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/action_plans/_progress.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/action_plans/_progress.html.erb @@ -1,15 +1,34 @@ <% - open_reviews_url = link_to action_plan.progress[:open].to_s, - :controller => 'reviews', :action => 'index', - :action_plans => [action_plan.id], :statuses => [Review::STATUS_OPEN, Review::STATUS_REOPENED], :assignee_login => '' + unless action_plan.progress[:total]==0 + options = {:controller => 'project_reviews', :action => 'index', :action_plan_id => action_plan.id, :projects => action_plan.project_id} - total_reviews_url = link_to action_plan.progress[:total].to_s, - :controller => 'reviews', :action => 'index', - :action_plans => [action_plan.id], :statuses => [''], :assignee_login => '' + resolved_reviews_link = link_to action_plan.progress[:resolved].to_s, options.merge({:statuses => "#{Review::STATUS_RESOLVED},#{Review::STATUS_CLOSED}"}) + total_reviews_link = link_to action_plan.progress[:total].to_s, options + + resolved_reviews_url = url_for options.merge({:statuses => "#{Review::STATUS_RESOLVED},#{Review::STATUS_CLOSED}"}) + open_reviews_url = url_for options.merge({:statuses => "#{Review::STATUS_OPEN},#{Review::STATUS_REOPENED}"}) + + percent_resolved = (action_plan.progress[:resolved]*100/action_plan.progress[:total]).to_i + percent_open = (action_plan.progress[:open]*100/action_plan.progress[:total]).to_i + + tooltip_resolved = message('action_plans.resolved_reviews_x_percent', :params => [percent_resolved.to_s, action_plan.progress[:resolved].to_s]) + tooltip_open = message('action_plans.open_reviews_x_percent', :params => [percent_open.to_s, action_plan.progress[:open].to_s]) %> + <div class="progress"> - <div class="bar"> - <div style="width:<%= action_plan.progress[:total]==0 ? '0' : action_plan.progress[:open]*100/action_plan.progress[:total] -%>%;"> </div> - </div> - <div class="note"><%= message('action_plans.x_out_of_x_reviews_solved', :params => [open_reviews_url, total_reviews_url]) -%></div> -</div>
\ No newline at end of file + <table> + <tbody> + <tr> + <td class="resolved" style="width:<%= percent_resolved -%>%;"> + <a href="<%= resolved_reviews_url -%>" title="<%= tooltip_resolved -%>" alt="<%= tooltip_resolved -%>"></a> + </td> + <td class="open" style="width:<%= percent_open -%>%;"> + <a href="<%= open_reviews_url -%>" title="<%= tooltip_open -%>" alt="<%= tooltip_open -%>"></a> + </td> + </tr> + </tbody> + </table> + <div class="note"><%= message('action_plans.x_out_of_x_reviews_solved', :params => [resolved_reviews_link, total_reviews_link]) -%></div> +</div> + +<% end %>
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/action_plans/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/action_plans/index.html.erb index d5d21cafc1f..16425cfdf1b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/action_plans/index.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/action_plans/index.html.erb @@ -3,6 +3,7 @@ vertical-align: top; } #actionPlans td.progress { + width: 300px; padding: 0px 40px; } </style> @@ -39,7 +40,7 @@ <tr> <td class="thin nowrap center"><img src="<%= ApplicationController.root_context -%>/images/status/<%= plan.status -%>.png" title="<%= message(plan.status.downcase).capitalize -%>"/></td> <td class="thin nowrap"><%= h(plan.name) -%></td> - <td class="thin nowrap" align="right"><%= plan.dead_line ? plan.dead_line.strftime('%Y/%m/%d') : ' ' -%></td> + <td class="thin nowrap" align="right" x="<%= plan.dead_line ? plan.dead_line.tv_sec : '' -%>"><%= plan.dead_line ? l(plan.dead_line) : ' ' -%></td> <td class="progress thin"> <%= render :partial => 'progress', :locals => {:action_plan => plan} -%> </td> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/project_reviews/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/project_reviews/index.html.erb new file mode 100644 index 00000000000..de1a58170c3 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/project_reviews/index.html.erb @@ -0,0 +1,6 @@ +<div id="reviews-search"> + <h1><%= message('reviews') -%></h1> + + <%= render :partial => "reviews/list" -%> + +</div>
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_list.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_list.html.erb new file mode 100644 index 00000000000..945b68097a3 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_list.html.erb @@ -0,0 +1,106 @@ + <% + if @reviews && !@reviews.empty? + %> + <% if @false_positives=='only' %> + <span class="falsePositive"><%= message('reviews.showing_false_positives_only') -%></span> + <% end %> + <% + if params[:from] && params[:to] + from = Time.parse(params[:from]) + to = Time.parse(params[:to]) + %> + <div style="color:#777777; font-size:93%; padding: 4px 0px 4px 10px;"> + <span style="background-color: #FFF6BF; padding-left: 5px; padding-right: 5px;"> + <%= message('reviews.reviews_filtered_by_date_x_to_y', :params => [l(from, :format => '%d %B %Y'), l(to, :format => '%d %B %Y')]) -%> + </span> + </div> + <% end %> + + <table id="reviews-list" class="data width100"> + <thead> + <tr> + <th width="1%" nowrap> + <a href="#" onClick="launchSearch('status', this)"><%= message('status_abbreviated') -%></a> + <%= image_tag(@asc ? "asc12.png" : "desc12.png") if @sort == 'status' -%> + </th> + <th width="1%" nowrap> + <a href="#" onClick="launchSearch('id', this)"><%= message('identifier_abbreviated') -%></a> + <%= image_tag(@asc ? "asc12.png" : "desc12.png") if @sort == 'id' -%> + </th> + <th width="1%" nowrap> + <a href="#" onClick="launchSearch('severity', this)"><%= message('severity_abbreviated') -%></a> + <%= image_tag(@asc ? "asc12.png" : "desc12.png") if @sort == 'severity' -%> + </th> + <th> + <a href="#" onClick="launchSearch('title', this)"><%= message('title') -%></a> + <%= image_tag(@asc ? "asc12.png" : "desc12.png") if @sort == 'title' -%> + </th> + <th width="1%"><%= message('project') -%></th> + <th><%= message('assignee') -%></th> + <th> + <a href="#" onClick="launchSearch('updated_at', this)"><%= message('age') -%></a> + <%= image_tag(@asc ? "asc12.png" : "desc12.png") if @sort == 'updated_at' -%> + </th> + </tr> + </thead> + <tfoot> + <tr> + <td colspan="6"> + <%= @total_number -%> <%= message('results').downcase -%> + <% if @page_count %> + | + <%= link_to_if @page_id>1, message('paging_previous'), {:overwrite_params => {:page_id => @page_id-1}} %> + <% for index in 1..@page_count %> + <%= link_to_unless index==@page_id, index.to_s, {:overwrite_params => {:page_id => index}} %> + <% end %> + <%= link_to_if @page_id<@page_count, message('paging_next'), {:overwrite_params => {:page_id => 1+@page_id}} %> + <% end %> + </td> + </tr> + </tfoot> + <tbody> + <% + @reviews.each do |review| + comment = review.comments.last + %> + <tr class="<%= cycle('even', 'odd') -%>"> + <td><img src="<%= ApplicationController.root_context -%>/images/status/<%= review.status -%>.png" title="<%= message(review.status.downcase).capitalize -%>"/></td> + <td> + <%= link_to h(review.id), :controller => "reviews", :action => "view", :id => review.id -%> + </td> + <td><img src="<%= ApplicationController.root_context -%>/images/priority/<%= review.severity -%>.png" title="<%= message(review.severity.downcase).capitalize -%>"/></td> + <td> + <%= link_to h(review.title), :controller => "reviews", :action => "view", :id => review.id -%> + <% if comment %> + <div class="comment-excerpt"> + <img src="<%= ApplicationController.root_context -%>/images/reviews/comment.png"/> + <b><%= comment.user.name -%> :</b> + <%= comment.excerpt -%> + <% end %> + </div> + </td> + <td> + <span class="nowrap"><%= review.project.name -%></span> + <br/> + <span class="note"><%= review.resource.name -%></span></td> + <td><%= review.assignee ? h(review.assignee.name) : '-' -%></td> + <td><%= distance_of_time_in_words_to_now(review.updated_at) -%></td> + </tr> + <% + end + %> + </tbody> + </table> + <% + elsif @reviews + %> + <p><%= message('no_results') -%></p> + <% + end + %> + + <% if @security_exclusions %> + <br/> + + <p class="notes"><%= message('results_not_display_due_to_security') -%></p> + <% end %>
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/index.html.erb index 31648dc70e2..9c7783e4e0a 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/index.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/index.html.erb @@ -1,26 +1,3 @@ -<script> - function reviewIdFieldModified(field) { - if (field.value != '') { - $('statuses').value = '' - $('severities').value = '' - $('projects').value = '' - $('author_login').value = '' - $('autocompleteText-author_login').value = '' - $('assignee_login').value = '' - $('autocompleteText-assignee_login').value = '' - $('false_positives').value = 'with' - } - } - function launchSearch(columnName, link) { - $('sort').value = columnName - if ($('asc').value == "true") { - $('asc').value = "false"; - } else { - $('asc').value = "true"; - } - document.forms[0].submit() - } -</script> <div id="reviews-search"> <h1><%= message('reviews') -%></h1> <% form_tag({:action => 'index'}, {:method => 'get'}) do %> @@ -100,115 +77,32 @@ <% end %> - <% - if @reviews && !@reviews.empty? - %> - <% if @false_positives=='only' %> - <span class="falsePositive"><%= message('reviews.showing_false_positives_only') -%></span> - <% end %> - <% - if params[:from] && params[:to] - from = Time.parse(params[:from]) - to = Time.parse(params[:to]) - %> - <div style="color:#777777; font-size:93%; padding: 4px 0px 4px 10px;"> - <span style="background-color: #FFF6BF; padding-left: 5px; padding-right: 5px;"> - <%= message('reviews.reviews_filtered_by_date_x_to_y', :params => [l(from, :format => '%d %B %Y'), l(to, :format => '%d %B %Y')]) -%> - </span> - </div> - <% end %> - - <table id="reviews-list" class="data width100"> - <thead> - <tr> - <th width="1%" nowrap> - <a href="#" onClick="launchSearch('status', this)"><%= message('status_abbreviated') -%></a> - <%= image_tag(@asc ? "asc12.png" : "desc12.png") if @sort == 'status' -%> - </th> - <th width="1%" nowrap> - <a href="#" onClick="launchSearch('id', this)"><%= message('identifier_abbreviated') -%></a> - <%= image_tag(@asc ? "asc12.png" : "desc12.png") if @sort == 'id' -%> - </th> - <th width="1%" nowrap> - <a href="#" onClick="launchSearch('severity', this)"><%= message('severity_abbreviated') -%></a> - <%= image_tag(@asc ? "asc12.png" : "desc12.png") if @sort == 'severity' -%> - </th> - <th> - <a href="#" onClick="launchSearch('title', this)"><%= message('title') -%></a> - <%= image_tag(@asc ? "asc12.png" : "desc12.png") if @sort == 'title' -%> - </th> - <th width="1%"><%= message('project') -%></th> - <th><%= message('assignee') -%></th> - <th> - <a href="#" onClick="launchSearch('updated_at', this)"><%= message('age') -%></a> - <%= image_tag(@asc ? "asc12.png" : "desc12.png") if @sort == 'updated_at' -%> - </th> - </tr> - </thead> - <tfoot> - <tr> - <td colspan="6"> - <%= @total_number -%> <%= message('results').downcase -%> - <% if @page_count %> - | - <%= link_to_if @page_id>1, message('paging_previous'), {:overwrite_params => {:page_id => @page_id-1}} %> - <% for index in 1..@page_count %> - <%= link_to_unless index==@page_id, index.to_s, {:overwrite_params => {:page_id => index}} %> - <% end %> - <%= link_to_if @page_id<@page_count, message('paging_next'), {:overwrite_params => {:page_id => 1+@page_id}} %> - <% end %> - </td> - </tr> - </tfoot> - <tbody> - <% - @reviews.each do |review| - comment = review.comments.last - %> - <tr class="<%= cycle('even', 'odd') -%>"> - <td><img src="<%= ApplicationController.root_context -%>/images/status/<%= review.status -%>.png" title="<%= message(review.status.downcase).capitalize -%>"/></td> - <td> - <%= link_to h(review.id), :controller => "reviews", :action => "view", :id => review.id -%> - </td> - <td><img src="<%= ApplicationController.root_context -%>/images/priority/<%= review.severity -%>.png" title="<%= message(review.severity.downcase).capitalize -%>"/></td> - <td> - <%= link_to h(review.title), :controller => "reviews", :action => "view", :id => review.id -%> - <% if comment %> - <div class="comment-excerpt"> - <img src="<%= ApplicationController.root_context -%>/images/reviews/comment.png"/> - <b><%= comment.user.name -%> :</b> - <%= comment.excerpt -%> - <% end %> - </div> - </td> - <td> - <span class="nowrap"><%= review.project.name -%></span> - <br/> - <span class="note"><%= review.resource.name -%></span></td> - <td><%= review.assignee ? h(review.assignee.name) : '-' -%></td> - <td><%= distance_of_time_in_words_to_now(review.updated_at) -%></td> - </tr> - <% - end - %> - </tbody> - </table> - <% - elsif @reviews - %> - <p><%= message('no_results') -%></p> - <% - end - %> - - <% if @security_exclusions %> - <br/> - - <p class="notes"><%= message('results_not_display_due_to_security') -%></p> - <% end %> + <%= render :partial => "list" -%> </div> <script> + function reviewIdFieldModified(field) { + if (field.value != '') { + $('statuses').value = '' + $('severities').value = '' + $('projects').value = '' + $('author_login').value = '' + $('autocompleteText-author_login').value = '' + $('assignee_login').value = '' + $('autocompleteText-assignee_login').value = '' + $('false_positives').value = 'with' + } + } + function launchSearch(columnName, link) { + $('sort').value = columnName + if ($('asc').value == "true") { + $('asc').value = "false"; + } else { + $('asc').value = "true"; + } + document.forms[0].submit() + } + $('review_id').focus(); </script>
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/stylesheets/style.css b/sonar-server/src/main/webapp/stylesheets/style.css index 7b44c075b92..9fb6b224d75 100644 --- a/sonar-server/src/main/webapp/stylesheets/style.css +++ b/sonar-server/src/main/webapp/stylesheets/style.css @@ -1226,22 +1226,30 @@ div.comment-excerpt { /* ACTION PLANS */ div.progress { - width: 400px; + width: 100%; margin: 4px; } -div.progress div.bar { +div.progress table { width: 100%; - background-color: #CC0000; - border: none; - margin-bottom: 4px; } -div.progress > div > div { +div.progress td { height: 10px; +} + +div.progress td a { + display: block; width: 100%; height: 100%; +} + +div.progress td.resolved { background-color: #078C00; } +div.progress td.open { + background-color: #CC0000; +} + div.progress div.note { color: #777777; font-size: 93%; |