Ver Fonte

HUE-8408 [report] Support basic filter.

jdesjean há 7 anos atrás
pai
commit
8d2f9dc23d

+ 1 - 1
desktop/core/src/desktop/static/desktop/js/ko.charts.js

@@ -979,7 +979,7 @@
       $.each(_options.fqs ? _options.fqs() : [], function (cnt, item) {
         if (item.id() == _options.datum.widget_id) {
           if (item.field() == _field) {
-            if (item.properties) {
+            if (item.properties && typeof item.properties === 'function') {
               bHasSelection = true;
               _chart.selectBars({
                 singleValues: $.map(item.filter(), function (it) {

+ 35 - 17
desktop/libs/dashboard/src/dashboard/templates/common_search.mako

@@ -1748,23 +1748,40 @@ ${ dashboard.layout_skeleton(suffix='search') }
         <!-- /ko -->
 
         <!-- ko if: widgetType() == 'document-widget' -->
-          <div data-bind="attr:{'id': 'pieChart_'+id()}, pieChart: {data: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, widget_id: $parent.id(), chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYSingle}, fqs: ko.observableArray([]),
-                transformer: pieChartDataTransformerGrid, maxWidth: 350, parentSelector: '.chart-container'}, visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.PIECHART" class="chart"></div>
-
-          <div data-bind="attr:{'id': 'barChart_'+id()}, barChart: {datum: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYMulti}, fqs: ko.observableArray([]), hideSelection: true, enableSelection: false, hideStacked: template.chartSettings.hideStacked,
-                transformer: multiSerieDataTransformerGrid, stacked: false, showLegend: true, type: template.chartSettings.chartSelectorType},  stacked: true, showLegend: true, visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.BARCHART" class="chart"></div>
-
-          <div data-bind="attr:{'id': 'lineChart_'+id()}, lineChart: {datum: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYMulti},
-                transformer: multiSerieDataTransformerGrid, showControls: false}, visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.LINECHART" class="chart"></div>
-
+          <!-- ko if: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.PIECHART -->
+          <div data-bind="attr:{'id': 'pieChart_'+id()}, pieChart: {data: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, widget_id: $parent.id(), chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYSingle}, field: template.chartSettings.chartX, fqs: $root.query.fqs,
+                transformer: pieChartDataTransformerGrid, maxWidth: 350, parentSelector: '.chart-container',
+                onClick: function(d){ searchViewModel.query.toggleFacet({facet: {cat: template.chartSettings.chartX(), value: d.data.label}, widget_id: $parent.id()}); }}" class="chart"></div>
+          <!-- /ko -->
+          <!-- ko if: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.BARCHART -->
+          <div data-bind="attr:{'id': 'barChart_'+id()}, barChart: {datum: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, widget_id: $parent.id(), chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYMulti}, field: template.chartSettings.chartX, fqs: $root.query.fqs, hideSelection: true, enableSelection: true, hideStacked: template.chartSettings.hideStacked,
+                transformer: multiSerieDataTransformerGrid, stacked: false, showLegend: true, type: template.chartSettings.chartSelectorType,
+                onClick: function(d){ searchViewModel.query.toggleFacet({facet: {cat: template.chartSettings.chartX(), value: d.x}, widget_id: $parent.id()}); },
+                onSelectRange: function(from, to){ $root.collection.selectTimelineFacet2({from: from, to: to, cat: template.chartSettings.chartX(), widget_id: $parent.id()}) }},  stacked: true, showLegend: true" class="chart"></div>
+          <!-- /ko -->
+          <!-- ko if: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.LINECHART -->
+          <div data-bind="attr:{'id': 'lineChart_'+id()}, lineChart: {datum: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, widget_id: $parent.id(), chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYMulti}, field: template.chartSettings.chartX, fqs: $root.query.fqs, hideSelection: true, enableSelection: true,
+                transformer: multiSerieDataTransformerGrid, showControls: false,
+                onClick: function(d){ searchViewModel.query.toggleFacet({facet: {cat: template.chartSettings.chartX(), value: d.x}, widget_id: $parent.id()}); },
+                onSelectRange: function(from, to){ $root.collection.selectTimelineFacet2({from: from, to: to, cat: template.chartSettings.chartX(), widget_id: $parent.id()}) }}" class="chart"></div>
+          <!-- /ko -->
+          <!-- ko if: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.MAP -->
           <div data-bind="attr: {'id': 'leafletMapChart_'+id()}, leafletMapChart: {datum: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYSingle, chartZ: template.chartSettings.chartMapLabel},
-                transformer: leafletMapChartDataTransformerGrid, showControls: false, height: 380, visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.MAP, forceRedraw: true}" class="chart"></div>
-
-          <div data-bind="attr:{'id': 'timelineChart_'+id()}, timelineChart: {datum: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYMulti}, fqs: ko.observableArray([]), hideSelection: true, enableSelection: false, hideStacked: template.chartSettings.hideStacked,
-                transformer: multiSerieDataTransformerGrid, showControls: false}, visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART" class="chart"></div>
-
-          <div data-bind="attr:{'id': 'gradientMapChart_'+id()}, mapChart: {data: {counts: $parent.results(), scope: template.chartSettings.chartScope(), snippet: $data, chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYSingle},
-              transformer: gradientMapChartDataTransformerGrid, maxWidth: 750, isScale: true}, visible: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP" />
+                transformer: leafletMapChartDataTransformerGrid, showControls: false, height: 380, forceRedraw: true,
+                showMoveCheckbox: true, moveCheckboxLabel: '${ _ko('Search as I move the map') }',
+                onRegionChange: function(bounds){ $root.query.selectMapRegionFacet({widget_id: $parent.id(), 'bounds': ko.toJS(bounds, null, 2), lat: template.chartSettings.chartX(), lon: template.chartSettings.chartYSingle()}); }}" class="chart"></div>
+          <!-- /ko -->
+          <!-- ko if: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.TIMELINECHART -->
+          <div data-bind="attr:{'id': 'timelineChart_'+id()}, timelineChart: {datum: {counts: $parent.results(), sorting: template.chartSettings.chartSorting(), snippet: $data, chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYMulti, widget_id: $parent.id()}, field: template.chartSettings.chartX, fqs: $root.query.fqs, hideSelection: true, enableSelection: true, hideStacked: template.chartSettings.hideStacked,
+                transformer: multiSerieDataTransformerGrid, showControls: false,
+                onClick: function(d){ searchViewModel.query.toggleFacet({facet: {cat: template.chartSettings.chartX(), value: d.x}, widget_id: $parent.id()}); },
+                onSelectRange: function(from, to){ $root.collection.selectTimelineFacet2({from: from, to: to, cat: template.chartSettings.chartX(), widget_id: $parent.id()}) }}" class="chart"></div>
+          <!-- /ko -->
+          <!-- ko if: template.chartSettings.chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP -->
+          <div data-bind="attr:{'id': 'gradientMapChart_'+id()}, mapChart: {data: {counts: $parent.results(), scope: template.chartSettings.chartScope(), snippet: $data, widget_id: $parent.id(), chartX: template.chartSettings.chartX, chartY: template.chartSettings.chartYSingle},
+              transformer: gradientMapChartDataTransformerGrid, maxWidth: 750, isScale: true,
+              onClick: function(d){ searchViewModel.query.toggleFacet({facet: {cat: template.chartSettings.chartX(), value: d.fields[0]}, widget_id: $parent.id()}); }}" />
+          <!-- /ko -->
           <div class="clearfix"></div>
         <!-- /ko -->
 
@@ -3419,6 +3436,7 @@ function pieChartDataTransformerGrid(data) {
   $(data.counts).each(function (cnt, item) {
     item.widget_id = data.widget_id;
     if (chartX != "" && item.item[chartX] && chartY != "" && item.item[chartY]) {
+      item.from = item.item[chartX]();
       _data.push({
         label: item.item[chartX](),
         value: item.item[chartY](),
@@ -3961,7 +3979,7 @@ function multiSerieDataTransformerGrid(rawDatum, isTimeline) {
         if (item.item[chartX] && item.item[col]) {
           _data.push({
             series: _plottedSerie,
-            x: isTimeline && new Date(item.item[chartX]()) || item.item[chartX](),
+            x: isTimeline && new Date(moment.utc(item.item[chartX]()).valueOf()) || item.item[chartX](),
             y: item.item[col](),
             obj: item.item
           });

+ 61 - 25
desktop/libs/notebook/src/notebook/dashboard_api.py

@@ -152,7 +152,16 @@ class SQLDashboardApi(DashboardApi):
             'filters': self._convert_filters_to_where(filters),
         }
       elif facet['type'] == 'statement':
-        sql = facet['properties']['statement']
+        if filters:
+          sql = '''SELECT *
+          FROM
+          (%(statement)s) as sub
+          %(filters)s''' % {
+            'statement': facet['properties']['statement'],
+            'filters': self._convert_filters_to_where(filters, alias='sub')
+          }
+        else:
+          sql = facet['properties']['statement']
         result_properties = facet['properties']['result']
     else:
       fields = Collection2.get_field_list(dashboard)
@@ -377,7 +386,9 @@ class SQLDashboardApi(DashboardApi):
     return [f for f in facet['properties']['facets'] if f['aggregate']['function'] == 'count']
 
 
-  def _convert_filters_to_where(self, filters):
+  def _convert_filters_to_where(self, filters, alias=None):
+    if alias:
+      filters = [alias + '.' + filter for filter in filters]
     return ('WHERE ' + ' AND '.join(filters)) if filters else ''
 
 
@@ -405,29 +416,53 @@ class SQLDashboardApi(DashboardApi):
           value = _filter['value']
           if value is not None:
             if isinstance(value, list):
-              f.append(' AND '.join([self._get_field_condition_formatting(collection, _f) % (_f, exclude, _val) for _f, _val in zip(fq['field'], value)]))
+              field_conditions = [self._get_field_condition_formatting(collection, facet, _f) % (_f, exclude, _val) for _f, _val in zip(fq['field'], value)]
+              field_conditions = [condition for condition in field_conditions if condition]
+              if field_conditions:
+                f.append(' AND '.join(field_conditions))
             else:
-              sql_condition = self._get_field_condition_formatting(collection, fq['field'])
-              f.append(sql_condition % (fq['field'], exclude, value))
-        clauses.append(' OR '.join(f))
+              sql_condition = self._get_field_condition_formatting(collection, facet, fq['field'])
+              if sql_condition:
+                f.append(sql_condition % (fq['field'], exclude, value))
+        if f:
+          clauses.append(' OR '.join(f))
       elif fq['type'] == 'range':
-        field = self._get_field(collection, fq['field'])
-        if self._is_date(field['type']):
-          quote = "'"
-        else:
-          quote = ''
-        clauses.append("`%(field)s` >= %(quote)s%(from)s%(quote)s AND `%(field)s` < %(quote)s%(to)s%(quote)s" % {
-          'field': fq['field'],
-          'to': fq['properties'][0]['to'],
-          'from': fq['properties'][0]['from'],
-          'quote': quote
-        })
-
+        field = self._get_field(collection, fq['field'], facet=facet)
+        if field:
+          if self._is_date(field['type']):
+            quote = "'"
+          else:
+            quote = ''
+          clauses.append("`%(field)s` >= %(quote)s%(from)s%(quote)s AND `%(field)s` < %(quote)s%(to)s%(quote)s" % {
+            'field': fq['field'],
+            'to': fq['properties'][0]['to'],
+            'from': fq['properties'][0]['from'],
+            'quote': quote
+          })
+      elif fq['type'] == 'map':
+        for direction in ['lat', 'lon']:
+          field = self._get_field(collection, fq[direction], facet=facet)
+          if field:
+            if self._is_number(field['type']):
+              quote = ''
+            else:
+              quote = "'"
+            min_direction = min(fq['properties'][direction+'_sw'], fq['properties'][direction+'_ne'])
+            max_direction = max(fq['properties'][direction+'_sw'], fq['properties'][direction+'_ne'])
+            clauses.append("`%(field)s` >= %(quote)s%(from)s%(quote)s AND `%(field)s` < %(quote)s%(to)s%(quote)s" % {
+              'field': fq[direction],
+              'to': max_direction,
+              'from': min_direction,
+              'quote': quote
+            })
     return clauses
 
-  def _get_field_condition_formatting(self, table, field_name):
-    field = self._get_field(table, field_name)
-    return "`%s` %s %s" if self._is_number(field['type']) else "`%s` %s '%s'"
+  def _get_field_condition_formatting(self, table, facet, field_name):
+    field = self._get_field(table, field_name, facet=facet)
+    if field:
+      return "`%s` %s %s" if self._is_number(field['type']) else "`%s` %s '%s'"
+    else:
+      return ''
 
 
   @classmethod
@@ -584,18 +619,19 @@ class SQLDashboardApi(DashboardApi):
 
     return duration
 
-  def _get_field(self, collection, name):
-    _field = [_f for _f in collection['template']['fieldsAttributes'] if _f['name'] == name]
+  def _get_field(self, collection, name, facet=None):
+    fields = collection['template']['fieldsAttributes'] or (facet and facet['template']['fieldsAttributes'])
+    _field = [_f for _f in fields if _f['name'] == name]
     if _field:
       return _field[0]
 
 
   def _is_number(self, _type):
-    return _type in ('int', 'long', 'bigint', 'float')
+    return _type in ('int', 'long', 'bigint', 'float', 'INT_TYPE', 'DECIMAL_TYPE', 'DOUBLE_TYPE', 'FLOAT_TYPE', 'SMALLINT_TYPE', 'TINYINT_TYPE', 'BIGINT_TYPE')
 
 
   def _is_date(self, _type):
-    return _type in ('timestamp',)
+    return _type in ('timestamp','TIMESTAMP_TYPE')
 
 
   def _get_time_filter_range(self, collection, query):