From: Stas Vilchik Date: Fri, 26 Dec 2014 12:19:21 +0000 (+0100) Subject: SONAR-5820 Display the list of custom rules created from a template rule X-Git-Tag: latest-silver-master-#65~408 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=ad9964466f846b59e99c42a92344934d67dff888;p=sonarqube.git SONAR-5820 Display the list of custom rules created from a template rule --- diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-rule-details.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-rule-details.hbs index 4414fd197d8..91acf126305 100644 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-rule-details.hbs +++ b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-rule-details.hbs @@ -15,17 +15,5 @@ {{/if}} -{{#if isTemplate}} -
-

{{t 'coding_rules.custom_rules'}}

- - {{#if canWrite}} -
- -
- {{/if}} -
-
-{{/if}} - +
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 index 00000000000..4d8f07efd37 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-custom-rule.hbs @@ -0,0 +1,26 @@ + + {{name}} + + + + {{severityIcon severity}} {{t "severity" severity}} + + + + {{#each parameters}} +
+ {{key}}{{value}} +
+ {{/each}} +   + + +{{#if canWrite}} + +
+ +
+ +{{/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 index 00000000000..f2a2cc9793e --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-custom-rules.hbs @@ -0,0 +1,10 @@ +
+

{{t 'coding_rules.custom_rules'}}

+ + {{#if canWrite}} +
+ +
+ {{/if}} +
+
diff --git a/server/sonar-web/src/main/js/coding-rules/rule-details-view.js b/server/sonar-web/src/main/js/coding-rules/rule-details-view.js index 051413e679f..627d3165311 100644 --- a/server/sonar-web/src/main/js/coding-rules/rule-details-view.js +++ b/server/sonar-web/src/main/js/coding-rules/rule-details-view.js @@ -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 index 00000000000..cb96f91c5c9 --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/rule/custom-rule-view.js @@ -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 index 00000000000..a6a25c7982d --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/rule/custom-rules-view.js @@ -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 + }); + } + }); + +}); 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 index b9e36555201..449282d756c 100644 --- 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 @@ -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 index 00000000000..fdce258714d --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules.js @@ -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 index 00000000000..f66b07ba5a1 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/app.json @@ -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 index 00000000000..0e4184e48a9 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/search-custom-rules.json @@ -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 : *.web.*", + "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 : *.web.*", + "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 index 00000000000..40ab6ae953a --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/search.json @@ -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 index 00000000000..517c5f6e754 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-custom-rules/show.json @@ -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": "

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.

\n

You can for instance use this rule to :

\n", + "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 : *.web.*", + "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 index 00000000000..d96e7d78761 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules.js @@ -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 index 00000000000..4f3319c8707 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/app.json @@ -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 index 00000000000..0e4184e48a9 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/search-custom-rules.json @@ -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 : *.web.*", + "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 : *.web.*", + "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 index 00000000000..40ab6ae953a --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/search.json @@ -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 index 00000000000..517c5f6e754 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-show-custom-rules/show.json @@ -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": "

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.

\n

You can for instance use this rule to :

\n", + "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 : *.web.*", + "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/less/coding-rules.less b/server/sonar-web/src/main/less/coding-rules.less index ec2e6440afe..7ff98d7b18e 100644 --- a/server/sonar-web/src/main/less/coding-rules.less +++ b/server/sonar-web/src/main/less/coding-rules.less @@ -277,7 +277,9 @@ margin-top: 3 * @navigatorPadding; } -.coding-rules-detail-quality-profiles { +.coding-rules-detail-quality-profiles, +.coding-rules-detail-list { + width: 100%; line-height: 22px; td { @@ -289,27 +291,31 @@ } } -.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%;