diff --git a/src/ui/public/agg_types/__tests__/buckets/_geo_hash.js b/src/ui/public/agg_types/__tests__/buckets/_geo_hash.js index cead8f6255d75c..a66ac01f4e20c4 100644 --- a/src/ui/public/agg_types/__tests__/buckets/_geo_hash.js +++ b/src/ui/public/agg_types/__tests__/buckets/_geo_hash.js @@ -3,9 +3,6 @@ import sinon from 'sinon'; import { geoHashBucketAgg } from 'ui/agg_types/buckets/geo_hash'; import * as AggConfigModule from 'ui/vis/agg_config'; import * as BucketAggTypeModule from 'ui/agg_types/buckets/_bucket_agg_type'; -import { aggTypes } from 'ui/agg_types/index'; - -AggConfigModule.AggConfig.aggTypes = aggTypes; describe('Geohash Agg', () => { diff --git a/src/ui/public/vis/__tests__/_agg_configs.js b/src/ui/public/vis/__tests__/_agg_configs.js index 584d3ca4379a44..82b634f8f2a175 100644 --- a/src/ui/public/vis/__tests__/_agg_configs.js +++ b/src/ui/public/vis/__tests__/_agg_configs.js @@ -4,7 +4,7 @@ import expect from 'expect.js'; import ngMock from 'ng_mock'; import { AggConfig } from 'ui/vis/agg_config'; import { VisProvider } from 'ui/vis'; -import { VisAggConfigsProvider } from 'ui/vis/agg_configs'; +import { AggConfigs } from 'ui/vis/agg_configs'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; import { Schemas } from 'ui/vis/editors/default/schemas'; import { IndexedArray } from 'ui/indexed_array'; @@ -12,12 +12,10 @@ import { IndexedArray } from 'ui/indexed_array'; describe('AggConfigs', function () { let Vis; - let AggConfigs; let indexPattern; beforeEach(ngMock.module('kibana')); beforeEach(ngMock.inject(function (Private) { - AggConfigs = Private(VisAggConfigsProvider); // replace the AggConfig module with a spy const spy = sinon.spy(AggConfig); diff --git a/src/ui/public/vis/agg_config.js b/src/ui/public/vis/agg_config.js index 0f41c796f741ba..557b659aef0d0e 100644 --- a/src/ui/public/vis/agg_config.js +++ b/src/ui/public/vis/agg_config.js @@ -7,9 +7,9 @@ import _ from 'lodash'; import { fieldFormats } from 'ui/registry/field_formats'; +import { aggTypes } from 'ui/agg_types/index'; - -function AggConfig(vis, opts) { +export function AggConfig(vis, opts) { const self = this; self.id = String(opts.id || AggConfig.nextId(vis.aggs)); @@ -29,6 +29,7 @@ function AggConfig(vis, opts) { self.setParams(opts.params || {}); } +AggConfig.aggTypes = aggTypes; /** * Ensure that all of the objects in the list have ids, the objects * and list are modified by reference. @@ -337,5 +338,3 @@ AggConfig.prototype.fieldIsTimeField = function () { const timeFieldName = this.vis.indexPattern.timeFieldName; return timeFieldName && this.fieldName() === timeFieldName; }; - -export { AggConfig }; diff --git a/src/ui/public/vis/agg_configs.js b/src/ui/public/vis/agg_configs.js index 8ab3e92c8244bb..0da7a9c22038b5 100644 --- a/src/ui/public/vis/agg_configs.js +++ b/src/ui/public/vis/agg_configs.js @@ -10,188 +10,183 @@ import _ from 'lodash'; import { IndexedArray } from 'ui/indexed_array'; import { AggConfig } from 'ui/vis/agg_config'; -import { aggTypes } from 'ui/agg_types/index'; -export function VisAggConfigsProvider() { - AggConfig.aggTypes = aggTypes; - - _.class(AggConfigs).inherits(IndexedArray); - function AggConfigs(vis, configStates) { - const self = this; - self.vis = vis; - - configStates = AggConfig.ensureIds(configStates || []); - - AggConfigs.Super.call(self, { - index: ['id'], - group: ['schema.group', 'type.name', 'schema.name'], - initialSet: configStates.map(function (aggConfigState) { - if (aggConfigState instanceof AggConfig) return aggConfigState; - return new AggConfig(vis, aggConfigState); +_.class(AggConfigs).inherits(IndexedArray); +function AggConfigs(vis, configStates) { + const self = this; + self.vis = vis; + + configStates = AggConfig.ensureIds(configStates || []); + + AggConfigs.Super.call(self, { + index: ['id'], + group: ['schema.group', 'type.name', 'schema.name'], + initialSet: configStates.map(function (aggConfigState) { + if (aggConfigState instanceof AggConfig) return aggConfigState; + return new AggConfig(vis, aggConfigState); + }) + }); + + + // Set the defaults for any schema which has them. If the defaults + // for some reason has more then the max only set the max number + // of defaults (not sure why a someone define more... + // but whatever). Also if a schema.name is already set then don't + // set anything. + if (vis && vis.type && vis.type.schemas && vis.type.schemas.all) { + _(vis.type.schemas.all) + .filter(function (schema) { + return Array.isArray(schema.defaults) && schema.defaults.length > 0; }) - }); - - - // Set the defaults for any schema which has them. If the defaults - // for some reason has more then the max only set the max number - // of defaults (not sure why a someone define more... - // but whatever). Also if a schema.name is already set then don't - // set anything. - if (vis && vis.type && vis.type.schemas && vis.type.schemas.all) { - _(vis.type.schemas.all) - .filter(function (schema) { - return Array.isArray(schema.defaults) && schema.defaults.length > 0; - }) - .each(function (schema) { - if (!self.bySchemaName[schema.name]) { - const defaults = schema.defaults.slice(0, schema.max); - _.each(defaults, function (defaultState) { - const state = _.defaults({ id: AggConfig.nextId(self) }, defaultState); - self.push(new AggConfig(vis, state)); - }); - } - }) - .commit(); - } + .each(function (schema) { + if (!self.bySchemaName[schema.name]) { + const defaults = schema.defaults.slice(0, schema.max); + _.each(defaults, function (defaultState) { + const state = _.defaults({ id: AggConfig.nextId(self) }, defaultState); + self.push(new AggConfig(vis, state)); + }); + } + }) + .commit(); } +} - /** - * Data-by-data comparison of this Aggregation - * Ignores the non-array indexes - * @param aggConfigs an AggConfigs instance - */ - AggConfigs.prototype.jsonDataEquals = function (aggConfigs) { - if (aggConfigs.length !== this.length) { +/** + * Data-by-data comparison of this Aggregation + * Ignores the non-array indexes + * @param aggConfigs an AggConfigs instance + */ +AggConfigs.prototype.jsonDataEquals = function (aggConfigs) { + if (aggConfigs.length !== this.length) { + return false; + } + for (let i = 0; i < this.length; i += 1) { + if (!_.isEqual(aggConfigs[i].toJSON(), this[i].toJSON())) { return false; } - for (let i = 0; i < this.length; i += 1) { - if (!_.isEqual(aggConfigs[i].toJSON(), this[i].toJSON())) { - return false; - } - } - return true; - }; + } + return true; +}; - function removeParentAggs(obj) { - for(const prop in obj) { - if (prop === 'parentAggs') delete obj[prop]; - else if (typeof obj[prop] === 'object') removeParentAggs(obj[prop]); - } +function removeParentAggs(obj) { + for(const prop in obj) { + if (prop === 'parentAggs') delete obj[prop]; + else if (typeof obj[prop] === 'object') removeParentAggs(obj[prop]); } +} - function parseParentAggs(dslLvlCursor, dsl) { - if (dsl.parentAggs) { - _.each(dsl.parentAggs, (agg, key) => { - dslLvlCursor[key] = agg; - parseParentAggs(dslLvlCursor, agg); - }); - } +function parseParentAggs(dslLvlCursor, dsl) { + if (dsl.parentAggs) { + _.each(dsl.parentAggs, (agg, key) => { + dslLvlCursor[key] = agg; + parseParentAggs(dslLvlCursor, agg); + }); } +} - AggConfigs.prototype.toDsl = function () { - const dslTopLvl = {}; - let dslLvlCursor; - let nestedMetrics; - - if (this.vis.isHierarchical()) { - // collect all metrics, and filter out the ones that we won't be copying - nestedMetrics = _(this.vis.aggs.bySchemaGroup.metrics) - .filter(function (agg) { - return agg.type.name !== 'count'; - }) - .map(function (agg) { - return { - config: agg, - dsl: agg.toDsl() - }; - }) - .value(); - } - this.getRequestAggs() - .filter(function (config) { - return !config.type.hasNoDsl; +AggConfigs.prototype.toDsl = function () { + const dslTopLvl = {}; + let dslLvlCursor; + let nestedMetrics; + + if (this.vis.isHierarchical()) { + // collect all metrics, and filter out the ones that we won't be copying + nestedMetrics = _(this.vis.aggs.bySchemaGroup.metrics) + .filter(function (agg) { + return agg.type.name !== 'count'; }) - .forEach(function nestEachConfig(config, i, list) { - if (!dslLvlCursor) { - // start at the top level - dslLvlCursor = dslTopLvl; - } else { - const prevConfig = list[i - 1]; - const prevDsl = dslLvlCursor[prevConfig.id]; - - // advance the cursor and nest under the previous agg, or - // put it on the same level if the previous agg doesn't accept - // sub aggs - dslLvlCursor = prevDsl.aggs || dslLvlCursor; - } + .map(function (agg) { + return { + config: agg, + dsl: agg.toDsl() + }; + }) + .value(); + } + this.getRequestAggs() + .filter(function (config) { + return !config.type.hasNoDsl; + }) + .forEach(function nestEachConfig(config, i, list) { + if (!dslLvlCursor) { + // start at the top level + dslLvlCursor = dslTopLvl; + } else { + const prevConfig = list[i - 1]; + const prevDsl = dslLvlCursor[prevConfig.id]; + + // advance the cursor and nest under the previous agg, or + // put it on the same level if the previous agg doesn't accept + // sub aggs + dslLvlCursor = prevDsl.aggs || dslLvlCursor; + } - const dsl = dslLvlCursor[config.id] = config.toDsl(); - let subAggs; + const dsl = dslLvlCursor[config.id] = config.toDsl(); + let subAggs; - parseParentAggs(dslLvlCursor, dsl); + parseParentAggs(dslLvlCursor, dsl); - if (config.schema.group === 'buckets' && i < list.length - 1) { - // buckets that are not the last item in the list accept sub-aggs - subAggs = dsl.aggs || (dsl.aggs = {}); - } + if (config.schema.group === 'buckets' && i < list.length - 1) { + // buckets that are not the last item in the list accept sub-aggs + subAggs = dsl.aggs || (dsl.aggs = {}); + } - if (subAggs && nestedMetrics) { - nestedMetrics.forEach(function (agg) { - subAggs[agg.config.id] = agg.dsl; - }); - } - }); - - removeParentAggs(dslTopLvl); - return dslTopLvl; - }; - - AggConfigs.prototype.getRequestAggs = function () { - //collect all the aggregations - const aggregations = this.reduce((requestValuesAggs, agg) => { - const aggs = agg.getRequestAggs(); - return aggs ? requestValuesAggs.concat(aggs) : requestValuesAggs; - }, []); - //move metrics to the end - return _.sortBy(aggregations, function (agg) { - return agg.schema.group === 'metrics' ? 1 : 0; - }); - }; - - /** - * Gets the AggConfigs (and possibly ResponseAggConfigs) that - * represent the values that will be produced when all aggs - * are run. - * - * With multi-value metric aggs it is possible for a single agg - * request to result in multiple agg values, which is why the length - * of a vis' responseValuesAggs may be different than the vis' aggs - * - * @return {array[AggConfig]} - */ - AggConfigs.prototype.getResponseAggs = function () { - return this.getRequestAggs().reduce(function (responseValuesAggs, agg) { - const aggs = agg.getResponseAggs(); - return aggs ? responseValuesAggs.concat(aggs) : responseValuesAggs; - }, []); - }; - - - /** - * Find a response agg by it's id. This may be an agg in the aggConfigs, or one - * created specifically for a response value - * - * @param {string} id - the id of the agg to find - * @return {AggConfig} - */ - AggConfigs.prototype.getResponseAggById = function (id) { - id = String(id); - const reqAgg = _.find(this.getRequestAggs(), function (agg) { - return id.substr(0, String(agg.id).length) === agg.id; + if (subAggs && nestedMetrics) { + nestedMetrics.forEach(function (agg) { + subAggs[agg.config.id] = agg.dsl; + }); + } }); - if (!reqAgg) return; - return _.find(reqAgg.getResponseAggs(), { id: id }); - }; - return AggConfigs; -} + removeParentAggs(dslTopLvl); + return dslTopLvl; +}; + +AggConfigs.prototype.getRequestAggs = function () { + //collect all the aggregations + const aggregations = this.reduce((requestValuesAggs, agg) => { + const aggs = agg.getRequestAggs(); + return aggs ? requestValuesAggs.concat(aggs) : requestValuesAggs; + }, []); + //move metrics to the end + return _.sortBy(aggregations, function (agg) { + return agg.schema.group === 'metrics' ? 1 : 0; + }); +}; + +/** + * Gets the AggConfigs (and possibly ResponseAggConfigs) that + * represent the values that will be produced when all aggs + * are run. + * + * With multi-value metric aggs it is possible for a single agg + * request to result in multiple agg values, which is why the length + * of a vis' responseValuesAggs may be different than the vis' aggs + * + * @return {array[AggConfig]} + */ +AggConfigs.prototype.getResponseAggs = function () { + return this.getRequestAggs().reduce(function (responseValuesAggs, agg) { + const aggs = agg.getResponseAggs(); + return aggs ? responseValuesAggs.concat(aggs) : responseValuesAggs; + }, []); +}; + + +/** + * Find a response agg by it's id. This may be an agg in the aggConfigs, or one + * created specifically for a response value + * + * @param {string} id - the id of the agg to find + * @return {AggConfig} + */ +AggConfigs.prototype.getResponseAggById = function (id) { + id = String(id); + const reqAgg = _.find(this.getRequestAggs(), function (agg) { + return id.substr(0, String(agg.id).length) === agg.id; + }); + if (!reqAgg) return; + return _.find(reqAgg.getResponseAggs(), { id: id }); +}; + +export { AggConfigs }; diff --git a/src/ui/public/vis/vis.js b/src/ui/public/vis/vis.js index 43fe40b60cee82..787c69446a490e 100644 --- a/src/ui/public/vis/vis.js +++ b/src/ui/public/vis/vis.js @@ -11,7 +11,7 @@ import { EventEmitter } from 'events'; import _ from 'lodash'; import { VisTypesRegistryProvider } from 'ui/registry/vis_types'; -import { VisAggConfigsProvider } from 'ui/vis/agg_configs'; +import { AggConfigs } from 'ui/vis/agg_configs'; import { PersistedState } from 'ui/persisted_state'; import { UtilsBrushEventProvider } from 'ui/utils/brush_event'; import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter'; @@ -23,7 +23,6 @@ import { SavedObjectsClientProvider } from 'ui/saved_objects'; export function VisProvider(Private, Promise, indexPatterns, timefilter, getAppState) { const visTypes = Private(VisTypesRegistryProvider); - const AggConfigs = Private(VisAggConfigsProvider); const brushEvent = Private(UtilsBrushEventProvider); const queryFilter = Private(FilterBarQueryFilterProvider); const filterBarClickHandler = Private(FilterBarClickHandlerProvider);