]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5820 Add quality profiles
authorStas Vilchik <vilchiks@gmail.com>
Mon, 22 Dec 2014 17:06:43 +0000 (18:06 +0100)
committerStas Vilchik <vilchiks@gmail.com>
Tue, 23 Dec 2014 11:37:57 +0000 (12:37 +0100)
19 files changed:
server/sonar-web/src/main/hbs/coding-rules/coding-rules-rule-details.hbs
server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-profile-activation.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-description.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-meta.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-parameters.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-profile.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-profiles.hbs [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/controller.js
server/sonar-web/src/main/js/coding-rules/models/rule.js
server/sonar-web/src/main/js/coding-rules/models/rules.js
server/sonar-web/src/main/js/coding-rules/rule-details-view.js
server/sonar-web/src/main/js/coding-rules/rule/profile-activation-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/rule/rule-description-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/rule/rule-meta-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/rule/rule-parameters-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/rule/rule-profile-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/rule/rule-profiles-view.js [new file with mode: 0644]
server/sonar-web/src/main/less/coding-rules.less
server/sonar-web/src/main/less/components/modals.less

index 935dd66e8cbbf975180303a43c792af9b09484db..4414fd197d8b038722f6141eb6dccf6a5962447a 100644 (file)
@@ -1,125 +1,6 @@
-<h3 class="coding-rules-detail-header">
-  {{name}}
-  <a class="coding-rules-detail-permalink icon-link" target="_blank" href="#rule_key={{key}}"></a>
-</h3>
-<span class="subtitle">{{key}}</span>
-
-<ul class="coding-rules-detail-properties">
-  {{#unless isManual}}
-    <li class="coding-rules-detail-property">{{severityIcon severity}} {{t "severity" severity}}</li>
-  {{/unless}}
-  {{#notEq status 'READY'}}
-    <li class="coding-rules-detail-property">
-      <span class="coding-rules-detail-status coding-rules-detail-not-ready">{{status}}</span>
-    </li>
-  {{/notEq}}
-
-
-  <li class="coding-rules-detail-property coding-rules-detail-tag-list {{#if canWrite}}coding-rules-detail-tags-change{{/if}}">
-    <i class="icon-tags"></i>
-    <span>{{#if allTags}}{{join allTags ', '}}{{else}}{{t 'coding_rules.no_tags'}}{{/if}}</span>
-  </li>
-  {{#if canWrite}}<li class="coding-rules-detail-property coding-rules-detail-tag-edit">
-    {{#if sysTags}}<i class="icon-tags"></i>
-      <span>{{join sysTags ', '}}</span>{{/if}}
-    <input class="coding-rules-detail-tag-input" type="text" value="{{#if tags}}{{join tags ','}}{{/if}}">
-
-    <div class="button-group">
-      <button class="coding-rules-detail-tag-edit-done">{{t 'Done'}}</button>
-    </div>
-    <a class="coding-rules-details-tag-edit-cancel">{{t 'cancel'}}</a>
-  </li>{{/if}}
-
-  {{#if subCharacteristic}}
-    <li class="coding-rules-detail-property coding-rules-subcharacteristic">{{subCharacteristic}}</li>
-  {{/if}}
-  <li class="coding-rules-detail-property">{{t 'coding_rules.available_since'}} {{d createdAt}}</li>
-  <li class="coding-rules-detail-property">{{repository}}{{#unless isManual}} ({{language}}){{/unless}}</li>
-
-  {{#if isTemplate}}
-    <li class="coding-rules-detail-property" title="{{t 'coding_rules.rule_template.title'}}">{{t 'coding_rules.rule_template'}}</li>
-  {{/if}}
-  {{#if templateKey}}
-    <li class="coding-rules-detail-property" title="{{t 'coding_rules.custom_rule.title'}}">{{t 'coding_rules.custom_rule'}}
-      (<a href="#rule_key={{templateKey}}">{{t 'coding_rules.show_template'}}</a>)
-    </li>
-  {{/if}}
-</ul>
-
-<div class="coding-rules-detail-description rule-desc markdown">{{{htmlDesc}}}</div>
-
-{{#unless isEditable}}
-  {{#unless isManual}}
-    <div class="coding-rules-detail-description coding-rules-detail-description-extra">
-      <div id="coding-rules-detail-description-extra">
-        {{#if htmlNote}}
-          <div class="rule-desc marginbottom10 markdown">{{{htmlNote}}}</div>{{/if}}
-        {{#if canWrite}}<div class="button-group">
-          <button id="coding-rules-detail-extend-description">{{t 'coding_rules.extend_description'}}</button>
-        </div>{{/if}}
-      </div>
-
-      {{#if canWrite}}<div class="coding-rules-detail-extend-description-form">
-        <table class="width100">
-          <tbody>
-          <tr>
-            <td class="width100" colspan="2">
-            <textarea id="coding-rules-detail-extend-description-text" rows="4"
-                      style="width: 100%; margin-bottom: 4px;">{{mdNote}}</textarea>
-            </td>
-          </tr>
-          <tr>
-            <td>
-              <div class="button-group">
-                <button id="coding-rules-detail-extend-description-submit">{{t 'save'}}</button>
-                {{#if mdNote}}
-                  <button id="coding-rules-detail-extend-description-remove" class="button-red">{{t 'remove'}}</button>
-                {{/if}}
-              </div>
-              <a id="coding-rules-detail-extend-description-cancel" class="action">{{t 'cancel'}}</a>
-            </td>
-            <td class="right">
-              {{> '_markdown-tips' }}
-            </td>
-          </tr>
-          </tbody>
-        </table>
-      </div>
-
-        <div id="coding-rules-detail-extend-description-spinner">
-          <i class="spinner"></i>
-        </div>{{/if}}
-    </div>
-  {{/unless}}
-{{/unless}}
-
-
-{{#if params}}
-  <h3 class="coding-rules-detail-title">{{t 'coding_rules.parameters'}}</h3>
-  <div class="coding-rules-detail-parameters">
-    {{#each params}}
-      <dl class="coding-rules-detail-parameter">
-        <dt class="coding-rules-detail-parameter-name">{{key}}</dt>
-        <dd class="coding-rules-detail-parameter-description" data-key="{{key}}">
-          <p>{{{htmlDesc}}}</p>
-          {{#if ../../templateKey}}
-            <div class="subtitle">
-              {{#if defaultValue }}
-                <span class="value">{{defaultValue}}</span>
-              {{else}}
-                {{t 'coding_rules.parameter.empty'}}
-              {{/if}}
-            </div>
-          {{else}}
-            {{#if defaultValue}}
-              <div class="subtitle">{{t 'coding_rules.parameters.default_value'}} <span class="value">{{defaultValue}}</span></div>
-            {{/if}}
-          {{/if}}
-        </dd>
-      </dl>
-    {{/each}}
-  </div>
-{{/if}}
+<div class="js-rule-meta"></div>
+<div class="js-rule-description"></div>
+<div class="js-rule-parameters"></div>
 
 {{#if isEditable}}
   <div class="coding-rules-detail-description">
   </div>
 {{/if}}
 
-
 {{#if isTemplate}}
   <div class="coding-rules-detail-custom-rules-section">
     <h3 class="coding-rules-detail-title">{{t 'coding_rules.custom_rules'}}</h3>
 
-    {{#if canWrite}}<div class="button-group coding-rules-detail-quality-profiles-activation">
-      <button id="coding-rules-custom-rules-create">{{t 'coding_rules.create'}}</button>
-    </div>{{/if}}
+    {{#if canWrite}}
+      <div class="button-group coding-rules-detail-quality-profiles-activation">
+        <button id="coding-rules-custom-rules-create">{{t 'coding_rules.create'}}</button>
+      </div>
+    {{/if}}
     <div id="coding-rules-detail-custom-rules"></div>
   </div>
 {{/if}}
 
-
-{{#if qualityProfilesVisible}}
-  <div class="coding-rules-detail-quality-profiles-section">
-    <h3 class="coding-rules-detail-title">{{t 'coding_rules.quality_profiles'}}</h3>
-
-    {{#if canWrite}}{{#unless isTemplate}}<div class="button-group coding-rules-detail-quality-profiles-activation">
-      <button id="coding-rules-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
-    </div>{{/unless}}{{/if}}
-    {{#if isTemplate}}
-      <div class="coding-rules-detail-quality-profiles-template-caption warning">{{t 'coding_rules.quality_profiles.template_caption'}}</div>
-    {{/if}}
-    <div id="coding-rules-detail-quality-profiles"></div>
-  </div>
-{{/if}}
+<div class="js-rule-profiles"></div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-profile-activation.hbs b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-profile-activation.hbs
new file mode 100644 (file)
index 0000000..dc3374d
--- /dev/null
@@ -0,0 +1,76 @@
+<form>
+  <div class="modal-head">
+    {{#if change}}
+      <h2>{{t 'coding_rules.change_details'}}</h2>
+    {{else}}
+      <h2>{{t 'coding_rules.activate_in_quality_profile'}}</h2>
+    {{/if}}
+  </div>
+
+  <div class="modal-body modal-body-select2">
+    <div class="modal-error"></div>
+
+    <table>
+      <tr class="property">
+        <th><h3>{{t 'coding_rules.quality_profile'}}</h3></th>
+        <td>
+          {{#if key}}
+            {{name}}
+          {{else}}
+            <select id="coding-rules-quality-profile-activation-select">
+              {{#each qualityProfiles}}
+                <option value="{{key}}">{{name}}</option>
+              {{/each}}
+            </select>
+          {{/if}}
+        </td>
+      </tr>
+      <tr class="property">
+        <th><h3>{{t 'severity'}}</h3></th>
+        <td>
+          <select id="coding-rules-quality-profile-activation-severity">
+            {{#each severities}}
+              <option value="{{this}}">{{t 'severity' this}}</option>
+            {{/each}}
+          </select>
+        </td>
+      </tr>
+      {{#if isCustomRule}}
+      <tr class="property">
+        <td colspan="2" class="note">{{t 'coding_rules.custom_rule.activation_notice'}}</td>
+      {{else}}
+      {{#each params}}
+        <tr class="property">
+          <th><h3>{{key}}</h3></th>
+          <td>
+            {{#eq type 'TEXT'}}
+              <textarea class="width100" rows="3" name="{{key}}" placeholder="{{defaultValue}}">{{value}}</textarea>
+            {{else}}
+              {{#eq type 'BOOLEAN'}}
+              <select name="{{key}}" value="{{value}}">
+                <option value="{{defaultValue}}">{{t 'default'}} ({{t defaultValue}})</option>
+                <option value="true"{{#eq value 'true'}} selected="selected"{{/eq}}>{{t 'true'}}</option>
+                <option value="false"{{#eq value 'false'}} selected="selected"{{/eq}}>{{t 'false'}}</option>
+              </select>
+              {{else}}
+              <input type="text" name="{{key}}" value="{{value}}" placeholder="{{defaultValue}}">
+              {{/eq}}
+            {{/eq}}
+            <div class="note">{{description}}</div>
+            {{#if extra}}
+              <div class="note">{{extra}}</div>
+            {{/if}}
+          </td>
+        </tr>
+      {{/each}}
+      {{/if}}
+    </table>
+  </div>
+
+  <div class="modal-foot">
+    <button id="coding-rules-quality-profile-activation-activate" {{#unless saveEnabled}}disabled="disabled"{{/unless}}>
+      {{#if change}}{{t 'save'}}{{else}}{{t 'coding_rules.activate'}}{{/if}}
+    </button>
+    <a id="coding-rules-quality-profile-activation-cancel" class="js-modal-close">{{t 'cancel'}}</a>
+  </div>
+</form>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-description.hbs b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-description.hbs
new file mode 100644 (file)
index 0000000..69a31cb
--- /dev/null
@@ -0,0 +1,48 @@
+<div class="coding-rules-detail-description rule-desc markdown">{{{htmlDesc}}}</div>
+
+{{#unless isEditable}}
+  {{#unless isManual}}
+    <div class="coding-rules-detail-description coding-rules-detail-description-extra">
+      <div id="coding-rules-detail-description-extra">
+        {{#if htmlNote}}
+          <div class="rule-desc marginbottom10 markdown">{{{htmlNote}}}</div>
+        {{/if}}
+        {{#if canWrite}}
+          <div class="button-group">
+            <button id="coding-rules-detail-extend-description">{{t 'coding_rules.extend_description'}}</button>
+          </div>
+        {{/if}}
+      </div>
+
+      {{#if canWrite}}
+        <div class="coding-rules-detail-extend-description-form hidden">
+          <table class="width100">
+            <tbody>
+            <tr>
+              <td class="width100" colspan="2">
+                <textarea id="coding-rules-detail-extend-description-text" rows="4"
+                          style="width: 100%; margin-bottom: 4px;">{{mdNote}}</textarea>
+              </td>
+            </tr>
+            <tr>
+              <td>
+                <div class="button-group">
+                  <button id="coding-rules-detail-extend-description-submit">{{t 'save'}}</button>
+                  {{#if mdNote}}
+                    <button id="coding-rules-detail-extend-description-remove"
+                            class="button-red">{{t 'remove'}}</button>
+                  {{/if}}
+                </div>
+                <a id="coding-rules-detail-extend-description-cancel" class="action">{{t 'cancel'}}</a>
+              </td>
+              <td class="right">
+                {{> '_markdown-tips' }}
+              </td>
+            </tr>
+            </tbody>
+          </table>
+        </div>
+      {{/if}}
+    </div>
+  {{/unless}}
+{{/unless}}
diff --git a/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-meta.hbs b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-meta.hbs
new file mode 100644 (file)
index 0000000..829003f
--- /dev/null
@@ -0,0 +1,54 @@
+<h3 class="coding-rules-detail-header">
+  {{name}}
+  <a class="coding-rules-detail-permalink icon-link" target="_blank" href="#rule_key={{key}}"></a>
+</h3>
+
+<span class="subtitle">{{key}}</span>
+
+<ul class="coding-rules-detail-properties">
+  {{#unless isManual}}
+    <li class="coding-rules-detail-property">{{severityIcon severity}}&nbsp;{{t "severity" severity}}</li>
+  {{/unless}}
+
+  {{#notEq status 'READY'}}
+    <li class="coding-rules-detail-property">{{status}}</li>
+  {{/notEq}}
+
+  <li class="coding-rules-detail-property coding-rules-detail-tag-list {{#if canWrite}}coding-rules-detail-tags-change{{/if}}">
+    <i class="icon-tags"></i>
+    <span>{{#if allTags}}{{join allTags ', '}}{{else}}{{t 'coding_rules.no_tags'}}{{/if}}</span>
+  </li>
+
+  {{#if canWrite}}
+    <li class="coding-rules-detail-property coding-rules-detail-tag-edit hidden">
+      {{#if sysTags}}<i class="icon-tags"></i>
+        <span>{{join sysTags ', '}}</span>{{/if}}
+      <input class="coding-rules-detail-tag-input" type="text" value="{{#if tags}}{{join tags ','}}{{/if}}">
+
+      <div class="button-group">
+        <button class="coding-rules-detail-tag-edit-done">{{t 'Done'}}</button>
+      </div>
+      <a class="coding-rules-details-tag-edit-cancel">{{t 'cancel'}}</a>
+    </li>
+  {{/if}}
+
+  {{#if subCharacteristic}}
+    <li class="coding-rules-detail-property coding-rules-subcharacteristic">{{subCharacteristic}}</li>
+  {{/if}}
+
+  <li class="coding-rules-detail-property">{{t 'coding_rules.available_since'}} {{d createdAt}}</li>
+
+  <li class="coding-rules-detail-property">{{default repo.name repo}}{{#unless isManual}} ({{langName}}){{/unless}}</li>
+
+  {{#if isTemplate}}
+    <li class="coding-rules-detail-property"
+        title="{{t 'coding_rules.rule_template.title'}}">{{t 'coding_rules.rule_template'}}</li>
+  {{/if}}
+
+  {{#if templateKey}}
+    <li class="coding-rules-detail-property"
+        title="{{t 'coding_rules.custom_rule.title'}}">{{t 'coding_rules.custom_rule'}}
+      (<a href="#rule_key={{templateKey}}">{{t 'coding_rules.show_template'}}</a>)
+    </li>
+  {{/if}}
+</ul>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-parameters.hbs b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-parameters.hbs
new file mode 100644 (file)
index 0000000..f0dcb3d
--- /dev/null
@@ -0,0 +1,25 @@
+<h3 class="coding-rules-detail-title">{{t 'coding_rules.parameters'}}</h3>
+<table class="coding-rules-detail-parameters">
+  {{#each params}}
+    <tr class="coding-rules-detail-parameter">
+      <td class="coding-rules-detail-parameter-name">{{key}}</td>
+      <td class="coding-rules-detail-parameter-description" data-key="{{key}}">
+        <p>{{{htmlDesc}}}</p>
+        {{#if ../../templateKey}}
+          <div class="subtitle">
+            {{#if defaultValue }}
+              <span class="value">{{defaultValue}}</span>
+            {{else}}
+              {{t 'coding_rules.parameter.empty'}}
+            {{/if}}
+          </div>
+        {{else}}
+          {{#if defaultValue}}
+            <div class="subtitle">{{t 'coding_rules.parameters.default_value'}} <span
+                class="value">{{defaultValue}}</span></div>
+          {{/if}}
+        {{/if}}
+      </td>
+    </tr>
+  {{/each}}
+</table>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-profile.hbs b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-profile.hbs
new file mode 100644 (file)
index 0000000..99f6f5f
--- /dev/null
@@ -0,0 +1,72 @@
+<td class="coding-rules-detail-quality-profile-name">
+  {{name}}
+  {{#if parent}}
+    <div class="coding-rules-detail-quality-profile-inheritance">
+      {{#eq inherit 'OVERRIDES'}}
+        <i class="icon-inheritance" title="{{tp 'coding_rules.overrides' name parent.name}}"></i>
+      {{/eq}}
+      {{#eq inherit 'INHERITED'}}
+        <i class="icon-inheritance" title="{{tp 'coding_rules.inherits' name parent.name}}"></i>
+      {{/eq}}
+      {{parent.name}}
+    </div>
+  {{/if}}
+</td>
+
+{{#if severity}}
+  <td class="coding-rules-detail-quality-profile-severity">
+    {{severityIcon severity}} {{t "severity" severity}}
+    {{#if parent}}{{#notEq severity parent.severity}}
+      <div class="coding-rules-detail-quality-profile-inheritance">
+        {{t 'coding_rules.original'}}&nbsp;{{t 'severity' parent.severity}}
+      </div>
+    {{/notEq}}{{/if}}
+  </td>
+
+  {{#unless templateKey}}
+    <td class="coding-rules-detail-quality-profile-parameters">
+      {{#each parameters}}
+        <div class="coding-rules-detail-quality-profile-parameter">
+          <span class="key">{{key}}</span><span class="sep">:&nbsp;</span><span class="value"
+                                                                                title="{{value}}">{{value}}</span>
+          {{#if ../parent}}{{#notEq value original}}
+            <div class="coding-rules-detail-quality-profile-inheritance">
+              {{t 'coding_rules.original'}}&nbsp;<span class="value">{{original}}</span>
+            </div>
+          {{/notEq}}{{/if}}
+        </div>
+      {{/each}}
+      &nbsp;
+    </td>
+  {{/unless}}
+
+  {{#if canWrite}}
+    <td class="coding-rules-detail-quality-profile-actions">
+      <div class="button-group">
+        {{#unless isTemplate}}
+          <button class="coding-rules-detail-quality-profile-change">{{t 'change_verb'}}</button>
+        {{/unless}}
+        {{#if parent}}
+          {{#eq inherit 'OVERRIDES'}}
+            <button class="coding-rules-detail-quality-profile-revert button-red">
+              {{t 'coding_rules.revert_to_parent_definition'}}
+            </button>
+          {{/eq}}
+        {{else}}
+          <button class="coding-rules-detail-quality-profile-deactivate button-red">
+            {{t 'coding_rules.deactivate'}}
+          </button>
+        {{/if}}
+      </div>
+    </td>
+  {{/if}}
+
+{{else}}
+  {{#if canWrite}}{{#unless isTemplate}}
+    <td class="coding-rules-detail-quality-profile-actions">
+      <div class="button-group">
+        <button class="coding-rules-detail-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
+      </div>
+    </td>
+  {{/unless}}{{/if}}
+{{/if}}
diff --git a/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-profiles.hbs b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-profiles.hbs
new file mode 100644 (file)
index 0000000..629206a
--- /dev/null
@@ -0,0 +1,19 @@
+<div class="coding-rules-detail-quality-profiles-section">
+  <h3 class="coding-rules-detail-title">{{t 'coding_rules.quality_profiles'}}</h3>
+
+  {{#if canWrite}}
+    {{#unless isTemplate}}
+      <div class="button-group coding-rules-detail-quality-profiles-activation">
+        <button id="coding-rules-quality-profile-activate">{{t 'coding_rules.activate'}}</button>
+      </div>
+    {{/unless}}
+  {{/if}}
+
+  {{#if isTemplate}}
+    <div class="coding-rules-detail-quality-profiles-template-caption warning">
+      {{t 'coding_rules.quality_profiles.template_caption'}}
+    </div>
+  {{/if}}
+
+  <table id="coding-rules-detail-quality-profiles" class="coding-rules-detail-quality-profiles width100"></table>
+</div>
index 3eec23d697cb1c7d7aa8722eddc5a27e87a0965b..3d391182d7433094e73ae5efcdd43c7c19650d61 100644 (file)
@@ -39,6 +39,7 @@ define([
           that.app.list.add(rules);
         }
         that.app.list.setIndex();
+        that.app.list.addExtraAttributes(that.app.languages, that.app.repositories);
         that.app.facets.reset(that._allFacets());
         that.app.facets.add(r.facets, { merge: true });
         that.enableFacets(that._enabledFacets());
@@ -74,26 +75,30 @@ define([
     },
 
     getRuleDetails: function (rule) {
-      var url = baseUrl + '/api/rules/show',
+      var that = this,
+          url = baseUrl + '/api/rules/show',
           options = {
             key: rule.id,
             actives: true
           };
       return $.get(url, options).done(function (data) {
         rule.set(data.rule);
+        rule.addExtraAttributes(that.app.languages, that.app.repositories);
       });
     },
 
     showDetails: function (rule) {
-      var that = this;
+      var that = this,
+          ruleModel = typeof rule === 'string' ? new Backbone.Model({ key: rule }) : rule;
       this.app.layout.workspaceDetailsRegion.reset();
-      this.getRuleDetails(rule).done(function () {
+      this.getRuleDetails(ruleModel).done(function (data) {
         key.setScope('details');
         that.app.workspaceListView.unbindScrollEvents();
-        that.app.state.set({ rule: rule });
+        that.app.state.set({ rule: ruleModel });
         that.app.workspaceDetailsView = new RuleDetailsView({
           app: that.app,
-          model: rule
+          model: ruleModel,
+          actives: data.actives
         });
         that.app.layout.workspaceDetailsRegion.show(that.app.workspaceDetailsView);
         that.app.layout.showDetails();
index 78c1804a21d9874e386eb84f9d27fd743f6914a3..0b20c8eab0d633729ecd58b0440f1d9fa71b92a3 100644 (file)
@@ -3,7 +3,20 @@ define([
 ], function (Backbone) {
 
   return Backbone.Model.extend({
-    idAttribute: 'key'
+    idAttribute: 'key',
+
+    addExtraAttributes: function (languages, repositories) {
+      var langName = languages[this.get('lang')] || this.get('lang'),
+          repo = _.findWhere(repositories, { key: this.get('repo') }) || this.get('repo'),
+          isManual = this.get('repo') === 'manual',
+          isCustom = this.has('templateKey');
+      this.set({
+        langName: langName,
+        repo: repo,
+        isManual: isManual,
+        isCustom: isCustom
+      });
+    }
   });
 
 });
index ea0c3577a2d6b103c987a7b575fb0fc506f9a8f5..752576ee2f82ff2cb5fcb15d7c0863deaa906d1f 100644 (file)
@@ -14,6 +14,12 @@ define([
       this.forEach(function (rule, index) {
         rule.set({ index: index });
       });
+    },
+
+    addExtraAttributes: function (languages, repositories) {
+      this.models.forEach(function (model) {
+        model.addExtraAttributes(languages, repositories);
+      });
     }
   });
 
index 202e1698dfd95b76bbfab56a1b6b9c6a5808d86f..2fa6378a677d20a38dc39e0768952a09f9d3dd6b 100644 (file)
@@ -1,23 +1,62 @@
 define([
-    'backbone.marionette',
-    'templates/coding-rules'
-], function (Marionette, Templates) {
+  'backbone',
+  'backbone.marionette',
+  'templates/coding-rules',
+  'coding-rules/rule/rule-meta-view',
+  'coding-rules/rule/rule-description-view',
+  'coding-rules/rule/rule-parameters-view',
+  'coding-rules/rule/rule-profiles-view'
+], function (Backbone, Marionette, Templates, MetaView, DescView, ParamView, ProfilesView) {
 
-  return Marionette.ItemView.extend({
+  return Marionette.Layout.extend({
     template: Templates['coding-rules-rule-details'],
 
-    modelEvents: {
-      'change': 'render'
+    regions: {
+      metaRegion: '.js-rule-meta',
+      descRegion: '.js-rule-description',
+      paramRegion: '.js-rule-parameters',
+      profilesRegion: '.js-rule-profiles'
     },
 
     initialize: function () {
       this.bindShortcuts();
     },
 
+    onRender: function () {
+      this.metaRegion.show(new MetaView({
+        app: this.options.app,
+        model: this.model
+      }));
+      this.descRegion.show(new DescView({
+        app: this.options.app,
+        model: this.model
+      }));
+      this.paramRegion.show(new ParamView({
+        app: this.options.app,
+        model: this.model
+      }));
+      this.profilesRegion.show(new ProfilesView({
+        app: this.options.app,
+        model: this.model,
+        collection: new Backbone.Collection(this.getQualityProfiles())
+      }));
+    },
+
     onClose: function () {
       this.unbindShortcuts();
     },
 
+    getQualityProfiles: function () {
+      var that = this;
+      return this.options.actives.map(function (profile) {
+        var profileBase = _.findWhere(that.options.app.qualityProfiles, { key: profile.qProfile });
+        if (profileBase != null) {
+          _.extend(profile, profileBase);
+        }
+        return profile;
+      });
+    },
+
     bindShortcuts: function () {
       var that = this;
       key('up', 'details', function () {
@@ -41,12 +80,25 @@ define([
     },
 
     serializeData: function () {
-      var isManual = (this.options.app.manualRepository().key === this.model.get('repo'));
+      var isManual = (this.options.app.manualRepository().key === this.model.get('repo')),
+          isCustom = this.model.has('templateKey'),
+          isEditable = this.options.app.canWrite && (isManual || isCustom),
+          qualityProfilesVisible = !isManual;
+
+      if (qualityProfilesVisible) {
+        if (this.model.get('isTemplate')) {
+          qualityProfilesVisible = !_.isEmpty(this.options.actives);
+        }
+        else {
+          qualityProfilesVisible = (this.options.app.canWrite || !_.isEmpty(this.options.actives));
+        }
+      }
 
       return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
-        language: this.options.app.languages[this.model.get('lang')],
-        repository: _.findWhere(this.options.app.repositories, { key: this.model.get('repo') }).name,
         isManual: isManual,
+        isEditable: isEditable,
+        canWrite: this.options.app.canWrite,
+        qualityProfilesVisible: qualityProfilesVisible,
         subCharacteristic: this.options.app.getSubCharacteristicName(this.model.get('debtSubChar')),
         allTags: _.union(this.model.get('sysTags'), this.model.get('tags'))
       });
diff --git a/server/sonar-web/src/main/js/coding-rules/rule/profile-activation-view.js b/server/sonar-web/src/main/js/coding-rules/rule/profile-activation-view.js
new file mode 100644 (file)
index 0000000..3bd8855
--- /dev/null
@@ -0,0 +1,131 @@
+define([
+  'common/modals',
+  'templates/coding-rules'
+], function (Modal, Templates) {
+
+  var $ = jQuery;
+
+  return Modal.extend({
+    template: Templates['coding-rules-profile-activation'],
+
+    ui: {
+      qualityProfileSelect: '#coding-rules-quality-profile-activation-select',
+      qualityProfileSeverity: '#coding-rules-quality-profile-activation-severity',
+      qualityProfileActivate: '#coding-rules-quality-profile-activation-activate',
+      qualityProfileParameters: '[name]'
+    },
+
+    events: function () {
+      return _.extend(Modal.prototype.events.apply(this, arguments), {
+        'click @ui.qualityProfileActivate': 'activate'
+      });
+    },
+
+    onRender: function () {
+      Modal.prototype.onRender.apply(this, arguments);
+
+      this.ui.qualityProfileSelect.select2({
+        width: '250px',
+        minimumResultsForSearch: 5
+      });
+
+      var format = function (state) {
+            if (!state.id) {
+              return state.text;
+            } else {
+              return '<i class="icon-severity-' + state.id.toLowerCase() + '"></i> ' + state.text;
+            }
+          },
+          severity = (this.model && this.model.get('severity')) || this.options.rule.get('severity');
+      this.ui.qualityProfileSeverity.val(severity);
+      this.ui.qualityProfileSeverity.select2({
+        width: '250px',
+        minimumResultsForSearch: 999,
+        formatResult: format,
+        formatSelection: format
+      });
+    },
+
+    activate: function () {
+      var that = this,
+          p = window.process.addBackgroundProcess(),
+          profileKey = this.ui.qualityProfileSelect.val(),
+          params = this.ui.qualityProfileParameters.map(function () {
+            return {
+              key: $(this).prop('name'),
+              value: $(this).val() || $(this).prop('placeholder') || ''
+            };
+          }).get(),
+          paramsHash = (params.map(function (param) {
+            return param.key + '=' + window.csvEscape(param.value);
+          })).join(';');
+
+      if (this.model) {
+        profileKey = this.model.get('qProfile');
+        if (!profileKey) {
+          profileKey = this.model.get('key');
+        }
+      }
+
+      var severity = this.ui.qualityProfileSeverity.val(),
+          ruleKey = this.options.rule.get('key');
+
+      this.close();
+
+      return jQuery.ajax({
+        type: 'POST',
+        url: baseUrl + '/api/qualityprofiles/activate_rule',
+        data: {
+          profile_key: profileKey,
+          rule_key: ruleKey,
+          severity: severity,
+          params: paramsHash
+        }
+      }).done(function () {
+        that.options.app.controller.showDetails(that.options.rule);
+        window.process.finishBackgroundProcess(p);
+      }).fail(function () {
+        that.options.app.controller.showDetails(that.options.rule);
+        window.process.failBackgroundProcess(p);
+      });
+    },
+
+    getAvailableQualityProfiles: function (lang) {
+      var activeQualityProfiles = this.collection,
+          inactiveProfiles = _.reject(this.options.app.qualityProfiles, function (profile) {
+            return activeQualityProfiles.findWhere({ key: profile.key });
+          });
+      return _.filter(inactiveProfiles, function (profile) {
+        return profile.lang === lang;
+      });
+    },
+
+    serializeData: function () {
+      var params = this.options.rule.get('params');
+      if (this.model != null) {
+        var modelParams = this.model.get('params');
+        if (_.isArray(modelParams)) {
+          params = params.map(function (p) {
+            var parentParam = _.findWhere(modelParams, { key: p.key });
+            if (parentParam != null) {
+              _.extend(p, { value: parentParam.value });
+            }
+            return p;
+          });
+        }
+      }
+
+      var availableProfiles = this.getAvailableQualityProfiles(this.options.rule.get('lang'));
+
+      return _.extend(Modal.prototype.serializeData.apply(this, arguments), {
+        change: this.model && this.model.has('severity'),
+        params: params,
+        qualityProfiles: availableProfiles,
+        severities: ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO'],
+        saveEnabled: !_.isEmpty(availableProfiles) || (this.model && this.model.get('qProfile')),
+        isCustomRule: (this.model && this.model.has('templateKey')) || this.options.rule.has('templateKey')
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/rule/rule-description-view.js b/server/sonar-web/src/main/js/coding-rules/rule/rule-description-view.js
new file mode 100644 (file)
index 0000000..dfbe5e1
--- /dev/null
@@ -0,0 +1,87 @@
+define([
+  'backbone.marionette',
+  'templates/coding-rules'
+], function (Marionette, Templates) {
+
+  return Marionette.ItemView.extend({
+    template: Templates['coding-rules-rule-description'],
+
+    modelEvents: {
+      'change': 'render'
+    },
+
+    ui: {
+      descriptionExtra: '#coding-rules-detail-description-extra',
+      extendDescriptionLink: '#coding-rules-detail-extend-description',
+      extendDescriptionForm: '.coding-rules-detail-extend-description-form',
+      extendDescriptionSubmit: '#coding-rules-detail-extend-description-submit',
+      extendDescriptionRemove: '#coding-rules-detail-extend-description-remove',
+      extendDescriptionText: '#coding-rules-detail-extend-description-text',
+      cancelExtendDescription: '#coding-rules-detail-extend-description-cancel'
+    },
+
+    events: {
+      'click @ui.extendDescriptionLink': 'showExtendDescriptionForm',
+      'click @ui.cancelExtendDescription': 'hideExtendDescriptionForm',
+      'click @ui.extendDescriptionSubmit': 'submitExtendDescription',
+      'click @ui.extendDescriptionRemove': 'removeExtendedDescription'
+    },
+
+    showExtendDescriptionForm: function () {
+      this.ui.descriptionExtra.addClass('hidden');
+      this.ui.extendDescriptionForm.removeClass('hidden');
+      this.ui.extendDescriptionText.focus();
+    },
+
+    hideExtendDescriptionForm: function () {
+      this.ui.descriptionExtra.removeClass('hidden');
+      this.ui.extendDescriptionForm.addClass('hidden');
+    },
+
+    submitExtendDescription: function () {
+      var that = this,
+          p = window.process.addBackgroundProcess();
+      this.ui.extendDescriptionForm.addClass('hidden');
+      return jQuery.ajax({
+        type: 'POST',
+        url: baseUrl + '/api/rules/update',
+        dataType: 'json',
+        data: {
+          key: this.model.get('key'),
+          markdown_note: this.ui.extendDescriptionText.val()
+        }
+      }).done(function (r) {
+        that.model.set({
+          htmlNote: r.rule.htmlNote,
+          mdNote: r.rule.mdNote
+        });
+        that.render();
+        window.process.finishBackgroundProcess(p);
+      }).fail(function () {
+        that.render();
+        window.process.failBackgroundProcess(p);
+      });
+    },
+
+    removeExtendedDescription: function () {
+      var that = this;
+      window.confirmDialog({
+        html: t('coding_rules.remove_extended_description.confirm'),
+        yesHandler: function () {
+          that.ui.extendDescriptionText.val('');
+          that.submitExtendDescription();
+        }
+      });
+    },
+
+    serializeData: function () {
+      var isEditable = this.options.app.canWrite && (this.model.get('isManual') || this.model.get('isCustom'));
+
+      return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+        isEditable: isEditable,
+        canWrite: this.options.app.canWrite
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/rule/rule-meta-view.js b/server/sonar-web/src/main/js/coding-rules/rule/rule-meta-view.js
new file mode 100644 (file)
index 0000000..6f3c3c3
--- /dev/null
@@ -0,0 +1,86 @@
+define([
+  'backbone.marionette',
+  'templates/coding-rules'
+], function (Marionette, Templates) {
+
+  return Marionette.ItemView.extend({
+    template: Templates['coding-rules-rule-meta'],
+
+    modelEvents: {
+      'change': 'render'
+    },
+
+    ui: {
+      tagsChange: '.coding-rules-detail-tags-change',
+      tagInput: '.coding-rules-detail-tag-input',
+      tagsEdit: '.coding-rules-detail-tag-edit',
+      tagsEditDone: '.coding-rules-detail-tag-edit-done',
+      tagsEditCancel: '.coding-rules-details-tag-edit-cancel',
+      tagsList: '.coding-rules-detail-tag-list'
+    },
+
+    events: {
+      'click @ui.tagsChange': 'changeTags',
+      'click @ui.tagsEditDone': 'editDone',
+      'click @ui.tagsEditCancel': 'cancelEdit'
+    },
+
+    requestTags: function () {
+      var url = baseUrl + '/api/rules/tags';
+      return jQuery.get(url);
+    },
+
+    changeTags: function () {
+      var that = this;
+      this.requestTags().done(function (r) {
+        that.ui.tagInput.select2({
+          tags: _.difference(_.difference(r.tags, that.model.get('tags')), that.model.get('sysTags')),
+          width: '300px'
+        });
+
+        that.ui.tagsEdit.removeClass('hidden');
+        that.ui.tagsList.addClass('hidden');
+        that.tagsBuffer = that.ui.tagInput.select2('val');
+      });
+    },
+
+    cancelEdit: function () {
+      this.ui.tagsList.removeClass('hidden');
+      this.ui.tagsEdit.addClass('hidden');
+      if (this.ui.tagInput.select2) {
+        this.ui.tagInput.select2('val', this.tagsBuffer);
+        this.ui.tagInput.select2('close');
+      }
+    },
+
+    editDone: function () {
+      var that = this,
+          p = window.process.addBackgroundProcess(),
+          tags = this.ui.tagInput.val();
+      return jQuery.ajax({
+        type: 'POST',
+        url: baseUrl + '/api/rules/update',
+        data: {
+          key: this.model.get('key'),
+          tags: tags
+        }
+      }).done(function (r) {
+        that.model.set('tags', r.rule.tags);
+        that.cancelEdit();
+        window.process.finishBackgroundProcess(p);
+      }).always(function () {
+        that.cancelEdit();
+        window.process.failBackgroundProcess(p);
+      });
+    },
+
+    serializeData: function () {
+      return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+        canWrite: this.options.app.canWrite,
+        subCharacteristic: this.options.app.getSubCharacteristicName(this.model.get('debtSubChar')),
+        allTags: _.union(this.model.get('sysTags'), this.model.get('tags'))
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/rule/rule-parameters-view.js b/server/sonar-web/src/main/js/coding-rules/rule/rule-parameters-view.js
new file mode 100644 (file)
index 0000000..f257246
--- /dev/null
@@ -0,0 +1,27 @@
+define([
+    'backbone.marionette',
+    'templates/coding-rules'
+], function (Marionette, Templates) {
+
+  return Marionette.ItemView.extend({
+    template: Templates['coding-rules-rule-parameters'],
+
+    modelEvents: {
+      'change': 'render'
+    },
+
+    onRender: function () {
+      this.$el.toggleClass('hidden', _.isEmpty(this.model.get('params')));
+    },
+
+    serializeData: function () {
+      var isEditable = this.options.app.canWrite && (this.model.get('isManual') || this.model.get('isCustom'));
+
+      return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+        isEditable: isEditable,
+        canWrite: this.options.app.canWrite
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/rule/rule-profile-view.js b/server/sonar-web/src/main/js/coding-rules/rule/rule-profile-view.js
new file mode 100644 (file)
index 0000000..6e90f6f
--- /dev/null
@@ -0,0 +1,135 @@
+define([
+  'backbone.marionette',
+  'templates/coding-rules',
+  'coding-rules/rule/profile-activation-view'
+], function (Marionette, Templates, ProfileActivationView) {
+
+  return Marionette.ItemView.extend({
+    tagName: 'tr',
+    template: Templates['coding-rules-rule-profile'],
+
+    modelEvents: {
+      'change': 'render'
+    },
+
+    ui: {
+      change: '.coding-rules-detail-quality-profile-change',
+      revert: '.coding-rules-detail-quality-profile-revert',
+      deactivate: '.coding-rules-detail-quality-profile-deactivate'
+    },
+
+    events: {
+      'click @ui.change': 'change',
+      'click @ui.revert': 'revert',
+      'click @ui.deactivate': 'deactivate'
+    },
+
+    change: function () {
+      new ProfileActivationView({
+        model: this.model,
+        collection: this.model.collection,
+        rule: this.options.rule,
+        app: this.options.app
+      }).render();
+    },
+
+    revert: function () {
+      var that = this,
+          ruleKey = this.options.rule.get('key');
+      window.confirmDialog({
+        title: t('coding_rules.revert_to_parent_definition'),
+        html: tp('coding_rules.revert_to_parent_definition.confirm', this.getParent().name),
+        yesHandler: function () {
+          var p = window.process.addBackgroundProcess();
+          return jQuery.ajax({
+            type: 'POST',
+            url: baseUrl + '/api/qualityprofiles/activate_rule',
+            data: {
+              profile_key: that.model.get('qProfile'),
+              rule_key: ruleKey,
+              reset: true
+            }
+          }).done(function () {
+            window.process.finishBackgroundProcess(p);
+            that.options.app.controller.showDetails(that.options.rule);
+          });
+        }
+      });
+    },
+
+    deactivate: function () {
+      var that = this,
+          ruleKey = this.options.rule.get('key'),
+          myProfile = _.findWhere(this.options.app.qualityProfiles, {
+            key: this.model.get('qProfile')
+          });
+      window.confirmDialog({
+        title: t('coding_rules.deactivate'),
+        html: tp('coding_rules.deactivate.confirm', myProfile.name),
+        yesHandler: function () {
+          var p = window.process.addBackgroundProcess();
+          return jQuery.ajax({
+            type: 'POST',
+            url: baseUrl + '/api/qualityprofiles/deactivate_rule',
+            data: {
+              profile_key: that.model.get('qProfile'),
+              rule_key: ruleKey
+            }
+          }).done(function () {
+            window.process.finishBackgroundProcess(p);
+            that.options.app.controller.showDetails(that.options.rule);
+          });
+        }
+      });
+    },
+
+    enableUpdate: function () {
+      return this.ui.update.prop('disabled', false);
+    },
+
+    getParent: function () {
+      if (!(this.model.get('inherit') && this.model.get('inherit') !== 'NONE')) {
+        return null;
+      }
+      var myProfile = _.findWhere(this.options.app.qualityProfiles, {
+            key: this.model.get('qProfile')
+          }),
+          parentKey = myProfile.parentKey,
+          parent = _.extend({}, _.findWhere(this.options.app.qualityProfiles, {
+            key: parentKey
+          })),
+          parentActiveInfo = this.model.collection.findWhere({ qProfile: parentKey }) || new Backbone.Model();
+      _.extend(parent, parentActiveInfo.toJSON());
+      return parent;
+    },
+
+    enhanceParameters: function () {
+      var parent = this.getParent(),
+          params = _.sortBy(this.model.get('params'), 'key');
+      if (!parent) {
+        return params;
+      }
+      return params.map(function (p) {
+        var parentParam = _.findWhere(parent.params, { key: p.key });
+        if (parentParam != null) {
+          return _.extend(p, {
+            original: _.findWhere(parent.params, { key: p.key }).value
+          });
+        } else {
+          return p;
+        }
+      });
+    },
+
+    serializeData: function () {
+      return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+        canWrite: this.options.app.canWrite,
+        parent: this.getParent(),
+        parameters: this.enhanceParameters(),
+        templateKey: this.options.rule.get('templateKey'),
+        isTemplate: this.options.rule.get('isTemplate')
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/rule/rule-profiles-view.js b/server/sonar-web/src/main/js/coding-rules/rule/rule-profiles-view.js
new file mode 100644 (file)
index 0000000..b9e3655
--- /dev/null
@@ -0,0 +1,43 @@
+define([
+  'backbone.marionette',
+  'templates/coding-rules',
+  'coding-rules/rule/rule-profile-view',
+  'coding-rules/rule/profile-activation-view'
+], function (Marionette, Templates, ProfileView, ProfileActivationView) {
+
+  return Marionette.CompositeView.extend({
+    template: Templates['coding-rules-rule-profiles'],
+    itemView: ProfileView,
+    itemViewContainer: '#coding-rules-detail-quality-profiles',
+
+    itemViewOptions: function () {
+      return {
+        app: this.options.app,
+        rule: this.model
+      };
+    },
+
+    modelEvents: {
+      'change': 'render'
+    },
+
+    events: {
+      'click #coding-rules-quality-profile-activate': 'activate'
+    },
+
+    activate: function () {
+      new ProfileActivationView({
+        rule: this.model,
+        collection: this.collection,
+        app: this.options.app
+      }).render();
+    },
+
+    serializeData: function () {
+      return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+        canWrite: this.options.app.canWrite
+      });
+    }
+  });
+
+});
index f8bd0a43811811c6e24e2a64c3a80fabdab5eec1..86badc92f7affb894ebd2a792e172d7267a2509d 100644 (file)
 .coding-rules-detail-header,
 .coding-rules-detail-title {
   position: relative;
-  margin-bottom: @navigatorPadding;
+  margin: 1em 0;
   line-height: 1.5;
-  font-weight: bold;
+  font-size: @bigFontSize;
+  font-weight: 400;
 }
 
 .coding-rules-detail-header {
@@ -70,8 +71,7 @@
 
 .coding-rules-detail-title {
   display: inline-block;
-  margin-top: 3 * @navigatorPadding;
-  text-transform: uppercase;
+  margin-top: 2em;
 }
 
 .coding-rules-detail-permalink {
 }
 
 .coding-rules-detail-parameters {
+  width: 100%;
   margin: @navigatorPadding 0 @navigatorPadding * 2;
 }
 
 .coding-rules-detail-parameter {
-  margin: @navigatorPadding 0;
+
 }
 
 .coding-rules-detail-parameter-name {
-  display: block;
-  margin-left: 2 * @navigatorPadding;
+  width: 1px;
+  vertical-align: top;
+  padding: 5px 10px 5px 0;
   font-weight: bold;
-  cursor: pointer;
 }
 
 .coding-rules-detail-parameter-description {
-  display: inline-block;
-  text-overflow: ellipsis;
   vertical-align: top;
-  max-width: 75%;
-  margin-left: 2 * @navigatorPadding;
-  padding: @navigatorPadding;
-  .box-sizing(border-box);
+  padding: 5px 5px;
 
   .subtitle {
     margin-top: @navigatorPadding;
 }
 
 .coding-rules-detail-quality-profiles {
-  font-size: 0;
-}
+  line-height: 22px;
 
-.coding-rules-detail-quality-profile {
-  margin-left: 2 * @navigatorPadding;
-}
+  td {
+    border-top: 1px solid @barBorderColor;
+  }
 
-.coding-rules-detail-quality-profile + .coding-rules-detail-quality-profile {
-  margin-top: @navigatorPadding;
-  padding-top: @navigatorPadding;
-  border-top: 1px solid @navigatorBorderLightColor;
+  tr:first-child td {
+    border-top: none;
+  }
 }
 
 .coding-rules-detail-quality-profile-name {
   vertical-align: top;
-  width: 15%;
+  width: 1px;
+  padding: 8px 5px 8px 0;
   font-weight: bold;
   white-space: nowrap;
-  padding-right: 5px;
 }
 
 .coding-rules-detail-quality-profile-severity {
   vertical-align: top;
-  width: 10%;
+  width: 1px;
+  padding: 8px 5px;
+  white-space: nowrap;
 }
 
 .coding-rules-detail-quality-profile-parameters {
   vertical-align: top;
-}
-
-.coding-rules-detail-quality-profile-parameter + .coding-rules-detail-quality-profile-parameter {
-  margin-top: 8px;
+  padding: 8px 5px;
 }
 
 .coding-rules-detail-quality-profile-actions {
   vertical-align: top;
-  width: 25%;
+  width: 1px;
+  padding: 8px 0 8px 5px;
   text-align: right;
+  white-space: nowrap;
 }
 
 .coding-rules-detail-quality-profile-inheritance {
index 9705916285223ff1998e6d45e8f0c4ecffdbbb53..6581e6691c66e1ea1de15ffb861880a8eba3f113 100644 (file)
@@ -1,6 +1,6 @@
 .modal {
   position: fixed;
-  z-index: 9100;
+  z-index: 9000;
   top: 15%;
   left: 50%;
   margin-left: -270px;
@@ -10,7 +10,7 @@
 
 .modal-overlay {
   position: fixed;
-  z-index: 9099;
+  z-index: 8999;
   top: 0; bottom: 0; left: 0; right: 0;
   background-color: rgba(0, 0, 0, 0.5);
 }