From 97e0a4eb5f0bdeb92ded3099b2ba6c183a77ee75 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Thu, 24 Apr 2014 12:37:07 -0700 Subject: [PATCH] temorarily improved labels for the query results, moved global time filter into the rootSearch, so that it can be easilyt excluded. Closes #32. Closes #68 --- .../apps/settings/services/index_patterns.js | 4 ++ .../visualize/saved_visualizations/_aggs.js | 25 +++++-- .../saved_visualizations/_build_chart_data.js | 41 ++++++++---- .../courier/data_source/abstract.js | 66 +++++++++---------- .../components/courier/data_source/search.js | 11 +++- src/kibana/components/courier/fetch/fetch.js | 39 ++--------- src/kibana/services/promises.js | 3 + src/kibana/services/root_search.js | 11 +++- 8 files changed, 112 insertions(+), 88 deletions(-) diff --git a/src/kibana/apps/settings/services/index_patterns.js b/src/kibana/apps/settings/services/index_patterns.js index 542dd6b662a24..38da5beb3f533 100644 --- a/src/kibana/apps/settings/services/index_patterns.js +++ b/src/kibana/apps/settings/services/index_patterns.js @@ -4,6 +4,10 @@ define(function (require) { module.service('indexPatterns', function (config, es, courier) { this.getFields = function (id) { + if (typeof id === 'object' && typeof id.get === 'function') { + id = id.get('index'); + } + return es.get({ index: config.file.kibanaIndex, type: 'mapping', diff --git a/src/kibana/apps/visualize/saved_visualizations/_aggs.js b/src/kibana/apps/visualize/saved_visualizations/_aggs.js index a2a710da9c8a5..4a0d48e3082ca 100644 --- a/src/kibana/apps/visualize/saved_visualizations/_aggs.js +++ b/src/kibana/apps/visualize/saved_visualizations/_aggs.js @@ -7,23 +7,38 @@ define(function (require) { aggs.metricAggs = [ { name: 'count', - display: 'Count' + display: 'Count', + makeLabel: function (params) { + return 'Count of documents'; + } }, { name: 'avg', - display: 'Average' + display: 'Average', + makeLabel: function (params) { + return 'Average ' + params.field; + } }, { name: 'sum', - display: 'Sum' + display: 'Sum', + makeLabel: function (params) { + return 'Sum of ' + params.field; + } }, { name: 'min', - display: 'Min' + display: 'Min', + makeLabel: function (params) { + return 'Min ' + params.field; + } }, { name: 'max', - display: 'Max' + display: 'Max', + makeLabel: function (params) { + return 'Max ' + params.field; + } } ]; aggs.metricAggsByName = _.indexBy(aggs.metricAggs, 'name'); diff --git a/src/kibana/apps/visualize/saved_visualizations/_build_chart_data.js b/src/kibana/apps/visualize/saved_visualizations/_build_chart_data.js index da78a1d0a75f1..0d0a8f4085552 100644 --- a/src/kibana/apps/visualize/saved_visualizations/_build_chart_data.js +++ b/src/kibana/apps/visualize/saved_visualizations/_build_chart_data.js @@ -2,6 +2,7 @@ define(function (require) { var converters = require('./resp_converters/index'); var aggs = require('./_aggs'); + var _ = require('lodash'); // private functionality for Vis.buildChartDataFromResp() return function (createNotifier) { @@ -20,17 +21,7 @@ define(function (require) { // the list of configs that make up the aggs and eventually // splits and columns, label added - var configs = vis.getConfig().map(function (col) { - var agg = aggs.byName[col.agg]; - if (!agg) { - col.label = col.agg; - } else if (agg.makeLabel) { - col.label = aggs.byName[col.agg].makeLabel(col.aggParams); - } else { - col.label = agg.display || agg.name; - } - return col; - }); + var configs = vis.getConfig(); var lastCol = configs[configs.length - 1]; @@ -43,7 +34,25 @@ define(function (require) { // all chart data will be written here or to child chartData // formatted objects - var chartData = {}; + var chartData = { + label: _.reduce(configs, function (label, col) { + var agg = aggs.byName[col.agg]; + + if (!agg) { + col.label = col.agg; + } else if (agg.makeLabel) { + col.label = aggs.byName[col.agg].makeLabel(col.aggParams); + } else { + col.label = agg.display || agg.name; + } + + if (label) { + return label + ' > ' + col.label; + } else { + return col.label; + } + }, '') + }; var writeRow = function (rows, bucket) { // collect the count and bail, free metric!! @@ -84,13 +93,19 @@ define(function (require) { // pick the key for the split's groups var groupsKey = col.row ? 'rows' : 'columns'; + // if (chartData.label) { + // chartData.label = col.label + ' > ' + chartData.label; + // } else { + // chartData.label = col.label; + // } + // the groups will be written here chartData[groupsKey] = []; result.buckets.forEach(function (bucket) { // create a new group for each bucket var group = { - label: col.label + label: bucket.key }; chartData[groupsKey].push(group); diff --git a/src/kibana/components/courier/data_source/abstract.js b/src/kibana/components/courier/data_source/abstract.js index c05166313cca2..3c9260d5a2318 100644 --- a/src/kibana/components/courier/data_source/abstract.js +++ b/src/kibana/components/courier/data_source/abstract.js @@ -6,7 +6,7 @@ define(function (require) { var module = require('modules').get('kibana/courier'); - module.factory('CouriersSourceAbstract', function (couriersFetch, Promise, timefilter, $q) { + module.factory('CouriersSourceAbstract', function (couriersFetch, Promise, timefilter) { function SourceAbstract(courier, initialState) { this._state = (function () { @@ -198,44 +198,47 @@ define(function (require) { /** * Walk the inheritance chain of a source and return it's * flat representaion (taking into account merging rules) - * @return {object} - the flat state of the SourceAbstract + * @returns {Promise} + * @resolved {Object|null} - the flat state of the SourceAbstract */ SourceAbstract.prototype._flatten = function () { var type = this._getType(); + // the merged state of this dataSource and it's ancestors var flatState = {}; - var collectProp = _.partial(this._mergeProp, flatState); + // function used to write each property from each state object in the chain to flat state + var root = this; - // walk the chain and merge each property + // start the chain at this source var current = this; - while (current) { - // stop processing if this or one of it's parents is disabled - if (current._fetchDisabled) return; - // merge the properties from the state into the flattened copy - _.forOwn(current._state, collectProp); - // move to this sources parent - current = current._parent; - } - current = null; + // call the ittr and return it's promise + return (function ittr(resolve, reject) { - // TODO: This is a hacky way of getting the timefield, this should be stored in mapping metadata - // and we should check if the data source is time based in the first place; - if (type === 'search') { + // stop processing if current is disabled, returns nothing + if (current._fetchDisabled) return Promise.resolved(); - return this._courier._mapper.getCachedFieldsFor(this).then(function (indexPattern) { + // itterate the _state object (not array) and + // pass each key:value pair to collect prop. + return Promise.all(_.map(current._state, function (value, key) { + return root._mergeProp(flatState, value, key); + })) + .then(function () { + // move to this sources parent + current = current._parent; + + // keep calling until we reach the top parent + if (current) return ittr(); + }); + }()) + .then(function () { + if (type === 'search') { // defaults for the query - _.forOwn({ - query: { + if (!flatState.body.query) { + flatState.body.query = { 'match_all': {} - } - }, collectProp); - - var filter = timefilter.get(indexPattern); - if (!!filter) { - flatState.filters = flatState.filters || []; - flatState.filters.push(filter); + }; } // switch to filtered query if there are filters @@ -254,15 +257,10 @@ define(function (require) { } delete flatState.filters; } + } - return flatState; - }); - } else { - var p = $q.defer(); - p.resolve(flatState); - return p.promise; - } - + return flatState; + }); }; return SourceAbstract; diff --git a/src/kibana/components/courier/data_source/search.js b/src/kibana/components/courier/data_source/search.js index acf5ae68eaaed..a5e58bb60af0d 100644 --- a/src/kibana/components/courier/data_source/search.js +++ b/src/kibana/components/courier/data_source/search.js @@ -6,7 +6,7 @@ define(function (require) { var module = require('modules').get('kibana/courier'); - module.factory('CouriersSearchSource', function (couriersErrors, CouriersSourceAbstract) { + module.factory('CouriersSearchSource', function (couriersErrors, CouriersSourceAbstract, Promise) { var FetchFailure = couriersErrors.FetchFailure; var RequestFailure = couriersErrors.RequestFailure; @@ -89,6 +89,15 @@ define(function (require) { * @return {undefined} */ SearchSource.prototype._mergeProp = function (state, val, key) { + if (typeof val === 'function') { + var source = this; + return Promise.cast(val(source)).then(function (res) { + return source._mergeProp(state, res, key); + }); + } + + if (val == null) return; + switch (key) { case 'filter': state.filters = state.filters || []; diff --git a/src/kibana/components/courier/fetch/fetch.js b/src/kibana/components/courier/fetch/fetch.js index ef35582b6191d..574d9e0a0326f 100644 --- a/src/kibana/components/courier/fetch/fetch.js +++ b/src/kibana/components/courier/fetch/fetch.js @@ -11,10 +11,6 @@ define(function (require) { location: 'Courier Fetch' }); - var flattenRequest = function (req) { - return req.source._flatten(); - }; - function RequestErrorHandler(courier) { this._courier = courier; } RequestErrorHandler.prototype.handle = function (req, error) { if (!this._courier) return req.defer.reject(error); @@ -36,11 +32,12 @@ define(function (require) { all = requests.splice(0); - var allRequests = all.map(flattenRequest); - - return $q.all(allRequests).then(function (reqs) { + return Promise.map(all, function (req) { + return req.source._flatten(); + }) + .then(function (reqs) { body = strategy.requestStatesToBody(reqs); - + return es[strategy.clientMethod]({ body: body }) @@ -60,31 +57,7 @@ define(function (require) { }); throw err; }); - - }); - - - /* - return es[strategy.clientMethod]({ - body: body - }) - .then(function (resp) { - strategy.getResponses(resp).forEach(function (resp) { - var req = all.shift(); - if (resp.error) return reqErrHandler.handle(req, new couriersErrors.FetchFailure(resp)); - else strategy.resolveRequest(req, resp); - }); - - // pass the response along to the next promise - return resp; - }) - .catch(function (err) { - all.forEach(function (req) { - reqErrHandler.handle(req, err); - }); - throw err; - }); - */ + }, notify.fatal); }; var fetchPending = function (strategy, courier) { diff --git a/src/kibana/services/promises.js b/src/kibana/services/promises.js index 06970d289cc59..f01db07cfc7ad 100644 --- a/src/kibana/services/promises.js +++ b/src/kibana/services/promises.js @@ -67,6 +67,9 @@ define(function (require) { cb(void 0, val); }, cb); }; + Promise.map = function (arr, fn) { + return Promise.all(arr.map(fn)); + }; /** * Create a promise that uses our "event" like pattern. diff --git a/src/kibana/services/root_search.js b/src/kibana/services/root_search.js index ad935c8d76a6e..96aa40e4ba565 100644 --- a/src/kibana/services/root_search.js +++ b/src/kibana/services/root_search.js @@ -1,8 +1,15 @@ define(function (require) { var module = require('modules').get('kibana/services'); - module.service('rootSearch', function (courier, config, $rootScope) { + module.service('rootSearch', function (courier, config, timefilter, indexPatterns) { return courier.createSource('search') - .index(config.get('defaultIndex')); + .index(config.get('defaultIndex')) + .filter(function (source) { + return source.getFields() + .then(function (fields) { + // dynamic time filter will be called in the _flatten phase of things + return timefilter.get(fields); + }); + }); }); }); \ No newline at end of file