aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-server/src/main
diff options
context:
space:
mode:
authorFabrice Bellingard <bellingard@gmail.com>2011-12-18 17:47:40 +0100
committerFabrice Bellingard <bellingard@gmail.com>2011-12-19 08:40:38 +0100
commit97a1d845f94d1bed1b5516a7837a47079959b4a8 (patch)
treeae4e74fb801d0ef93a909700921eb62222d4f087 /sonar-server/src/main
parentf8f1e54873eef3c3bcae4e9d54de87f9140cc027 (diff)
downloadsonarqube-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')
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/controllers/project_reviews_controller.rb51
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/action_plan.rb2
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/review.rb13
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/action_plans/_progress.html.erb41
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/action_plans/index.html.erb3
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/project_reviews/index.html.erb6
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_list.html.erb106
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/reviews/index.html.erb152
-rw-r--r--sonar-server/src/main/webapp/stylesheets/style.css20
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"/>
+ &nbsp;<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"/>
- &nbsp;<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%;