]> source.dussan.org Git - sonarqube.git/commitdiff
Duplicate rules configuration to prepare for pure ES implementation
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Wed, 11 Dec 2013 17:31:45 +0000 (18:31 +0100)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Thu, 12 Dec 2013 11:36:00 +0000 (12:36 +0100)
sonar-server/src/main/webapp/WEB-INF/app/controllers/new_rules_configuration_controller.rb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/helpers/new_rules_configuration_helper.rb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_active_rule_note.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule_note.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule_param.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/edit.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/index.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/new.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_tabs.html.erb

diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/new_rules_configuration_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/new_rules_configuration_controller.rb
new file mode 100644 (file)
index 0000000..66caee1
--- /dev/null
@@ -0,0 +1,444 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2013 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube 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.
+#
+# SonarQube 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 this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+require 'cgi'
+
+class NewRulesConfigurationController < ApplicationController
+
+  SECTION=Navigation::SECTION_QUALITY_PROFILES
+
+  STATUS_ACTIVE = "ACTIVE"
+  STATUS_INACTIVE = "INACTIVE"
+
+  ANY_SELECTION = []
+  RULE_PRIORITIES = Sonar::RulePriority.as_options.reverse
+
+  def index
+    require_parameters :id
+
+    @profile = Profile.find(params[:id])
+    add_breadcrumbs ProfilesController::root_breadcrumb, Api::Utils.language_name(@profile.language),
+                    {:name => @profile.name, :url => {:controller => 'new_rules_configuration', :action => 'index', :id => @profile.id}}
+
+    init_params()
+
+    @select_repositories = ANY_SELECTION + java_facade.getRuleRepositoriesByLanguage(@profile.language).collect { |repo| [repo.getName(true), repo.getKey()] }.sort
+    @select_priority = ANY_SELECTION + RULE_PRIORITIES
+    @select_activation = [[message('any'), 'any'], [message('active'), STATUS_ACTIVE], [message('inactive'), STATUS_INACTIVE]]
+    @select_inheritance = [[message('any'), 'any'], [message('rules_configuration.not_inherited'), 'NOT'], [message('rules_configuration.inherited'), 'INHERITED'],
+                           [message('rules_configuration.overrides'), 'OVERRIDES']]
+    @select_status = ANY_SELECTION + [[message('rules.status.beta'), Rule::STATUS_BETA],
+                      [message('rules.status.deprecated'), Rule::STATUS_DEPRECATED],
+                      [message('rules.status.ready'), Rule::STATUS_READY]]
+    @select_sort_by = [[message('rules_configuration.rule_name'), Rule::SORT_BY_RULE_NAME], [message('rules_configuration.creation_date'), Rule::SORT_BY_CREATION_DATE]]
+
+    begin
+      stop_watch = Internal.profiling.start("rules", "BASIC")
+
+      criteria = {
+      :profile => @profile, :activation => @activation, :priorities => @priorities, :inheritance => @inheritance, :status => @status,
+      :repositories => @repositories, :searchtext => @searchtext, :include_parameters_and_notes => true, :language => @profile.language, :sort_by => @sort_by}
+      @rules = Rule.search(java_facade, criteria)
+
+      unless @searchtext.blank?
+        if @activation==STATUS_ACTIVE
+          @hidden_inactives = Rule.search(java_facade, {
+              :profile => @profile, :activation => STATUS_INACTIVE, :priorities => @priorities, :status => @status,
+              :repositories => @repositories, :language => @profile.language, :searchtext => @searchtext, :include_parameters_and_notes => false}).size
+
+        elsif @activation==STATUS_INACTIVE
+          @hidden_actives = Rule.search(java_facade, {
+              :profile => @profile, :activation => STATUS_ACTIVE, :priorities => @priorities, :status => @status,
+              :repositories => @repositories, :language => @profile.language, :searchtext => @searchtext, :include_parameters_and_notes => false}).size
+        end
+      end
+
+      stop_watch.stop("found #{@rules.size} rules with criteria #{criteria.to_json}")
+    rescue
+      @rules = []
+    end
+      @pagination = Api::Pagination.new(params)
+      @pagination.count = @rules.size
+      @current_rules = @rules[@pagination.offset, @pagination.limit]
+  end
+
+
+  #
+  #
+  # POST /rules_configuration/revert_rule?id=<profile id>&active_rule_id=<active rule id>
+  #
+  #
+  def revert_rule
+    verify_post_request
+    access_denied unless has_role?(:profileadmin)
+    require_parameters :id, :active_rule_id
+    id = params[:id].to_i
+    rule_id = params[:active_rule_id].to_i
+    java_facade.revertRule(id, rule_id, current_user.name)
+    redirect_to request.query_parameters.merge({:action => 'index', :id => params[:id], :commit => nil})
+  end
+
+
+  #
+  #
+  # POST /rules_configuration/activate_rule?id=<profile id>&rule_id=<rule id>&level=<priority>
+  #
+  # If the parameter "level" is blank or null, then the rule is removed from the profile.
+  #
+  #
+  def activate_rule
+    verify_post_request
+    access_denied unless has_role?(:profileadmin)
+    require_parameters :id, :rule_id
+    profile = Profile.find(params[:id].to_i)
+    if profile
+      rule=Rule.first(:conditions => ["id = ? and status <> ?", params[:rule_id].to_i, Rule::STATUS_REMOVED])
+      priority=params[:level]
+
+      active_rule=profile.active_by_rule_id(rule.id)
+      if priority.blank?
+        # deactivate the rule
+        if active_rule
+          java_facade.ruleDeactivated(profile.id, active_rule.id, current_user.name)
+          active_rule.destroy
+          active_rule=nil
+        end
+      else
+        # activate the rule
+        activated = false
+        if active_rule.nil?
+          active_rule = ActiveRule.new(:profile_id => profile.id, :rule => rule)
+          rule.parameters.select { |p| p.default_value.present? }.each do |p|
+            active_rule.active_rule_parameters.build(:rules_parameter => p, :value => p.default_value)
+          end
+          activated = true
+        end
+        old_severity = active_rule.failure_level
+        active_rule.failure_level=Sonar::RulePriority.id(priority)
+        active_rule.save!
+        if activated
+          java_facade.ruleActivated(profile.id, active_rule.id, current_user.name)
+        else
+          java_facade.ruleSeverityChanged(profile.id, active_rule.id, old_severity, active_rule.failure_level, current_user.name)
+        end
+      end
+      if active_rule
+        active_rule.reload
+      end
+
+      render :update do |page|
+        page.replace_html("rule_#{rule.id}", :partial => 'rule', :object => rule, :locals => {:profile => profile, :rule => rule, :active_rule => active_rule})
+        page.assign('localModifications', true)
+      end
+    end
+  end
+
+
+  #
+  #
+  # GET /rules_configuration/new/<profile id>?rule_id=<rule id>
+  #
+  #
+  def new
+    # form to duplicate a rule
+    access_denied unless has_role?(:profileadmin)
+    require_parameters :id, :rule_id
+    @profile = Profile.find(params[:id].to_i)
+    add_breadcrumbs ProfilesController::root_breadcrumb, Api::Utils.language_name(@profile.language), {:name => @profile.name, :url => {:controller => 'new_rules_configuration', :action => 'index', :id => @profile.id}}
+
+    @rule = Rule.find(params[:rule_id])
+  end
+
+  #
+  #
+  # POST /rules_configuration/create/<profile id>?rule_id=<rule id>&rule[name]=<new name>&...
+  #
+  #
+  def create
+    verify_post_request
+    access_denied unless has_role?(:profileadmin)
+    require_parameters :id, :rule_id
+    profile = Profile.find(params[:id].to_i)
+    template=Rule.find(params[:rule_id])
+    # TODO Call Internal.rule.create(...) ?
+    rule=Rule.create(params[:rule].merge(
+                         {
+                             :priority => Sonar::RulePriority.id(params[:rule][:priority]),
+                             :parent_id => template.id,
+                             :plugin_name => template.plugin_name,
+                             :cardinality => 'SINGLE',
+                             :plugin_rule_key => "#{template.plugin_rule_key}_#{Time.now.to_i}",
+                             :plugin_config_key => template.plugin_config_key,
+                             :status => Rule::STATUS_READY,
+                             :language => profile.language
+                         }
+                     ))
+
+    template.parameters.each do |template_parameter|
+      rule.rules_parameters.build(:name => template_parameter.name, :param_type => template_parameter.param_type, :description => template_parameter.description,
+                                  :default_value => params[:rule_param][template_parameter.name])
+    end
+
+    if rule.save
+      Internal.rules.saveOrUpdate(rule.id)
+      redirect_to :action => 'index', :id => profile.id, :searchtext => "\"#{rule.name}\"", :rule_activation => 'INACTIVE', "plugins[]" => rule.plugin_name
+
+    else
+      flash[:error]=message('rules_configuration.rule_not_valid_message_x', :params => rule.errors.full_messages.join('<br/>'))
+      redirect_to :action => 'new', :id => profile.id, :rule_id => params[:rule_id]
+    end
+  end
+
+
+  # deprecated since 2.3
+  def export
+    redirect_to request.query_parameters.merge({:controller => 'profiles', :action => 'export'})
+  end
+
+  #
+  #
+  # GET /rules_configuration/new/<profile id>?rule_id=<rule id>
+  #
+  #
+  def edit
+    # form to edit a rule
+    access_denied unless has_role?(:profileadmin)
+    require_parameters :id, :rule_id
+    @profile = Profile.find(params[:id])
+    @rule = Rule.find(params[:rule_id])
+    if !@rule.editable?
+      redirect_to :action => 'index', :id => params[:id]
+    end
+  end
+
+  #
+  #
+  # POST /rules_configuration/update/<profile id>?rule_id=<rule id>&rule[name]=<new name>&...
+  #
+  #
+  def update
+    verify_post_request
+    access_denied unless has_role?(:profileadmin)
+    require_parameters :id, :rule_id
+    rule=Rule.find(params[:rule_id])
+    if rule.editable?
+      rule.name=params[:rule][:name]
+      rule.description=params[:rule][:description]
+      rule.priority=Sonar::RulePriority.id(params[:rule][:priority])
+      rule.parameters.each do |parameter|
+        parameter.default_value=params[:rule_param][parameter.name]
+        parameter.save
+      end
+      if rule.save
+        Internal.rules.saveOrUpdate(rule.id)
+        redirect_to :action => 'index', :id => params[:id], :searchtext => "\"#{rule.name}\"", :rule_activation => '', "plugins[]" => rule.plugin_name
+      else
+        flash[:error]=message('rules_configuration.rule_not_valid_message_x', :params => rule.errors.full_messages.join('<br/>'))
+        redirect_to :action => 'new', :id => params[:id], :rule_id => params[:rule_id]
+      end
+    else
+      flash[:error]='Unknown rule'
+      redirect_to :action => 'index', :id => params[:id]
+    end
+  end
+
+
+  #
+  #
+  # POST /rules_configuration/delete/<profile id>?rule_id=<rule id>
+  #
+  #
+  def delete
+    verify_post_request
+    access_denied unless has_role?(:profileadmin)
+    require_parameters :id, :rule_id
+    rule=Rule.find(params[:rule_id])
+    if rule.editable?
+      rule.status=Rule::STATUS_REMOVED
+      rule.save
+      Internal.rules.saveOrUpdate(rule.id)
+
+      # it's mandatory to execute 'destroy_all' but not 'delete_all' because active_rule_parameters must
+      # also be destroyed in cascade.
+      ActiveRule.destroy_all("rule_id=#{rule.id}")
+      flash[:notice]=message('rules_configuration.rule_deleted')
+    else
+      flash[:error]=message('rules_configuration.unknown_rule')
+    end
+    redirect_to :action => 'index', :id => params[:id]
+  end
+
+  #
+  #
+  # POST /rules_configuration/bulk_edit?id=<profile id>&bulk_rule_ids=<list of rule ids>&bulk_action=<action>
+  #
+  # Values of the parameter 'bulk_action' :
+  #   - 'activate' : activate all the selected rules with their default priority
+  #   - 'deactivate' : deactivate all the selected rules
+  #
+  #
+  def bulk_edit
+    verify_post_request
+    access_denied unless has_role?(:profileadmin)
+    require_parameters :id, :bulk_rule_ids, :bulk_action
+    profile = Profile.find(params[:id].to_i)
+    rule_ids = params[:bulk_rule_ids].split(',').map { |id| id.to_i }
+    activation=params[:rule_activation] || STATUS_ACTIVE
+
+    case params[:bulk_action]
+      when 'activate'
+        count=activate_rules(profile, rule_ids)
+        flash[:notice]=message('rules_configuration.x_rules_have_been_activated', :params => count)
+        activation=STATUS_ACTIVE if activation==STATUS_INACTIVE
+
+      when 'deactivate'
+        count=deactivate_rules(profile, rule_ids)
+        flash[:notice]=message('rules_configuration.x_rules_have_been_deactivated', :params => count)
+        activation=STATUS_INACTIVE if activation==STATUS_ACTIVE
+    end
+
+    url_parameters=request.query_parameters.merge({:action => 'index', :bulk_action => nil, :bulk_rule_ids => nil, :id => profile.id, :rule_activation => activation})
+    redirect_to url_parameters
+  end
+
+
+  def update_param
+    verify_post_request
+    access_denied unless has_role?(:profileadmin)
+    require_parameters :profile_id, :param_id, :active_rule_id
+    profile = Profile.find(params[:profile_id].to_i)
+    rule_param = RulesParameter.find(params[:param_id].to_i)
+    active_rule = ActiveRule.find(params[:active_rule_id].to_i)
+    # As the active param can be null, we should not raise a RecordNotFound exception when it's not found (as it would be done when using find(:id) function)
+    active_param = ActiveRuleParameter.find_by_id(params[:id].to_i) if params[:id].to_i > 0
+    value = params[:value]
+    if value != ""
+      active_param = ActiveRuleParameter.new(:rules_parameter => rule_param, :active_rule => active_rule) if active_param.nil?
+      old_value = active_param.value
+      active_param.value = value
+      if active_param.save! && active_param.valid?
+        active_param.reload
+        java_facade.ruleParamChanged(profile.id, active_rule.id, rule_param.name, old_value, value, current_user.name)
+      end
+    elsif !active_param.nil?
+      old_value = active_param.value
+      active_param.destroy
+      java_facade.ruleParamChanged(profile.id, active_rule.id, rule_param.name, old_value, nil, current_user.name)
+    end
+    # let's reload the active rule
+    active_rule = ActiveRule.find(active_rule.id)
+    render :partial => 'rule', :locals => {:profile => profile, :rule => active_rule.rule, :active_rule => active_rule}
+  end
+
+
+  def update_rule_note
+    verify_post_request
+    access_denied unless has_role?(:profileadmin)
+    require_parameters :rule_id
+    rule = Rule.find(params[:rule_id])
+    note = rule.note
+    unless note
+      note = RuleNote.new({:rule => rule})
+      # set the note on the rule to avoid reloading the rule
+      rule.note = note
+    end
+    note.text = params[:text]
+    note.user_login = current_user.login
+    note.save!
+    render :partial => 'rule_note', :locals => {:rule => rule}
+  end
+
+
+  def update_active_rule_note
+    verify_post_request
+    access_denied unless has_role?(:profileadmin)
+    require_parameters :active_rule_id, :note
+    active_rule = ActiveRule.find(params[:active_rule_id])
+    note = active_rule.note
+    unless note
+      note = ActiveRuleNote.new({:active_rule => active_rule})
+      # set the note on the rule to avoid reloading the rule
+      active_rule.note = note
+    end
+    note.text = params[:note]
+    note.user_login = current_user.login
+    note.save!
+    render :partial => 'active_rule_note', :locals => {:active_rule => active_rule, :profile => active_rule.rules_profile}
+  end
+
+
+  def delete_active_rule_note
+    verify_post_request
+    access_denied unless has_role?(:profileadmin)
+    require_parameters :active_rule_id
+    active_rule = ActiveRule.find(params[:active_rule_id])
+    active_rule.note.destroy if active_rule.note
+    active_rule.note = nil
+    render :partial => 'active_rule_note', :locals => {:active_rule => active_rule, :profile => active_rule.rules_profile}
+  end
+
+
+  private
+
+  # return the number of newly activated rules
+  def activate_rules(profile, rule_ids)
+    count=0
+    rule_ids_to_activate=(rule_ids - profile.active_rules.map { |ar| ar.rule_id })
+    unless rule_ids_to_activate.empty?
+      rules_to_activate=Rule.all(:conditions => ["status <> ? AND id IN (?)", Rule::STATUS_REMOVED, rule_ids_to_activate])
+      count = rules_to_activate.size
+      rules_to_activate.each do |rule|
+        active_rule = profile.active_rules.create(:rule => rule, :failure_level => rule.priority)
+        java_facade.ruleActivated(profile.id, active_rule.id, current_user.name)
+      end
+    end
+    count
+  end
+
+  def deactivate_rules(profile, rule_ids)
+    count=0
+    profile.active_rules.each do |ar|
+      if rule_ids.include?(ar.rule_id) && !ar.inheritance.present?
+        java_facade.ruleDeactivated(profile.id, ar.id, current_user.name)
+        ar.destroy
+        count+=1
+      end
+    end
+    count
+  end
+
+  def init_params
+    @id = params[:id]
+    @priorities = filter_any(params[:priorities]) || ['']
+    @repositories = filter_any(params[:repositories]) || ['']
+    @activation = params[:rule_activation] || STATUS_ACTIVE
+    @inheritance = params[:inheritance] || 'any'
+    @status = params[:status]
+    @sort_by = !params[:sort_by].blank? ? params[:sort_by] : Rule::SORT_BY_RULE_NAME
+    @searchtext = params[:searchtext]
+  end
+
+  def filter_any(array)
+    if array && array.size>1 && array.include?('')
+      array=[''] #keep only 'any'
+    end
+    array
+  end
+
+end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/helpers/new_rules_configuration_helper.rb b/sonar-server/src/main/webapp/WEB-INF/app/helpers/new_rules_configuration_helper.rb
new file mode 100644 (file)
index 0000000..6932df3
--- /dev/null
@@ -0,0 +1,86 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2013 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube 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.
+#
+# SonarQube 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 this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+module NewRulesConfigurationHelper
+  include PropertiesHelper
+
+  PARAM_TYPE_STRING_LIST = "s{}"
+  PARAM_TYPE_INTEGER_LIST = "i{}"
+
+  # Kept for compatibility with old rule param type
+  def type_with_compatibility(type)
+    return PropertyType::TYPE_STRING if type == 's'
+    return PropertyType::TYPE_STRING if type == PARAM_TYPE_STRING_LIST
+    return PropertyType::TYPE_INTEGER if type == 'i'
+    return PropertyType::TYPE_INTEGER if type == PARAM_TYPE_INTEGER_LIST
+    return PropertyType::TYPE_BOOLEAN if type == 'b'
+    return PropertyType::TYPE_REGULAR_EXPRESSION if type == 'r'
+    return PropertyType::TYPE_STRING if is_set(type)
+
+    type
+  end
+
+  def readable_type(param_type)
+    type=type_with_compatibility(param_type)
+
+    return "Set of comma delimited strings" if param_type == PARAM_TYPE_STRING_LIST
+    return "Number" if type == PropertyType::TYPE_INTEGER
+    return "Set of comma delimited numbers" if param_type == PARAM_TYPE_INTEGER_LIST
+    return "Regular expression" if type == PropertyType::TYPE_REGULAR_EXPRESSION
+    return "Set of comma delimited values" if is_set(param_type)
+    ""
+  end
+
+  def param_value_input(parameter, value, options = {})
+    type=type_with_compatibility(parameter.param_type)
+    name = options[:name] || 'value'
+    property_input_field name, type, value, 'WIDGET', {:id => parameter.id, :size => options[:size] }.update(options)
+  end
+
+  def is_set(type)
+    type.at(1) == "[" && type.ends_with?("]")
+  end
+
+  def validate_rule_param(attribute, param_type, errors, value)
+    return if attribute.nil? or attribute.length == 0
+
+    type=type_with_compatibility(param_type)
+
+    if is_set_type
+      attribute.split(',').each do |v|
+        if !get_allowed_tokens.include?(v)
+          errors.add("#{value}", "'#{v}' must be one of : " + get_allowed_tokens.join(', '))
+        end
+      end
+    elsif param_type == RulesConfigurationHelper::PARAM_TYPE_INTEGER_LIST
+      attribute.split(',').each do |n|
+        if !Api::Utils.is_integer?(n)
+          errors.add("#{value}", "'#{n}' must be an integer.")
+        end
+      end
+    elsif type == PropertyType::TYPE_REGULAR_EXPRESSION
+      errors.add("#{value}", "'#{attribute}' must be a regular expression") unless Api::Utils.is_regexp?(attribute)
+    elsif type == PropertyType::TYPE_INTEGER
+      errors.add("#{value}", "'#{attribute}' must be an integer.") unless Api::Utils.is_integer?(attribute)
+    elsif type == PropertyType::TYPE_BOOLEAN
+      errors.add("#{value}", "'#{attribute}' must be one of : true,false") unless Api::Utils.is_boolean?(attribute)
+    end
+  end
+end
+
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_active_rule_note.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_active_rule_note.html.erb
new file mode 100644 (file)
index 0000000..cc15396
--- /dev/null
@@ -0,0 +1,70 @@
+<% #locals = active_rule, profile
+  note = active_rule.note
+  active_note_detail_div_id = "and_" + active_rule.id.to_s
+  add_active_note_button_id = "aanb_" + active_rule.id.to_s
+  edit_active_note_link_id = "eanl_" + active_rule.id.to_s
+  delete_active_note_link_id = "danl_" + active_rule.id.to_s
+  active_note_form_div_id = "anf_" + active_rule.id.to_s
+  active_note_textarea_id = "ant_" + active_rule.id.to_s
+  submit_active_note_update_button_id = "sanub_" + active_rule.id.to_s
+%>
+
+<div id="<%= active_note_detail_div_id -%>">
+  <% if note %>
+    <blockquote class="spacer-bottom">
+      <cite>
+        <b><%= note.user.name -%></b> (<%= distance_of_time_in_words_to_now(note.updated_at) -%>)&nbsp;
+        <% if profiles_administrator? %>
+          | &nbsp;
+          <a href="#" id="<%= edit_active_note_link_id -%>" class="link-action"
+             onclick="$j('#<%= active_note_detail_div_id -%>').hide();$j('#<%= active_note_form_div_id -%>').show();$j('#<%= active_note_textarea_id -%>').focus();return false;"><%= message('edit') %></a>
+          &nbsp;
+          <a class="link-action"
+             onclick="if(confirm('<%= escape_javascript(message('rules_configuration.confirm_delete_note')) -%>')){
+                             $j.ajax({
+                                       url: '<%=ApplicationController.root_context-%>/new_rules_configuration/delete_active_rule_note?active_rule_id=<%=active_rule.id-%>',
+                                       type: 'post',
+                                       success:function(response){$j('#active_rule_note_<%= active_rule.id -%>').html(response);}
+                                     });};return false;"
+             href="#!"><%=message('delete')-%></a>
+        <% end %>
+      </cite>
+      <p><%= note.html_text -%></p>
+    </blockquote>
+  <% elsif profiles_administrator? %>
+    <a href="#" onclick="$j('#<%= active_note_form_div_id -%>').show();$j('#<%= active_note_detail_div_id -%>').hide();$j('#<%= active_note_textarea_id -%>').focus(); return false;"
+       class="link-action spacer-right" id="<%= add_active_note_button_id -%>"><%= message('rules_configuration.add_note') -%></a>
+  <% end %>
+</div>
+
+<% if profiles_administrator? %>
+  <form onsubmit="$j.ajax({
+                            url:'<%= ApplicationController.root_context -%>/new_rules_configuration/update_active_rule_note?active_rule_id=<%=active_rule.id-%>',
+                            data: $j(this).serialize(),
+                            type:'post',
+                            success:function(response){$j('#active_rule_note_<%= active_rule.id -%>').html(response);}
+                          });
+                  return false;"
+          method="post"
+          action="<%= ApplicationController.root_context -%>/new_rules_configuration//update_active_rule_note?active_rule_id=<%=active_rule.id-%>">
+  <table id="<%= active_note_form_div_id -%>" style="display: none" class="admin table width100">
+    <tbody>
+      <tr>
+        <td class="width100" colspan="2">
+          <textarea name="note" id="<%= active_note_textarea_id -%>" rows="10" style="width:100%"
+                    onkeyup="if (this.value=='') $j('#<%= submit_active_note_update_button_id -%>').prop('disabled', true); else $j('#<%= submit_active_note_update_button_id -%>').prop('disabled', false);"><%= h(note.plain_text) if note -%></textarea>
+        </td>
+      </tr>
+    <tr>
+      <td>
+        <input type="submit" value="<%= note ? message('update_verb') : message('rules_configuration.add_note') -%>" name="submit-active-note" id="<%= submit_active_note_update_button_id -%>" disabled="disabled"/>
+        <a href="#" onclick="$j('#<%= active_note_detail_div_id -%>').show();$j('#<%= active_note_form_div_id -%>').hide();return false;"><%= message('cancel') %></a>
+      </td>
+      <td align="right">
+        <%= render :partial => 'markdown/tips' -%>
+      </td>
+    </tr>
+    </tbody>
+  </table>
+  </form>
+<% end %>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule.html.erb
new file mode 100644 (file)
index 0000000..06d3415
--- /dev/null
@@ -0,0 +1,121 @@
+<td nowrap valign="top" class="left" x="<%= active_rule.failure_level if active_rule -%>" width="1%">
+  <form id="levels_<%= rule.id -%>" action="" class="rule-levels-form">
+    <% enable_modification = profiles_administrator?
+       select_box_id = "levels_select_#{rule.id}"
+       check_box_id = "levels_check_#{rule.id}"
+       activate_rule = "$j.ajax({url:'#{ApplicationController.root_context}/new_rules_configuration/activate_rule/#{profile.id}?rule_id=#{rule.id}',type: 'POST',
+                                 beforeSend: function(request){$j('#levels_#{rule.id}').replaceWith('<img src=\"#{ApplicationController.root_context}/images/loading.gif\"/>');},
+                                 data: 'level='+ get_level_for_rule($j('#levels_select_#{rule.id} :selected'),$j('#levels_check_#{rule.id}'))});"
+       changel_level = "if($j('#levels_check_#{rule.id}').prop('checked'))
+                        {$j.ajax({url:'#{ApplicationController.root_context}/new_rules_configuration/activate_rule/#{profile.id}?rule_id=#{rule.id}',type:'POST',
+                                  beforeSend:function(request){$j('#levels_#{rule.id}').replaceWith('<img src=\"#{ApplicationController.root_context}/images/loading.gif\"/>');},
+                                  data:'level='+$j('#levels_select_#{rule.id} :selected').val()})}"
+    %>
+
+    <%= check_box_tag(check_box_id, 'yes', (!active_rule.nil?), :onclick => activate_rule, :disabled => !enable_modification || (active_rule && (active_rule.inherited? || active_rule.overrides?))) %>
+    <%= select_tag(select_box_id, options_for_select(RulesConfigurationController::RULE_PRIORITIES, (active_rule.nil? ? rule.priority_text : active_rule.priority_text)),
+                   {:onchange => changel_level, :disabled => (!(enable_modification) || active_rule.nil?)}) %>
+
+    <% if active_rule %>
+      <% if active_rule.inherited? %>
+        <img src="<%= ApplicationController.root_context -%>/images/inherited.png" alt="Inherited from parent" title="<%= message('rules_configuration.inherited_from_parent') -%>"/>
+      <% elsif active_rule.overrides? %>
+        <img src="<%= ApplicationController.root_context -%>/images/overrides.png" alt="Overrides parent definition" title="<%= message('rules_configuration.overrides_parent_definition') -%>"/>
+      <% end %>
+    <% end %>
+  </form>
+</td>
+
+<td class="left" colspan="2">
+  <% unless rule.ready? %>
+    <div class="rule-status">
+      <% if rule.beta? %>
+        <span><%= message('rules.status.beta') %></span>
+      <% elsif rule.deprecated? %>
+        <span><%= message('rules.status.deprecated') %></span>
+      <% end %>
+    </div>
+  <% end %>
+
+  <div class="h3 rule-title"><%= link_to_function("#{h rule.name}", nil, :class => "") do |page|
+    page.toggle "desc_#{rule.id}"
+  end
+  %></div>
+
+  <div id="desc_<%= rule.id -%>" class="rule-desc" style="<%= 'display:none' -%>">
+    <a name="rule<%= rule.id -%>"></a>
+
+    <div id="rule_note_<%= rule.id -%>" class="marginbottom10">
+      <%= render :partial => 'rule_note', :locals => {:rule => rule} %>
+    </div>
+
+    <%
+       ancestor_profile = profile.parent
+       ancestor_active_rule = ancestor_profile.active_by_rule_id(rule.id) if ancestor_profile && active_rule && (active_rule.inherited? || active_rule.overrides?)
+       if ancestor_active_rule || !rule.parameters.empty?
+    %>
+      <table width="100%" class="table spacer-bottom bordered background-gray">
+        <%
+           if ancestor_active_rule
+             ancestor_active_rule_link = link_to ancestor_profile.name, :controller => 'rules_configuration', :action => 'index',
+                                                 :id => ancestor_profile.id, :rule_id => rule.id, :anchor => 'rule' + rule.id.to_s
+        %>
+          <tr>
+            <td colspan="2">
+              <%= message(active_rule.inherited? ? 'rules_configuration.rule_inherited_from_profile_x' : 'rules_configuration.rule_overriding_from_profile_x',
+                          :params => ancestor_active_rule_link) -%>
+              <% if ancestor_active_rule.priority != active_rule.priority %>
+                <img src="<%= ApplicationController.root_context -%>/images/overrides.png" alt="Overrides parent definition" title="<%= message('rules_configuration.overrides_parent_definition') -%>" style="vertical-align: middle"/>
+                <span class="form-val-note" style="font-weight: bold"> <%= message('rules_configuration.original_severity') -%>
+                  : <%= ancestor_active_rule.priority_text -%></span>
+              <% end %>
+              <% if profiles_administrator? && active_rule.overrides? %>
+                <form action="<%= url_for :overwrite_params => {:action => 'revert_rule', :id => profile.id, :active_rule_id => active_rule.id} -%>" method="post" style="display: inline">
+                  <input type="submit" value="<%= message('rules_configuration.revert_to_parent_definition') -%>">
+                </form>
+              <% end %>
+            </td>
+          </tr>
+        <% end %>
+        <% rule.parameters.sort.each do |parameter|
+          active_parameter = active_rule.active_param_by_param_id(parameter.id) if active_rule
+        %>
+          <tr id="param_<%= parameter.id -%>">
+            <%= render :partial => 'rule_param', :object => nil,
+                       :locals => {:parameter => parameter, :active_parameter => active_parameter, :profile => profile, :rule => rule,
+                                   :active_rule => active_rule, :ancestor_active_rule => ancestor_active_rule} %>
+          </tr>
+        <%
+           end
+        %>
+      </table>
+    <% end %>
+
+    <% if active_rule %>
+      <div id="active_rule_note_<%= active_rule.id -%>">
+        <%= render :partial => 'active_rule_note', :locals => {:active_rule => active_rule, :profile => profile} %>
+      </div>
+    <% end %>
+
+    <% if profiles_administrator? %>
+      <% if rule.template? %>
+        <%= link_to message('rules_configuration.copy_rule'), {:action => 'new', :id => profile.id, :rule_id => rule.id}, :id => "copy-#{u rule.key}", :class => 'link-action spacer-right' %>
+      <% end %>
+      <% if rule.editable? %>
+        <%= link_to message('rules_configuration.edit_rule'), {:action => 'edit', :id => profile.id, :rule_id => rule.id}, :class => 'link-action spacer-right' %>
+      <% end %>
+    <% end %>
+
+    <div class="note">
+      <span id="rule_repository_<%= rule.id -%>"><%= message('rules_configuration.repository') %>: <%= rule.repository_key %></span>
+      &nbsp;<%= image_tag 'sep12.png' -%>&nbsp;
+      <span id="rule_key_<%= rule.id -%>"><%= message('key') %>: <%= rule.plugin_rule_key %></span>
+      &nbsp;<%= image_tag 'sep12.png' -%>&nbsp;
+      <% if rule.removed? %>
+        <span id="rule_available_since_<%= rule.id -%>"><%= message('rules_configuration.removed_since') %>: <%= human_short_date(rule.updated_at) %></span>
+      <% else %>
+        <span id="rule_available_since_<%= rule.id -%>"><%= message('rules_configuration.available_since') %> <%= human_short_date(rule.created_at) %></span>
+      <% end %>
+    </div>
+  </div>
+</td>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule_note.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule_note.html.erb
new file mode 100644 (file)
index 0000000..bff449e
--- /dev/null
@@ -0,0 +1,65 @@
+<% #locals = rule
+  note = rule.note
+  note_detail_div_id = "nd_" + rule.id.to_s
+  note_extend_link_id = "nel_" + rule.id.to_s
+  note_form_div_id = "nf_" + rule.id.to_s
+  note_textarea_id = "nt_" + rule.id.to_s
+  submit_note_update_button_id = "snub_" + rule.id.to_s
+%>
+
+<div id="<%= note_detail_div_id -%>">
+  <div class="marginbottom10">
+  <% if rule.description.strip.start_with?('<p>') %>
+    <%= Internal.text.interpretMacros(rule.description) %>
+  <% else %>
+    <p><%= Internal.text.interpretMacros(rule.description) %></p>
+  <% end %>
+  </div>
+
+  <% if note && !note.text.strip.blank? %>
+    <p><%= note.html_text -%></p>
+  <% end %>
+
+  <% if profiles_administrator? %>
+    <div>
+        <a href="#" id="<%= note_extend_link_id -%>" class="link-action spacer-right"
+           onclick="$j('#<%= note_detail_div_id -%>').hide();$j('#<%= note_form_div_id -%>').show();$j('#<%= note_textarea_id -%>').focus();return false;"><%= message('rules_configuration.extend_description') %></a>
+    </div>
+  <% end %>
+</div>
+
+<% if profiles_administrator? %>
+<div id="<%= note_form_div_id -%>" style="display: none" class="admin">
+
+  <form onsubmit="$j.ajax({
+                        url:'<%=ApplicationController.root_context-%>/new_rules_configuration/update_rule_note?rule_id=<%=rule.id-%>',
+                        success:function(response){;$j('#rule_note_<%=rule.id-%>').html(response);},
+                        data: $j(this).serialize(),
+                        type:'post'});
+                  return false;"
+        method="post"
+        action="<%=ApplicationController.root_context-%>/new_rules_configuration/update_rule_note?rule_id=<%=rule.id-%>">
+  <table class="width100 table">
+    <tbody>
+      <tr>
+        <td colspan="2"><%= rule.description %></td>
+      </tr>
+      <tr>
+        <td class="width100" colspan="2">
+          <textarea name="text" id="<%= note_textarea_id -%>" rows="10" style="width:100%"><%= h(note.plain_text) if note -%></textarea>
+        </td>
+      </tr>
+    <tr>
+      <td>
+        <input type="submit" value="<%= message('rules_configuration.extend_description') -%>" name="commit" id="<%= submit_note_update_button_id -%>"/>
+        <a href="#" onclick="$j('#<%= note_detail_div_id -%>').show();$j('#<%= note_form_div_id -%>').hide();return false;"><%= message('cancel') %></a>
+      </td>
+      <td align="right">
+        <%= render :partial => 'markdown/tips' -%>
+      </td>
+    </tr>
+    </tbody>
+  </table>
+  </form>
+</div>
+<% end %>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule_param.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule_param.html.erb
new file mode 100644 (file)
index 0000000..dcd477e
--- /dev/null
@@ -0,0 +1,49 @@
+<% param_value = parameter.default_value || ''
+   param_value = active_parameter.value if active_parameter
+   active_param_id = active_parameter.id if active_parameter
+   active_rule_id = active_rule.id if active_rule
+   read_only = !active_rule || !profiles_administrator?
+%>
+
+<td class="form-key-cell"><%= parameter.name -%></td>
+
+<td class="form-val-cell">
+    <form onsubmit="$j.ajax({  url: '<%= ApplicationController.root_context -%>/new_rules_configuration/update_param/<%=active_param_id-%>?active_rule_id=<%=active_rule_id-%>&param_id=<%=parameter.id-%>&profile_id=<%=profile.id-%>',
+                               type:'post',beforeSend: function(request){$j('#param_loading_<%=parameter.id-%>').show();$j('#error_<%=parameter.id-%>').hide();},
+                               data: $j(this).serialize(),
+                               success: function(response){$j('#rule_<%=rule.id-%>').html(response);},
+                               complete: function(request){$j('#desc_<%=rule.id-%>').show();$j('#param_loading_<%=parameter.id-%>').hide();},
+                               error: function(request){$j('#error_<%=parameter.id-%>').text(request.responseText);$j('#error_<%=parameter.id-%>').show();}
+                            }); return false;"
+           name="form-<%=u parameter.name-%>" method="post"
+           action="<%= ApplicationController.root_context -%>/new_rules_configuration/update_param/<%=active_param_id-%>?active_rule_id=<%=active_rule_id-%>&param_id=<%=parameter.id-%>&profile_id=<%=profile.id-%>">
+
+  <div id="error_<%= parameter.id -%>" class="error" style="display: none"></div>
+
+  <span id="text_<%= parameter.id -%>"><%= param_value_input(parameter, param_value, :disabled => read_only) -%></span>
+
+  <% unless read_only %>
+    <%= submit_tag(message('update_verb'), :id => 'submit_' + parameter.id.to_s) %>
+    <img src="<%= ApplicationController.root_context -%>/images/loading.gif" style="display:none;" id="param_loading_<%= parameter.id -%>" class="rule-param-loading">
+    <% if active_parameter and active_parameter.errors.size>0 %>
+      <span class="error"><%= active_parameter.errors.on 'value' %></span>
+    <% end %>
+  <% end %>
+
+  <% if active_rule && active_rule.overrides? && ancestor_active_rule
+       ancestor_param = ancestor_active_rule.active_param_by_param_id(parameter.id)
+       ancestor_value = ancestor_param && ancestor_param.value ? ancestor_param.value : ''
+  %>
+    <% if ancestor_value != param_value %>
+      <img src="<%= ApplicationController.root_context -%>/images/overrides.png" alt="Overrides parent definition" title="<%= message('rules_configuration.overrides_parent_definition') -%>" style="vertical-align: middle"/>
+      <span class="form-val-note" style="font-weight: bold; vertical-align: middle;">
+        <%= message('rules_configuration.original_value') -%>
+        : <%= ancestor_value.blank? ? '(' + message('rules_configuration.parent_parameter.empty') + ')' : ancestor_value -%>
+      </span>
+    <% end %>
+  <% end %>
+
+  <div class="form-val-note"><%= h(parameter.description || "") -%> <%= ('(' + readable_type(parameter.param_type) + ')') if !readable_type(parameter.param_type).empty? -%></div>
+
+  </form>
+</td>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/edit.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/edit.html.erb
new file mode 100644 (file)
index 0000000..fba5800
--- /dev/null
@@ -0,0 +1,69 @@
+<h1 class="marginbottom10"><%= link_to message('quality_profiles.quality_profiles'), :controller => 'profiles', :action => 'index' -%> / <%= h @profile.language -%> / <%= h @profile.name %></h1>
+
+<%= render :partial => 'profiles/tabs', :locals => {:new_tab => 'Edit rule'} %>
+
+<div class="tabs-panel marginbottom10 background-gray">
+
+<form method="POST" id="delete-form" action="<%= url_for :action => 'delete', :id => @profile.id, :rule_id => @rule.id -%>" style="display: none"></form>
+<script>
+  function deleteRule() {
+    var count = <%= ActiveRule.count(:conditions => {:rule_id => @rule.id}) -%>;
+    var message = 'Are you sure?';
+    if (count>0) {
+      message += ' This rule is activated in ' + count + ' profiles.';
+    }
+    if (confirm(message)) {
+      $j('#delete-form').submit();
+    }
+    return false;
+  }
+</script>
+<form method="POST" action="<%= url_for :action => 'update', :id => @profile.id, :rule_id => @rule.id -%>">
+<table width="100%" class="spaced">
+  <tr>
+    <td width="1%" nowrap><%= message('template') -%>:</td>
+    <td class="sep"> </td>
+    <td><%= h @rule.parent.name -%></td>
+  </tr>
+  <tr>
+    <td width="1%" nowrap><%= message('name') -%>:</td>
+    <td class="sep"> </td>
+    <td><input type="text" name="rule[name]" size="80" value="<%= h @rule.name -%>" /></td>
+  </tr>
+  <tr>
+    <td width="1%" nowrap><%= message('default_severity') -%>:</td>
+    <td class="sep"> </td>
+    <td>
+      <select name="rule[priority]">
+        <%= options_for_select(Sonar::RulePriority.as_options, Sonar::RulePriority.to_s(@rule.priority)) %>
+      </select>
+    </td>
+  </tr>
+  <% @rule.parameters.sort{|x,y| x.name <=> y.name}.each do |parameter| %>
+    <tr>
+      <td width="1%" nowrap><%= parameter.name %>:</td>
+      <td class="sep"> </td>
+      <td>
+        <%= param_value_input(parameter, "#{h parameter.default_value}", {:name => "rule_param[#{h parameter.name }]", :size => '80x10'}) -%>
+        <span class="small"><%= h parameter.description %></span>
+      </td>
+    </tr>
+  <% end %>
+  <tr>
+    <td width="1%" nowrap style="vertical-align: top">Description:</td>
+    <td class="sep"> </td>
+    <td valign="top">
+      <textarea name="rule[description]" cols="80" rows="10" style="vertical-align: baseline"><%= @rule.description -%></textarea>
+      <span class="small"><%= message('rules_configuration.html_allowed') -%></span>
+    </td>
+  </tr>
+  <tr>
+    <td colspan="3">
+      <input type="submit" value="<%= message('update_verb') -%>" />
+      <input type="submit" value="<%= message('delete') -%>" onclick="return deleteRule()" class="red-button" />
+      <a href="<%= url_for :action => 'index', :id => @profile.id -%>"><%= message('cancel') -%></a>
+    </td>
+  </tr>
+</table>
+</form>
+</div>
\ No newline at end of file
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/index.html.erb
new file mode 100644 (file)
index 0000000..9c8d642
--- /dev/null
@@ -0,0 +1,169 @@
+<div class="page">
+<script>
+  var localModifications=false;
+
+  function get_level_for_rule(rule_select_box,rule_check_box) {
+     return rule_check_box.prop('checked') ? rule_select_box.val() : '';
+  }
+
+  function submitBulkForm() {
+    if (localModifications) {
+      alert("Please refresh the search results before.");
+      $j('#bulk-form').reset();
+    } else {
+      $j('#bulk-form').submit();
+      $j('#select-bulk-change').select2('disable');
+    }
+    return !localModifications;
+  }
+
+  function downloadCsv() {
+    if (localModifications) {
+      alert("Please refresh the search results before.");
+    }
+    return !localModifications;
+  }
+
+  function expand_rules(){
+     $j('.rule-desc').show();
+  }
+
+  function collapse_rules(){
+    $j('.rule-desc').hide();
+  }
+
+  function submitSearch() {
+    $j("#rules-search-form").submit();
+  }
+
+  function submitSortBy(){
+    $j('#sort_by').val($j('#select-rules-sort-by').val());
+    $j("#rules-search-form").submit();
+  }
+</script>
+<%= render :partial => 'profiles/tabs', :locals => {:selected_tab=>'Coding rules reloaded'} %>
+
+<% enable_modification = profiles_administrator? %>
+<div class="tabs-panel marginbottom10 background-gray">
+
+<% form_tag({:action => 'index'}, {:id => 'rules-search-form', :method => 'get'}) do %>
+    <%= hidden_field_tag "sort_by", @sort_by, :id => 'sort_by' %>
+
+    <div class="table" id="search_table">
+      <div class="rule-search top">
+        <span class="note"><%= message('name') -%>/<%= message('key') -%></span><br/>
+        <%= text_field_tag "searchtext", @searchtext, :id => 'searchtext' %>
+      </div>
+      <div class="rule-search top">
+        <span class="note"><%= message('rules_configuration.repository') -%></span><br/>
+        <%= dropdown_tag "repositories", options_for_select(@select_repositories, @repositories), {
+            :show_search_box => true,
+            :width => '120px',
+            :placeholder => message('any')
+        }, {:id => 'search_repository', :multiple => true} -%>
+      </div>
+      <div class="rule-search top">
+        <span class="note"><%= message('severity') -%></span><br/>
+        <%= dropdown_tag "priorities", options_for_select(@select_priority, @priorities), {
+            :show_search_box => true,
+            :width => '90px',
+            :placeholder => message('any')
+        }, {:id => 'search_priority', :multiple => true} -%>
+      </div>
+      <div class="rule-search top">
+        <span class="note"><%= message('activation') -%></span><br/>
+        <%= dropdown_tag "rule_activation", options_for_select(@select_activation, @activation), {
+            :width => '100px'
+        }, {:id => 'search_activation'} -%>
+      </div>
+      <div class="rule-search top">
+        <span class="note"><%= message('rules_configuration.status_filters') -%></span><br/>
+        <%= dropdown_tag "status", options_for_select(@select_status, @status), {
+            :show_search_box => true,
+            :width => '120px',
+            :placeholder => message('any')
+        }, {:id => 'search_status', :multiple => true} -%>
+      </div>
+      <% if @profile.inherited? %>
+        <div class="rule-search top">
+          <span class="note"><%= message('inheritance') -%></span><br/>
+          <%= dropdown_tag "inheritance", options_for_select(@select_inheritance, @inheritance), {
+              :width => '120px'
+          }, {:id => 'search_inheritance'} -%>
+        </div>
+      <% end %>
+      <div class="rule-search">
+        <br/>
+        <%= submit_tag message('search_verb'), :id => 'submit_search', :onclick => 'submitSearch();' %>
+      </div>
+    </div>
+
+<% end %>
+</div>
+<div class="line-block marginbottom10">
+  <ul style="float: right" class="horizontal">
+    <li class="marginleft10">
+      <div class="csv">
+      <a href="<%= url_for(:controller => 'api/rules', :action => 'index', :language => @profile.language, :profile => @profile.name, :plugins => @repositories.join(','),
+                           :status => @activation, :inheritance => @inheritance, :searchtext => @searchtext, :priorities => @priorities.join(','), :format => 'csv') -%>"
+         onClick="return downloadCsv()" id="download-link" class=""><%= message('download_verb') -%></a>
+      </div>
+    </li>
+    <% if enable_modification && @rules.size>0 %>
+      <li class="marginleft10">
+        <div class="bulk-edit"><%= message('bulk_change') -%>:
+        <form action="<%= ApplicationController.root_context -%>/new_rules_configuration/bulk_edit" method="POST" id="bulk-form"
+              style="display: inline; vertical-align: middle; padding-right:5px">
+          <input type="hidden" name="id" value="<%= @profile.id -%>"/>
+          <input type="hidden" name="bulk_rule_ids" value="<%= @rules.map{|r| r.id}.join(',') -%>"/>
+          <%= dropdown_tag "bulk_action", options_for_select([ ["", ""], [message('activate_all'), "activate"], [message('deactivate_all'), "deactivate"] ], ''), {
+              :width => '110px'
+          }, {:onChange => 'submitBulkForm()', :id => 'select-bulk-change'} -%>
+        </form>
+        </div>
+      </li>
+    <% end %>
+  </ul>
+  <h2>
+     <% if @hidden_actives && @hidden_actives>0 %>
+      <span class="small"><a href="<%= url_for params.merge({:rule_activation => ''}) -%>"
+        id="active-rules-link">+<%= message('rules_configuration.x_found_in_active_rules', :params => @hidden_actives) -%></a></span><% end %>
+     <% if @hidden_inactives && @hidden_inactives>0 %>
+      <span class="small"><a href="<%= url_for params.merge({:rule_activation => ''}) -%>"
+        id="inactive-rules-link">+<%= message('rules_configuration.x_found_in_inactive_rules', :params => @hidden_inactives) -%></a></span><% end %>
+  </h2>
+</div>
+<table class="table table-bordered width100 spacer-bottom" id="result_table">
+  <thead>
+    <tr>
+      <th class="left" nowrap><%= message('active') -%>/<%= message('severity') -%></th>
+      <th class="left"><%= message('name') -%> <span style="font-weight: normal">
+        [<%= link_to_function(message('rules_configuration.expand'), "expand_rules()") %> / <%= link_to_function(message('rules_configuration.collapse'), "collapse_rules()") %>]</span></th>
+      <th class="right" nowrap>
+        <span class="middle"><%= message('rules_configuration.sort_by') -%></span>
+        <% form_tag({:action => 'index'}, :class=> 'middle', :style => 'display:inline-block') do %>
+          <%= dropdown_tag "sort_by", options_for_select(@select_sort_by, @sort_by), {
+              :width => '120px'
+          }, {:id => 'select-rules-sort-by', :onChange => 'submitSortBy()'} -%>
+        <% end %>
+      </th>
+    </tr>
+</thead>
+
+<%= table_pagination(@pagination, :colspan => 2) { |label, page_id| link_to(label, params.merge({:page => page_id}))} -%>
+
+<tbody>
+<% if @current_rules.empty? %>
+<tr><td colspan="3" class="even"><%= message('no_results') -%>.</td></tr>
+<% end %>
+<%
+  @current_rules.each do |rule|
+    active_rule = @profile.active_by_rule_id(rule.id)
+%>
+  <tr id="rule_<%= rule.id -%>">
+    <%= render :partial => 'rule', :object => rule, :locals => {:profile => @profile, :rule => rule, :active_rule => active_rule} %>
+  </tr>
+<% end %>
+</tbody>
+</table>
+</div>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/new.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/new.html.erb
new file mode 100644 (file)
index 0000000..c767c20
--- /dev/null
@@ -0,0 +1,53 @@
+<div class="page">
+<%= render :partial => 'profiles/tabs', :locals => {:new_tab => message('rules_configuration.tab.new_rule')} %>
+
+<div class="tabs-panel marginbottom10 background-gray">
+
+<form method="POST" action="<%= url_for :action => 'create', :id => @profile.id, :rule_id => @rule.id -%>">
+<table width="100%" class="spaced">
+  <tr>
+    <td width="1%" nowrap><%= message('template') -%>:</td>
+    <td class="sep"> </td>
+    <td><%= h @rule.name -%></td>
+  </tr>
+  <tr>
+    <td width="1%" nowrap><%= message('name') -%>:</td>
+    <td class="sep"> </td>
+    <td><input type="text" name="rule[name]" size="80"/></td>
+  </tr>
+  <tr>
+    <td width="1%" nowrap><%= message('default_severity') -%>:</td>
+    <td class="sep"> </td>
+    <td>
+      <select name="rule[priority]">
+        <%= options_for_select(Sonar::RulePriority.as_options) %>
+      </select>
+    </td>
+  </tr>
+  <% @rule.parameters.sort{|x,y| x.name <=> y.name}.each do |parameter| %>
+    <tr>
+      <td width="1%" nowrap><%= parameter.name %>:</td>
+      <td class="sep"> </td>
+      <td>
+        <%= param_value_input(parameter, "", {:name => "rule_param[#{h parameter.name}]", :size => '80x10'}) -%>
+        <span class="small"><%= h parameter.description %></span>
+      </td>
+    </tr>
+  <% end %>
+  <tr>
+    <td width="1%" nowrap style="vertical-align: top"><%= message('description') -%>:</td>
+    <td class="sep"> </td>
+    <td valign="top">
+      <textarea name="rule[description]" cols="80" rows="10" style="vertical-align: baseline"></textarea>
+      <span class="small"><%= message('rules_configuration.html_allowed') -%></span>
+    </td>
+  </tr>
+  <tr>
+    <td colspan="3">
+      <input type="submit" value="<%= message('create') -%>"/> <a href="<%= url_for :action => 'index', :id => @profile.id -%>"><%= message('cancel') -%></a>
+    </td>
+  </tr>
+</table>
+</form>
+</div>
+</div>
index 5a5ce051762b9bd3badedbaa16afdf2838c16bcf..4fc5f49a68f74a0759574e739eb6406503e5b54d 100644 (file)
@@ -21,6 +21,9 @@
   <li>
     <a href="<%= url_for :controller => 'profiles', :action => 'changelog', :id => @profile.id -%>" <%= "class='selected'" if selected_tab=='changelog' -%> id="tab-changelog"><%= message('changelog') -%></a>
   </li>
+  <li>
+    <a href="<%= url_for :controller => 'new_rules_configuration', :action => 'index', :id => @profile.id %>" <%= "class='selected'" if selected_tab=='Coding rules reloaded' -%> id="tab-rules"><%= message('Coding rules reloaded') -%></a>
+  </li>
   <% if new_tab %>
   <li>
     <a href="#" class='selected'><%= new_tab -%></a>