Browse Source

[search] Date range facets support

Romain Rigaux 12 years ago
parent
commit
f497174

+ 15 - 13
apps/search/src/search/models.py

@@ -45,8 +45,8 @@ class Facet(models.Model):
 
   def update_from_post(self, post_data):
     data_dict = json.loads(self.data)
-    
-    for attr in Sorting._META_TEMPLATE_ATTRS:
+
+    for attr in Facet._ATTRIBUTES:
       if post_data.get(attr):
         data_dict[attr] = json.loads(post_data[attr])
 
@@ -56,11 +56,13 @@ class Facet(models.Model):
   def get_query_params(self):
     data_dict = json.loads(self.data)
 
+    properties = data_dict.get('properties')
+    
     params = (
-        ('facet', data_dict.get('properties', {}).get('is_enabled') and 'true' or 'false'),
-        ('facet.limit', 10),
-        ('facet.mincount', 1),
-        ('facet.sort', 'count'),
+        ('facet', properties.get('isEnabled') and 'true' or 'false'),
+        ('facet.limit', properties.get('limit')),
+        ('facet.mincount', properties.get('mincount')),
+        ('facet.sort', properties.get('sort')),
     )
 
     if data_dict.get('fields'):
@@ -83,8 +85,8 @@ class Facet(models.Model):
         end = datetime.strptime(field_facet['end'], '%m-%d-%Y') - datetime.now()
         range_facets = tuple([
                            ('facet.date', field_facet['field']),
-                           ('f.%s.facet.date.start' % field_facet['field'], 'NOW/DAY%sDAYS' % start.days),
-                           ('f.%s.facet.date.end' % field_facet['field'], 'NOW/DAY%sDAY' % end.days),
+                           ('f.%s.facet.date.start' % field_facet['field'], '%sDAYS/DAY' % start.days),
+                           ('f.%s.facet.date.end' % field_facet['field'], '%sDAYS/DAY' % end.days),
                            ('f.%s.facet.date.gap' % field_facet['field'], '+%sDAY' % field_facet['gap']),]
                         )
         params += range_facets
@@ -93,14 +95,14 @@ class Facet(models.Model):
 
 
 class Result(models.Model):
-  _META_TEMPLATE_ATTRS = ['properties', 'template', 'highlighting']
+  _ATTRIBUTES = ['properties', 'template', 'highlighting']
 
   data = models.TextField()
 
   def update_from_post(self, post_data):
     data_dict = json.loads(self.data)
 
-    for attr in Result._META_TEMPLATE_ATTRS:
+    for attr in Result._ATTRIBUTES:
       if post_data.get(attr):
         data_dict[attr] = json.loads(post_data[attr])
 
@@ -132,14 +134,14 @@ class Result(models.Model):
 
 
 class Sorting(models.Model):
-  _META_TEMPLATE_ATTRS = ['properties', 'fields']
+  _ATTRIBUTES = ['properties', 'fields']
 
   data = models.TextField()
 
   def update_from_post(self, post_data):
     data_dict = json.loads(self.data)
 
-    for attr in Sorting._META_TEMPLATE_ATTRS:
+    for attr in Sorting._ATTRIBUTES:
       if post_data.get(attr):
         data_dict[attr] = json.loads(post_data[attr])
 
@@ -171,7 +173,7 @@ class CoreManager(models.Manager):
       return self.get(name=name)
     except Core.DoesNotExist:
       facets = Facet.objects.create(data=json.dumps({
-                   'properties': {'is_enabled': False},
+                   'properties': {'isEnabled': False, 'limit': 10, 'mincount': 1, 'sort': 'count'},
                    'ranges': [],
                    'fields': [],
                    'dates': []

+ 75 - 17
apps/search/src/search/templates/admin_core_facets.mako

@@ -51,9 +51,34 @@ ${ commonheader(_('Search'), "search", user) | n,unicode }
             ${_('Facets provide an intuitive way to filter the results.')}
             ${_('Different types of facets can be added on the following steps.')}
           </p>
-          <p>
-            <input type='checkbox' data-bind="checked: isEnabled" style="margin-top: -2px; margin-right: 4px"/> ${_('Enabled') }
-          </p>
+
+	      <div class="control-group"">
+	        <label class="control-label"> ${_('Enabled') }</label>
+	        <div class="controls">
+	          <input type='checkbox' data-bind="checked: properties().isEnabled" />	           
+	        </div>
+	      </div>
+          <div class="control-group"">
+            <label class="control-label"> ${_('Limit') }</label>
+            <div class="controls">
+              <input type='number' data-bind="value: properties().limit" class="input-mini"/>
+            </div>
+          </div>
+          <div class="control-group"">
+            <label class="control-label"> ${_('Mincount') }</label>
+            <div class="controls">
+              <input type='number' data-bind="value: properties().mincount" class="input-mini"/>
+            </div>
+          </div>          
+          <div class="control-group"">
+            <label class="control-label"> ${_('Sort') }</label>
+            <div class="controls">
+              <select data-bind="value: properties().sort">
+                <option value="count">count</option>
+                <option value="index">index</option>
+              </select>
+            </div>
+          </div>          
         </div>
 
         <div id="step2" class="stepDetails hide">
@@ -102,7 +127,7 @@ ${ commonheader(_('Search'), "search", user) | n,unicode }
           &nbsp;${_('End')}
           <input type="number" data-bind="value: selectedRangeEndFacet" class="input-mini" />
           &nbsp;${_('Gap')}
-          <input type="number" data-bind="value: selectedRangeGapFacet" class="input-mini" />
+          <input type="number" data-bind="value: selectedRangeGapFacet" class="input-mini" />          
           <a class="btn" data-bind="click: $root.addRangeFacet"><i class="icon-plus"></i> ${_('Add')}</a>
         </div>
       </div>
@@ -132,6 +157,12 @@ ${ commonheader(_('Search'), "search", user) | n,unicode }
           <input id="dp-end" class="input-small" type="text" data-bind="value: selectedDateEndFacet" />
           &nbsp;${_('Gap')}
           <input type="number" data-bind="value: selectedDateGapFacet" class="input-mini" />
+          ##           <input type='checkbox' data-bind="checked: properties().isVerbatim" />
+          
+          ##<input class="input-mini" type="number" data-bind="value: selectedDateDateMaths()[0].frequency" />
+          ##<input class="input-small" type="text" data-bind="value: selectedDateDateMaths()[0].unit" />
+          ##<input class="input-small" type="text" data-bind="value: selectedDateDateMaths()[0].unit" />
+          
           <a class="btn" data-bind="click: $root.addDateFacet"><i class="icon-plus"></i> ${_('Add')}</a>
         </div>
       </div>
@@ -153,9 +184,11 @@ ${ commonheader(_('Search'), "search", user) | n,unicode }
 <script src="/static/ext/js/routie-0.3.0.min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/bootstrap-datepicker.min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/bootstrap-editable.min.js"></script>
+<script src="/static/ext/js/moment.min.js" type="text/javascript" charset="utf-8"></script>
 
 <script type="text/javascript">
   var DATE_FORMAT = "mm-dd-yyyy";
+  var MOMENT_DATE_FORMAT = "MM-DD-YYYY";
 
   var Facet = function (type, field, start, end, gap) {
     return {
@@ -163,7 +196,9 @@ ${ commonheader(_('Search'), "search", user) | n,unicode }
       field: field,
       start: start,
       end: end,
-      gap: gap
+      gap: gap,
+      isVerbatim: false,
+      verbatim: ""
     }
   }
 
@@ -179,6 +214,25 @@ ${ commonheader(_('Search'), "search", user) | n,unicode }
     return new Facet("date", field, start, end, gap);
   }
 
+  var Properties = function (properties) {
+    var self = this;
+
+    self.isEnabled = ko.observable(properties.isEnabled);
+    self.limit = ko.observable(properties.limit);
+    self.mincount = ko.observable(properties.mincount);
+    self.sort = ko.observable(properties.sort);    
+  }
+  
+  var DateMath = function (frequency, unit, isRounded, isVerbatim, verbatim) {
+    var self = this;
+
+    self.frequency = ko.observable(frequency);
+    self.unit = ko.observable(unit);
+    self.isVerbatim = ko.observable(typeof isVerbatim !== 'undefined' ? isVerbatim : true);
+    self.verbatim = ko.observable(unit);
+    self.isRounded = ko.observable(typeof isRounded !== 'undefined' ? isRounded : true);    
+  }
+
   function ViewModel() {
     var self = this;
 
@@ -190,8 +244,8 @@ ${ commonheader(_('Search'), "search", user) | n,unicode }
     $.each(${ hue_core.fields_data | n,unicode }, function(index, field) {
       self.fullFields[field.name] = field;
     });
-
-    self.isEnabled = ko.observable(${ hue_core.facets.data | n,unicode }.properties.is_enabled);
+    
+    self.properties = ko.observable(new Properties(${ hue_core.facets.data | n,unicode }.properties));
 
     self.fieldFacets = ko.observableArray(ko.utils.arrayMap(${ hue_core.facets.data | n,unicode }.fields, function (obj) {
       return new FieldFacet(obj.field);
@@ -229,14 +283,19 @@ ${ commonheader(_('Search'), "search", user) | n,unicode }
 
     self.selectedFieldFacet = ko.observable();
     self.selectedRangeFacet = ko.observable();
-    self.selectedRangeStartFacet = ko.observable("");
-    self.selectedRangeEndFacet = ko.observable("");
-    self.selectedRangeGapFacet = ko.observable("");
+    self.selectedRangeStartFacet = ko.observable(0);
+    self.selectedRangeEndFacet = ko.observable(100);
+    self.selectedRangeGapFacet = ko.observable(10);
+    
     self.selectedDateFacet = ko.observable();
-    self.selectedDateStartFacet = ko.observable("");
-    self.selectedDateEndFacet = ko.observable("");
-    self.selectedDateGapFacet = ko.observable("");
-
+    self.selectedDateStartFacet = ko.observable(moment().subtract('days', 10).format(MOMENT_DATE_FORMAT));
+    self.selectedDateEndFacet = ko.observable(moment().format(MOMENT_DATE_FORMAT));
+    self.selectedDateGapFacet = ko.observable(10);
+    self.selectedDateIsVerbatim = ko.observable(false);
+
+    self.selectedDateDateMaths = ko.observableArray([new DateMath(10, 'DAY')]);
+    
+    
     self.removeFieldFacet = function (facet) {
       self.fieldFacets.remove(facet);
       self.fieldFacetsList.push(facet.field);
@@ -261,7 +320,7 @@ ${ commonheader(_('Search'), "search", user) | n,unicode }
       if (!found){
         self.fieldFacets.push(new FieldFacet(self.selectedFieldFacet()));
         self.fieldFacetsList.remove(self.selectedFieldFacet());
-        self.isEnabled(true);
+        self.properties().isEnabled(true);
       }
       else {
         $("#field-facet-error").show();
@@ -285,7 +344,7 @@ ${ commonheader(_('Search'), "search", user) | n,unicode }
     self.submit = function () {
       $.ajax("${ url('search:admin_core_facets', core=hue_core.name) }", {
         data: {
-          'properties': ko.utils.stringifyJson({'is_enabled': self.isEnabled()}),
+          'properties': ko.toJSON(self.properties),
           'fields': ko.utils.stringifyJson(self.fieldFacets),
           'ranges': ko.utils.stringifyJson(self.rangeFacets),
           'dates': ko.utils.stringifyJson(self.dateFacets)
@@ -410,4 +469,3 @@ ${ commonheader(_('Search'), "search", user) | n,unicode }
 </script>
 
 ${ commonfooter(messages) | n,unicode }
-

+ 2 - 2
apps/search/src/search/templates/layout.mako

@@ -74,7 +74,7 @@
       </div>
     </li>
       <li class="${ utils.is_selected(section, 'properties') }">
-        <a href="${ url('search:admin_core_properties', core=core) }">${_('Properties')}</a>
+        <a href="${ url('search:admin_core_properties', core=core) }"><i class="icon-reorder"></i> ${_('Properties')}</a>
       </li>
 
       <li class="nav-header">${_('Template')}</li>
@@ -92,7 +92,7 @@
       </li>
       <li class="nav-header">${_('Search')}</li>
       <li>
-        <a href="${ url('search:index') }?cores=${ core }" target="_blank"><i class="icon-share-alt"></i> ${ _('Query') }</a>
+        <a href="${ url('search:index') }?cores=${ core }"><i class="icon-share-alt"></i> ${ _('Query') }</a>
       </li>
 
       ##<li class="nav-header">${_('Solr')}</li>