diff --git a/public/app/panels/table/controller.ts b/public/app/panels/table/controller.ts index e2166f82577..4547a9d7896 100644 --- a/public/app/panels/table/controller.ts +++ b/public/app/panels/table/controller.ts @@ -27,7 +27,7 @@ export class TablePanelCtrl { var panelDefaults = { targets: [{}], transform: 'timeseries_to_rows', - pageSize: 50, + pageSize: null, showHeader: true, styles: [ { diff --git a/public/app/panels/table/editor.html b/public/app/panels/table/editor.html index a862a2b7776..27bf9002d56 100644 --- a/public/app/panels/table/editor.html +++ b/public/app/panels/table/editor.html @@ -44,7 +44,7 @@ Pagination (Page size)
  • -
  • diff --git a/public/app/panels/table/editor.ts b/public/app/panels/table/editor.ts index 228b41ccd57..2908023d330 100644 --- a/public/app/panels/table/editor.ts +++ b/public/app/panels/table/editor.ts @@ -38,7 +38,7 @@ export function tablePanelEditor() { scope.updateColumnsMenu = function(data) { scope.columnsMenu = transformers[scope.panel.transform].getColumns(data); - scope.showColumnOptions = scope.columnsMenu.length > 0; + scope.showColumnOptions = true; }; scope.$on('render', function(event, table, rawData) { @@ -51,6 +51,7 @@ export function tablePanelEditor() { }; scope.transformChanged = function() { + scope.panel.columns = []; scope.updateColumnsMenu(); scope.render(); }; diff --git a/public/app/panels/table/module.ts b/public/app/panels/table/module.ts index f09a7389a59..dbdc4d0ba25 100644 --- a/public/app/panels/table/module.ts +++ b/public/app/panels/table/module.ts @@ -45,7 +45,8 @@ export function tablePanel() { function appendPaginationControls(footerElem) { footerElem.empty(); - var pageCount = Math.ceil(data.rows.length / panel.pageSize); + var pageSize = panel.pageSize || 100; + var pageCount = Math.ceil(data.rows.length / pageSize); if (pageCount === 1) { return; } @@ -55,18 +56,12 @@ export function tablePanel() { var paginationList = $(''); - // var prevLink = $('
  • «
  • '); - // paginationList.append(prevLink); - for (var i = startPage; i < endPage; i++) { var activeClass = i === scope.pageIndex ? 'active' : ''; var pageLinkElem = $('
  • ' + (i+1) + '
  • '); paginationList.append(pageLinkElem); } - // var nextLink = $('
  • »
  • '); - // paginationList.append(nextLink); - footerElem.append(paginationList); } diff --git a/public/app/panels/table/renderer.ts b/public/app/panels/table/renderer.ts index 3ecb6d68643..a55a8bf2fac 100644 --- a/public/app/panels/table/renderer.ts +++ b/public/app/panels/table/renderer.ts @@ -119,8 +119,9 @@ export class TableRenderer { } render(page) { - let startPos = page * this.panel.pageSize; - let endPos = Math.min(startPos + this.panel.pageSize, this.table.rows.length); + let pageSize = this.panel.pageSize || 100; + let startPos = page * pageSize; + let endPos = Math.min(startPos + pageSize, this.table.rows.length); var html = ""; for (var y = startPos; y < endPos; y++) { diff --git a/public/app/panels/table/transformers.ts b/public/app/panels/table/transformers.ts index 48559f943bd..1a5482693e7 100644 --- a/public/app/panels/table/transformers.ts +++ b/public/app/panels/table/transformers.ts @@ -145,7 +145,7 @@ transformers['json'] = { var names: any = {}; for (var i = 0; i < data.length; i++) { var series = data[i]; - if (series.type === 'docs') { + if (series.type !== 'docs') { continue; } diff --git a/public/app/plugins/datasource/elasticsearch/elastic_response.js b/public/app/plugins/datasource/elasticsearch/elastic_response.js index 7eb4378831d..73050ce7f2b 100644 --- a/public/app/plugins/datasource/elasticsearch/elastic_response.js +++ b/public/app/plugins/datasource/elasticsearch/elastic_response.js @@ -86,20 +86,71 @@ function (_, queryDef) { } }; + ElasticResponse.prototype.processAggregationDocs = function(esAgg, aggDef, target, docs, props) { + var metric, y, i, bucket, metricName, doc; + + for (i = 0; i < esAgg.buckets.length; i++) { + bucket = esAgg.buckets[i]; + doc = _.defaults({}, props); + doc[aggDef.field] = bucket.key; + + for (y = 0; y < target.metrics.length; y++) { + metric = target.metrics[y]; + + switch(metric.type) { + case "count": { + metricName = this._getMetricName(metric.type); + doc[metricName] = bucket.doc_count; + break; + } + case 'extended_stats': { + for (var statName in metric.meta) { + if (!metric.meta[statName]) { + continue; + } + + var stats = bucket[metric.id]; + // add stats that are in nested obj to top level obj + stats.std_deviation_bounds_upper = stats.std_deviation_bounds.upper; + stats.std_deviation_bounds_lower = stats.std_deviation_bounds.lower; + + metricName = this._getMetricName(statName); + doc[metricName] = stats[statName]; + } + break; + } + default: { + metricName = this._getMetricName(metric.type); + doc[metricName] =bucket[metric.id].value; + break; + } + } + } + + docs.push(doc); + } + }; + // This is quite complex // neeed to recurise down the nested buckets to build series - ElasticResponse.prototype.processBuckets = function(aggs, target, seriesList, props) { + ElasticResponse.prototype.processBuckets = function(aggs, target, seriesList, docs, props, depth) { var bucket, aggDef, esAgg, aggId; + var maxDepth = target.bucketAggs.length-1; for (aggId in aggs) { aggDef = _.findWhere(target.bucketAggs, {id: aggId}); esAgg = aggs[aggId]; + if (!aggDef) { continue; } - if (aggDef.type === 'date_histogram') { - this.processMetrics(esAgg, target, seriesList, props); + if (depth === maxDepth) { + if (aggDef.type === 'date_histogram') { + this.processMetrics(esAgg, target, seriesList, props); + } else { + this.processAggregationDocs(esAgg, aggDef, target, docs, props); + } } else { for (var nameIndex in esAgg.buckets) { bucket = esAgg.buckets[nameIndex]; @@ -109,7 +160,7 @@ function (_, queryDef) { } else { props["filter"] = nameIndex; } - this.processBuckets(bucket, target, seriesList, props); + this.processBuckets(bucket, target, seriesList, docs, props, depth+1); } } } @@ -217,13 +268,18 @@ function (_, queryDef) { var aggregations = response.aggregations; var target = this.targets[i]; var tmpSeriesList = []; + var docs = []; - this.processBuckets(aggregations, target, tmpSeriesList, {}); + this.processBuckets(aggregations, target, tmpSeriesList, docs, {}, 0); this.nameSeries(tmpSeriesList, target); for (var y = 0; y < tmpSeriesList.length; y++) { seriesList.push(tmpSeriesList[y]); } + + if (seriesList.length === 0 && docs.length > 0) { + seriesList.push({target: 'docs', type: 'docs', datapoints: docs}); + } } } diff --git a/public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts index 5ae67f92d78..4e80833c55b 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts @@ -411,6 +411,51 @@ describe('ElasticResponse', function() { }); }); + describe('No group by time', function() { + beforeEach(function() { + targets = [{ + refId: 'A', + metrics: [{type: 'avg', id: '1'}, {type: 'count' }], + bucketAggs: [{id: '2', type: 'terms', field: 'host'}], + }]; + + response = { + responses: [{ + aggregations: { + "2": { + buckets: [ + { + "1": { value: 1000}, + key: "server-1", + doc_count: 369, + }, + { + "1": { value: 2000}, + key: "server-2", + doc_count: 200, + }, + ] + } + } + }] + }; + + result = new ElasticResponse(targets, response).getTimeSeries(); + }); + + it.only('should return table', function() { + expect(result.data.length).to.be(1); + expect(result.data[0].type).to.be('docs'); + expect(result.data[0].datapoints.length).to.be(2); + expect(result.data[0].datapoints[0].host).to.be("server-1"); + expect(result.data[0].datapoints[0].Average).to.be(1000); + expect(result.data[0].datapoints[0].Count).to.be(369); + + expect(result.data[0].datapoints[1].host).to.be("server-2"); + expect(result.data[0].datapoints[1].Average).to.be(2000); + }); + }); + describe('Raw documents query', function() { beforeEach(function() { targets = [{ refId: 'A', metrics: [{type: 'raw_document', id: '1'}], bucketAggs: [] }];