]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4851 More criteria dropdown, favorite filters
authorStas Vilchik <vilchiks@gmail.com>
Fri, 8 Nov 2013 07:25:49 +0000 (13:25 +0600)
committerStas Vilchik <vilchiks@gmail.com>
Fri, 8 Nov 2013 07:25:49 +0000 (13:25 +0600)
sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/views/issues/_filter_favourites2.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/issues/search2.html.erb
sonar-server/src/main/webapp/javascripts/navigator/app.js
sonar-server/src/main/webapp/javascripts/navigator/filters.js
sonar-server/src/main/webapp/stylesheets/navigator.css
sonar-server/src/main/webapp/stylesheets/navigator.less

index 319c23062218e7b0106418df07f0f3386eac884a..a15a6e7b626aaad114331017343a04c6a678eacf 100644 (file)
@@ -22,7 +22,7 @@ require 'set'
 class IssuesController < ApplicationController
 
   before_filter :init_options
-  before_filter :load_fav_filters, :only => [:index, :search, :filter, :manage, :favourites, :toggle_fav]
+  before_filter :load_fav_filters, :only => [:index, :search, :search2, :filter, :manage, :favourites, :toggle_fav]
 
   PAGE_SIZE = 100
 
@@ -54,7 +54,7 @@ class IssuesController < ApplicationController
     end
   end
 
-  # GET /issues/search
+  # GET /issues/search2
   def search2
     @issues_query_params = criteria_params
     @first_search = issues_query_params_sanitized.empty?
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_filter_favourites2.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_filter_favourites2.html.erb
new file mode 100644 (file)
index 0000000..dc1bd72
--- /dev/null
@@ -0,0 +1,21 @@
+<% if logged_in? %>
+<div style="border-bottom: 1px solid #ccc; padding-bottom: 10px;">
+  <ul>
+    <% if !@favourite_filters.empty? %>
+      <% @favourite_filters.each do |filter| %>
+        <li>
+          <a href="<%= ApplicationController.root_context -%>/issues/filter/<%= filter.id -%>"><%= h filter.name -%></a>
+        </li>
+      <% end %>
+    <% else %>
+      <li>No favorite filters</li>
+    <% end %>
+  </ul>
+</div>
+
+<div>
+  <ul>
+    <li><a href="<%= ApplicationController.root_context -%>/issues/manage" class="link-action"><%= message('manage') %></a></li>
+  </ul>
+</div>
+<% end %>
index 6bd2ffee8db28dbad58d836fe1920403171caf3b..5a79e409b2f7f6ab03f10fb70706cbd97825b435 100644 (file)
       <a class="navigator-filters-favorite-toggle" onclick="showDropdownMenu('favorite-filters'); return false;"></a>
 
       <div id="favorite-filters" class="dropdown-menu" style="max-width: none; display: none; font-size: 12px;">
-        <div style="border-bottom: 1px solid #ccc; padding-bottom: 10px;">
-          <ul>
-            <li><a href="#">First filter set</a></li>
-            <li><a href="#">Second filter set</a></li>
-            <li><a href="#">Third filter set</a></li>
-          </ul>
-        </div>
-
-        <div>
-          <ul>
-            <li><a href="#">Manage</a></li>
-          </ul>
-        </div>
+        <%= render :partial => 'issues/filter_favourites2' -%>
       </div>
     </div>
 
     <div class="navigator-filters-list"></div>
+    <div class="navigator-filters-actions">
+      <select class="navigator-disabled-filters"></select>
+    </div>
   </form>
 </script>
 
index 9820dbd453b924e696721392cd4daaf14027183e..6a01e062631f937d4825414a9315697b5ef2bcc0 100644 (file)
@@ -1,4 +1,4 @@
-/* global $j:false, Backbone:false */
+/* global $j:false, Backbone:false, baseUrl:false */
 
 window.SS = typeof window.SS === 'object' ? window.SS : {};
 
@@ -21,11 +21,12 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
           name: 'Project',
           property: 'componentRoots',
           type: window.SS.AjaxSelectFilterView,
+          enabled: true,
           select2 : {
             allowClear: true,
             ajax: {
               quietMillis: 300,
-              url: '/dev/api/resources/search?f=s2&q=TRK&display_key=true',
+              url: baseUrl + '/api/resources/search?f=s2&q=TRK&display_key=true',
               data: function (term, page) { return { s: term, p: page }; },
               results: function (data) { return { more: data.more, results: data.results }; }
             }
@@ -36,6 +37,7 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
           name: 'Severity',
           property: 'severities[]',
           type: window.SS.SelectFilterView,
+          enabled: true,
           choices: window.SS.severities
         }),
 
@@ -43,6 +45,7 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
           name: 'Status',
           property: 'statuses[]',
           type: window.SS.SelectFilterView,
+          enabled: true,
           choices: window.SS.statuses
         }),
 
@@ -50,6 +53,7 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
           name: 'Resolution',
           property: 'resolutions[]',
           type: window.SS.SelectFilterView,
+          enabled: false,
           choices: window.SS.resolutions
         }),
 
@@ -57,6 +61,7 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
           name: 'Assignee',
           property: 'assignees',
           type: window.SS.AjaxSelectFilterView,
+          enabled: true,
           select2: {
             allowClear: true,
             query:
@@ -64,7 +69,7 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
                   if (query.term.length === 0) {
                     query.callback({results: [{id:'<unassigned>',text:'Unassigned'}]});
                   } else if (query.term.length >= 2) {
-                    $j.ajax('/dev/api/users/search?f=s2', {
+                    $j.ajax(baseUrl + '/api/users/search?f=s2', {
                       data: {s: query.term},
                       dataType: 'jsonp'
                     }).done(function(data) {
@@ -79,7 +84,8 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
           name: 'Created',
           propertyFrom: 'createdAfter',
           propertyTo: 'createdBefore',
-          type: window.SS.RangeFilterView
+          type: window.SS.RangeFilterView,
+          enabled: false
         })
     ]);
 
index 0336b007d9425da5aa6aaf5ff4fa8b351d0533d5..4d99cdf515a7b79fecc0540824f35f1fd42e2190 100644 (file)
@@ -1,54 +1,75 @@
-/* global _:false, $j:false, Backbone:false */
+/* global _:false, $j:false, Backbone:false, baseUrl:false */
 
 window.SS = typeof window.SS === 'object' ? window.SS : {};
 
 (function() {
 
-  var Filter = Backbone.Model.extend({
+  var Filter = Backbone.Model.extend({});
+
 
-  });
 
   var Filters = Backbone.Collection.extend({
     model: Filter
   });
 
 
+
   var BaseFilterView = Backbone.Marionette.ItemView.extend({
     template: '#filterTemplate',
     className: 'navigator-filter',
 
+
     events: function() {
       return {};
     },
 
+
+    modelEvents: {
+      "change:enabled": "render"
+    },
+
+
+    initialize: function() {
+      Backbone.Marionette.ItemView.prototype.initialize.call(this, arguments);
+      this.model.view = this;
+    },
+
+
+    render: function() {
+      Backbone.Marionette.ItemView.prototype.render.call(this, arguments);
+
+      this.$el.toggleClass(
+          'navigator-filter-disabled',
+          !this.model.get('enabled'));
+    },
+
+
     renderBody: function() {
       return '';
     },
 
+
     serializeData: function() {
       return _.extend({}, this.model.toJSON(), {
         body: this.renderBody()
       });
     },
 
-    restore: function() {
 
-    }
+    restore: function() {}
   });
 
 
-  var SelectFilterView = BaseFilterView.extend({
 
-    modelEvents: {
-      "change": "render"
-    },
+  var SelectFilterView = BaseFilterView.extend({
 
     renderBody: function() {
       var template = _.template($j('#selectFilterTemplate').html());
       return template(this.model.toJSON());
     },
 
-    onRender: function() {
+
+    onDomRefresh: function() {
       var that = this;
 
       this.$('.navigator-filter-label').hide();
@@ -60,18 +81,21 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
       }).on('change', function(e) {
             that.model.set('value', e.val);
           });
-
-      this.restore();
     },
 
+
     restore: function() {
       if (this.model.get('value')) {
         this.$(':input').select2('val', this.model.get('value'));
       }
-    }
+    },
+
+
+    focus: function() {}
   });
 
 
+
   var AjaxSelectFilterView = BaseFilterView.extend({
 
     renderBody: function() {
@@ -79,7 +103,7 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
       return template(this.model.toJSON());
     },
 
-    onRender: function() {
+    onDomRefresh: function() {
       var that = this;
 
       this.$('.navigator-filter-label').hide();
@@ -93,18 +117,19 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
           .on('change', function(e) {
             that.model.set('value', e.val);
           });
-
-      this.restore();
     },
 
     restore: function() {
       if (this.model.get('value')) {
         this.$(':input').select2('data', this.model.get('value'));
       }
-    }
+    },
+
+    focus: function() {}
   });
 
 
+
   var RangeFilterView = BaseFilterView.extend({
 
     events: function() {
@@ -113,27 +138,38 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
       });
     },
 
+
     renderBody: function() {
       var template = _.template($j('#rangeFilterTemplate').html());
       return template(this.model.toJSON());
     },
 
+
     onRender: function() {
-      this.restore();
+      this.inputFrom = this.$('[name="' + this.model.get('propertyFrom') + '"]');
+      this.inputTo = this.$('[name="' + this.model.get('propertyTo') + '"]');
     },
 
+
     changeInput: function() {
       this.model.set('value', {
-        from: '',
-        to: ''
+        from: this.inputFrom.val(),
+        to: this.inputTo.val()
       });
     },
 
+
     restore: function() {
-      if (this.model.get('value')) {
-        this.$('[name="' + this.model.get('propertyFrom') + '"]').val(this.model.get('value').from);
-        this.$('[name="' + this.model.get('propertyTo') + '"]').val(this.model.get('value').to);
+      var value = this.model.get('value');
+      if (typeof value === 'object') {
+        this.inputFrom.val(value.from || '');
+        this.inputTo.val(value.to || '');
       }
+    },
+
+
+    focus: function() {
+      this.inputFrom.focus();
     }
 
   });
@@ -143,10 +179,18 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
     template: '#filterBarTemplate',
     itemViewContainer: '.navigator-filters-list',
 
+
     collectionEvents: {
-      'change': 'changeFilters'
+      'change:value': 'changeFilters',
+      'change:enabled': 'renderDisabledFilters'
+    },
+
+
+    ui: {
+      disabledFilters: '.navigator-disabled-filters'
     },
 
+
     getItemView: function(item) {
       return item.get('type') || BaseFilterView;
     },
@@ -158,6 +202,52 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
       };
     },
 
+
+    render: function() {
+      Backbone.Marionette.CompositeView.prototype.render.call(this, arguments);
+      this.renderDisabledFilters();
+    },
+
+
+    renderDisabledFilters: function() {
+      var that = this,
+          disabledFilters = this.collection.where({ enabled: false });
+
+      that.ui.disabledFilters.select2('destroy').empty().show();
+
+      if (disabledFilters.length > 0) {
+        $j('<option>').appendTo(that.ui.disabledFilters);
+        _.each(disabledFilters, function(item) {
+          $j('<option>').text(item.get('name')).prop('value', item.cid)
+              .appendTo(that.ui.disabledFilters);
+        });
+        that.ui.disabledFilters.select2({
+          allowClear: true,
+          placeholder: 'More criteria',
+          width: '150px'
+        }).on('change', function(e) {
+              that.ui.disabledFilters.select2('val', '');
+              that.enableFilter(e.val);
+            });
+      } else {
+        that.ui.disabledFilters.hide();
+      }
+    },
+
+
+    enableFilter: function(key) {
+      var item = this.collection.find(function(item) {
+        return item.cid === key;
+      });
+
+      if (item) {
+        item.view.$el.detach().appendTo(this.itemViewContainer);
+        item.set('enabled', true);
+        item.view.focus();
+      }
+    },
+
+
     changeFilters: function() {
       var query = {};
       this.collection.each(function(item) {
@@ -168,9 +258,10 @@ window.SS = typeof window.SS === 'object' ? window.SS : {};
       this.applyQuery($j.param(query));
     },
 
+
     applyQuery: function(query) {
       $j.ajax({
-        url: '/dev/issues/search',
+        url: baseUrl + '/issues/search',
         type: 'get',
         data: query
       }).done(function(r) {
index 7541faff6730e67d05bd3e7e9da7046bce221691..146ed8be9bf6b14e9419ae4bddb2aa0e08391071 100644 (file)
   vertical-align: middle;
   font-size: 0;
 }
-input.navigator-filters-search[type=submit] {
+.navigator-filters-actions {
   display: inline-block;
   vertical-align: middle;
   margin-left: 20px;
+  font-size: 14px;
 }
 .navigator-filter {
   display: inline-block;
@@ -57,6 +58,9 @@ input.navigator-filters-search[type=submit] {
 .navigator-filter + .navigator-filter {
   margin-left: 20px;
 }
+.navigator-filter-disabled {
+  display: none;
+}
 .navigator-filter-label {
   display: inline-block;
   vertical-align: middle;
@@ -73,9 +77,6 @@ input.navigator-filters-search[type=submit] {
   color: #000;
   font-size: 14px;
 }
-.navigator-filter-body input {
-  font-size: 12px;
-}
 .navigator-filter-range-input {
   width: 80px;
 }
index 5903791c4c549b2f2b8d8a0a00d5d03db5d52883..031988f5f6172eeb080132480dbfaf2c064318a9 100644 (file)
   font-size: 0;
 }
 
-input.navigator-filters-search[type=submit] {
+.navigator-filters-actions {
   display: inline-block;
   vertical-align: middle;
   margin-left: 20px;
+  font-size: 14px;
 }
 
 .navigator-filter {
@@ -69,8 +70,10 @@ input.navigator-filters-search[type=submit] {
 
 .navigator-filter + .navigator-filter {
   margin-left: 20px;
-//  padding-left: 14px;
-//  border-left: 1px solid @darkGrey;
+}
+
+.navigator-filter-disabled {
+  display: none;
 }
 
 .navigator-filter-label {
@@ -88,10 +91,6 @@ input.navigator-filters-search[type=submit] {
   vertical-align: middle;
   color: #000;
   font-size: 14px;
-
-  input {
-    font-size: 12px;
-  }
 }
 
 .navigator-filter-range-input {