--- /dev/null
- public String getDefault(String language) {
- QualityProfileDto profile = factory.getDefault(language);
- return profile != null ? profile.getKey() : null;
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.
+ */
+package org.sonar.server.qualityprofile;
+
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.index.query.FilterBuilders;
+import org.elasticsearch.index.query.OrFilterBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.sonar.api.ServerComponent;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.qualityprofile.db.ActiveRuleKey;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.user.UserDto;
+import org.sonar.server.activity.index.ActivityIndex;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.rule.index.RuleQuery;
+import org.sonar.server.search.IndexClient;
+import org.sonar.server.search.QueryOptions;
+import org.sonar.server.search.Result;
+import org.sonar.server.user.UserSession;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.List;
+
+public class QProfileService implements ServerComponent {
+
+ private final DbClient db;
+ private final IndexClient index;
+ private final RuleActivator ruleActivator;
+ private final QProfileFactory factory;
+ private final QProfileBackuper backuper;
+ private final QProfileCopier copier;
+ private final QProfileReset reset;
+
+ public QProfileService(DbClient db, IndexClient index, RuleActivator ruleActivator, QProfileFactory factory,
+ QProfileBackuper backuper, QProfileCopier copier, QProfileReset reset) {
+ this.db = db;
+ this.index = index;
+ this.ruleActivator = ruleActivator;
+ this.factory = factory;
+ this.backuper = backuper;
+ this.copier = copier;
+ this.reset = reset;
+ }
+
+ public QualityProfileDto create(QProfileName name) {
+ verifyAdminPermission();
+ DbSession dbSession = db.openSession(false);
+ try {
+ QualityProfileDto profile = factory.create(dbSession, name);
+ dbSession.commit();
+ return profile;
+ } finally {
+ dbSession.close();
+ }
+ }
+
+ /**
+ * Activate a rule on a Quality profile. Update configuration (severity/parameters) if the rule is already
+ * activated.
+ */
+ public List<ActiveRuleChange> activate(String profileKey, RuleActivation activation) {
+ verifyAdminPermission();
+ DbSession dbSession = db.openSession(false);
+ try {
+ List<ActiveRuleChange> changes = ruleActivator.activate(dbSession, activation, profileKey);
+ dbSession.commit();
+ return changes;
+ } finally {
+ dbSession.close();
+ }
+ }
+
+ /**
+ * Deactivate a rule on a Quality profile. Does nothing if the rule is not activated, but
+ * fails if the rule or the profile does not exist.
+ */
+ public List<ActiveRuleChange> deactivate(ActiveRuleKey key) {
+ verifyAdminPermission();
+ return ruleActivator.deactivate(key);
+ }
+
+ public BulkChangeResult bulkActivate(RuleQuery ruleQuery, String profile, @Nullable String severity) {
+ verifyAdminPermission();
+ return ruleActivator.bulkActivate(ruleQuery, profile, severity);
+ }
+
+ public BulkChangeResult bulkDeactivate(RuleQuery ruleQuery, String profile) {
+ verifyAdminPermission();
+ return ruleActivator.bulkDeactivate(ruleQuery, profile);
+ }
+
+ public void backup(String profileKey, Writer writer) {
+ // Allowed to non-admin users (see http://jira.codehaus.org/browse/SONAR-2039)
+ backuper.backup(profileKey, writer);
+ }
+
+ /**
+ * @deprecated used only by Ruby on Rails. Use {@link #backup(String, java.io.Writer)}
+ */
+ @Deprecated
+ public String backup(String profileKey) {
+ StringWriter output = new StringWriter();
+ backup(profileKey, output);
+ return output.toString();
+ }
+
+ public void restore(Reader backup) {
+ verifyAdminPermission();
+ backuper.restore(backup, null);
+ }
+
+ /**
+ * @deprecated used only by Ruby on Rails. Use {@link #restore(java.io.Reader)}
+ */
+ @Deprecated
+ public void restore(String backup) {
+ restore(new StringReader(backup));
+ }
+
+ public void restoreBuiltInProfilesForLanguage(String lang) {
+ verifyAdminPermission();
+ reset.resetLanguage(lang);
+ }
+
+ /**
+ * Currently used by Ruby on Rails
+ */
+ public Collection<String> builtInProfileNamesForLanguage(String lang) {
+ return reset.builtInProfileNamesForLanguage(lang);
+ }
+
+ public void copyToName(String fromKey, String toName) {
+ verifyAdminPermission();
+ copier.copyToName(fromKey, toName);
+ }
+
+ public void delete(String key) {
+ verifyAdminPermission();
+ factory.delete(key);
+ }
+
+ public void rename(String key, String newName) {
+ verifyAdminPermission();
+ factory.rename(key, newName);
+ }
+
+ /**
+ * Set or unset parent profile.
+ *
+ * @param key key of existing profile
+ * @param parentKey key of parent profile to be inherited from. Or <code>null</code> to unset the parent.
+ */
+ public void setParent(String key, @Nullable String parentKey) {
+ verifyAdminPermission();
+ ruleActivator.setParent(key, parentKey);
+ }
+
+ /**
+ * Set the given quality profile as default for the related language
+ */
+ public void setDefault(String key) {
+ verifyAdminPermission();
+ factory.setDefault(key);
+ }
+
++ /**
++ * Used in /api/profiles and in /profiles/export
++ * @param language
++ * @return
++ */
+ @CheckForNull
++ public QualityProfileDto getDefault(String language) {
++ return factory.getDefault(language);
+ }
+
+ private void verifyAdminPermission() {
+ UserSession.get().checkLoggedIn();
+ UserSession.get().checkGlobalPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+ }
+
+ public Result<QProfileActivity> searchActivities(QProfileActivityQuery query, QueryOptions options) {
+ DbSession session = db.openSession(false);
+ try {
+ OrFilterBuilder activityFilter = FilterBuilders.orFilter();
+ for (String profileKey : query.getQprofileKeys()) {
+ activityFilter.add(FilterBuilders.nestedFilter("details",
+ QueryBuilders.matchQuery("details.profileKey", profileKey)));
+ }
+
+ SearchResponse response = index.get(ActivityIndex.class).search(query, options, activityFilter);
+ Result<QProfileActivity> result = new Result<QProfileActivity>(response);
+ for (SearchHit hit : response.getHits().getHits()) {
+ QProfileActivity profileActivity = new QProfileActivity(hit.getSource());
+ RuleDto ruleDto = db.ruleDao().getNullableByKey(session, profileActivity.ruleKey());
+ profileActivity.ruleName(ruleDto != null ? ruleDto.getName() : null);
+
+ String login = profileActivity.login();
+ if (login != null) {
+ UserDto user = db.userDao().selectActiveUserByLogin(login, session);
+ profileActivity.authorName(user != null ? user.getName() : null);
+ }
+ result.getHits().add(profileActivity);
+ }
+ return result;
+ } finally {
+ session.close();
+ }
+ }
+}
--- /dev/null
- disabledFilters = this.collection.where enabled: false
+define [
+ 'navigator/filters/filter-bar',
+ 'navigator/filters/base-filters',
+ 'navigator/filters/favorite-filters',
+ 'navigator/filters/more-criteria-filters',
++ 'navigator/filters/read-only-filters',
+ 'templates/coding-rules'
+], (
+ FilterBarView,
+ BaseFilters,
+ FavoriteFiltersModule,
+ MoreCriteriaFilters,
++ ReadOnlyFilterView,
+ Templates
+) ->
+
+ class CodingRulesFilterBarView extends FilterBarView
+ template: Templates['coding-rules-filter-bar']
+
+ collectionEvents:
+ 'change:enabled': 'changeEnabled'
+
+
+ events:
+ 'click .navigator-filter-submit': 'search'
+
+
+ onRender: ->
+ @selectFirst()
+
+
+ getQuery: ->
+ query = {}
+ @collection.each (filter) ->
+ _.extend query, filter.view.formatValue()
+ query
+
+
+ onAfterItemAdded: (itemView) ->
+ if itemView.model.get('type') == FavoriteFiltersModule.FavoriteFilterView
+ jQuery('.navigator-header').addClass 'navigator-header-favorite'
+
+
+ addMoreCriteriaFilter: ->
- filter.get('type') == MoreCriteriaFilters.MoreCriteriaFilterView
++ readOnlyFilters = @collection.where(type: ReadOnlyFilterView)
++ disabledFilters = _.difference(@collection.where(enabled: false), readOnlyFilters)
+ if disabledFilters.length > 0
+ @moreCriteriaFilter = new BaseFilters.Filter
+ type: MoreCriteriaFilters.MoreCriteriaFilterView,
+ enabled: true,
+ optional: false,
+ filters: disabledFilters
+ @collection.add @moreCriteriaFilter
+
+
+ changeEnabled: ->
+ if @moreCriteriaFilter?
+ disabledFilters = _.reject @collection.where(enabled: false), (filter) ->
++ filter.get('type') in [MoreCriteriaFilters.MoreCriteriaFilterView, ReadOnlyFilterView]
+
+ if disabledFilters.length == 0
+ @moreCriteriaFilter.set { enabled: false }, { silent: true }
+ else
+ @moreCriteriaFilter.set { enabled: true }, { silent: true }
+
+ @moreCriteriaFilter.set { filters: disabledFilters }, { silent: true }
+ @moreCriteriaFilter.trigger 'change:filters'
+
+
+ search: ->
+ @$('.navigator-filter-submit').blur()
+ @options.app.state.set
+ query: this.options.app.getQuery(),
+ search: true
+ @options.app.fetchFirstPage()
+
+
+ fetchNextPage: ->
+ @options.app.fetchNextPage()
--- /dev/null
- default_profile_by_language[language] = Internal.quality_profiles.defaultProfile(language)
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 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 'json'
+
+class Api::ProfilesController < Api::ApiController
+
+ # GET /api/profiles/list?[language=<language][&project=<project id or key>]
+ #
+ # Since v.3.3
+ #
+ # ==== Examples
+ # - get all the profiles : GET /api/profiles/list
+ # - get all the Java profiles : GET /api/profiles/list?language=java
+ # - get the profiles used by the project 'foo' : GET /api/profiles/list?project=foo
+ # - get the Java profile used by the project 'foo' : GET /api/profiles/list?project=foo&language=java
+ def list
+ language = params[:language]
+ project_key = params[:project]
+
+ profiles = []
+ default_profile_by_language = {}
+ if project_key.present?
+ project = Project.by_key(project_key)
+ not_found('Unknown project') unless project
+ if language.present?
- default_profile_by_language[language.getKey()] = Internal.quality_profiles.defaultProfile(language.getKey())
++ default_profile_by_language[language] = Internal.qprofile_service.getDefault(language)
+ profile = Internal.quality_profiles.findProfileByProjectAndLanguage(project.id, language)
+ profiles << profile if profile
+ # Return default profile if the project is not associate to a profile
+ profiles << default_profile_by_language[language] unless profile
+ else
+ Api::Utils.languages.each do |language|
- default_profile_by_language[lang] = Internal.quality_profiles.defaultProfile(lang.to_s)
++ default_profile_by_language[language.getKey()] = Internal.qprofile_service.getDefault(language.getKey())
+ profile = Internal.quality_profiles.findProfileByProjectAndLanguage(project.id, language.getKey())
+ profiles << profile if profile
+ # Return default profile if the project is not associate to a profile
+ profiles << default_profile_by_language[language.getKey()] unless profile
+ end
+ end
+ elsif language.present?
+ profiles = Internal.quality_profiles.profilesByLanguage(language).to_a
+ else
+ profiles = Internal.quality_profiles.allProfiles().to_a
+ end
+
+ # Populate the map of default profile by language by searching for all profiles languages
+ # We have to do that as the profiles list do not contain this information (maybe we should add it?)
+ profiles.each do |p|
+ lang = p.language
+ unless default_profile_by_language[lang]
- profile_key=Java::OrgSonarCoreQualityprofileDb::QualityProfileKey.of(params[:name], params[:language])
++ default_profile_by_language[lang] = Internal.qprofile_service.getDefault(lang.to_s)
+ end
+ end
+
+ json = profiles.compact.map { |profile| {:name => profile.name, :language => profile.language, :default => default_profile_by_language[profile.language].name == profile.name } }
+ respond_to do |format|
+ format.json { render :json => jsonp(json) }
+ format.xml { render :xml => xml_not_supported }
+ format.text { render :text => text_not_supported }
+ end
+ end
+
+ # POST /api/profiles/destroy?language=<language>&name=<name>
+ def destroy
+ verify_post_request
+ access_denied unless has_role?(:profileadmin)
+ require_parameters :language, :name
+
- Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).delete(profile_key)
+ call_backend do
- profile_key=Java::OrgSonarCoreQualityprofileDb::QualityProfileKey.of(profile.name, profile.language)
- Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).setDefault(profile_key)
++ profile = Internal.quality_profiles.profile(params[:name], params[:language])
++ not_found('Profile not found') unless profile
++ Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).delete(profile.key)
+ end
+ render_success('Profile destroyed')
+ end
+
+ # POST /api/profiles/set_as_default?language=<language>&name=<name>
+ #
+ # Since v.3.3
+ def set_as_default
+ verify_post_request
+ profile = Internal.quality_profiles.profile(params[:name], params[:language])
+ not_found('Profile not found') unless profile
- profile = Internal.quality_profiles.defaultProfile(language)
++ Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).setDefault(profile.key)
+ render_success
+ end
+
+ # GET /api/profiles?language=<language>[&name=<name>]
+ def index
+ require_parameters :language
+
+ language=params[:language]
+ name=params[:name]
+ if name.blank?
+ @profile=Profile.by_default(language)
+ else
+ @profile=Profile.find_by_name_and_language(name, language)
+ end
+ not_found('Profile not found') unless @profile
+
+ @active_rules=filter_rules()
+
+ respond_to do |format|
+ format.json { render :json => jsonp(to_json) }
+ format.xml { render :xml => to_xml }
+ format.text { render :text => text_not_supported }
+ end
+ end
+
+ # Backup a profile. If output format is xml, then backup is directly returned.
+ # GET /api/profiles/backup?language=<language>[&name=my_profile] -v
+ def backup
+ require_parameters :language
+
+ language = params[:language]
+ if (params[:name].blank?)
- profile_key=Java::OrgSonarCoreQualityprofileDb::QualityProfileKey.of(profile.name, profile.language)
- backup = Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).backup(profile_key)
++ profile = Internal.qprofile_service.getDefault(language)
+ else
+ profile = Internal.quality_profiles.profile(params[:name], params[:language])
+ end
+
- xml.parent(@profile.parent_name) if @profile.parent_name.present?
++ not_found('Profile not found') unless profile
++ backup = Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).backup(profile.key)
+
+ respond_to do |format|
+ format.xml { render :xml => backup }
+ format.json { render :json => jsonp({:backup => backup}) }
+ end
+ end
+
+ # Restore a profile backup.
+ # curl -X POST -u admin:admin -F 'backup=<my>backup</my>' -v http://localhost:9000/api/profiles/restore
+ # curl -X POST -u admin:admin -F 'backup=@backup.xml' -v http://localhost:9000/api/profiles/restore
+ def restore
+ verify_post_request
+ require_parameters :backup
+
+ backup = Api::Utils.read_post_request_param(params[:backup])
+ Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).restore(backup)
+
+ respond_to do |format|
+ #TODO format.json { render :json => jsonp(validation_result_to_json(result)), :status => 200 }
+ format.json { render :json => jsonp({}), :status => 200 }
+ end
+ end
+
+ private
+
+ def validation_messages_to_json(messages)
+ hash={}
+ hash[:errors]=messages.getErrors().to_a.map { |message| message }
+ hash[:warnings]=messages.getWarnings().to_a.map { |message| message }
+ hash[:infos]=messages.getInfos().to_a.map { |message| message }
+ hash
+ end
+
+ def validation_result_to_json(result)
+ hash={}
+ hash[:warnings]=result.warnings().to_a.map { |message| message }
+ hash[:infos]=result.infos().to_a.map { |message| message }
+ hash
+ end
+
+ def filter_rules
+ conditions=['active_rules.profile_id=?']
+ condition_values=[@profile.id]
+
+ if params[:rule_repositories].present?
+ conditions<<'rules.plugin_name in (?)'
+ condition_values<<params[:rule_repositories].split(',')
+ end
+
+ if params[:rule_severities].present?
+ conditions<<'failure_level in (?)'
+ condition_values<<params[:rule_severities].split(',').map { |severity| Sonar::RulePriority.id(severity) }
+ end
+
+ ActiveRule.find(:all, :include => [:rule, {:active_rule_parameters => :rules_parameter}], :conditions => [conditions.join(' AND ')].concat(condition_values))
+ end
+
+ def to_json
+ result={}
+ result[:name]=@profile.name
+ result[:language]=@profile.language
+ result[:parent]=@profile.parent_kee if @profile.parent_kee.present?
+ result[:default]=@profile.default_profile?
+
+ rules=[]
+ @active_rules.each do |active_rule|
+ hash={}
+ hash[:key]=active_rule.rule.plugin_rule_key
+ hash[:repo]=active_rule.rule.plugin_name
+ hash[:severity]=active_rule.priority_text
+ hash[:inheritance]=active_rule.inheritance if active_rule.inheritance
+ params_hash=[]
+ active_rule.active_rule_parameters.each do |param|
+ params_hash<<{:key => param.name, :value => param.value}
+ end
+ hash[:params]=params_hash unless params_hash.empty?
+ rules<<hash
+ end
+ result[:rules]=rules unless rules.empty?
+
+ [result]
+ end
+
+ def to_xml
+ xml = Builder::XmlMarkup.new(:indent => 0)
+ xml.instruct!
+
+ xml.profile do
+ xml.name(@profile.name)
+ xml.language(@profile.language)
++ xml.parent(@profile.parent_kee) if @profile.parent_kee.present?
+ xml.default(@profile.default_profile?)
+
+ @active_rules.each do |active_rule|
+ xml.rule do
+ xml.key(active_rule.rule.plugin_rule_key)
+ xml.repo(active_rule.rule.plugin_name)
+ xml.severity(active_rule.priority_text)
+ xml.inheritance(active_rule.inheritance) if active_rule.inheritance
+ active_rule.active_rule_parameters.each do |param|
+ xml.param do
+ xml.key(param.name)
+ xml.value(param.value)
+ end
+ end
+ end
+ end
+ end
+ end
+
+end
--- /dev/null
- is_default_profile = default_profile && default_profile==profile.key()
+<div class="page">
+<div class="line-block marginbottom10">
+ <ul style="float: right" class="operations">
+ <li>
+ <i class="icon-compare"></i>
+ <a href="profiles/compare" id="compare-link"><%= message('quality_profiles.compare_profiles') -%></a>
+ </li>
+ <% if profiles_administrator? %>
+ <li class="last">
+ <i class="icon-restore"></i>
+ <a href="profiles/restore_form" class="open-modal" id="restore-link"><%= message('quality_profiles.restore_profile') -%></a>
+ </li>
+ <% end %>
+ </ul>
+</div>
+
+<%
+ Api::Utils.insensitive_sort(languages){|l| l.getName()}.each do |language|
+ default_profile = Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).getDefault(language.getKey())
+%>
+ <div class="line-block">
+ <% if profiles_administrator? %>
+ <ul style="float: right" class="horizontal">
+ <li class="marginleft10">
+ <i class="icon-plus"></i>
+ <a id="create-link-<%= language.getKey() -%>" href="<%= ApplicationController.root_context -%>/profiles/create_form?language=<%= u language.getKey() -%>"
+ class="open-modal link-action"><%= message('create') -%></a>
+ </li>
+ </ul>
+ <ul style="float: right" class="horizontal">
+ <li class="marginleft10">
+ <a id="create-link-<%= language.getKey() -%>" href="<%= ApplicationController.root_context -%>/profiles/restore_built_in_form?language=<%= u language.getKey() -%>"
+ class="open-modal link-action"><%= message('quality_profiles.restore_built_in_profiles') -%></a>
+ </li>
+ </ul>
+ <% end %>
+ <h2><%= message('quality_profiles.x_language_profiles', :params => language.getName()) -%></h2>
+ </div>
+
+ <table class="data width100" id="profiles_<%= language.getKey() -%>">
+ <thead>
+ <tr>
+ <th class="left"><%= message('name') -%></th>
+ <th class="right"><%= message('rules') -%></th>
+ <th class="right"><%= message('projects') -%></th>
+ <th class="right"><%= message('default') -%></th>
+ <% if profiles_administrator? %>
+ <th width="1%" class="right" colspan="4"><%= message('operations') -%></th>
+ <% end %>
+ </tr>
+ </thead>
+ <tbody>
+ <% @profiles.select { |p| p.language == language.getKey() }.each do |profile|
+ projects_count = projects_count(profile)
++ is_default_profile = default_profile && default_profile.key()==profile.key()
+ %>
+ <tr class="<%= cycle 'even', 'odd', :name => language.getKey() -%> hoverable" id="<%= u profile.key() %>">
+ <td width="40%">
+ <a href="<%= url_for :controller => 'profiles', :action => 'show', :key => profile.key() -%>"
+ id="rules-<%= profile.key() -%>"><%= h profile.name() -%></a>
+ </td>
+
+ <td align="right" width="10%">
+ <%
+ rules_tooltip = message('quality_profiles.see_rules_tooltip_x_profile', :params => [profile.name()])
+ rules_tooltip = message('quality_profiles.manage_rules_tooltip_x_profile', :params => [profile.name()]) if profiles_administrator?
+ %>
+ <a class="widget-link"
+ href="<%= "#{ApplicationController.root_context}/coding_rules#qprofile=#{profile.key()}|activation=true|languages=#{profile.language()}" -%>"
+ title="<%= rules_tooltip %>">
+ <span id="activated_rules_<%= u profile.key() -%>">
+ <%= @active_rule_counts[profile.key()] || 0 -%>
+ </span>
+ </a>
+ </td>
+
+ <td align="right" width="10%" nowrap>
+ <% unless is_default_profile %>
+ <span id="projects_<%= u profile.key() -%>"><%= projects_count -%></span>
+ <% end %>
+ </td>
+
+ <td align="right" width="10%" nowrap>
+ <% if !is_default_profile && profiles_administrator? %>
+ <%= link_to_action message('set_as_default'), "#{ApplicationController.root_context}/profiles/set_as_default?id=#{profile.id()}",
+ :id => "activate_#{profile.key().parameterize}",
+ :class => 'link-action',
+ :confirm_title => message('set_as_default'),
+ :confirm_msg => message('quality_profiles.are_you_sure_want_x_profile_as_default', :params => [profile.name()]),
+ :confirm_button => message('set_as_default')
+ -%>
+ <% end %>
+ <% if is_default_profile %>
+ <i class="icon-check" id='<%= "is_active_#{u profile.key()}" -%>'></i>
+ <% end %>
+ </td>
+
+ <td align="right" nowrap>
+ <form method="post" action="<%= ApplicationController.root_context -%>/profiles/backup" id="backup-<%= profile.key() -%>-form">
+ <input type="hidden" name="key" value="<%= profile.key() -%>"/>
+ <a href="#" class="link-action" name="button_backup" id="backup_<%= u profile.key() -%>" onclick="$j('#backup-<%= profile.key() -%>-form').submit();return false;"><%= message('backup_verb') -%></a>
+ </form>
+ </td>
+ <% if profiles_administrator? %>
+ <td align="right">
+ <a id="rename-<%= profile.key().parameterize -%>" href="<%= ApplicationController.root_context -%>/profiles/rename_form/<%= profile.id() -%>" class="link-action open-modal"><%= message('rename') -%></a>
+ </td>
+
+ <td align="right">
+ <a id="copy-<%= profile.key().parameterize -%>" href="<%= ApplicationController.root_context -%>/profiles/copy_form/<%= profile.id() -%>" class="link-action open-modal"><%= message('copy') -%></a>
+ </td>
+
+ <td>
+ <% if !is_default_profile %>
+ <%= link_to_action message('delete'), "#{ApplicationController.root_context}/profiles/delete/#{profile.id()}",
+ :class => 'link-action link-red',
+ :id => "delete_#{profile.key().parameterize}",
+ :confirm_button => message('delete'),
+ :confirm_title => 'quality_profiles.delete_confirm_title',
+ :confirm_msg => 'quality_profiles.are_you_sure_want_delete_profile_x_and_descendants',
+ :confirm_msg_params => [profile.name()]
+ -%>
+ <% end %>
+ </td>
+ <% end %>
+ </tr>
+ <% end %>
+ </tbody>
+ </table>
+ <br/><br/>
+<% end %>
+</div>