diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2014-12-26 17:43:39 +0100 |
---|---|---|
committer | Stas Vilchik <vilchiks@gmail.com> | 2015-01-05 11:27:17 +0100 |
commit | 1fc88c2c9114999f7635df19d6d33e04df95b0f6 (patch) | |
tree | 95afcf506125d7a037848ac81caa54cb265e1c16 /server/sonar-web/src | |
parent | e87e06f2789cc3c42c30de31f62084552f6295d3 (diff) | |
download | sonarqube-1fc88c2c9114999f7635df19d6d33e04df95b0f6.tar.gz sonarqube-1fc88c2c9114999f7635df19d6d33e04df95b0f6.zip |
SONAR-5820 Ability to create, edit and delete a "Manual" rule
Diffstat (limited to 'server/sonar-web/src')
19 files changed, 866 insertions, 134 deletions
diff --git a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filters.hbs b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filters.hbs index 45ce48c26c6..dc97d68a6fe 100644 --- a/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filters.hbs +++ b/server/sonar-web/src/main/hbs/coding-rules/coding-rules-filters.hbs @@ -5,5 +5,8 @@ <div class="search-navigator-filters-actions"> <div class="button-group"> <button class="js-new-search" id="coding-rules-new-search">{{t 'issue_filter.new_search'}}</button> + {{#if canWrite}} + <button class="js-create-manual-rule">{{t 'coding_rules.create'}}</button> + {{/if}} </div> </div> 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 91acf126305..930576b5285 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 @@ -6,11 +6,11 @@ <div class="coding-rules-detail-description"> <div class="button-group"> {{#if isManual}} - <button id="coding-rules-detail-manual-rule-change">{{t 'edit'}}</button> + <button class="js-edit-manual" id="coding-rules-detail-manual-rule-change">{{t 'edit'}}</button> {{else}} - <button id="coding-rules-detail-custom-rule-change">{{t 'edit'}}</button> + <button class="js-edit-custom" id="coding-rules-detail-custom-rule-change">{{t 'edit'}}</button> {{/if}} - <button id="coding-rules-detail-rule-delete" class="button-red">{{t 'delete'}}</button> + <button class="js-delete" id="coding-rules-detail-rule-delete" class="button-red">{{t 'delete'}}</button> </div> </div> {{/if}} diff --git a/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-manual-rule-creation.hbs b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-manual-rule-creation.hbs new file mode 100644 index 00000000000..5a6e62a6c46 --- /dev/null +++ b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-manual-rule-creation.hbs @@ -0,0 +1,50 @@ +<form> + <div class="modal-head"> + {{#if change}} + <h2>{{t 'coding_rules.update_manual_rule'}}</h2> + {{else}} + <h2>{{t 'coding_rules.create_manual_rule'}}</h2> + {{/if}} + </div> + + <div class="modal-body"> + <div class="modal-error"></div> + <div class="modal-warning">{{t 'coding_rules.reactivate.help'}}</div> + + <table> + <tr class="property"> + <th><h3>{{t 'name'}} <em class="mandatory">*</em></h3></th> + <td> + <input type="text" name="name" id="coding-rules-manual-rule-creation-name" + class="coding-rules-name-key" value="{{name}}"/> + </td> + </tr> + <tr class="property"> + <th><h3>{{t 'key'}}{{#unless change}} <em class="mandatory">*</em>{{/unless}}</h3></th> + <td> + {{#if change}} + {{key}} + {{else}} + <input type="text" name="key" id="coding-rules-manual-rule-creation-key" + class="coding-rules-name-key" value="{{internalKey}}"/> + {{/if}} + </td> + </tr> + <tr class="property"> + <th><h3>{{t 'description'}} <em class="mandatory">*</em></h3></th> + <td> + <textarea name="markdown_description" id="coding-rules-manual-rule-creation-html-description" + class="coding-rules-markdown-description" rows="15">{{{mdDesc}}}</textarea> + <span class="right">{{> '_markdown-tips' }}</span> + </td> + </tr> + </table> + </div> + + <div class="modal-foot"> + <button id="coding-rules-manual-rule-creation-create"> + {{#if change}}{{t 'save'}}{{else}}{{t 'create'}}{{/if}} + </button> + <a id="coding-rules-manual-rule-creation-cancel" class="action">{{t 'cancel'}}</a> + </div> +</form> 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 index fff167bbcf3..af307386b1d 100644 --- 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 @@ -38,13 +38,11 @@ </li> {{/if}} - - <li class="coding-rules-detail-property">{{t 'coding_rules.available_since'}} {{d createdAt}}</li> <li class="coding-rules-detail-property" - data-toggle="tooltip" data-placement="bottom" title="Rule repository (language)"> - {{default repo.name repo}}{{#unless isManual}} ({{langName}}){{/unless}} + data-toggle="tooltip" data-placement="bottom" title="Rule repository{{#unless isManual}} (language){{/unless}}"> + {{repoName}}{{#unless isManual}} ({{langName}}){{/unless}} </li> {{#if isTemplate}} diff --git a/server/sonar-web/src/main/js/coding-rules/app.js b/server/sonar-web/src/main/js/coding-rules/app.js index c42f4a41a8b..4dfb34661a7 100644 --- a/server/sonar-web/src/main/js/coding-rules/app.js +++ b/server/sonar-web/src/main/js/coding-rules/app.js @@ -114,7 +114,7 @@ requirejs([ App.manualRepository = function () { return { key: 'manual', - name: t('coding_rules.manual_rules'), + name: t('coding_rules.manual_rule'), language: 'none' }; }; diff --git a/server/sonar-web/src/main/js/coding-rules/filters-view.js b/server/sonar-web/src/main/js/coding-rules/filters-view.js index 9c2de652b4a..d46f4f68e12 100644 --- a/server/sonar-web/src/main/js/coding-rules/filters-view.js +++ b/server/sonar-web/src/main/js/coding-rules/filters-view.js @@ -1,17 +1,31 @@ define([ 'backbone.marionette', - 'templates/coding-rules' -], function (Marionette, Templates) { + 'templates/coding-rules', + 'coding-rules/rule/manual-rule-creation-view' +], function (Marionette, Templates, ManualRuleCreationView) { return Marionette.ItemView.extend({ template: Templates['coding-rules-filters'], events: { - 'click .js-new-search': 'newSearch' + 'click .js-new-search': 'newSearch', + 'click .js-create-manual-rule': 'createManualRule' }, newSearch: function () { this.options.app.controller.newSearch(); + }, + + createManualRule: function() { + new ManualRuleCreationView({ + app: this.options.app + }).render(); + }, + + 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/models/rule.js b/server/sonar-web/src/main/js/coding-rules/models/rule.js index 0b20c8eab0d..9363ff689d8 100644 --- a/server/sonar-web/src/main/js/coding-rules/models/rule.js +++ b/server/sonar-web/src/main/js/coding-rules/models/rule.js @@ -8,11 +8,12 @@ define([ addExtraAttributes: function (languages, repositories) { var langName = languages[this.get('lang')] || this.get('lang'), repo = _.findWhere(repositories, { key: this.get('repo') }) || this.get('repo'), + repoName = repo != null ? repo.name : repo, isManual = this.get('repo') === 'manual', isCustom = this.has('templateKey'); this.set({ langName: langName, - repo: repo, + repoName: repoName, isManual: isManual, isCustom: isCustom }); 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 627d3165311..d9b76e526d2 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 @@ -7,130 +7,172 @@ define([ 'coding-rules/rule/rule-description-view', 'coding-rules/rule/rule-parameters-view', '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', - template: Templates['coding-rules-rule-details'], - - regions: { - metaRegion: '.js-rule-meta', - descRegion: '.js-rule-description', - paramRegion: '.js-rule-parameters', - 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 () { - 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()) - })); - this.customRulesRegion.show(new CustomRulesView({ - app: this.options.app, - model: this.model, - collection: this.customRules - })); - this.$el.scrollParent().scrollTop(30); - }, - - onClose: function () { - 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) { - 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 () { - that.options.app.controller.selectPrev(); - that.options.app.controller.showDetailsForSelected(); - return false; - }); - key('down', 'details', function () { - that.options.app.controller.selectNext(); - that.options.app.controller.showDetailsForSelected(); - return false; - }); - key('left', 'details', function () { - that.options.app.controller.hideDetails(); - return false; - }); - }, + 'coding-rules/rule/custom-rules-view', + 'coding-rules/rule/manual-rule-creation-view' +], + function (Backbone, + Marionette, + Templates, + Rules, + MetaView, + DescView, + ParamView, + ProfilesView, + CustomRulesView, + ManualRuleCreationView) { - unbindShortcuts: function () { - key.deleteScope('details'); - }, + var $ = jQuery; - serializeData: function () { - 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; + return Marionette.Layout.extend({ + className: 'coding-rule-details', + template: Templates['coding-rules-rule-details'], - if (qualityProfilesVisible) { - if (this.model.get('isTemplate')) { - qualityProfilesVisible = !_.isEmpty(this.options.actives); - } - else { - qualityProfilesVisible = (this.options.app.canWrite || !_.isEmpty(this.options.actives)); + regions: { + metaRegion: '.js-rule-meta', + descRegion: '.js-rule-description', + paramRegion: '.js-rule-parameters', + profilesRegion: '.js-rule-profiles', + customRulesRegion: '.js-rule-custom-rules' + }, + + events: { + 'click .js-edit-manual': 'editManualRule', + 'click .js-delete': 'deleteRule' + }, + + initialize: function () { + this.bindShortcuts(); + this.customRules = new Rules(); + if (this.model.get('isTemplate')) { + this.fetchCustomRules(); + } + }, + + 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()) + })); + this.customRulesRegion.show(new CustomRulesView({ + app: this.options.app, + model: this.model, + collection: this.customRules + })); + this.$el.scrollParent().scrollTop(30); + }, + + onClose: function () { + 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) { + 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 () { + that.options.app.controller.selectPrev(); + that.options.app.controller.showDetailsForSelected(); + return false; + }); + key('down', 'details', function () { + that.options.app.controller.selectNext(); + that.options.app.controller.showDetailsForSelected(); + return false; + }); + key('left', 'details', function () { + that.options.app.controller.hideDetails(); + return false; + }); + }, + + unbindShortcuts: function () { + key.deleteScope('details'); + }, + + editManualRule: function () { + new ManualRuleCreationView({ + app: this.options.app, + model: this.model + }).render(); + }, + + deleteRule: function () { + var that = this, + ruleType = this.model.has('templateKey') ? 'custom' : 'manual'; + window.confirmDialog({ + title: t('delete'), + html: tp('coding_rules.delete.' + ruleType + '.confirm', this.model.get('name')), + yesHandler: function () { + var p = window.process.addBackgroundProcess(), + url = baseUrl + '/api/rules/delete', + options = { key: that.model.id }; + $.post(url, options).done(function () { + that.options.app.controller.fetchList(); + window.process.finishBackgroundProcess(p); + }).fail(function () { + window.process.failBackgroundProcess(p); + }); + } + }); + }, + + serializeData: function () { + var isManual = this.model.get('isManual'), + 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), { + 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')) + }); } - } - - return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), { - 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/manual-rule-creation-view.js b/server/sonar-web/src/main/js/coding-rules/rule/manual-rule-creation-view.js new file mode 100644 index 00000000000..53f58f0b2aa --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/rule/manual-rule-creation-view.js @@ -0,0 +1,115 @@ +define([ + 'common/modal-form', + 'templates/coding-rules' +], function (ModalFormView, Templates) { + + var $ = jQuery; + + return ModalFormView.extend({ + template: Templates['coding-rules-manual-rule-creation'], + + ui: function () { + return _.extend(ModalFormView.prototype.ui.apply(this.arguments), { + manualRuleCreationKey: '#coding-rules-manual-rule-creation-key', + manualRuleCreationName: '#coding-rules-manual-rule-creation-name', + manualRuleCreationHtmlDescription: '#coding-rules-manual-rule-creation-html-description', + manualRuleCreationSeverity: '#coding-rules-manual-rule-creation-severity', + manualRuleCreationStatus: '#coding-rules-manual-rule-creation-status', + manualRuleCreationParameters: '[name]', + manualRuleCreationCreate: '#coding-rules-manual-rule-creation-create', + manualRuleCreationReactivate: '#coding-rules-manual-rule-creation-reactivate', + modalFoot: '.modal-foot' + }); + }, + + events: function () { + return _.extend(ModalFormView.prototype.events.apply(this.arguments), { + 'input @ui.manualRuleCreationName': 'generateKey', + 'keydown @ui.manualRuleCreationName': 'generateKey', + 'keyup @ui.manualRuleCreationName': 'generateKey', + + 'input @ui.manualRuleCreationKey': 'flagKey', + 'keydown @ui.manualRuleCreationKey': 'flagKey', + 'keyup @ui.manualRuleCreationKey': 'flagKey', + + 'click #coding-rules-manual-rule-creation-cancel': 'hide', + 'click @ui.manualRuleCreationCreate': 'create', + 'click @ui.manualRuleCreationReactivate': 'reactivate' + }); + }, + + onRender: function () { + ModalFormView.prototype.onRender.apply(this, arguments); + this.keyModifiedByUser = false; + }, + + generateKey: function () { + if (!this.keyModifiedByUser && this.ui.manualRuleCreationKey) { + var generatedKey = this.ui.manualRuleCreationName.val().latinize().replace(/[^A-Za-z0-9]/g, '_'); + this.ui.manualRuleCreationKey.val(generatedKey); + } + }, + + flagKey: function () { + this.keyModifiedByUser = true; + // Cannot use @ui.manualRuleCreationReactivate.hide() directly since it was not there at initial render + $(this.ui.manualRuleCreationReactivate.selector).hide(); + }, + + create: function () { + var action = (this.model && this.model.has('key')) ? 'update' : 'create', + options = { + name: this.ui.manualRuleCreationName.val(), + markdown_description: this.ui.manualRuleCreationHtmlDescription.val() + }; + if (action === 'update') { + options.key = this.model.get('key'); + } else { + options.manual_key = this.ui.manualRuleCreationKey.val(); + options.prevent_reactivation = true; + } + this.sendRequest(action, options); + }, + + reactivate: function () { + var options = { + name: this.existingRule.name, + markdown_description: this.existingRule.mdDesc, + manual_key: this.ui.manualRuleCreationKey.val(), + prevent_reactivation: false + }; + this.sendRequest('create', options); + }, + + sendRequest: function (action, options) { + this.$('.modal-error').hide(); + this.$('.modal-warning').hide(); + var that = this, + p = window.process.addBackgroundProcess(), + url = baseUrl + '/api/rules/' + action; + return $.post(url, options).done(function (r) { + if (typeof r === 'string') { + r = JSON.parse(r); + } + that.options.app.controller.showDetails(r.rule.key); + that.close(); + }).fail(function (jqXHR) { + if (jqXHR.status === 409) { + that.existingRule = jqXHR.responseJSON.rule; + that.$('.modal-warning').show(); + } else { + that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); + } + }).always(function () { + window.process.finishBackgroundProcess(p); + }); + }, + + serializeData: function () { + return _.extend(ModalFormView.prototype.serializeData.apply(this, arguments), { + change: this.model && this.model.has('key') + }); + } + }); + +}); 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 0aedc97918c..5a7be4748e0 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 @@ -26,7 +26,7 @@ define([ }, onRender: function () { - var isManual = (this.options.app.manualRepository().key === this.model.get('repo')), + var isManual = this.model.get('isManual'), qualityProfilesVisible = !isManual; if (qualityProfilesVisible) { diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-create-manual-rules.js b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-create-manual-rules.js new file mode 100644 index 00000000000..a128ffa277c --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-create-manual-rules.js @@ -0,0 +1,50 @@ +/* global casper:false */ + +var lib = require('../lib'); + +lib.initMessages(); +lib.changeWorkingDirectory('coding-rules-page-should-create-manual-rules'); + + +casper.test.begin('coding-rules-page-should-delete-manual-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.json'); + lib.mockRequestFromFile('/api/rules/create', 'show.json'); + lib.mockRequestFromFile('/api/rules/show', 'show.json'); + }) + + .then(function () { + casper.waitForSelector('.js-create-manual-rule', function () { + casper.click('.js-create-manual-rule'); + }); + }) + + .then(function () { + casper.waitForSelector('.modal'); + }) + + .then(function () { + casper.evaluate(function () { + jQuery('.modal [name="name"]').val('Manual Rule'); + jQuery('.modal [name="key"]').val('manual:Manual_Rule'); + jQuery('.modal [name="markdown_description"]').val('Manual Rule Description'); + jQuery('.modal #coding-rules-manual-rule-creation-create').click(); + }); + casper.waitForSelector('.coding-rules-detail-header'); + }) + + .then(function () { + test.assertSelectorContains('.coding-rules-detail-header', 'Manual Rule'); + test.assertSelectorContains('.coding-rule-details .subtitle', 'manual:Manual_Rule'); + test.assertSelectorContains('.coding-rules-detail-description', 'Manual Rule Description'); + }) + + .run(function () { + test.done(); + }); +}); diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-create-manual-rules/app.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-create-manual-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-create-manual-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-create-manual-rules/search.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-create-manual-rules/search.json new file mode 100644 index 00000000000..f43d117c569 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-create-manual-rules/search.json @@ -0,0 +1,7 @@ +{ + "total": 0, + "p": 1, + "ps": 200, + "rules": [], + "facets": [] +} diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-create-manual-rules/show.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-create-manual-rules/show.json new file mode 100644 index 00000000000..38190c28abb --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-create-manual-rules/show.json @@ -0,0 +1,17 @@ +{ + "rule": { + "key": "manual:Manual_Rule", + "repo": "manual", + "name": "Manual Rule", + "createdAt": "2015-01-05T10:02:11+0100", + "status": "READY", + "isTemplate": false, + "tags": [], + "sysTags": [], + "htmlDesc": "Manual Rule Description", + "mdDesc": "Manual Rule Description", + "debtOverloaded": false, + "params": [] + }, + "actives": [] +} diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-rules.js b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-rules.js new file mode 100644 index 00000000000..06fcd20739a --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-rules.js @@ -0,0 +1,50 @@ +/* global casper:false */ + +var lib = require('../lib'); + +lib.initMessages(); +lib.changeWorkingDirectory('coding-rules-page-should-delete-manual-rules'); + + +casper.test.begin('coding-rules-page-should-delete-manual-rules', 1, function (test) { + casper + .start(lib.buildUrl('coding-rules'), function () { + lib.setDefaultViewport(); + + lib.mockRequest('/api/l10n/index', '{}'); + lib.mockRequestFromFile('/api/rules/app', 'app.json'); + this.searchMock = lib.mockRequestFromFile('/api/rules/search', 'search-before.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('.js-delete'); + }) + + .then(function () { + casper.click('.js-delete'); + casper.waitForSelector('[data-confirm="yes"]'); + }) + + .then(function () { + lib.clearRequestMock(this.searchMock); + lib.mockRequestFromFile('/api/rules/search', 'search-after.json'); + casper.click('[data-confirm="yes"]'); + casper.waitForSelectorTextChange('#coding-rules-total'); + }) + + .then(function () { + test.assertSelectorContains('#coding-rules-total', 0); + }) + + .run(function () { + test.done(); + }); +}); diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-rules/app.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-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-manual-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-manual-rules/search-after.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-rules/search-after.json new file mode 100644 index 00000000000..f43d117c569 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-rules/search-after.json @@ -0,0 +1,7 @@ +{ + "total": 0, + "p": 1, + "ps": 200, + "rules": [], + "facets": [] +} diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-rules/search-before.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-rules/search-before.json new file mode 100644 index 00000000000..1f19e1d27c2 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-rules/search-before.json @@ -0,0 +1,25 @@ +{ + "total": 1, + "p": 1, + "ps": 200, + "rules": [ + { + "key": "manual:Manual_Rule", + "name": "Manual Rule", + "sysTags": [], + "tags": [], + "status": "READY" + } + ], + "facets": [ + { + "property": "repositories", + "values": [ + { + "val": "manual", + "count": 1 + } + ] + } + ] +} diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-rules/show.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-rules/show.json new file mode 100644 index 00000000000..38190c28abb --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-should-delete-manual-rules/show.json @@ -0,0 +1,17 @@ +{ + "rule": { + "key": "manual:Manual_Rule", + "repo": "manual", + "name": "Manual Rule", + "createdAt": "2015-01-05T10:02:11+0100", + "status": "READY", + "isTemplate": false, + "tags": [], + "sysTags": [], + "htmlDesc": "Manual Rule Description", + "mdDesc": "Manual Rule Description", + "debtOverloaded": false, + "params": [] + }, + "actives": [] +} |