]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5851 filter list of profiles by language
authorStas Vilchik <vilchiks@gmail.com>
Fri, 17 Apr 2015 13:00:50 +0000 (15:00 +0200)
committerStas Vilchik <vilchiks@gmail.com>
Fri, 17 Apr 2015 13:20:42 +0000 (15:20 +0200)
server/sonar-web/src/main/hbs/quality-profiles/quality-profiles-actions.hbs
server/sonar-web/src/main/hbs/quality-profiles/quality-profiles-profiles-language.hbs
server/sonar-web/src/main/js/quality-profiles/actions-view.js
server/sonar-web/src/main/js/quality-profiles/app.js
server/sonar-web/src/main/js/quality-profiles/profile-view.js
server/sonar-web/src/main/js/quality-profiles/profiles-view.js
server/sonar-web/src/test/js/quality-profiles.js
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index b173c8ee77f2683eb7ea2ab99877f3351138c971..24fa188c8994b3d21d5521e61d459e3ffda7d67e 100644 (file)
@@ -1,26 +1,46 @@
-<h1 class="page-title">{{t 'quality_profiles.page'}}</h1>
+<header class="page-header">
+  <h1 class="page-title">{{t 'quality_profiles.page'}}</h1>
 
+  <div class="page-actions">
+    {{#if canWrite}}
+      <div class="button-group dropdown">
+        <button id="quality-profiles-create">{{t 'create'}}</button>
+        <a class="button dropdown-toggle" href="#" data-toggle="dropdown"><i class="icon-dropdown"></i></a>
+        <ul class="dropdown-menu dropdown-menu-right">
+          <li>
+            <a id="quality-profiles-compare" href="#">{{t 'quality_profiles.compare_profiles'}}</a>
+          </li>
+          <li>
+            <a id="quality-profiles-restore" href="#">{{t 'quality_profiles.restore_profile'}}</a>
+          </li>
+          <li>
+            <a id="quality-profiles-restore-built-in" href="#">{{t 'quality_profiles.restore_built_in_profiles'}}</a>
+          </li>
+        </ul>
+      </div>
+    {{else}}
+      <div class="button-group">
+        <button id="quality-profiles-compare">{{t 'quality_profiles.compare_profiles'}}</button>
+      </div>
+    {{/if}}
+  </div>
+</header>
 
-<div class="page-actions">
-  {{#if canWrite}}
-    <div class="button-group dropdown">
-      <button id="quality-profiles-create">{{t 'create'}}</button>
-      <a class="button dropdown-toggle" href="#" data-toggle="dropdown"><i class="icon-dropdown"></i></a>
-      <ul class="dropdown-menu dropdown-menu-right">
-        <li>
-          <a id="quality-profiles-compare" href="#">{{t 'quality_profiles.compare_profiles'}}</a>
-        </li>
-        <li>
-          <a id="quality-profiles-restore" href="#">{{t 'quality_profiles.restore_profile'}}</a>
-        </li>
-        <li>
-          <a id="quality-profiles-restore-built-in" href="#">{{t 'quality_profiles.restore_built_in_profiles'}}</a>
-        </li>
-      </ul>
-    </div>
+<div class="dropdown" id="quality-profiles-filter-by-language">
+  <span>Show:</span>
+  {{#if selectedLanguage}}
+    <a class="dropdown-toggle link-no-underline" href="#" data-toggle="dropdown">
+      {{tp 'quality_profiles.x_profiles' selectedLanguage.name}} <i class="icon-dropdown"></i>
+    </a>
   {{else}}
-    <div class="button-group">
-      <button id="quality-profiles-compare">{{t 'quality_profiles.compare_profiles'}}</button>
-    </div>
+    <a class="dropdown-toggle link-no-underline" href="#" data-toggle="dropdown">
+      {{t 'quality_profiles.all_profiles'}} <i class="icon-dropdown"></i>
+    </a>
   {{/if}}
+  <ul class="dropdown-menu">
+    <li><a class="js-filter-by-language" href="#">{{t 'quality_profiles.all_profiles'}}</a></li>
+    {{#each languages}}
+      <li><a class="js-filter-by-language" href="#" data-language="{{key}}">{{tp 'quality_profiles.x_profiles' name}}</a></li>
+    {{/each}}
+  </ul>
 </div>
index e7288e85f877b944158daff6ac34e13d0b82784a..f3ec16f0a9c7b0177b88e770dc54646e8a7898c3 100644 (file)
@@ -1 +1 @@
-<h6 class="spacer-top js-list-language">{{languageName}}</h6>
+<h6 class="spacer-top js-list-language" data-language="{{language}}">{{languageName}}</h6>
index 9cb0e2d3f980306bc126ce07e82d8b971a3f33bc..3581f909c1b47897062e3c82bdda953b9fd95bc2 100644 (file)
@@ -32,7 +32,9 @@ define([
     events: {
       'click #quality-profiles-create': 'onCreateClick',
       'click #quality-profiles-restore': 'onRestoreClick',
-      'click #quality-profiles-restore-built-in': 'onRestoreBuiltInClick'
+      'click #quality-profiles-restore-built-in': 'onRestoreBuiltInClick',
+
+      'click .js-filter-by-language': 'onLanguageClick'
     },
 
     onCreateClick: function (e) {
@@ -50,9 +52,15 @@ define([
       this.restoreBuiltIn();
     },
 
+    onLanguageClick: function (e) {
+      e.preventDefault();
+      var language = $(e.currentTarget).data('language');
+      this.filterByLanguage(language);
+    },
+
     create: function () {
       var that = this;
-      $.when(this.requestLanguages(), this.requestImporters()).done(function () {
+      this.requestImporters().done(function () {
         new CreateProfileView({
           collection: that.collection,
           languages: that.languages,
@@ -68,13 +76,10 @@ define([
     },
 
     restoreBuiltIn: function () {
-      var that = this;
-      this.requestLanguages().done(function (r) {
-        new RestoreBuiltInProfilesView({
-          collection: that.collection,
-          languages: r.languages
-        }).render();
-      });
+      new RestoreBuiltInProfilesView({
+        collection: this.collection,
+        languages: this.languages
+      }).render();
     },
 
     requestLanguages: function () {
@@ -93,9 +98,17 @@ define([
       });
     },
 
+    filterByLanguage: function (language) {
+      this.selectedLanguage = _.findWhere(this.languages, { key: language });
+      this.render();
+      this.collection.trigger('filter', language);
+    },
+
     serializeData: function () {
       return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
-        canWrite: this.options.canWrite
+        canWrite: this.options.canWrite,
+        languages: this.languages,
+        selectedLanguage: this.selectedLanguage
       });
     }
   });
index d139f2b17b55759c03d84caf8e12caa855a0ef15..e2650a470ffc883bda04196737896ae44e20811d 100644 (file)
@@ -46,7 +46,9 @@ require([
       collection: this.profiles,
       canWrite: this.canWrite
     });
-    this.layout.actionsRegion.show(this.actionsView);
+    this.actionsView.requestLanguages().done(function () {
+      App.layout.actionsRegion.show(App.actionsView);
+    });
 
     // Profiles View
     this.profilesView = new ProfilesView({
index 680cc25d6135243e31842a928c1b3cc132524f66..d2d42aee324976dc6fc9cf1ce825364b226164e7 100644 (file)
@@ -37,6 +37,7 @@ define([
     onRender: function () {
       this.$el.toggleClass('active', this.options.highlighted);
       this.$el.attr('data-key', this.model.id);
+      this.$el.attr('data-language', this.model.get('language'));
       this.$('[data-toggle="tooltip"]').tooltip({ container: 'body' });
     },
 
index fe2e1a97dd8560818d508b52dbe053c5528b0dc3..7909647c32ce16c0d0762554af254422099af146 100644 (file)
@@ -29,6 +29,10 @@ define([
     itemView: ProfileView,
     itemViewContainer: '.js-list',
 
+    collectionEvents: {
+      'filter': 'filterByLanguage'
+    },
+
     itemViewOptions: function (model) {
       return {
         collectionView: this,
@@ -64,7 +68,16 @@ define([
     closeChildren: function () {
       Marionette.CompositeView.prototype.closeChildren.apply(this, arguments);
       this.$('.js-list-language').remove();
-    }
+    },
+
+    filterByLanguage: function (language) {
+      if (language) {
+        this.$('[data-language]').addClass('hidden');
+        this.$('[data-language="' + language + '"]').removeClass('hidden');
+      } else {
+        this.$('[data-language]').removeClass('hidden');
+      }
+    },
   });
 
 });
index 04e2632639c566cb30b7b8d7061845145a04d50e..796a395997a62ea0de815da7ed5f771db3ad7093 100644 (file)
@@ -34,6 +34,7 @@ casper.test.begin(testName('Should Show List'), 9, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user.json');
         lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
       })
 
       .then(function () {
@@ -70,6 +71,69 @@ casper.test.begin(testName('Should Show List'), 9, function (test) {
 });
 
 
+casper.test.begin(testName('Should Filter List By Language'), 15, function (test) {
+  casper
+      .start(lib.buildUrl('profiles'), function () {
+        lib.setDefaultViewport();
+
+        lib.mockRequestFromFile('/api/users/current', 'user.json');
+        lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
+      })
+
+      .then(function () {
+        casper.evaluate(function () {
+          require(['/js/quality-profiles/app.js']);
+        });
+      })
+
+      .then(function () {
+        casper.waitForSelector('.js-list .list-group-item');
+      })
+
+      .then(function () {
+        test.assertElementCount('.js-list .list-group-item', 5);
+        test.assertVisible('.js-list .list-group-item[data-key="java-sonar-way-67887"]');
+        test.assertVisible('.js-list .list-group-item[data-key="js-sonar-way-71566"]');
+
+        test.assertElementCount('.js-list-language', 4);
+        test.assertVisible('.js-list-language[data-language="java"]');
+        test.assertVisible('.js-list-language[data-language="js"]');
+      })
+
+      .then(function () {
+        test.assertExists('#quality-profiles-filter-by-language');
+        casper.click('.js-filter-by-language[data-language="js"]');
+      })
+
+      .then(function () {
+        test.assertNotVisible('.js-list .list-group-item[data-key="java-sonar-way-67887"]');
+        test.assertVisible('.js-list .list-group-item[data-key="js-sonar-way-71566"]');
+        test.assertNotVisible('.js-list-language[data-language="java"]');
+        test.assertVisible('.js-list-language[data-language="js"]');
+      })
+
+      .then(function () {
+        casper.click('.js-filter-by-language:nth-child(1)');
+      })
+
+      .then(function () {
+        test.assertVisible('.js-list .list-group-item[data-key="java-sonar-way-67887"]');
+        test.assertVisible('.js-list .list-group-item[data-key="js-sonar-way-71566"]');
+        test.assertVisible('.js-list-language[data-language="java"]');
+        test.assertVisible('.js-list-language[data-language="js"]');
+      })
+
+      .then(function () {
+        lib.sendCoverage();
+      })
+
+      .run(function () {
+        test.done();
+      });
+});
+
+
 casper.test.begin(testName('Should Show Details'), 10, function (test) {
   casper
       .start(lib.buildUrl('profiles'), function () {
@@ -77,6 +141,7 @@ casper.test.begin(testName('Should Show Details'), 10, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user.json');
         lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json',
             { data: { qprofile: 'java-sonar-way-67887', activation: 'true' }});
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json', {
@@ -130,6 +195,7 @@ casper.test.begin(testName('Should Show Details', 'Admin'), 10, function (test)
 
         lib.mockRequestFromFile('/api/users/current', 'user-admin.json');
         lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json',
             { data: { qprofile: 'java-sonar-way-67887', activation: 'true' }});
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json', {
@@ -183,6 +249,7 @@ casper.test.begin(testName('Should Show Inheritance Details'), 10, function (tes
 
         lib.mockRequestFromFile('/api/users/current', 'user-admin.json');
         lib.mockRequestFromFile('/api/qualityprofiles/search', 'search-inheritance.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance-plus.json', {
           data: { profileKey: 'java-inherited-profile-85155' }
@@ -236,6 +303,7 @@ casper.test.begin(testName('Should Show Selected Projects'), 2, function (test)
 
         lib.mockRequestFromFile('/api/users/current', 'user-admin.json');
         lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         lib.mockRequestFromFile('/api/qualityprofiles/projects?key=php-psr-2-46772', 'projects.json');
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json');
@@ -282,6 +350,7 @@ casper.test.begin(testName('Copy Profile'), 5, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user-admin.json');
         lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json');
         lib.mockRequestFromFile('/api/qualityprofiles/copy', 'copy.json', {
@@ -343,6 +412,7 @@ casper.test.begin(testName('Rename Profile'), 2, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user-admin.json');
         this.searchMock = lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json');
         lib.mockRequest('/api/qualityprofiles/rename', '{}', {
@@ -404,6 +474,7 @@ casper.test.begin(testName('Make Profile Default'), 4, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user-admin.json');
         this.searchMock = lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json');
         lib.mockRequest('/api/qualityprofiles/set_default', '{}', {
@@ -459,6 +530,7 @@ casper.test.begin(testName('Delete Profile'), 2, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user-admin.json');
         this.searchMock = lib.mockRequestFromFile('/api/qualityprofiles/search', 'search-with-copy.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json');
         lib.mockRequest('/api/qualityprofiles/delete', '{}', {
@@ -573,6 +645,7 @@ casper.test.begin(testName('Restore Profile'), 2, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user-admin.json');
         this.searchMock = lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json');
       })
@@ -739,6 +812,7 @@ casper.test.begin(testName('Change Parent'), 1, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user-admin.json');
         this.searchMock = lib.mockRequestFromFile('/api/qualityprofiles/search', 'search-change-parent.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         this.inheritanceMock = lib.mockRequestFromFile('/api/qualityprofiles/inheritance',
             'inheritance-change-parent.json');
@@ -802,6 +876,7 @@ casper.test.begin(testName('Permalink'), 9, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user-admin.json');
         lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json');
       })
@@ -846,6 +921,7 @@ casper.test.begin(testName('Changelog'), 21, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user.json');
         lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json');
         lib.mockRequestFromFile('/api/qualityprofiles/changelog', 'changelog2.json', {
@@ -922,6 +998,7 @@ casper.test.begin(testName('Changelog Permalink'), 2, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user.json');
         lib.mockRequestFromFile('/api/qualityprofiles/search', 'search.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json');
         lib.mockRequestFromFile('/api/qualityprofiles/changelog', 'changelog2.json', {
@@ -979,6 +1056,7 @@ casper.test.begin(testName('Comparison'), 12, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user.json');
         lib.mockRequestFromFile('/api/qualityprofiles/search', 'search-with-copy.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json');
         lib.mockRequestFromFile('/api/qualityprofiles/compare', 'compare.json', {
@@ -1036,6 +1114,7 @@ casper.test.begin(testName('Comparison Permalink'), 4, function (test) {
 
         lib.mockRequestFromFile('/api/users/current', 'user.json');
         lib.mockRequestFromFile('/api/qualityprofiles/search', 'search-with-copy.json');
+        lib.mockRequestFromFile('/api/languages/list', 'languages.json');
         lib.mockRequestFromFile('/api/rules/search', 'rules.json');
         lib.mockRequestFromFile('/api/qualityprofiles/inheritance', 'inheritance.json');
         lib.mockRequestFromFile('/api/qualityprofiles/compare', 'compare.json', {
index b1eb6e9d794744fdf83b0102c154c6c9d2d2a00b..3b08fd16d2c4c03f6b48c8354c230e5d3d8a2dfd 100644 (file)
@@ -1792,6 +1792,8 @@ quality_profiles.inherits=Inherits "{0}"
 quality_profile.x_active_rules={0} active rules
 quality_profiles.x_overridden_rules={0} overridden rules
 quality_profiles.change_parent=Change Parent
+quality_profiles.all_profiles=All Profiles
+quality_profiles.x_profiles={0} Profiles