]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5820 Display the list of custom rules created from a template rule
authorStas Vilchik <vilchiks@gmail.com>
Fri, 26 Dec 2014 12:19:21 +0000 (13:19 +0100)
committerStas Vilchik <vilchiks@gmail.com>
Fri, 26 Dec 2014 12:38:55 +0000 (13:38 +0100)
18 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-custom-rule.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-custom-rules.hbs [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/rule-details-view.js
server/sonar-web/src/main/js/coding-rules/rule/custom-rule-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/rule/custom-rules-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/coding-rules/rule/rule-profiles-view.js
server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules.js [new file with mode: 0644]
server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/app.json [new file with mode: 0644]
server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/search-custom-rules.json [new file with mode: 0644]
server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/search.json [new file with mode: 0644]
server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/show.json [new file with mode: 0644]
server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules.js [new file with mode: 0644]
server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/app.json [new file with mode: 0644]
server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/search-custom-rules.json [new file with mode: 0644]
server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/search.json [new file with mode: 0644]
server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/show.json [new file with mode: 0644]
server/sonar-web/src/main/less/coding-rules.less

index 4414fd197d8b038722f6141eb6dccf6a5962447a..91acf126305bdbadd2d7b1d798320fbcf20e1e96 100644 (file)
   </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}}
-    <div id="coding-rules-detail-custom-rules"></div>
-  </div>
-{{/if}}
-
+<div class="js-rule-custom-rules"></div>
 <div class="js-rule-profiles"></div>
diff --git a/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-custom-rule.hbs b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-custom-rule.hbs
new file mode 100644 (file)
index 0000000..4d8f07e
--- /dev/null
@@ -0,0 +1,26 @@
+<td class="coding-rules-detail-list-name">
+  <a target="_blank" href="{{permalink}}">{{name}}</a>
+</td>
+
+<td class="coding-rules-detail-list-severity">
+  {{severityIcon severity}}&nbsp;{{t "severity" severity}}
+</td>
+
+<td class="coding-rules-detail-list-parameters">
+  {{#each parameters}}
+    <div class="coding-rules-detail-list-parameter">
+      <span class="key">{{key}}</span><span class="sep">:&nbsp;</span><span class="value" title="{{value}}">{{value}}</span>
+    </div>
+  {{/each}}
+  &nbsp;
+</td>
+
+{{#if canWrite}}
+<td class="coding-rules-detail-list-actions">
+  <div class="button-group">
+    <button class="js-delete-custom-rule button-red">
+      {{t 'delete'}}
+    </button>
+  </div>
+</td>
+{{/if}}
diff --git a/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-custom-rules.hbs b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-custom-rules.hbs
new file mode 100644 (file)
index 0000000..f2a2cc9
--- /dev/null
@@ -0,0 +1,10 @@
+<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}}
+  <table id="coding-rules-detail-custom-rules" class="coding-rules-detail-list"></table>
+</div>
index 051413e679fc6ffb17a9a009706cf6098cc63382..627d3165311af5ce72233404685a89a82c54dac9 100644 (file)
@@ -2,11 +2,15 @@ define([
   'backbone',
   'backbone.marionette',
   'templates/coding-rules',
+  'coding-rules/models/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) {
+  'coding-rules/rule/rule-profiles-view',
+  'coding-rules/rule/custom-rules-view'
+], function (Backbone, Marionette, Templates, Rules, MetaView, DescView, ParamView, ProfilesView, CustomRulesView) {
+
+  var $ = jQuery;
 
   return Marionette.Layout.extend({
     className: 'coding-rule-details',
@@ -16,11 +20,16 @@ define([
       metaRegion: '.js-rule-meta',
       descRegion: '.js-rule-description',
       paramRegion: '.js-rule-parameters',
-      profilesRegion: '.js-rule-profiles'
+      profilesRegion: '.js-rule-profiles',
+      customRulesRegion: '.js-rule-custom-rules'
     },
 
     initialize: function () {
       this.bindShortcuts();
+      this.customRules = new Rules();
+      if (this.model.get('isTemplate')) {
+        this.fetchCustomRules();
+      }
     },
 
     onRender: function () {
@@ -41,6 +50,11 @@ define([
         model: this.model,
         collection: new Backbone.Collection(this.getQualityProfiles())
       }));
+      this.customRulesRegion.show(new CustomRulesView({
+        app: this.options.app,
+        model: this.model,
+        collection: this.customRules
+      }));
       this.$el.scrollParent().scrollTop(30);
     },
 
@@ -48,6 +62,18 @@ define([
       this.unbindShortcuts();
     },
 
+    fetchCustomRules: function () {
+      var that = this,
+          url = baseUrl + '/api/rules/search',
+          options = {
+            template_key: this.model.get('key'),
+            f: 'name,severity,params'
+          };
+      return $.get(url, options).done(function (data) {
+        that.customRules.reset(data.rules);
+      });
+    },
+
     getQualityProfiles: function () {
       var that = this;
       return this.options.actives.map(function (profile) {
diff --git a/server/sonar-web/src/main/js/coding-rules/rule/custom-rule-view.js b/server/sonar-web/src/main/js/coding-rules/rule/custom-rule-view.js
new file mode 100644 (file)
index 0000000..cb96f91
--- /dev/null
@@ -0,0 +1,49 @@
+define([
+  'backbone.marionette',
+  'templates/coding-rules'
+], function (Marionette, Templates) {
+
+  var $ = jQuery;
+
+  return Marionette.ItemView.extend({
+    tagName: 'tr',
+    template: Templates['coding-rules-custom-rule'],
+
+    modelEvents: {
+      'change': 'render'
+    },
+
+    events: {
+      'click .js-delete-custom-rule': 'deleteRule'
+    },
+
+    deleteRule: function () {
+      var that = this;
+      window.confirmDialog({
+        title: t('delete'),
+        html: t('are_you_sure'),
+        yesHandler: function () {
+          var p = window.process.addBackgroundProcess(),
+              url = baseUrl + '/api/rules/delete',
+              options = { key: that.model.id };
+          $.post(url, options).done(function () {
+            that.model.collection.remove(that.model);
+            that.close();
+            window.process.finishBackgroundProcess(p);
+          }).fail(function () {
+            window.process.failBackgroundProcess(p);
+          });
+        }
+      });
+    },
+
+    serializeData: function () {
+      return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+        canWrite: this.options.app.canWrite,
+        templateRule: this.options.templateRule,
+        permalink: baseUrl + '/coding_rules/show?key=' + encodeURIComponent(this.model.id)
+      });
+    }
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/coding-rules/rule/custom-rules-view.js b/server/sonar-web/src/main/js/coding-rules/rule/custom-rules-view.js
new file mode 100644 (file)
index 0000000..a6a25c7
--- /dev/null
@@ -0,0 +1,34 @@
+define([
+  'backbone.marionette',
+  'templates/coding-rules',
+  'coding-rules/rule/custom-rule-view'
+], function (Marionette, Templates, CustomRuleView) {
+
+  return Marionette.CompositeView.extend({
+    template: Templates['coding-rules-custom-rules'],
+    itemView: CustomRuleView,
+    itemViewContainer: '#coding-rules-detail-custom-rules',
+
+    itemViewOptions: function () {
+      return {
+        app: this.options.app,
+        templateRule: this.model
+      };
+    },
+
+    modelEvents: {
+      'change': 'render'
+    },
+
+    onRender: function () {
+      this.$el.toggleClass('hidden', !this.model.get('isTemplate'));
+    },
+
+    serializeData: function () {
+      return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+        canWrite: this.options.app.canWrite
+      });
+    }
+  });
+
+});
index b9e36555201a1564f227e6448a9a763a7265d692..449282d756c7e155a22b1f0334915907dd7acd62 100644 (file)
@@ -25,6 +25,22 @@ define([
       'click #coding-rules-quality-profile-activate': 'activate'
     },
 
+    onRender: function () {
+      var isManual = (this.options.app.manualRepository().key === this.model.get('repo')),
+          qualityProfilesVisible = !isManual;
+
+      if (qualityProfilesVisible) {
+        if (this.model.get('isTemplate')) {
+          qualityProfilesVisible = !_.isEmpty(this.options.actives);
+        }
+        else {
+          qualityProfilesVisible = (this.options.app.canWrite || !_.isEmpty(this.options.actives));
+        }
+      }
+
+      this.$el.toggleClass('hidden', !qualityProfilesVisible);
+    },
+
     activate: function () {
       new ProfileActivationView({
         rule: this.model,
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules.js b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules.js
new file mode 100644 (file)
index 0000000..fdce258
--- /dev/null
@@ -0,0 +1,45 @@
+/* global casper:false */
+
+var lib = require('../lib');
+
+lib.initMessages();
+lib.changeWorkingDirectory('coding-rules-page-should-delete-custom-rules');
+
+
+casper.test.begin('coding-rules-page-should-delete-custom-rules', 2, function (test) {
+  casper
+      .start(lib.buildUrl('coding-rules'), function () {
+        lib.setDefaultViewport();
+
+        lib.mockRequest('/api/l10n/index', '{}');
+        lib.mockRequestFromFile('/api/rules/app', 'app.json');
+        lib.mockRequestFromFile('/api/rules/search', 'search-custom-rules.json',
+            { data: { template_key: 'squid:ArchitecturalConstraint' } });
+        lib.mockRequestFromFile('/api/rules/search', 'search.json');
+        lib.mockRequestFromFile('/api/rules/show', 'show.json');
+        lib.mockRequest('/api/rules/delete', '{}');
+      })
+
+      .then(function () {
+        casper.waitForSelector('.coding-rule.selected', function () {
+          casper.click('.coding-rule.selected .js-rule');
+        });
+      })
+
+      .then(function () {
+        casper.waitForSelector('#coding-rules-detail-custom-rules .coding-rules-detail-list-name');
+      })
+
+      .then(function () {
+        test.assertElementCount('#coding-rules-detail-custom-rules .coding-rules-detail-list-name', 2);
+        casper.click('.js-delete-custom-rule');
+        casper.click('[data-confirm="yes"]');
+        lib.waitForElementCount('#coding-rules-detail-custom-rules .coding-rules-detail-list-name', 1, function () {
+          test.assert(true); // put dummy assert into wait statement
+        });
+      })
+
+      .run(function () {
+        test.done();
+      });
+});
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/app.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/app.json
new file mode 100644 (file)
index 0000000..f66b07b
--- /dev/null
@@ -0,0 +1,168 @@
+{
+  "canWrite": true,
+  "qualityprofiles": [
+    {
+      "key": "java-default-with-mojo-conventions-49307",
+      "name": "Default - Maven Conventions",
+      "lang": "java",
+      "parentKey": "java-top-profile-without-formatting-conventions-50037"
+    },
+    {
+      "key": "java-default-with-sonarsource-conventions-27339",
+      "name": "Default - SonarSource conventions",
+      "lang": "java",
+      "parentKey": "java-top-profile-without-formatting-conventions-50037"
+    },
+    {
+      "key": "java-top-profile-without-formatting-conventions-50037",
+      "name": "Default - Top",
+      "lang": "java"
+    },
+    {
+      "key": "java-findbugs-14954",
+      "name": "FindBugs",
+      "lang": "java"
+    },
+    {
+      "key": "java-for-sq-java-plugin-only-92289",
+      "name": "For SQ Java Plugin Only",
+      "lang": "java",
+      "parentKey": "java-default-with-sonarsource-conventions-27339"
+    },
+    {
+      "key": "java-for-sq-only-95381",
+      "name": "For SQ Only",
+      "lang": "java",
+      "parentKey": "java-default-with-sonarsource-conventions-27339"
+    },
+    {
+      "key": "php-psr-2-06315",
+      "name": "PSR-2",
+      "lang": "php"
+    },
+    {
+      "key": "java-sonar-way-80423",
+      "name": "Sonar way",
+      "lang": "java"
+    },
+    {
+      "key": "js-sonar-way",
+      "name": "Sonar way",
+      "lang": "js"
+    },
+    {
+      "key": "php-sonar-way-05548",
+      "name": "Sonar way",
+      "lang": "php"
+    },
+    {
+      "key": "py-sonar-way-80265",
+      "name": "Sonar way",
+      "lang": "py"
+    },
+    {
+      "key": "java-without-findbugs",
+      "name": "Without Findbugs",
+      "lang": "java"
+    }
+  ],
+  "languages": {
+    "py": "Python",
+    "js": "JavaScript",
+    "php": "PHP",
+    "java": "Java"
+  },
+  "repositories": [
+    {
+      "key": "common-java",
+      "name": "Common SonarQube",
+      "language": "java"
+    },
+    {
+      "key": "common-js",
+      "name": "Common SonarQube",
+      "language": "js"
+    },
+    {
+      "key": "common-php",
+      "name": "Common SonarQube",
+      "language": "php"
+    },
+    {
+      "key": "common-py",
+      "name": "Common SonarQube",
+      "language": "py"
+    },
+    {
+      "key": "Pylint",
+      "name": "Pylint",
+      "language": "py"
+    },
+    {
+      "key": "javascript",
+      "name": "SonarQube",
+      "language": "js"
+    },
+    {
+      "key": "php",
+      "name": "SonarQube",
+      "language": "php"
+    },
+    {
+      "key": "python",
+      "name": "SonarQube",
+      "language": "py"
+    },
+    {
+      "key": "squid",
+      "name": "SonarQube",
+      "language": "java"
+    }
+  ],
+  "statuses": {
+    "BETA": "Beta",
+    "DEPRECATED": "Deprecated",
+    "READY": "Ready"
+  },
+  "characteristics": {
+    "UNDERSTANDABILITY": "Maintainability: Understandability",
+    "MAINTAINABILITY": "Maintainability",
+    "TIME_ZONE_RELATED_PORTABILITY": "Portability: Time zone related portability",
+    "READABILITY": "Maintainability: Readability",
+    "SECURITY_FEATURES": "Security: Security features",
+    "ARCHITECTURE_RELIABILITY": "Reliability: Architecture related reliability",
+    "OS_RELATED_PORTABILITY": "Portability: OS related portability",
+    "EXCEPTION_HANDLING": "Reliability: Exception handling",
+    "LOGIC_CHANGEABILITY": "Changeability: Logic related changeability",
+    "SOFTWARE_RELATED_PORTABILITY": "Portability: Software related portability",
+    "INPUT_VALIDATION_AND_REPRESENTATION": "Security: Input validation and representation",
+    "LANGUAGE_RELATED_PORTABILITY": "Portability: Language related portability",
+    "ERRORS": "Security: Errors",
+    "SECURITY": "Security",
+    "RELIABILITY": "Reliability",
+    "PORTABILITY": "Portability",
+    "HARDWARE_RELATED_PORTABILITY": "Portability: Hardware related portability",
+    "SYNCHRONIZATION_RELIABILITY": "Reliability: Synchronization related reliability",
+    "TRANSPORTABILITY": "Reusability: Transportability",
+    "COMPILER_RELATED_PORTABILITY": "Portability: Compiler related portability",
+    "RESOURCE_RELIABILITY": "Reliability: Resource",
+    "CPU_EFFICIENCY": "Efficiency: Processor use",
+    "EFFICIENCY": "Efficiency",
+    "CHANGEABILITY": "Changeability",
+    "DATA_CHANGEABILITY": "Changeability: Data related changeability",
+    "API_ABUSE": "Security: API abuse",
+    "ARCHITECTURE_CHANGEABILITY": "Changeability: Architecture related changeability",
+    "UNIT_TESTS": "Reliability: Unit tests",
+    "INSTRUCTION_RELIABILITY": "Reliability: Instruction related reliability",
+    "REUSABILITY": "Reusability",
+    "MODULARITY": "Reusability: Modularity",
+    "UNIT_TESTABILITY": "Testability: Unit level testability",
+    "TESTABILITY": "Testability",
+    "INTEGRATION_TESTABILITY": "Testability: Integration level testability",
+    "NETWORK_USE": "Efficiency: Network use",
+    "MEMORY_EFFICIENCY": "Efficiency: Memory use",
+    "DATA_RELIABILITY": "Reliability: Data related reliability",
+    "FAULT_TOLERANCE": "Reliability: Fault tolerance",
+    "LOGIC_RELIABILITY": "Reliability: Logic related reliability"
+  }
+}
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/search-custom-rules.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/search-custom-rules.json
new file mode 100644 (file)
index 0000000..0e4184e
--- /dev/null
@@ -0,0 +1,45 @@
+{
+  "total": 2,
+  "p": 1,
+  "ps": 10,
+  "rules": [
+    {
+      "key": "squid:Do_not_use_org_h2_util_StringUtils",
+      "name": "Do not use org.h2.util.StringUtils",
+      "severity": "MAJOR",
+      "params": [
+        {
+          "key": "fromClasses",
+          "htmlDesc": "Optional. If this property is not defined, all classes should adhere to this constraint. Ex : *<em>.web.</em>*",
+          "type": "STRING",
+          "defaultValue": ""
+        },
+        {
+          "key": "toClasses",
+          "htmlDesc": "Mandatory. Ex : java.util.Vector, java.util.Hashtable, java.util.Enumeration",
+          "type": "STRING",
+          "defaultValue": "org.h2.util.StringUtils"
+        }
+      ]
+    },
+    {
+      "key": "squid:Do_not_use_edu_emory_mathcs_backport_java_util_Collections",
+      "name": "Do not use edu.emory.mathcs.backport.java.util.Collections",
+      "severity": "MAJOR",
+      "params": [
+        {
+          "key": "fromClasses",
+          "htmlDesc": "Optional. If this property is not defined, all classes should adhere to this constraint. Ex : *<em>.web.</em>*",
+          "type": "STRING",
+          "defaultValue": ""
+        },
+        {
+          "key": "toClasses",
+          "htmlDesc": "Mandatory. Ex : java.util.Vector, java.util.Hashtable, java.util.Enumeration",
+          "type": "STRING",
+          "defaultValue": "edu.emory.mathcs.backport.java.util.Collections"
+        }
+      ]
+    }
+  ]
+}
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/search.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/search.json
new file mode 100644 (file)
index 0000000..40ab6ae
--- /dev/null
@@ -0,0 +1,36 @@
+{
+  "total": 1,
+  "p": 1,
+  "ps": 200,
+  "rules": [
+    {
+      "key": "squid:ArchitecturalConstraint",
+      "name": "Architectural constraint",
+      "lang": "java",
+      "langName": "Java",
+      "sysTags": [],
+      "tags": [],
+      "status": "READY"
+    }
+  ],
+  "facets": [
+    {
+      "property": "languages",
+      "values": [
+        {
+          "val": "java",
+          "count": 1
+        }
+      ]
+    },
+    {
+      "property": "repositories",
+      "values": [
+        {
+          "val": "squid",
+          "count": 1
+        }
+      ]
+    }
+  ]
+}
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/show.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/show.json
new file mode 100644 (file)
index 0000000..517c5f6
--- /dev/null
@@ -0,0 +1,37 @@
+{
+  "rule": {
+    "key": "squid:ArchitecturalConstraint",
+    "repo": "squid",
+    "name": "Architectural constraint",
+    "createdAt": "2013-03-27T09:52:40+0100",
+    "severity": "MAJOR",
+    "status": "READY",
+    "internalKey": "ArchitecturalConstraint",
+    "isTemplate": true,
+    "tags": [],
+    "sysTags": [],
+    "lang": "java",
+    "langName": "Java",
+    "htmlDesc": "<p>A source code comply to an architectural model when it fully\n\tadheres to a set of architectural constraints. A constraint allows to\n\tdeny references between classes by pattern.</p>\n<p>You can for instance use this rule to :</p>\n<ul>\n\t<li>forbid access to **.web.** from **.dao.** classes</li>\n\t<li>forbid access to java.util.Vector, java.util.Hashtable and\n\t\tjava.util.Enumeration from any classes</li>\n\t<li>forbid access to java.sql.** from **.ui.** and **.web.**\n\t\tclasses</li>\n</ul>",
+    "debtChar": "CHANGEABILITY",
+    "debtSubChar": "ARCHITECTURE_CHANGEABILITY",
+    "debtCharName": "Changeability",
+    "debtSubCharName": "Architecture related changeability",
+    "debtOverloaded": true,
+    "debtRemFnType": "LINEAR",
+    "debtRemFnCoeff": "3h",
+    "params": [
+      {
+        "key": "fromClasses",
+        "htmlDesc": "Optional. If this property is not defined, all classes should adhere to this constraint. Ex : *<em>.web.</em>*",
+        "type": "STRING"
+      },
+      {
+        "key": "toClasses",
+        "htmlDesc": "Mandatory. Ex : java.util.Vector, java.util.Hashtable, java.util.Enumeration",
+        "type": "STRING"
+      }
+    ]
+  },
+  "actives": []
+}
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules.js b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules.js
new file mode 100644 (file)
index 0000000..d96e7d7
--- /dev/null
@@ -0,0 +1,42 @@
+/* global casper:false */
+
+var lib = require('../lib');
+
+lib.initMessages();
+lib.changeWorkingDirectory('coding-rules-page-should-show-custom-rules');
+
+
+casper.test.begin('coding-rules-page-should-show-custom-rules', 3, function (test) {
+  casper
+      .start(lib.buildUrl('coding-rules'), function () {
+        lib.setDefaultViewport();
+
+        lib.mockRequest('/api/l10n/index', '{}');
+        lib.mockRequestFromFile('/api/rules/app', 'app.json');
+        lib.mockRequestFromFile('/api/rules/search', 'search-custom-rules.json',
+            { data: { template_key: 'squid:ArchitecturalConstraint' } });
+        lib.mockRequestFromFile('/api/rules/search', 'search.json');
+        lib.mockRequestFromFile('/api/rules/show', 'show.json');
+      })
+
+      .then(function () {
+        casper.waitForSelector('.coding-rule.selected', function () {
+          casper.click('.coding-rule.selected .js-rule');
+        });
+      })
+
+      .then(function () {
+        casper.waitForSelector('#coding-rules-detail-custom-rules .coding-rules-detail-list-name');
+      })
+
+      .then(function () {
+        test.assertExists('#coding-rules-detail-custom-rules');
+        test.assertElementCount('#coding-rules-detail-custom-rules .coding-rules-detail-list-name', 2);
+        test.assertSelectorContains('#coding-rules-detail-custom-rules .coding-rules-detail-list-name',
+            'Do not use org.h2.util.StringUtils');
+      })
+
+      .run(function () {
+        test.done();
+      });
+});
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/app.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/app.json
new file mode 100644 (file)
index 0000000..4f3319c
--- /dev/null
@@ -0,0 +1,168 @@
+{
+  "canWrite": false,
+  "qualityprofiles": [
+    {
+      "key": "java-default-with-mojo-conventions-49307",
+      "name": "Default - Maven Conventions",
+      "lang": "java",
+      "parentKey": "java-top-profile-without-formatting-conventions-50037"
+    },
+    {
+      "key": "java-default-with-sonarsource-conventions-27339",
+      "name": "Default - SonarSource conventions",
+      "lang": "java",
+      "parentKey": "java-top-profile-without-formatting-conventions-50037"
+    },
+    {
+      "key": "java-top-profile-without-formatting-conventions-50037",
+      "name": "Default - Top",
+      "lang": "java"
+    },
+    {
+      "key": "java-findbugs-14954",
+      "name": "FindBugs",
+      "lang": "java"
+    },
+    {
+      "key": "java-for-sq-java-plugin-only-92289",
+      "name": "For SQ Java Plugin Only",
+      "lang": "java",
+      "parentKey": "java-default-with-sonarsource-conventions-27339"
+    },
+    {
+      "key": "java-for-sq-only-95381",
+      "name": "For SQ Only",
+      "lang": "java",
+      "parentKey": "java-default-with-sonarsource-conventions-27339"
+    },
+    {
+      "key": "php-psr-2-06315",
+      "name": "PSR-2",
+      "lang": "php"
+    },
+    {
+      "key": "java-sonar-way-80423",
+      "name": "Sonar way",
+      "lang": "java"
+    },
+    {
+      "key": "js-sonar-way",
+      "name": "Sonar way",
+      "lang": "js"
+    },
+    {
+      "key": "php-sonar-way-05548",
+      "name": "Sonar way",
+      "lang": "php"
+    },
+    {
+      "key": "py-sonar-way-80265",
+      "name": "Sonar way",
+      "lang": "py"
+    },
+    {
+      "key": "java-without-findbugs",
+      "name": "Without Findbugs",
+      "lang": "java"
+    }
+  ],
+  "languages": {
+    "py": "Python",
+    "js": "JavaScript",
+    "php": "PHP",
+    "java": "Java"
+  },
+  "repositories": [
+    {
+      "key": "common-java",
+      "name": "Common SonarQube",
+      "language": "java"
+    },
+    {
+      "key": "common-js",
+      "name": "Common SonarQube",
+      "language": "js"
+    },
+    {
+      "key": "common-php",
+      "name": "Common SonarQube",
+      "language": "php"
+    },
+    {
+      "key": "common-py",
+      "name": "Common SonarQube",
+      "language": "py"
+    },
+    {
+      "key": "Pylint",
+      "name": "Pylint",
+      "language": "py"
+    },
+    {
+      "key": "javascript",
+      "name": "SonarQube",
+      "language": "js"
+    },
+    {
+      "key": "php",
+      "name": "SonarQube",
+      "language": "php"
+    },
+    {
+      "key": "python",
+      "name": "SonarQube",
+      "language": "py"
+    },
+    {
+      "key": "squid",
+      "name": "SonarQube",
+      "language": "java"
+    }
+  ],
+  "statuses": {
+    "BETA": "Beta",
+    "DEPRECATED": "Deprecated",
+    "READY": "Ready"
+  },
+  "characteristics": {
+    "UNDERSTANDABILITY": "Maintainability: Understandability",
+    "MAINTAINABILITY": "Maintainability",
+    "TIME_ZONE_RELATED_PORTABILITY": "Portability: Time zone related portability",
+    "READABILITY": "Maintainability: Readability",
+    "SECURITY_FEATURES": "Security: Security features",
+    "ARCHITECTURE_RELIABILITY": "Reliability: Architecture related reliability",
+    "OS_RELATED_PORTABILITY": "Portability: OS related portability",
+    "EXCEPTION_HANDLING": "Reliability: Exception handling",
+    "LOGIC_CHANGEABILITY": "Changeability: Logic related changeability",
+    "SOFTWARE_RELATED_PORTABILITY": "Portability: Software related portability",
+    "INPUT_VALIDATION_AND_REPRESENTATION": "Security: Input validation and representation",
+    "LANGUAGE_RELATED_PORTABILITY": "Portability: Language related portability",
+    "ERRORS": "Security: Errors",
+    "SECURITY": "Security",
+    "RELIABILITY": "Reliability",
+    "PORTABILITY": "Portability",
+    "HARDWARE_RELATED_PORTABILITY": "Portability: Hardware related portability",
+    "SYNCHRONIZATION_RELIABILITY": "Reliability: Synchronization related reliability",
+    "TRANSPORTABILITY": "Reusability: Transportability",
+    "COMPILER_RELATED_PORTABILITY": "Portability: Compiler related portability",
+    "RESOURCE_RELIABILITY": "Reliability: Resource",
+    "CPU_EFFICIENCY": "Efficiency: Processor use",
+    "EFFICIENCY": "Efficiency",
+    "CHANGEABILITY": "Changeability",
+    "DATA_CHANGEABILITY": "Changeability: Data related changeability",
+    "API_ABUSE": "Security: API abuse",
+    "ARCHITECTURE_CHANGEABILITY": "Changeability: Architecture related changeability",
+    "UNIT_TESTS": "Reliability: Unit tests",
+    "INSTRUCTION_RELIABILITY": "Reliability: Instruction related reliability",
+    "REUSABILITY": "Reusability",
+    "MODULARITY": "Reusability: Modularity",
+    "UNIT_TESTABILITY": "Testability: Unit level testability",
+    "TESTABILITY": "Testability",
+    "INTEGRATION_TESTABILITY": "Testability: Integration level testability",
+    "NETWORK_USE": "Efficiency: Network use",
+    "MEMORY_EFFICIENCY": "Efficiency: Memory use",
+    "DATA_RELIABILITY": "Reliability: Data related reliability",
+    "FAULT_TOLERANCE": "Reliability: Fault tolerance",
+    "LOGIC_RELIABILITY": "Reliability: Logic related reliability"
+  }
+}
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/search-custom-rules.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/search-custom-rules.json
new file mode 100644 (file)
index 0000000..0e4184e
--- /dev/null
@@ -0,0 +1,45 @@
+{
+  "total": 2,
+  "p": 1,
+  "ps": 10,
+  "rules": [
+    {
+      "key": "squid:Do_not_use_org_h2_util_StringUtils",
+      "name": "Do not use org.h2.util.StringUtils",
+      "severity": "MAJOR",
+      "params": [
+        {
+          "key": "fromClasses",
+          "htmlDesc": "Optional. If this property is not defined, all classes should adhere to this constraint. Ex : *<em>.web.</em>*",
+          "type": "STRING",
+          "defaultValue": ""
+        },
+        {
+          "key": "toClasses",
+          "htmlDesc": "Mandatory. Ex : java.util.Vector, java.util.Hashtable, java.util.Enumeration",
+          "type": "STRING",
+          "defaultValue": "org.h2.util.StringUtils"
+        }
+      ]
+    },
+    {
+      "key": "squid:Do_not_use_edu_emory_mathcs_backport_java_util_Collections",
+      "name": "Do not use edu.emory.mathcs.backport.java.util.Collections",
+      "severity": "MAJOR",
+      "params": [
+        {
+          "key": "fromClasses",
+          "htmlDesc": "Optional. If this property is not defined, all classes should adhere to this constraint. Ex : *<em>.web.</em>*",
+          "type": "STRING",
+          "defaultValue": ""
+        },
+        {
+          "key": "toClasses",
+          "htmlDesc": "Mandatory. Ex : java.util.Vector, java.util.Hashtable, java.util.Enumeration",
+          "type": "STRING",
+          "defaultValue": "edu.emory.mathcs.backport.java.util.Collections"
+        }
+      ]
+    }
+  ]
+}
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/search.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/search.json
new file mode 100644 (file)
index 0000000..40ab6ae
--- /dev/null
@@ -0,0 +1,36 @@
+{
+  "total": 1,
+  "p": 1,
+  "ps": 200,
+  "rules": [
+    {
+      "key": "squid:ArchitecturalConstraint",
+      "name": "Architectural constraint",
+      "lang": "java",
+      "langName": "Java",
+      "sysTags": [],
+      "tags": [],
+      "status": "READY"
+    }
+  ],
+  "facets": [
+    {
+      "property": "languages",
+      "values": [
+        {
+          "val": "java",
+          "count": 1
+        }
+      ]
+    },
+    {
+      "property": "repositories",
+      "values": [
+        {
+          "val": "squid",
+          "count": 1
+        }
+      ]
+    }
+  ]
+}
diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/show.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/show.json
new file mode 100644 (file)
index 0000000..517c5f6
--- /dev/null
@@ -0,0 +1,37 @@
+{
+  "rule": {
+    "key": "squid:ArchitecturalConstraint",
+    "repo": "squid",
+    "name": "Architectural constraint",
+    "createdAt": "2013-03-27T09:52:40+0100",
+    "severity": "MAJOR",
+    "status": "READY",
+    "internalKey": "ArchitecturalConstraint",
+    "isTemplate": true,
+    "tags": [],
+    "sysTags": [],
+    "lang": "java",
+    "langName": "Java",
+    "htmlDesc": "<p>A source code comply to an architectural model when it fully\n\tadheres to a set of architectural constraints. A constraint allows to\n\tdeny references between classes by pattern.</p>\n<p>You can for instance use this rule to :</p>\n<ul>\n\t<li>forbid access to **.web.** from **.dao.** classes</li>\n\t<li>forbid access to java.util.Vector, java.util.Hashtable and\n\t\tjava.util.Enumeration from any classes</li>\n\t<li>forbid access to java.sql.** from **.ui.** and **.web.**\n\t\tclasses</li>\n</ul>",
+    "debtChar": "CHANGEABILITY",
+    "debtSubChar": "ARCHITECTURE_CHANGEABILITY",
+    "debtCharName": "Changeability",
+    "debtSubCharName": "Architecture related changeability",
+    "debtOverloaded": true,
+    "debtRemFnType": "LINEAR",
+    "debtRemFnCoeff": "3h",
+    "params": [
+      {
+        "key": "fromClasses",
+        "htmlDesc": "Optional. If this property is not defined, all classes should adhere to this constraint. Ex : *<em>.web.</em>*",
+        "type": "STRING"
+      },
+      {
+        "key": "toClasses",
+        "htmlDesc": "Mandatory. Ex : java.util.Vector, java.util.Hashtable, java.util.Enumeration",
+        "type": "STRING"
+      }
+    ]
+  },
+  "actives": []
+}
index ec2e6440afeabc14aad4f0d77c57c6aa3f8bda86..7ff98d7b18e94ef733f66b1d0367db591a6234c9 100644 (file)
   margin-top: 3 * @navigatorPadding;
 }
 
-.coding-rules-detail-quality-profiles {
+.coding-rules-detail-quality-profiles,
+.coding-rules-detail-list {
+  width: 100%;
   line-height: 22px;
 
   td {
   }
 }
 
-.coding-rules-detail-quality-profile-name {
+.coding-rules-detail-quality-profile-name,
+.coding-rules-detail-list-name {
   vertical-align: top;
   width: 1px;
   padding: 8px 5px 8px 0;
-  font-weight: bold;
+  font-weight: 500;
   white-space: nowrap;
 }
 
-.coding-rules-detail-quality-profile-severity {
+.coding-rules-detail-quality-profile-severity,
+.coding-rules-detail-list-severity {
   vertical-align: top;
   width: 1px;
   padding: 8px 5px;
   white-space: nowrap;
 }
 
-.coding-rules-detail-quality-profile-parameters {
+.coding-rules-detail-quality-profile-parameters,
+.coding-rules-detail-list-parameters {
   vertical-align: top;
   padding: 8px 5px;
 }
 
-.coding-rules-detail-quality-profile-actions {
+.coding-rules-detail-quality-profile-actions,
+.coding-rules-detail-list-actions {
   vertical-align: top;
   width: 1px;
   padding: 8px 0 8px 5px;
@@ -373,37 +379,11 @@ input.coding-rules-name-key {
   width: 30em;
 }
 
-[id=coding-rules-detail-custom-rules] {
-  padding-left: 2 * @navigatorPadding;
-}
-
 textarea.coding-rules-markdown-description {
   width: 100%;
   margin-bottom: 4px;
 }
 
-.coding-rules-detail-custom-rule + .coding-rules-detail-custom-rule {
-  margin-top: @navigatorPadding;
-  padding-top: @navigatorPadding;
-  border-top: 1px solid @navigatorBorderLightColor;
-}
-
-.coding-rules-detail-custom-rule td {
-  padding: @navigatorPadding;
-}
-
-.coding-rules-detail-custom-rule-name {
-  font-weight: bold;
-}
-
-.coding-rules-detail-custom-rule-key {
-  display:inline-block;
-  max-width: 460px;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-
 .coding-rules-modal .property {
   input, textarea {
     width: 100%;