]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2662 Make it possible to assign a review to an action plan
authorFabrice Bellingard <bellingard@gmail.com>
Mon, 19 Dec 2011 15:21:22 +0000 (16:21 +0100)
committerFabrice Bellingard <bellingard@gmail.com>
Mon, 19 Dec 2011 15:22:20 +0000 (16:22 +0100)
- From the resource viewer
- From the review detail/permalink page

plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties
sonar-server/src/main/webapp/WEB-INF/app/controllers/reviews_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/models/action_plan.rb
sonar-server/src/main/webapp/WEB-INF/app/models/review.rb
sonar-server/src/main/webapp/WEB-INF/app/views/action_plans/index.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/resource/_javascript.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/resource/_violation.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_action_plan_form.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_review.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_violation_action_plan_form.html.erb [new file with mode: 0644]

index 97bade0325a874b9df2741070499b60350018c22..ee60aff5462fec928d5a4432817492e0607b2ef9 100644 (file)
@@ -400,6 +400,12 @@ reviews.status.OPEN=Open
 reviews.status.CLOSED=Closed
 reviews.resolution.FALSE-POSITIVE=False-positive
 reviews.resolution.FIXED=Fixed
+reviews.link_to_action_plan=Action plan
+reviews.action_plan_label=Action plan
+reviews.action_plan_submit=Link to action plan
+reviews.no_action_plan=None
+reviews.planned_for_x=Planned for {0}
+reviews.planned_for_label=Planned for
 
 
 #------------------------------------------------------------------------------
@@ -418,6 +424,7 @@ action_plans.col.description=Description
 action_plans.col.author=Author
 action_plans.col.operations=Operations
 action_plans.no_action_plan=No action plan
+action_plans.no_reviews_linked_to_action_plan=No reviews linked to this action plan yet.
 action_plans.confirm_delete=Delete this action plan? Associated reviews will not be deleted.
 action_plans.create_new_action_plan=Create a new action plan
 action_plans.date_format_help=The date should be entered using the following pattern: 'day/month/year'. For instance, '31/12/2011'.
index c8db5e02216a559793dd13d480267053dfece25d..65ac6dfa25e587c2a9a2c8c4c2e1d0fe2d641812 100644 (file)
@@ -25,7 +25,8 @@ class ReviewsController < ApplicationController
   verify :method => :post,
          :only => [:assign, :flag_as_false_positive, :save_comment, :delete_comment, :change_status,
                    :violation_assign, :violation_flag_as_false_positive, :violation_change_severity,
-                   :violation_save_comment, :violation_delete_comment, :violation_change_status],
+                   :violation_save_comment, :violation_delete_comment, :violation_change_status,
+                   :violation_link_to_action_plan],
          :redirect_to => {:action => :error_not_post}
   helper SourceHelper, UsersHelper
 
@@ -186,6 +187,27 @@ class ReviewsController < ApplicationController
     render :partial => "reviews/review"
   end
 
+  # GET
+  def action_plan_form
+    @review = Review.find(params[:id])
+    @action_plans = ActionPlan.by_project_id(@review.project_id)
+    render :partial => 'reviews/action_plan_form'
+  end
+  
+  # POST
+  def link_to_action_plan
+    @review = Review.find(params[:id])
+    unless has_rights_to_modify?(@review.project)
+      render :text => "<b>Cannot link to action plan</b> : access denied."
+      return
+    end
+    
+    action_plan = params[:action_plan_id].to_i==-1 ? nil : ActionPlan.find(params[:action_plan_id])
+    @review.link_to_action_plan(action_plan, current_user, params)
+
+    render :partial => "reviews/review"
+  end
+
 
   #
   #
@@ -252,14 +274,12 @@ class ReviewsController < ApplicationController
     render :partial => "resource/violation", :locals => {:violation => violation}
   end
 
-
   # GET
   def violation_false_positive_form
     @violation = RuleFailure.find(params[:id])
     render :partial => 'reviews/violation_false_positive_form'
   end
 
-
   # POST
   def violation_flag_as_false_positive
     violation=RuleFailure.find(params[:id], :include => 'snapshot')
@@ -359,6 +379,31 @@ class ReviewsController < ApplicationController
     render :partial => "resource/violation", :locals => {:violation => violation}
   end
 
+  # GET
+  def violation_action_plan_form
+    @violation = RuleFailure.find(params[:id], :include => ['review', 'snapshot'])
+    @action_plans = ActionPlan.by_project_id(@violation.snapshot.root_project_id)
+    render :partial => 'reviews/violation_action_plan_form'
+  end
+  
+  # POST
+  def violation_link_to_action_plan
+    violation = RuleFailure.find(params[:id], :include => 'snapshot')
+    unless has_rights_to_modify?(violation.snapshot)
+      render :text => "<b>Cannot link to action plan</b> : access denied."
+      return
+    end
+    sanitize_violation(violation)
+    
+    if violation.review.nil?
+      violation.build_review(:user_id => current_user.id)
+    end
+    action_plan = params[:action_plan_id].to_i==-1 ? nil : ActionPlan.find(params[:action_plan_id])
+    violation.review.link_to_action_plan(action_plan, current_user, params)
+
+    render :partial => "resource/violation", :locals => {:violation => violation}
+  end
+
 
   #
   #
index 720462165397dd8d4bda564b1d8c30aa3e6a6e4a..847178da0c7163e1fa55bca50085a0a90df8f858 100644 (file)
@@ -33,6 +33,10 @@ class ActionPlan < ActiveRecord::Base
   STATUS_OPEN = 'OPEN'
   STATUS_CLOSED = 'CLOSED'
   
+  def self.by_project_id(project_id)
+    ActionPlan.find :all, :conditions => ['project_id=?', project_id], :order => :name
+  end
+  
   def user
     @user ||=
         begin
index e7dcdae8766fe4f3088930c013467a06ffa8e08d..9c05675324e8c3df75b1add1a5bc44b3efcb96b3 100644 (file)
@@ -201,6 +201,19 @@ class Review < ActiveRecord::Base
     notification_manager.notifyChanged(id.to_i, user.login.to_java, old, to_java_map("comment" => options[:text]))
   end
 
+  def link_to_action_plan(action_plan, user, options={})
+    if options[:text].present?
+      comments.create!(:user => user, :text => options[:text])
+    end
+    old = self.to_java_map
+    self.action_plans.clear
+    if action_plan
+      self.action_plans << action_plan
+    end
+    self.save!
+    notification_manager.notifyChanged(id.to_i, user.login.to_java, old, to_java_map("action_plans" => action_plan ? action_plan.name : ''))
+  end
+
   def resolved?
     status == STATUS_RESOLVED
   end
@@ -216,6 +229,19 @@ class Review < ActiveRecord::Base
   def open?
     status == STATUS_OPEN
   end
+  
+  def linked_to? (action_plan)
+    action_plans.include? action_plan
+  end
+  
+  def planned?
+    action_plans.size!=0
+  end
+  
+  # used as long as we currently allow to link a review to only 1 action plan.
+  def action_plan
+    action_plans[0]
+  end
 
   #
   #
index 3e4b74dcf54461d96e2b3e5917da09f948ea28cc..61b62974a37111b788a9dab1b80f0b072718994c 100644 (file)
@@ -5,7 +5,13 @@
   #actionPlans td.progress {
     width: 300px;
     padding: 0px 40px;
-  }    
+  }
+  #actionPlans td.noprogress {
+    color: #777777; 
+    font-size: 93%;
+    padding-left: 40px;
+    padding-right: 40px;
+  } 
 </style>
 
 <div class="line-block marginbottom10">
       <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" x="<%= plan.dead_line ? plan.dead_line.tv_sec : '' -%>"><%= plan.dead_line ? l(plan.dead_line) : ' '  -%></td>
+      <% if plan.progress[:total]==0 %>
+      <td class="noprogress thin nowrap">
+        <%= message('action_plans.no_reviews_linked_to_action_plan') -%>
+      </td>
+      <% else %>
       <td class="progress thin">
         <%= render :partial => 'progress', :locals => {:action_plan => plan} -%>
       </td>
+      <% end %>
       <td id="desc"><%= h(plan.description) -%></td>
       <td id="desc"><%= h(plan.user.name) -%></td>
       <td class="thin nowrap">
index b68d442baa6c659d04162757caa5dd35ccd32ade..a4e72396f7454053e3220760d4447b83a3ac0af5 100644 (file)
     return false;
   }
 
+  // show the form to link a review to an action plan
+  function sAPF(violation_id) {
+    new Ajax.Updater('reviewForm' + violation_id,
+      '<%= ApplicationController.root_context -%>/reviews/violation_action_plan_form/' + violation_id,
+      {
+        asynchronous:true,
+        evalScripts:true,
+        onComplete:function (request) {
+          $('vBody' + violation_id).remove();
+          $('reviewForm' + violation_id).show();
+          $('action_plan').focus();
+        }
+      });
+    return false;
+  }
+
   // show the form to create violation
   function sVF(resource, line, gray_colspan, white_colspan) {
     row = $('createViolationForm' + line);
index 7a150b1fe12f2cdf08cac89719aee609e874cead..f92df0462102f38039817e7958e996a455793e5a 100644 (file)
         <%= message('assigned_to') -%> <%= h(violation.review.assignee.name) -%>
         &nbsp;
       <% end %>
+      <% if violation.review && violation.review.planned? %>
+        <img src="<%= ApplicationController.root_context -%>/images/sep12.png">
+        &nbsp;
+        <%= message('reviews.planned_for_x', :params => h(violation.review.action_plan.name)) -%>
+        &nbsp;
+      <% end %>
 
     </div>
 
@@ -78,6 +84,8 @@
 
           <% unless violation.review && violation.review.resolved? %>
             <%= button_to_function message('reviews.change_severity'), "sCSF(#{violation.id})", :name => 'bChangeSeverity' -%>
+            
+            <%= button_to_function message('reviews.link_to_action_plan'), "sAPF(#{violation.id})", :name => 'bLinkActionPlan' -%>
           <% end %>
         </div>
       <% end %>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_action_plan_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_action_plan_form.html.erb
new file mode 100644 (file)
index 0000000..5e6c95d
--- /dev/null
@@ -0,0 +1,16 @@
+<form method="POST">
+  <input type="hidden" name="id" value="<%= params[:id] -%>"/>
+
+  <%= message('reviews.action_plan_label') -%>:
+  <select name="action_plan_id" id="selectActionPlan">
+    <option value="-1" <%= 'selected' if !@review.planned? -%>><%= message('reviews.no_action_plan') -%></option>
+    <% @action_plans.each do |plan| %>
+      <option value="<%= plan.id -%>" <%= 'selected' if @review.linked_to?(plan) -%>><%= h(plan.name) -%></option>
+    <% end %>
+  </select>
+
+  <textarea id="actionText" rows="4" name="text" style="width: 100%"></textarea>
+  <%= submit_to_remote "submit_btn", message('reviews.action_plan_submit'), :url => {:action => 'link_to_action_plan'}, :html => {:id => "submit_btn"}, :update => 'review' -%>
+  &nbsp;
+  <%= link_to_remote message('cancel'), :url => {:action => 'show', :id => params[:id]}, :update => 'review' -%>
+</form>
index 567d6e01a419be92ccd293f4c89625be05946821..6b2ef05584fcff2aafe43caf20251beedff0f217 100644 (file)
                              :url => {:controller => "reviews", :action => "change_severity_form", :id => review.id},
                              :update => "actionForm",
                              :complete => "$('actionButtons').remove();$('actionForm').show();$('selectSeverity').focus();" -%>
+
+        <%= button_to_remote message('reviews.link_to_action_plan'),
+                             :url => {:controller => "reviews", :action => "action_plan_form", :id => review.id},
+                             :update => "actionForm",
+                             :complete => "$('actionButtons').remove();$('actionForm').show();$('selectSeverity').focus();" -%>
       <% end %>
     </div>
   <% end %>
         <%= l(review.updated_at) -%>
       </td>
     </tr>
+    <% if review.planned? %>
+      <tr>
+        <td class="key">
+          <%= message('reviews.planned_for_label') -%>:
+        </td>
+        <td class="val" colspan="3">
+          <%= h(review.action_plan.name) -%>
+        </td>
+      </tr>
+    <% end %>
     <% if review.rule %>
       <tr>
         <td class="key">
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_violation_action_plan_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_violation_action_plan_form.html.erb
new file mode 100644 (file)
index 0000000..596ca7b
--- /dev/null
@@ -0,0 +1,27 @@
+<form method="POST" action="violation_link_to_action_plan">
+  <input type="hidden" name="id" value="<%= params[:id] -%>"/>
+
+  <%= message('reviews.action_plan_label') -%>:
+  <select name="action_plan_id" id="selectActionPlan<%= params[:id] -%>">
+    <option value="-1" <%= 'selected' if !@violation.review || (@violation.review && !@violation.review.planned?) -%>><%= message('reviews.no_action_plan') -%></option>
+    <% @action_plans.each do |plan| %>
+      <option value="<%= plan.id -%>" <%= 'selected' if @violation.review && @violation.review.linked_to?(plan) -%>><%= h(plan.name) -%></option>
+    <% end %>
+  </select>
+
+  <table class="width100">
+    <tr>
+      <td style="vertical-align:top">
+        <textarea id="commentText<%= params[:id] -%>" rows="4" name="text" style="width: 100%"></textarea>
+      </td>
+      <td class="sep"></td>
+      <td style="vertical-align:top;width: 90px">
+        <%= render :partial => 'markdown/help' -%>
+      </td>
+    </tr>
+  </table>
+
+  <%= submit_to_remote "submit_btn"+params[:id], message('reviews.action_plan_submit'), :url => {:action => 'violation_link_to_action_plan'}, :html => {:id => "submit_btn"+params[:id]}, :update => 'vId'+params[:id] -%>
+  &nbsp;
+  <%= link_to_function message('cancel'), "cancelViolationAction(#{params[:id]})" -%>
+</form>