Explorar o código

HUE-2173 [search] Skeleton of Analytic timeline widget

Romain Rigaux %!s(int64=9) %!d(string=hai) anos
pai
achega
cbf166e07a

+ 5 - 1
apps/search/src/search/static/search/js/search.ko.js

@@ -948,7 +948,7 @@ var Collection = function (vm, collection) {
     return _fields;
   });
   self.template.availableWidgetFields = ko.computed(function() {
-    if (self.template.fieldsModalType() == 'histogram-widget') {
+    if (self.template.fieldsModalType() == 'histogram-widget' || self.template.fieldsModalType() == 'timeline-widget') {
       return vm.availableDateFields();
     }
     else if (self.template.fieldsModalType() == 'line-widget') {
@@ -1351,6 +1351,7 @@ var SearchViewModel = function (collection_json, query_json, initial_json) {
   self.draggableHeatmap = ko.observable(bareWidgetBuilder("Heatmap", "heatmap-widget"));
   self.draggableCounter = ko.observable(bareWidgetBuilder("Counter", "hit-widget"));
   self.draggableBucket = ko.observable(bareWidgetBuilder("Chart", "bucket-widget"));
+  self.draggableTimeline = ko.observable(bareWidgetBuilder("Timeline", "timeline-widget"));
 
   self.availableDateFields = ko.computed(function() {
     return $.grep(self.collection.availableFacetFields(), function(field) { return DATE_TYPES.indexOf(field.type()) != -1; });
@@ -1381,6 +1382,9 @@ var SearchViewModel = function (collection_json, query_json, initial_json) {
   self.availableDraggableHistogram = ko.computed(function() {
     return self.availableDateFields().length > 0;
   });
+  self.availableTimeline = ko.computed(function() {
+    return self.availableDateFields().length > 0;
+  });
   self.availableDraggableNumbers = ko.computed(function() {
     return self.availableNumberFields().length > 0;
   });

+ 98 - 3
apps/search/src/search/templates/search.mako

@@ -254,7 +254,7 @@ ${ commonheader(_('Search'), "search", user, request, "80px") | n,unicode }
                        <i class="fa fa-th"></i>
          </a>
     </div>
-    <div data-bind="css: { 'draggable-widget': true, 'disabled': ! availableDraggableHistogram() },
+    <div data-bind="visible: ! $root.isLatest(), css: { 'draggable-widget': true, 'disabled': ! availableDraggableHistogram() },
                     draggable: {data: draggableHistogram(), isEnabled: availableDraggableHistogram,
                     options: {'start': function(event, ui){lastWindowScrollPosition = $(window).scrollTop();$('.card-body').slideUp('fast');},
                               'stop': function(event, ui){$('.card-body').slideDown('fast', function(){$(window).scrollTop(lastWindowScrollPosition)});}}}"
@@ -263,6 +263,15 @@ ${ commonheader(_('Search'), "search", user, request, "80px") | n,unicode }
                        <i class="hcha hcha-timeline-chart"></i>
          </a>
     </div>
+    <div data-bind="visible: $root.isLatest(), css: { 'draggable-widget': true, 'disabled': ! availableTimeline() },
+                    draggable: {data: draggableTimeline(), isEnabled: availableTimeline,
+                    options: {'start': function(event, ui){lastWindowScrollPosition = $(window).scrollTop();$('.card-body').slideUp('fast');},
+                              'stop': function(event, ui){$('.card-body').slideDown('fast', function(){$(window).scrollTop(lastWindowScrollPosition)});}}}"
+         title="${_('Timeline')}" rel="tooltip" data-placement="top">
+         <a data-bind="style: { cursor: $root.availableTimeline() ? 'move' : 'default' }">
+                       <i class="hcha hcha-timeline-chart"></i>
+         </a>
+    </div>
     <div data-bind="css: { 'draggable-widget': true, 'disabled': ! availableDraggableMap() },
                     draggable: {data: draggableMap(), isEnabled: availableDraggableMap,
                     options: {'start': function(event, ui){lastWindowScrollPosition = $(window).scrollTop();$('.card-body').slideUp('fast');},
@@ -1090,6 +1099,92 @@ ${ dashboard.layout_skeleton() }
 </script>
 
 
+<script type="text/html" id="timeline-widget">
+  <div class="widget-spinner" data-bind="visible: isLoading()">
+    <!--[if !IE]> --><i class="fa fa-spinner fa-spin"></i><!-- <![endif]-->
+    <!--[if IE]><img src="${ static('desktop/art/spinner.gif') }" /><![endif]-->
+  </div>
+
+  <!-- ko if: $root.getFacetFromQuery(id()).has_data() -->
+  <div class="row-fluid" data-bind="with: $root.getFacetFromQuery(id())">
+    <div data-bind="visible: $root.isEditing, with: $root.collection.getFacetById($parent.id())" style="margin-bottom: 20px">
+      <span data-bind="template: { name: 'facet-toggle' }">
+      </span>
+
+        <div class="title" style="border: 1px dashed #d8d8d8; border-bottom: none">
+          <a data-bind="visible: ko.toJSON(properties.facets_form.field) != '', click: $root.collection.addPivotFacetValue" class="pull-right" href="javascript:void(0)">
+            <i class="fa fa-plus"></i> ${ _('Add') }
+          </a>
+          <select data-bind="options: $root.collection.template.fieldsNames, value: properties.facets_form.field, optionsCaption: '${ _ko('Field...') }'" class="hit-options" style="margin-bottom: 0; height: 20px"></select>
+          <div class="clearfix"></div>
+        </div>
+        <div class="content" style="border: 1px dashed #d8d8d8; border-top: none">
+          <div class="facet-field-cnt">
+            <span class="spinedit-cnt">
+              <span class="facet-field-label">
+                ${ _('Metric') }
+              </span>
+              <select data-bind="options: HIT_OPTIONS, optionsText: 'label', optionsValue: 'value', value: properties.facets_form.aggregate" class="hit-options"></select>
+            </span>
+          </div>
+
+          <div class="facet-field-cnt">
+            <span class="spinedit-cnt">
+              <span class="facet-field-label">
+                ${ _('Limit') }
+              </span>
+              <input type="text" class="input-medium" data-bind="spinedit: properties.facets_form.limit"/>
+            </span>
+          </div>
+
+          <div class="facet-field-cnt">
+            <span class="spinedit-cnt">
+              <span class="facet-field-label">
+                ${ _('Min Count') }
+              </span>
+              <input type="text" class="input-medium" data-bind="spinedit: properties.facets_form.mincount"/>
+            </span>
+          </div>
+        </div>
+
+
+    </div>
+
+    <div style="padding-bottom: 10px; text-align: right; padding-right: 20px" data-bind="visible: counts().length > 0">
+      <span data-bind="with: $root.collection.getFacetById($parent.id())">
+        <span class="facet-field-label">${ _('Chart Type') }</span>
+        <select class="input-small" data-bind="options: $root.timelineChartTypes,
+                       optionsText: 'label',
+                       optionsValue: 'value',
+                       value: properties.timelineChartType">
+        </select>&nbsp;
+        <span class="facet-field-label">${ _('Interval') }</span>
+        <select class="input-small" data-bind="options: $root.intervalOptions,
+                       optionsText: 'label',
+                       optionsValue: 'value',
+                       value: properties.gap">
+        </select>&nbsp;
+      </span>
+      <span class="facet-field-label">${ _('Zoom') }</span>
+      <a href="javascript:void(0)" data-bind="click: $root.collection.rangeZoomOut"><i class="fa fa-search-minus"></i> ${ _('reset') }</a>
+      <span class="facet-field-label" data-bind="visible: $root.query.multiqs().length > 1">${ _('Group by') }</span>
+      <select class="input-medium" data-bind="visible: $root.query.multiqs().length > 1, options: $root.query.multiqs, optionsValue: 'id', optionsText: 'label', value: $root.query.selectedMultiq"></select>
+    </div>
+
+    <!-- ko if: $root.collection.getFacetById($parent.id()) -->
+      <div data-bind="timelineChart: {datum: {counts: counts(), extraSeries: extraSeries(), widget_id: $parent.id(), label: label()}, stacked: $root.collection.getFacetById($parent.id()).properties.stacked(), field: field, label: label(), transformer: timelineChartDataTransformer,
+        type: $root.collection.getFacetById($parent.id()).properties.timelineChartType,
+        fqs: $root.query.fqs,
+        onSelectRange: function(from, to){ $root.collection.selectTimelineFacet({from: from, to: to, cat: field, widget_id: $parent.id()}) },
+        onStateChange: function(state){ $root.collection.getFacetById($parent.id()).properties.stacked(state.stacked); },
+        onClick: function(d){ $root.query.selectRangeFacet({count: d.obj.value, widget_id: $parent.id(), from: d.obj.from, to: d.obj.to, cat: d.obj.field}) },
+        onComplete: function(){ $root.getWidgetById($parent.id()).isLoading(false) }}" />
+    <!-- /ko -->
+  </div>
+  <!-- /ko -->
+</script>
+
+
 <script type="text/html" id="bar-widget">
   <div class="widget-spinner" data-bind="visible: isLoading()">
     <!--[if !IE]> --><i class="fa fa-spinner fa-spin"></i><!-- <![endif]-->
@@ -1928,7 +2023,7 @@ ${ dashboard.layout_skeleton() }
           </span>
         </li>
       </ul>
-      <div class="alert alert-info inline" data-bind="visible: $root.collection.template.filteredModalFields().length == 0" style="margin-left: 250px;margin-right: 50px; height: 42px;line-height: 42px">
+      <div class="alert alert-info inline" data-bind="visible: $root.collection.template.filteredModalFields().length == 0" style="margin-left: 250px; margin-right: 50px; height: 42px;line-height: 42px">
         ${_('There are no fields matching your search term.')}
       </div>
     </div>
@@ -2038,7 +2133,7 @@ ${ dashboard.layout_skeleton() }
 
 
 <script type="text/html" id="time-filter-select">
-  <select id="settingstimeinterval" data-bind="value: collection.timeFilter.value" class="input-medium" style="margin-right: 4px">
+  <select id="settingstimeinterval" data-bind="value: collection.timeFilter.value" class="input-small" style="margin-right: 4px">
     <option value="all">${ _('All') }</option>
     <option value="5MINUTES">${ _('Past 5 Minutes') }</option>
     <option value="30MINUTES">${ _('Past 30 Minutes') }</option>

+ 1 - 1
apps/search/src/search/views.py

@@ -532,7 +532,7 @@ def _create_facet(collection, user, facet_id, facet_label, facet_field, widget_t
     else:
       facet_type = 'field'
 
-    if widget_type == 'bucket-widget' or widget_type == 'pie2-widget':
+    if widget_type == 'bucket-widget' or widget_type == 'pie2-widget' or widget_type == 'timeline-widget':
       facet_type = 'nested'
       properties['facets_form'] = {'field': '', 'mincount': 1, 'limit': 10, 'aggregate': 'count'}
       properties['facets'] = []