[6.x] remove angular from AggTypes (#17681) (#18884)

* remove angular from AggTypes (#17681)

# Conflicts:
#	src/ui/public/agg_response/point_series/__tests__/_fake_x_aspect.js
#	src/ui/public/agg_response/point_series/_fake_x_aspect.js
#	src/ui/public/agg_types/__tests__/agg_param_writer.js
#	src/ui/public/agg_types/__tests__/agg_type.js
#	src/ui/public/agg_types/__tests__/buckets/_geo_hash.js
#	src/ui/public/agg_types/__tests__/buckets/_histogram.js
#	src/ui/public/agg_types/__tests__/buckets/_terms_other_bucket_helper.js
#	src/ui/public/agg_types/__tests__/buckets/create_filter/date_histogram.js
#	src/ui/public/agg_types/__tests__/buckets/create_filter/date_range.js
#	src/ui/public/agg_types/__tests__/buckets/create_filter/filters.js
#	src/ui/public/agg_types/__tests__/buckets/create_filter/histogram.js
#	src/ui/public/agg_types/__tests__/buckets/create_filter/ip_range.js
#	src/ui/public/agg_types/__tests__/buckets/create_filter/range.js
#	src/ui/public/agg_types/__tests__/buckets/create_filter/terms.js
#	src/ui/public/agg_types/__tests__/buckets/date_histogram/_editor.js
#	src/ui/public/agg_types/__tests__/buckets/date_histogram/_params.js
#	src/ui/public/agg_types/__tests__/buckets/terms.js
#	src/ui/public/agg_types/__tests__/index.js
#	src/ui/public/agg_types/__tests__/metrics/parent_pipeline.js
#	src/ui/public/agg_types/__tests__/metrics/percentile_ranks.js
#	src/ui/public/agg_types/__tests__/metrics/percentiles.js
#	src/ui/public/agg_types/__tests__/metrics/sibling_pipeline.js
#	src/ui/public/agg_types/__tests__/metrics/std_deviation.js
#	src/ui/public/agg_types/__tests__/metrics/top_hit.js
#	src/ui/public/agg_types/buckets/_bucket_agg_type.js
#	src/ui/public/agg_types/buckets/_terms_other_bucket_helper.js
#	src/ui/public/agg_types/buckets/create_filter/date_range.js
#	src/ui/public/agg_types/buckets/date_histogram.js
#	src/ui/public/agg_types/buckets/date_range.js
#	src/ui/public/agg_types/buckets/filter.js
#	src/ui/public/agg_types/buckets/filters.js
#	src/ui/public/agg_types/buckets/geo_hash.js
#	src/ui/public/agg_types/buckets/histogram.js
#	src/ui/public/agg_types/buckets/ip_range.js
#	src/ui/public/agg_types/buckets/range.js
#	src/ui/public/agg_types/buckets/significant_terms.js
#	src/ui/public/agg_types/buckets/terms.js
#	src/ui/public/agg_types/index.js
#	src/ui/public/agg_types/metrics/avg.js
#	src/ui/public/agg_types/metrics/bucket_avg.js
#	src/ui/public/agg_types/metrics/bucket_max.js
#	src/ui/public/agg_types/metrics/bucket_min.js
#	src/ui/public/agg_types/metrics/bucket_sum.js
#	src/ui/public/agg_types/metrics/cardinality.js
#	src/ui/public/agg_types/metrics/count.js
#	src/ui/public/agg_types/metrics/cumulative_sum.js
#	src/ui/public/agg_types/metrics/derivative.js
#	src/ui/public/agg_types/metrics/geo_bounds.js
#	src/ui/public/agg_types/metrics/geo_centroid.js
#	src/ui/public/agg_types/metrics/max.js
#	src/ui/public/agg_types/metrics/median.js
#	src/ui/public/agg_types/metrics/metric_agg_type.js
#	src/ui/public/agg_types/metrics/min.js
#	src/ui/public/agg_types/metrics/moving_avg.js
#	src/ui/public/agg_types/metrics/percentile_ranks.js
#	src/ui/public/agg_types/metrics/percentiles.js
#	src/ui/public/agg_types/metrics/serial_diff.js
#	src/ui/public/agg_types/metrics/std_deviation.js
#	src/ui/public/agg_types/metrics/sum.js
#	src/ui/public/agg_types/metrics/top_hit.js
#	src/ui/public/courier/data_source/__tests__/decorate_query.js
#	src/ui/public/time_buckets/time_buckets.js
#	src/ui/public/vis/__tests__/_agg_config.js
#	src/ui/public/vis/agg_configs.js
#	src/ui/public/vis/editors/default/agg_params.js

* updating x-pack
This commit is contained in:
Peter Pisljar 2018-05-07 20:28:52 -05:00 committed by GitHub
parent 8079bec770
commit 5961589ed2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
98 changed files with 2546 additions and 2865 deletions

View file

@ -21,7 +21,7 @@ import { BasicResponseHandlerProvider } from 'ui/vis/response_handlers/basic';
import { DocTitleProvider } from 'ui/doc_title';
import PluginsKibanaDiscoverHitSortFnProvider from '../_hit_sort_fn';
import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter';
import { AggTypesBucketsIntervalOptionsProvider } from 'ui/agg_types/buckets/_interval_options';
import { intervalOptions } from 'ui/agg_types/buckets/_interval_options';
import { stateMonitorFactory } from 'ui/state_management/state_monitor_factory';
import uiRoutes from 'ui/routes';
import { uiModules } from 'ui/modules';
@ -138,7 +138,7 @@ function discoverController(
});
$scope.getDocLink = getDocLink;
$scope.intervalOptions = Private(AggTypesBucketsIntervalOptionsProvider);
$scope.intervalOptions = intervalOptions;
$scope.showInterval = false;
$scope.minimumVisibleRows = 50;

View file

@ -2,20 +2,18 @@ import expect from 'expect.js';
import ngMock from 'ng_mock';
import { VisProvider } from '../../../vis';
import { AggConfig } from '../../../vis/agg_config';
import { AggTypesAggTypeProvider } from '../../../agg_types/agg_type';
import { AggType } from '../../../agg_types/agg_type';
import { PointSeriesFakeXAxisProvider } from '../_fake_x_aspect';
describe('makeFakeXAspect', function () {
let makeFakeXAspect;
let Vis;
let AggType;
let indexPattern;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
Vis = Private(VisProvider);
AggType = Private(AggTypesAggTypeProvider);
indexPattern = Private(VisProvider);
makeFakeXAspect = Private(PointSeriesFakeXAxisProvider);
}));

View file

@ -1,8 +1,7 @@
import { AggConfig } from '../../vis/agg_config';
import { AggTypesAggTypeProvider } from '../../agg_types/agg_type';
import { AggType } from '../../agg_types/agg_type';
export function PointSeriesFakeXAxisProvider(Private) {
const AggType = Private(AggTypesAggTypeProvider);
export function PointSeriesFakeXAxisProvider() {
const allAgg = new AggType({
name: 'all',

View file

@ -1,6 +1,6 @@
import _ from 'lodash';
import { VisProvider } from '../../vis';
import { AggTypesIndexProvider } from '..';
import { aggTypes } from '..';
import { VisTypesRegistryProvider } from '../../registry/vis_types';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { AggConfig } from '../../vis/agg_config';
@ -8,7 +8,6 @@ import { AggConfig } from '../../vis/agg_config';
// eslint-disable-next-line @elastic/kibana-custom/no-default-export
export default function AggParamWriterHelper(Private) {
const Vis = Private(VisProvider);
const aggTypes = Private(AggTypesIndexProvider);
const visTypes = Private(VisTypesRegistryProvider);
const stubbedLogstashIndexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);

View file

@ -5,11 +5,10 @@ import '../../private';
import { AggParams } from '../agg_params';
import { VisProvider } from '../../vis';
import { fieldFormats } from '../../registry/field_formats';
import { AggTypesAggTypeProvider } from '../agg_type';
import { AggType } from '../agg_type';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
describe('AggType Class', function () {
let AggType;
let indexPattern;
let Vis;
@ -18,7 +17,6 @@ describe('AggType Class', function () {
beforeEach(ngMock.inject(function (Private) {
Vis = Private(VisProvider);
AggType = Private(AggTypesAggTypeProvider);
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
}));

View file

@ -1,9 +1,10 @@
import expect from 'expect.js';
import sinon from 'sinon';
import ngMock from 'ng_mock';
import { AggTypesBucketsGeoHashProvider } from '../../buckets/geo_hash';
import { geoHashBucketAgg } from '../../buckets/geo_hash';
import * as AggConfigModule from '../../../vis/agg_config';
import { AggTypesIndexProvider } from '../..';
import * as BucketAggTypeModule from '../../buckets/_bucket_agg_type';
import { aggTypes } from '../..';
AggConfigModule.AggConfig.aggTypes = aggTypes;
describe('Geohash Agg', () => {
@ -40,27 +41,15 @@ describe('Geohash Agg', () => {
const AggConfigMock = (vis, aggOptions) => {
return aggOptions;
};
const PrivateMock = (provider) => {
switch (provider.name) {
case 'AggTypesBucketsBucketAggTypeProvider':
return BucketAggTypeMock;
break;
default:
return () => {};
}
};
const configMock = {
get: () => {
return 7;//"visualization:tileMap:maxPrecision"
}
};
before(function () {
sinon.stub(AggConfigModule, 'AggConfig', AggConfigMock);
sinon.stub(BucketAggTypeModule, 'BucketAggType', BucketAggTypeMock);
});
after(function () {
AggConfigModule.AggConfig.restore();
BucketAggTypeModule.BucketAggType.restore();
});
@ -93,23 +82,12 @@ describe('Geohash Agg', () => {
};
}
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
AggConfigModule.AggConfig.aggTypes = Private(AggTypesIndexProvider);
}));
let geohashAgg;
beforeEach(() => {
geohashAgg = AggTypesBucketsGeoHashProvider(PrivateMock, configMock); // eslint-disable-line new-cap
});
describe('precision parameter', () => {
const PRECISION_PARAM_INDEX = 6;
let precisionParam;
beforeEach(() => {
precisionParam = geohashAgg.params[PRECISION_PARAM_INDEX];
precisionParam = geoHashBucketAgg.params[PRECISION_PARAM_INDEX];
});
it('should select precision parameter', () => {
@ -169,7 +147,7 @@ describe('Geohash Agg', () => {
beforeEach(() => {
initVisSessionState();
initAggParams();
requestAggs = geohashAgg.getRequestAggs(aggMock);
requestAggs = geoHashBucketAgg.getRequestAggs(aggMock);
});
it('should create filter, geohash_grid, and geo_centroid aggregations', () => {
@ -189,7 +167,7 @@ describe('Geohash Agg', () => {
// there was a bug because of an "&& mapZoom" check which excluded 0 as a valid mapZoom, but it is.
it('should create filter, geohash_grid, and geo_centroid aggregations when zoom level 0', () => {
aggMock.vis.params.mapZoom = 0;
requestAggs = geohashAgg.getRequestAggs(aggMock);
requestAggs = geoHashBucketAgg.getRequestAggs(aggMock);
expect(requestAggs.length).to.equal(3);
expect(requestAggs[0].type).to.equal('filter');
expect(requestAggs[1].type).to.equal('geohash_grid');
@ -206,7 +184,7 @@ describe('Geohash Agg', () => {
it('should only create geohash_grid and geo_centroid aggregations when isFilteredByCollar is false', () => {
aggMock.params.isFilteredByCollar = false;
const requestAggs = geohashAgg.getRequestAggs(aggMock);
const requestAggs = geoHashBucketAgg.getRequestAggs(aggMock);
expect(requestAggs.length).to.equal(2);
expect(requestAggs[0].type).to.equal('geohash_grid');
expect(requestAggs[1].type).to.equal('geo_centroid');
@ -214,7 +192,7 @@ describe('Geohash Agg', () => {
it('should only create filter and geohash_grid aggregations when useGeocentroid is false', () => {
aggMock.params.useGeocentroid = false;
const requestAggs = geohashAgg.getRequestAggs(aggMock);
const requestAggs = geoHashBucketAgg.getRequestAggs(aggMock);
expect(requestAggs.length).to.equal(2);
expect(requestAggs[0].type).to.equal('filter');
expect(requestAggs[1].type).to.equal('geohash_grid');
@ -229,7 +207,7 @@ describe('Geohash Agg', () => {
beforeEach(() => {
resetMap();
initAggParams();
origRequestAggs = geohashAgg.getRequestAggs(aggMock);
origRequestAggs = geoHashBucketAgg.getRequestAggs(aggMock);
origMapCollar = aggMock.vis.sessionState.mapCollar;
});
@ -239,7 +217,7 @@ describe('Geohash Agg', () => {
bottom_right: { lat: -0.9, lon: 0.9 }
});
const newRequestAggs = geohashAgg.getRequestAggs(aggMock);
const newRequestAggs = geoHashBucketAgg.getRequestAggs(aggMock);
expect(JSON.stringify(origRequestAggs[0].params, null, '')).to.equal(JSON.stringify(newRequestAggs[0].params, null, ''));
const newMapCollar = aggMock.vis.sessionState.mapCollar;
@ -252,7 +230,7 @@ describe('Geohash Agg', () => {
bottom_right: { lat: 9.0, lon: -9.0 }
});
const newRequestAggs = geohashAgg.getRequestAggs(aggMock);
const newRequestAggs = geoHashBucketAgg.getRequestAggs(aggMock);
expect(JSON.stringify(origRequestAggs[0].params, null, '')).not.to.equal(JSON.stringify(newRequestAggs[0].params, null, ''));
const newMapCollar = aggMock.vis.sessionState.mapCollar;
@ -262,7 +240,7 @@ describe('Geohash Agg', () => {
it('should change geo_bounding_box filter aggregation and vis session state when map zoom level changes', () => {
zoomMap(-1);
const newRequestAggs = geohashAgg.getRequestAggs(aggMock);
const newRequestAggs = geoHashBucketAgg.getRequestAggs(aggMock);
expect(JSON.stringify(origRequestAggs[0].params, null, '')).not.to.equal(JSON.stringify(newRequestAggs[0].params, null, ''));
const newMapCollar = aggMock.vis.sessionState.mapCollar;

View file

@ -1,16 +1,12 @@
import expect from 'expect.js';
import ngMock from 'ng_mock';
import { AggTypesIndexProvider } from '../..';
import { aggTypes } from '../..';
import AggParamWriterProvider from '../agg_param_writer';
const histogram = aggTypes.byName.histogram;
describe('Histogram Agg', function () {
describe('ordered', function () {
let histogram;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
histogram = Private(AggTypesIndexProvider).byName.histogram;
}));
it('is ordered', function () {
expect(histogram.ordered).to.be.ok();

View file

@ -1,6 +1,6 @@
import expect from 'expect.js';
import ngMock from 'ng_mock';
import { OtherBucketHelperProvider } from '../../buckets/_terms_other_bucket_helper';
import { buildOtherBucketAgg, mergeOtherBucketAggResponse, updateMissingBucket } from '../../buckets/_terms_other_bucket_helper';
import { VisProvider } from '../../../vis';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
@ -118,7 +118,6 @@ const nestedOtherResponse = {
describe('Terms Agg Other bucket helper', () => {
let otherBucketHelper;
let vis;
function init(aggConfig) {
@ -126,7 +125,6 @@ describe('Terms Agg Other bucket helper', () => {
ngMock.inject((Private) => {
const Vis = Private(VisProvider);
const indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
otherBucketHelper = Private(OtherBucketHelperProvider);
vis = new Vis(indexPattern, aggConfig);
});
@ -136,13 +134,13 @@ describe('Terms Agg Other bucket helper', () => {
it('returns a function', () => {
init(visConfigSingleTerm);
const agg = otherBucketHelper.buildOtherBucketAgg(vis.aggs, vis.aggs[0], singleTermResponse);
const agg = buildOtherBucketAgg(vis.aggs, vis.aggs[0], singleTermResponse);
expect(agg).to.be.a('function');
});
it('correctly builds query with single terms agg', () => {
init(visConfigSingleTerm);
const agg = otherBucketHelper.buildOtherBucketAgg(vis.aggs, vis.aggs[0], singleTermResponse)();
const agg = buildOtherBucketAgg(vis.aggs, vis.aggs[0], singleTermResponse)();
const expectedResponse = {
aggs: undefined,
filters: {
@ -171,7 +169,7 @@ describe('Terms Agg Other bucket helper', () => {
it('correctly builds query for nested terms agg', () => {
init(visConfigNestedTerm);
const agg = otherBucketHelper.buildOtherBucketAgg(vis.aggs, vis.aggs[1], nestedTermResponse)();
const agg = buildOtherBucketAgg(vis.aggs, vis.aggs[1], nestedTermResponse)();
const expectedResponse = {
'other-filter': {
aggs: undefined,
@ -220,9 +218,13 @@ describe('Terms Agg Other bucket helper', () => {
describe('mergeOtherBucketAggResponse', () => {
it('correctly merges other bucket with single terms agg', () => {
init(visConfigSingleTerm);
const otherAggConfig = otherBucketHelper.buildOtherBucketAgg(vis.aggs, vis.aggs[0], singleTermResponse)();
const mergedResponse = otherBucketHelper
.mergeOtherBucketAggResponse(vis.aggs, singleTermResponse, singleOtherResponse, vis.aggs[0], otherAggConfig);
const otherAggConfig = buildOtherBucketAgg(vis.aggs, vis.aggs[0], singleTermResponse)();
const mergedResponse = mergeOtherBucketAggResponse(
vis.aggs,
singleTermResponse,
singleOtherResponse,
vis.aggs[0],
otherAggConfig);
expect(mergedResponse.aggregations['1'].buckets[3].key).to.equal('Other');
expect(mergedResponse.aggregations['1'].buckets[3].filters.length).to.equal(2);
@ -230,9 +232,9 @@ describe('Terms Agg Other bucket helper', () => {
it('correctly merges other bucket with nested terms agg', () => {
init(visConfigNestedTerm);
const otherAggConfig = otherBucketHelper.buildOtherBucketAgg(vis.aggs, vis.aggs[1], nestedTermResponse)();
const mergedResponse = otherBucketHelper
.mergeOtherBucketAggResponse(vis.aggs, nestedTermResponse, nestedOtherResponse, vis.aggs[1], otherAggConfig);
const otherAggConfig = buildOtherBucketAgg(vis.aggs, vis.aggs[1], nestedTermResponse)();
const mergedResponse = mergeOtherBucketAggResponse(vis.aggs, nestedTermResponse,
nestedOtherResponse, vis.aggs[1], otherAggConfig);
expect(mergedResponse.aggregations['1'].buckets[1]['2'].buckets[3].key).to.equal('Other');
expect(mergedResponse.aggregations['1'].buckets[1]['2'].buckets[3].filters.length).to.equal(2);
@ -243,12 +245,12 @@ describe('Terms Agg Other bucket helper', () => {
describe('updateMissingBucket', () => {
it('correctly updates missing bucket key', () => {
init(visConfigNestedTerm);
const updatedResponse = otherBucketHelper.updateMissingBucket(singleTermResponse, vis.aggs, vis.aggs[0]);
const updatedResponse = updateMissingBucket(singleTermResponse, vis.aggs, vis.aggs[0]);
expect(updatedResponse.aggregations['1'].buckets.find(bucket => bucket.key === 'Missing')).to.not.be('undefined');
});
it('correctly sets the bucket filter', () => {
const updatedResponse = otherBucketHelper.updateMissingBucket(singleTermResponse, vis.aggs, vis.aggs[0]);
const updatedResponse = updateMissingBucket(singleTermResponse, vis.aggs, vis.aggs[0]);
const missingBucket = updatedResponse.aggregations['1'].buckets.find(bucket => bucket.key === 'Missing');
expect(missingBucket.filters).to.not.be('undefined');
expect(missingBucket.filters[0]).to.eql({

View file

@ -5,8 +5,8 @@ import ngMock from 'ng_mock';
import expect from 'expect.js';
import { VisProvider } from '../../../../vis';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { AggTypesBucketsCreateFilterDateHistogramProvider } from '../../../buckets/create_filter/date_histogram';
import { AggTypesBucketsIntervalOptionsProvider } from '../../../buckets/_interval_options';
import { createFilterDateHistogram } from '../../../buckets/create_filter/date_histogram';
import { intervalOptions } from '../../../buckets/_interval_options';
describe('AggConfig Filters', function () {
describe('date_histogram', function () {
@ -16,7 +16,6 @@ describe('AggConfig Filters', function () {
let filter;
let bucketKey;
let bucketStart;
let intervalOptions;
let init;
@ -24,8 +23,6 @@ describe('AggConfig Filters', function () {
beforeEach(ngMock.inject(function (Private) {
const Vis = Private(VisProvider);
const indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
const createFilter = Private(AggTypesBucketsCreateFilterDateHistogramProvider);
intervalOptions = Private(AggTypesBucketsIntervalOptionsProvider);
init = function (interval, duration) {
interval = interval || 'auto';
@ -54,7 +51,7 @@ describe('AggConfig Filters', function () {
});
agg.buckets.setInterval(interval);
filter = createFilter(agg, bucketKey);
filter = createFilterDateHistogram(agg, bucketKey);
};
}));

View file

@ -3,19 +3,17 @@ import expect from 'expect.js';
import ngMock from 'ng_mock';
import { VisProvider } from '../../../../vis';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { AggTypesBucketsCreateFilterDateRangeProvider } from '../../../buckets/create_filter/date_range';
import { createFilterDateRange } from '../../../buckets/create_filter/date_range';
describe('AggConfig Filters', function () {
describe('Date range', function () {
let indexPattern;
let Vis;
let createFilter;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
Vis = Private(VisProvider);
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
createFilter = Private(AggTypesBucketsCreateFilterDateRangeProvider);
}));
it('should return a range filter for date_range agg', function () {
@ -35,7 +33,7 @@ describe('AggConfig Filters', function () {
});
const aggConfig = vis.aggs.byTypeName.date_range[0];
const filter = createFilter(aggConfig, 'February 1st, 2015 to February 7th, 2015');
const filter = createFilterDateRange(aggConfig, 'February 1st, 2015 to February 7th, 2015');
expect(filter).to.have.property('range');
expect(filter).to.have.property('meta');
expect(filter.meta).to.have.property('index', indexPattern.id);

View file

@ -2,19 +2,17 @@ import expect from 'expect.js';
import ngMock from 'ng_mock';
import { VisProvider } from '../../../../vis';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { AggTypesBucketsCreateFilterFiltersProvider } from '../../../buckets/create_filter/filters';
import { createFilterFilters } from '../../../buckets/create_filter/filters';
describe('AggConfig Filters', function () {
describe('filters', function () {
let indexPattern;
let Vis;
let createFilter;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
Vis = Private(VisProvider);
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
createFilter = Private(AggTypesBucketsCreateFilterFiltersProvider);
}));
it('should return a filters filter', function () {
@ -35,7 +33,7 @@ describe('AggConfig Filters', function () {
});
const aggConfig = vis.aggs.byTypeName.filters[0];
const filter = createFilter(aggConfig, 'type:nginx');
const filter = createFilterFilters(aggConfig, 'type:nginx');
expect(filter.query.query_string.query).to.be('type:nginx');
expect(filter.meta).to.have.property('index', indexPattern.id);

View file

@ -3,19 +3,17 @@ import expect from 'expect.js';
import ngMock from 'ng_mock';
import { VisProvider } from '../../../../vis';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { AggTypesBucketsCreateFilterHistogramProvider } from '../../../buckets/create_filter/histogram';
import { createFilterHistogram } from '../../../buckets/create_filter/histogram';
describe('AggConfig Filters', function () {
describe('histogram', function () {
let indexPattern;
let Vis;
let createFilter;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
Vis = Private(VisProvider);
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
createFilter = Private(AggTypesBucketsCreateFilterHistogramProvider);
}));
it('should return an range filter for histogram', function () {
@ -31,7 +29,7 @@ describe('AggConfig Filters', function () {
});
const aggConfig = vis.aggs.byTypeName.histogram[0];
const filter = createFilter(aggConfig, 2048);
const filter = createFilterHistogram(aggConfig, 2048);
expect(filter).to.have.property('meta');
expect(filter.meta).to.have.property('index', indexPattern.id);
expect(filter).to.have.property('range');

View file

@ -2,19 +2,17 @@ import expect from 'expect.js';
import ngMock from 'ng_mock';
import { VisProvider } from '../../../../vis';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { AggTypesBucketsCreateFilterIpRangeProvider } from '../../../buckets/create_filter/ip_range';
import { createFilterIpRange } from '../../../buckets/create_filter/ip_range';
describe('AggConfig Filters', function () {
describe('IP range', function () {
let indexPattern;
let Vis;
let createFilter;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
Vis = Private(VisProvider);
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
createFilter = Private(AggTypesBucketsCreateFilterIpRangeProvider);
}));
it('should return a range filter for ip_range agg', function () {
@ -38,7 +36,7 @@ describe('AggConfig Filters', function () {
});
const aggConfig = vis.aggs.byTypeName.ip_range[0];
const filter = createFilter(aggConfig, '0.0.0.0 to 1.1.1.1');
const filter = createFilterIpRange(aggConfig, '0.0.0.0 to 1.1.1.1');
expect(filter).to.have.property('range');
expect(filter).to.have.property('meta');
expect(filter.meta).to.have.property('index', indexPattern.id);
@ -68,7 +66,7 @@ describe('AggConfig Filters', function () {
});
const aggConfig = vis.aggs.byTypeName.ip_range[0];
const filter = createFilter(aggConfig, '67.129.65.201/27');
const filter = createFilterIpRange(aggConfig, '67.129.65.201/27');
expect(filter).to.have.property('range');
expect(filter).to.have.property('meta');
expect(filter.meta).to.have.property('index', indexPattern.id);

View file

@ -2,20 +2,18 @@ import expect from 'expect.js';
import ngMock from 'ng_mock';
import { VisProvider } from '../../../../vis';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { AggTypesBucketsCreateFilterRangeProvider } from '../../../buckets/create_filter/range';
import { createFilterRange } from '../../../buckets/create_filter/range';
describe('AggConfig Filters', function () {
describe('range', function () {
let indexPattern;
let Vis;
let createFilter;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
Vis = Private(VisProvider);
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
createFilter = Private(AggTypesBucketsCreateFilterRangeProvider);
}));
it('should return a range filter for range agg', function () {
@ -36,7 +34,7 @@ describe('AggConfig Filters', function () {
});
const aggConfig = vis.aggs.byTypeName.range[0];
const filter = createFilter(aggConfig, { gte: 1024, lt: 2048.0 });
const filter = createFilterRange(aggConfig, { gte: 1024, lt: 2048.0 });
expect(filter).to.have.property('range');
expect(filter).to.have.property('meta');
expect(filter.meta).to.have.property('index', indexPattern.id);

View file

@ -2,20 +2,18 @@ import expect from 'expect.js';
import ngMock from 'ng_mock';
import { VisProvider } from '../../../../vis';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { AggTypesBucketsCreateFilterTermsProvider } from '../../../buckets/create_filter/terms';
import { createFilterTerms } from '../../../buckets/create_filter/terms';
describe('AggConfig Filters', function () {
describe('terms', function () {
let indexPattern;
let Vis;
let createFilter;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
Vis = Private(VisProvider);
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
createFilter = Private(AggTypesBucketsCreateFilterTermsProvider);
}));
it('should return a match filter for terms', function () {
@ -24,7 +22,7 @@ describe('AggConfig Filters', function () {
aggs: [ { type: 'terms', schema: 'segment', params: { field: '_type' } } ]
});
const aggConfig = vis.aggs.byTypeName.terms[0];
const filter = createFilter(aggConfig, 'apache');
const filter = createFilterTerms(aggConfig, 'apache');
expect(filter).to.have.property('query');
expect(filter.query).to.have.property('match');
expect(filter.query.match).to.have.property('_type');
@ -41,13 +39,13 @@ describe('AggConfig Filters', function () {
aggs: [ { type: 'terms', schema: 'segment', params: { field: 'ssl' } } ]
});
const aggConfig = vis.aggs.byTypeName.terms[0];
const filterFalse = createFilter(aggConfig, 0);
const filterFalse = createFilterTerms(aggConfig, 0);
expect(filterFalse).to.have.property('query');
expect(filterFalse.query).to.have.property('match');
expect(filterFalse.query.match).to.have.property('ssl');
expect(filterFalse.query.match.ssl).to.have.property('query', false);
const filterTrue = createFilter(aggConfig, 1);
const filterTrue = createFilterTerms(aggConfig, 1);
expect(filterTrue).to.have.property('query');
expect(filterTrue.query).to.have.property('match');
expect(filterTrue.query.match).to.have.property('ssl');

View file

@ -4,7 +4,7 @@ import ngMock from 'ng_mock';
import expect from 'expect.js';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { VisProvider } from '../../../../vis';
import { AggTypesBucketsIntervalOptionsProvider } from '../../../buckets/_interval_options';
import { intervalOptions } from '../../../buckets/_interval_options';
describe('editor', function () {
@ -74,9 +74,9 @@ describe('editor', function () {
let field;
let interval;
beforeEach(ngMock.inject(function (Private) {
beforeEach(ngMock.inject(function () {
field = _.sample(indexPattern.fields);
interval = _.sample(Private(AggTypesBucketsIntervalOptionsProvider));
interval = _.sample(intervalOptions);
params = render({ field: field, interval: interval });
}));

View file

@ -4,7 +4,7 @@ import expect from 'expect.js';
import ngMock from 'ng_mock';
import AggParamWriterProvider from '../../agg_param_writer';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { AggTypesIndexProvider } from '../../..';
import { aggTypes } from '../../..';
import { AggConfig } from '../../../../vis/agg_config';
describe('params', function () {
@ -12,7 +12,6 @@ describe('params', function () {
let paramWriter;
let writeInterval;
let aggTypes;
let setTimeBounds;
let timeField;
@ -23,7 +22,6 @@ describe('params', function () {
const timefilter = $injector.get('timefilter');
timeField = indexPattern.timeFieldName;
aggTypes = Private(AggTypesIndexProvider);
paramWriter = new AggParamWriter({ aggType: 'date_histogram' });
writeInterval = function (interval) {

View file

@ -1,6 +1,6 @@
import expect from 'expect.js';
import ngMock from 'ng_mock';
import { AggTypesIndexProvider } from '../..';
import { aggTypes } from '../..';
describe('Terms Agg', function () {
describe('order agg editor UI', function () {
@ -10,7 +10,7 @@ describe('Terms Agg', function () {
function init({ responseValueAggs = [], aggParams = {} }) {
ngMock.module('kibana');
ngMock.inject(function (Private, $controller, _$rootScope_) {
const terms = Private(AggTypesIndexProvider).byName.terms;
const terms = aggTypes.byName.terms;
const orderAggController = terms.params.byName.orderAgg.controller;
$rootScope = _$rootScope_;

View file

@ -1,5 +1,4 @@
import expect from 'expect.js';
import ngMock from 'ng_mock';
import './agg_type';
import './agg_params';
import './buckets/_histogram';
@ -8,22 +7,16 @@ import './buckets/_range';
import './buckets/_terms_other_bucket_helper';
import './buckets/date_histogram/_editor';
import './buckets/date_histogram/_params';
import { AggTypesIndexProvider } from '..';
import { AggTypesBucketsBucketAggTypeProvider } from '../buckets/_bucket_agg_type';
import { AggTypesMetricsMetricAggTypeProvider } from '../metrics/metric_agg_type';
import { aggTypes } from '..';
import { BucketAggType } from '../buckets/_bucket_agg_type';
import { MetricAggType } from '../metrics/metric_agg_type';
const bucketAggs = aggTypes.byType.buckets;
const metricAggs = aggTypes.byType.metrics;
describe('AggTypesComponent', function () {
describe('bucket aggs', function () {
let bucketAggs;
let BucketAggType;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
bucketAggs = Private(AggTypesIndexProvider).byType.buckets;
BucketAggType = Private(AggTypesBucketsBucketAggTypeProvider);
}));
it('all extend BucketAggType', function () {
bucketAggs.forEach(function (bucketAgg) {
expect(bucketAgg).to.be.a(BucketAggType);
@ -32,15 +25,6 @@ describe('AggTypesComponent', function () {
});
describe('metric aggs', function () {
let metricAggs;
let MetricAggType;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
metricAggs = Private(AggTypesIndexProvider).byType.metrics;
MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
}));
it('all extend MetricAggType', function () {
metricAggs.forEach(function (metricAgg) {
expect(metricAgg).to.be.a(MetricAggType);

View file

@ -1,18 +1,18 @@
import expect from 'expect.js';
import sinon from 'sinon';
import ngMock from 'ng_mock';
import { AggTypesMetricsDerivativeProvider } from '../../metrics/derivative';
import { AggTypesMetricsCumulativeSumProvider } from '../../metrics/cumulative_sum';
import { AggTypesMetricsMovingAvgProvider } from '../../metrics/moving_avg';
import { AggTypesMetricsSerialDiffProvider } from '../../metrics/serial_diff';
import { derivativeMetricAgg } from '../../metrics/derivative';
import { cumulativeSumMetricAgg } from '../../metrics/cumulative_sum';
import { movingAvgMetricAgg } from '../../metrics/moving_avg';
import { serialDiffMetricAgg } from '../../metrics/serial_diff';
import { VisProvider } from '../../../vis';
import StubbedIndexPattern from 'fixtures/stubbed_logstash_index_pattern';
const metrics = [
{ name: 'derivative', title: 'Derivative', provider: AggTypesMetricsDerivativeProvider },
{ name: 'cumulative_sum', title: 'Cumulative Sum', provider: AggTypesMetricsCumulativeSumProvider },
{ name: 'moving_avg', title: 'Moving Avg', provider: AggTypesMetricsMovingAvgProvider },
{ name: 'serial_diff', title: 'Serial Diff', provider: AggTypesMetricsSerialDiffProvider },
{ name: 'derivative', title: 'Derivative', agg: derivativeMetricAgg },
{ name: 'cumulative_sum', title: 'Cumulative Sum', agg: cumulativeSumMetricAgg },
{ name: 'moving_avg', title: 'Moving Avg', agg: movingAvgMetricAgg },
{ name: 'serial_diff', title: 'Serial Diff', agg: serialDiffMetricAgg },
];
describe('parent pipeline aggs', function () {
@ -29,7 +29,7 @@ describe('parent pipeline aggs', function () {
const Vis = Private(VisProvider);
const indexPattern = Private(StubbedIndexPattern);
indexPattern.stubSetFieldFormat('bytes', 'bytes');
metricAgg = Private(metric.provider);
metricAgg = metric.agg;
const params = settings || {
metricAgg: '1',

View file

@ -1,6 +1,6 @@
import expect from 'expect.js';
import ngMock from 'ng_mock';
import { AggTypesMetricsPercentileRanksProvider } from '../../metrics/percentile_ranks';
import { percentileRanksMetricAgg } from '../../metrics/percentile_ranks';
import { VisProvider } from '../../../vis';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
@ -8,13 +8,11 @@ describe('AggTypesMetricsPercentileRanksProvider class', function () {
let Vis;
let indexPattern;
let aggTypeMetricPercentileRanks;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
Vis = Private(VisProvider);
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
aggTypeMetricPercentileRanks = Private(AggTypesMetricsPercentileRanksProvider);
}));
it('uses the custom label if it is set', function () {
@ -29,7 +27,7 @@ describe('AggTypesMetricsPercentileRanksProvider class', function () {
displayName: 'bytes'
};
const responseAggs = aggTypeMetricPercentileRanks.getResponseAggs(aggConfig);
const responseAggs = percentileRanksMetricAgg.getResponseAggs(aggConfig);
const percentileRankLabelFor5kBytes = responseAggs[0].makeLabel();
const percentileRankLabelFor10kBytes = responseAggs[1].makeLabel();

View file

@ -1,6 +1,6 @@
import expect from 'expect.js';
import ngMock from 'ng_mock';
import { AggTypesMetricsPercentilesProvider } from '../../metrics/percentiles';
import { percentilesMetricAgg } from '../../metrics/percentiles';
import { VisProvider } from '../../../vis';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
@ -8,13 +8,11 @@ describe('AggTypesMetricsPercentilesProvider class', function () {
let Vis;
let indexPattern;
let aggTypeMetricPercentiles;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
Vis = Private(VisProvider);
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
aggTypeMetricPercentiles = Private(AggTypesMetricsPercentilesProvider);
}));
it('uses the custom label if it is set', function () {
@ -29,7 +27,7 @@ describe('AggTypesMetricsPercentilesProvider class', function () {
displayName: 'bytes'
};
const responseAggs = aggTypeMetricPercentiles.getResponseAggs(aggConfig);
const responseAggs = percentilesMetricAgg.getResponseAggs(aggConfig);
const ninetyFifthPercentileLabel = responseAggs[0].makeLabel();
expect(ninetyFifthPercentileLabel).to.be('95th percentile of prince');

View file

@ -1,18 +1,18 @@
import expect from 'expect.js';
import sinon from 'sinon';
import ngMock from 'ng_mock';
import { AggTypesMetricsBucketSumProvider } from '../../metrics/bucket_sum';
import { AggTypesMetricsBucketAvgProvider } from '../../metrics/bucket_avg';
import { AggTypesMetricsBucketMinProvider } from '../../metrics/bucket_min';
import { AggTypesMetricsBucketMaxProvider } from '../../metrics/bucket_max';
import { bucketSumMetricAgg } from '../../metrics/bucket_sum';
import { bucketAvgMetricAgg } from '../../metrics/bucket_avg';
import { bucketMinMetricAgg } from '../../metrics/bucket_min';
import { bucketMaxMetricAgg } from '../../metrics/bucket_max';
import { VisProvider } from '../../../vis';
import StubbedIndexPattern from 'fixtures/stubbed_logstash_index_pattern';
const metrics = [
{ name: 'sum_bucket', title: 'Overall Sum', provider: AggTypesMetricsBucketSumProvider },
{ name: 'avg_bucket', title: 'Overall Average', provider: AggTypesMetricsBucketAvgProvider },
{ name: 'min_bucket', title: 'Overall Min', provider: AggTypesMetricsBucketMinProvider },
{ name: 'max_bucket', title: 'Overall Max', provider: AggTypesMetricsBucketMaxProvider },
{ name: 'sum_bucket', title: 'Overall Sum', provider: bucketSumMetricAgg },
{ name: 'avg_bucket', title: 'Overall Average', provider: bucketAvgMetricAgg },
{ name: 'min_bucket', title: 'Overall Min', provider: bucketMinMetricAgg },
{ name: 'max_bucket', title: 'Overall Max', provider: bucketMaxMetricAgg },
];
describe('sibling pipeline aggs', function () {
@ -29,7 +29,7 @@ describe('sibling pipeline aggs', function () {
const Vis = Private(VisProvider);
const indexPattern = Private(StubbedIndexPattern);
indexPattern.stubSetFieldFormat('bytes', 'bytes');
metricAgg = Private(metric.provider);
metricAgg = metric.provider;
const params = settings || {
customMetric: {

View file

@ -1,6 +1,6 @@
import expect from 'expect.js';
import ngMock from 'ng_mock';
import { AggTypesMetricsStdDeviationProvider } from '../../metrics/std_deviation';
import { stdDeviationMetricAgg } from '../../metrics/std_deviation';
import { VisProvider } from '../../../vis';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
@ -8,13 +8,11 @@ describe('AggTypeMetricStandardDeviationProvider class', function () {
let Vis;
let indexPattern;
let aggTypeMetricStandardDeviation;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
Vis = Private(VisProvider);
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
aggTypeMetricStandardDeviation = Private(AggTypesMetricsStdDeviationProvider);
}));
it('uses the custom label if it is set', function () {
@ -28,7 +26,7 @@ describe('AggTypeMetricStandardDeviationProvider class', function () {
displayName: 'memory'
};
const responseAggs = aggTypeMetricStandardDeviation.getResponseAggs(aggConfig);
const responseAggs = stdDeviationMetricAgg.getResponseAggs(aggConfig);
const lowerStdDevLabel = responseAggs[0].makeLabel();
const upperStdDevLabel = responseAggs[1].makeLabel();
@ -46,7 +44,7 @@ describe('AggTypeMetricStandardDeviationProvider class', function () {
displayName: 'memory'
};
const responseAggs = aggTypeMetricStandardDeviation.getResponseAggs(aggConfig);
const responseAggs = stdDeviationMetricAgg.getResponseAggs(aggConfig);
const lowerStdDevLabel = responseAggs[0].makeLabel();
const upperStdDevLabel = responseAggs[1].makeLabel();

View file

@ -1,13 +1,12 @@
import _ from 'lodash';
import expect from 'expect.js';
import ngMock from 'ng_mock';
import { AggTypesMetricsTopHitProvider } from '../../metrics/top_hit';
import { topHitMetricAgg } from '../../metrics/top_hit';
import { VisProvider } from '../../../vis';
import StubbedIndexPattern from 'fixtures/stubbed_logstash_index_pattern';
describe('Top hit metric', function () {
let aggDsl;
let topHitMetric;
let aggConfig;
function init({ field, sortOrder = 'desc', aggregate = 'concat', size = 1 }) {
@ -15,7 +14,6 @@ describe('Top hit metric', function () {
ngMock.inject(function (Private) {
const Vis = Private(VisProvider);
const indexPattern = Private(StubbedIndexPattern);
topHitMetric = Private(AggTypesMetricsTopHitProvider);
const params = {};
if (field) {
@ -54,7 +52,7 @@ describe('Top hit metric', function () {
it('should return a label prefixed with Last if sorting in descending order', function () {
init({ field: 'bytes' });
expect(topHitMetric.makeLabel(aggConfig)).to.eql('Last bytes');
expect(topHitMetricAgg.makeLabel(aggConfig)).to.eql('Last bytes');
});
it('should return a label prefixed with First if sorting in ascending order', function () {
@ -62,7 +60,7 @@ describe('Top hit metric', function () {
field: 'bytes',
sortOrder: 'asc'
});
expect(topHitMetric.makeLabel(aggConfig)).to.eql('First bytes');
expect(topHitMetricAgg.makeLabel(aggConfig)).to.eql('First bytes');
});
it('should request the _source field', function () {
@ -106,7 +104,7 @@ describe('Top hit metric', function () {
};
init({ field: '@tags' });
expect(topHitMetric.getValue(aggConfig, bucket)).to.be(null);
expect(topHitMetricAgg.getValue(aggConfig, bucket)).to.be(null);
});
it('should return undefined if the field does not appear in the source', function () {
@ -125,7 +123,7 @@ describe('Top hit metric', function () {
};
init({ field: '@tags' });
expect(topHitMetric.getValue(aggConfig, bucket)).to.be(undefined);
expect(topHitMetricAgg.getValue(aggConfig, bucket)).to.be(undefined);
});
it('should return the field value from the top hit', function () {
@ -144,7 +142,7 @@ describe('Top hit metric', function () {
};
init({ field: '@tags' });
expect(topHitMetric.getValue(aggConfig, bucket)).to.be('aaa');
expect(topHitMetricAgg.getValue(aggConfig, bucket)).to.be('aaa');
});
it('should return the object if the field value is an object', function () {
@ -165,7 +163,7 @@ describe('Top hit metric', function () {
};
init({ field: '@tags' });
expect(topHitMetric.getValue(aggConfig, bucket)).to.eql({ label: 'aaa' });
expect(topHitMetricAgg.getValue(aggConfig, bucket)).to.eql({ label: 'aaa' });
});
it('should return an array if the field has more than one values', function () {
@ -184,7 +182,7 @@ describe('Top hit metric', function () {
};
init({ field: '@tags' });
expect(topHitMetric.getValue(aggConfig, bucket)).to.eql([ 'aaa', 'bbb' ]);
expect(topHitMetricAgg.getValue(aggConfig, bucket)).to.eql([ 'aaa', 'bbb' ]);
});
it('should get the value from the doc_values field if the source does not have that field', function () {
@ -206,7 +204,7 @@ describe('Top hit metric', function () {
};
init({ field: 'machine.os.raw' });
expect(topHitMetric.getValue(aggConfig, bucket)).to.be('linux');
expect(topHitMetricAgg.getValue(aggConfig, bucket)).to.be('linux');
});
it('should return undefined if the field is not in the source nor in the doc_values field', function () {
@ -228,7 +226,7 @@ describe('Top hit metric', function () {
};
init({ field: 'machine.os.raw' });
expect(topHitMetric.getValue(aggConfig, bucket)).to.be(undefined);
expect(topHitMetricAgg.getValue(aggConfig, bucket)).to.be(undefined);
});
describe('Multivalued field and first/last X docs', function () {
@ -237,7 +235,7 @@ describe('Top hit metric', function () {
field: 'bytes',
size: 2
});
expect(topHitMetric.makeLabel(aggConfig)).to.eql('Last 2 bytes');
expect(topHitMetricAgg.makeLabel(aggConfig)).to.eql('Last 2 bytes');
});
it('should return a label prefixed with First X docs if sorting in ascending order', function () {
@ -246,7 +244,7 @@ describe('Top hit metric', function () {
size: 2,
sortOrder: 'asc'
});
expect(topHitMetric.makeLabel(aggConfig)).to.eql('First 2 bytes');
expect(topHitMetricAgg.makeLabel(aggConfig)).to.eql('First 2 bytes');
});
[
@ -322,7 +320,7 @@ describe('Top hit metric', function () {
};
init({ field: 'bytes', aggregate: agg.type });
expect(topHitMetric.getValue(aggConfig, bucket)).to.eql(agg.result);
expect(topHitMetricAgg.getValue(aggConfig, bucket)).to.eql(agg.result);
});
it(`should return the result of the ${agg.type} aggregation over the last X docs - ${agg.description}`, function () {
@ -346,7 +344,7 @@ describe('Top hit metric', function () {
};
init({ field: 'bytes', aggregate: agg.type });
expect(topHitMetric.getValue(aggConfig, bucket)).to.eql(agg.result);
expect(topHitMetricAgg.getValue(aggConfig, bucket)).to.eql(agg.result);
});
});
});

View file

@ -2,173 +2,168 @@ import _ from 'lodash';
import { AggParams } from './agg_params';
import { fieldFormats } from '../registry/field_formats';
export function AggTypesAggTypeProvider() {
/**
* Generic AggType Constructor
*
* Used to create the values exposed by the agg_types module.
*
* @class AggType
* @private
* @param {object} config - used to set the properties of the AggType
*/
function AggType(config) {
/**
* Generic AggType Constructor
* the unique, unchanging, name that we have assigned this aggType
*
* Used to create the values exposed by the agg_types module.
*
* @class AggType
* @private
* @param {object} config - used to set the properties of the AggType
* @property name
* @type {string}
*/
function AggType(config) {
this.name = config.name;
/**
* the unique, unchanging, name that we have assigned this aggType
*
* @property name
* @type {string}
*/
this.name = config.name;
/**
* the name of the elasticsearch aggregation that this aggType represents. Usually just this.name
*
* @property name
* @type {string}
*/
this.dslName = config.dslName || config.name;
/**
* the name of the elasticsearch aggregation that this aggType represents. Usually just this.name
*
* @property name
* @type {string}
*/
this.dslName = config.dslName || config.name;
/**
* the user friendly name that will be shown in the ui for this aggType
*
* @property title
* @type {string}
*/
this.title = config.title;
/**
* the user friendly name that will be shown in the ui for this aggType
*
* @property title
* @type {string}
*/
this.title = config.title;
/**
* a function that will be called when this aggType is assigned to
* an aggConfig, and that aggConfig is being rendered (in a form, chart, etc.).
*
* @method makeLabel
* @param {AggConfig} aggConfig - an agg config of this type
* @returns {string} - label that can be used in the ui to descripe the aggConfig
*/
this.makeLabel = config.makeLabel || _.constant(this.name);
/**
* a function that will be called when this aggType is assigned to
* an aggConfig, and that aggConfig is being rendered (in a form, chart, etc.).
*
* @method makeLabel
* @param {AggConfig} aggConfig - an agg config of this type
* @returns {string} - label that can be used in the ui to descripe the aggConfig
*/
this.makeLabel = config.makeLabel || _.constant(this.name);
/**
* Describes if this aggType creates data that is ordered, and if that ordered data
* is some sort of time series.
*
* If the aggType does not create ordered data, set this to something "falsey".
*
* If this does create orderedData, then the value should be an object.
*
* If the orderdata is some sort of time series, `this.ordered` should be an object
* with the property `date: true`
*
* @property ordered
* @type {object|undefined}
*/
this.ordered = config.ordered;
/**
* Describes if this aggType creates data that is ordered, and if that ordered data
* is some sort of time series.
*
* If the aggType does not create ordered data, set this to something "falsey".
*
* If this does create orderedData, then the value should be an object.
*
* If the orderdata is some sort of time series, `this.ordered` should be an object
* with the property `date: true`
*
* @property ordered
* @type {object|undefined}
*/
this.ordered = config.ordered;
/**
* Flag that prevents this aggregation from being included in the dsl. This is only
* used by the count aggregation (currently) since it doesn't really exist and it's output
* is available on every bucket.
*
* @type {Boolean}
*/
this.hasNoDsl = !!config.hasNoDsl;
/**
* Flag that prevents this aggregation from being included in the dsl. This is only
* used by the count aggregation (currently) since it doesn't really exist and it's output
* is available on every bucket.
*
* @type {Boolean}
*/
this.hasNoDsl = !!config.hasNoDsl;
/**
* The method to create a filter representation of the bucket
* @param {object} aggConfig The instance of the aggConfig
* @param {mixed} key The key for the bucket
* @returns {object} The filter
*/
this.createFilter = config.createFilter;
/**
* The method to create a filter representation of the bucket
* @param {object} aggConfig The instance of the aggConfig
* @param {mixed} key The key for the bucket
* @returns {object} The filter
*/
this.createFilter = config.createFilter;
/**
* An instance of {{#crossLink "AggParams"}}{{/crossLink}}.
*
* @property params
* @type {AggParams}
*/
this.params = config.params || [];
if (!(this.params instanceof AggParams)) {
// always append the raw JSON param
this.params.push({
name: 'json',
type: 'json',
advanced: true
});
// always append custom label
/**
* An instance of {{#crossLink "AggParams"}}{{/crossLink}}.
*
* @property params
* @type {AggParams}
*/
this.params = config.params || [];
if (!(this.params instanceof AggParams)) {
// always append the raw JSON param
if (config.customLabels !== false) {
this.params.push({
name: 'json',
type: 'json',
advanced: true
name: 'customLabel',
type: 'string',
write: _.noop
});
// always append custom label
if (config.customLabels !== false) {
this.params.push({
name: 'customLabel',
type: 'string',
write: _.noop
});
}
this.params = new AggParams(this.params);
}
/**
* Designed for multi-value metric aggs, this method can return a
* set of AggConfigs that should replace this aggConfig in requests
*
* @method getRequestAggs
* @returns {array[AggConfig]|undefined} - an array of aggConfig objects
* that should replace this one,
* or undefined
*/
this.getRequestAggs = config.getRequestAggs || _.noop;
/**
* Designed for multi-value metric aggs, this method can return a
* set of AggConfigs that should replace this aggConfig in result sets
* that walk the AggConfig set.
*
* @method getResponseAggs
* @returns {array[AggConfig]|undefined} - an array of aggConfig objects
* that should replace this one,
* or undefined
*/
this.getResponseAggs = config.getResponseAggs || _.noop;
/**
* A function that will be called each time an aggConfig of this type
* is created, giving the agg type a chance to modify the agg config
*/
this.decorateAggConfig = config.decorateAggConfig || null;
/**
* A function that needs to be called after the main request has been made
* and should return an updated response
* @param aggConfigs - agg config array used to produce main request
* @param aggConfig - AggConfig that requested the post flight request
* @param searchSourceAggs - SearchSource aggregation configuration
* @param resp - Response to the main request
* @param nestedSearchSource - the new SearchSource that will be used to make post flight request
* @return {Promise}
*/
this.postFlightRequest = config.postFlightRequest || _.identity;
if (config.getFormat) {
this.getFormat = config.getFormat;
}
this.params = new AggParams(this.params);
}
/**
* Pick a format for the values produced by this agg type,
* overriden by several metrics that always output a simple
* number
* Designed for multi-value metric aggs, this method can return a
* set of AggConfigs that should replace this aggConfig in requests
*
* @param {agg} agg - the agg to pick a format for
* @return {FieldFromat}
* @method getRequestAggs
* @returns {array[AggConfig]|undefined} - an array of aggConfig objects
* that should replace this one,
* or undefined
*/
AggType.prototype.getFormat = function (agg) {
const field = agg.getField();
return field ? field.format : fieldFormats.getDefaultInstance('string');
};
this.getRequestAggs = config.getRequestAggs || _.noop;
return AggType;
/**
* Designed for multi-value metric aggs, this method can return a
* set of AggConfigs that should replace this aggConfig in result sets
* that walk the AggConfig set.
*
* @method getResponseAggs
* @returns {array[AggConfig]|undefined} - an array of aggConfig objects
* that should replace this one,
* or undefined
*/
this.getResponseAggs = config.getResponseAggs || _.noop;
/**
* A function that will be called each time an aggConfig of this type
* is created, giving the agg type a chance to modify the agg config
*/
this.decorateAggConfig = config.decorateAggConfig || null;
/**
* A function that needs to be called after the main request has been made
* and should return an updated response
* @param aggConfigs - agg config array used to produce main request
* @param aggConfig - AggConfig that requested the post flight request
* @param searchSourceAggs - SearchSource aggregation configuration
* @param resp - Response to the main request
* @param nestedSearchSource - the new SearchSource that will be used to make post flight request
* @return {Promise}
*/
this.postFlightRequest = config.postFlightRequest || _.identity;
if (config.getFormat) {
this.getFormat = config.getFormat;
}
}
/**
* Pick a format for the values produced by this agg type,
* overriden by several metrics that always output a simple
* number
*
* @param {agg} agg - the agg to pick a format for
* @return {FieldFromat}
*/
AggType.prototype.getFormat = function (agg) {
const field = agg.getField();
return field ? field.format : fieldFormats.getDefaultInstance('string');
};
export { AggType };

View file

@ -1,22 +1,18 @@
import _ from 'lodash';
import { AggTypesAggTypeProvider } from '../agg_type';
import { AggType } from '../agg_type';
import { createLegacyClass } from '../../utils/legacy_class';
export function AggTypesBucketsBucketAggTypeProvider(Private) {
const AggType = Private(AggTypesAggTypeProvider);
createLegacyClass(BucketAggType).inherits(AggType);
function BucketAggType(config) {
BucketAggType.Super.call(this, config);
createLegacyClass(BucketAggType).inherits(AggType);
function BucketAggType(config) {
BucketAggType.Super.call(this, config);
if (_.isFunction(config.getKey)) {
this.getKey = config.getKey;
}
if (_.isFunction(config.getKey)) {
this.getKey = config.getKey;
}
BucketAggType.prototype.getKey = function (bucket, key) {
return key || bucket.key;
};
return BucketAggType;
}
BucketAggType.prototype.getKey = function (bucket, key) {
return key || bucket.key;
};
export { BucketAggType };

View file

@ -1,49 +1,47 @@
export function AggTypesBucketsIntervalOptionsProvider() {
return [
{
display: 'Auto',
val: 'auto',
enabled: function (agg) {
// not only do we need a time field, but the selected field needs
// to be the time field. (see #3028)
return agg.fieldIsTimeField();
}
},
{
display: 'Millisecond',
val: 'ms'
},
{
display: 'Second',
val: 's'
},
{
display: 'Minute',
val: 'm'
},
{
display: 'Hourly',
val: 'h'
},
{
display: 'Daily',
val: 'd'
},
{
display: 'Weekly',
val: 'w'
},
{
display: 'Monthly',
val: 'M'
},
{
display: 'Yearly',
val: 'y'
},
{
display: 'Custom',
val: 'custom'
export const intervalOptions = [
{
display: 'Auto',
val: 'auto',
enabled: function (agg) {
// not only do we need a time field, but the selected field needs
// to be the time field. (see #3028)
return agg.fieldIsTimeField();
}
];
}
},
{
display: 'Millisecond',
val: 'ms'
},
{
display: 'Second',
val: 's'
},
{
display: 'Minute',
val: 'm'
},
{
display: 'Hourly',
val: 'h'
},
{
display: 'Daily',
val: 'd'
},
{
display: 'Weekly',
val: 'w'
},
{
display: 'Monthly',
val: 'M'
},
{
display: 'Yearly',
val: 'y'
},
{
display: 'Custom',
val: 'custom'
}
];

View file

@ -83,104 +83,100 @@ const getOtherAggTerms = (requestAgg, key, otherAgg) => {
);
};
const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => {
const bucketAggs = aggConfigs.filter(agg => agg.type.type === 'buckets');
const index = bucketAggs.findIndex(agg => agg.id === aggWithOtherBucket.id);
const aggs = aggConfigs.toDsl();
const indexPattern = aggWithOtherBucket.params.field.indexPattern;
export const OtherBucketHelperProvider = () => {
// create filters aggregation
const filterAgg = new AggConfig(aggConfigs[index].vis, {
type: 'filters',
id: 'other',
schema: {
group: 'buckets'
}
});
const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => {
const bucketAggs = aggConfigs.filter(agg => agg.type.type === 'buckets');
const index = bucketAggs.findIndex(agg => agg.id === aggWithOtherBucket.id);
const aggs = aggConfigs.toDsl();
const indexPattern = aggWithOtherBucket.params.field.indexPattern;
// nest all the child aggregations of aggWithOtherBucket
const resultAgg = {
aggs: getNestedAggDSL(aggs, aggWithOtherBucket.id).aggs,
filters: filterAgg.toDsl(),
};
// create filters aggregation
const filterAgg = new AggConfig(aggConfigs[index].vis, {
type: 'filters',
id: 'other',
schema: {
group: 'buckets'
}
});
// nest all the child aggregations of aggWithOtherBucket
const resultAgg = {
aggs: getNestedAggDSL(aggs, aggWithOtherBucket.id).aggs,
filters: filterAgg.toDsl(),
};
// create filters for all parent aggregation buckets
const walkBucketTree = (aggIndex, aggs, aggId, filters, key) => {
const agg = aggs[aggId];
const newAggIndex = aggIndex + 1;
const newAgg = bucketAggs[newAggIndex];
const currentAgg = bucketAggs[aggIndex];
if (aggIndex < index) {
_.each(agg.buckets, (bucket, bucketObjKey) => {
const bucketKey = currentAgg.getKey(bucket, Number.isInteger(bucketObjKey) ? null : bucketObjKey);
const filter = _.cloneDeep(bucket.filter) || currentAgg.createFilter(bucketKey);
const newFilters = [...filters, filter];
walkBucketTree(newAggIndex, bucket, newAgg.id, newFilters, `${key}-${bucketKey.toString()}`);
});
return;
}
if (!aggWithOtherBucket.params.missingBucket || agg.buckets.some(bucket => bucket.key === '__missing__')) {
filters.push(buildExistsFilter(aggWithOtherBucket.params.field, aggWithOtherBucket.params.field.indexPattern));
}
// create not filters for all the buckets
_.each(agg.buckets, bucket => {
if (bucket.key === '__missing__') return;
const filter = currentAgg.createFilter(bucket.key);
filter.meta.negate = true;
filters.push(filter);
// create filters for all parent aggregation buckets
const walkBucketTree = (aggIndex, aggs, aggId, filters, key) => {
const agg = aggs[aggId];
const newAggIndex = aggIndex + 1;
const newAgg = bucketAggs[newAggIndex];
const currentAgg = bucketAggs[aggIndex];
if (aggIndex < index) {
_.each(agg.buckets, (bucket, bucketObjKey) => {
const bucketKey = currentAgg.getKey(bucket, Number.isInteger(bucketObjKey) ? null : bucketObjKey);
const filter = _.cloneDeep(bucket.filter) || currentAgg.createFilter(bucketKey);
const newFilters = [...filters, filter];
walkBucketTree(newAggIndex, bucket, newAgg.id, newFilters, `${key}-${bucketKey.toString()}`);
});
return;
}
resultAgg.filters.filters[key] = {
bool: buildQueryFromFilters(filters, _.noop, indexPattern)
};
};
walkBucketTree(0, response.aggregations, bucketAggs[0].id, [], '');
if (!aggWithOtherBucket.params.missingBucket || agg.buckets.some(bucket => bucket.key === '__missing__')) {
filters.push(buildExistsFilter(aggWithOtherBucket.params.field, aggWithOtherBucket.params.field.indexPattern));
}
return () => {
return {
'other-filter': resultAgg
};
// create not filters for all the buckets
_.each(agg.buckets, bucket => {
if (bucket.key === '__missing__') return;
const filter = currentAgg.createFilter(bucket.key);
filter.meta.negate = true;
filters.push(filter);
});
resultAgg.filters.filters[key] = {
bool: buildQueryFromFilters(filters, _.noop, indexPattern)
};
};
walkBucketTree(0, response.aggregations, bucketAggs[0].id, [], '');
const mergeOtherBucketAggResponse = (aggsConfig, response, otherResponse, otherAgg, requestAgg) => {
const updatedResponse = _.cloneDeep(response);
_.each(otherResponse.aggregations['other-filter'].buckets, (bucket, key) => {
if (!bucket.doc_count) return;
const bucketKey = key.replace(/^-/, '');
const aggResultBuckets = getAggResultBuckets(aggsConfig, updatedResponse.aggregations, otherAgg, bucketKey);
const requestFilterTerms = getOtherAggTerms(requestAgg, key, otherAgg);
const phraseFilter = buildPhrasesFilter(otherAgg.params.field, requestFilterTerms, otherAgg.params.field.indexPattern);
phraseFilter.meta.negate = true;
bucket.filters = [ phraseFilter ];
bucket.key = otherAgg.params.otherBucketLabel;
if (aggResultBuckets.some(bucket => bucket.key === '__missing__')) {
bucket.filters.push(buildExistsFilter(otherAgg.params.field, otherAgg.params.field.indexPattern));
}
aggResultBuckets.push(bucket);
});
return updatedResponse;
return () => {
return {
'other-filter': resultAgg
};
};
const updateMissingBucket = (response, aggConfigs, agg) => {
const updatedResponse = _.cloneDeep(response);
const aggResultBuckets = getAggConfigResultMissingBuckets(updatedResponse.aggregations, agg.id);
aggResultBuckets.forEach(bucket => {
bucket.key = agg.params.missingBucketLabel;
const existsFilter = buildExistsFilter(agg.params.field, agg.params.field.indexPattern);
existsFilter.meta.negate = true;
bucket.filters = [ existsFilter ];
});
return updatedResponse;
};
return { buildOtherBucketAgg, mergeOtherBucketAggResponse, updateMissingBucket };
};
const mergeOtherBucketAggResponse = (aggsConfig, response, otherResponse, otherAgg, requestAgg) => {
const updatedResponse = _.cloneDeep(response);
_.each(otherResponse.aggregations['other-filter'].buckets, (bucket, key) => {
if (!bucket.doc_count) return;
const bucketKey = key.replace(/^-/, '');
const aggResultBuckets = getAggResultBuckets(aggsConfig, updatedResponse.aggregations, otherAgg, bucketKey);
const requestFilterTerms = getOtherAggTerms(requestAgg, key, otherAgg);
const phraseFilter = buildPhrasesFilter(otherAgg.params.field, requestFilterTerms, otherAgg.params.field.indexPattern);
phraseFilter.meta.negate = true;
bucket.filters = [ phraseFilter ];
bucket.key = otherAgg.params.otherBucketLabel;
if (aggResultBuckets.some(bucket => bucket.key === '__missing__')) {
bucket.filters.push(buildExistsFilter(otherAgg.params.field, otherAgg.params.field.indexPattern));
}
aggResultBuckets.push(bucket);
});
return updatedResponse;
};
const updateMissingBucket = (response, aggConfigs, agg) => {
const updatedResponse = _.cloneDeep(response);
const aggResultBuckets = getAggConfigResultMissingBuckets(updatedResponse.aggregations, agg.id);
aggResultBuckets.forEach(bucket => {
bucket.key = agg.params.missingBucketLabel;
const existsFilter = buildExistsFilter(agg.params.field, agg.params.field.indexPattern);
existsFilter.meta.negate = true;
bucket.filters = [ existsFilter ];
});
return updatedResponse;
};
export { buildOtherBucketAgg, mergeOtherBucketAggResponse, updateMissingBucket };

View file

@ -1,17 +1,13 @@
import moment from 'moment';
import { buildRangeFilter } from '../../../filter_manager/lib/range';
export function AggTypesBucketsCreateFilterDateHistogramProvider() {
return function (agg, key) {
const start = moment(key);
const interval = agg.buckets.getInterval();
return buildRangeFilter(agg.params.field, {
gte: start.valueOf(),
lt: start.add(interval).valueOf(),
format: 'epoch_millis'
}, agg.vis.indexPattern);
};
export function createFilterDateHistogram(agg, key) {
const start = moment(key);
const interval = agg.buckets.getInterval();
return buildRangeFilter(agg.params.field, {
gte: start.valueOf(),
lt: start.add(interval).valueOf(),
format: 'epoch_millis'
}, agg.vis.indexPattern);
}

View file

@ -1,17 +1,16 @@
import chrome from 'ui/chrome';
import { dateRange } from '../../../utils/date_range';
import { buildRangeFilter } from '../../../filter_manager/lib/range';
export function AggTypesBucketsCreateFilterDateRangeProvider(config) {
const config = chrome.getUiSettingsClient();
return function (agg, key) {
const range = dateRange.parse(key, config.get('dateFormat'));
export function createFilterDateRange(agg, key) {
const range = dateRange.parse(key, config.get('dateFormat'));
const filter = {};
if (range.from) filter.gte = +range.from;
if (range.to) filter.lt = +range.to;
if (range.to && range.from) filter.format = 'epoch_millis';
return buildRangeFilter(agg.params.field, filter, agg.vis.indexPattern);
};
const filter = {};
if (range.from) filter.gte = +range.from;
if (range.to) filter.lt = +range.to;
if (range.to && range.from) filter.format = 'epoch_millis';
return buildRangeFilter(agg.params.field, filter, agg.vis.indexPattern);
}

View file

@ -1,14 +1,12 @@
import { buildQueryFilter } from '../../../filter_manager/lib/query';
import _ from 'lodash';
export function AggTypesBucketsCreateFilterFiltersProvider() {
return function (aggConfig, key) {
// have the aggConfig write agg dsl params
const dslFilters = _.get(aggConfig.toDsl(), 'filters.filters');
const filter = dslFilters[key];
export function createFilterFilters(aggConfig, key) {
// have the aggConfig write agg dsl params
const dslFilters = _.get(aggConfig.toDsl(), 'filters.filters');
const filter = dslFilters[key];
if (filter) {
return buildQueryFilter(filter.query, aggConfig.vis.indexPattern.id);
}
};
if (filter) {
return buildQueryFilter(filter.query, aggConfig.vis.indexPattern.id);
}
}

View file

@ -1,14 +1,12 @@
import { buildRangeFilter } from '../../../filter_manager/lib/range';
export function AggTypesBucketsCreateFilterHistogramProvider() {
return function (aggConfig, key) {
const value = parseInt(key, 10);
export function createFilterHistogram(aggConfig, key) {
const value = parseInt(key, 10);
return buildRangeFilter(
aggConfig.params.field,
{ gte: value, lt: value + aggConfig.params.interval },
aggConfig.vis.indexPattern,
aggConfig.fieldFormatter()(key)
);
};
return buildRangeFilter(
aggConfig.params.field,
{ gte: value, lt: value + aggConfig.params.interval },
aggConfig.vis.indexPattern,
aggConfig.fieldFormatter()(key)
);
}

View file

@ -1,19 +1,17 @@
import { CidrMask } from '../../../utils/cidr_mask';
import { buildRangeFilter } from '../../../filter_manager/lib/range';
export function AggTypesBucketsCreateFilterIpRangeProvider() {
return function (aggConfig, key) {
let range;
if (aggConfig.params.ipRangeType === 'mask') {
range = new CidrMask(key).getRange();
} else {
const [from, to] = key.split(/\s+to\s+/);
range = {
from: from === '-Infinity' ? -Infinity : from,
to: to === 'Infinity' ? Infinity : to
};
}
export function createFilterIpRange(aggConfig, key) {
let range;
if (aggConfig.params.ipRangeType === 'mask') {
range = new CidrMask(key).getRange();
} else {
const [from, to] = key.split(/\s+to\s+/);
range = {
from: from === '-Infinity' ? -Infinity : from,
to: to === 'Infinity' ? Infinity : to
};
}
return buildRangeFilter(aggConfig.params.field, { gte: range.from, lte: range.to }, aggConfig.vis.indexPattern);
};
return buildRangeFilter(aggConfig.params.field, { gte: range.from, lte: range.to }, aggConfig.vis.indexPattern);
}

View file

@ -1,12 +1,10 @@
import { buildRangeFilter } from '../../../filter_manager/lib/range';
export function AggTypesBucketsCreateFilterRangeProvider() {
return function (aggConfig, key) {
return buildRangeFilter(
aggConfig.params.field,
key,
aggConfig.vis.indexPattern,
aggConfig.fieldFormatter()(key)
);
};
export function createFilterRange(aggConfig, key) {
return buildRangeFilter(
aggConfig.params.field,
key,
aggConfig.vis.indexPattern,
aggConfig.fieldFormatter()(key)
);
}

View file

@ -1,7 +1,5 @@
import { buildPhraseFilter } from '../../../filter_manager/lib/phrase';
export function AggTypesBucketsCreateFilterTermsProvider() {
return function (aggConfig, key) {
return buildPhraseFilter(aggConfig.params.field, key, aggConfig.vis.indexPattern);
};
export function createFilterTerms(aggConfig, key) {
return buildPhraseFilter(aggConfig.params.field, key, aggConfig.vis.indexPattern);
}

View file

@ -1,169 +1,164 @@
import { jstz as tzDetect } from 'jstimezonedetect';
import _ from 'lodash';
import chrome from 'ui/chrome';
import moment from 'moment';
import '../../filters/field_type';
import '../../validate_date_interval';
import { AggTypesBucketsBucketAggTypeProvider } from './_bucket_agg_type';
import { TimeBucketsProvider } from '../../time_buckets';
import { AggTypesBucketsCreateFilterDateHistogramProvider } from './create_filter/date_histogram';
import { AggTypesBucketsIntervalOptionsProvider } from './_interval_options';
import { BucketAggType } from './_bucket_agg_type';
import { TimeBuckets } from '../../time_buckets';
import { createFilterDateHistogram } from './create_filter/date_histogram';
import { intervalOptions } from './_interval_options';
import intervalTemplate from '../controls/time_interval.html';
export function AggTypesBucketsDateHistogramProvider(timefilter, config, Private) {
const BucketAggType = Private(AggTypesBucketsBucketAggTypeProvider);
const TimeBuckets = Private(TimeBucketsProvider);
const createFilter = Private(AggTypesBucketsCreateFilterDateHistogramProvider);
const intervalOptions = Private(AggTypesBucketsIntervalOptionsProvider);
const config = chrome.getUiSettingsClient();
const detectedTimezone = tzDetect.determine().name();
const tzOffset = moment().format('Z');
const detectedTimezone = tzDetect.determine().name();
const tzOffset = moment().format('Z');
function getInterval(agg) {
const interval = _.get(agg, ['params', 'interval']);
if (interval && interval.val === 'custom') {
return _.get(agg, ['params', 'customInterval']);
}
return interval;
function getInterval(agg) {
const interval = _.get(agg, ['params', 'interval']);
if (interval && interval.val === 'custom') {
return _.get(agg, ['params', 'customInterval']);
}
return interval;
}
function getBounds(vis) {
if (timefilter.isTimeRangeSelectorEnabled && vis.filters) {
return timefilter.calculateBounds(vis.filters.timeRange);
}
function getBounds(vis) {
if (vis.API.timeFilter.isTimeRangeSelectorEnabled && vis.filters) {
return vis.API.timeFilter.calculateBounds(vis.filters.timeRange);
}
}
function setBounds(agg, force) {
if (agg.buckets._alreadySet && !force) return;
agg.buckets._alreadySet = true;
const bounds = getBounds(agg.vis);
agg.buckets.setBounds(agg.fieldIsTimeField() && bounds);
}
function setBounds(agg, force) {
if (agg.buckets._alreadySet && !force) return;
agg.buckets._alreadySet = true;
const bounds = getBounds(agg.vis);
agg.buckets.setBounds(agg.fieldIsTimeField() && bounds);
}
return new BucketAggType({
name: 'date_histogram',
title: 'Date Histogram',
ordered: {
date: true
},
makeLabel: function (agg) {
const output = this.params.write(agg);
const field = agg.getFieldDisplayName();
return field + ' per ' + (output.metricScaleText || output.bucketInterval.description);
},
createFilter: createFilter,
decorateAggConfig: function () {
let buckets;
return {
buckets: {
configurable: true,
get: function () {
if (buckets) return buckets;
export const dateHistogramBucketAgg = new BucketAggType({
name: 'date_histogram',
title: 'Date Histogram',
ordered: {
date: true
},
makeLabel: function (agg) {
const output = this.params.write(agg);
const field = agg.getFieldDisplayName();
return field + ' per ' + (output.metricScaleText || output.bucketInterval.description);
},
createFilter: createFilterDateHistogram,
decorateAggConfig: function () {
let buckets;
return {
buckets: {
configurable: true,
get: function () {
if (buckets) return buckets;
buckets = new TimeBuckets();
buckets.setInterval(getInterval(this));
setBounds(this);
buckets = new TimeBuckets();
buckets.setInterval(getInterval(this));
setBounds(this);
return buckets;
}
}
};
},
getFormat: function (agg) {
return agg.buckets.getScaledDateFormatter();
},
params: [
{
name: 'field',
filterFieldTypes: 'date',
default: function (agg) {
return agg.vis.indexPattern.timeFieldName;
},
onChange: function (agg) {
if (_.get(agg, 'params.interval.val') === 'auto' && !agg.fieldIsTimeField()) {
delete agg.params.interval;
}
setBounds(agg, true);
return buckets;
}
}
};
},
getFormat: function (agg) {
return agg.buckets.getScaledDateFormatter();
},
params: [
{
name: 'field',
filterFieldTypes: 'date',
default: function (agg) {
return agg.vis.indexPattern.timeFieldName;
},
onChange: function (agg) {
if (_.get(agg, 'params.interval.val') === 'auto' && !agg.fieldIsTimeField()) {
delete agg.params.interval;
}
{
name: 'interval',
type: 'optioned',
deserialize: function (state) {
const interval = _.find(intervalOptions, { val: state });
return interval || _.find(intervalOptions, function (option) {
// For upgrading from 4.0.x to 4.1.x - intervals are now stored as 'y' instead of 'year',
// but this maps the old values to the new values
return Number(moment.duration(1, state)) === Number(moment.duration(1, option.val));
setBounds(agg, true);
}
},
{
name: 'interval',
type: 'optioned',
deserialize: function (state) {
const interval = _.find(intervalOptions, { val: state });
return interval || _.find(intervalOptions, function (option) {
// For upgrading from 4.0.x to 4.1.x - intervals are now stored as 'y' instead of 'year',
// but this maps the old values to the new values
return Number(moment.duration(1, state)) === Number(moment.duration(1, option.val));
});
},
default: 'auto',
options: intervalOptions,
editor: intervalTemplate,
modifyAggConfigOnSearchRequestStart: function (agg) {
setBounds(agg, true);
},
write: function (agg, output) {
setBounds(agg);
agg.buckets.setInterval(getInterval(agg));
const interval = agg.buckets.getInterval();
output.bucketInterval = interval;
output.params.interval = interval.expression;
const isDefaultTimezone = config.isDefault('dateFormat:tz');
if (isDefaultTimezone) {
output.params.time_zone = detectedTimezone || tzOffset;
} else {
output.params.time_zone = config.get('dateFormat:tz');
}
const scaleMetrics = interval.scaled && interval.scale < 1;
if (scaleMetrics) {
const all = _.every(agg.vis.getAggConfig().bySchemaGroup.metrics, function (agg) {
return agg.type && agg.type.isScalable();
});
},
default: 'auto',
options: intervalOptions,
editor: intervalTemplate,
modifyAggConfigOnSearchRequestStart: function (agg) {
setBounds(agg, true);
},
write: function (agg, output) {
setBounds(agg);
agg.buckets.setInterval(getInterval(agg));
const interval = agg.buckets.getInterval();
output.bucketInterval = interval;
output.params.interval = interval.expression;
const isDefaultTimezone = config.isDefault('dateFormat:tz');
if (isDefaultTimezone) {
output.params.time_zone = detectedTimezone || tzOffset;
} else {
output.params.time_zone = config.get('dateFormat:tz');
}
const scaleMetrics = interval.scaled && interval.scale < 1;
if (scaleMetrics) {
const all = _.every(agg.vis.getAggConfig().bySchemaGroup.metrics, function (agg) {
return agg.type && agg.type.isScalable();
});
if (all) {
output.metricScale = interval.scale;
output.metricScaleText = interval.preScaled.description;
}
}
}
},
{
name: 'customInterval',
default: '2h',
write: _.noop
},
{
name: 'format'
},
{
name: 'min_doc_count',
default: 1
},
{
name: 'extended_bounds',
default: {},
write: function (agg, output) {
const val = agg.params.extended_bounds;
if (val.min != null || val.max != null) {
output.params.extended_bounds = {
min: moment(val.min).valueOf(),
max: moment(val.max).valueOf()
};
return;
if (all) {
output.metricScale = interval.scale;
output.metricScaleText = interval.preScaled.description;
}
}
}
]
});
}
},
{
name: 'customInterval',
default: '2h',
write: _.noop
},
{
name: 'format'
},
{
name: 'min_doc_count',
default: 1
},
{
name: 'extended_bounds',
default: {},
write: function (agg, output) {
const val = agg.params.extended_bounds;
if (val.min != null || val.max != null) {
output.params.extended_bounds = {
min: moment(val.min).valueOf(),
max: moment(val.max).valueOf()
};
return;
}
}
}
]
});

View file

@ -1,43 +1,37 @@
import { dateRange } from '../../utils/date_range';
import '../../directives/validate_date_math';
import '../../directives/documentation_href';
import { AggTypesBucketsBucketAggTypeProvider } from './_bucket_agg_type';
import { AggTypesBucketsCreateFilterDateRangeProvider } from './create_filter/date_range';
import { BucketAggType } from './_bucket_agg_type';
import { createFilterDateRange } from './create_filter/date_range';
import { fieldFormats } from '../../registry/field_formats';
import dateRangesTemplate from '../controls/date_ranges.html';
export function AggTypesBucketsDateRangeProvider(Private) {
const BucketAggType = Private(AggTypesBucketsBucketAggTypeProvider);
const createFilter = Private(AggTypesBucketsCreateFilterDateRangeProvider);
return new BucketAggType({
name: 'date_range',
title: 'Date Range',
createFilter: createFilter,
getKey: function (bucket, key, agg) {
const formatter = agg.fieldOwnFormatter('text', fieldFormats.getDefaultInstance('date'));
return dateRange.toString(bucket, formatter);
},
getFormat: function () {
return fieldFormats.getDefaultInstance('string');
},
makeLabel: function (aggConfig) {
return aggConfig.getFieldDisplayName() + ' date ranges';
},
params: [{
name: 'field',
filterFieldTypes: 'date',
default: function (agg) {
return agg.vis.indexPattern.timeFieldName;
}
}, {
name: 'ranges',
default: [{
from: 'now-1w/w',
to: 'now'
}],
editor: dateRangesTemplate
}]
});
}
export const dateRangeBucketAgg = new BucketAggType({
name: 'date_range',
title: 'Date Range',
createFilter: createFilterDateRange,
getKey: function (bucket, key, agg) {
const formatter = agg.fieldOwnFormatter('text', fieldFormats.getDefaultInstance('date'));
return dateRange.toString(bucket, formatter);
},
getFormat: function () {
return fieldFormats.getDefaultInstance('string');
},
makeLabel: function (aggConfig) {
return aggConfig.getFieldDisplayName() + ' date ranges';
},
params: [{
name: 'field',
filterFieldTypes: 'date',
default: function (agg) {
return agg.vis.indexPattern.timeFieldName;
}
}, {
name: 'ranges',
default: [{
from: 'now-1w/w',
to: 'now'
}],
editor: dateRangesTemplate
}]
});

View file

@ -1,15 +1,11 @@
import { AggTypesBucketsBucketAggTypeProvider } from './_bucket_agg_type';
import { BucketAggType } from './_bucket_agg_type';
export function AggTypesBucketsFilterProvider(Private) {
const BucketAggType = Private(AggTypesBucketsBucketAggTypeProvider);
return new BucketAggType({
name: 'filter',
title: 'Filter',
params: [
{
name: 'geo_bounding_box'
}
]
});
}
export const filterBucketAgg = new BucketAggType({
name: 'filter',
title: 'Filter',
params: [
{
name: 'geo_bounding_box'
}
]
});

View file

@ -2,51 +2,46 @@ import _ from 'lodash';
import angular from 'angular';
import { luceneStringToDsl } from '../../courier/data_source/build_query/lucene_string_to_dsl.js';
import { AggTypesBucketsBucketAggTypeProvider } from './_bucket_agg_type';
import { AggTypesBucketsCreateFilterFiltersProvider } from './create_filter/filters';
import { DecorateQueryProvider } from '../../courier/data_source/_decorate_query';
import { BucketAggType } from './_bucket_agg_type';
import { createFilterFilters } from './create_filter/filters';
import { decorateQuery } from '../../courier/data_source/_decorate_query';
import filtersTemplate from '../controls/filters.html';
export function AggTypesBucketsFiltersProvider(Private, Notifier) {
const BucketAggType = Private(AggTypesBucketsBucketAggTypeProvider);
const createFilter = Private(AggTypesBucketsCreateFilterFiltersProvider);
const decorateQuery = Private(DecorateQueryProvider);
const notif = new Notifier({ location: 'Filters Agg' });
import { toastNotifications } from 'ui/notify';
return new BucketAggType({
name: 'filters',
title: 'Filters',
createFilter: createFilter,
customLabels: false,
params: [
{
name: 'filters',
editor: filtersTemplate,
default: [ { input: {}, label: '' } ],
write: function (aggConfig, output) {
const inFilters = aggConfig.params.filters;
if (!_.size(inFilters)) return;
export const filtersBucketAgg = new BucketAggType({
name: 'filters',
title: 'Filters',
createFilter: createFilterFilters,
customLabels: false,
params: [
{
name: 'filters',
editor: filtersTemplate,
default: [ { input: {}, label: '' } ],
write: function (aggConfig, output) {
const inFilters = aggConfig.params.filters;
if (!_.size(inFilters)) return;
const outFilters = _.transform(inFilters, function (filters, filter) {
const input = _.cloneDeep(filter.input);
if (!input) return notif.log('malformed filter agg params, missing "input" query');
const outFilters = _.transform(inFilters, function (filters, filter) {
const input = _.cloneDeep(filter.input);
if (!input) return toastNotifications.add('malformed filter agg params, missing "input" query');
const query = input.query = luceneStringToDsl(input.query);
if (!query) return notif.log('malformed filter agg params, missing "query" on input');
const query = input.query = luceneStringToDsl(input.query);
if (!query) return toastNotifications.add('malformed filter agg params, missing "query" on input');
decorateQuery(query);
decorateQuery(query);
const matchAllLabel = (filter.input.query === '' && _.has(query, 'match_all')) ? '*' : '';
const label = filter.label || matchAllLabel || _.get(query, 'query_string.query') || angular.toJson(query);
filters[label] = input;
}, {});
const matchAllLabel = (filter.input.query === '' && _.has(query, 'match_all')) ? '*' : '';
const label = filter.label || matchAllLabel || _.get(query, 'query_string.query') || angular.toJson(query);
filters[label] = input;
}, {});
if (!_.size(outFilters)) return;
if (!_.size(outFilters)) return;
const params = output.params || (output.params = {});
params.filters = outFilters;
}
const params = output.params || (output.params = {});
params.filters = outFilters;
}
]
});
}
}
]
});

View file

@ -1,157 +1,156 @@
import _ from 'lodash';
import { AggTypesBucketsBucketAggTypeProvider } from './_bucket_agg_type';
import chrome from 'ui/chrome';
import { BucketAggType } from './_bucket_agg_type';
import { AggConfig } from '../../vis/agg_config';
import precisionTemplate from '../controls/precision.html';
import { geohashColumns } from '../../utils/decode_geo_hash';
import { geoContains, scaleBounds } from '../../utils/geo_utils';
export function AggTypesBucketsGeoHashProvider(Private, config) {
const BucketAggType = Private(AggTypesBucketsBucketAggTypeProvider);
const config = chrome.getUiSettingsClient();
const defaultPrecision = 2;
const maxPrecision = parseInt(config.get('visualization:tileMap:maxPrecision'), 10) || 12;
/**
* Map Leaflet zoom levels to geohash precision levels.
* The size of a geohash column-width on the map should be at least `minGeohashPixels` pixels wide.
*/
const zoomPrecision = {};
const minGeohashPixels = 16;
for (let zoom = 0; zoom <= 21; zoom += 1) {
const worldPixels = 256 * Math.pow(2, zoom);
zoomPrecision[zoom] = 1;
for (let precision = 2; precision <= maxPrecision; precision += 1) {
const columns = geohashColumns(precision);
if ((worldPixels / columns) >= minGeohashPixels) {
zoomPrecision[zoom] = precision;
} else {
break;
const defaultPrecision = 2;
const maxPrecision = parseInt(config.get('visualization:tileMap:maxPrecision'), 10) || 12;
/**
* Map Leaflet zoom levels to geohash precision levels.
* The size of a geohash column-width on the map should be at least `minGeohashPixels` pixels wide.
*/
const zoomPrecision = {};
const minGeohashPixels = 16;
for (let zoom = 0; zoom <= 21; zoom += 1) {
const worldPixels = 256 * Math.pow(2, zoom);
zoomPrecision[zoom] = 1;
for (let precision = 2; precision <= maxPrecision; precision += 1) {
const columns = geohashColumns(precision);
if ((worldPixels / columns) >= minGeohashPixels) {
zoomPrecision[zoom] = precision;
} else {
break;
}
}
}
function getPrecision(precision) {
precision = parseInt(precision, 10);
if (isNaN(precision)) {
precision = defaultPrecision;
}
if (precision > maxPrecision) {
return maxPrecision;
}
return precision;
}
function getMapZoom(vis) {
if (vis.hasUiState() && parseInt(vis.uiStateVal('mapZoom')) >= 0) {
return parseInt(vis.uiStateVal('mapZoom'));
}
return vis.params.mapZoom;
}
function isOutsideCollar(bounds, collar) {
return bounds && collar && !geoContains(collar, bounds);
}
export const geoHashBucketAgg = new BucketAggType({
name: 'geohash_grid',
title: 'Geohash',
params: [
{
name: 'field',
filterFieldTypes: 'geo_point'
},
{
name: 'autoPrecision',
default: true,
write: _.noop
},
{
name: 'isFilteredByCollar',
default: true,
write: _.noop
},
{
name: 'useGeocentroid',
default: true,
write: _.noop
},
{
name: 'mapZoom',
write: _.noop
},
{
name: 'mapCenter',
write: _.noop
},
{
name: 'precision',
editor: precisionTemplate,
default: defaultPrecision,
deserialize: getPrecision,
controller: function () {
},
write: function (aggConfig, output) {
const vis = aggConfig.vis;
const currZoom = getMapZoom(vis);
const autoPrecisionVal = zoomPrecision[currZoom];
output.params.precision = aggConfig.params.autoPrecision ? autoPrecisionVal : getPrecision(aggConfig.params.precision);
}
}
}
],
getRequestAggs: function (agg) {
const aggs = [];
function getPrecision(precision) {
precision = parseInt(precision, 10);
if (isNaN(precision)) {
precision = defaultPrecision;
}
if (precision > maxPrecision) {
return maxPrecision;
}
return precision;
}
function getMapZoom(vis) {
if (vis.hasUiState() && parseInt(vis.uiStateVal('mapZoom')) >= 0) {
return parseInt(vis.uiStateVal('mapZoom'));
}
return vis.params.mapZoom;
}
function isOutsideCollar(bounds, collar) {
return bounds && collar && !geoContains(collar, bounds);
}
return new BucketAggType({
name: 'geohash_grid',
title: 'Geohash',
params: [
{
name: 'field',
filterFieldTypes: 'geo_point'
},
{
name: 'autoPrecision',
default: true,
write: _.noop
},
{
name: 'isFilteredByCollar',
default: true,
write: _.noop
},
{
name: 'useGeocentroid',
default: true,
write: _.noop
},
{
name: 'mapZoom',
write: _.noop
},
{
name: 'mapCenter',
write: _.noop
},
{
name: 'precision',
editor: precisionTemplate,
default: defaultPrecision,
deserialize: getPrecision,
controller: function () {
},
write: function (aggConfig, output) {
const vis = aggConfig.vis;
const currZoom = getMapZoom(vis);
const autoPrecisionVal = zoomPrecision[currZoom];
output.params.precision = aggConfig.params.autoPrecision ? autoPrecisionVal : getPrecision(aggConfig.params.precision);
if (agg.params.isFilteredByCollar && agg.getField()) {
const vis = agg.vis;
const mapBounds = vis.sessionState.mapBounds;
const mapZoom = getMapZoom(vis);
if (mapBounds) {
const lastMapCollar = vis.sessionState.mapCollar;
let mapCollar;
if (!lastMapCollar || lastMapCollar.zoom !== mapZoom || isOutsideCollar(mapBounds, lastMapCollar)) {
mapCollar = scaleBounds(mapBounds);
mapCollar.zoom = mapZoom;
vis.sessionState.mapCollar = mapCollar;
} else {
mapCollar = lastMapCollar;
}
}
],
getRequestAggs: function (agg) {
const aggs = [];
if (agg.params.isFilteredByCollar && agg.getField()) {
const vis = agg.vis;
const mapBounds = vis.sessionState.mapBounds;
const mapZoom = getMapZoom(vis);
if (mapBounds) {
const lastMapCollar = vis.sessionState.mapCollar;
let mapCollar;
if (!lastMapCollar || lastMapCollar.zoom !== mapZoom || isOutsideCollar(mapBounds, lastMapCollar)) {
mapCollar = scaleBounds(mapBounds);
mapCollar.zoom = mapZoom;
vis.sessionState.mapCollar = mapCollar;
} else {
mapCollar = lastMapCollar;
}
const boundingBox = {};
boundingBox[agg.getField().name] = {
top_left: mapCollar.top_left,
bottom_right: mapCollar.bottom_right
};
aggs.push(new AggConfig(agg.vis, {
type: 'filter',
id: 'filter_agg',
enabled: true,
params: {
geo_bounding_box: boundingBox
},
schema: {
group: 'buckets'
}
}));
}
}
aggs.push(agg);
if (agg.params.useGeocentroid) {
const boundingBox = {};
boundingBox[agg.getField().name] = {
top_left: mapCollar.top_left,
bottom_right: mapCollar.bottom_right
};
aggs.push(new AggConfig(agg.vis, {
type: 'geo_centroid',
type: 'filter',
id: 'filter_agg',
enabled: true,
params: {
field: agg.getField()
geo_bounding_box: boundingBox
},
schema: 'metric'
schema: {
group: 'buckets'
}
}));
}
return aggs;
}
});
}
aggs.push(agg);
if (agg.params.useGeocentroid) {
aggs.push(new AggConfig(agg.vis, {
type: 'geo_centroid',
enabled: true,
params: {
field: agg.getField()
},
schema: 'metric'
}));
}
return aggs;
}
});

View file

@ -1,142 +1,139 @@
import _ from 'lodash';
import '../../validate_date_interval';
import { AggTypesBucketsBucketAggTypeProvider } from './_bucket_agg_type';
import { AggTypesBucketsCreateFilterHistogramProvider } from './create_filter/histogram';
import chrome from 'ui/chrome';
import { BucketAggType } from './_bucket_agg_type';
import { createFilterHistogram } from './create_filter/histogram';
import intervalTemplate from '../controls/number_interval.html';
import minDocCountTemplate from '../controls/min_doc_count.html';
import extendedBoundsTemplate from '../controls/extended_bounds.html';
export function AggTypesBucketsHistogramProvider(Private, config) {
const BucketAggType = Private(AggTypesBucketsBucketAggTypeProvider);
const createFilter = Private(AggTypesBucketsCreateFilterHistogramProvider);
const config = chrome.getUiSettingsClient();
export const histogramBucketAgg = new BucketAggType({
name: 'histogram',
title: 'Histogram',
ordered: {},
makeLabel: function (aggConfig) {
return aggConfig.getFieldDisplayName();
},
createFilter: createFilterHistogram,
decorateAggConfig: function () {
let autoBounds;
return new BucketAggType({
name: 'histogram',
title: 'Histogram',
ordered: {},
makeLabel: function (aggConfig) {
return aggConfig.getFieldDisplayName();
},
createFilter: createFilter,
decorateAggConfig: function () {
let autoBounds;
return {
setAutoBounds: {
configurable: true,
value(newValue) {
autoBounds = newValue;
}
},
getAutoBounds: {
configurable: true,
value() {
return autoBounds;
}
}
};
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
},
{
name: 'interval',
editor: intervalTemplate,
modifyAggConfigOnSearchRequestStart(aggConfig, searchSource) {
const field = aggConfig.getField();
const aggBody = field.scripted
? { script: { inline: field.script, lang: field.lang } }
: { field: field.name };
return searchSource
.extend()
.size(0)
.aggs({
maxAgg: {
max: aggBody
},
minAgg: {
min: aggBody
}
})
.fetchAsRejectablePromise()
.then((resp) => {
aggConfig.setAutoBounds({
min: _.get(resp, 'aggregations.minAgg.value'),
max: _.get(resp, 'aggregations.maxAgg.value')
});
});
},
write: function (aggConfig, output) {
let interval = parseFloat(aggConfig.params.interval);
if (interval <= 0) {
interval = 1;
}
// ensure interval does not create too many buckets and crash browser
if (aggConfig.getAutoBounds()) {
const range = aggConfig.getAutoBounds().max - aggConfig.getAutoBounds().min;
const bars = range / interval;
if (bars > config.get('histogram:maxBars')) {
const minInterval = range / config.get('histogram:maxBars');
// Round interval by order of magnitude to provide clean intervals
// Always round interval up so there will always be less buckets than histogram:maxBars
const orderOfMaginute = Math.pow(10, Math.floor(Math.log10(minInterval)));
let roundInterval = orderOfMaginute;
while (roundInterval < minInterval) {
roundInterval += orderOfMaginute;
}
interval = roundInterval;
}
}
output.params.interval = interval;
return {
setAutoBounds: {
configurable: true,
value(newValue) {
autoBounds = newValue;
}
},
{
name: 'min_doc_count',
default: null,
editor: minDocCountTemplate,
write: function (aggConfig, output) {
if (aggConfig.params.min_doc_count) {
output.params.min_doc_count = 0;
} else {
output.params.min_doc_count = 1;
}
}
},
{
name: 'extended_bounds',
default: {},
editor: extendedBoundsTemplate,
write: function (aggConfig, output) {
const val = aggConfig.params.extended_bounds;
if (aggConfig.params.min_doc_count && (val.min != null || val.max != null)) {
output.params.extended_bounds = {
min: val.min,
max: val.max
};
}
},
// called from the editor
shouldShow: function (aggConfig) {
const field = aggConfig.params.field;
if (
field
&& (field.type === 'number' || field.type === 'date')
) {
return aggConfig.params.min_doc_count;
}
getAutoBounds: {
configurable: true,
value() {
return autoBounds;
}
}
]
});
}
};
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
},
{
name: 'interval',
editor: intervalTemplate,
modifyAggConfigOnSearchRequestStart(aggConfig, searchSource) {
const field = aggConfig.getField();
const aggBody = field.scripted
? { script: { inline: field.script, lang: field.lang } }
: { field: field.name };
return searchSource
.extend()
.size(0)
.aggs({
maxAgg: {
max: aggBody
},
minAgg: {
min: aggBody
}
})
.fetchAsRejectablePromise()
.then((resp) => {
aggConfig.setAutoBounds({
min: _.get(resp, 'aggregations.minAgg.value'),
max: _.get(resp, 'aggregations.maxAgg.value')
});
});
},
write: function (aggConfig, output) {
let interval = parseFloat(aggConfig.params.interval);
if (interval <= 0) {
interval = 1;
}
// ensure interval does not create too many buckets and crash browser
if (aggConfig.getAutoBounds()) {
const range = aggConfig.getAutoBounds().max - aggConfig.getAutoBounds().min;
const bars = range / interval;
if (bars > config.get('histogram:maxBars')) {
const minInterval = range / config.get('histogram:maxBars');
// Round interval by order of magnitude to provide clean intervals
// Always round interval up so there will always be less buckets than histogram:maxBars
const orderOfMaginute = Math.pow(10, Math.floor(Math.log10(minInterval)));
let roundInterval = orderOfMaginute;
while (roundInterval < minInterval) {
roundInterval += orderOfMaginute;
}
interval = roundInterval;
}
}
output.params.interval = interval;
}
},
{
name: 'min_doc_count',
default: null,
editor: minDocCountTemplate,
write: function (aggConfig, output) {
if (aggConfig.params.min_doc_count) {
output.params.min_doc_count = 0;
} else {
output.params.min_doc_count = 1;
}
}
},
{
name: 'extended_bounds',
default: {},
editor: extendedBoundsTemplate,
write: function (aggConfig, output) {
const val = aggConfig.params.extended_bounds;
if (aggConfig.params.min_doc_count && (val.min != null || val.max != null)) {
output.params.extended_bounds = {
min: val.min,
max: val.max
};
}
},
// called from the editor
shouldShow: function (aggConfig) {
const field = aggConfig.params.field;
if (
field
&& (field.type === 'number' || field.type === 'date')
) {
return aggConfig.params.min_doc_count;
}
}
}
]
});

View file

@ -1,61 +1,56 @@
import _ from 'lodash';
import '../../directives/validate_ip';
import '../../directives/validate_cidr_mask';
import { AggTypesBucketsBucketAggTypeProvider } from './_bucket_agg_type';
import { AggTypesBucketsCreateFilterIpRangeProvider } from './create_filter/ip_range';
import { BucketAggType } from './_bucket_agg_type';
import { createFilterIpRange } from './create_filter/ip_range';
import ipRangesTemplate from '../controls/ip_ranges.html';
export function AggTypesBucketsIpRangeProvider(Private) {
const BucketAggType = Private(AggTypesBucketsBucketAggTypeProvider);
const createFilter = Private(AggTypesBucketsCreateFilterIpRangeProvider);
export const ipRangeBucketAgg = new BucketAggType({
name: 'ip_range',
title: 'IPv4 Range',
createFilter: createFilterIpRange,
getKey: function (bucket, key) {
if (key) return key;
const from = _.get(bucket, 'from', '-Infinity');
const to = _.get(bucket, 'to', 'Infinity');
return `${from} to ${to}`;
},
makeLabel: function (aggConfig) {
return aggConfig.getFieldDisplayName() + ' IP ranges';
},
params: [
{
name: 'field',
filterFieldTypes: 'ip'
}, {
name: 'ipRangeType',
default: 'fromTo',
write: _.noop
}, {
name: 'ranges',
default: {
fromTo: [
{ from: '0.0.0.0', to: '127.255.255.255' },
{ from: '128.0.0.0', to: '191.255.255.255' }
],
mask: [
{ mask: '0.0.0.0/1' },
{ mask: '128.0.0.0/2' }
]
},
editor: ipRangesTemplate,
write: function (aggConfig, output) {
const ipRangeType = aggConfig.params.ipRangeType;
let ranges = aggConfig.params.ranges[ipRangeType];
return new BucketAggType({
name: 'ip_range',
title: 'IPv4 Range',
createFilter: createFilter,
getKey: function (bucket, key) {
if (key) return key;
const from = _.get(bucket, 'from', '-Infinity');
const to = _.get(bucket, 'to', 'Infinity');
return `${from} to ${to}`;
},
makeLabel: function (aggConfig) {
return aggConfig.getFieldDisplayName() + ' IP ranges';
},
params: [
{
name: 'field',
filterFieldTypes: 'ip'
}, {
name: 'ipRangeType',
default: 'fromTo',
write: _.noop
}, {
name: 'ranges',
default: {
fromTo: [
{ from: '0.0.0.0', to: '127.255.255.255' },
{ from: '128.0.0.0', to: '191.255.255.255' }
],
mask: [
{ mask: '0.0.0.0/1' },
{ mask: '128.0.0.0/2' }
]
},
editor: ipRangesTemplate,
write: function (aggConfig, output) {
const ipRangeType = aggConfig.params.ipRangeType;
let ranges = aggConfig.params.ranges[ipRangeType];
if (ipRangeType === 'fromTo') {
ranges = _.map(ranges, (range) => {
return _.omit(range, _.isNull);
});
}
output.params.ranges = ranges;
if (ipRangeType === 'fromTo') {
ranges = _.map(ranges, (range) => {
return _.omit(range, _.isNull);
});
}
output.params.ranges = ranges;
}
]
});
}
}
]
});

View file

@ -1,73 +1,67 @@
import { AggTypesBucketsBucketAggTypeProvider } from './_bucket_agg_type';
import { AggTypesBucketsCreateFilterRangeProvider } from './create_filter/range';
import { BucketAggType } from './_bucket_agg_type';
import { createFilterRange } from './create_filter/range';
import { FieldFormat } from '../../../field_formats/field_format';
import { RangeKeyProvider } from './range_key';
import { RangeKey } from './range_key';
import rangesTemplate from '../controls/ranges.html';
export function AggTypesBucketsRangeProvider(Private) {
const BucketAggType = Private(AggTypesBucketsBucketAggTypeProvider);
const createFilter = Private(AggTypesBucketsCreateFilterRangeProvider);
const RangeKey = Private(RangeKeyProvider);
const keyCaches = new WeakMap();
const formats = new WeakMap();
const keyCaches = new WeakMap();
const formats = new WeakMap();
export const rangeBucketAgg = new BucketAggType({
name: 'range',
title: 'Range',
createFilter: createFilterRange,
makeLabel: function (aggConfig) {
return aggConfig.getFieldDisplayName() + ' ranges';
},
getKey: function (bucket, key, agg) {
let keys = keyCaches.get(agg);
return new BucketAggType({
name: 'range',
title: 'Range',
createFilter: createFilter,
makeLabel: function (aggConfig) {
return aggConfig.getFieldDisplayName() + ' ranges';
if (!keys) {
keys = new Map();
keyCaches.set(agg, keys);
}
const id = RangeKey.idBucket(bucket);
key = keys.get(id);
if (!key) {
key = new RangeKey(bucket);
keys.set(id, key);
}
return key;
},
getFormat: function (agg) {
let format = formats.get(agg);
if (format) return format;
const RangeFormat = FieldFormat.from(function (range) {
const format = agg.fieldOwnFormatter();
return `${format(range.gte)} to ${format(range.lt)}`;
});
format = new RangeFormat();
formats.set(agg, format);
return format;
},
params: [
{
name: 'field',
filterFieldTypes: ['number']
},
getKey: function (bucket, key, agg) {
let keys = keyCaches.get(agg);
if (!keys) {
keys = new Map();
keyCaches.set(agg, keys);
{
name: 'ranges',
default: [
{ from: 0, to: 1000 },
{ from: 1000, to: 2000 }
],
editor: rangesTemplate,
write: function (aggConfig, output) {
output.params.ranges = aggConfig.params.ranges;
output.params.keyed = true;
}
const id = RangeKey.idBucket(bucket);
key = keys.get(id);
if (!key) {
key = new RangeKey(bucket);
keys.set(id, key);
}
return key;
},
getFormat: function (agg) {
let format = formats.get(agg);
if (format) return format;
const RangeFormat = FieldFormat.from(function (range) {
const format = agg.fieldOwnFormatter();
return `${format(range.gte)} to ${format(range.lt)}`;
});
format = new RangeFormat();
formats.set(agg, format);
return format;
},
params: [
{
name: 'field',
filterFieldTypes: ['number']
},
{
name: 'ranges',
default: [
{ from: 0, to: 1000 },
{ from: 1000, to: 2000 }
],
editor: rangesTemplate,
write: function (aggConfig, output) {
output.params.ranges = aggConfig.params.ranges;
output.params.keyed = true;
}
}
]
});
}
}
]
});

View file

@ -1,25 +1,21 @@
export function RangeKeyProvider() {
const id = Symbol('id');
const id = Symbol('id');
class RangeKey {
constructor(bucket) {
this.gte = bucket.from == null ? -Infinity : bucket.from;
this.lt = bucket.to == null ? +Infinity : bucket.to;
class RangeKey {
constructor(bucket) {
this.gte = bucket.from == null ? -Infinity : bucket.from;
this.lt = bucket.to == null ? +Infinity : bucket.to;
this[id] = RangeKey.idBucket(bucket);
}
static idBucket(bucket) {
return `from:${bucket.from},to:${bucket.to}`;
}
toString() {
return this[id];
}
this[id] = RangeKey.idBucket(bucket);
}
return RangeKey;
static idBucket(bucket) {
return `from:${bucket.from},to:${bucket.to}`;
}
toString() {
return this[id];
}
}
export { RangeKey };

View file

@ -1,38 +1,33 @@
import { AggTypesBucketsBucketAggTypeProvider } from './_bucket_agg_type';
import { AggTypesBucketsCreateFilterTermsProvider } from './create_filter/terms';
import { BucketAggType } from './_bucket_agg_type';
import { createFilterTerms } from './create_filter/terms';
import orderAndSizeTemplate from '../controls/order_and_size.html';
export function AggTypesBucketsSignificantTermsProvider(Private) {
const BucketAggType = Private(AggTypesBucketsBucketAggTypeProvider);
const createFilter = Private(AggTypesBucketsCreateFilterTermsProvider);
return new BucketAggType({
name: 'significant_terms',
title: 'Significant Terms',
makeLabel: function (aggConfig) {
return 'Top ' + aggConfig.params.size + ' unusual terms in ' + aggConfig.getFieldDisplayName();
export const significantTermsBucketAgg = new BucketAggType({
name: 'significant_terms',
title: 'Significant Terms',
makeLabel: function (aggConfig) {
return 'Top ' + aggConfig.params.size + ' unusual terms in ' + aggConfig.getFieldDisplayName();
},
createFilter: createFilterTerms,
params: [
{
name: 'field',
scriptable: false,
filterFieldTypes: 'string'
},
createFilter: createFilter,
params: [
{
name: 'field',
scriptable: false,
filterFieldTypes: 'string'
},
{
name: 'size',
editor: orderAndSizeTemplate,
},
{
name: 'exclude',
type: 'regex',
advanced: true
},
{
name: 'include',
type: 'regex',
advanced: true
}
]
});
}
{
name: 'size',
editor: orderAndSizeTemplate,
},
{
name: 'exclude',
type: 'regex',
advanced: true
},
{
name: 'include',
type: 'regex',
advanced: true
}
]
});

View file

@ -1,253 +1,246 @@
import _ from 'lodash';
import { AggTypesBucketsBucketAggTypeProvider } from './_bucket_agg_type';
import { BucketAggType } from './_bucket_agg_type';
import { AggConfig } from '../../vis/agg_config';
import { Schemas } from '../../vis/editors/default/schemas';
import { AggTypesBucketsCreateFilterTermsProvider } from './create_filter/terms';
import { createFilterTerms } from './create_filter/terms';
import orderAggTemplate from '../controls/order_agg.html';
import orderAndSizeTemplate from '../controls/order_and_size.html';
import otherBucketTemplate from 'ui/agg_types/controls/other_bucket.html';
import { RouteBasedNotifierProvider } from '../../route_based_notifier';
import { OtherBucketHelperProvider } from './_terms_other_bucket_helper';
import otherBucketTemplate from '../controls/other_bucket.html';
import { buildOtherBucketAgg, mergeOtherBucketAggResponse, updateMissingBucket } from './_terms_other_bucket_helper';
import { toastNotifications } from '../../notify';
export function AggTypesBucketsTermsProvider(Private) {
const BucketAggType = Private(AggTypesBucketsBucketAggTypeProvider);
const createFilter = Private(AggTypesBucketsCreateFilterTermsProvider);
const routeBasedNotifier = Private(RouteBasedNotifierProvider);
const { buildOtherBucketAgg, mergeOtherBucketAggResponse, updateMissingBucket } = Private(OtherBucketHelperProvider);
const aggFilter = [
'!top_hits', '!percentiles', '!median', '!std_dev',
'!derivative', '!moving_avg', '!serial_diff', '!cumulative_sum',
'!avg_bucket', '!max_bucket', '!min_bucket', '!sum_bucket'
];
const aggFilter = [
'!top_hits', '!percentiles', '!median', '!std_dev',
'!derivative', '!moving_avg', '!serial_diff', '!cumulative_sum',
'!avg_bucket', '!max_bucket', '!min_bucket', '!sum_bucket'
];
const orderAggSchema = (new Schemas([
{
group: 'none',
name: 'orderAgg',
title: 'Order Agg',
hideCustomLabel: true,
aggFilter: aggFilter
}
])).all[0];
function isNotType(type) {
return function (agg) {
const field = agg.params.field;
return !field || field.type !== type;
};
const orderAggSchema = (new Schemas([
{
group: 'none',
name: 'orderAgg',
title: 'Order Agg',
hideCustomLabel: true,
aggFilter: aggFilter
}
])).all[0];
const migrateIncludeExcludeFormat = {
serialize: function (value) {
if (!value || _.isString(value)) return value;
else return value.pattern;
},
write: function (aggConfig, output) {
const value = aggConfig.params[this.name];
if (_.isObject(value)) {
output.params[this.name] = value.pattern;
} else if (value) {
output.params[this.name] = value;
}
}
function isNotType(type) {
return function (agg) {
const field = agg.params.field;
return !field || field.type !== type;
};
}
return new BucketAggType({
name: 'terms',
title: 'Terms',
makeLabel: function (agg) {
const params = agg.params;
return agg.getFieldDisplayName() + ': ' + params.order.display;
const migrateIncludeExcludeFormat = {
serialize: function (value) {
if (!value || _.isString(value)) return value;
else return value.pattern;
},
write: function (aggConfig, output) {
const value = aggConfig.params[this.name];
if (_.isObject(value)) {
output.params[this.name] = value.pattern;
} else if (value) {
output.params[this.name] = value;
}
}
};
export const termsBucketAgg = new BucketAggType({
name: 'terms',
title: 'Terms',
makeLabel: function (agg) {
const params = agg.params;
return agg.getFieldDisplayName() + ': ' + params.order.display;
},
createFilter: createFilterTerms,
postFlightRequest: async (resp, aggConfigs, aggConfig, nestedSearchSource) => {
if (aggConfig.params.otherBucket) {
const filterAgg = buildOtherBucketAgg(aggConfigs, aggConfig, resp);
nestedSearchSource.set('aggs', filterAgg);
const response = await nestedSearchSource.fetchAsRejectablePromise();
resp = mergeOtherBucketAggResponse(aggConfigs, resp, response, aggConfig, filterAgg());
}
if (aggConfig.params.missingBucket) {
resp = updateMissingBucket(resp, aggConfigs, aggConfig);
}
return resp;
},
params: [
{
name: 'field',
filterFieldTypes: ['number', 'boolean', 'date', 'ip', 'string']
},
createFilter: createFilter,
postFlightRequest: async (resp, aggConfigs, aggConfig, nestedSearchSource) => {
if (aggConfig.params.otherBucket) {
const filterAgg = buildOtherBucketAgg(aggConfigs, aggConfig, resp);
nestedSearchSource.set('aggs', filterAgg);
const response = await nestedSearchSource.fetchAsRejectablePromise();
resp = mergeOtherBucketAggResponse(aggConfigs, resp, response, aggConfig, filterAgg());
}
if (aggConfig.params.missingBucket) {
resp = updateMissingBucket(resp, aggConfigs, aggConfig);
}
return resp;
{
name: 'size',
default: 5
},
params: [
{
name: 'field',
filterFieldTypes: ['number', 'boolean', 'date', 'ip', 'string']
{
name: 'orderAgg',
type: AggConfig,
default: null,
editor: orderAggTemplate,
serialize: function (orderAgg) {
return orderAgg.toJSON();
},
{
name: 'size',
default: 5
deserialize: function (state, agg) {
return this.makeOrderAgg(agg, state);
},
{
name: 'orderAgg',
type: AggConfig,
default: null,
editor: orderAggTemplate,
serialize: function (orderAgg) {
return orderAgg.toJSON();
},
deserialize: function (state, agg) {
return this.makeOrderAgg(agg, state);
},
makeOrderAgg: function (termsAgg, state) {
state = state || {};
state.schema = orderAggSchema;
const orderAgg = new AggConfig(termsAgg.vis, state);
orderAgg.id = termsAgg.id + '-orderAgg';
return orderAgg;
},
controller: function ($scope) {
$scope.safeMakeLabel = function (agg) {
try {
return agg.makeLabel();
} catch (e) {
return '- agg not valid -';
}
};
const INIT = {}; // flag to know when prevOrderBy has changed
let prevOrderBy = INIT;
$scope.$watch('responseValueAggs', updateOrderAgg);
$scope.$watch('agg.params.orderBy', updateOrderAgg);
// Returns true if the agg is not compatible with the terms bucket
$scope.rejectAgg = function rejectAgg(agg) {
return aggFilter.includes(`!${agg.type.name}`);
};
$scope.$watch('agg.params.field.type', (type) => {
if (type !== 'string') {
$scope.agg.params.missingBucket = false;
}
});
function updateOrderAgg() {
// abort until we get the responseValueAggs
if (!$scope.responseValueAggs) return;
const agg = $scope.agg;
const params = agg.params;
const orderBy = params.orderBy;
const paramDef = agg.type.params.byName.orderAgg;
// setup the initial value of orderBy
if (!orderBy && prevOrderBy === INIT) {
let respAgg = _($scope.responseValueAggs).filter((agg) => !$scope.rejectAgg(agg)).first();
if (!respAgg) {
respAgg = { id: '_term' };
}
params.orderBy = respAgg.id;
return;
}
// track the previous value
prevOrderBy = orderBy;
// we aren't creating a custom aggConfig
if (!orderBy || orderBy !== 'custom') {
params.orderAgg = null;
// ensure that orderBy is set to a valid agg
const respAgg = _($scope.responseValueAggs).filter((agg) => !$scope.rejectAgg(agg)).find({ id: orderBy });
if (!respAgg) {
params.orderBy = '_term';
}
return;
}
params.orderAgg = params.orderAgg || paramDef.makeOrderAgg(agg);
makeOrderAgg: function (termsAgg, state) {
state = state || {};
state.schema = orderAggSchema;
const orderAgg = new AggConfig(termsAgg.vis, state);
orderAgg.id = termsAgg.id + '-orderAgg';
return orderAgg;
},
controller: function ($scope) {
$scope.safeMakeLabel = function (agg) {
try {
return agg.makeLabel();
} catch (e) {
return '- agg not valid -';
}
},
write: function (agg, output) {
const vis = agg.vis;
const dir = agg.params.order.val;
const order = output.params.order = {};
};
let orderAgg = agg.params.orderAgg || vis.aggs.getResponseAggById(agg.params.orderBy);
const INIT = {}; // flag to know when prevOrderBy has changed
let prevOrderBy = INIT;
// TODO: This works around an Elasticsearch bug the always casts terms agg scripts to strings
// thus causing issues with filtering. This probably causes other issues since float might not
// be able to contain the number on the elasticsearch side
if (output.params.script) {
output.params.valueType = agg.getField().type === 'number' ? 'float' : agg.getField().type;
$scope.$watch('responseValueAggs', updateOrderAgg);
$scope.$watch('agg.params.orderBy', updateOrderAgg);
// Returns true if the agg is not compatible with the terms bucket
$scope.rejectAgg = function rejectAgg(agg) {
return aggFilter.includes(`!${agg.type.name}`);
};
$scope.$watch('agg.params.field.type', (type) => {
if (type !== 'string') {
$scope.agg.params.missingBucket = false;
}
});
if (agg.params.missingBucket && agg.params.field.type === 'string') {
output.params.missing = '__missing__';
}
function updateOrderAgg() {
// abort until we get the responseValueAggs
if (!$scope.responseValueAggs) return;
const agg = $scope.agg;
const params = agg.params;
const orderBy = params.orderBy;
const paramDef = agg.type.params.byName.orderAgg;
if (!orderAgg) {
order[agg.params.orderBy || '_count'] = dir;
// setup the initial value of orderBy
if (!orderBy && prevOrderBy === INIT) {
let respAgg = _($scope.responseValueAggs).filter((agg) => !$scope.rejectAgg(agg)).first();
if (!respAgg) {
respAgg = { id: '_term' };
}
params.orderBy = respAgg.id;
return;
}
if (orderAgg.type.name === 'count') {
if (dir === 'asc') {
routeBasedNotifier.warning('Sorting in Ascending order by Count in Terms aggregations is deprecated');
// track the previous value
prevOrderBy = orderBy;
// we aren't creating a custom aggConfig
if (!orderBy || orderBy !== 'custom') {
params.orderAgg = null;
// ensure that orderBy is set to a valid agg
const respAgg = _($scope.responseValueAggs).filter((agg) => !$scope.rejectAgg(agg)).find({ id: orderBy });
if (!respAgg) {
params.orderBy = '_term';
}
order._count = dir;
return;
}
const orderAggId = orderAgg.id;
if (orderAgg.parentId) {
orderAgg = vis.aggs.byId[orderAgg.parentId];
}
output.subAggs = (output.subAggs || []).concat(orderAgg);
order[orderAggId] = dir;
params.orderAgg = params.orderAgg || paramDef.makeOrderAgg(agg);
}
},
{
name: 'order',
type: 'optioned',
default: 'desc',
editor: orderAndSizeTemplate,
options: [
{ display: 'Descending', val: 'desc' },
{ display: 'Ascending', val: 'asc' }
],
write: _.noop // prevent default write, it's handled by orderAgg
},
{
name: 'orderBy',
write: _.noop // prevent default write, it's handled by orderAgg
},
{
name: 'otherBucket',
default: false,
editor: otherBucketTemplate,
write: _.noop
}, {
name: 'otherBucketLabel',
default: 'Other',
write: _.noop
}, {
name: 'missingBucket',
default: false,
write: _.noop
}, {
name: 'missingBucketLabel',
default: 'Missing',
write: _.noop
},
{
name: 'exclude',
type: 'string',
advanced: true,
disabled: isNotType('string'),
...migrateIncludeExcludeFormat
},
{
name: 'include',
type: 'string',
advanced: true,
disabled: isNotType('string'),
...migrateIncludeExcludeFormat
},
]
});
}
write: function (agg, output) {
const vis = agg.vis;
const dir = agg.params.order.val;
const order = output.params.order = {};
let orderAgg = agg.params.orderAgg || vis.aggs.getResponseAggById(agg.params.orderBy);
// TODO: This works around an Elasticsearch bug the always casts terms agg scripts to strings
// thus causing issues with filtering. This probably causes other issues since float might not
// be able to contain the number on the elasticsearch side
if (output.params.script) {
output.params.valueType = agg.getField().type === 'number' ? 'float' : agg.getField().type;
}
if (agg.params.missingBucket && agg.params.field.type === 'string') {
output.params.missing = '__missing__';
}
if (!orderAgg) {
order[agg.params.orderBy || '_count'] = dir;
return;
}
if (orderAgg.type.name === 'count') {
if (dir === 'asc') {
toastNotifications.addWarning('Sorting in Ascending order by Count in Terms aggregations is deprecated');
}
order._count = dir;
return;
}
const orderAggId = orderAgg.id;
if (orderAgg.parentId) {
orderAgg = vis.aggs.byId[orderAgg.parentId];
}
output.subAggs = (output.subAggs || []).concat(orderAgg);
order[orderAggId] = dir;
}
},
{
name: 'order',
type: 'optioned',
default: 'desc',
editor: orderAndSizeTemplate,
options: [
{ display: 'Descending', val: 'desc' },
{ display: 'Ascending', val: 'asc' }
],
write: _.noop // prevent default write, it's handled by orderAgg
},
{
name: 'orderBy',
write: _.noop // prevent default write, it's handled by orderAgg
},
{
name: 'otherBucket',
default: false,
editor: otherBucketTemplate,
write: _.noop
}, {
name: 'otherBucketLabel',
default: 'Other',
write: _.noop
}, {
name: 'missingBucket',
default: false,
write: _.noop
}, {
name: 'missingBucketLabel',
default: 'Missing',
write: _.noop
},
{
name: 'exclude',
type: 'string',
advanced: true,
disabled: isNotType('string'),
...migrateIncludeExcludeFormat
},
{
name: 'include',
type: 'string',
advanced: true,
disabled: isNotType('string'),
...migrateIncludeExcludeFormat
}
]
});

View file

@ -1,105 +1,102 @@
import { IndexedArray } from '../indexed_array';
import './agg_params';
import { AggTypesMetricsCountProvider } from './metrics/count';
import { AggTypesMetricsAvgProvider } from './metrics/avg';
import { AggTypesMetricsSumProvider } from './metrics/sum';
import { AggTypesMetricsMedianProvider } from './metrics/median';
import { AggTypesMetricsMinProvider } from './metrics/min';
import { AggTypesMetricsMaxProvider } from './metrics/max';
import { AggTypesMetricsTopHitProvider } from './metrics/top_hit';
import { AggTypesMetricsStdDeviationProvider } from './metrics/std_deviation';
import { AggTypesMetricsCardinalityProvider } from './metrics/cardinality';
import { AggTypesMetricsPercentilesProvider } from './metrics/percentiles';
import { AggTypesMetricsGeoBoundsProvider } from './metrics/geo_bounds';
import { AggTypesMetricsGeoCentroidProvider } from './metrics/geo_centroid';
import { AggTypesMetricsPercentileRanksProvider } from './metrics/percentile_ranks';
import { AggTypesMetricsDerivativeProvider } from './metrics/derivative';
import { AggTypesMetricsCumulativeSumProvider } from './metrics/cumulative_sum';
import { AggTypesMetricsMovingAvgProvider } from './metrics/moving_avg';
import { AggTypesMetricsSerialDiffProvider } from './metrics/serial_diff';
import { AggTypesBucketsDateHistogramProvider } from './buckets/date_histogram';
import { AggTypesBucketsHistogramProvider } from './buckets/histogram';
import { AggTypesBucketsRangeProvider } from './buckets/range';
import { AggTypesBucketsDateRangeProvider } from './buckets/date_range';
import { AggTypesBucketsIpRangeProvider } from './buckets/ip_range';
import { AggTypesBucketsTermsProvider } from './buckets/terms';
import { AggTypesBucketsFilterProvider } from './buckets/filter';
import { AggTypesBucketsFiltersProvider } from './buckets/filters';
import { AggTypesBucketsSignificantTermsProvider } from './buckets/significant_terms';
import { AggTypesBucketsGeoHashProvider } from './buckets/geo_hash';
import { AggTypesMetricsBucketSumProvider } from './metrics/bucket_sum';
import { AggTypesMetricsBucketAvgProvider } from './metrics/bucket_avg';
import { AggTypesMetricsBucketMinProvider } from './metrics/bucket_min';
import { AggTypesMetricsBucketMaxProvider } from './metrics/bucket_max';
import '../directives/validate_agg';
import './agg_params';
import { IndexedArray } from '../indexed_array';
import { countMetricAgg } from './metrics/count';
import { avgMetricAgg } from './metrics/avg';
import { sumMetricAgg } from './metrics/sum';
import { medianMetricAgg } from './metrics/median';
import { minMetricAgg } from './metrics/min';
import { maxMetricAgg } from './metrics/max';
import { topHitMetricAgg } from './metrics/top_hit';
import { stdDeviationMetricAgg } from './metrics/std_deviation';
import { cardinalityMetricAgg } from './metrics/cardinality';
import { percentilesMetricAgg } from './metrics/percentiles';
import { geoBoundsMetricAgg } from './metrics/geo_bounds';
import { geoCentroidMetricAgg } from './metrics/geo_centroid';
import { percentileRanksMetricAgg } from './metrics/percentile_ranks';
import { derivativeMetricAgg } from './metrics/derivative';
import { cumulativeSumMetricAgg } from './metrics/cumulative_sum';
import { movingAvgMetricAgg } from './metrics/moving_avg';
import { serialDiffMetricAgg } from './metrics/serial_diff';
import { dateHistogramBucketAgg } from './buckets/date_histogram';
import { histogramBucketAgg } from './buckets/histogram';
import { rangeBucketAgg } from './buckets/range';
import { dateRangeBucketAgg } from './buckets/date_range';
import { ipRangeBucketAgg } from './buckets/ip_range';
import { termsBucketAgg } from './buckets/terms';
import { filterBucketAgg } from './buckets/filter';
import { filtersBucketAgg } from './buckets/filters';
import { significantTermsBucketAgg } from './buckets/significant_terms';
import { geoHashBucketAgg } from './buckets/geo_hash';
import { bucketSumMetricAgg } from './metrics/bucket_sum';
import { bucketAvgMetricAgg } from './metrics/bucket_avg';
import { bucketMinMetricAgg } from './metrics/bucket_min';
import { bucketMaxMetricAgg } from './metrics/bucket_max';
export function AggTypesIndexProvider(Private) {
const aggs = {
metrics: [
countMetricAgg,
avgMetricAgg,
sumMetricAgg,
medianMetricAgg,
minMetricAgg,
maxMetricAgg,
stdDeviationMetricAgg,
cardinalityMetricAgg,
percentilesMetricAgg,
percentileRanksMetricAgg,
topHitMetricAgg,
derivativeMetricAgg,
cumulativeSumMetricAgg,
movingAvgMetricAgg,
serialDiffMetricAgg,
bucketAvgMetricAgg,
bucketSumMetricAgg,
bucketMinMetricAgg,
bucketMaxMetricAgg,
geoBoundsMetricAgg,
geoCentroidMetricAgg
],
buckets: [
dateHistogramBucketAgg,
histogramBucketAgg,
rangeBucketAgg,
dateRangeBucketAgg,
ipRangeBucketAgg,
termsBucketAgg,
filterBucketAgg,
filtersBucketAgg,
significantTermsBucketAgg,
geoHashBucketAgg
]
};
const aggs = {
metrics: [
Private(AggTypesMetricsCountProvider),
Private(AggTypesMetricsAvgProvider),
Private(AggTypesMetricsSumProvider),
Private(AggTypesMetricsMedianProvider),
Private(AggTypesMetricsMinProvider),
Private(AggTypesMetricsMaxProvider),
Private(AggTypesMetricsStdDeviationProvider),
Private(AggTypesMetricsCardinalityProvider),
Private(AggTypesMetricsPercentilesProvider),
Private(AggTypesMetricsPercentileRanksProvider),
Private(AggTypesMetricsTopHitProvider),
Private(AggTypesMetricsDerivativeProvider),
Private(AggTypesMetricsCumulativeSumProvider),
Private(AggTypesMetricsMovingAvgProvider),
Private(AggTypesMetricsSerialDiffProvider),
Private(AggTypesMetricsBucketAvgProvider),
Private(AggTypesMetricsBucketSumProvider),
Private(AggTypesMetricsBucketMinProvider),
Private(AggTypesMetricsBucketMaxProvider),
Private(AggTypesMetricsGeoBoundsProvider),
Private(AggTypesMetricsGeoCentroidProvider)
],
buckets: [
Private(AggTypesBucketsDateHistogramProvider),
Private(AggTypesBucketsHistogramProvider),
Private(AggTypesBucketsRangeProvider),
Private(AggTypesBucketsDateRangeProvider),
Private(AggTypesBucketsIpRangeProvider),
Private(AggTypesBucketsTermsProvider),
Private(AggTypesBucketsFilterProvider),
Private(AggTypesBucketsFiltersProvider),
Private(AggTypesBucketsSignificantTermsProvider),
Private(AggTypesBucketsGeoHashProvider),
]
};
Object.keys(aggs).forEach(function (type) {
aggs[type].forEach(function (agg) {
agg.type = type;
});
Object.keys(aggs).forEach(function (type) {
aggs[type].forEach(function (agg) {
agg.type = type;
});
});
/**
* IndexedArray of Aggregation Types.
*
* These types form two groups, metric and buckets.
*
* @module agg_types
* @type {IndexedArray}
*/
export const aggTypes = new IndexedArray({
/**
* IndexedArray of Aggregation Types.
*
* These types form two groups, metric and buckets.
*
* @module agg_types
* @type {IndexedArray}
* @type {Array}
*/
return new IndexedArray({
index: ['name'],
/**
* @type {Array}
*/
index: ['name'],
/**
* [group description]
* @type {Array}
*/
group: ['type'],
initialSet: aggs.metrics.concat(aggs.buckets)
});
}
/**
* [group description]
* @type {Array}
*/
group: ['type'],
initialSet: aggs.metrics.concat(aggs.buckets)
});

View file

@ -1,19 +1,15 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
export function AggTypesMetricsAvgProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'avg',
title: 'Average',
makeLabel: function (aggConfig) {
return 'Average ' + aggConfig.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
}
]
});
}
export const avgMetricAgg = new MetricAggType({
name: 'avg',
title: 'Average',
makeLabel: function (aggConfig) {
return 'Average ' + aggConfig.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
}
]
});

View file

@ -1,30 +1,26 @@
import { get } from 'lodash';
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper';
export function AggTypesMetricsBucketAvgProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
export const bucketAvgMetricAgg = new MetricAggType({
name: 'avg_bucket',
title: 'Average Bucket',
makeLabel: agg => makeNestedLabel(agg, 'overall average'),
subtype: siblingPipelineAggHelper.subtype,
params: [
...siblingPipelineAggHelper.params()
],
getFormat: siblingPipelineAggHelper.getFormat,
getValue: function (agg, bucket) {
const customMetric = agg.params.customMetric;
const scaleMetrics = customMetric.type && customMetric.type.isScalable();
return new MetricAggType({
name: 'avg_bucket',
title: 'Average Bucket',
makeLabel: agg => makeNestedLabel(agg, 'overall average'),
subtype: siblingPipelineAggHelper.subtype,
params: [
...siblingPipelineAggHelper.params()
],
getFormat: siblingPipelineAggHelper.getFormat,
getValue: function (agg, bucket) {
const customMetric = agg.params.customMetric;
const scaleMetrics = customMetric.type && customMetric.type.isScalable();
let value = bucket[agg.id] && bucket[agg.id].value;
if (scaleMetrics) {
const aggInfo = agg.params.customBucket.write();
value *= get(aggInfo, 'bucketInterval.scale', 1);
}
return value;
let value = bucket[agg.id] && bucket[agg.id].value;
if (scaleMetrics) {
const aggInfo = agg.params.customBucket.write();
value *= get(aggInfo, 'bucketInterval.scale', 1);
}
});
}
return value;
}
});

View file

@ -1,18 +1,14 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper';
export function AggTypesMetricsBucketMaxProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'max_bucket',
title: 'Max Bucket',
makeLabel: agg => makeNestedLabel(agg, 'overall max'),
subtype: siblingPipelineAggHelper.subtype,
params: [
...siblingPipelineAggHelper.params()
],
getFormat: siblingPipelineAggHelper.getFormat
});
}
export const bucketMaxMetricAgg = new MetricAggType({
name: 'max_bucket',
title: 'Max Bucket',
makeLabel: agg => makeNestedLabel(agg, 'overall max'),
subtype: siblingPipelineAggHelper.subtype,
params: [
...siblingPipelineAggHelper.params()
],
getFormat: siblingPipelineAggHelper.getFormat
});

View file

@ -1,18 +1,14 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper';
export function AggTypesMetricsBucketMinProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'min_bucket',
title: 'Min Bucket',
makeLabel: agg => makeNestedLabel(agg, 'overall min'),
subtype: siblingPipelineAggHelper.subtype,
params: [
...siblingPipelineAggHelper.params()
],
getFormat: siblingPipelineAggHelper.getFormat
});
}
export const bucketMinMetricAgg = new MetricAggType({
name: 'min_bucket',
title: 'Min Bucket',
makeLabel: agg => makeNestedLabel(agg, 'overall min'),
subtype: siblingPipelineAggHelper.subtype,
params: [
...siblingPipelineAggHelper.params()
],
getFormat: siblingPipelineAggHelper.getFormat
});

View file

@ -1,18 +1,14 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper';
export function AggTypesMetricsBucketSumProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'sum_bucket',
title: 'Sum Bucket',
makeLabel: agg => makeNestedLabel(agg, 'overall sum'),
subtype: siblingPipelineAggHelper.subtype,
params: [
...siblingPipelineAggHelper.params()
],
getFormat: siblingPipelineAggHelper.getFormat
});
}
export const bucketSumMetricAgg = new MetricAggType({
name: 'sum_bucket',
title: 'Sum Bucket',
makeLabel: agg => makeNestedLabel(agg, 'overall sum'),
subtype: siblingPipelineAggHelper.subtype,
params: [
...siblingPipelineAggHelper.params()
],
getFormat: siblingPipelineAggHelper.getFormat
});

View file

@ -1,23 +1,18 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
import { fieldFormats } from '../../registry/field_formats';
export function AggTypesMetricsCardinalityProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'cardinality',
title: 'Unique Count',
makeLabel: function (aggConfig) {
return 'Unique count of ' + aggConfig.getFieldDisplayName();
},
getFormat: function () {
return fieldFormats.getDefaultInstance('number');
},
params: [
{
name: 'field'
}
]
});
}
export const cardinalityMetricAgg = new MetricAggType({
name: 'cardinality',
title: 'Unique Count',
makeLabel: function (aggConfig) {
return 'Unique count of ' + aggConfig.getFieldDisplayName();
},
getFormat: function () {
return fieldFormats.getDefaultInstance('number');
},
params: [
{
name: 'field'
}
]
});

View file

@ -1,25 +1,20 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
import { fieldFormats } from '../../registry/field_formats';
export function AggTypesMetricsCountProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'count',
title: 'Count',
hasNoDsl: true,
makeLabel: function () {
return 'Count';
},
getFormat: function () {
return fieldFormats.getDefaultInstance('number');
},
getValue: function (agg, bucket) {
return bucket.doc_count;
},
isScalable: function () {
return true;
}
});
}
export const countMetricAgg = new MetricAggType({
name: 'count',
title: 'Count',
hasNoDsl: true,
makeLabel: function () {
return 'Count';
},
getFormat: function () {
return fieldFormats.getDefaultInstance('number');
},
getValue: function (agg, bucket) {
return bucket.doc_count;
},
isScalable: function () {
return true;
}
});

View file

@ -1,18 +1,14 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper';
import { makeNestedLabel } from './lib/make_nested_label';
export function AggTypesMetricsCumulativeSumProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'cumulative_sum',
title: 'Cumulative Sum',
subtype: parentPipelineAggHelper.subtype,
makeLabel: agg => makeNestedLabel(agg, 'cumulative sum'),
params: [
...parentPipelineAggHelper.params()
],
getFormat: parentPipelineAggHelper.getFormat
});
}
export const cumulativeSumMetricAgg = new MetricAggType({
name: 'cumulative_sum',
title: 'Cumulative Sum',
subtype: parentPipelineAggHelper.subtype,
makeLabel: agg => makeNestedLabel(agg, 'cumulative sum'),
params: [
...parentPipelineAggHelper.params()
],
getFormat: parentPipelineAggHelper.getFormat
});

View file

@ -1,18 +1,14 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper';
import { makeNestedLabel } from './lib/make_nested_label';
export function AggTypesMetricsDerivativeProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'derivative',
title: 'Derivative',
subtype: parentPipelineAggHelper.subtype,
makeLabel: agg => makeNestedLabel(agg, 'derivative'),
params: [
...parentPipelineAggHelper.params()
],
getFormat: parentPipelineAggHelper.getFormat
});
}
export const derivativeMetricAgg = new MetricAggType({
name: 'derivative',
title: 'Derivative',
subtype: parentPipelineAggHelper.subtype,
makeLabel: agg => makeNestedLabel(agg, 'derivative'),
params: [
...parentPipelineAggHelper.params()
],
getFormat: parentPipelineAggHelper.getFormat
});

View file

@ -1,19 +1,15 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
export function AggTypesMetricsGeoBoundsProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'geo_bounds',
title: 'Geo Bounds',
makeLabel: function () {
return 'Geo Bounds';
},
params: [
{
name: 'field',
filterFieldTypes: 'geo_point'
}
]
});
}
export const geoBoundsMetricAgg = new MetricAggType({
name: 'geo_bounds',
title: 'Geo Bounds',
makeLabel: function () {
return 'Geo Bounds';
},
params: [
{
name: 'field',
filterFieldTypes: 'geo_point'
}
]
});

View file

@ -1,22 +1,18 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
export function AggTypesMetricsGeoCentroidProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'geo_centroid',
title: 'Geo Centroid',
makeLabel: function () {
return 'Geo Centroid';
},
params: [
{
name: 'field',
filterFieldTypes: 'geo_point'
}
],
getValue: function (agg, bucket) {
return bucket[agg.id] && bucket[agg.id].location;
export const geoCentroidMetricAgg = new MetricAggType({
name: 'geo_centroid',
title: 'Geo Centroid',
makeLabel: function () {
return 'Geo Centroid';
},
params: [
{
name: 'field',
filterFieldTypes: 'geo_point'
}
});
}
],
getValue: function (agg, bucket) {
return bucket[agg.id] && bucket[agg.id].location;
}
});

View file

@ -1,50 +1,47 @@
import _ from 'lodash';
export function AggTypesMetricsGetResponseAggConfigClassProvider() {
/**
* Get the ResponseAggConfig class for an aggConfig,
* which might be cached on the aggConfig or created.
*
* @param {AggConfig} agg - the AggConfig the VAC should inherit from
* @param {object} props - properties that the VAC should have
* @return {Constructor} - a constructor for VAC objects that will inherit the aggConfig
*/
return function getResponseConfigClass(agg, props) {
if (agg.$$_ResponseAggConfigClass) {
return agg.$$_ResponseAggConfigClass;
} else {
return (agg.$$_ResponseAggConfigClass = create(agg, props));
}
};
function create(parentAgg, props) {
/**
* AggConfig "wrapper" for multi-value metric aggs which
* need to modify AggConfig behavior for each value produced.
*
* @param {string|number} key - the key or index that identifies
* this part of the multi-value
*/
function ResponseAggConfig(key) {
this.key = key;
this.parentId = this.id;
const subId = String(key);
if (subId.indexOf('.') > -1) {
this.id = this.parentId + '[\'' + subId.replace(/'/g, '\\\'') + '\']';
} else {
this.id = this.parentId + '.' + subId;
}
}
ResponseAggConfig.prototype = Object.create(parentAgg, {
constructor: ResponseAggConfig
});
_.assign(ResponseAggConfig.prototype, props);
return ResponseAggConfig;
/**
* Get the ResponseAggConfig class for an aggConfig,
* which might be cached on the aggConfig or created.
*
* @param {AggConfig} agg - the AggConfig the VAC should inherit from
* @param {object} props - properties that the VAC should have
* @return {Constructor} - a constructor for VAC objects that will inherit the aggConfig
*/
export function getResponseAggConfigClass(agg, props) {
if (agg.$$_ResponseAggConfigClass) {
return agg.$$_ResponseAggConfigClass;
} else {
return (agg.$$_ResponseAggConfigClass = create(agg, props));
}
}
function create(parentAgg, props) {
/**
* AggConfig "wrapper" for multi-value metric aggs which
* need to modify AggConfig behavior for each value produced.
*
* @param {string|number} key - the key or index that identifies
* this part of the multi-value
*/
function ResponseAggConfig(key) {
this.key = key;
this.parentId = this.id;
const subId = String(key);
if (subId.indexOf('.') > -1) {
this.id = this.parentId + '[\'' + subId.replace(/'/g, '\\\'') + '\']';
} else {
this.id = this.parentId + '.' + subId;
}
}
ResponseAggConfig.prototype = Object.create(parentAgg, {
constructor: ResponseAggConfig
});
_.assign(ResponseAggConfig.prototype, props);
return ResponseAggConfig;
}

View file

@ -1,19 +1,15 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
export function AggTypesMetricsMaxProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'max',
title: 'Max',
makeLabel: function (aggConfig) {
return 'Max ' + aggConfig.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number,date'
}
]
});
}
export const maxMetricAgg = new MetricAggType({
name: 'max',
title: 'Max',
makeLabel: function (aggConfig) {
return 'Max ' + aggConfig.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number,date'
}
]
});

View file

@ -1,34 +1,28 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { AggTypesMetricsPercentilesProvider } from './percentiles';
import { MetricAggType } from './metric_agg_type';
import { percentilesMetricAgg } from './percentiles';
export function AggTypesMetricsMedianProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
const percentiles = Private(AggTypesMetricsPercentilesProvider);
return new MetricAggType({
name: 'median',
dslName: 'percentiles',
title: 'Median',
makeLabel: function (aggConfig) {
return 'Median ' + aggConfig.getFieldDisplayName();
export const medianMetricAgg = new MetricAggType({
name: 'median',
dslName: 'percentiles',
title: 'Median',
makeLabel: function (aggConfig) {
return 'Median ' + aggConfig.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
},
{
name: 'percents',
default: [50]
},
{
write(agg, output) {
output.params.keyed = false;
}
{
name: 'percents',
default: [50]
},
{
write(agg, output) {
output.params.keyed = false;
}
],
getResponseAggs: percentiles.getResponseAggs,
getValue: percentiles.getValue
});
}
}
],
getResponseAggs: percentilesMetricAgg.getResponseAggs,
getValue: percentilesMetricAgg.getValue
});

View file

@ -1,60 +1,55 @@
import _ from 'lodash';
import { AggTypesAggTypeProvider } from '../agg_type';
import { AggType } from '../agg_type';
import { fieldFormats } from '../../registry/field_formats';
import { createLegacyClass } from '../../utils/legacy_class';
export function AggTypesMetricsMetricAggTypeProvider(Private) {
const AggType = Private(AggTypesAggTypeProvider);
createLegacyClass(MetricAggType).inherits(AggType);
function MetricAggType(config) {
MetricAggType.Super.call(this, config);
createLegacyClass(MetricAggType).inherits(AggType);
function MetricAggType(config) {
MetricAggType.Super.call(this, config);
// allow overriding any value on the prototype
_.forOwn(config, function (val, key) {
if (_.has(MetricAggType.prototype, key)) {
this[key] = val;
}
}, this);
}
MetricAggType.prototype.subtype = 'Metric Aggregations';
/**
* Read the values for this metric from the
* @param {[type]} bucket [description]
* @return {*} [description]
*/
MetricAggType.prototype.getValue = function (agg, bucket) {
// Metric types where an empty set equals `zero`
const isSettableToZero = ['cardinality', 'sum'].indexOf(agg.__type.name) !== -1;
// Return proper values when no buckets are present
// `Count` handles empty sets properly
if (!bucket[agg.id] && isSettableToZero) return 0;
return bucket[agg.id] && bucket[agg.id].value;
};
/**
* Pick a format for the values produced by this agg type,
* overriden by several metrics that always output a simple
* number
*
* @param {agg} agg - the agg to pick a format for
* @return {FieldFromat}
*/
MetricAggType.prototype.getFormat = function (agg) {
const field = agg.getField();
return field ? field.format : fieldFormats.getDefaultInstance('number');
};
/**
* Determines if this metric can be scaled
*/
MetricAggType.prototype.isScalable = function () {
return false;
};
return MetricAggType;
// allow overriding any value on the prototype
_.forOwn(config, function (val, key) {
if (_.has(MetricAggType.prototype, key)) {
this[key] = val;
}
}, this);
}
MetricAggType.prototype.subtype = 'Metric Aggregations';
/**
* Read the values for this metric from the
* @param {[type]} bucket [description]
* @return {*} [description]
*/
MetricAggType.prototype.getValue = function (agg, bucket) {
// Metric types where an empty set equals `zero`
const isSettableToZero = ['cardinality', 'sum'].indexOf(agg.__type.name) !== -1;
// Return proper values when no buckets are present
// `Count` handles empty sets properly
if (!bucket[agg.id] && isSettableToZero) return 0;
return bucket[agg.id] && bucket[agg.id].value;
};
/**
* Pick a format for the values produced by this agg type,
* overriden by several metrics that always output a simple
* number
*
* @param {agg} agg - the agg to pick a format for
* @return {FieldFromat}
*/
MetricAggType.prototype.getFormat = function (agg) {
const field = agg.getField();
return field ? field.format : fieldFormats.getDefaultInstance('number');
};
/**
* Determines if this metric can be scaled
*/
MetricAggType.prototype.isScalable = function () {
return false;
};
export { MetricAggType };

View file

@ -1,19 +1,15 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
export function AggTypesMetricsMinProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'min',
title: 'Min',
makeLabel: function (aggConfig) {
return 'Min ' + aggConfig.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number,date'
}
]
});
}
export const minMetricAgg = new MetricAggType({
name: 'min',
title: 'Min',
makeLabel: function (aggConfig) {
return 'Min ' + aggConfig.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number,date'
}
]
});

View file

@ -1,18 +1,14 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper';
import { makeNestedLabel } from './lib/make_nested_label';
export function AggTypesMetricsMovingAvgProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'moving_avg',
title: 'Moving Avg',
subtype: parentPipelineAggHelper.subtype,
makeLabel: agg => makeNestedLabel(agg, 'moving avg'),
params: [
...parentPipelineAggHelper.params()
],
getFormat: parentPipelineAggHelper.getFormat
});
}
export const movingAvgMetricAgg = new MetricAggType({
name: 'moving_avg',
title: 'Moving Avg',
subtype: parentPipelineAggHelper.subtype,
makeLabel: agg => makeNestedLabel(agg, 'moving avg'),
params: [
...parentPipelineAggHelper.params()
],
getFormat: parentPipelineAggHelper.getFormat
});

View file

@ -1,61 +1,56 @@
import valuesEditor from '../controls/percentile_ranks.html';
import '../../number_list';
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { AggTypesMetricsGetResponseAggConfigClassProvider } from './get_response_agg_config_class';
import { MetricAggType } from './metric_agg_type';
import { getResponseAggConfigClass } from './get_response_agg_config_class';
import { fieldFormats } from '../../registry/field_formats';
import { getPercentileValue } from './percentiles_get_value';
export function AggTypesMetricsPercentileRanksProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
const getResponseAggConfigClass = Private(AggTypesMetricsGetResponseAggConfigClassProvider);
// required by the values editor
// required by the values editor
const valueProps = {
makeLabel: function () {
const field = this.getField();
const format = (field && field.format) || fieldFormats.getDefaultInstance('number');
const label = this.params.customLabel || this.getFieldDisplayName();
const valueProps = {
makeLabel: function () {
const field = this.getField();
const format = (field && field.format) || fieldFormats.getDefaultInstance('number');
const label = this.params.customLabel || this.getFieldDisplayName();
return 'Percentile rank ' + format.convert(this.key, 'text') + ' of "' + label + '"';
}
};
return 'Percentile rank ' + format.convert(this.key, 'text') + ' of "' + label + '"';
}
};
return new MetricAggType({
name: 'percentile_ranks',
title: 'Percentile Ranks',
makeLabel: function (agg) {
return 'Percentile ranks of ' + agg.getFieldDisplayName();
export const percentileRanksMetricAgg = new MetricAggType({
name: 'percentile_ranks',
title: 'Percentile Ranks',
makeLabel: function (agg) {
return 'Percentile ranks of ' + agg.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
},
{
name: 'values',
editor: valuesEditor,
default: []
},
{
write(agg, output) {
output.params.keyed = false;
}
{
name: 'values',
editor: valuesEditor,
default: []
},
{
write(agg, output) {
output.params.keyed = false;
}
],
getResponseAggs: function (agg) {
const ValueAggConfig = getResponseAggConfigClass(agg, valueProps);
return agg.params.values.map(function (value) {
return new ValueAggConfig(value);
});
},
getFormat: function () {
return fieldFormats.getInstance('percent') || fieldFormats.getDefaultInstance('number');
},
getValue: function (agg, bucket) {
return getPercentileValue(agg, bucket) / 100;
}
});
}
],
getResponseAggs: function (agg) {
const ValueAggConfig = getResponseAggConfigClass(agg, valueProps);
return agg.params.values.map(function (value) {
return new ValueAggConfig(value);
});
},
getFormat: function () {
return fieldFormats.getInstance('percent') || fieldFormats.getDefaultInstance('number');
},
getValue: function (agg, bucket) {
return getPercentileValue(agg, bucket) / 100;
}
});

View file

@ -1,52 +1,45 @@
import { ordinalSuffix } from '../../utils/ordinal_suffix';
import percentsEditor from '../controls/percentiles.html';
import '../../number_list';
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { AggTypesMetricsGetResponseAggConfigClassProvider } from './get_response_agg_config_class';
import { MetricAggType } from './metric_agg_type';
import { getResponseAggConfigClass } from './get_response_agg_config_class';
import { getPercentileValue } from './percentiles_get_value';
export function AggTypesMetricsPercentilesProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
const getResponseAggConfigClass = Private(AggTypesMetricsGetResponseAggConfigClassProvider);
const valueProps = {
makeLabel: function () {
const label = this.params.customLabel || this.getFieldDisplayName();
return ordinalSuffix(this.key) + ' percentile of ' + label;
}
};
// required by the percentiles editor
const valueProps = {
makeLabel: function () {
const label = this.params.customLabel || this.getFieldDisplayName();
return ordinalSuffix(this.key) + ' percentile of ' + label;
}
};
return new MetricAggType({
name: 'percentiles',
title: 'Percentiles',
makeLabel: function (agg) {
return 'Percentiles of ' + agg.getFieldDisplayName();
export const percentilesMetricAgg = new MetricAggType({
name: 'percentiles',
title: 'Percentiles',
makeLabel: function (agg) {
return 'Percentiles of ' + agg.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
},
{
name: 'percents',
editor: percentsEditor,
default: [1, 5, 25, 50, 75, 95, 99]
},
{
write(agg, output) {
output.params.keyed = false;
}
{
name: 'percents',
editor: percentsEditor,
default: [1, 5, 25, 50, 75, 95, 99]
},
{
write(agg, output) {
output.params.keyed = false;
}
],
getResponseAggs: function (agg) {
const ValueAggConfig = getResponseAggConfigClass(agg, valueProps);
}
],
getResponseAggs: function (agg) {
const ValueAggConfig = getResponseAggConfigClass(agg, valueProps);
return agg.params.percents.map(function (percent) {
return new ValueAggConfig(percent);
});
},
getValue: getPercentileValue
});
}
return agg.params.percents.map(function (percent) {
return new ValueAggConfig(percent);
});
},
getValue: getPercentileValue
});

View file

@ -1,18 +1,14 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper';
import { makeNestedLabel } from './lib/make_nested_label';
export function AggTypesMetricsSerialDiffProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'serial_diff',
title: 'Serial Diff',
subtype: parentPipelineAggHelper.subtype,
makeLabel: agg => makeNestedLabel(agg, 'serial diff'),
params: [
...parentPipelineAggHelper.params()
],
getFormat: parentPipelineAggHelper.getFormat
});
}
export const serialDiffMetricAgg = new MetricAggType({
name: 'serial_diff',
title: 'Serial Diff',
subtype: parentPipelineAggHelper.subtype,
makeLabel: agg => makeNestedLabel(agg, 'serial diff'),
params: [
...parentPipelineAggHelper.params()
],
getFormat: parentPipelineAggHelper.getFormat
});

View file

@ -1,61 +1,56 @@
import _ from 'lodash';
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { AggTypesMetricsGetResponseAggConfigClassProvider } from './get_response_agg_config_class';
import { MetricAggType } from './metric_agg_type';
import { getResponseAggConfigClass } from './get_response_agg_config_class';
export function AggTypesMetricsStdDeviationProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
const getResponseAggConfigClass = Private(AggTypesMetricsGetResponseAggConfigClassProvider);
const responseAggConfigProps = {
valProp: function () {
const details = this.keyedDetails(this.params.customLabel)[this.key];
return details.valProp;
},
makeLabel: function () {
const fieldDisplayName = this.getFieldDisplayName();
const details = this.keyedDetails(this.params.customLabel, fieldDisplayName);
return _.get(details, [this.key, 'title']);
},
keyedDetails: function (customLabel, fieldDisplayName) {
const label = customLabel ? customLabel : 'Standard Deviation of ' + fieldDisplayName;
return {
std_lower: {
valProp: ['std_deviation_bounds', 'lower'],
title: 'Lower ' + label
},
std_upper: {
valProp: ['std_deviation_bounds', 'upper'],
title: 'Upper ' + label
}
};
}
};
return new MetricAggType({
name: 'std_dev',
dslName: 'extended_stats',
title: 'Standard Deviation',
makeLabel: function (agg) {
return 'Standard Deviation of ' + agg.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
const responseAggConfigProps = {
valProp: function () {
const details = this.keyedDetails(this.params.customLabel)[this.key];
return details.valProp;
},
makeLabel: function () {
const fieldDisplayName = this.getFieldDisplayName();
const details = this.keyedDetails(this.params.customLabel, fieldDisplayName);
return _.get(details, [this.key, 'title']);
},
keyedDetails: function (customLabel, fieldDisplayName) {
const label = customLabel ? customLabel : 'Standard Deviation of ' + fieldDisplayName;
return {
std_lower: {
valProp: ['std_deviation_bounds', 'lower'],
title: 'Lower ' + label
},
std_upper: {
valProp: ['std_deviation_bounds', 'upper'],
title: 'Upper ' + label
}
],
};
}
};
getResponseAggs: function (agg) {
const ValueAggConfig = getResponseAggConfigClass(agg, responseAggConfigProps);
return [
new ValueAggConfig('std_lower'),
new ValueAggConfig('std_upper')
];
},
getValue: function (agg, bucket) {
return _.get(bucket[agg.parentId], agg.valProp());
export const stdDeviationMetricAgg = new MetricAggType({
name: 'std_dev',
dslName: 'extended_stats',
title: 'Standard Deviation',
makeLabel: function (agg) {
return 'Standard Deviation of ' + agg.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
}
});
}
],
getResponseAggs: function (agg) {
const ValueAggConfig = getResponseAggConfigClass(agg, responseAggConfigProps);
return [
new ValueAggConfig('std_lower'),
new ValueAggConfig('std_upper')
];
},
getValue: function (agg, bucket) {
return _.get(bucket[agg.parentId], agg.valProp());
}
});

View file

@ -1,22 +1,18 @@
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
export function AggTypesMetricsSumProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
return new MetricAggType({
name: 'sum',
title: 'Sum',
makeLabel: function (aggConfig) {
return 'Sum of ' + aggConfig.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
}
],
isScalable: function () {
return true;
export const sumMetricAgg = new MetricAggType({
name: 'sum',
title: 'Sum',
makeLabel: function (aggConfig) {
return 'Sum of ' + aggConfig.getFieldDisplayName();
},
params: [
{
name: 'field',
filterFieldTypes: 'number'
}
});
}
],
isScalable: function () {
return true;
}
});

View file

@ -1,201 +1,197 @@
import _ from 'lodash';
import { AggTypesMetricsMetricAggTypeProvider } from './metric_agg_type';
import { MetricAggType } from './metric_agg_type';
import topSortEditor from '../controls/top_sort.html';
import aggregateAndSizeEditor from '../controls/top_aggregate_and_size.html';
export function AggTypesMetricsTopHitProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
const isNumber = function (type) {
return type === 'number';
};
const isNumber = function (type) {
return type === 'number';
};
export const topHitMetricAgg = new MetricAggType({
name: 'top_hits',
title: 'Top Hit',
makeLabel: function (aggConfig) {
let prefix = aggConfig.params.sortOrder.val === 'desc' ? 'Last' : 'First';
if (aggConfig.params.size !== 1) {
prefix += ` ${aggConfig.params.size}`;
}
const field = aggConfig.params.field;
return `${prefix} ${field ? field.displayName : ''}`;
},
params: [
{
name: 'field',
onlyAggregatable: false,
filterFieldTypes: function (vis, value) {
if (vis.type.name === 'table' || vis.type.name === 'metric') {
return true;
}
return value === 'number';
},
write(agg, output) {
const field = agg.params.field;
output.params = {};
return new MetricAggType({
name: 'top_hits',
title: 'Top Hit',
makeLabel: function (aggConfig) {
let prefix = aggConfig.params.sortOrder.val === 'desc' ? 'Last' : 'First';
if (aggConfig.params.size !== 1) {
prefix += ` ${aggConfig.params.size}`;
if (field.scripted) {
output.params.script_fields = {
[ field.name ]: {
script: {
inline: field.script,
lang: field.lang
}
}
};
} else {
if (field.readFromDocValues) {
output.params.docvalue_fields = [ field.name ];
}
output.params._source = field.name === '_source' ? true : field.name;
}
}
const field = aggConfig.params.field;
return `${prefix} ${field ? field.displayName : ''}`;
},
params: [
{
name: 'field',
onlyAggregatable: false,
filterFieldTypes: function (vis, value) {
if (vis.type.name === 'table' || vis.type.name === 'metric') {
return true;
}
return value === 'number';
{
name: 'aggregate',
type: 'optioned',
editor: aggregateAndSizeEditor,
options: [
{
display: 'Min',
isCompatibleType: isNumber,
isCompatibleVis: _.constant(true),
disabled: true,
val: 'min'
},
write(agg, output) {
const field = agg.params.field;
output.params = {};
if (field.scripted) {
output.params.script_fields = {
[ field.name ]: {
script: {
inline: field.script,
lang: field.lang
}
}
};
} else {
if (field.readFromDocValues) {
output.params.docvalue_fields = [ field.name ];
}
output.params._source = field.name === '_source' ? true : field.name;
}
{
display: 'Max',
isCompatibleType: isNumber,
isCompatibleVis: _.constant(true),
disabled: true,
val: 'max'
},
{
display: 'Sum',
isCompatibleType: isNumber,
isCompatibleVis: _.constant(true),
disabled: true,
val: 'sum'
},
{
display: 'Average',
isCompatibleType: isNumber,
isCompatibleVis: _.constant(true),
disabled: true,
val: 'average'
},
{
display: 'Concatenate',
isCompatibleType: _.constant(true),
isCompatibleVis: function (name) {
return name === 'metric' || name === 'table';
},
disabled: true,
val: 'concat'
}
},
{
name: 'aggregate',
type: 'optioned',
editor: aggregateAndSizeEditor,
options: [
{
display: 'Min',
isCompatibleType: isNumber,
isCompatibleVis: _.constant(true),
disabled: true,
val: 'min'
},
{
display: 'Max',
isCompatibleType: isNumber,
isCompatibleVis: _.constant(true),
disabled: true,
val: 'max'
},
{
display: 'Sum',
isCompatibleType: isNumber,
isCompatibleVis: _.constant(true),
disabled: true,
val: 'sum'
},
{
display: 'Average',
isCompatibleType: isNumber,
isCompatibleVis: _.constant(true),
disabled: true,
val: 'average'
},
{
display: 'Concatenate',
isCompatibleType: _.constant(true),
isCompatibleVis: function (name) {
return name === 'metric' || name === 'table';
},
disabled: true,
val: 'concat'
],
controller: function ($scope) {
$scope.options = [];
$scope.$watchGroup([ 'agg.vis.type.name', 'agg.params.field.type' ], function ([ visName, fieldType ]) {
if (fieldType && visName) {
$scope.options = _.filter($scope.aggParam.options, option => {
return option.isCompatibleVis(visName) && option.isCompatibleType(fieldType);
});
if ($scope.options.length === 1) {
$scope.agg.params.aggregate = $scope.options[0];
}
}
],
controller: function ($scope) {
$scope.options = [];
$scope.$watchGroup([ 'agg.vis.type.name', 'agg.params.field.type' ], function ([ visName, fieldType ]) {
if (fieldType && visName) {
$scope.options = _.filter($scope.aggParam.options, option => {
return option.isCompatibleVis(visName) && option.isCompatibleType(fieldType);
});
if ($scope.options.length === 1) {
$scope.agg.params.aggregate = $scope.options[0];
});
},
write: _.noop
},
{
name: 'size',
editor: null, // size setting is done together with the aggregation setting
default: 1
},
{
name: 'sortField',
type: 'field',
editor: null,
filterFieldTypes: [ 'number', 'date', 'ip', 'string' ],
default: function (agg) {
return agg.vis.indexPattern.timeFieldName;
},
write: _.noop // prevent default write, it is handled below
},
{
name: 'sortOrder',
type: 'optioned',
default: 'desc',
editor: topSortEditor,
options: [
{ display: 'Descending', val: 'desc' },
{ display: 'Ascending', val: 'asc' }
],
write(agg, output) {
const sortField = agg.params.sortField;
const sortOrder = agg.params.sortOrder;
if (sortField.scripted) {
output.params.sort = [
{
_script: {
script: {
inline: sortField.script,
lang: sortField.lang
},
type: sortField.type,
order: sortOrder.val
}
}
});
},
write: _.noop
},
{
name: 'size',
editor: null, // size setting is done together with the aggregation setting
default: 1
},
{
name: 'sortField',
type: 'field',
editor: null,
filterFieldTypes: [ 'number', 'date', 'ip', 'string' ],
default: function (agg) {
return agg.vis.indexPattern.timeFieldName;
},
write: _.noop // prevent default write, it is handled below
},
{
name: 'sortOrder',
type: 'optioned',
default: 'desc',
editor: topSortEditor,
options: [
{ display: 'Descending', val: 'desc' },
{ display: 'Ascending', val: 'asc' }
],
write(agg, output) {
const sortField = agg.params.sortField;
const sortOrder = agg.params.sortOrder;
if (sortField.scripted) {
output.params.sort = [
{
_script: {
script: {
inline: sortField.script,
lang: sortField.lang
},
type: sortField.type,
order: sortOrder.val
}
];
} else {
output.params.sort = [
{
[ sortField.name ]: {
order: sortOrder.val
}
];
} else {
output.params.sort = [
{
[ sortField.name ]: {
order: sortOrder.val
}
}
];
}
}
];
}
}
],
getValue(agg, bucket) {
const hits = _.get(bucket, `${agg.id}.hits.hits`);
if (!hits || !hits.length) {
}
],
getValue(agg, bucket) {
const hits = _.get(bucket, `${agg.id}.hits.hits`);
if (!hits || !hits.length) {
return null;
}
const path = agg.params.field.name;
let values = _(hits).map(hit => {
return path === '_source' ? hit._source : agg.vis.indexPattern.flattenHit(hit, true)[path];
})
.flatten()
.value();
if (values.length === 1) {
values = values[0];
}
if (Array.isArray(values)) {
if (!_.compact(values).length) {
return null;
}
const path = agg.params.field.name;
let values = _(hits).map(hit => {
return path === '_source' ? hit._source : agg.vis.indexPattern.flattenHit(hit, true)[path];
})
.flatten()
.value();
if (values.length === 1) {
values = values[0];
switch (agg.params.aggregate.val) {
case 'max':
return _.max(values);
case 'min':
return _.min(values);
case 'sum':
return _.sum(values);
case 'average':
return _.sum(values) / values.length;
}
if (Array.isArray(values)) {
if (!_.compact(values).length) {
return null;
}
switch (agg.params.aggregate.val) {
case 'max':
return _.max(values);
case 'min':
return _.min(values);
case 'sum':
return _.sum(values);
case 'average':
return _.sum(values) / values.length;
}
}
return values;
}
});
}
return values;
}
});

View file

@ -24,6 +24,7 @@ describe('Config service', () => {
config.getAll();
sinon.assert.calledOnce(uiSettings.getAll);
sinon.assert.calledWithExactly(uiSettings.getAll);
uiSettings.getAll.restore();
});
});
@ -33,6 +34,7 @@ describe('Config service', () => {
config.get('key', 'default');
sinon.assert.calledOnce(uiSettings.get);
sinon.assert.calledWithExactly(uiSettings.get, 'key', 'default');
uiSettings.get.restore();
});
});
@ -42,6 +44,7 @@ describe('Config service', () => {
config.isDeclared('key');
sinon.assert.calledOnce(uiSettings.isDeclared);
sinon.assert.calledWithExactly(uiSettings.isDeclared, 'key');
uiSettings.isDeclared.restore();
});
});
@ -51,6 +54,7 @@ describe('Config service', () => {
config.isDefault('key');
sinon.assert.calledOnce(uiSettings.isDefault);
sinon.assert.calledWithExactly(uiSettings.isDefault, 'key');
uiSettings.isDefault.restore();
});
});
@ -69,6 +73,7 @@ describe('Config service', () => {
config.remove('foobar');
sinon.assert.calledOnce(uiSettings.remove);
sinon.assert.calledWithExactly(uiSettings.remove, 'foobar');
uiSettings.remove.restore();
});
it('returns an angular promise', () => {

View file

@ -1,36 +1,17 @@
import expect from 'expect.js';
import ngMock from 'ng_mock';
import { DecorateQueryProvider } from '../_decorate_query';
import chrome from 'ui/chrome';
import { decorateQuery } from '../_decorate_query';
const config = chrome.getUiSettingsClient();
describe('Query decorator', function () {
let config;
let fn;
beforeEach(ngMock.module(
'kibana',
function ($provide) {
// Super simple config stub
$provide.service('config', function () {
const keys = {};
return {
get: function (key) { return keys[key]; },
set: function (key, value) { keys[key] = value; }
};
});
}
));
beforeEach(ngMock.inject(function (Private, $injector, _config_) {
config = _config_;
fn = Private(DecorateQueryProvider);
}));
it('should be a function', function () {
expect(fn).to.be.a(Function);
expect(decorateQuery).to.be.a(Function);
});
it('should merge in the query string options', function () {
config.set('query:queryString:options', { analyze_wildcard: true });
expect(fn({ query_string: { query: '*' } })).to.eql({ query_string: { query: '*', analyze_wildcard: true } });
const decoratedQuery = decorateQuery({ query_string: { query: '*' } });
expect(decoratedQuery).to.eql({ query_string: { query: '*', analyze_wildcard: true } });
});
});

View file

@ -1,18 +1,19 @@
import _ from 'lodash';
import chrome from 'ui/chrome';
export function DecorateQueryProvider(config) {
/**
* Decorate queries with default parameters
* @param {query} query object
* @returns {object}
*/
return function (query) {
const queryOptions = config.get('query:queryString:options');
const config = chrome.getUiSettingsClient();
if (_.has(query, 'query_string.query')) {
_.extend(query.query_string, queryOptions);
}
/**
* Decorate queries with default parameters
* @param {query} query object
* @returns {object}
*/
export function decorateQuery(query) {
const queryOptions = config.get('query:queryString:options');
return query;
};
if (_.has(query, 'query_string.query')) {
_.extend(query.query_string, queryOptions);
}
return query;
}

View file

@ -4,11 +4,10 @@ import ngMock from 'ng_mock';
import { expectDeepEqual } from '../../../../../../test_utils/expect_deep_equal.js';
import { fromKueryExpression, toElasticsearchQuery } from '../../../../kuery';
import { luceneStringToDsl } from '../lucene_string_to_dsl';
import { DecorateQueryProvider } from '../../_decorate_query';
import { decorateQuery } from '../../_decorate_query';
let indexPattern;
let buildEsQuery;
let decorateQuery;
describe('build query', function () {
@ -18,7 +17,6 @@ describe('build query', function () {
beforeEach(ngMock.inject(function (Private) {
indexPattern = Private(StubbedLogstashIndexPatternProvider);
buildEsQuery = Private(BuildESQueryProvider);
decorateQuery = Private(DecorateQueryProvider);
}));
it('should return the parameters of an Elasticsearch bool query', function () {

View file

@ -1,19 +1,11 @@
import { buildQueryFromFilters } from '../from_filters';
import { DecorateQueryProvider } from '../../_decorate_query.js';
import ngMock from 'ng_mock';
import { decorateQuery } from '../../_decorate_query.js';
import { expectDeepEqual } from '../../../../../../test_utils/expect_deep_equal.js';
let decorateQuery;
describe('build query', function () {
describe('buildQueryFromFilters', function () {
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
decorateQuery = Private(DecorateQueryProvider);
}));
it('should return the parameters of an Elasticsearch bool query', function () {
const result = buildQueryFromFilters([]);
const expected = {

View file

@ -1,20 +1,13 @@
import { buildQueryFromLucene } from '../from_lucene';
import { DecorateQueryProvider } from '../../_decorate_query.js';
import ngMock from 'ng_mock';
import { decorateQuery } from '../../_decorate_query.js';
import { expectDeepEqual } from '../../../../../../test_utils/expect_deep_equal.js';
import { luceneStringToDsl } from '../lucene_string_to_dsl';
let decorateQuery;
describe('build query', function () {
describe('buildQueryFromLucene', function () {
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
decorateQuery = Private(DecorateQueryProvider);
}));
it('should return the parameters of an Elasticsearch bool query', function () {
const result = buildQueryFromLucene();
const expected = {

View file

@ -1,11 +1,10 @@
import { groupBy, has } from 'lodash';
import { DecorateQueryProvider } from '../_decorate_query';
import { decorateQuery } from '../_decorate_query';
import { buildQueryFromKuery } from './from_kuery';
import { buildQueryFromFilters } from './from_filters';
import { buildQueryFromLucene } from './from_lucene';
export function BuildESQueryProvider(Private, config) {
const decorateQuery = Private(DecorateQueryProvider);
export function BuildESQueryProvider(config) {
/**
*

View file

@ -1,71 +1,69 @@
import moment from 'moment';
const { duration: d } = moment;
export function TimeBucketsCalcAutoIntervalProvider() {
// these are the rounding rules used by roundInterval()
// these are the rounding rules used by roundInterval()
const roundingRules = [
[ d(500, 'ms'), d(100, 'ms') ],
[ d(5, 'second'), d(1, 'second') ],
[ d(7.5, 'second'), d(5, 'second') ],
[ d(15, 'second'), d(10, 'second') ],
[ d(45, 'second'), d(30, 'second') ],
[ d(3, 'minute'), d(1, 'minute') ],
[ d(9, 'minute'), d(5, 'minute') ],
[ d(20, 'minute'), d(10, 'minute') ],
[ d(45, 'minute'), d(30, 'minute') ],
[ d(2, 'hour'), d(1, 'hour') ],
[ d(6, 'hour'), d(3, 'hour') ],
[ d(24, 'hour'), d(12, 'hour') ],
[ d(1, 'week'), d(1, 'd') ],
[ d(3, 'week'), d(1, 'week') ],
[ d(1, 'year'), d(1, 'month') ],
[ Infinity, d(1, 'year') ]
];
const roundingRules = [
[ d(500, 'ms'), d(100, 'ms') ],
[ d(5, 'second'), d(1, 'second') ],
[ d(7.5, 'second'), d(5, 'second') ],
[ d(15, 'second'), d(10, 'second') ],
[ d(45, 'second'), d(30, 'second') ],
[ d(3, 'minute'), d(1, 'minute') ],
[ d(9, 'minute'), d(5, 'minute') ],
[ d(20, 'minute'), d(10, 'minute') ],
[ d(45, 'minute'), d(30, 'minute') ],
[ d(2, 'hour'), d(1, 'hour') ],
[ d(6, 'hour'), d(3, 'hour') ],
[ d(24, 'hour'), d(12, 'hour') ],
[ d(1, 'week'), d(1, 'd') ],
[ d(3, 'week'), d(1, 'week') ],
[ d(1, 'year'), d(1, 'month') ],
[ Infinity, d(1, 'year') ]
];
const revRoundingRules = roundingRules.slice(0).reverse();
const revRoundingRules = roundingRules.slice(0).reverse();
function find(rules, check, last) {
function pick(buckets, duration) {
const target = duration / buckets;
let lastResp;
function find(rules, check, last) {
function pick(buckets, duration) {
const target = duration / buckets;
let lastResp;
for (let i = 0; i < rules.length; i++) {
const rule = rules[i];
const resp = check(rule[0], rule[1], target);
for (let i = 0; i < rules.length; i++) {
const rule = rules[i];
const resp = check(rule[0], rule[1], target);
if (resp == null) {
if (!last) continue;
if (lastResp) return lastResp;
break;
}
if (!last) return resp;
lastResp = resp;
if (resp == null) {
if (!last) continue;
if (lastResp) return lastResp;
break;
}
// fallback to just a number of milliseconds, ensure ms is >= 1
const ms = Math.max(Math.floor(target), 1);
return moment.duration(ms, 'ms');
if (!last) return resp;
lastResp = resp;
}
return function (buckets, duration) {
const interval = pick(buckets, duration);
if (interval) return moment.duration(interval._data);
};
// fallback to just a number of milliseconds, ensure ms is >= 1
const ms = Math.max(Math.floor(target), 1);
return moment.duration(ms, 'ms');
}
return {
near: find(revRoundingRules, function near(bound, interval, target) {
if (bound > target) return interval;
}, true),
lessThan: find(revRoundingRules, function (bound, interval, target) {
if (interval < target) return interval;
}),
atLeast: find(revRoundingRules, function atLeast(bound, interval, target) {
if (interval <= target) return interval;
}),
return function (buckets, duration) {
const interval = pick(buckets, duration);
if (interval) return moment.duration(interval._data);
};
}
export const calcAutoInterval = {
near: find(revRoundingRules, function near(bound, interval, target) {
if (bound > target) return interval;
}, true),
lessThan: find(revRoundingRules, function (bound, interval, target) {
if (interval < target) return interval;
}),
atLeast: find(revRoundingRules, function atLeast(bound, interval, target) {
if (interval <= target) return interval;
}),
};

View file

@ -1,48 +1,42 @@
import dateMath from '@kbn/datemath';
export function TimeBucketsCalcEsIntervalProvider() {
const unitsDesc = dateMath.unitsDesc;
const largeMax = unitsDesc.indexOf('M');
const unitsDesc = dateMath.unitsDesc;
const largeMax = unitsDesc.indexOf('M');
/**
* Convert a moment.duration into an es
* compatible expression, and provide
* associated metadata
*
* @param {moment.duration} duration
* @return {object}
*/
export function calcEsInterval(duration) {
for (let i = 0; i < unitsDesc.length; i++) {
const unit = unitsDesc[i];
const val = duration.as(unit);
// find a unit that rounds neatly
if (val >= 1 && Math.floor(val) === val) {
/**
* Convert a moment.duration into an es
* compatible expression, and provide
* associated metadata
*
* @param {moment.duration} duration
* @return {object}
*/
function esDuration(duration) {
for (let i = 0; i < unitsDesc.length; i++) {
const unit = unitsDesc[i];
const val = duration.as(unit);
// find a unit that rounds neatly
if (val >= 1 && Math.floor(val) === val) {
// if the unit is "large", like years, but
// isn't set to 1 ES will puke. So keep going until
// we get out of the "large" units
if (i <= largeMax && val !== 1) {
continue;
}
return {
value: val,
unit: unit,
expression: val + unit
};
// if the unit is "large", like years, but
// isn't set to 1 ES will puke. So keep going until
// we get out of the "large" units
if (i <= largeMax && val !== 1) {
continue;
}
}
const ms = duration.as('ms');
return {
value: ms,
unit: 'ms',
expression: ms + 'ms'
};
return {
value: val,
unit: unit,
expression: val + unit
};
}
}
return esDuration;
const ms = duration.as('ms');
return {
value: ms,
unit: 'ms',
expression: ms + 'ms'
};
}

View file

@ -1 +1 @@
export { TimeBucketsProvider } from './time_buckets';
export { TimeBuckets } from './time_buckets';

View file

@ -1,380 +1,377 @@
import _ from 'lodash';
import moment from 'moment';
import chrome from 'ui/chrome';
import { parseInterval } from '../utils/parse_interval';
import { TimeBucketsCalcAutoIntervalProvider } from './calc_auto_interval';
import { TimeBucketsCalcEsIntervalProvider } from './calc_es_interval';
import { calcAutoInterval } from './calc_auto_interval';
import { calcEsInterval } from './calc_es_interval';
import { fieldFormats } from '../registry/field_formats';
export function TimeBucketsProvider(Private, timefilter, config) {
const calcAuto = Private(TimeBucketsCalcAutoIntervalProvider);
const calcEsInterval = Private(TimeBucketsCalcEsIntervalProvider);
const config = chrome.getUiSettingsClient();
const getConfig = (...args) => config.get(...args);
const getConfig = (...args) => config.get(...args);
function isValidMoment(m) {
return m && ('isValid' in m) && m.isValid();
}
/**
* Helper class for wrapping the concept of an "Interval",
* which describes a timespan that will seperate moments.
*
* @param {state} object - one of ""
* @param {[type]} display [description]
*/
function TimeBuckets() {
return TimeBuckets.__cached__(this);
}
/****
* PUBLIC API
****/
/**
* Set the bounds that these buckets are expected to cover.
* This is required to support interval "auto" as well
* as interval scaling.
*
* @param {object} input - an object with properties min and max,
* representing the edges for the time span
* we should cover
*
* @returns {undefined}
*/
TimeBuckets.prototype.setBounds = function (input) {
if (!input) return this.clearBounds();
let bounds;
if (_.isPlainObject(input)) {
// accept the response from timefilter.getActiveBounds()
bounds = [input.min, input.max];
} else {
bounds = Array.isArray(input) ? input : [];
}
const moments = _(bounds)
.map(_.ary(moment, 1))
.sortBy(Number);
const valid = moments.size() === 2 && moments.every(isValidMoment);
if (!valid) {
this.clearBounds();
throw new Error('invalid bounds set: ' + input);
}
this._lb = moments.shift();
this._ub = moments.pop();
if (this.getDuration().asSeconds() < 0) {
throw new TypeError('Intervals must be positive');
}
};
/**
* Clear the stored bounds
*
* @return {undefined}
*/
TimeBuckets.prototype.clearBounds = function () {
this._lb = this._ub = null;
};
/**
* Check to see if we have received bounds yet
*
* @return {Boolean}
*/
TimeBuckets.prototype.hasBounds = function () {
return isValidMoment(this._ub) && isValidMoment(this._lb);
};
/**
* Return the current bounds, if we have any.
*
* THIS DOES NOT CLONE THE BOUNDS, so editing them
* may have unexpected side-effects. Always
* call bounds.min.clone() before editing
*
* @return {object|undefined} - If bounds are not defined, this
* returns undefined, else it returns the bounds
* for these buckets. This object has two props,
* min and max. Each property will be a moment()
* object
*
*/
TimeBuckets.prototype.getBounds = function () {
if (!this.hasBounds()) return;
return {
min: this._lb,
max: this._ub
};
};
/**
* Get a moment duration object representing
* the distance between the bounds, if the bounds
* are set.
*
* @return {moment.duration|undefined}
*/
TimeBuckets.prototype.getDuration = function () {
if (!this.hasBounds()) return;
return moment.duration(this._ub - this._lb, 'ms');
};
/**
* Update the interval at which buckets should be
* generated.
*
* Input can be one of the following:
* - Any object from src/ui/agg_types/buckets/_interval_options.js
* - "auto"
* - Pass a valid moment unit
* - a moment.duration object.
*
* @param {object|string|moment.duration} input - see desc
*/
TimeBuckets.prototype.setInterval = function (input) {
let interval = input;
// selection object -> val
if (_.isObject(input)) {
interval = input.val;
}
if (!interval || interval === 'auto') {
this._i = 'auto';
return;
}
if (_.isString(interval)) {
input = interval;
interval = parseInterval(interval);
if (+interval === 0) {
interval = null;
}
}
// if the value wasn't converted to a duration, and isn't
// already a duration, we have a problem
if (!moment.isDuration(interval)) {
throw new TypeError('"' + input + '" is not a valid interval.');
}
this._i = interval;
};
/**
* Get the interval for the buckets. If the
* number of buckets created by the interval set
* is larger than config:histogram:maxBars then the
* interval will be scaled up. If the number of buckets
* created is less than one, the interval is scaled back.
*
* The interval object returned is a moment.duration
* object that has been decorated with the following
* properties.
*
* interval.description: a text description of the interval.
* designed to be used list "field per {{ desc }}".
* - "minute"
* - "10 days"
* - "3 years"
*
* interval.expr: the elasticsearch expression that creates this
* interval. If the interval does not properly form an elasticsearch
* expression it will be forced into one.
*
* interval.scaled: the interval was adjusted to
* accomidate the maxBars setting.
*
* interval.scale: the numer that y-values should be
* multiplied by
*
* interval.scaleDescription: a description that reflects
* the values which will be produced by using the
* interval.scale.
*
*
* @return {[type]} [description]
*/
TimeBuckets.prototype.getInterval = function () {
const self = this;
const duration = self.getDuration();
return decorateInterval(maybeScaleInterval(readInterval()));
// either pull the interval from state or calculate the auto-interval
function readInterval() {
const interval = self._i;
if (moment.isDuration(interval)) return interval;
return calcAuto.near(config.get('histogram:barTarget'), duration);
}
// check to see if the interval should be scaled, and scale it if so
function maybeScaleInterval(interval) {
if (!self.hasBounds()) return interval;
const maxLength = config.get('histogram:maxBars');
const approxLen = duration / interval;
let scaled;
if (approxLen > maxLength) {
scaled = calcAuto.lessThan(maxLength, duration);
} else {
return interval;
}
if (+scaled === +interval) return interval;
decorateInterval(interval);
return _.assign(scaled, {
preScaled: interval,
scale: interval / scaled,
scaled: true
});
}
// append some TimeBuckets specific props to the interval
function decorateInterval(interval) {
const esInterval = calcEsInterval(interval);
interval.esValue = esInterval.value;
interval.esUnit = esInterval.unit;
interval.expression = esInterval.expression;
interval.overflow = duration > interval ? moment.duration(interval - duration) : false;
const prettyUnits = moment.normalizeUnits(esInterval.unit);
if (esInterval.value === 1) {
interval.description = prettyUnits;
} else {
interval.description = esInterval.value + ' ' + prettyUnits + 's';
}
return interval;
}
};
/**
* Get a date format string that will represent dates that
* progress at our interval.
*
* Since our interval can be as small as 1ms, the default
* date format is usually way too much. with `dateFormat:scaled`
* users can modify how dates are formatted within series
* produced by TimeBuckets
*
* @return {string}
*/
TimeBuckets.prototype.getScaledDateFormat = function () {
const interval = this.getInterval();
const rules = config.get('dateFormat:scaled');
for (let i = rules.length - 1; i >= 0; i--) {
const rule = rules[i];
if (!rule[0] || interval >= moment.duration(rule[0])) {
return rule[1];
}
}
return config.get('dateFormat');
};
TimeBuckets.prototype.getScaledDateFormatter = function () {
const DateFieldFormat = fieldFormats.getType('date');
return new DateFieldFormat({
pattern: this.getScaledDateFormat()
}, getConfig);
};
TimeBuckets.__cached__ = function (self) {
let cache = {};
const sameMoment = same(moment.isMoment);
const sameDuration = same(moment.isDuration);
const desc = {
__cached__: {
value: self
},
};
const breakers = {
setBounds: 'bounds',
clearBounds: 'bounds',
setInterval: 'interval'
};
const resources = {
bounds: {
setup: function () {
return [self._lb, self._ub];
},
changes: function (prev) {
return !sameMoment(prev[0], self._lb) || !sameMoment(prev[1], self._ub);
}
},
interval: {
setup: function () {
return self._i;
},
changes: function (prev) {
return !sameDuration(prev, this._i);
}
}
};
function cachedGetter(prop) {
return {
value: function cachedGetter() {
if (cache.hasOwnProperty(prop)) {
return cache[prop];
}
return cache[prop] = self[prop]();
}
};
}
function cacheBreaker(prop) {
const resource = resources[breakers[prop]];
const setup = resource.setup;
const changes = resource.changes;
const fn = self[prop];
return {
value: function cacheBreaker() {
const prev = setup.call(self);
const ret = fn.apply(self, arguments);
if (changes.call(self, prev)) {
cache = {};
}
return ret;
}
};
}
function same(checkType) {
return function (a, b) {
if (a === b) return true;
if (checkType(a) === checkType(b)) return +a === +b;
return false;
};
}
_.forOwn(TimeBuckets.prototype, function (fn, prop) {
if (prop[0] === '_') return;
if (breakers.hasOwnProperty(prop)) {
desc[prop] = cacheBreaker(prop);
} else {
desc[prop] = cachedGetter(prop);
}
});
return Object.create(self, desc);
};
return TimeBuckets;
function isValidMoment(m) {
return m && ('isValid' in m) && m.isValid();
}
/**
* Helper class for wrapping the concept of an "Interval",
* which describes a timespan that will seperate moments.
*
* @param {state} object - one of ""
* @param {[type]} display [description]
*/
function TimeBuckets() {
return TimeBuckets.__cached__(this);
}
/****
* PUBLIC API
****/
/**
* Set the bounds that these buckets are expected to cover.
* This is required to support interval "auto" as well
* as interval scaling.
*
* @param {object} input - an object with properties min and max,
* representing the edges for the time span
* we should cover
*
* @returns {undefined}
*/
TimeBuckets.prototype.setBounds = function (input) {
if (!input) return this.clearBounds();
let bounds;
if (_.isPlainObject(input)) {
// accept the response from timefilter.getActiveBounds()
bounds = [input.min, input.max];
} else {
bounds = Array.isArray(input) ? input : [];
}
const moments = _(bounds)
.map(_.ary(moment, 1))
.sortBy(Number);
const valid = moments.size() === 2 && moments.every(isValidMoment);
if (!valid) {
this.clearBounds();
throw new Error('invalid bounds set: ' + input);
}
this._lb = moments.shift();
this._ub = moments.pop();
if (this.getDuration().asSeconds() < 0) {
throw new TypeError('Intervals must be positive');
}
};
/**
* Clear the stored bounds
*
* @return {undefined}
*/
TimeBuckets.prototype.clearBounds = function () {
this._lb = this._ub = null;
};
/**
* Check to see if we have received bounds yet
*
* @return {Boolean}
*/
TimeBuckets.prototype.hasBounds = function () {
return isValidMoment(this._ub) && isValidMoment(this._lb);
};
/**
* Return the current bounds, if we have any.
*
* THIS DOES NOT CLONE THE BOUNDS, so editing them
* may have unexpected side-effects. Always
* call bounds.min.clone() before editing
*
* @return {object|undefined} - If bounds are not defined, this
* returns undefined, else it returns the bounds
* for these buckets. This object has two props,
* min and max. Each property will be a moment()
* object
*
*/
TimeBuckets.prototype.getBounds = function () {
if (!this.hasBounds()) return;
return {
min: this._lb,
max: this._ub
};
};
/**
* Get a moment duration object representing
* the distance between the bounds, if the bounds
* are set.
*
* @return {moment.duration|undefined}
*/
TimeBuckets.prototype.getDuration = function () {
if (!this.hasBounds()) return;
return moment.duration(this._ub - this._lb, 'ms');
};
/**
* Update the interval at which buckets should be
* generated.
*
* Input can be one of the following:
* - Any object from src/ui/agg_types/buckets/_interval_options.js
* - "auto"
* - Pass a valid moment unit
* - a moment.duration object.
*
* @param {object|string|moment.duration} input - see desc
*/
TimeBuckets.prototype.setInterval = function (input) {
let interval = input;
// selection object -> val
if (_.isObject(input)) {
interval = input.val;
}
if (!interval || interval === 'auto') {
this._i = 'auto';
return;
}
if (_.isString(interval)) {
input = interval;
interval = parseInterval(interval);
if (+interval === 0) {
interval = null;
}
}
// if the value wasn't converted to a duration, and isn't
// already a duration, we have a problem
if (!moment.isDuration(interval)) {
throw new TypeError('"' + input + '" is not a valid interval.');
}
this._i = interval;
};
/**
* Get the interval for the buckets. If the
* number of buckets created by the interval set
* is larger than config:histogram:maxBars then the
* interval will be scaled up. If the number of buckets
* created is less than one, the interval is scaled back.
*
* The interval object returned is a moment.duration
* object that has been decorated with the following
* properties.
*
* interval.description: a text description of the interval.
* designed to be used list "field per {{ desc }}".
* - "minute"
* - "10 days"
* - "3 years"
*
* interval.expr: the elasticsearch expression that creates this
* interval. If the interval does not properly form an elasticsearch
* expression it will be forced into one.
*
* interval.scaled: the interval was adjusted to
* accomidate the maxBars setting.
*
* interval.scale: the numer that y-values should be
* multiplied by
*
* interval.scaleDescription: a description that reflects
* the values which will be produced by using the
* interval.scale.
*
*
* @return {[type]} [description]
*/
TimeBuckets.prototype.getInterval = function () {
const self = this;
const duration = self.getDuration();
return decorateInterval(maybeScaleInterval(readInterval()));
// either pull the interval from state or calculate the auto-interval
function readInterval() {
const interval = self._i;
if (moment.isDuration(interval)) return interval;
return calcAutoInterval.near(config.get('histogram:barTarget'), duration);
}
// check to see if the interval should be scaled, and scale it if so
function maybeScaleInterval(interval) {
if (!self.hasBounds()) return interval;
const maxLength = config.get('histogram:maxBars');
const approxLen = duration / interval;
let scaled;
if (approxLen > maxLength) {
scaled = calcAutoInterval.lessThan(maxLength, duration);
} else {
return interval;
}
if (+scaled === +interval) return interval;
decorateInterval(interval);
return _.assign(scaled, {
preScaled: interval,
scale: interval / scaled,
scaled: true
});
}
// append some TimeBuckets specific props to the interval
function decorateInterval(interval) {
const esInterval = calcEsInterval(interval);
interval.esValue = esInterval.value;
interval.esUnit = esInterval.unit;
interval.expression = esInterval.expression;
interval.overflow = duration > interval ? moment.duration(interval - duration) : false;
const prettyUnits = moment.normalizeUnits(esInterval.unit);
if (esInterval.value === 1) {
interval.description = prettyUnits;
} else {
interval.description = esInterval.value + ' ' + prettyUnits + 's';
}
return interval;
}
};
/**
* Get a date format string that will represent dates that
* progress at our interval.
*
* Since our interval can be as small as 1ms, the default
* date format is usually way too much. with `dateFormat:scaled`
* users can modify how dates are formatted within series
* produced by TimeBuckets
*
* @return {string}
*/
TimeBuckets.prototype.getScaledDateFormat = function () {
const interval = this.getInterval();
const rules = config.get('dateFormat:scaled');
for (let i = rules.length - 1; i >= 0; i--) {
const rule = rules[i];
if (!rule[0] || interval >= moment.duration(rule[0])) {
return rule[1];
}
}
return config.get('dateFormat');
};
TimeBuckets.prototype.getScaledDateFormatter = function () {
const DateFieldFormat = fieldFormats.getType('date');
return new DateFieldFormat({
pattern: this.getScaledDateFormat()
}, getConfig);
};
TimeBuckets.__cached__ = function (self) {
let cache = {};
const sameMoment = same(moment.isMoment);
const sameDuration = same(moment.isDuration);
const desc = {
__cached__: {
value: self
},
};
const breakers = {
setBounds: 'bounds',
clearBounds: 'bounds',
setInterval: 'interval'
};
const resources = {
bounds: {
setup: function () {
return [self._lb, self._ub];
},
changes: function (prev) {
return !sameMoment(prev[0], self._lb) || !sameMoment(prev[1], self._ub);
}
},
interval: {
setup: function () {
return self._i;
},
changes: function (prev) {
return !sameDuration(prev, this._i);
}
}
};
function cachedGetter(prop) {
return {
value: function cachedGetter() {
if (cache.hasOwnProperty(prop)) {
return cache[prop];
}
return cache[prop] = self[prop]();
}
};
}
function cacheBreaker(prop) {
const resource = resources[breakers[prop]];
const setup = resource.setup;
const changes = resource.changes;
const fn = self[prop];
return {
value: function cacheBreaker() {
const prev = setup.call(self);
const ret = fn.apply(self, arguments);
if (changes.call(self, prev)) {
cache = {};
}
return ret;
}
};
}
function same(checkType) {
return function (a, b) {
if (a === b) return true;
if (checkType(a) === checkType(b)) return +a === +b;
return false;
};
}
_.forOwn(TimeBuckets.prototype, function (fn, prop) {
if (prop[0] === '_') return;
if (breakers.hasOwnProperty(prop)) {
desc[prop] = cacheBreaker(prop);
} else {
desc[prop] = cachedGetter(prop);
}
});
return Object.create(self, desc);
};
export { TimeBuckets };

View file

@ -2,7 +2,7 @@ import sinon from 'sinon';
import expect from 'expect.js';
import ngMock from 'ng_mock';
import { VisProvider } from '..';
import { AggTypesAggTypeProvider } from '../../agg_types/agg_type';
import { AggType } from '../../agg_types/agg_type';
import { AggConfig } from '../agg_config';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { fieldFormats } from '../../registry/field_formats';
@ -10,13 +10,11 @@ import { fieldFormats } from '../../registry/field_formats';
describe('AggConfig', function () {
let Vis;
let AggType;
let indexPattern;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private) {
Vis = Private(VisProvider);
AggType = Private(AggTypesAggTypeProvider);
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
}));

View file

@ -10,11 +10,11 @@
import _ from 'lodash';
import { IndexedArray } from '../indexed_array';
import { AggConfig } from './agg_config';
import { AggTypesIndexProvider } from '../agg_types';
import { aggTypes } from '../agg_types';
import { createLegacyClass } from '../utils/legacy_class';
export function VisAggConfigsProvider(Private) {
AggConfig.aggTypes = Private(AggTypesIndexProvider);
export function VisAggConfigsProvider() {
AggConfig.aggTypes = aggTypes;
createLegacyClass(AggConfigs).inherits(IndexedArray);
function AggConfigs(vis, configStates) {

View file

@ -4,15 +4,14 @@ import aggSelectHtml from './agg_select.html';
import advancedToggleHtml from './advanced_toggle.html';
import '../../../filters/match_any';
import './agg_param';
import { AggTypesIndexProvider } from '../../../agg_types';
import { aggTypes } from '../../../agg_types';
import { uiModules } from '../../../modules';
import { documentationLinks } from '../../../documentation_links/documentation_links';
import aggParamsTemplate from './agg_params.html';
uiModules
.get('app/visualize')
.directive('visEditorAggParams', function ($compile, $parse, Private) {
const aggTypes = Private(AggTypesIndexProvider);
.directive('visEditorAggParams', function ($compile) {
return {
restrict: 'E',

View file

@ -22,7 +22,7 @@ import chrome from 'ui/chrome';
import uiRoutes from 'ui/routes';
import { notify } from 'ui/notify';
import { luceneStringToDsl } from 'ui/courier/data_source/build_query/lucene_string_to_dsl.js';
import { DecorateQueryProvider } from 'ui/courier/data_source/_decorate_query';
import { decorateQuery } from 'ui/courier/data_source/_decorate_query';
import { ML_JOB_FIELD_TYPES, KBN_FIELD_TYPES } from 'plugins/ml/../common/constants/field_types';
import { kbnTypeToMLJobType } from 'plugins/ml/util/field_types_utils';
@ -113,7 +113,6 @@ module
}
}
const decorateQuery = Private(DecorateQueryProvider);
$scope.searchQuery = buildSearchQuery();
$scope.samplerShardSize = $scope.appState.samplerShardSize ?

View file

@ -21,7 +21,7 @@ import moment from 'moment';
import { formatValue } from 'plugins/ml/formatters/format_value';
import { getSeverityWithLow } from 'plugins/ml/util/anomaly_utils';
import { drawLineChartDots, numTicksForDateFormat } from 'plugins/ml/util/chart_utils';
import { TimeBucketsProvider } from 'ui/time_buckets';
import { TimeBuckets } from 'ui/time_buckets';
import loadingIndicatorWrapperTemplate from 'plugins/ml/components/loading_indicator/loading_indicator_wrapper.html';
import { mlEscape } from 'plugins/ml/util/string_utils';
import { mlFieldFormatService } from 'plugins/ml/services/field_format_service';
@ -51,7 +51,6 @@ module.directive('mlExplorerChart', function (
// Left margin is adjusted later for longest y-axis label.
const margin = { top: 10, right: 0, bottom: 30, left: 60 };
const TimeBuckets = Private(TimeBucketsProvider);
let lineChartXScale = null;
let lineChartYScale = null;
let lineChartGroup;

View file

@ -17,13 +17,13 @@ import angular from 'angular';
import moment from 'moment';
import 'ui/timefilter';
import { TimeBucketsProvider } from 'ui/time_buckets';
import { TimeBuckets } from 'ui/time_buckets';
import { numTicksForDateFormat } from 'plugins/ml/util/chart_utils';
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
module.directive('mlEventRateChart', function (Private) {
module.directive('mlEventRateChart', function () {
function link(scope, element) {
@ -33,7 +33,6 @@ module.directive('mlEventRateChart', function (Private) {
const svgHeight = barChartHeight + margin.top + margin.bottom;
let vizWidth = svgWidth - margin.left - margin.right;
const chartLimits = { max: 0, min: 0 };
const TimeBuckets = Private(TimeBucketsProvider);
let barChartXScale = null;
let swimlaneXScale = null;

View file

@ -15,13 +15,13 @@ import d3 from 'd3';
import angular from 'angular';
import moment from 'moment';
import { TimeBucketsProvider } from 'ui/time_buckets';
import { TimeBuckets } from 'ui/time_buckets';
import { drawLineChartDots, numTicksForDateFormat } from 'plugins/ml/util/chart_utils';
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
module.directive('mlMultiMetricJobChart', function (Private) {
module.directive('mlMultiMetricJobChart', function () {
function link(scope, element) {
@ -31,7 +31,6 @@ module.directive('mlMultiMetricJobChart', function (Private) {
const svgHeight = lineChartHeight + margin.top + margin.bottom;
let vizWidth = svgWidth - margin.left - margin.right;
const chartLimits = { max: 0, min: 0 };
const TimeBuckets = Private(TimeBucketsProvider);
let lineChartXScale = null;
let lineChartYScale = null;

View file

@ -9,7 +9,7 @@
import _ from 'lodash';
import 'plugins/kibana/visualize/styles/main.less';
import { AggTypesIndexProvider } from 'ui/agg_types/index';
import { aggTypes } from 'ui/agg_types/index';
import { addJobValidationMethods } from 'plugins/ml/../common/util/validation_utils';
import { parseInterval } from 'plugins/ml/../common/util/parse_interval';
@ -84,7 +84,6 @@ module
};
const appState = new AppState(stateDefaults);
const aggTypes = Private(AggTypesIndexProvider);
mlMultiMetricJobService.clearChartData();
$scope.chartData = mlMultiMetricJobService.chartData;

View file

@ -15,14 +15,14 @@ import d3 from 'd3';
import angular from 'angular';
import moment from 'moment';
import { TimeBucketsProvider } from 'ui/time_buckets';
import { TimeBuckets } from 'ui/time_buckets';
import { numTicksForDateFormat } from 'plugins/ml/util/chart_utils';
import { mlEscape } from 'plugins/ml/util/string_utils';
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
module.directive('mlPopulationJobChart', function (Private, mlChartTooltipService) {
module.directive('mlPopulationJobChart', function (mlChartTooltipService) {
function link(scope, element) {
@ -32,7 +32,6 @@ module.directive('mlPopulationJobChart', function (Private, mlChartTooltipServic
const svgHeight = chartHeight + margin.top + margin.bottom;
let vizWidth = svgWidth - margin.left - margin.right;
const chartLimits = { max: 0, min: 0 };
const TimeBuckets = Private(TimeBucketsProvider);
let chartXScale = null;
let chartYScale = null;

View file

@ -9,7 +9,7 @@
import _ from 'lodash';
import 'plugins/kibana/visualize/styles/main.less';
import { AggTypesIndexProvider } from 'ui/agg_types/index';
import { aggTypes } from 'ui/agg_types/index';
import { addJobValidationMethods } from 'plugins/ml/../common/util/validation_utils';
import { parseInterval } from 'plugins/ml/../common/util/parse_interval';
@ -84,8 +84,6 @@ module
};
const appState = new AppState(stateDefaults);
const aggTypes = Private(AggTypesIndexProvider);
mlPopulationJobService.clearChartData();
$scope.chartData = mlPopulationJobService.chartData;
const jobDefaults = newJobDefaults();

View file

@ -16,13 +16,13 @@ import angular from 'angular';
import moment from 'moment';
import 'ui/timefilter';
import { TimeBucketsProvider } from 'ui/time_buckets';
import { TimeBuckets } from 'ui/time_buckets';
import { drawLineChartDots, numTicksForDateFormat } from 'plugins/ml/util/chart_utils';
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
module.directive('mlSingleMetricJobChart', function (Private) {
module.directive('mlSingleMetricJobChart', function () {
function link(scope, element) {
@ -33,7 +33,6 @@ module.directive('mlSingleMetricJobChart', function (Private) {
const svgHeight = lineChartHeight + swimlaneHeight + margin.top + margin.bottom;
let vizWidth = svgWidth - margin.left - margin.right;
const chartLimits = { max: 0, min: 0 };
const TimeBuckets = Private(TimeBucketsProvider);
let lineChartXScale = null;
let lineChartYScale = null;

View file

@ -9,7 +9,7 @@
import _ from 'lodash';
import 'plugins/kibana/visualize/styles/main.less';
import { AggTypesIndexProvider } from 'ui/agg_types/index';
import { aggTypes } from 'ui/agg_types/index';
import { addJobValidationMethods } from 'plugins/ml/../common/util/validation_utils';
import { parseInterval } from 'plugins/ml/../common/util/parse_interval';
@ -83,8 +83,6 @@ module
};
const appState = new AppState(stateDefaults);
const aggTypes = Private(AggTypesIndexProvider);
$scope.index = $route.current.params.index;
$scope.chartData = mlSingleMetricJobService.chartData;
$scope.changeJobIDCase = changeJobIDCase;

View file

@ -27,7 +27,7 @@ import {
filterAxisLabels,
numTicksForDateFormat
} from 'plugins/ml/util/chart_utils';
import { TimeBucketsProvider } from 'ui/time_buckets';
import { TimeBuckets } from 'ui/time_buckets';
import ContextChartMask from 'plugins/ml/timeseriesexplorer/context_chart_mask';
import { findNearestChartPointToTime } from 'plugins/ml/timeseriesexplorer/timeseriesexplorer_utils';
import { mlEscape } from 'plugins/ml/util/string_utils';
@ -101,8 +101,6 @@ module.directive('mlTimeseriesChart', function (
let contextXScale = d3.time.scale().range([0, vizWidth]);
let contextYScale = d3.scale.linear().range([contextChartHeight, contextChartLineTopMargin]);
const TimeBuckets = Private(TimeBucketsProvider);
let fieldFormat = undefined;
const brush = d3.svg.brush();

View file

@ -16,15 +16,14 @@ import moment from 'moment';
import { TimeBucketsCalcAutoIntervalProvider } from 'plugins/ml/util/ml_calc_auto_interval';
import { inherits } from 'plugins/ml/util/inherits';
import { TimeBucketsCalcEsIntervalProvider } from 'ui/time_buckets/calc_es_interval';
import { calcEsInterval } from 'ui/time_buckets/calc_es_interval';
import { TimeBucketsProvider } from 'ui/time_buckets';
import { TimeBuckets as KibanaTimeBuckets } from 'ui/time_buckets';
export function IntervalHelperProvider(Private, timefilter, config) {
const calcAuto = Private(TimeBucketsCalcAutoIntervalProvider);
const calcEsInterval = Private(TimeBucketsCalcEsIntervalProvider);
inherits(TimeBuckets, Private(TimeBucketsProvider));
inherits(TimeBuckets, KibanaTimeBuckets);
function TimeBuckets() {
this.barTarget = config.get('histogram:barTarget');

View file

@ -8,7 +8,7 @@ import moment from 'moment';
import 'ui/filters/moment';
import { isNumber, forEach, merge } from 'lodash';
import { uiModules } from 'ui/modules';
import { TimeBucketsProvider } from 'ui/time_buckets';
import { TimeBuckets } from 'ui/time_buckets';
import 'plugins/watcher/components/flot_chart';
import 'plugins/watcher/components/chart_tooltip';
import template from './threshold_preview_chart.html';
@ -19,8 +19,6 @@ const app = uiModules.get('xpack/watcher');
app.directive('thresholdPreviewChart', function ($injector) {
const config = $injector.get('config');
const Private = $injector.get('Private');
const TimeBuckets = Private(TimeBucketsProvider);
moment.tz.setDefault(config.get('dateFormat:tz'));

View file

@ -6,12 +6,10 @@
import { uiModules } from 'ui/modules';
import { XpackWatcherIntervalService } from './xpack_watcher_interval_service';
import { TimeBucketsProvider } from 'ui/time_buckets';
import { TimeBuckets } from 'ui/time_buckets';
uiModules.get('xpack/watcher')
.factory('xpackWatcherIntervalService', ($injector) => {
const Private = $injector.get('Private');
const TimeBuckets = Private(TimeBucketsProvider);
.factory('xpackWatcherIntervalService', () => {
const timeBuckets = new TimeBuckets();
return new XpackWatcherIntervalService(timeBuckets);