diff options
author | Fabrice Bellingard <bellingard@gmail.com> | 2011-12-19 16:21:22 +0100 |
---|---|---|
committer | Fabrice Bellingard <bellingard@gmail.com> | 2011-12-19 16:22:20 +0100 |
commit | 17a932cde5030121ddec6094b9b89852152cefde (patch) | |
tree | 66cbf2ca1be1410896f5c6743177e56ff25f9520 | |
parent | c5edb54175be630d973a3a994e6cb44c46d3edfb (diff) | |
download | sonarqube-17a932cde5030121ddec6094b9b89852152cefde.tar.gz sonarqube-17a932cde5030121ddec6094b9b89852152cefde.zip |
SONAR-2662 Make it possible to assign a review to an action plan
- From the resource viewer
- From the review detail/permalink page
10 files changed, 180 insertions, 4 deletions
diff --git a/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties index 97bade0325a..ee60aff5462 100644 --- a/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -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'. diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/reviews_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/reviews_controller.rb index c8db5e02216..65ac6dfa25e 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/reviews_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/reviews_controller.rb @@ -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 + # # 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 72046216539..847178da0c7 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 @@ -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 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 e7dcdae8766..9c05675324e 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 @@ -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 # # 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 3e4b74dcf54..61b62974a37 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 @@ -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"> @@ -41,9 +47,15 @@ <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"> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_javascript.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_javascript.html.erb index b68d442baa6..a4e72396f74 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_javascript.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_javascript.html.erb @@ -117,6 +117,22 @@ 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); diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_violation.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_violation.html.erb index 7a150b1fe12..f92df046210 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_violation.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/resource/_violation.html.erb @@ -53,6 +53,12 @@ <%= message('assigned_to') -%> <%= h(violation.review.assignee.name) -%> <% end %> + <% if violation.review && violation.review.planned? %> + <img src="<%= ApplicationController.root_context -%>/images/sep12.png"> + + <%= message('reviews.planned_for_x', :params => h(violation.review.action_plan.name)) -%> + + <% 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 index 00000000000..5e6c95d3934 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_action_plan_form.html.erb @@ -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' -%> + + <%= link_to_remote message('cancel'), :url => {:action => 'show', :id => params[:id]}, :update => 'review' -%> +</form> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_review.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_review.html.erb index 567d6e01a41..6b2ef05584f 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_review.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_review.html.erb @@ -38,6 +38,11 @@ :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 %> @@ -90,6 +95,16 @@ <%= 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 index 00000000000..596ca7b9611 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_violation_action_plan_form.html.erb @@ -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] -%> + + <%= link_to_function message('cancel'), "cancelViolationAction(#{params[:id]})" -%> +</form> |