From 9353e6cc11c7f9b9a1abdcba7b53c85184078253 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Wed, 29 Jan 2020 15:59:57 -0700 Subject: [PATCH 01/10] Copy ui/agg_types to shim data plugin without changing anything. --- .../buckets/_terms_other_bucket_helper.js | 320 ++++++++++++ .../data/public/search/aggs/agg_config.ts | 467 ++++++++++++++++++ .../data/public/search/aggs/agg_configs.ts | 318 ++++++++++++ .../data/public/search/aggs/agg_groups.ts | 37 ++ .../public/search/aggs/agg_params.test.ts | 84 ++++ .../data/public/search/aggs/agg_params.ts | 93 ++++ .../data/public/search/aggs/agg_type.test.ts | 169 +++++++ .../data/public/search/aggs/agg_type.ts | 260 ++++++++++ .../search/aggs/buckets/_bucket_agg_type.ts | 62 +++ .../search/aggs/buckets/_interval_options.ts | 82 +++ .../buckets/_terms_other_bucket_helper.js | 261 ++++++++++ .../search/aggs/buckets/bucket_agg_types.ts | 32 ++ .../create_filter/date_histogram.test.ts | 122 +++++ .../buckets/create_filter/date_histogram.ts | 40 ++ .../buckets/create_filter/date_range.test.ts | 79 +++ .../aggs/buckets/create_filter/date_range.ts | 32 ++ .../buckets/create_filter/filters.test.ts | 67 +++ .../aggs/buckets/create_filter/filters.ts | 33 ++ .../buckets/create_filter/histogram.test.ts | 75 +++ .../aggs/buckets/create_filter/histogram.ts | 33 ++ .../buckets/create_filter/ip_range.test.ts | 105 ++++ .../aggs/buckets/create_filter/ip_range.ts | 42 ++ .../aggs/buckets/create_filter/range.test.ts | 79 +++ .../aggs/buckets/create_filter/range.ts | 30 ++ .../aggs/buckets/create_filter/terms.test.ts | 131 +++++ .../aggs/buckets/create_filter/terms.ts | 46 ++ .../search/aggs/buckets/date_histogram.ts | 267 ++++++++++ .../search/aggs/buckets/date_range.test.ts | 112 +++++ .../public/search/aggs/buckets/date_range.ts | 121 +++++ .../data/public/search/aggs/buckets/filter.ts | 35 ++ .../public/search/aggs/buckets/filters.ts | 106 ++++ .../search/aggs/buckets/geo_hash.test.ts | 225 +++++++++ .../public/search/aggs/buckets/geo_hash.ts | 201 ++++++++ .../public/search/aggs/buckets/geo_tile.ts | 73 +++ .../search/aggs/buckets/histogram.test.ts | 292 +++++++++++ .../public/search/aggs/buckets/histogram.ts | 201 ++++++++ .../public/search/aggs/buckets/ip_range.ts | 109 ++++ .../search/aggs/buckets/lib/cidr_mask.test.ts | 75 +++ .../search/aggs/buckets/lib/cidr_mask.ts | 58 +++ .../search/aggs/buckets/lib/geo_utils.ts | 75 +++ .../buckets/migrate_include_exclude_format.ts | 53 ++ .../public/search/aggs/buckets/range.test.ts | 99 ++++ .../data/public/search/aggs/buckets/range.ts | 106 ++++ .../public/search/aggs/buckets/range_key.ts | 41 ++ .../aggs/buckets/significant_terms.test.ts | 111 +++++ .../search/aggs/buckets/significant_terms.ts | 76 +++ .../public/search/aggs/buckets/terms.test.ts | 78 +++ .../data/public/search/aggs/buckets/terms.ts | 290 +++++++++++ .../aggs/filter/agg_type_filters.test.ts | 62 +++ .../search/aggs/filter/agg_type_filters.ts | 64 +++ .../data/public/search/aggs/filter/index.ts | 21 + .../search/aggs/filter/prop_filter.test.ts | 94 ++++ .../public/search/aggs/filter/prop_filter.ts | 96 ++++ .../data/public/search/aggs/index.test.ts | 46 ++ .../data/public/search/aggs/index.ts | 103 ++++ .../data/public/search/aggs/metrics/avg.ts | 45 ++ .../public/search/aggs/metrics/bucket_avg.ts | 57 +++ .../public/search/aggs/metrics/bucket_max.ts | 42 ++ .../public/search/aggs/metrics/bucket_min.ts | 40 ++ .../public/search/aggs/metrics/bucket_sum.ts | 41 ++ .../public/search/aggs/metrics/cardinality.ts | 50 ++ .../data/public/search/aggs/metrics/count.ts | 48 ++ .../search/aggs/metrics/cumulative_sum.ts | 41 ++ .../public/search/aggs/metrics/derivative.ts | 43 ++ .../public/search/aggs/metrics/geo_bounds.ts | 44 ++ .../search/aggs/metrics/geo_centroid.ts | 47 ++ .../lib/get_response_agg_config_class.ts | 74 +++ .../metrics/lib/make_nested_label.test.ts | 59 +++ .../aggs/metrics/lib/make_nested_label.ts | 49 ++ .../aggs/metrics/lib/nested_agg_helpers.ts | 56 +++ .../aggs/metrics/lib/ordinal_suffix.test.ts | 69 +++ .../search/aggs/metrics/lib/ordinal_suffix.ts | 36 ++ .../metrics/lib/parent_pipeline_agg_helper.ts | 107 ++++ .../metrics/lib/parent_pipeline_agg_writer.ts | 40 ++ .../lib/sibling_pipeline_agg_helper.ts | 123 +++++ .../lib/sibling_pipeline_agg_writer.ts | 40 ++ .../data/public/search/aggs/metrics/max.ts | 45 ++ .../public/search/aggs/metrics/median.test.ts | 69 +++ .../data/public/search/aggs/metrics/median.ts | 59 +++ .../search/aggs/metrics/metric_agg_type.ts | 96 ++++ .../search/aggs/metrics/metric_agg_types.ts | 42 ++ .../data/public/search/aggs/metrics/min.ts | 44 ++ .../public/search/aggs/metrics/moving_avg.ts | 64 +++ .../aggs/metrics/parent_pipeline.test.ts | 236 +++++++++ .../aggs/metrics/percentile_ranks.test.ts | 76 +++ .../search/aggs/metrics/percentile_ranks.ts | 94 ++++ .../search/aggs/metrics/percentiles.test.ts | 74 +++ .../public/search/aggs/metrics/percentiles.ts | 80 +++ .../aggs/metrics/percentiles_get_value.ts | 32 ++ .../public/search/aggs/metrics/serial_diff.ts | 41 ++ .../aggs/metrics/sibling_pipeline.test.ts | 182 +++++++ .../search/aggs/metrics/std_deviation.test.ts | 85 ++++ .../search/aggs/metrics/std_deviation.ts | 107 ++++ .../data/public/search/aggs/metrics/sum.ts | 48 ++ .../search/aggs/metrics/top_hit.test.ts | 366 ++++++++++++++ .../public/search/aggs/metrics/top_hit.ts | 255 ++++++++++ .../public/search/aggs/param_types/agg.ts | 55 +++ .../public/search/aggs/param_types/base.ts | 84 ++++ .../search/aggs/param_types/field.test.ts | 90 ++++ .../public/search/aggs/param_types/field.ts | 133 +++++ .../param_types/filter/field_filters.test.ts | 62 +++ .../aggs/param_types/filter/field_filters.ts | 60 +++ .../search/aggs/param_types/filter/index.ts | 20 + .../public/search/aggs/param_types/index.ts | 24 + .../search/aggs/param_types/json.test.ts | 118 +++++ .../public/search/aggs/param_types/json.ts | 82 +++ .../search/aggs/param_types/optioned.test.ts | 36 ++ .../search/aggs/param_types/optioned.ts | 59 +++ .../search/aggs/param_types/string.test.ts | 80 +++ .../public/search/aggs/param_types/string.ts | 35 ++ .../data/public/search/aggs/schemas.ts | 107 ++++ .../data/public/search/aggs/utils.test.tsx | 51 ++ .../data/public/search/aggs/utils.ts | 72 +++ 113 files changed, 10803 insertions(+) create mode 100644 src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js create mode 100644 src/legacy/core_plugins/data/public/search/aggs/agg_config.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/agg_params.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/agg_type.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/bucket_agg_types.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/filter.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/filters.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/lib/geo_utils.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/range_key.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/terms.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/filter/index.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/index.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/index.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/lib/get_response_agg_config_class.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/lib/nested_agg_helpers.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_types.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/min.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/moving_avg.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles_get_value.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/serial_diff.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/agg.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/filter/index.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/index.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/json.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/json.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/string.test.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/param_types/string.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/schemas.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/utils.test.tsx create mode 100644 src/legacy/core_plugins/data/public/search/aggs/utils.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js b/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js new file mode 100644 index 0000000000000..acf932c1fb451 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js @@ -0,0 +1,320 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import expect from '@kbn/expect'; +import ngMock from 'ng_mock'; +import { + buildOtherBucketAgg, + mergeOtherBucketAggResponse, + updateMissingBucket, +} from '../../buckets/_terms_other_bucket_helper'; +import { Vis } from '../../../../../core_plugins/visualizations/public'; +import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; + +const visConfigSingleTerm = { + type: 'pie', + aggs: [ + { + type: 'terms', + schema: 'segment', + params: { field: 'machine.os.raw', otherBucket: true, missingBucket: true }, + }, + ], +}; + +const visConfigNestedTerm = { + type: 'pie', + aggs: [ + { + type: 'terms', + schema: 'segment', + params: { field: 'geo.src', size: 2, otherBucket: false, missingBucket: false }, + }, + { + type: 'terms', + schema: 'segment', + params: { field: 'machine.os.raw', size: 2, otherBucket: true, missingBucket: true }, + }, + ], +}; + +const singleTermResponse = { + took: 10, + timed_out: false, + _shards: { + total: 1, + successful: 1, + skipped: 0, + failed: 0, + }, + hits: { + total: 14005, + max_score: 0, + hits: [], + }, + aggregations: { + '1': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 8325, + buckets: [ + { key: 'ios', doc_count: 2850 }, + { key: 'win xp', doc_count: 2830 }, + { key: '__missing__', doc_count: 1430 }, + ], + }, + }, + status: 200, +}; + +const nestedTermResponse = { + took: 10, + timed_out: false, + _shards: { + total: 1, + successful: 1, + skipped: 0, + failed: 0, + }, + hits: { + total: 14005, + max_score: 0, + hits: [], + }, + aggregations: { + '1': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 8325, + buckets: [ + { + '2': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 8325, + buckets: [ + { key: 'ios', doc_count: 2850 }, + { key: 'win xp', doc_count: 2830 }, + { key: '__missing__', doc_count: 1430 }, + ], + }, + key: 'US', + doc_count: 2850, + }, + { + '2': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 8325, + buckets: [ + { key: 'ios', doc_count: 1850 }, + { key: 'win xp', doc_count: 1830 }, + { key: '__missing__', doc_count: 130 }, + ], + }, + key: 'IN', + doc_count: 2830, + }, + ], + }, + }, + status: 200, +}; + +const nestedTermResponseNoResults = { + took: 10, + timed_out: false, + _shards: { + total: 1, + successful: 1, + skipped: 0, + failed: 0, + }, + hits: { + total: 0, + max_score: null, + hits: [], + }, + aggregations: { + '1': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [], + }, + }, + status: 200, +}; + +const singleOtherResponse = { + took: 3, + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { total: 14005, max_score: 0, hits: [] }, + aggregations: { + 'other-filter': { + buckets: { '': { doc_count: 2805 } }, + }, + }, + status: 200, +}; + +const nestedOtherResponse = { + took: 3, + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { total: 14005, max_score: 0, hits: [] }, + aggregations: { + 'other-filter': { + buckets: { '-US': { doc_count: 2805 }, '-IN': { doc_count: 2804 } }, + }, + }, + status: 200, +}; + +describe('Terms Agg Other bucket helper', () => { + let vis; + + function init(aggConfig) { + ngMock.module('kibana'); + ngMock.inject(Private => { + const indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider); + + vis = new Vis(indexPattern, aggConfig); + }); + } + + describe('buildOtherBucketAgg', () => { + it('returns a function', () => { + init(visConfigSingleTerm); + const agg = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[0], singleTermResponse); + expect(agg).to.be.a('function'); + }); + + it('correctly builds query with single terms agg', () => { + init(visConfigSingleTerm); + const agg = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[0], singleTermResponse)(); + const expectedResponse = { + aggs: undefined, + filters: { + filters: { + '': { + bool: { + must: [], + filter: [{ exists: { field: 'machine.os.raw' } }], + should: [], + must_not: [ + { match_phrase: { 'machine.os.raw': 'ios' } }, + { match_phrase: { 'machine.os.raw': 'win xp' } }, + ], + }, + }, + }, + }, + }; + + expect(agg['other-filter']).to.eql(expectedResponse); + }); + + it('correctly builds query for nested terms agg', () => { + init(visConfigNestedTerm); + const agg = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[1], nestedTermResponse)(); + const expectedResponse = { + 'other-filter': { + aggs: undefined, + filters: { + filters: { + '-IN': { + bool: { + must: [], + filter: [ + { match_phrase: { 'geo.src': 'IN' } }, + { exists: { field: 'machine.os.raw' } }, + ], + should: [], + must_not: [ + { match_phrase: { 'machine.os.raw': 'ios' } }, + { match_phrase: { 'machine.os.raw': 'win xp' } }, + ], + }, + }, + '-US': { + bool: { + must: [], + filter: [ + { match_phrase: { 'geo.src': 'US' } }, + { exists: { field: 'machine.os.raw' } }, + ], + should: [], + must_not: [ + { match_phrase: { 'machine.os.raw': 'ios' } }, + { match_phrase: { 'machine.os.raw': 'win xp' } }, + ], + }, + }, + }, + }, + }, + }; + + expect(agg).to.eql(expectedResponse); + }); + + it('returns false when nested terms agg has no buckets', () => { + init(visConfigNestedTerm); + const agg = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[1], nestedTermResponseNoResults); + expect(agg).to.eql(false); + }); + }); + + describe('mergeOtherBucketAggResponse', () => { + it('correctly merges other bucket with single terms agg', () => { + init(visConfigSingleTerm); + const otherAggConfig = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[0], singleTermResponse)(); + const mergedResponse = mergeOtherBucketAggResponse( + vis.aggs, + singleTermResponse, + singleOtherResponse, + vis.aggs.aggs[0], + otherAggConfig + ); + + expect(mergedResponse.aggregations['1'].buckets[3].key).to.equal('__other__'); + }); + + it('correctly merges other bucket with nested terms agg', () => { + init(visConfigNestedTerm); + const otherAggConfig = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[1], nestedTermResponse)(); + const mergedResponse = mergeOtherBucketAggResponse( + vis.aggs, + nestedTermResponse, + nestedOtherResponse, + vis.aggs.aggs[1], + otherAggConfig + ); + + expect(mergedResponse.aggregations['1'].buckets[1]['2'].buckets[3].key).to.equal('__other__'); + }); + }); + + describe('updateMissingBucket', () => { + it('correctly updates missing bucket key', () => { + init(visConfigNestedTerm); + const updatedResponse = updateMissingBucket(singleTermResponse, vis.aggs, vis.aggs.aggs[0]); + expect( + updatedResponse.aggregations['1'].buckets.find(bucket => bucket.key === '__missing__') + ).to.not.be('undefined'); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts new file mode 100644 index 0000000000000..2ab701d4019fb --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts @@ -0,0 +1,467 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @name AggConfig + * + * @description This class represents an aggregation, which is displayed in the left-hand nav of + * the Visualize app. + */ + +import _ from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { npStart } from 'ui/new_platform'; +import { AggType } from './agg_type'; +import { AggGroupNames } from './agg_groups'; +import { writeParams } from './agg_params'; +import { AggConfigs } from './agg_configs'; +import { Schema } from './schemas'; +import { + ISearchSource, + FetchOptions, + fieldFormats, + KBN_FIELD_TYPES, +} from '../../../../plugins/data/public'; + +export interface AggConfigOptions { + enabled: boolean; + type: string; + params: any; + id?: string; + schema?: string; +} + +const unknownSchema: Schema = { + name: 'unknown', + title: 'Unknown', + hideCustomLabel: true, + aggFilter: [], + min: 1, + max: 1, + params: [], + defaults: {}, + editor: false, + group: AggGroupNames.Metrics, +}; + +const getTypeFromRegistry = (type: string): AggType => { + // We need to inline require here, since we're having a cyclic dependency + // from somewhere inside agg_types back to AggConfig. + const aggTypes = require('../agg_types').aggTypes; + const registeredType = + aggTypes.metrics.find((agg: AggType) => agg.name === type) || + aggTypes.buckets.find((agg: AggType) => agg.name === type); + + if (!registeredType) { + throw new Error('unknown type'); + } + + return registeredType; +}; + +const getSchemaFromRegistry = (schemas: any, schema: string): Schema => { + let registeredSchema = schemas ? schemas.byName[schema] : null; + if (!registeredSchema) { + registeredSchema = Object.assign({}, unknownSchema); + registeredSchema.name = schema; + } + + return registeredSchema; +}; + +export class AggConfig { + /** + * Ensure that all of the objects in the list have ids, the objects + * and list are modified by reference. + * + * @param {array[object]} list - a list of objects, objects can be anything really + * @return {array} - the list that was passed in + */ + static ensureIds(list: AggConfig[]) { + const have: AggConfig[] = []; + const haveNot: AggConfig[] = []; + list.forEach(function (obj) { + (obj.id ? have : haveNot).push(obj); + }); + + let nextId = AggConfig.nextId(have); + haveNot.forEach(function (obj) { + obj.id = String(nextId++); + }); + + return list; + } + + /** + * Calculate the next id based on the ids in this list + * + * @return {array} list - a list of objects with id properties + */ + static nextId(list: AggConfig[]) { + return ( + 1 + + list.reduce(function (max, obj) { + return Math.max(max, +obj.id || 0); + }, 0) + ); + } + + public aggConfigs: AggConfigs; + public id: string; + public enabled: boolean; + public params: any; + public parent?: AggConfigs; + public brandNew?: boolean; + + private __schema: Schema; + private __type: AggType; + private __typeDecorations: any; + private subAggs: AggConfig[] = []; + + constructor(aggConfigs: AggConfigs, opts: AggConfigOptions) { + this.aggConfigs = aggConfigs; + this.id = String(opts.id || AggConfig.nextId(aggConfigs.aggs as any)); + this.enabled = typeof opts.enabled === 'boolean' ? opts.enabled : true; + + // start with empty params so that checks in type/schema setters don't freak + // because this.params is undefined + this.params = {}; + + // setters + this.setType(opts.type); + + if (opts.schema) { + this.setSchema(opts.schema); + } + + // set the params to the values from opts, or just to the defaults + this.setParams(opts.params || {}); + + // @ts-ignore + this.__type = this.__type; + // @ts-ignore + this.__schema = this.__schema; + } + + /** + * Write the current values to this.params, filling in the defaults as we go + * + * @param {object} [from] - optional object to read values from, + * used when initializing + * @return {undefined} + */ + setParams(from: any) { + from = from || this.params || {}; + const to = (this.params = {} as any); + + this.getAggParams().forEach(aggParam => { + let val = from[aggParam.name]; + + if (val == null) { + if (aggParam.default == null) return; + + if (!_.isFunction(aggParam.default)) { + val = aggParam.default; + } else { + val = aggParam.default(this); + if (val == null) return; + } + } + + if (aggParam.deserialize) { + const isTyped = _.isFunction(aggParam.valueType); + + const isType = isTyped && val instanceof aggParam.valueType; + const isObject = !isTyped && _.isObject(val); + const isDeserialized = isType || isObject; + + if (!isDeserialized) { + val = aggParam.deserialize(val, this); + } + + to[aggParam.name] = val; + return; + } + + to[aggParam.name] = _.cloneDeep(val); + }); + } + + getParam(key: string): any { + return _.get(this.params, key); + } + + write(aggs?: AggConfigs) { + return writeParams(this.type.params, this, aggs); + } + + isFilterable() { + return _.isFunction(this.type.createFilter); + } + + createFilter(key: string, params = {}) { + const createFilter = this.type.createFilter; + + if (!createFilter) { + throw new TypeError(`The "${this.type.title}" aggregation does not support filtering.`); + } + + const field = this.getField(); + const label = this.getFieldDisplayName(); + if (field && !field.filterable) { + let message = `The "${label}" field can not be used for filtering.`; + if (field.scripted) { + message = `The "${label}" field is scripted and can not be used for filtering.`; + } + throw new TypeError(message); + } + + return createFilter(this, key, params); + } + + /** + * Hook for pre-flight logic, see AggType#onSearchRequestStart + * @param {Courier.SearchSource} searchSource + * @param {Courier.FetchOptions} options + * @return {Promise} + */ + onSearchRequestStart(searchSource: ISearchSource, options?: FetchOptions) { + if (!this.type) { + return Promise.resolve(); + } + + return Promise.all( + this.type.params.map((param: any) => + param.modifyAggConfigOnSearchRequestStart(this, searchSource, options) + ) + ); + } + + /** + * Convert this aggConfig to its dsl syntax. + * + * Adds params and adhoc subaggs to a pojo, then returns it + * + * @param {AggConfigs} aggConfigs - the config object to convert + * @return {void|Object} - if the config has a dsl representation, it is + * returned, else undefined is returned + */ + toDsl(aggConfigs?: AggConfigs) { + if (this.type.hasNoDsl) return; + const output = this.write(aggConfigs) as any; + + const configDsl = {} as any; + configDsl[this.type.dslName || this.type.name] = output.params; + + // if the config requires subAggs, write them to the dsl as well + if (this.subAggs.length && !output.subAggs) output.subAggs = this.subAggs; + if (output.subAggs) { + const subDslLvl = configDsl.aggs || (configDsl.aggs = {}); + output.subAggs.forEach(function nestAdhocSubAggs(subAggConfig: any) { + subDslLvl[subAggConfig.id] = subAggConfig.toDsl(aggConfigs); + }); + } + + if (output.parentAggs) { + const subDslLvl = configDsl.parentAggs || (configDsl.parentAggs = {}); + output.parentAggs.forEach(function nestAdhocSubAggs(subAggConfig: any) { + subDslLvl[subAggConfig.id] = subAggConfig.toDsl(aggConfigs); + }); + } + + return configDsl; + } + + toJSON() { + const params = this.params; + + const outParams = _.transform( + this.getAggParams(), + (out, aggParam) => { + let val = params[aggParam.name]; + + // don't serialize undefined/null values + if (val == null) return; + if (aggParam.serialize) val = aggParam.serialize(val, this); + if (val == null) return; + + // to prevent accidental leaking, we will clone all complex values + out[aggParam.name] = _.cloneDeep(val); + }, + {} + ); + + return { + id: this.id, + enabled: this.enabled, + type: this.type && this.type.name, + schema: _.get(this, 'schema.name', this.schema), + params: outParams, + }; + } + + getAggParams() { + return [ + ...(_.has(this, 'type.params') ? this.type.params : []), + ...(_.has(this, 'schema.params') ? (this.schema as Schema).params : []), + ]; + } + + getRequestAggs() { + return (this.type && this.type.getRequestAggs(this)) || [this]; + } + + getResponseAggs() { + return (this.type && this.type.getResponseAggs(this)) || [this]; + } + + getValue(bucket: any) { + return this.type.getValue(this, bucket); + } + + getKey(bucket: any, key?: string) { + if (this.type.getKey) { + return this.type.getKey(bucket, key, this); + } else { + return ''; + } + } + + getFieldDisplayName() { + const field = this.getField(); + + return field ? field.displayName || this.fieldName() : ''; + } + + getField() { + return this.params.field; + } + + makeLabel(percentageMode = false) { + if (this.params.customLabel) { + return this.params.customLabel; + } + + if (!this.type) return ''; + return percentageMode + ? i18n.translate('common.ui.vis.aggConfig.percentageOfLabel', { + defaultMessage: 'Percentage of {label}', + values: { label: this.type.makeLabel(this) }, + }) + : `${this.type.makeLabel(this)}`; + } + + getIndexPattern() { + return this.aggConfigs.indexPattern; + } + + getTimeRange() { + return this.aggConfigs.timeRange; + } + + fieldFormatter(contentType?: fieldFormats.ContentType, defaultFormat?: any) { + const format = this.type && this.type.getFormat(this); + + if (format) { + return format.getConverterFor(contentType); + } + + return this.fieldOwnFormatter(contentType, defaultFormat); + } + + fieldOwnFormatter(contentType?: fieldFormats.ContentType, defaultFormat?: any) { + const fieldFormatsService = npStart.plugins.data.fieldFormats; + const field = this.getField(); + let format = field && field.format; + if (!format) format = defaultFormat; + if (!format) format = fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.STRING); + return format.getConverterFor(contentType); + } + + fieldName() { + const field = this.getField(); + return field ? field.name : ''; + } + + fieldIsTimeField() { + const indexPattern = this.getIndexPattern(); + if (!indexPattern) return false; + // @ts-ignore + const timeFieldName = indexPattern.timeFieldName; + return timeFieldName && this.fieldName() === timeFieldName; + } + + public get type() { + return this.__type; + } + + public set type(type) { + if (this.__typeDecorations) { + _.forOwn( + this.__typeDecorations, + function (prop, name: string | undefined) { + // @ts-ignore + delete this[name]; + }, + this + ); + } + + if (type && _.isFunction(type.decorateAggConfig)) { + this.__typeDecorations = type.decorateAggConfig(); + Object.defineProperties(this, this.__typeDecorations); + } + + this.__type = type; + let availableFields = []; + + const fieldParam = this.type && this.type.params.find((p: any) => p.type === 'field'); + + if (fieldParam) { + // @ts-ignore + availableFields = fieldParam.getAvailableFields(this.getIndexPattern().fields); + } + + // clear out the previous params except for a few special ones + this.setParams({ + // split row/columns is "outside" of the agg, so don't reset it + row: this.params.row, + + // almost every agg has fields, so we try to persist that when type changes + field: availableFields.find((field: any) => field.name === this.getField()), + }); + } + + public setType(type: string | AggType) { + this.type = typeof type === 'string' ? getTypeFromRegistry(type) : type; + } + + public get schema() { + return this.__schema; + } + + public set schema(schema) { + this.__schema = schema; + } + + public setSchema(schema: string | Schema) { + this.schema = + typeof schema === 'string' ? getSchemaFromRegistry(this.aggConfigs.schemas, schema) : schema; + } +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts new file mode 100644 index 0000000000000..47e2222abe1e8 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts @@ -0,0 +1,318 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @name AggConfig + * + * @extends IndexedArray + * + * @description A "data structure"-like class with methods for indexing and + * accessing instances of AggConfig. + */ + +import _ from 'lodash'; +import { AggConfig, AggConfigOptions } from './agg_config'; +import { Schema } from './schemas'; +import { AggGroupNames } from './agg_groups'; +import { + IndexPattern, + ISearchSource, + FetchOptions, + TimeRange, +} from '../../../../plugins/data/public'; + +type Schemas = Record; + +function removeParentAggs(obj: any) { + for (const prop in obj) { + if (prop === 'parentAggs') delete obj[prop]; + else if (typeof obj[prop] === 'object') removeParentAggs(obj[prop]); + } +} + +function parseParentAggs(dslLvlCursor: any, dsl: any) { + if (dsl.parentAggs) { + _.each(dsl.parentAggs, (agg, key) => { + dslLvlCursor[key as string] = agg; + parseParentAggs(dslLvlCursor, agg); + }); + } +} + +export class AggConfigs { + public indexPattern: IndexPattern; + public schemas: any; + public timeRange?: TimeRange; + + aggs: AggConfig[]; + + constructor(indexPattern: IndexPattern, configStates = [] as any, schemas?: any) { + configStates = AggConfig.ensureIds(configStates); + + this.aggs = []; + this.indexPattern = indexPattern; + this.schemas = schemas; + + configStates.forEach((params: any) => this.createAggConfig(params)); + + if (this.schemas) { + this.initializeDefaultsFromSchemas(schemas); + } + } + + initializeDefaultsFromSchemas(schemas: Schemas) { + // Set the defaults for any schema which has them. If the defaults + // for some reason has more then the max only set the max number + // of defaults (not sure why a someone define more... + // but whatever). Also if a schema.name is already set then don't + // set anything. + _(schemas) + .filter((schema: Schema) => { + return Array.isArray(schema.defaults) && schema.defaults.length > 0; + }) + .each((schema: any) => { + if (!this.aggs.find((agg: AggConfig) => agg.schema && agg.schema.name === schema.name)) { + const defaults = schema.defaults.slice(0, schema.max); + _.each(defaults, defaultState => { + const state = _.defaults({ id: AggConfig.nextId(this.aggs) }, defaultState); + this.aggs.push(new AggConfig(this, state as AggConfigOptions)); + }); + } + }) + .commit(); + } + + setTimeRange(timeRange: TimeRange) { + this.timeRange = timeRange; + + const updateAggTimeRange = (agg: AggConfig) => { + _.each(agg.params, param => { + if (param instanceof AggConfig) { + updateAggTimeRange(param); + } + }); + if (_.get(agg, 'type.name') === 'date_histogram') { + agg.params.timeRange = timeRange; + } + }; + + this.aggs.forEach(updateAggTimeRange); + } + + // clone method will reuse existing AggConfig in the list (will not create new instances) + clone({ enabledOnly = true } = {}) { + const filterAggs = (agg: AggConfig) => { + if (!enabledOnly) return true; + return agg.enabled; + }; + const aggConfigs = new AggConfigs( + this.indexPattern, + this.aggs.filter(filterAggs), + this.schemas + ); + return aggConfigs; + } + + createAggConfig = ( + params: AggConfig | AggConfigOptions, + { addToAggConfigs = true } = {} + ) => { + let aggConfig; + if (params instanceof AggConfig) { + aggConfig = params; + params.parent = this; + } else { + aggConfig = new AggConfig(this, params); + } + if (addToAggConfigs) { + this.aggs.push(aggConfig); + } + return aggConfig as T; + }; + + /** + * Data-by-data comparison of this Aggregation + * Ignores the non-array indexes + * @param aggConfigs an AggConfigs instance + */ + jsonDataEquals(aggConfigs: AggConfig[]) { + if (aggConfigs.length !== this.aggs.length) { + return false; + } + for (let i = 0; i < this.aggs.length; i += 1) { + if (!_.isEqual(aggConfigs[i].toJSON(), this.aggs[i].toJSON())) { + return false; + } + } + return true; + } + + toDsl(hierarchical: boolean = false) { + const dslTopLvl = {}; + let dslLvlCursor: Record; + let nestedMetrics: Array<{ config: AggConfig; dsl: any }> | []; + + if (hierarchical) { + // collect all metrics, and filter out the ones that we won't be copying + nestedMetrics = this.aggs + .filter(function(agg) { + return agg.type.type === 'metrics' && agg.type.name !== 'count'; + }) + .map(agg => { + return { + config: agg, + dsl: agg.toDsl(this), + }; + }); + } + this.getRequestAggs() + .filter((config: AggConfig) => !config.type.hasNoDsl) + .forEach((config: AggConfig, i: number, list) => { + if (!dslLvlCursor) { + // start at the top level + dslLvlCursor = dslTopLvl; + } else { + const prevConfig: AggConfig = list[i - 1]; + const prevDsl = dslLvlCursor[prevConfig.id]; + + // advance the cursor and nest under the previous agg, or + // put it on the same level if the previous agg doesn't accept + // sub aggs + dslLvlCursor = prevDsl.aggs || dslLvlCursor; + } + + const dsl = (dslLvlCursor[config.id] = config.toDsl(this)); + let subAggs: any; + + parseParentAggs(dslLvlCursor, dsl); + + if (config.type.type === AggGroupNames.Buckets && i < list.length - 1) { + // buckets that are not the last item in the list accept sub-aggs + subAggs = dsl.aggs || (dsl.aggs = {}); + } + + if (subAggs && nestedMetrics) { + nestedMetrics.forEach((agg: any) => { + subAggs[agg.config.id] = agg.dsl; + // if a nested metric agg has parent aggs, we have to add them to every level of the tree + // to make sure "bucket_path" references in the nested metric agg itself are still working + if (agg.dsl.parentAggs) { + Object.entries(agg.dsl.parentAggs).forEach(([parentAggId, parentAgg]) => { + subAggs[parentAggId] = parentAgg; + }); + } + }); + } + }); + + removeParentAggs(dslTopLvl); + return dslTopLvl; + } + + getAll() { + return [...this.aggs]; + } + + byIndex(index: number) { + return this.aggs[index]; + } + + byId(id: string) { + return this.aggs.find(agg => agg.id === id); + } + + byName(name: string) { + return this.aggs.filter(agg => agg.type.name === name); + } + + byType(type: string) { + return this.aggs.filter(agg => agg.type.type === type); + } + + byTypeName(type: string) { + return this.aggs.filter(agg => agg.type.name === type); + } + + bySchemaName(schema: string) { + return this.aggs.filter(agg => agg.schema && agg.schema.name === schema); + } + + bySchemaGroup(group: string) { + return this.aggs.filter(agg => agg.schema && agg.schema.group === group); + } + + getRequestAggs(): AggConfig[] { + // collect all the aggregations + const aggregations = this.aggs + .filter(agg => agg.enabled && agg.type) + .reduce((requestValuesAggs, agg: AggConfig) => { + const aggs = agg.getRequestAggs(); + return aggs ? requestValuesAggs.concat(aggs) : requestValuesAggs; + }, [] as AggConfig[]); + // move metrics to the end + return _.sortBy(aggregations, (agg: AggConfig) => + agg.type.type === AggGroupNames.Metrics ? 1 : 0 + ); + } + + getRequestAggById(id: string) { + return this.aggs.find((agg: AggConfig) => agg.id === id); + } + + /** + * Gets the AggConfigs (and possibly ResponseAggConfigs) that + * represent the values that will be produced when all aggs + * are run. + * + * With multi-value metric aggs it is possible for a single agg + * request to result in multiple agg values, which is why the length + * of a vis' responseValuesAggs may be different than the vis' aggs + * + * @return {array[AggConfig]} + */ + getResponseAggs(): AggConfig[] { + return this.getRequestAggs().reduce(function(responseValuesAggs, agg: AggConfig) { + const aggs = agg.getResponseAggs(); + return aggs ? responseValuesAggs.concat(aggs) : responseValuesAggs; + }, [] as AggConfig[]); + } + + /** + * Find a response agg by it's id. This may be an agg in the aggConfigs, or one + * created specifically for a response value + * + * @param {string} id - the id of the agg to find + * @return {AggConfig} + */ + getResponseAggById(id: string): AggConfig | undefined { + id = String(id); + const reqAgg = _.find(this.getRequestAggs(), function(agg: AggConfig) { + return id.substr(0, String(agg.id).length) === agg.id; + }); + if (!reqAgg) return; + return _.find(reqAgg.getResponseAggs(), { id }); + } + + onSearchRequestStart(searchSource: ISearchSource, options?: FetchOptions) { + return Promise.all( + // @ts-ignore + this.getRequestAggs().map((agg: AggConfig) => agg.onSearchRequestStart(searchSource, options)) + ); + } +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts new file mode 100644 index 0000000000000..d08e875bf213e --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { $Values } from '@kbn/utility-types'; + +export const AggGroupNames = Object.freeze({ + Buckets: 'buckets' as 'buckets', + Metrics: 'metrics' as 'metrics', + None: 'none' as 'none', +}); +export type AggGroupNames = $Values; + +export const aggGroupNamesMap = () => ({ + [AggGroupNames.Metrics]: i18n.translate('common.ui.aggTypes.aggGroups.metricsText', { + defaultMessage: 'Metrics', + }), + [AggGroupNames.Buckets]: i18n.translate('common.ui.aggTypes.aggGroups.bucketsText', { + defaultMessage: 'Buckets', + }), +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts new file mode 100644 index 0000000000000..25e62e06d52d7 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts @@ -0,0 +1,84 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { initParams } from './agg_params'; +import { BaseParamType } from './param_types/base'; +import { FieldParamType } from './param_types/field'; +import { OptionedParamType } from './param_types/optioned'; +import { AggParamType } from '../agg_types/param_types/agg'; + +jest.mock('ui/new_platform'); + +describe('AggParams class', () => { + describe('constructor args', () => { + it('accepts an array of param defs', () => { + const params = [{ name: 'one' }, { name: 'two' }] as AggParamType[]; + const aggParams = initParams(params); + + expect(aggParams).toHaveLength(params.length); + expect(Array.isArray(aggParams)).toBeTruthy(); + }); + }); + + describe('AggParam creation', () => { + it('Uses the FieldParamType class for params with the name "field"', () => { + const params = [{ name: 'field', type: 'field' }] as AggParamType[]; + const aggParams = initParams(params); + + expect(aggParams).toHaveLength(params.length); + expect(aggParams[0] instanceof FieldParamType).toBeTruthy(); + }); + + it('Uses the OptionedParamType class for params of type "optioned"', () => { + const params = [ + { + name: 'order', + type: 'optioned', + }, + ] as AggParamType[]; + const aggParams = initParams(params); + + expect(aggParams).toHaveLength(params.length); + expect(aggParams[0] instanceof OptionedParamType).toBeTruthy(); + }); + + it('Always converts the params to a BaseParamType', function() { + const params = [ + { + name: 'height', + displayName: 'height', + }, + { + name: 'weight', + displayName: 'weight', + }, + { + name: 'waist', + displayName: 'waist', + }, + ] as AggParamType[]; + + const aggParams = initParams(params); + + expect(aggParams).toHaveLength(params.length); + + aggParams.forEach(aggParam => expect(aggParam instanceof BaseParamType).toBeTruthy()); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_params.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_params.ts new file mode 100644 index 0000000000000..262a57f4a5aa3 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_params.ts @@ -0,0 +1,93 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AggParamType } from './param_types/agg'; +import { FieldParamType } from './param_types/field'; +import { OptionedParamType } from './param_types/optioned'; +import { StringParamType } from './param_types/string'; +import { JsonParamType } from './param_types/json'; +import { BaseParamType } from './param_types/base'; + +import { AggConfig } from './agg_config'; +import { AggConfigs } from './agg_configs'; + +const paramTypeMap = { + field: FieldParamType, + optioned: OptionedParamType, + string: StringParamType, + json: JsonParamType, + agg: AggParamType, + _default: BaseParamType, +} as Record; + +export type AggParam = BaseParamType; + +export interface AggParamOption { + val: string; + display: string; + enabled?(agg: AggConfig): boolean; +} + +export const initParams = ( + params: TAggParam[] +): TAggParam[] => + params.map((config: TAggParam) => { + const Class = paramTypeMap[config.type] || paramTypeMap._default; + + return new Class(config); + }) as TAggParam[]; + +/** + * Reads an aggConfigs + * + * @method write + * @param {AggConfig} aggConfig + * the AggConfig object who's type owns these aggParams and contains the param values for our param defs + * @param {object} [locals] + * an array of locals that will be available to the write function (can be used to enhance + * the quality of things like date_histogram's "auto" interval) + * @return {object} output + * output of the write calls, reduced into a single object. A `params: {}` property is exposed on the + * output object which is used to create the agg dsl for the search request. All other properties + * are dependent on the AggParam#write methods which should be studied for each AggType. + */ +export const writeParams = < + TAggConfig extends AggConfig = AggConfig, + TAggParam extends AggParamType = AggParamType +>( + params: Array> = [], + aggConfig: TAggConfig, + aggs?: AggConfigs, + locals?: Record +) => { + const output = { params: {} as Record }; + locals = locals || {}; + + params.forEach(param => { + if (param.write) { + param.write(aggConfig, output, aggs, locals); + } else { + if (param && param.name) { + output.params[param.name] = aggConfig.params[param.name]; + } + } + }); + + return output; +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts new file mode 100644 index 0000000000000..9b34910e81e88 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts @@ -0,0 +1,169 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AggType, AggTypeConfig } from './agg_type'; +import { AggConfig } from './agg_config'; +import { npStart } from 'ui/new_platform'; + +jest.mock('ui/new_platform'); + +describe('AggType Class', () => { + describe('constructor', () => { + it("requires a valid config object as it's first param", () => { + expect(() => { + const aggConfig: AggTypeConfig = (undefined as unknown) as AggTypeConfig; + new AggType(aggConfig); + }).toThrowError(); + }); + + describe('application of config properties', () => { + it('assigns the config value to itself', () => { + const config: AggTypeConfig = { + name: 'name', + title: 'title', + }; + + const aggType = new AggType(config); + + expect(aggType.name).toBe('name'); + expect(aggType.title).toBe('title'); + }); + + describe('makeLabel', () => { + it('makes a function when the makeLabel config is not specified', () => { + const makeLabel = () => 'label'; + const aggConfig = {} as AggConfig; + const config: AggTypeConfig = { + name: 'name', + title: 'title', + makeLabel, + }; + + const aggType = new AggType(config); + + expect(aggType.makeLabel).toBe(makeLabel); + expect(aggType.makeLabel(aggConfig)).toBe('label'); + }); + }); + + describe('getResponseAggs/getRequestAggs', () => { + it('copies the value', () => { + const testConfig = (aggConfig: AggConfig) => [aggConfig]; + + const aggType = new AggType({ + name: 'name', + title: 'title', + getResponseAggs: testConfig, + getRequestAggs: testConfig, + }); + + expect(aggType.getResponseAggs).toBe(testConfig); + expect(aggType.getResponseAggs).toBe(testConfig); + }); + + it('defaults to noop', () => { + const aggConfig = {} as AggConfig; + const aggType = new AggType({ + name: 'name', + title: 'title', + }); + const responseAggs = aggType.getRequestAggs(aggConfig); + + expect(responseAggs).toBe(undefined); + }); + }); + + describe('params', () => { + it('defaults to AggParams object with JSON param', () => { + const aggType = new AggType({ + name: 'smart agg', + title: 'title', + }); + + expect(Array.isArray(aggType.params)).toBeTruthy(); + expect(aggType.params.length).toBe(2); + expect(aggType.params[0].name).toBe('json'); + expect(aggType.params[1].name).toBe('customLabel'); + }); + + it('can disable customLabel', () => { + const aggType = new AggType({ + name: 'smart agg', + title: 'title', + customLabels: false, + }); + + expect(aggType.params.length).toBe(1); + expect(aggType.params[0].name).toBe('json'); + }); + + it('passes the params arg directly to the AggParams constructor', () => { + const params = [{ name: 'one' }, { name: 'two' }]; + const paramLength = params.length + 2; // json and custom label are always appended + + const aggType = new AggType({ + name: 'bucketeer', + title: 'title', + params, + }); + + expect(Array.isArray(aggType.params)).toBeTruthy(); + expect(aggType.params.length).toBe(paramLength); + }); + }); + }); + + describe('getFormat', function() { + let aggConfig: AggConfig; + let field: any; + + beforeEach(() => { + aggConfig = ({ + getField: jest.fn(() => field), + } as unknown) as AggConfig; + }); + + it('returns the formatter for the aggConfig', () => { + const aggType = new AggType({ + name: 'name', + title: 'title', + }); + + field = { + format: 'format', + }; + + expect(aggType.getFormat(aggConfig)).toBe('format'); + }); + + it('returns default formatter', () => { + npStart.plugins.data.fieldFormats.getDefaultInstance = jest.fn(() => 'default') as any; + + const aggType = new AggType({ + name: 'name', + title: 'title', + }); + + field = undefined; + + expect(aggType.getFormat(aggConfig)).toBe('default'); + }); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts new file mode 100644 index 0000000000000..7ec688277b9c4 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts @@ -0,0 +1,260 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { constant, noop, identity } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { npStart } from 'ui/new_platform'; +import { initParams } from './agg_params'; + +import { AggConfig } from './agg_config'; +import { AggConfigs } from './agg_configs'; +import { Adapters } from '../../../../plugins/inspector/public'; +import { BaseParamType } from './param_types/base'; +import { AggParamType } from '../agg_types/param_types/agg'; +import { KBN_FIELD_TYPES, fieldFormats, ISearchSource } from '../../../../plugins/data/public'; + +export interface AggTypeConfig< + TAggConfig extends AggConfig = AggConfig, + TParam extends AggParamType = AggParamType +> { + name: string; + title: string; + createFilter?: (aggConfig: TAggConfig, key: any, params?: any) => any; + type?: string; + dslName?: string; + makeLabel?: ((aggConfig: TAggConfig) => string) | (() => string); + ordered?: any; + hasNoDsl?: boolean; + params?: Array>; + getRequestAggs?: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); + getResponseAggs?: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); + customLabels?: boolean; + decorateAggConfig?: () => any; + postFlightRequest?: ( + resp: any, + aggConfigs: AggConfigs, + aggConfig: TAggConfig, + searchSource: ISearchSource, + inspectorAdapters: Adapters, + abortSignal?: AbortSignal + ) => Promise; + getFormat?: (agg: TAggConfig) => fieldFormats.FieldFormat; + getValue?: (agg: TAggConfig, bucket: any) => any; + getKey?: (bucket: any, key: any, agg: TAggConfig) => any; +} + +const getFormat = (agg: AggConfig) => { + const field = agg.getField(); + const fieldFormatsService = npStart.plugins.data.fieldFormats; + + return field ? field.format : fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.STRING); +}; + +export class AggType< + TAggConfig extends AggConfig = AggConfig, + TParam extends AggParamType = AggParamType +> { + /** + * the unique, unchanging, name that we have assigned this aggType + * + * @property name + * @type {string} + */ + name: string; + + type: string; + subtype?: string; + /** + * the name of the elasticsearch aggregation that this aggType represents. Usually just this.name + * + * @property name + * @type {string} + */ + dslName: string; + /** + * the user friendly name that will be shown in the ui for this aggType + * + * @property title + * @type {string} + */ + title: string; + /** + * 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 describe the aggConfig + */ + makeLabel: ((aggConfig: TAggConfig) => string) | (() => string); + /** + * 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 "falsy". + * + * 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} + */ + ordered: any; + /** + * 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} + */ + hasNoDsl: boolean; + /** + * 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 + */ + createFilter: ((aggConfig: TAggConfig, key: any, params?: any) => any) | undefined; + /** + * An instance of {{#crossLink "AggParams"}}{{/crossLink}}. + * + * @property params + * @type {AggParams} + */ + params: TParam[]; + /** + * 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]} - an array of aggConfig objects + * that should replace this one, + * or undefined + */ + getRequestAggs: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); + /** + * 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 + */ + getResponseAggs: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); + /** + * 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 + */ + decorateAggConfig: () => any; + /** + * 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} + */ + postFlightRequest: ( + resp: any, + aggConfigs: AggConfigs, + aggConfig: TAggConfig, + searchSource: ISearchSource, + inspectorAdapters: Adapters, + abortSignal?: AbortSignal + ) => Promise; + /** + * Pick a format for the values produced by this agg type, + * overridden by several metrics that always output a simple + * number + * + * @param {agg} agg - the agg to pick a format for + * @return {FieldFormat} + */ + getFormat: (agg: TAggConfig) => fieldFormats.FieldFormat; + + getValue: (agg: TAggConfig, bucket: any) => any; + + getKey?: (bucket: any, key: any, agg: TAggConfig) => any; + + paramByName = (name: string) => { + return this.params.find((p: TParam) => p.name === name); + }; + + /** + * 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 + */ + constructor(config: AggTypeConfig) { + this.name = config.name; + this.type = config.type || 'metrics'; + this.dslName = config.dslName || config.name; + this.title = config.title; + this.makeLabel = config.makeLabel || constant(this.name); + this.ordered = config.ordered; + this.hasNoDsl = !!config.hasNoDsl; + + if (config.createFilter) { + this.createFilter = config.createFilter; + } + + if (config.params && config.params.length && config.params[0] instanceof BaseParamType) { + this.params = config.params as TParam[]; + } else { + // always append the raw JSON param + const params: any[] = config.params ? [...config.params] : []; + params.push({ + name: 'json', + type: 'json', + advanced: true, + }); + // always append custom label + + if (config.customLabels !== false) { + params.push({ + name: 'customLabel', + displayName: i18n.translate('common.ui.aggTypes.string.customLabel', { + defaultMessage: 'Custom label', + }), + type: 'string', + write: noop, + }); + } + + this.params = initParams(params); + } + + this.getRequestAggs = config.getRequestAggs || noop; + this.getResponseAggs = config.getResponseAggs || (() => {}); + this.decorateAggConfig = config.decorateAggConfig || (() => ({})); + this.postFlightRequest = config.postFlightRequest || identity; + this.getFormat = config.getFormat || getFormat; + this.getValue = config.getValue || ((agg: TAggConfig, bucket: any) => {}); + } +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts new file mode 100644 index 0000000000000..9b7c97a8f11b6 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts @@ -0,0 +1,62 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AggConfig } from '../agg_config'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { AggType, AggTypeConfig } from '../agg_type'; +import { AggParamType } from '../param_types/agg'; + +export interface IBucketAggConfig extends AggConfig { + type: InstanceType; +} + +export interface BucketAggParam + extends AggParamType { + scriptable?: boolean; + filterFieldTypes?: KBN_FIELD_TYPES | KBN_FIELD_TYPES[] | '*'; +} + +const bucketType = 'buckets'; + +interface BucketAggTypeConfig + extends AggTypeConfig> { + getKey?: (bucket: any, key: any, agg: AggConfig) => any; +} + +export class BucketAggType extends AggType< + TBucketAggConfig, + BucketAggParam +> { + getKey: (bucket: any, key: any, agg: TBucketAggConfig) => any; + type = bucketType; + + constructor(config: BucketAggTypeConfig) { + super(config); + + this.getKey = + config.getKey || + ((bucket, key) => { + return key || bucket.key; + }); + } +} + +export function isBucketAggType(aggConfig: any): aggConfig is BucketAggType { + return aggConfig && aggConfig.type === bucketType; +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts new file mode 100644 index 0000000000000..01d0abb7a366c --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts @@ -0,0 +1,82 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { i18n } from '@kbn/i18n'; +import { IBucketAggConfig } from './_bucket_agg_type'; + +export const intervalOptions = [ + { + display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.autoDisplayName', { + defaultMessage: 'Auto', + }), + val: 'auto', + enabled(agg: IBucketAggConfig) { + // not only do we need a time field, but the selected field needs + // to be the time field. (see #3028) + return agg.fieldIsTimeField(); + }, + }, + { + display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.millisecondDisplayName', { + defaultMessage: 'Millisecond', + }), + val: 'ms', + }, + { + display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.secondDisplayName', { + defaultMessage: 'Second', + }), + val: 's', + }, + { + display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.minuteDisplayName', { + defaultMessage: 'Minute', + }), + val: 'm', + }, + { + display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.hourlyDisplayName', { + defaultMessage: 'Hourly', + }), + val: 'h', + }, + { + display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.dailyDisplayName', { + defaultMessage: 'Daily', + }), + val: 'd', + }, + { + display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.weeklyDisplayName', { + defaultMessage: 'Weekly', + }), + val: 'w', + }, + { + display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.monthlyDisplayName', { + defaultMessage: 'Monthly', + }), + val: 'M', + }, + { + display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.yearlyDisplayName', { + defaultMessage: 'Yearly', + }), + val: 'y', + }, +]; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js b/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js new file mode 100644 index 0000000000000..c8580183756f4 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js @@ -0,0 +1,261 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import _ from 'lodash'; +import { esFilters, esQuery } from '../../../../../plugins/data/public'; +import { AggGroupNames } from '../agg_groups'; + +/** + * walks the aggregation DSL and returns DSL starting at aggregation with id of startFromAggId + * @param aggNestedDsl: aggregation config DSL (top level) + * @param startFromId: id of an aggregation from where we want to get the nested DSL + */ +const getNestedAggDSL = (aggNestedDsl, startFromAggId) => { + if (aggNestedDsl[startFromAggId]) { + return aggNestedDsl[startFromAggId]; + } + const nestedAggs = _.values(aggNestedDsl); + let aggs; + for (let i = 0; i < nestedAggs.length; i++) { + if (nestedAggs[i].aggs && (aggs = getNestedAggDSL(nestedAggs[i].aggs, startFromAggId))) { + return aggs; + } + } +}; + +/** + * returns buckets from response for a specific other bucket + * @param aggConfigs: configuration for the aggregations + * @param response: response from elasticsearch + * @param aggWithOtherBucket: AggConfig of the aggregation with other bucket enabled + * @param key: key from the other bucket request for a specific other bucket + */ +const getAggResultBuckets = (aggConfigs, response, aggWithOtherBucket, key) => { + const keyParts = key.split('-'); + let responseAgg = response; + for (const i in keyParts) { + if (keyParts[i]) { + const responseAggs = _.values(responseAgg); + // If you have multi aggs, we cannot just assume the first one is the `other` bucket, + // so we need to loop over each agg until we find it. + for (let aggId = 0; aggId < responseAggs.length; aggId++) { + const agg = responseAggs[aggId]; + const aggKey = _.keys(responseAgg)[aggId]; + const aggConfig = _.find(aggConfigs.aggs, agg => agg.id === aggKey); + const bucket = _.find(agg.buckets, (bucket, bucketObjKey) => { + const bucketKey = aggConfig + .getKey(bucket, Number.isInteger(bucketObjKey) ? null : bucketObjKey) + .toString(); + return bucketKey === keyParts[i]; + }); + if (bucket) { + responseAgg = bucket; + break; + } + } + } + } + if (responseAgg[aggWithOtherBucket.id]) { + return responseAgg[aggWithOtherBucket.id].buckets; + } + return []; +}; + +/** + * gets all the missing buckets in our response for a specific aggregation id + * @param responseAggs: array of aggregations from response + * @param aggId: id of the aggregation with missing bucket + */ +const getAggConfigResultMissingBuckets = (responseAggs, aggId) => { + const missingKey = '__missing__'; + let resultBuckets = []; + if (responseAggs[aggId]) { + const matchingBucket = responseAggs[aggId].buckets.find(bucket => bucket.key === missingKey); + if (matchingBucket) resultBuckets.push(matchingBucket); + return resultBuckets; + } + _.each(responseAggs, agg => { + if (agg.buckets) { + _.each(agg.buckets, bucket => { + resultBuckets = [ + ...resultBuckets, + ...getAggConfigResultMissingBuckets(bucket, aggId, missingKey), + ]; + }); + } + }); + + return resultBuckets; +}; + +/** + * gets all the terms that are NOT in the other bucket + * @param requestAgg: an aggregation we are looking at + * @param key: the key for this specific other bucket + * @param otherAgg: AggConfig of the aggregation with other bucket + */ +const getOtherAggTerms = (requestAgg, key, otherAgg) => { + return requestAgg['other-filter'].filters.filters[key].bool.must_not + .filter(filter => filter.match_phrase && filter.match_phrase[otherAgg.params.field.name]) + .map(filter => filter.match_phrase[otherAgg.params.field.name]); +}; + +export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => { + const bucketAggs = aggConfigs.aggs.filter(agg => agg.type.type === AggGroupNames.Buckets); + const index = bucketAggs.findIndex(agg => agg.id === aggWithOtherBucket.id); + const aggs = aggConfigs.toDsl(); + const indexPattern = aggWithOtherBucket.params.field.indexPattern; + + // create filters aggregation + const filterAgg = aggConfigs.createAggConfig( + { + type: 'filters', + id: 'other', + params: { + filters: [], + }, + }, + { + addToAggConfigs: false, + } + ); + + // nest all the child aggregations of aggWithOtherBucket + const resultAgg = { + aggs: getNestedAggDSL(aggs, aggWithOtherBucket.id).aggs, + filters: filterAgg.toDsl(), + }; + + let noAggBucketResults = false; + + // recursively create filters for all parent aggregation buckets + const walkBucketTree = (aggIndex, aggs, aggId, filters, key) => { + // make sure there are actually results for the buckets + if (aggs[aggId].buckets.length < 1) { + noAggBucketResults = true; + return; + } + + 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.filters) || currentAgg.createFilter(bucketKey); + const newFilters = _.flatten([...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( + esFilters.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); + }); + + resultAgg.filters.filters[key] = { + bool: esQuery.buildQueryFromFilters(filters, indexPattern), + }; + }; + walkBucketTree(0, response.aggregations, bucketAggs[0].id, [], ''); + + // bail if there were no bucket results + if (noAggBucketResults) { + return false; + } + + return () => { + return { + 'other-filter': resultAgg, + }; + }; +}; + +export 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 = esFilters.buildPhrasesFilter( + otherAgg.params.field, + requestFilterTerms, + otherAgg.params.field.indexPattern + ); + phraseFilter.meta.negate = true; + bucket.filters = [phraseFilter]; + bucket.key = '__other__'; + + if (aggResultBuckets.some(bucket => bucket.key === '__missing__')) { + bucket.filters.push( + esFilters.buildExistsFilter(otherAgg.params.field, otherAgg.params.field.indexPattern) + ); + } + aggResultBuckets.push(bucket); + }); + return updatedResponse; +}; + +export const updateMissingBucket = (response, aggConfigs, agg) => { + const updatedResponse = _.cloneDeep(response); + const aggResultBuckets = getAggConfigResultMissingBuckets(updatedResponse.aggregations, agg.id); + aggResultBuckets.forEach(bucket => { + bucket.key = '__missing__'; + }); + return updatedResponse; +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/bucket_agg_types.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/bucket_agg_types.ts new file mode 100644 index 0000000000000..a1321722cf294 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/bucket_agg_types.ts @@ -0,0 +1,32 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export enum BUCKET_TYPES { + FILTER = 'filter', + FILTERS = 'filters', + HISTOGRAM = 'histogram', + IP_RANGE = 'ip_range', + DATE_RANGE = 'date_range', + RANGE = 'range', + TERMS = 'terms', + SIGNIFICANT_TERMS = 'significant_terms', + GEOHASH_GRID = 'geohash_grid', + GEOTILE_GRID = 'geotile_grid', + DATE_HISTOGRAM = 'date_histogram', +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts new file mode 100644 index 0000000000000..9426df7d34c29 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts @@ -0,0 +1,122 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import moment from 'moment'; +import { createFilterDateHistogram } from './date_histogram'; +import { intervalOptions } from '../_interval_options'; +import { AggConfigs } from '../../agg_configs'; +import { IBucketDateHistogramAggConfig } from '../date_histogram'; +import { BUCKET_TYPES } from '../bucket_agg_types'; +import { esFilters } from '../../../../../../plugins/data/public'; + +jest.mock('ui/new_platform'); + +describe('AggConfig Filters', () => { + describe('date_histogram', () => { + let agg: IBucketDateHistogramAggConfig; + let filter: esFilters.RangeFilter; + let bucketStart: any; + let field: any; + + const init = (interval: string = 'auto', duration: any = moment.duration(15, 'minutes')) => { + field = { + name: 'date', + }; + + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + const aggConfigs = new AggConfigs( + indexPattern, + [ + { + type: BUCKET_TYPES.DATE_HISTOGRAM, + schema: 'segment', + params: { field: field.name, interval, customInterval: '5d' }, + }, + ], + null + ); + const bucketKey = 1422579600000; + + agg = aggConfigs.aggs[0] as IBucketDateHistogramAggConfig; + bucketStart = moment(bucketKey); + + const timePad = moment.duration(duration / 2); + + agg.buckets.setBounds({ + min: bucketStart.clone().subtract(timePad), + max: bucketStart.clone().add(timePad), + }); + agg.buckets.setInterval(interval); + filter = createFilterDateHistogram(agg, bucketKey); + }; + + it('creates a valid range filter', () => { + init(); + + expect(filter).toHaveProperty('range'); + expect(filter.range).toHaveProperty(field.name); + + const fieldParams = filter.range[field.name]; + expect(fieldParams).toHaveProperty('gte'); + expect(typeof fieldParams.gte).toBe('string'); + + expect(fieldParams).toHaveProperty('lt'); + expect(typeof fieldParams.lt).toBe('string'); + + expect(fieldParams).toHaveProperty('format'); + expect(fieldParams.format).toBe('strict_date_optional_time'); + + expect(filter).toHaveProperty('meta'); + expect(filter.meta).toHaveProperty('index', '1234'); + }); + + it('extends the filter edge to 1ms before the next bucket for all interval options', () => { + intervalOptions.forEach(option => { + let duration; + if (option.val !== 'custom' && moment(1, option.val).isValid()) { + // @ts-ignore + duration = moment.duration(10, option.val); + + if (+duration < 10) { + throw new Error('unable to create interval for ' + option.val); + } + } + init(option.val, duration); + + const interval = agg.buckets.getInterval(); + const params = filter.range[field.name]; + + expect(params.gte).toBe(bucketStart.toISOString()); + expect(params.lt).toBe( + bucketStart + .clone() + .add(interval) + .toISOString() + ); + }); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts new file mode 100644 index 0000000000000..f91a92eab1c33 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts @@ -0,0 +1,40 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import moment from 'moment'; +import { IBucketDateHistogramAggConfig } from '../date_histogram'; +import { esFilters } from '../../../../../../plugins/data/public'; + +export const createFilterDateHistogram = ( + agg: IBucketDateHistogramAggConfig, + key: string | number +) => { + const start = moment(key); + const interval = agg.buckets.getInterval(); + + return esFilters.buildRangeFilter( + agg.params.field, + { + gte: start.toISOString(), + lt: start.add(interval).toISOString(), + format: 'strict_date_optional_time', + }, + agg.getIndexPattern() + ); +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts new file mode 100644 index 0000000000000..9c2c4f72704f4 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts @@ -0,0 +1,79 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import moment from 'moment'; +import { createFilterDateRange } from './date_range'; +import { fieldFormats } from '../../../../../../plugins/data/public'; +import { AggConfigs } from '../../agg_configs'; +import { BUCKET_TYPES } from '../bucket_agg_types'; +import { IBucketAggConfig } from '../_bucket_agg_type'; + +jest.mock('ui/new_platform'); + +describe('AggConfig Filters', () => { + describe('Date range', () => { + const getConfig = (() => {}) as fieldFormats.GetConfigFn; + const getAggConfigs = () => { + const field = { + name: '@timestamp', + format: new fieldFormats.DateFormat({}, getConfig), + }; + + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + return new AggConfigs( + indexPattern, + [ + { + type: BUCKET_TYPES.DATE_RANGE, + params: { + field: '@timestamp', + ranges: [{ from: '2014-01-01', to: '2014-12-31' }], + }, + }, + ], + null + ); + }; + + it('should return a range filter for date_range agg', () => { + const aggConfigs = getAggConfigs(); + const from = new Date('1 Feb 2015'); + const to = new Date('7 Feb 2015'); + const filter = createFilterDateRange(aggConfigs.aggs[0] as IBucketAggConfig, { + from: from.valueOf(), + to: to.valueOf(), + }); + + expect(filter).toHaveProperty('range'); + expect(filter).toHaveProperty('meta'); + expect(filter.meta).toHaveProperty('index', '1234'); + expect(filter.range).toHaveProperty('@timestamp'); + expect(filter.range['@timestamp']).toHaveProperty('gte', moment(from).toISOString()); + expect(filter.range['@timestamp']).toHaveProperty('lt', moment(to).toISOString()); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts new file mode 100644 index 0000000000000..01689d954a072 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts @@ -0,0 +1,32 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import moment from 'moment'; +import { IBucketAggConfig } from '../_bucket_agg_type'; +import { DateRangeKey } from '../date_range'; +import { esFilters } from '../../../../../../plugins/data/public'; + +export const createFilterDateRange = (agg: IBucketAggConfig, { from, to }: DateRangeKey) => { + const filter: esFilters.RangeFilterParams = {}; + if (from) filter.gte = moment(from).toISOString(); + if (to) filter.lt = moment(to).toISOString(); + if (to && from) filter.format = 'strict_date_optional_time'; + + return esFilters.buildRangeFilter(agg.params.field, filter, agg.getIndexPattern()); +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts new file mode 100644 index 0000000000000..34cf996826865 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts @@ -0,0 +1,67 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { createFilterFilters } from './filters'; +import { AggConfigs } from '../../agg_configs'; +import { IBucketAggConfig } from '../_bucket_agg_type'; + +jest.mock('ui/new_platform'); + +describe('AggConfig Filters', () => { + describe('filters', () => { + const getAggConfigs = () => { + const field = { + name: 'bytes', + }; + + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + return new AggConfigs( + indexPattern, + [ + { + type: 'filters', + schema: 'segment', + params: { + filters: [ + { input: { query: 'type:apache', language: 'lucene' } }, + { input: { query: 'type:nginx', language: 'lucene' } }, + ], + }, + }, + ], + null + ); + }; + it('should return a filters filter', () => { + const aggConfigs = getAggConfigs(); + const filter = createFilterFilters(aggConfigs.aggs[0] as IBucketAggConfig, 'type:nginx'); + + expect(filter!.query.bool.must[0].query_string.query).toBe('type:nginx'); + expect(filter!.meta).toHaveProperty('index', '1234'); + expect(filter!.meta).toHaveProperty('alias', 'type:nginx'); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts new file mode 100644 index 0000000000000..6b614514580b6 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { get } from 'lodash'; +import { IBucketAggConfig } from '../_bucket_agg_type'; +import { esFilters } from '../../../../../../plugins/data/public'; + +export const createFilterFilters = (aggConfig: IBucketAggConfig, key: string) => { + // have the aggConfig write agg dsl params + const dslFilters: any = get(aggConfig.toDsl(), 'filters.filters'); + const filter = dslFilters[key]; + const indexPattern = aggConfig.getIndexPattern(); + + if (filter && indexPattern && indexPattern.id) { + return esFilters.buildQueryFilter(filter.query, indexPattern.id, key); + } +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts new file mode 100644 index 0000000000000..ef49636f9e0c1 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts @@ -0,0 +1,75 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { createFilterHistogram } from './histogram'; +import { AggConfigs } from '../../agg_configs'; +import { BUCKET_TYPES } from '../bucket_agg_types'; +import { IBucketAggConfig } from '../_bucket_agg_type'; +import { fieldFormats } from '../../../../../../plugins/data/public'; + +jest.mock('ui/new_platform'); + +describe('AggConfig Filters', () => { + describe('histogram', () => { + const getConfig = (() => {}) as fieldFormats.GetConfigFn; + const getAggConfigs = () => { + const field = { + name: 'bytes', + format: new fieldFormats.BytesFormat({}, getConfig), + }; + + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + return new AggConfigs( + indexPattern, + [ + { + id: BUCKET_TYPES.HISTOGRAM, + type: BUCKET_TYPES.HISTOGRAM, + schema: 'buckets', + params: { + field: 'bytes', + interval: 1024, + }, + }, + ], + null + ); + }; + + it('should return an range filter for histogram', () => { + const aggConfigs = getAggConfigs(); + const filter = createFilterHistogram(aggConfigs.aggs[0] as IBucketAggConfig, '2048'); + + expect(filter).toHaveProperty('meta'); + expect(filter.meta).toHaveProperty('index', '1234'); + expect(filter).toHaveProperty('range'); + expect(filter.range).toHaveProperty('bytes'); + expect(filter.range.bytes).toHaveProperty('gte', 2048); + expect(filter.range.bytes).toHaveProperty('lt', 3072); + expect(filter.meta).toHaveProperty('formattedValue', '2,048'); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts new file mode 100644 index 0000000000000..fc587fa9ecdb6 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IBucketAggConfig } from '../_bucket_agg_type'; +import { esFilters } from '../../../../../../plugins/data/public'; + +export const createFilterHistogram = (aggConfig: IBucketAggConfig, key: string) => { + const value = parseInt(key, 10); + const params: esFilters.RangeFilterParams = { gte: value, lt: value + aggConfig.params.interval }; + + return esFilters.buildRangeFilter( + aggConfig.params.field, + params, + aggConfig.getIndexPattern(), + aggConfig.fieldFormatter()(key) + ); +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts new file mode 100644 index 0000000000000..a9eca3bbb7a56 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts @@ -0,0 +1,105 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { createFilterIpRange } from './ip_range'; +import { AggConfigs } from '../../agg_configs'; +import { fieldFormats } from '../../../../../../plugins/data/public'; +import { BUCKET_TYPES } from '../bucket_agg_types'; +import { IBucketAggConfig } from '../_bucket_agg_type'; + +jest.mock('ui/new_platform'); + +describe('AggConfig Filters', () => { + describe('IP range', () => { + const getAggConfigs = (aggs: Array>) => { + const field = { + name: 'ip', + format: fieldFormats.IpFormat, + }; + + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + return new AggConfigs(indexPattern, aggs, null); + }; + + it('should return a range filter for ip_range agg', () => { + const aggConfigs = getAggConfigs([ + { + type: BUCKET_TYPES.IP_RANGE, + schema: 'segment', + params: { + field: 'ip', + ipRangeType: 'range', + ranges: { + fromTo: [{ from: '0.0.0.0', to: '1.1.1.1' }], + }, + }, + }, + ]); + + const filter = createFilterIpRange(aggConfigs.aggs[0] as IBucketAggConfig, { + type: 'range', + from: '0.0.0.0', + to: '1.1.1.1', + }); + + expect(filter).toHaveProperty('range'); + expect(filter).toHaveProperty('meta'); + expect(filter.meta).toHaveProperty('index', '1234'); + expect(filter.range).toHaveProperty('ip'); + expect(filter.range.ip).toHaveProperty('gte', '0.0.0.0'); + expect(filter.range.ip).toHaveProperty('lte', '1.1.1.1'); + }); + + it('should return a range filter for ip_range agg using a CIDR mask', () => { + const aggConfigs = getAggConfigs([ + { + type: BUCKET_TYPES.IP_RANGE, + schema: 'segment', + params: { + field: 'ip', + ipRangeType: 'mask', + ranges: { + mask: [{ mask: '67.129.65.201/27' }], + }, + }, + }, + ]); + + const filter = createFilterIpRange(aggConfigs.aggs[0] as IBucketAggConfig, { + type: 'mask', + mask: '67.129.65.201/27', + }); + + expect(filter).toHaveProperty('range'); + expect(filter).toHaveProperty('meta'); + expect(filter.meta).toHaveProperty('index', '1234'); + expect(filter.range).toHaveProperty('ip'); + expect(filter.range.ip).toHaveProperty('gte', '67.129.65.192'); + expect(filter.range.ip).toHaveProperty('lte', '67.129.65.223'); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts new file mode 100644 index 0000000000000..a513b8c782739 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts @@ -0,0 +1,42 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { CidrMask } from '../lib/cidr_mask'; +import { IBucketAggConfig } from '../_bucket_agg_type'; +import { IpRangeKey } from '../ip_range'; +import { esFilters } from '../../../../../../plugins/data/public'; + +export const createFilterIpRange = (aggConfig: IBucketAggConfig, key: IpRangeKey) => { + let range: esFilters.RangeFilterParams; + + if (key.type === 'mask') { + range = new CidrMask(key.mask).getRange(); + } else { + range = { + from: key.from ? key.from : -Infinity, + to: key.to ? key.to : Infinity, + }; + } + + return esFilters.buildRangeFilter( + aggConfig.params.field, + { gte: range.from, lte: range.to }, + aggConfig.getIndexPattern() + ); +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts new file mode 100644 index 0000000000000..720e952c28821 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts @@ -0,0 +1,79 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { createFilterRange } from './range'; +import { fieldFormats } from '../../../../../../plugins/data/public'; +import { AggConfigs } from '../../agg_configs'; +import { BUCKET_TYPES } from '../bucket_agg_types'; +import { IBucketAggConfig } from '../_bucket_agg_type'; + +jest.mock('ui/new_platform'); + +describe('AggConfig Filters', () => { + describe('range', () => { + const getConfig = (() => {}) as fieldFormats.GetConfigFn; + const getAggConfigs = () => { + const field = { + name: 'bytes', + format: new fieldFormats.BytesFormat({}, getConfig), + }; + + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + return new AggConfigs( + indexPattern, + [ + { + id: BUCKET_TYPES.RANGE, + type: BUCKET_TYPES.RANGE, + schema: 'buckets', + params: { + field: 'bytes', + ranges: [{ from: 1024, to: 2048 }], + }, + }, + ], + null + ); + }; + + it('should return a range filter for range agg', () => { + const aggConfigs = getAggConfigs(); + const filter = createFilterRange(aggConfigs.aggs[0] as IBucketAggConfig, { + gte: 1024, + lt: 2048.0, + }); + + expect(filter).toHaveProperty('range'); + expect(filter).toHaveProperty('meta'); + expect(filter.meta).toHaveProperty('index', '1234'); + expect(filter.range).toHaveProperty('bytes'); + expect(filter.range.bytes).toHaveProperty('gte', 1024.0); + expect(filter.range.bytes).toHaveProperty('lt', 2048.0); + expect(filter.meta).toHaveProperty('formattedValue', '≥ 1,024 and < 2,048'); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts new file mode 100644 index 0000000000000..929827c6e3fec --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts @@ -0,0 +1,30 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IBucketAggConfig } from '../_bucket_agg_type'; +import { esFilters } from '../../../../../../plugins/data/public'; + +export const createFilterRange = (aggConfig: IBucketAggConfig, params: any) => { + return esFilters.buildRangeFilter( + aggConfig.params.field, + params, + aggConfig.getIndexPattern(), + aggConfig.fieldFormatter()(params) + ); +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts new file mode 100644 index 0000000000000..86c0aa24f529a --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts @@ -0,0 +1,131 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { createFilterTerms } from './terms'; +import { AggConfigs } from '../../agg_configs'; +import { BUCKET_TYPES } from '../bucket_agg_types'; +import { IBucketAggConfig } from '../_bucket_agg_type'; +import { esFilters } from '../../../../../../plugins/data/public'; + +jest.mock('ui/new_platform'); + +describe('AggConfig Filters', () => { + describe('terms', () => { + const getAggConfigs = (aggs: Array>) => { + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + const field = { + name: 'field', + indexPattern, + }; + + return new AggConfigs(indexPattern, aggs, null); + }; + + it('should return a match_phrase filter for terms', () => { + const aggConfigs = getAggConfigs([ + { type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } }, + ]); + + const filter = createFilterTerms( + aggConfigs.aggs[0] as IBucketAggConfig, + 'apache', + {} + ) as esFilters.Filter; + + expect(filter).toHaveProperty('query'); + expect(filter.query).toHaveProperty('match_phrase'); + expect(filter.query.match_phrase).toHaveProperty('field'); + expect(filter.query.match_phrase.field).toBe('apache'); + expect(filter).toHaveProperty('meta'); + expect(filter.meta).toHaveProperty('index', '1234'); + }); + + it('should set query to true or false for boolean filter', () => { + const aggConfigs = getAggConfigs([ + { type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } }, + ]); + + const filterFalse = createFilterTerms( + aggConfigs.aggs[0] as IBucketAggConfig, + '', + {} + ) as esFilters.Filter; + + expect(filterFalse).toHaveProperty('query'); + expect(filterFalse.query).toHaveProperty('match_phrase'); + expect(filterFalse.query.match_phrase).toHaveProperty('field'); + expect(filterFalse.query.match_phrase.field).toBeFalsy(); + + const filterTrue = createFilterTerms( + aggConfigs.aggs[0] as IBucketAggConfig, + '1', + {} + ) as esFilters.Filter; + + expect(filterTrue).toHaveProperty('query'); + expect(filterTrue.query).toHaveProperty('match_phrase'); + expect(filterTrue.query.match_phrase).toHaveProperty('field'); + expect(filterTrue.query.match_phrase.field).toBeTruthy(); + }); + + it('should generate correct __missing__ filter', () => { + const aggConfigs = getAggConfigs([ + { type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } }, + ]); + const filter = createFilterTerms( + aggConfigs.aggs[0] as IBucketAggConfig, + '__missing__', + {} + ) as esFilters.ExistsFilter; + + expect(filter).toHaveProperty('exists'); + expect(filter.exists).toHaveProperty('field', 'field'); + expect(filter).toHaveProperty('meta'); + expect(filter.meta).toHaveProperty('index', '1234'); + expect(filter.meta).toHaveProperty('negate', true); + }); + + it('should generate correct __other__ filter', () => { + const aggConfigs = getAggConfigs([ + { type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } }, + ]); + + const [filter] = createFilterTerms(aggConfigs.aggs[0] as IBucketAggConfig, '__other__', { + terms: ['apache'], + }) as esFilters.Filter[]; + + expect(filter).toHaveProperty('query'); + expect(filter.query).toHaveProperty('bool'); + expect(filter.query.bool).toHaveProperty('should'); + expect(filter.query.bool.should[0]).toHaveProperty('match_phrase'); + expect(filter.query.bool.should[0].match_phrase).toHaveProperty('field', 'apache'); + expect(filter).toHaveProperty('meta'); + expect(filter.meta).toHaveProperty('index', '1234'); + expect(filter.meta).toHaveProperty('negate', true); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts new file mode 100644 index 0000000000000..5bd770e672786 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts @@ -0,0 +1,46 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IBucketAggConfig } from '../_bucket_agg_type'; +import { esFilters } from '../../../../../../plugins/data/public'; + +export const createFilterTerms = (aggConfig: IBucketAggConfig, key: string, params: any) => { + const field = aggConfig.params.field; + const indexPattern = field.indexPattern; + + if (key === '__other__') { + const terms = params.terms; + + const phraseFilter = esFilters.buildPhrasesFilter(field, terms, indexPattern); + phraseFilter.meta.negate = true; + + const filters: esFilters.Filter[] = [phraseFilter]; + + if (terms.some((term: string) => term === '__missing__')) { + filters.push(esFilters.buildExistsFilter(field, indexPattern)); + } + + return filters; + } else if (key === '__missing__') { + const existsFilter = esFilters.buildExistsFilter(field, indexPattern); + existsFilter.meta.negate = true; + return existsFilter; + } + return esFilters.buildPhraseFilter(field, key, indexPattern); +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts new file mode 100644 index 0000000000000..33672b54b1f2e --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts @@ -0,0 +1,267 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import _ from 'lodash'; +import moment from 'moment-timezone'; +import { i18n } from '@kbn/i18n'; + +import { npStart } from 'ui/new_platform'; +import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { createFilterDateHistogram } from './create_filter/date_histogram'; +import { intervalOptions } from './_interval_options'; +import { timefilter } from '../../timefilter'; +import { dateHistogramInterval } from '../../../../core_plugins/data/public'; +import { writeParams } from '../agg_params'; +import { isMetricAggType } from '../metrics/metric_agg_type'; + +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +// @ts-ignore +import { TimeBuckets } from '../../time_buckets'; + +const detectedTimezone = moment.tz.guess(); +const tzOffset = moment().format('Z'); + +const getInterval = (agg: IBucketAggConfig): string => _.get(agg, ['params', 'interval']); + +export const setBounds = (agg: IBucketDateHistogramAggConfig, force?: boolean) => { + if (agg.buckets._alreadySet && !force) return; + agg.buckets._alreadySet = true; + const bounds = agg.params.timeRange ? timefilter.calculateBounds(agg.params.timeRange) : null; + agg.buckets.setBounds(agg.fieldIsTimeField() && bounds); +}; + +// will be replaced by src/legacy/ui/public/time_buckets/time_buckets.js +interface TimeBuckets { + _alreadySet?: boolean; + setBounds: Function; + getScaledDateFormatter: Function; + setInterval: Function; + getInterval: Function; +} + +export interface IBucketDateHistogramAggConfig extends IBucketAggConfig { + buckets: TimeBuckets; +} + +export function isDateHistogramBucketAggConfig(agg: any): agg is IBucketDateHistogramAggConfig { + return Boolean(agg.buckets); +} + +export const dateHistogramBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.DATE_HISTOGRAM, + title: i18n.translate('common.ui.aggTypes.buckets.dateHistogramTitle', { + defaultMessage: 'Date Histogram', + }), + ordered: { + date: true, + }, + makeLabel(agg) { + let output: Record = {}; + + if (this.params) { + output = writeParams(this.params, agg); + } + + const field = agg.getFieldDisplayName(); + return i18n.translate('common.ui.aggTypes.buckets.dateHistogramLabel', { + defaultMessage: '{fieldName} per {intervalDescription}', + values: { + fieldName: field, + intervalDescription: output.metricScaleText || output.bucketInterval.description, + }, + }); + }, + createFilter: createFilterDateHistogram, + decorateAggConfig() { + let buckets: any; + return { + buckets: { + configurable: true, + get() { + if (buckets) return buckets; + + buckets = new TimeBuckets(); + buckets.setInterval(getInterval(this)); + setBounds(this); + + return buckets; + }, + } as any, + }; + }, + getFormat(agg) { + return agg.buckets.getScaledDateFormatter(); + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.DATE, + default(agg: IBucketDateHistogramAggConfig) { + return agg.getIndexPattern().timeFieldName; + }, + onChange(agg: IBucketDateHistogramAggConfig) { + if (_.get(agg, 'params.interval') === 'auto' && !agg.fieldIsTimeField()) { + delete agg.params.interval; + } + + setBounds(agg, true); + }, + }, + { + name: 'timeRange', + default: null, + write: _.noop, + }, + { + name: 'useNormalizedEsInterval', + default: true, + write: _.noop, + }, + { + name: 'scaleMetricValues', + default: false, + write: _.noop, + advanced: true, + }, + { + name: 'interval', + deserialize(state: any, agg) { + // For upgrading from 7.0.x to 7.1.x - intervals are now stored as key of options or custom value + if (state === 'custom') { + return _.get(agg, 'params.customInterval'); + } + + const interval = _.find(intervalOptions, { val: state }); + + // 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 + if (!interval && state === 'year') { + return 'y'; + } + return state; + }, + default: 'auto', + options: intervalOptions, + modifyAggConfigOnSearchRequestStart(agg: IBucketDateHistogramAggConfig) { + setBounds(agg, true); + }, + write(agg, output, aggs) { + setBounds(agg, true); + agg.buckets.setInterval(getInterval(agg)); + const { useNormalizedEsInterval, scaleMetricValues } = agg.params; + const interval = agg.buckets.getInterval(useNormalizedEsInterval); + output.bucketInterval = interval; + if (interval.expression === '0ms') { + // We are hitting this code a couple of times while configuring in editor + // with an interval of 0ms because the overall time range has not yet been + // set. Since 0ms is not a valid ES interval, we cannot pass it through dateHistogramInterval + // below, since it would throw an exception. So in the cases we still have an interval of 0ms + // here we simply skip the rest of the method and never write an interval into the DSL, since + // this DSL will anyway not be used before we're passing this code with an actual interval. + return; + } + output.params = { + ...output.params, + ...dateHistogramInterval(interval.expression), + }; + + const scaleMetrics = scaleMetricValues && interval.scaled && interval.scale < 1; + if (scaleMetrics && aggs) { + const metrics = aggs.aggs.filter(a => isMetricAggType(a.type)); + const all = _.every(metrics, (a: IBucketAggConfig) => { + const { type } = a; + + if (isMetricAggType(type)) { + return type.isScalable(); + } + }); + if (all) { + output.metricScale = interval.scale; + output.metricScaleText = interval.preScaled.description; + } + } + }, + }, + { + name: 'time_zone', + default: undefined, + // We don't ever want this parameter to be serialized out (when saving or to URLs) + // since we do all the logic handling it "on the fly" in the `write` method, to prevent + // time_zones being persisted into saved_objects + serialize: _.noop, + write(agg, output) { + // If a time_zone has been set explicitly always prefer this. + let tz = agg.params.time_zone; + if (!tz && agg.params.field) { + // If a field has been configured check the index pattern's typeMeta if a date_histogram on that + // field requires a specific time_zone + tz = _.get(agg.getIndexPattern(), [ + 'typeMeta', + 'aggs', + 'date_histogram', + agg.params.field.name, + 'time_zone', + ]); + } + if (!tz) { + const config = npStart.core.uiSettings; + // If the index pattern typeMeta data, didn't had a time zone assigned for the selected field use the configured tz + const isDefaultTimezone = config.isDefault('dateFormat:tz'); + tz = isDefaultTimezone ? detectedTimezone || tzOffset : config.get('dateFormat:tz'); + } + output.params.time_zone = tz; + }, + }, + { + name: 'drop_partials', + default: false, + write: _.noop, + shouldShow: agg => { + const field = agg.params.field; + return field && field.name && field.name === agg.getIndexPattern().timeFieldName; + }, + }, + { + name: 'format', + }, + { + name: 'min_doc_count', + default: 1, + }, + { + name: 'extended_bounds', + default: {}, + write(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; + } + }, + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.test.ts new file mode 100644 index 0000000000000..e34cb4e36720f --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.test.ts @@ -0,0 +1,112 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { AggConfigs } from '../agg_configs'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { npStart } from 'ui/new_platform'; + +jest.mock('ui/new_platform'); + +describe('date_range params', () => { + const getAggConfigs = (params: Record = {}, hasIncludeTypeMeta: boolean = true) => { + const field = { + name: 'bytes', + }; + + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + typeMeta: hasIncludeTypeMeta + ? { + aggs: { + date_range: { + bytes: { + time_zone: 'defaultTimeZone', + }, + }, + }, + } + : undefined, + } as any; + + return new AggConfigs( + indexPattern, + [ + { + id: BUCKET_TYPES.DATE_RANGE, + type: BUCKET_TYPES.DATE_RANGE, + schema: 'buckets', + params, + }, + ], + null + ); + }; + + describe('getKey', () => { + it('should return object', () => { + const aggConfigs = getAggConfigs(); + const dateRange = aggConfigs.aggs[0]; + const bucket = { from: 'from-date', to: 'to-date', key: 'from-dateto-date' }; + + expect(dateRange.getKey(bucket)).toEqual({ from: 'from-date', to: 'to-date' }); + }); + }); + + describe('time_zone', () => { + it('should use the specified time_zone', () => { + const aggConfigs = getAggConfigs({ + time_zone: 'Europe/Minsk', + field: 'bytes', + }); + const dateRange = aggConfigs.aggs[0]; + const params = dateRange.toDsl()[BUCKET_TYPES.DATE_RANGE]; + + expect(params.time_zone).toBe('Europe/Minsk'); + }); + + it('should use the fixed time_zone from the index pattern typeMeta', () => { + const aggConfigs = getAggConfigs({ + field: 'bytes', + }); + const dateRange = aggConfigs.aggs[0]; + const params = dateRange.toDsl()[BUCKET_TYPES.DATE_RANGE]; + + expect(params.time_zone).toBe('defaultTimeZone'); + }); + + it('should use the Kibana time_zone if no parameter specified', () => { + npStart.core.uiSettings.get = jest.fn(() => 'kibanaTimeZone' as any); + + const aggConfigs = getAggConfigs( + { + field: 'bytes', + }, + false + ); + const dateRange = aggConfigs.aggs[0]; + const params = dateRange.toDsl()[BUCKET_TYPES.DATE_RANGE]; + + expect(params.time_zone).toBe('kibanaTimeZone'); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts new file mode 100644 index 0000000000000..ee04e0657f317 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts @@ -0,0 +1,121 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { get } from 'lodash'; +import moment from 'moment-timezone'; +import { i18n } from '@kbn/i18n'; +import { npStart } from 'ui/new_platform'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; +import { createFilterDateRange } from './create_filter/date_range'; + +import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../plugins/data/public'; + +const dateRangeTitle = i18n.translate('common.ui.aggTypes.buckets.dateRangeTitle', { + defaultMessage: 'Date Range', +}); + +export interface DateRangeKey { + from: number; + to: number; +} + +export const dateRangeBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.DATE_RANGE, + title: dateRangeTitle, + createFilter: createFilterDateRange, + getKey({ from, to }): DateRangeKey { + return { from, to }; + }, + getFormat(agg) { + const fieldFormatsService = npStart.plugins.data.fieldFormats; + + const formatter = agg.fieldOwnFormatter( + fieldFormats.TEXT_CONTEXT_TYPE, + fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.DATE) + ); + const DateRangeFormat = fieldFormats.FieldFormat.from(function(range: DateRangeKey) { + return convertDateRangeToString(range, formatter); + }); + return new DateRangeFormat(); + }, + makeLabel(aggConfig) { + return aggConfig.getFieldDisplayName() + ' date ranges'; + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.DATE, + default(agg: IBucketAggConfig) { + return agg.getIndexPattern().timeFieldName; + }, + }, + { + name: 'ranges', + default: [ + { + from: 'now-1w/w', + to: 'now', + }, + ], + }, + { + name: 'time_zone', + default: undefined, + // Implimentation method is the same as that of date_histogram + serialize: () => undefined, + write: (agg, output) => { + const field = agg.getParam('field'); + let tz = agg.getParam('time_zone'); + + if (!tz && field) { + tz = get(agg.getIndexPattern(), [ + 'typeMeta', + 'aggs', + 'date_range', + field.name, + 'time_zone', + ]); + } + if (!tz) { + const config = npStart.core.uiSettings; + const detectedTimezone = moment.tz.guess(); + const tzOffset = moment().format('Z'); + const isDefaultTimezone = config.isDefault('dateFormat:tz'); + + tz = isDefaultTimezone ? detectedTimezone || tzOffset : config.get('dateFormat:tz'); + } + output.params.time_zone = tz; + }, + }, + ], +}); + +export const convertDateRangeToString = ( + { from, to }: DateRangeKey, + format: (val: any) => string +) => { + if (!from) { + return 'Before ' + format(to); + } else if (!to) { + return 'After ' + format(from); + } else { + return format(from) + ' to ' + format(to); + } +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/filter.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/filter.ts new file mode 100644 index 0000000000000..3f8a898f4c963 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/filter.ts @@ -0,0 +1,35 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { i18n } from '@kbn/i18n'; +import { BucketAggType } from './_bucket_agg_type'; +import { BUCKET_TYPES } from './bucket_agg_types'; + +const filterTitle = i18n.translate('common.ui.aggTypes.buckets.filterTitle', { + defaultMessage: 'Filter', +}); + +export const filterBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.FILTER, + title: filterTitle, + params: [ + { + name: 'geo_bounding_box', + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/filters.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/filters.ts new file mode 100644 index 0000000000000..d9b78b3063e23 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/filters.ts @@ -0,0 +1,106 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import _ from 'lodash'; +import angular from 'angular'; + +import { i18n } from '@kbn/i18n'; + +import chrome from 'ui/chrome'; +import { createFilterFilters } from './create_filter/filters'; +import { BucketAggType } from './_bucket_agg_type'; +import { Storage } from '../../../../../plugins/kibana_utils/public'; +import { getQueryLog, esQuery, Query } from '../../../../../plugins/data/public'; +import { BUCKET_TYPES } from './bucket_agg_types'; + +const config = chrome.getUiSettingsClient(); +const storage = new Storage(window.localStorage); + +const filtersTitle = i18n.translate('common.ui.aggTypes.buckets.filtersTitle', { + defaultMessage: 'Filters', + description: + 'The name of an aggregation, that allows to specify multiple individual filters to group data by.', +}); + +interface FilterValue { + input: Query; + label: string; + id: string; +} + +export const filtersBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.FILTERS, + title: filtersTitle, + createFilter: createFilterFilters, + customLabels: false, + params: [ + { + name: 'filters', + default: [{ input: { query: '', language: config.get('search:queryLanguage') }, label: '' }], + write(aggConfig, output) { + const inFilters: FilterValue[] = aggConfig.params.filters; + if (!_.size(inFilters)) return; + + inFilters.forEach(filter => { + const persistedLog = getQueryLog( + config, + storage, + 'vis_default_editor', + filter.input.language + ); + persistedLog.add(filter.input.query); + }); + + const outFilters = _.transform( + inFilters, + function(filters, filter) { + const input = _.cloneDeep(filter.input); + + if (!input) { + console.log('malformed filter agg params, missing "input" query'); // eslint-disable-line no-console + return; + } + + const query = esQuery.buildEsQuery(aggConfig.getIndexPattern(), [input], [], config); + + if (!query) { + console.log('malformed filter agg params, missing "query" on input'); // eslint-disable-line no-console + return; + } + + const matchAllLabel = filter.input.query === '' ? '*' : ''; + const label = + filter.label || + matchAllLabel || + (typeof filter.input.query === 'string' + ? filter.input.query + : angular.toJson(filter.input.query)); + filters[label] = { query }; + }, + {} + ); + + if (!_.size(outFilters)) return; + + const params = output.params || (output.params = {}); + params.filters = outFilters; + }, + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts new file mode 100644 index 0000000000000..effa49f0ade6b --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts @@ -0,0 +1,225 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { geoHashBucketAgg, IBucketGeoHashGridAggConfig } from './geo_hash'; +import { AggConfigs } from '../agg_configs'; +import { BUCKET_TYPES } from './bucket_agg_types'; + +jest.mock('ui/new_platform'); + +describe('Geohash Agg', () => { + const getAggConfigs = (params?: Record) => { + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + const field = { + name: 'location', + indexPattern, + }; + + return new AggConfigs( + indexPattern, + [ + { + id: BUCKET_TYPES.GEOHASH_GRID, + type: BUCKET_TYPES.GEOHASH_GRID, + schema: 'segment', + params: { + field: { + name: 'location', + }, + isFilteredByCollar: true, + useGeocentroid: true, + mapZoom: 10, + mapBounds: { + top_left: { lat: 1.0, lon: -1.0 }, + bottom_right: { lat: -1.0, lon: 1.0 }, + }, + ...params, + }, + }, + ], + null + ); + }; + + describe('precision parameter', () => { + const PRECISION_PARAM_INDEX = 2; + + let precisionParam: any; + + beforeEach(() => { + precisionParam = geoHashBucketAgg.params[PRECISION_PARAM_INDEX]; + }); + + it('should select precision parameter', () => { + expect(precisionParam.name).toEqual('precision'); + }); + + describe('precision parameter write', () => { + const zoomToGeoHashPrecision: Record = { + 0: 1, + 1: 2, + 2: 2, + 3: 2, + 4: 3, + 5: 3, + 6: 4, + 7: 4, + 8: 4, + 9: 5, + 10: 5, + 11: 6, + 12: 6, + 13: 6, + 14: 7, + 15: 7, + 16: 8, + 17: 8, + 18: 8, + 19: 9, + 20: 9, + 21: 10, + }; + + Object.keys(zoomToGeoHashPrecision).forEach((zoomLevel: string) => { + it(`zoom level ${zoomLevel} should correspond to correct geohash-precision`, () => { + const aggConfigs = getAggConfigs({ + autoPrecision: true, + mapZoom: zoomLevel, + }); + + const { [BUCKET_TYPES.GEOHASH_GRID]: params } = aggConfigs.aggs[0].toDsl(); + + expect(params.precision).toEqual(zoomToGeoHashPrecision[zoomLevel]); + }); + }); + }); + }); + + describe('getRequestAggs', () => { + describe('initial aggregation creation', () => { + let aggConfigs: AggConfigs; + let geoHashGridAgg: IBucketGeoHashGridAggConfig; + + beforeEach(() => { + aggConfigs = getAggConfigs(); + geoHashGridAgg = aggConfigs.aggs[0] as IBucketGeoHashGridAggConfig; + }); + + it('should create filter, geohash_grid, and geo_centroid aggregations', () => { + const requestAggs = geoHashBucketAgg.getRequestAggs( + geoHashGridAgg + ) as IBucketGeoHashGridAggConfig[]; + + expect(requestAggs.length).toEqual(3); + expect(requestAggs[0].type.name).toEqual('filter'); + expect(requestAggs[1].type.name).toEqual('geohash_grid'); + expect(requestAggs[2].type.name).toEqual('geo_centroid'); + }); + + it('should set mapCollar in vis session state', () => { + const [, geoHashAgg] = geoHashBucketAgg.getRequestAggs( + geoHashGridAgg + ) as IBucketGeoHashGridAggConfig[]; + + expect(geoHashAgg).toHaveProperty('lastMapCollar'); + expect(geoHashAgg.lastMapCollar).toHaveProperty('top_left'); + expect(geoHashAgg.lastMapCollar).toHaveProperty('bottom_right'); + expect(geoHashAgg.lastMapCollar).toHaveProperty('zoom'); + }); + }); + }); + + describe('aggregation options', () => { + it('should only create geohash_grid and geo_centroid aggregations when isFilteredByCollar is false', () => { + const aggConfigs = getAggConfigs({ isFilteredByCollar: false }); + const requestAggs = geoHashBucketAgg.getRequestAggs( + aggConfigs.aggs[0] as IBucketGeoHashGridAggConfig + ) as IBucketGeoHashGridAggConfig[]; + + expect(requestAggs.length).toEqual(2); + expect(requestAggs[0].type.name).toEqual('geohash_grid'); + expect(requestAggs[1].type.name).toEqual('geo_centroid'); + }); + + it('should only create filter and geohash_grid aggregations when useGeocentroid is false', () => { + const aggConfigs = getAggConfigs({ useGeocentroid: false }); + const requestAggs = geoHashBucketAgg.getRequestAggs( + aggConfigs.aggs[0] as IBucketGeoHashGridAggConfig + ) as IBucketGeoHashGridAggConfig[]; + + expect(requestAggs.length).toEqual(2); + expect(requestAggs[0].type.name).toEqual('filter'); + expect(requestAggs[1].type.name).toEqual('geohash_grid'); + }); + }); + + describe('aggregation creation after map interaction', () => { + let originalRequestAggs: IBucketGeoHashGridAggConfig[]; + + beforeEach(() => { + originalRequestAggs = geoHashBucketAgg.getRequestAggs( + getAggConfigs().aggs[0] as IBucketGeoHashGridAggConfig + ) as IBucketGeoHashGridAggConfig[]; + }); + + it('should change geo_bounding_box filter aggregation and vis session state when map movement is outside map collar', () => { + const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs( + getAggConfigs({ + mapBounds: { + top_left: { lat: 10.0, lon: -10.0 }, + bottom_right: { lat: 9.0, lon: -9.0 }, + }, + }).aggs[0] as IBucketGeoHashGridAggConfig + ) as IBucketGeoHashGridAggConfig[]; + + expect(originalRequestAggs[1].params).not.toEqual(geoBoxingBox.params); + }); + + it('should not change geo_bounding_box filter aggregation and vis session state when map movement is within map collar', () => { + const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs( + getAggConfigs({ + mapBounds: { + top_left: { lat: 1, lon: -1 }, + bottom_right: { lat: -1, lon: 1 }, + }, + }).aggs[0] as IBucketGeoHashGridAggConfig + ) as IBucketGeoHashGridAggConfig[]; + + expect(originalRequestAggs[1].params).toEqual(geoBoxingBox.params); + }); + + it('should change geo_bounding_box filter aggregation and vis session state when map zoom level changes', () => { + const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs( + getAggConfigs({ + mapZoom: -1, + }).aggs[0] as IBucketGeoHashGridAggConfig + ) as IBucketGeoHashGridAggConfig[]; + + expect(originalRequestAggs[1].lastMapCollar).not.toEqual(geoBoxingBox.lastMapCollar); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts new file mode 100644 index 0000000000000..b2519df6fb175 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts @@ -0,0 +1,201 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { geohashColumns } from 'ui/vis/map/decode_geo_hash'; +import chrome from '../../chrome'; +import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +import { geoContains, scaleBounds, GeoBoundingBox } from './lib/geo_utils'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { AggGroupNames } from '../agg_groups'; + +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: any = {}; +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(val: string) { + let precision = parseInt(val, 10); + + if (Number.isNaN(precision)) { + precision = defaultPrecision; + } + + if (precision > maxPrecision) { + return maxPrecision; + } + + return precision; +} + +const isOutsideCollar = (bounds: GeoBoundingBox, collar: MapCollar) => + bounds && collar && !geoContains(collar, bounds); + +const geohashGridTitle = i18n.translate('common.ui.aggTypes.buckets.geohashGridTitle', { + defaultMessage: 'Geohash', +}); + +interface MapCollar extends GeoBoundingBox { + zoom?: unknown; +} + +export interface IBucketGeoHashGridAggConfig extends IBucketAggConfig { + lastMapCollar: MapCollar; +} + +export const geoHashBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.GEOHASH_GRID, + title: geohashGridTitle, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT, + }, + { + name: 'autoPrecision', + default: true, + write: () => {}, + }, + { + name: 'precision', + default: defaultPrecision, + deserialize: getPrecision, + write(aggConfig, output) { + const currZoom = aggConfig.params.mapZoom; + const autoPrecisionVal = zoomPrecision[currZoom]; + output.params.precision = aggConfig.params.autoPrecision + ? autoPrecisionVal + : getPrecision(aggConfig.params.precision); + }, + }, + { + name: 'useGeocentroid', + default: true, + write: () => {}, + }, + { + name: 'isFilteredByCollar', + default: true, + write: () => {}, + }, + { + name: 'mapZoom', + default: 2, + write: () => {}, + }, + { + name: 'mapCenter', + default: [0, 0], + write: () => {}, + }, + { + name: 'mapBounds', + default: null, + write: () => {}, + }, + ], + getRequestAggs(agg) { + const aggs = []; + const params = agg.params; + + if (params.isFilteredByCollar && agg.getField()) { + const { mapBounds, mapZoom } = params; + if (mapBounds) { + let mapCollar: MapCollar; + + if ( + mapBounds && + (!agg.lastMapCollar || + agg.lastMapCollar.zoom !== mapZoom || + isOutsideCollar(mapBounds, agg.lastMapCollar)) + ) { + mapCollar = scaleBounds(mapBounds); + mapCollar.zoom = mapZoom; + agg.lastMapCollar = mapCollar; + } else { + mapCollar = agg.lastMapCollar; + } + const boundingBox = { + ignore_unmapped: true, + [agg.getField().name]: { + top_left: mapCollar.top_left, + bottom_right: mapCollar.bottom_right, + }, + }; + aggs.push( + agg.aggConfigs.createAggConfig( + { + type: 'filter', + id: 'filter_agg', + enabled: true, + params: { + geo_bounding_box: boundingBox, + }, + schema: { + group: AggGroupNames.Buckets, + }, + } as any, + { addToAggConfigs: false } + ) + ); + } + } + + aggs.push(agg); + + if (params.useGeocentroid) { + aggs.push( + agg.aggConfigs.createAggConfig( + { + type: 'geo_centroid', + enabled: true, + params: { + field: agg.getField(), + }, + }, + { addToAggConfigs: false } + ) + ); + } + + return aggs as IBucketGeoHashGridAggConfig[]; + }, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts new file mode 100644 index 0000000000000..ef71e3947566a --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts @@ -0,0 +1,73 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { noop } from 'lodash'; +import { AggConfigOptions } from '../agg_config'; + +import { BucketAggType } from './_bucket_agg_type'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { IBucketAggConfig } from './_bucket_agg_type'; +import { METRIC_TYPES } from '../metrics/metric_agg_types'; + +const geotileGridTitle = i18n.translate('common.ui.aggTypes.buckets.geotileGridTitle', { + defaultMessage: 'Geotile', +}); + +export const geoTileBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.GEOTILE_GRID, + title: geotileGridTitle, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT, + }, + { + name: 'useGeocentroid', + default: true, + write: noop, + }, + { + name: 'precision', + default: 0, + }, + ], + getRequestAggs(agg) { + const aggs = []; + const useGeocentroid = agg.getParam('useGeocentroid'); + + aggs.push(agg); + + if (useGeocentroid) { + const aggConfig: AggConfigOptions = { + type: METRIC_TYPES.GEO_CENTROID, + enabled: true, + params: { + field: agg.getField(), + }, + }; + + aggs.push(agg.aggConfigs.createAggConfig(aggConfig, { addToAggConfigs: false })); + } + + return aggs as IBucketAggConfig[]; + }, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.test.ts new file mode 100644 index 0000000000000..4e89d7db1ff64 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.test.ts @@ -0,0 +1,292 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { npStart } from 'ui/new_platform'; +import { AggConfigs } from '../index'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { IBucketHistogramAggConfig, histogramBucketAgg, AutoBounds } from './histogram'; +import { BucketAggType } from './_bucket_agg_type'; + +jest.mock('ui/new_platform'); + +describe('Histogram Agg', () => { + const getAggConfigs = (params: Record = {}) => { + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + const field = { + name: 'field', + indexPattern, + }; + + return new AggConfigs( + indexPattern, + [ + { + field: { + name: 'field', + }, + id: 'test', + type: BUCKET_TYPES.HISTOGRAM, + schema: 'segment', + params, + }, + ], + null + ); + }; + + const getParams = (options: Record) => { + const aggConfigs = getAggConfigs({ + ...options, + field: { + name: 'field', + }, + }); + return aggConfigs.aggs[0].toDsl()[BUCKET_TYPES.HISTOGRAM]; + }; + + describe('ordered', () => { + let histogramType: BucketAggType; + + beforeEach(() => { + histogramType = histogramBucketAgg; + }); + + it('is ordered', () => { + expect(histogramType.ordered).toBeDefined(); + }); + + it('is not ordered by date', () => { + expect(histogramType.ordered).not.toHaveProperty('date'); + }); + }); + + describe('params', () => { + describe('intervalBase', () => { + it('should not be written to the DSL', () => { + const aggConfigs = getAggConfigs({ + intervalBase: 100, + field: { + name: 'field', + }, + }); + const { [BUCKET_TYPES.HISTOGRAM]: params } = aggConfigs.aggs[0].toDsl(); + + expect(params).not.toHaveProperty('intervalBase'); + }); + }); + + describe('interval', () => { + it('accepts a whole number', () => { + const params = getParams({ + interval: 100, + }); + + expect(params).toHaveProperty('interval', 100); + }); + + it('accepts a decimal number', function() { + const params = getParams({ + interval: 0.1, + }); + + expect(params).toHaveProperty('interval', 0.1); + }); + + it('accepts a decimal number string', function() { + const params = getParams({ + interval: '0.1', + }); + + expect(params).toHaveProperty('interval', 0.1); + }); + + it('accepts a whole number string', function() { + const params = getParams({ + interval: '10', + }); + + expect(params).toHaveProperty('interval', 10); + }); + + it('fails on non-numeric values', function() { + const params = getParams({ + interval: [], + }); + + expect(params.interval).toBeNaN(); + }); + + describe('interval scaling', () => { + const getInterval = ( + maxBars: number, + params?: Record, + autoBounds?: AutoBounds + ) => { + const aggConfigs = getAggConfigs({ + ...params, + field: { + name: 'field', + }, + }); + const aggConfig = aggConfigs.aggs[0] as IBucketHistogramAggConfig; + + if (autoBounds) { + aggConfig.setAutoBounds(autoBounds); + } + + // mock histogram:maxBars value; + npStart.core.uiSettings.get = jest.fn(() => maxBars as any); + + return aggConfig.write(aggConfigs).params; + }; + + it('will respect the histogram:maxBars setting', () => { + const params = getInterval( + 5, + { interval: 5 }, + { + min: 0, + max: 10000, + } + ); + + expect(params).toHaveProperty('interval', 2000); + }); + + it('will return specified interval, if bars are below histogram:maxBars config', () => { + const params = getInterval(100, { interval: 5 }); + + expect(params).toHaveProperty('interval', 5); + }); + + it('will set to intervalBase if interval is below base', () => { + const params = getInterval(1000, { interval: 3, intervalBase: 8 }); + + expect(params).toHaveProperty('interval', 8); + }); + + it('will round to nearest intervalBase multiple if interval is above base', () => { + const roundUp = getInterval(1000, { interval: 46, intervalBase: 10 }); + expect(roundUp).toHaveProperty('interval', 50); + + const roundDown = getInterval(1000, { interval: 43, intervalBase: 10 }); + expect(roundDown).toHaveProperty('interval', 40); + }); + + it('will not change interval if it is a multiple of base', () => { + const output = getInterval(1000, { interval: 35, intervalBase: 5 }); + + expect(output).toHaveProperty('interval', 35); + }); + + it('will round to intervalBase after scaling histogram:maxBars', () => { + const output = getInterval(100, { interval: 5, intervalBase: 6 }, { min: 0, max: 1000 }); + + // 100 buckets in 0 to 1000 would result in an interval of 10, so we should + // round to the next multiple of 6 -> 12 + expect(output).toHaveProperty('interval', 12); + }); + }); + + describe('min_doc_count', () => { + let output: Record; + + it('casts true values to 0', () => { + output = getParams({ min_doc_count: true }); + expect(output).toHaveProperty('min_doc_count', 0); + + output = getParams({ min_doc_count: 'yes' }); + expect(output).toHaveProperty('min_doc_count', 0); + + output = getParams({ min_doc_count: 1 }); + expect(output).toHaveProperty('min_doc_count', 0); + + output = getParams({ min_doc_count: {} }); + expect(output).toHaveProperty('min_doc_count', 0); + }); + + it('writes 1 for falsy values', () => { + output = getParams({ min_doc_count: '' }); + expect(output).toHaveProperty('min_doc_count', 1); + + output = getParams({ min_doc_count: null }); + expect(output).toHaveProperty('min_doc_count', 1); + + output = getParams({ min_doc_count: undefined }); + expect(output).toHaveProperty('min_doc_count', 1); + }); + }); + + describe('extended_bounds', function() { + it('does not write when only eb.min is set', function() { + const output = getParams({ + has_extended_bounds: true, + extended_bounds: { min: 0 }, + }); + expect(output).not.toHaveProperty('extended_bounds'); + }); + + it('does not write when only eb.max is set', function() { + const output = getParams({ + has_extended_bounds: true, + extended_bounds: { max: 0 }, + }); + + expect(output).not.toHaveProperty('extended_bounds'); + }); + + it('writes when both eb.min and eb.max are set', function() { + const output = getParams({ + has_extended_bounds: true, + extended_bounds: { min: 99, max: 100 }, + }); + + expect(output.extended_bounds).toHaveProperty('min', 99); + expect(output.extended_bounds).toHaveProperty('max', 100); + }); + + it('does not write when nothing is set', function() { + const output = getParams({ + has_extended_bounds: true, + extended_bounds: {}, + }); + + expect(output).not.toHaveProperty('extended_bounds'); + }); + + it('does not write when has_extended_bounds is false', function() { + const output = getParams({ + has_extended_bounds: false, + extended_bounds: { min: 99, max: 100 }, + }); + + expect(output).not.toHaveProperty('extended_bounds'); + }); + }); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts new file mode 100644 index 0000000000000..44327c7c19e6d --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts @@ -0,0 +1,201 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import _ from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { toastNotifications } from 'ui/notify'; + +import { npStart } from 'ui/new_platform'; +import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; +import { createFilterHistogram } from './create_filter/histogram'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { BUCKET_TYPES } from './bucket_agg_types'; + +export interface AutoBounds { + min: number; + max: number; +} + +export interface IBucketHistogramAggConfig extends IBucketAggConfig { + setAutoBounds: (bounds: AutoBounds) => void; + getAutoBounds: () => AutoBounds; +} + +const getUIConfig = () => npStart.core.uiSettings; + +export const histogramBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.HISTOGRAM, + title: i18n.translate('common.ui.aggTypes.buckets.histogramTitle', { + defaultMessage: 'Histogram', + }), + ordered: {}, + makeLabel(aggConfig) { + return aggConfig.getFieldDisplayName(); + }, + createFilter: createFilterHistogram, + decorateAggConfig() { + let autoBounds: AutoBounds; + + return { + setAutoBounds: { + configurable: true, + value(newValue: AutoBounds) { + autoBounds = newValue; + }, + }, + getAutoBounds: { + configurable: true, + value() { + return autoBounds; + }, + }, + }; + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.NUMBER, + }, + { + /* + * This parameter can be set if you want the auto scaled interval to always + * be a multiple of a specific base. + */ + name: 'intervalBase', + default: null, + write: () => {}, + }, + { + name: 'interval', + modifyAggConfigOnSearchRequestStart( + aggConfig: IBucketHistogramAggConfig, + searchSource: any, + options: any + ) { + const field = aggConfig.getField(); + const aggBody = field.scripted + ? { script: { source: field.script, lang: field.lang } } + : { field: field.name }; + + const childSearchSource = searchSource + .createChild() + .setField('size', 0) + .setField('aggs', { + maxAgg: { + max: aggBody, + }, + minAgg: { + min: aggBody, + }, + }); + + return childSearchSource + .fetch(options) + .then((resp: any) => { + aggConfig.setAutoBounds({ + min: _.get(resp, 'aggregations.minAgg.value'), + max: _.get(resp, 'aggregations.maxAgg.value'), + }); + }) + .catch((e: Error) => { + if (e.name === 'AbortError') return; + toastNotifications.addWarning( + i18n.translate('common.ui.aggTypes.histogram.missingMaxMinValuesWarning', { + defaultMessage: + 'Unable to retrieve max and min values to auto-scale histogram buckets. This may lead to poor visualization performance.', + }) + ); + }); + }, + write(aggConfig, output) { + let interval = parseFloat(aggConfig.params.interval); + if (interval <= 0) { + interval = 1; + } + const autoBounds = aggConfig.getAutoBounds(); + + // ensure interval does not create too many buckets and crash browser + if (autoBounds) { + const range = autoBounds.max - autoBounds.min; + const bars = range / interval; + + const config = getUIConfig(); + 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 orderOfMagnitude = Math.pow(10, Math.floor(Math.log10(minInterval))); + let roundInterval = orderOfMagnitude; + + while (roundInterval < minInterval) { + roundInterval += orderOfMagnitude; + } + interval = roundInterval; + } + } + const base = aggConfig.params.intervalBase; + + if (base) { + if (interval < base) { + // In case the specified interval is below the base, just increase it to it's base + interval = base; + } else if (interval % base !== 0) { + // In case the interval is not a multiple of the base round it to the next base + interval = Math.round(interval / base) * base; + } + } + + output.params.interval = interval; + }, + }, + { + name: 'min_doc_count', + default: false, + write(aggConfig, output) { + if (aggConfig.params.min_doc_count) { + output.params.min_doc_count = 0; + } else { + output.params.min_doc_count = 1; + } + }, + }, + { + name: 'has_extended_bounds', + default: false, + write: () => {}, + }, + { + name: 'extended_bounds', + default: { + min: '', + max: '', + }, + write(aggConfig, output) { + const { min, max } = aggConfig.params.extended_bounds; + + if (aggConfig.params.has_extended_bounds && (min || min === 0) && (max || max === 0)) { + output.params.extended_bounds = { min, max }; + } + }, + shouldShow: (aggConfig: IBucketAggConfig) => aggConfig.params.has_extended_bounds, + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts new file mode 100644 index 0000000000000..41141dabf507c --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts @@ -0,0 +1,109 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { noop, map, omit, isNull } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { npStart } from 'ui/new_platform'; +import { BucketAggType } from './_bucket_agg_type'; +import { BUCKET_TYPES } from './bucket_agg_types'; + +// @ts-ignore +import { createFilterIpRange } from './create_filter/ip_range'; +import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../plugins/data/public'; + +const ipRangeTitle = i18n.translate('common.ui.aggTypes.buckets.ipRangeTitle', { + defaultMessage: 'IPv4 Range', +}); + +export type IpRangeKey = + | { type: 'mask'; mask: string } + | { type: 'range'; from: string; to: string }; + +export const ipRangeBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.IP_RANGE, + title: ipRangeTitle, + createFilter: createFilterIpRange, + getKey(bucket, key, agg): IpRangeKey { + if (agg.params.ipRangeType === 'mask') { + return { type: 'mask', mask: key }; + } + return { type: 'range', from: bucket.from, to: bucket.to }; + }, + getFormat(agg) { + const fieldFormatsService = npStart.plugins.data.fieldFormats; + const formatter = agg.fieldOwnFormatter( + fieldFormats.TEXT_CONTEXT_TYPE, + fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.IP) + ); + const IpRangeFormat = fieldFormats.FieldFormat.from(function(range: IpRangeKey) { + return convertIPRangeToString(range, formatter); + }); + return new IpRangeFormat(); + }, + makeLabel(aggConfig) { + return i18n.translate('common.ui.aggTypes.buckets.ipRangeLabel', { + defaultMessage: '{fieldName} IP ranges', + values: { + fieldName: aggConfig.getFieldDisplayName(), + }, + }); + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.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' }], + }, + write(aggConfig, output) { + const ipRangeType = aggConfig.params.ipRangeType; + let ranges = aggConfig.params.ranges[ipRangeType]; + + if (ipRangeType === 'fromTo') { + ranges = map(ranges, (range: any) => omit(range, isNull)); + } + + output.params.ranges = ranges; + }, + }, + ], +}); + +export const convertIPRangeToString = (range: IpRangeKey, format: (val: any) => string) => { + if (range.type === 'mask') { + return format(range.mask); + } + const from = range.from ? format(range.from) : '-Infinity'; + const to = range.to ? format(range.to) : 'Infinity'; + + return `${from} to ${to}`; +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.test.ts new file mode 100644 index 0000000000000..01dd3ddf1b874 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.test.ts @@ -0,0 +1,75 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { CidrMask } from './cidr_mask'; + +describe('CidrMask', () => { + test('should throw errors with invalid CIDR masks', () => { + expect( + () => + // @ts-ignore + new CidrMask() + ).toThrowError(); + + expect(() => new CidrMask('')).toThrowError(); + expect(() => new CidrMask('hello, world')).toThrowError(); + expect(() => new CidrMask('0.0.0.0')).toThrowError(); + expect(() => new CidrMask('0.0.0.0/0')).toThrowError(); + expect(() => new CidrMask('0.0.0.0/33')).toThrowError(); + expect(() => new CidrMask('256.0.0.0/32')).toThrowError(); + expect(() => new CidrMask('0.0.0.0/32/32')).toThrowError(); + expect(() => new CidrMask('1.2.3/1')).toThrowError(); + expect(() => new CidrMask('0.0.0.0/123d')).toThrowError(); + }); + + test('should correctly grab IP address and prefix length', () => { + let mask = new CidrMask('0.0.0.0/1'); + expect(mask.initialAddress.toString()).toBe('0.0.0.0'); + expect(mask.prefixLength).toBe(1); + + mask = new CidrMask('128.0.0.1/31'); + expect(mask.initialAddress.toString()).toBe('128.0.0.1'); + expect(mask.prefixLength).toBe(31); + }); + + test('should calculate a range of IP addresses', () => { + let mask = new CidrMask('0.0.0.0/1'); + let range = mask.getRange(); + expect(range.from.toString()).toBe('0.0.0.0'); + expect(range.to.toString()).toBe('127.255.255.255'); + + mask = new CidrMask('1.2.3.4/2'); + range = mask.getRange(); + expect(range.from.toString()).toBe('0.0.0.0'); + expect(range.to.toString()).toBe('63.255.255.255'); + + mask = new CidrMask('67.129.65.201/27'); + range = mask.getRange(); + expect(range.from.toString()).toBe('67.129.65.192'); + expect(range.to.toString()).toBe('67.129.65.223'); + }); + + test('toString()', () => { + let mask = new CidrMask('.../1'); + expect(mask.toString()).toBe('0.0.0.0/1'); + + mask = new CidrMask('128.0.0.1/31'); + expect(mask.toString()).toBe('128.0.0.1/31'); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts new file mode 100644 index 0000000000000..aadbbc8c82276 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts @@ -0,0 +1,58 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Ipv4Address } from '../../../../../../plugins/kibana_utils/public'; + +const NUM_BITS = 32; + +function throwError(mask: string) { + throw Error('Invalid CIDR mask: ' + mask); +} + +export class CidrMask { + public readonly initialAddress: Ipv4Address; + public readonly prefixLength: number; + + constructor(mask: string) { + const splits = mask.split('/'); + if (splits.length !== 2) { + throwError(mask); + } + this.initialAddress = new Ipv4Address(splits[0]); + this.prefixLength = Number(splits[1]); + if (isNaN(this.prefixLength) || this.prefixLength < 1 || this.prefixLength > NUM_BITS) { + throwError(mask); + } + } + + public getRange() { + const variableBits = NUM_BITS - this.prefixLength; + // eslint-disable-next-line no-bitwise + const fromAddress = ((this.initialAddress.valueOf() >> variableBits) << variableBits) >>> 0; // >>> 0 coerces to unsigned + const numAddresses = Math.pow(2, variableBits); + return { + from: new Ipv4Address(fromAddress).toString(), + to: new Ipv4Address(fromAddress + numAddresses - 1).toString(), + }; + } + + public toString() { + return this.initialAddress.toString() + '/' + this.prefixLength; + } +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/geo_utils.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/geo_utils.ts new file mode 100644 index 0000000000000..639b6d1fbb03e --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/geo_utils.ts @@ -0,0 +1,75 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import _ from 'lodash'; + +interface GeoBoundingBoxCoordinate { + lat: number; + lon: number; +} + +export interface GeoBoundingBox { + top_left: GeoBoundingBoxCoordinate; + bottom_right: GeoBoundingBoxCoordinate; +} + +export function geoContains(collar: GeoBoundingBox, bounds: GeoBoundingBox) { + // test if bounds top_left is outside collar + if (bounds.top_left.lat > collar.top_left.lat || bounds.top_left.lon < collar.top_left.lon) { + return false; + } + + // test if bounds bottom_right is outside collar + if ( + bounds.bottom_right.lat < collar.bottom_right.lat || + bounds.bottom_right.lon > collar.bottom_right.lon + ) { + return false; + } + + // both corners are inside collar so collar contains bounds + return true; +} + +export function scaleBounds(bounds: GeoBoundingBox): GeoBoundingBox { + const scale = 0.5; // scale bounds by 50% + + const topLeft = bounds.top_left; + const bottomRight = bounds.bottom_right; + let latDiff = _.round(Math.abs(topLeft.lat - bottomRight.lat), 5); + const lonDiff = _.round(Math.abs(bottomRight.lon - topLeft.lon), 5); + // map height can be zero when vis is first created + if (latDiff === 0) latDiff = lonDiff; + + const latDelta = latDiff * scale; + let topLeftLat = _.round(topLeft.lat, 5) + latDelta; + if (topLeftLat > 90) topLeftLat = 90; + let bottomRightLat = _.round(bottomRight.lat, 5) - latDelta; + if (bottomRightLat < -90) bottomRightLat = -90; + const lonDelta = lonDiff * scale; + let topLeftLon = _.round(topLeft.lon, 5) - lonDelta; + if (topLeftLon < -180) topLeftLon = -180; + let bottomRightLon = _.round(bottomRight.lon, 5) + lonDelta; + if (bottomRightLon > 180) bottomRightLon = 180; + + return { + top_left: { lat: topLeftLat, lon: topLeftLon }, + bottom_right: { lat: bottomRightLat, lon: bottomRightLon }, + }; +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts new file mode 100644 index 0000000000000..77e84e044de55 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts @@ -0,0 +1,53 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { isString, isObject } from 'lodash'; +import { IBucketAggConfig, BucketAggType, BucketAggParam } from './_bucket_agg_type'; +import { AggConfig } from '../agg_config'; + +export const isType = (type: string) => { + return (agg: AggConfig): boolean => { + const field = agg.params.field; + + return field && field.type === type; + }; +}; + +export const isStringType = isType('string'); + +export const migrateIncludeExcludeFormat = { + serialize(this: BucketAggParam, value: any, agg: IBucketAggConfig) { + if (this.shouldShow && !this.shouldShow(agg)) return; + if (!value || isString(value)) return value; + else return value.pattern; + }, + write( + this: BucketAggType, + aggConfig: IBucketAggConfig, + output: Record + ) { + const value = aggConfig.getParam(this.name); + + if (isObject(value)) { + output.params[this.name] = value.pattern; + } else if (value && isStringType(aggConfig)) { + output.params[this.name] = value; + } + }, +} as Partial>; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts new file mode 100644 index 0000000000000..dd85c3b31939f --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts @@ -0,0 +1,99 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AggConfigs } from '../agg_configs'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { fieldFormats } from '../../../../../plugins/data/public'; + +jest.mock('ui/new_platform'); + +const buckets = [ + { + to: 1024, + to_as_string: '1024.0', + doc_count: 20904, + }, + { + from: 1024, + from_as_string: '1024.0', + to: 2560, + to_as_string: '2560.0', + doc_count: 23358, + }, + { + from: 2560, + from_as_string: '2560.0', + doc_count: 174250, + }, +]; + +describe('Range Agg', () => { + const getConfig = (() => {}) as fieldFormats.GetConfigFn; + const getAggConfigs = () => { + const field = { + name: 'bytes', + format: new fieldFormats.NumberFormat( + { + pattern: '0,0.[000] b', + }, + getConfig + ), + }; + + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + return new AggConfigs( + indexPattern, + [ + { + type: BUCKET_TYPES.RANGE, + schema: 'segment', + params: { + field: 'bytes', + ranges: [ + { from: 0, to: 1000 }, + { from: 1000, to: 2000 }, + ], + }, + }, + ], + null + ); + }; + + describe('formating', () => { + it('formats bucket keys properly', () => { + const aggConfigs = getAggConfigs(); + const agg = aggConfigs.aggs[0]; + + const format = (val: any) => agg.fieldFormatter()(agg.getKey(val)); + + expect(format(buckets[0])).toBe('≥ -∞ and < 1 KB'); + expect(format(buckets[1])).toBe('≥ 1 KB and < 2.5 KB'); + expect(format(buckets[2])).toBe('≥ 2.5 KB and < +∞'); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts new file mode 100644 index 0000000000000..f24473e0c68aa --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts @@ -0,0 +1,106 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { BucketAggType } from './_bucket_agg_type'; +import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { RangeKey } from './range_key'; +import { createFilterRange } from './create_filter/range'; +import { BUCKET_TYPES } from './bucket_agg_types'; + +const keyCaches = new WeakMap(); +const formats = new WeakMap(); + +const rangeTitle = i18n.translate('common.ui.aggTypes.buckets.rangeTitle', { + defaultMessage: 'Range', +}); + +export const rangeBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.RANGE, + title: rangeTitle, + createFilter: createFilterRange, + makeLabel(aggConfig) { + return i18n.translate('common.ui.aggTypes.buckets.rangesLabel', { + defaultMessage: '{fieldName} ranges', + values: { + fieldName: aggConfig.getFieldDisplayName(), + }, + }); + }, + getKey(bucket, key, agg) { + let keys = keyCaches.get(agg); + + 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(agg) { + let aggFormat = formats.get(agg); + if (aggFormat) return aggFormat; + + const RangeFormat = fieldFormats.FieldFormat.from((range: any) => { + const format = agg.fieldOwnFormatter(); + const gte = '\u2265'; + const lt = '\u003c'; + return i18n.translate('common.ui.aggTypes.buckets.ranges.rangesFormatMessage', { + defaultMessage: '{gte} {from} and {lt} {to}', + values: { + gte, + from: format(range.gte), + lt, + to: format(range.lt), + }, + }); + }); + + aggFormat = new RangeFormat(); + + formats.set(agg, aggFormat); + return aggFormat; + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: [KBN_FIELD_TYPES.NUMBER], + }, + { + name: 'ranges', + default: [ + { from: 0, to: 1000 }, + { from: 1000, to: 2000 }, + ], + write(aggConfig, output) { + output.params.ranges = aggConfig.params.ranges; + output.params.keyed = true; + }, + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/range_key.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/range_key.ts new file mode 100644 index 0000000000000..cd781f7e082a2 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/range_key.ts @@ -0,0 +1,41 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const id = Symbol('id'); + +export class RangeKey { + [id]: string; + gte: string | number; + lt: string | number; + + constructor(bucket: any) { + this.gte = bucket.from == null ? -Infinity : bucket.from; + this.lt = bucket.to == null ? +Infinity : bucket.to; + + this[id] = RangeKey.idBucket(bucket); + } + + static idBucket(bucket: any) { + return `from:${bucket.from},to:${bucket.to}`; + } + + toString() { + return this[id]; + } +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts new file mode 100644 index 0000000000000..8db9226e41eec --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts @@ -0,0 +1,111 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AggConfigs } from '../index'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { significantTermsBucketAgg } from './significant_terms'; +import { IBucketAggConfig } from './_bucket_agg_type'; + +jest.mock('ui/new_platform'); + +describe('Significant Terms Agg', () => { + describe('order agg editor UI', () => { + describe('convert include/exclude from old format', () => { + const getAggConfigs = (params: Record = {}) => { + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + const field = { + name: 'field', + indexPattern, + }; + + return new AggConfigs( + indexPattern, + [ + { + id: 'test', + type: BUCKET_TYPES.SIGNIFICANT_TERMS, + schema: 'segment', + params, + }, + ], + null + ); + }; + + const testSerializeAndWrite = (aggs: AggConfigs) => { + const agg = aggs.aggs[0]; + const { [BUCKET_TYPES.SIGNIFICANT_TERMS]: params } = agg.toDsl(); + + expect(params.field).toBe('field'); + expect(params.include).toBe('404'); + expect(params.exclude).toBe('400'); + }; + + it('should generate correct label', () => { + const aggConfigs = getAggConfigs({ + size: 'SIZE', + field: { + name: 'FIELD', + }, + }); + const label = significantTermsBucketAgg.makeLabel(aggConfigs.aggs[0] as IBucketAggConfig); + + expect(label).toBe('Top SIZE unusual terms in FIELD'); + }); + + it('should doesnt do anything with string type', () => { + const aggConfigs = getAggConfigs({ + include: '404', + exclude: '400', + field: { + name: 'field', + type: 'string', + }, + }); + + testSerializeAndWrite(aggConfigs); + }); + + it('should converts object to string type', () => { + const aggConfigs = getAggConfigs({ + include: { + pattern: '404', + }, + exclude: { + pattern: '400', + }, + field: { + name: 'field', + type: 'string', + }, + }); + + testSerializeAndWrite(aggConfigs); + }); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts new file mode 100644 index 0000000000000..38ca0768d3bc1 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts @@ -0,0 +1,76 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { BucketAggType } from './_bucket_agg_type'; +import { createFilterTerms } from './create_filter/terms'; +import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +const significantTermsTitle = i18n.translate('common.ui.aggTypes.buckets.significantTermsTitle', { + defaultMessage: 'Significant Terms', +}); + +export const significantTermsBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.SIGNIFICANT_TERMS, + title: significantTermsTitle, + makeLabel(aggConfig) { + return i18n.translate('common.ui.aggTypes.buckets.significantTermsLabel', { + defaultMessage: 'Top {size} unusual terms in {fieldName}', + values: { + size: aggConfig.params.size, + fieldName: aggConfig.getFieldDisplayName(), + }, + }); + }, + createFilter: createFilterTerms, + params: [ + { + name: 'field', + type: 'field', + scriptable: false, + filterFieldTypes: KBN_FIELD_TYPES.STRING, + }, + { + name: 'size', + default: '', + }, + { + name: 'exclude', + displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.excludeLabel', { + defaultMessage: 'Exclude', + }), + type: 'string', + advanced: true, + shouldShow: isStringType, + ...migrateIncludeExcludeFormat, + }, + { + name: 'include', + displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.includeLabel', { + defaultMessage: 'Include', + }), + type: 'string', + advanced: true, + shouldShow: isStringType, + ...migrateIncludeExcludeFormat, + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.test.ts new file mode 100644 index 0000000000000..24ac332ae4d55 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.test.ts @@ -0,0 +1,78 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AggConfigs } from '../index'; +import { BUCKET_TYPES } from './bucket_agg_types'; + +jest.mock('ui/new_platform'); + +describe('Terms Agg', () => { + describe('order agg editor UI', () => { + const getAggConfigs = (params: Record = {}) => { + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + const field = { + name: 'field', + indexPattern, + }; + + return new AggConfigs( + indexPattern, + [ + { + id: 'test', + params, + type: BUCKET_TYPES.TERMS, + }, + ], + null + ); + }; + + it('converts object to string type', function() { + const aggConfigs = getAggConfigs({ + include: { + pattern: '404', + }, + exclude: { + pattern: '400', + }, + field: { + name: 'field', + }, + orderAgg: { + type: 'count', + }, + }); + + const { [BUCKET_TYPES.TERMS]: params } = aggConfigs.aggs[0].toDsl(); + + expect(params.field).toBe('field'); + expect(params.include).toBe('404'); + expect(params.exclude).toBe('400'); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts new file mode 100644 index 0000000000000..4ced1417402b5 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts @@ -0,0 +1,290 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { noop } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { + getRequestInspectorStats, + getResponseInspectorStats, +} from '../../../../core_plugins/data/public'; +import { BucketAggType } from './_bucket_agg_type'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { IBucketAggConfig } from './_bucket_agg_type'; +import { createFilterTerms } from './create_filter/terms'; +import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; +import { AggConfigs } from '../agg_configs'; + +import { Adapters } from '../../../../../plugins/inspector/public'; +import { ISearchSource, fieldFormats, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +import { + buildOtherBucketAgg, + mergeOtherBucketAggResponse, + updateMissingBucket, + // @ts-ignore +} from './_terms_other_bucket_helper'; +import { Schemas } from '../schemas'; +import { AggGroupNames } from '../agg_groups'; + +export const termsAggFilter = [ + '!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: AggGroupNames.None, + name: 'orderAgg', + // This string is never visible to the user so it doesn't need to be translated + title: 'Order Agg', + hideCustomLabel: true, + aggFilter: termsAggFilter, + }, +]).all; + +const termsTitle = i18n.translate('common.ui.aggTypes.buckets.termsTitle', { + defaultMessage: 'Terms', +}); + +export const termsBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.TERMS, + title: termsTitle, + makeLabel(agg) { + const params = agg.params; + return agg.getFieldDisplayName() + ': ' + params.order.text; + }, + getFormat(bucket): fieldFormats.FieldFormat { + return { + getConverterFor: (type: fieldFormats.ContentType) => { + return (val: any) => { + if (val === '__other__') { + return bucket.params.otherBucketLabel; + } + if (val === '__missing__') { + return bucket.params.missingBucketLabel; + } + + return bucket.params.field.format.convert(val, type); + }; + }, + } as fieldFormats.FieldFormat; + }, + createFilter: createFilterTerms, + postFlightRequest: async ( + resp: any, + aggConfigs: AggConfigs, + aggConfig: IBucketAggConfig, + searchSource: ISearchSource, + inspectorAdapters: Adapters, + abortSignal?: AbortSignal + ) => { + if (!resp.aggregations) return resp; + const nestedSearchSource = searchSource.createChild(); + if (aggConfig.params.otherBucket) { + const filterAgg = buildOtherBucketAgg(aggConfigs, aggConfig, resp); + if (!filterAgg) return resp; + + nestedSearchSource.setField('aggs', filterAgg); + + const request = inspectorAdapters.requests.start( + i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketTitle', { + defaultMessage: 'Other bucket', + }), + { + description: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketDescription', { + defaultMessage: + 'This request counts the number of documents that fall ' + + 'outside the criterion of the data buckets.', + }), + } + ); + nestedSearchSource.getSearchRequestBody().then((body: string) => { + request.json(body); + }); + request.stats(getRequestInspectorStats(nestedSearchSource)); + + const response = await nestedSearchSource.fetch({ abortSignal }); + request.stats(getResponseInspectorStats(nestedSearchSource, response)).ok({ json: response }); + resp = mergeOtherBucketAggResponse(aggConfigs, resp, response, aggConfig, filterAgg()); + } + if (aggConfig.params.missingBucket) { + resp = updateMissingBucket(resp, aggConfigs, aggConfig); + } + return resp; + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: [ + KBN_FIELD_TYPES.NUMBER, + KBN_FIELD_TYPES.BOOLEAN, + KBN_FIELD_TYPES.DATE, + KBN_FIELD_TYPES.IP, + KBN_FIELD_TYPES.STRING, + ], + }, + { + name: 'orderBy', + write: noop, // prevent default write, it's handled by orderAgg + }, + { + name: 'orderAgg', + type: 'agg', + default: null, + makeAgg(termsAgg, state) { + state = state || {}; + state.schema = orderAggSchema; + const orderAgg = termsAgg.aggConfigs.createAggConfig(state, { + addToAggConfigs: false, + }); + orderAgg.id = termsAgg.id + '-orderAgg'; + + return orderAgg; + }, + write(agg, output, aggs) { + const dir = agg.params.order.value; + const order: Record = (output.params.order = {}); + + let orderAgg = agg.params.orderAgg || 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.value_type = + 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') { + order._count = dir; + return; + } + + const orderAggId = orderAgg.id; + + if (orderAgg.parentId && aggs) { + orderAgg = aggs.byId(orderAgg.parentId); + } + + output.subAggs = (output.subAggs || []).concat(orderAgg); + order[orderAggId] = dir; + }, + }, + { + name: 'order', + type: 'optioned', + default: 'desc', + options: [ + { + text: i18n.translate('common.ui.aggTypes.buckets.terms.orderDescendingTitle', { + defaultMessage: 'Descending', + }), + value: 'desc', + }, + { + text: i18n.translate('common.ui.aggTypes.buckets.terms.orderAscendingTitle', { + defaultMessage: 'Ascending', + }), + value: 'asc', + }, + ], + write: noop, // prevent default write, it's handled by orderAgg + }, + { + name: 'size', + default: 5, + }, + { + name: 'otherBucket', + default: false, + write: noop, + }, + { + name: 'otherBucketLabel', + type: 'string', + default: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketLabel', { + defaultMessage: 'Other', + }), + displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForOtherBucketLabel', { + defaultMessage: 'Label for other bucket', + }), + shouldShow: agg => agg.getParam('otherBucket'), + write: noop, + }, + { + name: 'missingBucket', + default: false, + write: noop, + }, + { + name: 'missingBucketLabel', + default: i18n.translate('common.ui.aggTypes.buckets.terms.missingBucketLabel', { + defaultMessage: 'Missing', + description: `Default label used in charts when documents are missing a field. + Visible when you create a chart with a terms aggregation and enable "Show missing values"`, + }), + type: 'string', + displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForMissingValuesLabel', { + defaultMessage: 'Label for missing values', + }), + shouldShow: agg => agg.getParam('missingBucket'), + write: noop, + }, + { + name: 'exclude', + displayName: i18n.translate('common.ui.aggTypes.buckets.terms.excludeLabel', { + defaultMessage: 'Exclude', + }), + type: 'string', + advanced: true, + shouldShow: isStringType, + ...migrateIncludeExcludeFormat, + }, + { + name: 'include', + displayName: i18n.translate('common.ui.aggTypes.buckets.terms.includeLabel', { + defaultMessage: 'Include', + }), + type: 'string', + advanced: true, + shouldShow: isStringType, + ...migrateIncludeExcludeFormat, + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts new file mode 100644 index 0000000000000..0344f304877f2 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts @@ -0,0 +1,62 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IndexPattern } from '../../../../../plugins/data/public'; +import { AggTypeFilters } from './agg_type_filters'; +import { AggConfig, AggType } from '..'; + +describe('AggTypeFilters', () => { + let registry: AggTypeFilters; + const indexPattern = ({ id: '1234', fields: [], title: 'foo' } as unknown) as IndexPattern; + const aggConfig = {} as AggConfig; + + beforeEach(() => { + registry = new AggTypeFilters(); + }); + + it('should filter nothing without registered filters', async () => { + const aggTypes = [{ name: 'count' }, { name: 'sum' }] as AggType[]; + const filtered = registry.filter(aggTypes, indexPattern, aggConfig); + expect(filtered).toEqual(aggTypes); + }); + + it('should pass all aggTypes to the registered filter', async () => { + const aggTypes = [{ name: 'count' }, { name: 'sum' }] as AggType[]; + const filter = jest.fn(); + registry.addFilter(filter); + registry.filter(aggTypes, indexPattern, aggConfig); + expect(filter).toHaveBeenCalledWith(aggTypes[0], indexPattern, aggConfig); + expect(filter).toHaveBeenCalledWith(aggTypes[1], indexPattern, aggConfig); + }); + + it('should allow registered filters to filter out aggTypes', async () => { + const aggTypes = [{ name: 'count' }, { name: 'sum' }, { name: 'avg' }] as AggType[]; + let filtered = registry.filter(aggTypes, indexPattern, aggConfig); + expect(filtered).toEqual(aggTypes); + + registry.addFilter(() => true); + registry.addFilter(aggType => aggType.name !== 'count'); + filtered = registry.filter(aggTypes, indexPattern, aggConfig); + expect(filtered).toEqual([aggTypes[1], aggTypes[2]]); + + registry.addFilter(aggType => aggType.name !== 'avg'); + filtered = registry.filter(aggTypes, indexPattern, aggConfig); + expect(filtered).toEqual([aggTypes[1]]); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts new file mode 100644 index 0000000000000..2cc4a6e962214 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts @@ -0,0 +1,64 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { IndexPattern } from 'src/plugins/data/public'; +import { AggType, AggConfig } from '..'; + +type AggTypeFilter = ( + aggType: AggType, + indexPattern: IndexPattern, + aggConfig: AggConfig +) => boolean; + +/** + * A registry to store {@link AggTypeFilter} which are used to filter down + * available aggregations for a specific visualization and {@link AggConfig}. + */ +class AggTypeFilters { + private filters = new Set(); + + /** + * Register a new {@link AggTypeFilter} with this registry. + * + * @param filter The filter to register. + */ + public addFilter(filter: AggTypeFilter): void { + this.filters.add(filter); + } + + /** + * Returns the {@link AggType|aggTypes} filtered by all registered filters. + * + * @param aggTypes A list of aggTypes that will be filtered down by this registry. + * @param indexPattern The indexPattern for which this list should be filtered down. + * @param aggConfig The aggConfig for which the returning list will be used. + * @return A filtered list of the passed aggTypes. + */ + public filter(aggTypes: AggType[], indexPattern: IndexPattern, aggConfig: AggConfig) { + const allFilters = Array.from(this.filters); + const allowedAggTypes = aggTypes.filter(aggType => { + const isAggTypeAllowed = allFilters.every(filter => filter(aggType, indexPattern, aggConfig)); + return isAggTypeAllowed; + }); + return allowedAggTypes; + } +} + +const aggTypeFilters = new AggTypeFilters(); + +export { aggTypeFilters, AggTypeFilters }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/index.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/index.ts new file mode 100644 index 0000000000000..3fc577e7e9a23 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/filter/index.ts @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { aggTypeFilters } from './agg_type_filters'; +export { propFilter } from './prop_filter'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.test.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.test.ts new file mode 100644 index 0000000000000..431e1161e0dbd --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.test.ts @@ -0,0 +1,94 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import expect from '@kbn/expect'; +import { propFilter } from './prop_filter'; + +describe('prop filter', () => { + let nameFilter: Function; + + beforeEach(() => { + nameFilter = propFilter('name'); + }); + + const getObjects = (...names: string[]) => { + const count = new Map(); + const objects = []; + + for (const name of names) { + if (!count.has(name)) { + count.set(name, 1); + } + objects.push({ + name, + title: `${name} ${count.get(name)}`, + }); + count.set(name, count.get(name) + 1); + } + + return objects; + }; + + it('returns list when no filters are provided', () => { + const objects = getObjects('table', 'table', 'pie'); + expect(nameFilter(objects)).to.eql(objects); + }); + + it('returns list when empty list of filters is provided', () => { + const objects = getObjects('table', 'table', 'pie'); + expect(nameFilter(objects, [])).to.eql(objects); + }); + + it('should keep only the tables', () => { + const objects = getObjects('table', 'table', 'pie'); + expect(nameFilter(objects, 'table')).to.eql(getObjects('table', 'table')); + }); + + it('should support comma-separated values', () => { + const objects = getObjects('table', 'line', 'pie'); + expect(nameFilter(objects, 'table,line')).to.eql(getObjects('table', 'line')); + }); + + it('should support an array of values', () => { + const objects = getObjects('table', 'line', 'pie'); + expect(nameFilter(objects, ['table', 'line'])).to.eql(getObjects('table', 'line')); + }); + + it('should return all objects', () => { + const objects = getObjects('table', 'line', 'pie'); + expect(nameFilter(objects, '*')).to.eql(objects); + }); + + it('should allow negation', () => { + const objects = getObjects('table', 'line', 'pie'); + expect(nameFilter(objects, ['!line'])).to.eql(getObjects('table', 'pie')); + }); + + it('should support a function for specifying what should be kept', () => { + const objects = getObjects('table', 'line', 'pie'); + const line = (value: string) => value === 'line'; + expect(nameFilter(objects, line)).to.eql(getObjects('line')); + }); + + it('gracefully handles a filter function with zero arity', () => { + const objects = getObjects('table', 'line', 'pie'); + const rejectEverything = () => false; + expect(nameFilter(objects, rejectEverything)).to.eql([]); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.ts new file mode 100644 index 0000000000000..e6b5f3831e65d --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.ts @@ -0,0 +1,96 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { isFunction } from 'lodash'; + +type FilterFunc

= (item: T[P]) => boolean; + +/** + * Filters out a list by a given filter. This is currently used to implement: + * - fieldType filters a list of fields by their type property + * - aggFilter filters a list of aggs by their name property + * + * @returns the filter function which can be registered with angular + */ +function propFilter

(prop: P) { + /** + * List filtering function which accepts an array or list of values that a property + * must contain + * + * @param {array} list - array of items to filter + * @param {function|array|string} filters - the values to match against the list + * - if a function, it is expected to take the field property as argument and returns true to keep it. + * - Can be also an array, a single value as a string, or a comma-separated list of items + * @return {array} - the filtered list + */ + return function filterByName( + list: T[], + filters: string[] | string | FilterFunc = [] + ): T[] { + if (isFunction(filters)) { + return list.filter(item => (filters as FilterFunc)(item[prop])); + } + + if (!Array.isArray(filters)) { + filters = filters.split(','); + } + + if (filters.length === 0) { + return list; + } + + if (filters.includes('*')) { + return list; + } + + const options = filters.reduce((acc, filter) => { + let type = 'include'; + let value = filter; + + if (filter.charAt(0) === '!') { + type = 'exclude'; + value = filter.substr(1); + } + + if (!acc[type]) { + acc[type] = []; + } + acc[type].push(value); + return acc; + }, {} as { [type: string]: string[] }); + + return list.filter(item => { + const value = item[prop]; + + const excluded = options.exclude && options.exclude.includes(value); + if (excluded) { + return false; + } + + const included = !options.include || options.include.includes(value); + if (included) { + return true; + } + + return false; + }); + }; +} + +export { propFilter }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/index.test.ts b/src/legacy/core_plugins/data/public/search/aggs/index.test.ts new file mode 100644 index 0000000000000..a867769a77fc1 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/index.test.ts @@ -0,0 +1,46 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { aggTypes } from './index'; + +import { isBucketAggType } from './buckets/_bucket_agg_type'; +import { isMetricAggType } from './metrics/metric_agg_type'; + +const bucketAggs = aggTypes.buckets; +const metricAggs = aggTypes.metrics; + +jest.mock('ui/new_platform'); + +describe('AggTypesComponent', () => { + describe('bucket aggs', () => { + it('all extend BucketAggType', () => { + bucketAggs.forEach(bucketAgg => { + expect(isBucketAggType(bucketAgg)).toBeTruthy(); + }); + }); + }); + + describe('metric aggs', () => { + it('all extend MetricAggType', () => { + metricAggs.forEach(metricAgg => { + expect(isMetricAggType(metricAgg)).toBeTruthy(); + }); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/index.ts b/src/legacy/core_plugins/data/public/search/aggs/index.ts new file mode 100644 index 0000000000000..ca7c2f82023c9 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/index.ts @@ -0,0 +1,103 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +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, setBounds } 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, termsAggFilter } 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 { geoTileBucketAgg } from './buckets/geo_tile'; +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 { AggType } from './agg_type'; + +export const aggTypes = { + 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, + geoTileBucketAgg, + ], +}; + +export { AggParam } from './agg_params'; +export { AggConfig } from './agg_config'; +export { AggConfigs } from './agg_configs'; +export { AggGroupNames, aggGroupNamesMap } from './agg_groups'; +export { FieldParamType } from './param_types'; +export { BUCKET_TYPES } from './buckets/bucket_agg_types'; +export { METRIC_TYPES } from './metrics/metric_agg_types'; +export { ISchemas, Schema, Schemas } from './schemas'; + +export { setBounds, termsAggFilter }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts new file mode 100644 index 0000000000000..0222a8e543223 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts @@ -0,0 +1,45 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { METRIC_TYPES } from './metric_agg_types'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +const averageTitle = i18n.translate('common.ui.aggTypes.metrics.averageTitle', { + defaultMessage: 'Average', +}); + +export const avgMetricAgg = new MetricAggType({ + name: METRIC_TYPES.AVG, + title: averageTitle, + makeLabel: aggConfig => { + return i18n.translate('common.ui.aggTypes.metrics.averageLabel', { + defaultMessage: 'Average {field}', + values: { field: aggConfig.getFieldDisplayName() }, + }); + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.NUMBER, + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts new file mode 100644 index 0000000000000..7142546dbd494 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts @@ -0,0 +1,57 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { get } from 'lodash'; + +import { MetricAggType } from './metric_agg_type'; +import { makeNestedLabel } from './lib/make_nested_label'; +import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; +import { METRIC_TYPES } from './metric_agg_types'; + +const overallAverageLabel = i18n.translate('common.ui.aggTypes.metrics.overallAverageLabel', { + defaultMessage: 'overall average', +}); + +const averageBucketTitle = i18n.translate('common.ui.aggTypes.metrics.averageBucketTitle', { + defaultMessage: 'Average Bucket', +}); + +export const bucketAvgMetricAgg = new MetricAggType({ + name: METRIC_TYPES.AVG_BUCKET, + title: averageBucketTitle, + makeLabel: agg => makeNestedLabel(agg, overallAverageLabel), + subtype: siblingPipelineAggHelper.subtype, + params: [...siblingPipelineAggHelper.params()], + getFormat: siblingPipelineAggHelper.getFormat, + getValue(agg, bucket) { + const customMetric = agg.getParam('customMetric'); + const customBucket = agg.getParam('customBucket'); + const scaleMetrics = customMetric.type && customMetric.type.isScalable(); + + let value = bucket[agg.id] && bucket[agg.id].value; + + if (scaleMetrics && customBucket.type.name === 'date_histogram') { + const aggInfo = customBucket.write(); + + value *= get(aggInfo, 'bucketInterval.scale', 1); + } + return value; + }, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts new file mode 100644 index 0000000000000..aa5b0521709a5 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts @@ -0,0 +1,42 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; + +import { MetricAggType } from './metric_agg_type'; +import { makeNestedLabel } from './lib/make_nested_label'; +import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; +import { METRIC_TYPES } from './metric_agg_types'; + +const overallMaxLabel = i18n.translate('common.ui.aggTypes.metrics.overallMaxLabel', { + defaultMessage: 'overall max', +}); + +const maxBucketTitle = i18n.translate('common.ui.aggTypes.metrics.maxBucketTitle', { + defaultMessage: 'Max Bucket', +}); + +export const bucketMaxMetricAgg = new MetricAggType({ + name: METRIC_TYPES.MAX_BUCKET, + title: maxBucketTitle, + makeLabel: agg => makeNestedLabel(agg, overallMaxLabel), + subtype: siblingPipelineAggHelper.subtype, + params: [...siblingPipelineAggHelper.params()], + getFormat: siblingPipelineAggHelper.getFormat, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts new file mode 100644 index 0000000000000..b5c0b8865e106 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts @@ -0,0 +1,40 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { makeNestedLabel } from './lib/make_nested_label'; +import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; +import { METRIC_TYPES } from './metric_agg_types'; + +const overallMinLabel = i18n.translate('common.ui.aggTypes.metrics.overallMinLabel', { + defaultMessage: 'overall min', +}); + +const minBucketTitle = i18n.translate('common.ui.aggTypes.metrics.minBucketTitle', { + defaultMessage: 'Min Bucket', +}); + +export const bucketMinMetricAgg = new MetricAggType({ + name: METRIC_TYPES.MIN_BUCKET, + title: minBucketTitle, + makeLabel: agg => makeNestedLabel(agg, overallMinLabel), + subtype: siblingPipelineAggHelper.subtype, + params: [...siblingPipelineAggHelper.params()], + getFormat: siblingPipelineAggHelper.getFormat, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts new file mode 100644 index 0000000000000..d4faa81c4041c --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts @@ -0,0 +1,41 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { makeNestedLabel } from './lib/make_nested_label'; +import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; +import { METRIC_TYPES } from './metric_agg_types'; + +const overallSumLabel = i18n.translate('common.ui.aggTypes.metrics.overallSumLabel', { + defaultMessage: 'overall sum', +}); + +const sumBucketTitle = i18n.translate('common.ui.aggTypes.metrics.sumBucketTitle', { + defaultMessage: 'Sum Bucket', +}); + +export const bucketSumMetricAgg = new MetricAggType({ + name: METRIC_TYPES.SUM_BUCKET, + title: sumBucketTitle, + makeLabel: agg => makeNestedLabel(agg, overallSumLabel), + subtype: siblingPipelineAggHelper.subtype, + params: [...siblingPipelineAggHelper.params()], + getFormat: siblingPipelineAggHelper.getFormat, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts new file mode 100644 index 0000000000000..c69ffae3b4871 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts @@ -0,0 +1,50 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { npStart } from 'ui/new_platform'; +import { MetricAggType } from './metric_agg_type'; +import { METRIC_TYPES } from './metric_agg_types'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +const uniqueCountTitle = i18n.translate('common.ui.aggTypes.metrics.uniqueCountTitle', { + defaultMessage: 'Unique Count', +}); + +export const cardinalityMetricAgg = new MetricAggType({ + name: METRIC_TYPES.CARDINALITY, + title: uniqueCountTitle, + makeLabel(aggConfig) { + return i18n.translate('common.ui.aggTypes.metrics.uniqueCountLabel', { + defaultMessage: 'Unique count of {field}', + values: { field: aggConfig.getFieldDisplayName() }, + }); + }, + getFormat() { + const fieldFormatsService = npStart.plugins.data.fieldFormats; + + return fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER); + }, + params: [ + { + name: 'field', + type: 'field', + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts new file mode 100644 index 0000000000000..22a939cd9a3fd --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts @@ -0,0 +1,48 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { npStart } from 'ui/new_platform'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { MetricAggType } from './metric_agg_type'; +import { METRIC_TYPES } from './metric_agg_types'; + +export const countMetricAgg = new MetricAggType({ + name: METRIC_TYPES.COUNT, + title: i18n.translate('common.ui.aggTypes.metrics.countTitle', { + defaultMessage: 'Count', + }), + hasNoDsl: true, + makeLabel() { + return i18n.translate('common.ui.aggTypes.metrics.countLabel', { + defaultMessage: 'Count', + }); + }, + getFormat() { + const fieldFormatsService = npStart.plugins.data.fieldFormats; + + return fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER); + }, + getValue(agg, bucket) { + return bucket.doc_count; + }, + isScalable() { + return true; + }, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts new file mode 100644 index 0000000000000..bad2de8cb16dc --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts @@ -0,0 +1,41 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; +import { makeNestedLabel } from './lib/make_nested_label'; +import { METRIC_TYPES } from './metric_agg_types'; + +const cumulativeSumLabel = i18n.translate('common.ui.aggTypes.metrics.cumulativeSumLabel', { + defaultMessage: 'cumulative sum', +}); + +const cumulativeSumTitle = i18n.translate('common.ui.aggTypes.metrics.cumulativeSumTitle', { + defaultMessage: 'Cumulative Sum', +}); + +export const cumulativeSumMetricAgg = new MetricAggType({ + name: METRIC_TYPES.CUMULATIVE_SUM, + title: cumulativeSumTitle, + subtype: parentPipelineAggHelper.subtype, + makeLabel: agg => makeNestedLabel(agg, cumulativeSumLabel), + params: [...parentPipelineAggHelper.params()], + getFormat: parentPipelineAggHelper.getFormat, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts new file mode 100644 index 0000000000000..42921621a2933 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts @@ -0,0 +1,43 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; +import { makeNestedLabel } from './lib/make_nested_label'; +import { METRIC_TYPES } from './metric_agg_types'; + +const derivativeLabel = i18n.translate('common.ui.aggTypes.metrics.derivativeLabel', { + defaultMessage: 'derivative', +}); + +const derivativeTitle = i18n.translate('common.ui.aggTypes.metrics.derivativeTitle', { + defaultMessage: 'Derivative', +}); + +export const derivativeMetricAgg = new MetricAggType({ + name: METRIC_TYPES.DERIVATIVE, + title: derivativeTitle, + subtype: parentPipelineAggHelper.subtype, + makeLabel(agg) { + return makeNestedLabel(agg, derivativeLabel); + }, + params: [...parentPipelineAggHelper.params()], + getFormat: parentPipelineAggHelper.getFormat, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts new file mode 100644 index 0000000000000..b8ce03cdf11ec --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts @@ -0,0 +1,44 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { METRIC_TYPES } from './metric_agg_types'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +const geoBoundsTitle = i18n.translate('common.ui.aggTypes.metrics.geoBoundsTitle', { + defaultMessage: 'Geo Bounds', +}); + +const geoBoundsLabel = i18n.translate('common.ui.aggTypes.metrics.geoBoundsLabel', { + defaultMessage: 'Geo Bounds', +}); + +export const geoBoundsMetricAgg = new MetricAggType({ + name: METRIC_TYPES.GEO_BOUNDS, + title: geoBoundsTitle, + makeLabel: () => geoBoundsLabel, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT, + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts new file mode 100644 index 0000000000000..5313e31796a5b --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts @@ -0,0 +1,47 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { METRIC_TYPES } from './metric_agg_types'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +const geoCentroidTitle = i18n.translate('common.ui.aggTypes.metrics.geoCentroidTitle', { + defaultMessage: 'Geo Centroid', +}); + +const geoCentroidLabel = i18n.translate('common.ui.aggTypes.metrics.geoCentroidLabel', { + defaultMessage: 'Geo Centroid', +}); + +export const geoCentroidMetricAgg = new MetricAggType({ + name: METRIC_TYPES.GEO_CENTROID, + title: geoCentroidTitle, + makeLabel: () => geoCentroidLabel, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT, + }, + ], + getValue(agg, bucket) { + return bucket[agg.id] && bucket[agg.id].location; + }, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/get_response_agg_config_class.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/get_response_agg_config_class.ts new file mode 100644 index 0000000000000..054543de3dd06 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/get_response_agg_config_class.ts @@ -0,0 +1,74 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { assign } from 'lodash'; +import { IMetricAggConfig } from '../metric_agg_type'; + +/** + * 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 const getResponseAggConfigClass = (agg: any, props: Partial) => { + if (agg.$$_ResponseAggConfigClass) { + return agg.$$_ResponseAggConfigClass; + } else { + return (agg.$$_ResponseAggConfigClass = create(agg, props)); + } +}; + +export interface IResponseAggConfig extends IMetricAggConfig { + key: string | number; + parentId: IMetricAggConfig['id']; +} + +export const create = (parentAgg: IMetricAggConfig, props: Partial) => { + /** + * 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(this: IResponseAggConfig, key: string) { + const parentId = parentAgg.id; + let id; + + const subId = String(key); + + if (subId.indexOf('.') > -1) { + id = parentId + "['" + subId.replace(/'/g, "\\'") + "']"; + } else { + id = parentId + '.' + subId; + } + + this.id = id; + this.key = key; + this.parentId = parentId; + } + + ResponseAggConfig.prototype = Object.create(parentAgg); + ResponseAggConfig.prototype.constructor = ResponseAggConfig; + + assign(ResponseAggConfig.prototype, props); + + return ResponseAggConfig; +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.test.ts new file mode 100644 index 0000000000000..479ff40b7c0ae --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.test.ts @@ -0,0 +1,59 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { makeNestedLabel } from './make_nested_label'; +import { IMetricAggConfig } from '../metric_agg_type'; + +describe('metric agg make_nested_label', () => { + const generateAggConfig = (metricLabel: string): IMetricAggConfig => { + return ({ + params: { + customMetric: { + makeLabel: () => { + return metricLabel; + }, + }, + }, + getParam(this: IMetricAggConfig, key: string) { + return this.params[key]; + }, + } as unknown) as IMetricAggConfig; + }; + + it('should return a metric label with prefix', () => { + const aggConfig = generateAggConfig('Count'); + const label = makeNestedLabel(aggConfig, 'derivative'); + + expect(label).toEqual('Derivative of Count'); + }); + + it('should return a numbered prefix', () => { + const aggConfig = generateAggConfig('Derivative of Count'); + const label = makeNestedLabel(aggConfig, 'derivative'); + + expect(label).toEqual('2. derivative of Count'); + }); + + it('should return a prefix with correct order', () => { + const aggConfig = generateAggConfig('3. derivative of Count'); + const label = makeNestedLabel(aggConfig, 'derivative'); + + expect(label).toEqual('4. derivative of Count'); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.ts new file mode 100644 index 0000000000000..95bcdf6e99fd9 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.ts @@ -0,0 +1,49 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { startCase } from 'lodash'; +import { IMetricAggConfig } from '../metric_agg_type'; + +export const makeNestedLabel = (aggConfig: IMetricAggConfig, label: string) => { + const uppercaseLabel = startCase(label); + const customMetric = aggConfig.getParam('customMetric'); + const metricAgg = aggConfig.getParam('metricAgg'); + + if (customMetric) { + let metricLabel = customMetric.makeLabel(); + + if (metricLabel.includes(`${uppercaseLabel} of `)) { + metricLabel = metricLabel.substring(`${uppercaseLabel} of `.length); + metricLabel = `2. ${label} of ${metricLabel}`; + } else if (metricLabel.includes(`${label} of `)) { + metricLabel = parseInt(metricLabel.substring(0, 1), 10) + 1 + metricLabel.substring(1); + } else { + metricLabel = `${uppercaseLabel} of ${metricLabel}`; + } + return metricLabel; + } + + const metric = aggConfig.aggConfigs.byId(metricAgg); + + if (!metric) { + return ''; + } + + return `${uppercaseLabel} of ${metric.makeLabel()}`; +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/nested_agg_helpers.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/nested_agg_helpers.ts new file mode 100644 index 0000000000000..a7bfb7b82b97f --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/nested_agg_helpers.ts @@ -0,0 +1,56 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; + +/** + * Forwards modifyAggConfigOnSearchRequestStart calls to a nested AggConfig. + * This must be used for each parameter, that accepts a nested aggregation, otherwise + * some parameters of the nested aggregation might not work properly (like auto interval + * on a nested date histogram). + * You should assign the return value of this function to the modifyAggConfigOnSearchRequestStart + * of the parameter that accepts a nested aggregation. Example: + * { + * name: 'customBucket', + * modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart('customBucket') + * } + * + * @param {string} paramName - The name of the parameter, that this function should forward + * calls to. That should match the name of the parameter the function is called on. + * @returns {function} A function, that forwards the calls. + */ +export const forwardModifyAggConfigOnSearchRequestStart = (paramName: string) => { + return (aggConfig: IMetricAggConfig, searchSource?: any, request?: any) => { + if (!aggConfig || !aggConfig.params) { + return; + } + + const nestedAggConfig = aggConfig.getParam(paramName); + + if (nestedAggConfig && nestedAggConfig.type && nestedAggConfig.type.params) { + nestedAggConfig.type.params.forEach((param: MetricAggParam) => { + // Check if this parameter of the nested aggConfig has a modifyAggConfigOnSearchRequestStart + // function, that needs to be called. + if (param.modifyAggConfigOnSearchRequestStart) { + param.modifyAggConfigOnSearchRequestStart(nestedAggConfig, searchSource, request); + } + }); + } + }; +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.test.ts new file mode 100644 index 0000000000000..18ee6b4de3204 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.test.ts @@ -0,0 +1,69 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { forOwn } from 'lodash'; +import { ordinalSuffix } from './ordinal_suffix'; + +describe('ordinal suffix util', () => { + const checks = { + 1: 'st', + 2: 'nd', + 3: 'rd', + 4: 'th', + 5: 'th', + 6: 'th', + 7: 'th', + 8: 'th', + 9: 'th', + 10: 'th', + 11: 'th', + 12: 'th', + 13: 'th', + 14: 'th', + 15: 'th', + 16: 'th', + 17: 'th', + 18: 'th', + 19: 'th', + 20: 'th', + 21: 'st', + 22: 'nd', + 23: 'rd', + 24: 'th', + 25: 'th', + 26: 'th', + 27: 'th', + 28: 'th', + 29: 'th', + 30: 'th', + }; + + forOwn(checks, (expected, num: any) => { + const int = parseInt(num, 10); + const float = int + Math.random(); + + it('knowns ' + int, () => { + expect(ordinalSuffix(num)).toBe(num + '' + expected); + }); + + it('knows ' + float, () => { + expect(ordinalSuffix(num)).toBe(num + '' + expected); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.ts new file mode 100644 index 0000000000000..21903995ebb2f --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.ts @@ -0,0 +1,36 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// adopted from http://stackoverflow.com/questions/3109978/php-display-number-with-ordinal-suffix +export function ordinalSuffix(num: any): string { + return num + '' + suffix(num); +} + +function suffix(num: any): string { + const int = Math.floor(parseFloat(num)); + + const hunth = int % 100; + if (hunth >= 11 && hunth <= 13) return 'th'; + + const tenth = int % 10; + if (tenth === 1) return 'st'; + if (tenth === 2) return 'nd'; + if (tenth === 3) return 'rd'; + return 'th'; +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts new file mode 100644 index 0000000000000..4d558e50304e6 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts @@ -0,0 +1,107 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { noop } from 'lodash'; + +import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; +import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; +import { parentPipelineAggWriter } from './parent_pipeline_agg_writer'; + +import { Schemas } from '../../schemas'; + +const metricAggFilter = [ + '!top_hits', + '!percentiles', + '!percentile_ranks', + '!median', + '!std_dev', + '!geo_bounds', + '!geo_centroid', +]; + +const metricAggTitle = i18n.translate('common.ui.aggTypes.metrics.metricAggTitle', { + defaultMessage: 'Metric agg', +}); + +const [metricAggSchema] = new Schemas([ + { + group: 'none', + name: 'metricAgg', + title: metricAggTitle, + hideCustomLabel: true, + aggFilter: metricAggFilter, + }, +]).all; + +const parentPipelineType = i18n.translate( + 'common.ui.aggTypes.metrics.parentPipelineAggregationsSubtypeTitle', + { + defaultMessage: 'Parent Pipeline Aggregations', + } +); + +const parentPipelineAggHelper = { + subtype: parentPipelineType, + params() { + return [ + { + name: 'metricAgg', + default: 'custom', + write: parentPipelineAggWriter, + }, + { + name: 'customMetric', + type: 'agg', + makeAgg(termsAgg, state: any) { + state = state || { type: 'count' }; + state.schema = metricAggSchema; + + const metricAgg = termsAgg.aggConfigs.createAggConfig(state, { addToAggConfigs: false }); + + metricAgg.id = termsAgg.id + '-metric'; + + return metricAgg; + }, + modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart( + 'customMetric' + ), + write: noop, + }, + { + name: 'buckets_path', + write: noop, + }, + ] as Array>; + }, + + getFormat(agg: IMetricAggConfig) { + let subAgg; + const customMetric = agg.getParam('customMetric'); + + if (customMetric) { + subAgg = customMetric; + } else { + subAgg = agg.aggConfigs.byId(agg.getParam('metricAgg')); + } + return subAgg.type.getFormat(subAgg); + }, +}; + +export { parentPipelineAggHelper, parentPipelineType }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts new file mode 100644 index 0000000000000..684fe721a754a --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts @@ -0,0 +1,40 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AggConfigs } from '../../agg_configs'; +import { IMetricAggConfig } from '../metric_agg_type'; + +export const parentPipelineAggWriter = ( + agg: IMetricAggConfig, + output: Record, + aggConfigs?: AggConfigs +): void => { + const customMetric = agg.getParam('customMetric'); + const metricAgg = agg.getParam('metricAgg'); + + const selectedMetric = customMetric || (aggConfigs && aggConfigs.getResponseAggById(metricAgg)); + + if (customMetric && customMetric.type.name !== 'count') { + output.parentAggs = (output.parentAggs || []).concat(selectedMetric); + } + + output.params = { + buckets_path: selectedMetric.type.name === 'count' ? '_count' : selectedMetric.id, + }; +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts new file mode 100644 index 0000000000000..9dd737bd6708e --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts @@ -0,0 +1,123 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { siblingPipelineAggWriter } from './sibling_pipeline_agg_writer'; +import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; + +import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; +import { Schemas } from '../../schemas'; + +const metricAggFilter: string[] = [ + '!top_hits', + '!percentiles', + '!percentile_ranks', + '!median', + '!std_dev', + '!sum_bucket', + '!avg_bucket', + '!min_bucket', + '!max_bucket', + '!derivative', + '!moving_avg', + '!serial_diff', + '!cumulative_sum', + '!geo_bounds', + '!geo_centroid', +]; +const bucketAggFilter: string[] = []; + +const [metricAggSchema] = new Schemas([ + { + group: 'none', + name: 'metricAgg', + title: i18n.translate('common.ui.aggTypes.metrics.metricAggTitle', { + defaultMessage: 'Metric agg', + }), + aggFilter: metricAggFilter, + }, +]).all; + +const [bucketAggSchema] = new Schemas([ + { + group: 'none', + title: i18n.translate('common.ui.aggTypes.metrics.bucketAggTitle', { + defaultMessage: 'Bucket agg', + }), + name: 'bucketAgg', + aggFilter: bucketAggFilter, + }, +]).all; + +const siblingPipelineType = i18n.translate( + 'common.ui.aggTypes.metrics.siblingPipelineAggregationsSubtypeTitle', + { + defaultMessage: 'Sibling pipeline aggregations', + } +); + +const siblingPipelineAggHelper = { + subtype: siblingPipelineType, + params() { + return [ + { + name: 'customBucket', + type: 'agg', + default: null, + makeAgg(agg: IMetricAggConfig, state: any) { + state = state || { type: 'date_histogram' }; + state.schema = bucketAggSchema; + const orderAgg = agg.aggConfigs.createAggConfig(state, { addToAggConfigs: false }); + orderAgg.id = agg.id + '-bucket'; + + return orderAgg; + }, + modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart( + 'customBucket' + ), + write: () => {}, + }, + { + name: 'customMetric', + type: 'agg', + default: null, + makeAgg(agg: IMetricAggConfig, state: any) { + state = state || { type: 'count' }; + state.schema = metricAggSchema; + const orderAgg = agg.aggConfigs.createAggConfig(state, { addToAggConfigs: false }); + orderAgg.id = agg.id + '-metric'; + + return orderAgg; + }, + modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart( + 'customMetric' + ), + write: siblingPipelineAggWriter, + }, + ] as Array>; + }, + + getFormat(agg: IMetricAggConfig) { + const customMetric = agg.getParam('customMetric'); + + return customMetric.type.getFormat(customMetric); + }, +}; + +export { siblingPipelineAggHelper, siblingPipelineType }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts new file mode 100644 index 0000000000000..acdce8cb5f171 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts @@ -0,0 +1,40 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IMetricAggConfig } from '../metric_agg_type'; +import { METRIC_TYPES } from '../metric_agg_types'; + +export const siblingPipelineAggWriter = (agg: IMetricAggConfig, output: Record) => { + const customMetric = agg.getParam('customMetric'); + + if (!customMetric) return; + + const metricAgg = customMetric; + const bucketAgg = agg.getParam('customBucket'); + + // if a bucket is selected, we must add this agg as a sibling to it, and add a metric to that bucket (or select one of its) + if (metricAgg.type.name !== METRIC_TYPES.COUNT) { + bucketAgg.subAggs = (output.subAggs || []).concat(metricAgg); + output.params.buckets_path = `${bucketAgg.id}>${metricAgg.id}`; + } else { + output.params.buckets_path = bucketAgg.id + '>_count'; + } + + output.parentAggs = (output.parentAggs || []).concat(bucketAgg); +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts new file mode 100644 index 0000000000000..5c43511acee72 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts @@ -0,0 +1,45 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { METRIC_TYPES } from './metric_agg_types'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +const maxTitle = i18n.translate('common.ui.aggTypes.metrics.maxTitle', { + defaultMessage: 'Max', +}); + +export const maxMetricAgg = new MetricAggType({ + name: METRIC_TYPES.MAX, + title: maxTitle, + makeLabel(aggConfig) { + return i18n.translate('common.ui.aggTypes.metrics.maxLabel', { + defaultMessage: 'Max {field}', + values: { field: aggConfig.getFieldDisplayName() }, + }); + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE], + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts new file mode 100644 index 0000000000000..819c24f135cdc --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts @@ -0,0 +1,69 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AggConfigs } from '../agg_configs'; +import { METRIC_TYPES } from './metric_agg_types'; + +jest.mock('ui/new_platform'); + +describe('AggTypeMetricMedianProvider class', () => { + let aggConfigs: AggConfigs; + + beforeEach(() => { + const field = { + name: 'bytes', + }; + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + aggConfigs = new AggConfigs( + indexPattern, + [ + { + id: METRIC_TYPES.MEDIAN, + type: METRIC_TYPES.MEDIAN, + schema: 'metric', + params: { + field: 'bytes', + percents: [70], + }, + }, + ], + null + ); + }); + + it('requests the percentiles aggregation in the Elasticsearch query DSL', () => { + const dsl: Record = aggConfigs.toDsl(); + + expect(dsl.median.percentiles.percents).toEqual([70]); + }); + + it('asks Elasticsearch for array-based values in the aggregation response', () => { + const dsl: Record = aggConfigs.toDsl(); + + expect(dsl.median.percentiles.keyed).toBeFalsy(); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts new file mode 100644 index 0000000000000..5792d4a7c2ba3 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts @@ -0,0 +1,59 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { METRIC_TYPES } from './metric_agg_types'; + +// @ts-ignore +import { percentilesMetricAgg } from './percentiles'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +const medianTitle = i18n.translate('common.ui.aggTypes.metrics.medianTitle', { + defaultMessage: 'Median', +}); + +export const medianMetricAgg = new MetricAggType({ + name: METRIC_TYPES.MEDIAN, + dslName: 'percentiles', + title: medianTitle, + makeLabel(aggConfig) { + return i18n.translate('common.ui.aggTypes.metrics.medianLabel', { + defaultMessage: 'Median {field}', + values: { field: aggConfig.getFieldDisplayName() }, + }); + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE], + }, + { + name: 'percents', + default: [50], + }, + { + write(agg, output) { + output.params.keyed = false; + }, + }, + ], + getResponseAggs: percentilesMetricAgg.getResponseAggs, + getValue: percentilesMetricAgg.getValue, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts new file mode 100644 index 0000000000000..5cd3dffb10b9d --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts @@ -0,0 +1,96 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { npStart } from 'ui/new_platform'; +import { AggType, AggTypeConfig } from '../agg_type'; +import { AggParamType } from '../param_types/agg'; +import { AggConfig } from '../agg_config'; +import { METRIC_TYPES } from './metric_agg_types'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +export interface IMetricAggConfig extends AggConfig { + type: InstanceType; +} + +export interface MetricAggParam + extends AggParamType { + filterFieldTypes?: KBN_FIELD_TYPES | KBN_FIELD_TYPES[] | '*'; + onlyAggregatable?: boolean; +} + +const metricType = 'metrics'; + +interface MetricAggTypeConfig + extends AggTypeConfig> { + isScalable?: () => boolean; + subtype?: string; +} + +export class MetricAggType extends AggType< + TMetricAggConfig, + MetricAggParam +> { + subtype: string; + isScalable: () => boolean; + type = metricType; + + getKey = () => {}; + + constructor(config: MetricAggTypeConfig) { + super(config); + + this.getValue = + config.getValue || + ((agg, bucket) => { + // Metric types where an empty set equals `zero` + const isSettableToZero = [METRIC_TYPES.CARDINALITY, METRIC_TYPES.SUM].includes( + agg.type.name as METRIC_TYPES + ); + + // 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; + }); + + this.getFormat = + config.getFormat || + (agg => { + const fieldFormatsService = npStart.plugins.data.fieldFormats; + const field = agg.getField(); + return field + ? field.format + : fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER); + }); + + this.subtype = + config.subtype || + i18n.translate('common.ui.aggTypes.metrics.metricAggregationsSubtypeTitle', { + defaultMessage: 'Metric Aggregations', + }); + + this.isScalable = config.isScalable || (() => false); + } +} + +export function isMetricAggType(aggConfig: any): aggConfig is MetricAggType { + return aggConfig && aggConfig.type === metricType; +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_types.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_types.ts new file mode 100644 index 0000000000000..ae9904ffcfa6b --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_types.ts @@ -0,0 +1,42 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export enum METRIC_TYPES { + AVG = 'avg', + CARDINALITY = 'cardinality', + AVG_BUCKET = 'avg_bucket', + MAX_BUCKET = 'max_bucket', + MIN_BUCKET = 'min_bucket', + SUM_BUCKET = 'sum_bucket', + COUNT = 'count', + CUMULATIVE_SUM = 'cumulative_sum', + DERIVATIVE = 'derivative', + GEO_BOUNDS = 'geo_bounds', + GEO_CENTROID = 'geo_centroid', + MEDIAN = 'median', + MIN = 'min', + MAX = 'max', + MOVING_FN = 'moving_avg', + SERIAL_DIFF = 'serial_diff', + SUM = 'sum', + TOP_HITS = 'top_hits', + PERCENTILES = 'percentiles', + PERCENTILE_RANKS = 'percentile_ranks', + STD_DEV = 'std_dev', +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/min.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/min.ts new file mode 100644 index 0000000000000..5f8ca72954cc2 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/min.ts @@ -0,0 +1,44 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { METRIC_TYPES } from './metric_agg_types'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +const minTitle = i18n.translate('common.ui.aggTypes.metrics.minTitle', { + defaultMessage: 'Min', +}); + +export const minMetricAgg = new MetricAggType({ + name: METRIC_TYPES.MIN, + title: minTitle, + makeLabel(aggConfig) { + return i18n.translate('common.ui.aggTypes.metrics.minLabel', { + defaultMessage: 'Min {field}', + values: { field: aggConfig.getFieldDisplayName() }, + }); + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE], + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/moving_avg.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/moving_avg.ts new file mode 100644 index 0000000000000..b6a8e7a5d6a99 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/moving_avg.ts @@ -0,0 +1,64 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; +import { makeNestedLabel } from './lib/make_nested_label'; +import { METRIC_TYPES } from './metric_agg_types'; + +const movingAvgTitle = i18n.translate('common.ui.aggTypes.metrics.movingAvgTitle', { + defaultMessage: 'Moving Avg', +}); + +const movingAvgLabel = i18n.translate('common.ui.aggTypes.metrics.movingAvgLabel', { + defaultMessage: 'moving avg', +}); + +export const movingAvgMetricAgg = new MetricAggType({ + name: METRIC_TYPES.MOVING_FN, + dslName: 'moving_fn', + title: movingAvgTitle, + subtype: parentPipelineAggHelper.subtype, + makeLabel: agg => makeNestedLabel(agg, movingAvgLabel), + params: [ + ...parentPipelineAggHelper.params(), + { + name: 'window', + default: 5, + }, + { + name: 'script', + default: 'MovingFunctions.unweightedAvg(values)', + }, + ], + getValue(agg, bucket) { + /** + * The previous implementation using `moving_avg` did not + * return any bucket in case there are no documents or empty window. + * The `moving_fn` aggregation returns buckets with the value null if the + * window is empty or doesn't return any value if the sibiling metric + * is null. Since our generic MetricAggType.getValue implementation + * would return the value 0 for null buckets, we need a specific + * implementation here, that preserves the null value. + */ + return bucket[agg.id] ? bucket[agg.id].value : null; + }, + getFormat: parentPipelineAggHelper.getFormat, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts new file mode 100644 index 0000000000000..11fc39c20bdc4 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts @@ -0,0 +1,236 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import sinon from 'sinon'; +import { derivativeMetricAgg } from './derivative'; +import { cumulativeSumMetricAgg } from './cumulative_sum'; +import { movingAvgMetricAgg } from './moving_avg'; +import { serialDiffMetricAgg } from './serial_diff'; +import { AggConfigs } from '../agg_configs'; +import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; + +jest.mock('../schemas', () => { + class MockedSchemas { + all = [{}]; + } + return { + Schemas: jest.fn().mockImplementation(() => new MockedSchemas()), + }; +}); + +jest.mock('ui/new_platform'); + +describe('parent pipeline aggs', function() { + const metrics = [ + { name: 'derivative', title: 'Derivative', provider: derivativeMetricAgg }, + { name: 'cumulative_sum', title: 'Cumulative Sum', provider: cumulativeSumMetricAgg }, + { name: 'moving_avg', title: 'Moving Avg', provider: movingAvgMetricAgg, dslName: 'moving_fn' }, + { name: 'serial_diff', title: 'Serial Diff', provider: serialDiffMetricAgg }, + ]; + + metrics.forEach(metric => { + describe(`${metric.title} metric`, () => { + let aggDsl: Record; + let metricAgg: MetricAggType; + let aggConfig: IMetricAggConfig; + + const init = ( + params: any = { + metricAgg: '1', + customMetric: null, + } + ) => { + const field = { + name: 'field', + format: { + type: { + id: 'bytes', + }, + }, + }; + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + const aggConfigs = new AggConfigs( + indexPattern, + [ + { + id: '1', + type: 'count', + schema: 'metric', + }, + { + id: '2', + type: metric.name, + schema: 'metric', + params, + }, + { + id: '3', + type: 'max', + params: { field: 'field' }, + schema: 'metric', + }, + ], + null + ); + + // Grab the aggConfig off the vis (we don't actually use the vis for anything else) + metricAgg = metric.provider; + aggConfig = aggConfigs.aggs[1] as IMetricAggConfig; + aggDsl = aggConfig.toDsl(aggConfigs); + }; + + it(`should return a label prefixed with ${metric.title} of`, () => { + init(); + + expect(metricAgg.makeLabel(aggConfig)).toEqual(`${metric.title} of Count`); + }); + + it(`should return a label ${metric.title} of max bytes`, () => { + init({ + metricAgg: 'custom', + customMetric: { + id: '1-orderAgg', + type: 'max', + params: { field: 'field' }, + schema: 'orderAgg', + }, + }); + expect(metricAgg.makeLabel(aggConfig)).toEqual(`${metric.title} of Max field`); + }); + + it(`should return a label prefixed with number of ${metric.title.toLowerCase()}`, () => { + init({ + metricAgg: 'custom', + customMetric: { + id: '2-orderAgg', + type: metric.name, + params: { + buckets_path: 'custom', + customMetric: { + id: '2-orderAgg-orderAgg', + type: 'count', + schema: 'orderAgg', + }, + }, + schema: 'orderAgg', + }, + }); + expect(metricAgg.makeLabel(aggConfig)).toEqual(`2. ${metric.title.toLowerCase()} of Count`); + }); + + it('should set parent aggs', () => { + init({ + metricAgg: 'custom', + customMetric: { + id: '2-metric', + type: 'max', + params: { field: 'field' }, + schema: 'orderAgg', + }, + }); + expect(aggDsl[metric.dslName || metric.name].buckets_path).toBe('2-metric'); + expect(aggDsl.parentAggs['2-metric'].max.field).toBe('field'); + }); + + it('should set nested parent aggs', () => { + init({ + metricAgg: 'custom', + customMetric: { + id: '2-metric', + type: metric.name, + params: { + buckets_path: 'custom', + customMetric: { + id: '2-metric-metric', + type: 'max', + params: { field: 'field' }, + schema: 'orderAgg', + }, + }, + schema: 'orderAgg', + }, + }); + expect(aggDsl[metric.dslName || metric.name].buckets_path).toBe('2-metric'); + expect(aggDsl.parentAggs['2-metric'][metric.dslName || metric.name].buckets_path).toBe( + '2-metric-metric' + ); + }); + + it('should have correct formatter', () => { + init({ + metricAgg: '3', + }); + expect(metricAgg.getFormat(aggConfig).type.id).toBe('bytes'); + }); + + it('should have correct customMetric nested formatter', () => { + init({ + metricAgg: 'custom', + customMetric: { + id: '2-metric', + type: metric.name, + params: { + buckets_path: 'custom', + customMetric: { + id: '2-metric-metric', + type: 'max', + params: { field: 'field' }, + schema: 'orderAgg', + }, + }, + schema: 'orderAgg', + }, + }); + expect(metricAgg.getFormat(aggConfig).type.id).toBe('bytes'); + }); + + it("should call modifyAggConfigOnSearchRequestStart for its customMetric's parameters", () => { + init({ + metricAgg: 'custom', + customMetric: { + id: '2-metric', + type: 'max', + params: { field: 'field' }, + schema: 'orderAgg', + }, + }); + + const searchSource: any = {}; + const customMetricSpy = sinon.spy(); + const customMetric = aggConfig.params.customMetric; + + // Attach a modifyAggConfigOnSearchRequestStart with a spy to the first parameter + customMetric.type.params[0].modifyAggConfigOnSearchRequestStart = customMetricSpy; + + aggConfig.type.params.forEach(param => { + param.modifyAggConfigOnSearchRequestStart(aggConfig, searchSource); + }); + expect(customMetricSpy.calledWith(customMetric, searchSource)).toBe(true); + }); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts new file mode 100644 index 0000000000000..7461b5cf07ee7 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts @@ -0,0 +1,76 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IPercentileRanksAggConfig, percentileRanksMetricAgg } from './percentile_ranks'; +import { AggConfigs } from '../agg_configs'; +import { METRIC_TYPES } from './metric_agg_types'; + +jest.mock('ui/new_platform'); + +describe('AggTypesMetricsPercentileRanksProvider class', function() { + let aggConfigs: AggConfigs; + + beforeEach(() => { + const field = { + name: 'bytes', + }; + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + aggConfigs = new AggConfigs( + indexPattern, + [ + { + id: METRIC_TYPES.PERCENTILE_RANKS, + type: METRIC_TYPES.PERCENTILE_RANKS, + schema: 'metric', + params: { + field: { + displayName: 'bytes', + format: { + convert: jest.fn(x => x), + }, + }, + customLabel: 'my custom field label', + values: [5000, 10000], + }, + }, + ], + null + ); + }); + + it('uses the custom label if it is set', function() { + const responseAggs: any = percentileRanksMetricAgg.getResponseAggs( + aggConfigs.aggs[0] as IPercentileRanksAggConfig + ); + + const percentileRankLabelFor5kBytes = responseAggs[0].makeLabel(); + const percentileRankLabelFor10kBytes = responseAggs[1].makeLabel(); + + expect(percentileRankLabelFor5kBytes).toBe('Percentile rank 5000 of "my custom field label"'); + expect(percentileRankLabelFor10kBytes).toBe('Percentile rank 10000 of "my custom field label"'); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts new file mode 100644 index 0000000000000..cbd46e3f5b28d --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts @@ -0,0 +1,94 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { npStart } from 'ui/new_platform'; +import { MetricAggType } from './metric_agg_type'; +import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; + +import { getPercentileValue } from './percentiles_get_value'; +import { METRIC_TYPES } from './metric_agg_types'; +import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +// required by the values editor + +export type IPercentileRanksAggConfig = IResponseAggConfig; + +const getFieldFormats = () => npStart.plugins.data.fieldFormats; + +const valueProps = { + makeLabel(this: IPercentileRanksAggConfig) { + const fieldFormatsService = getFieldFormats(); + const field = this.getField(); + const format = + (field && field.format) || fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER); + const customLabel = this.getParam('customLabel'); + const label = customLabel || this.getFieldDisplayName(); + + return i18n.translate('common.ui.aggTypes.metrics.percentileRanks.valuePropsLabel', { + defaultMessage: 'Percentile rank {format} of "{label}"', + values: { format: format.convert(this.key, 'text'), label }, + }); + }, +}; + +export const percentileRanksMetricAgg = new MetricAggType({ + name: METRIC_TYPES.PERCENTILE_RANKS, + title: i18n.translate('common.ui.aggTypes.metrics.percentileRanksTitle', { + defaultMessage: 'Percentile Ranks', + }), + makeLabel(agg) { + return i18n.translate('common.ui.aggTypes.metrics.percentileRanksLabel', { + defaultMessage: 'Percentile ranks of {field}', + values: { field: agg.getFieldDisplayName() }, + }); + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.NUMBER, + }, + { + name: 'values', + default: [], + }, + { + write(agg, output) { + output.params.keyed = false; + }, + }, + ], + getResponseAggs(agg) { + const ValueAggConfig = getResponseAggConfigClass(agg, valueProps); + const values = agg.getParam('values'); + + return values.map((value: any) => new ValueAggConfig(value)); + }, + getFormat() { + const fieldFormatsService = getFieldFormats(); + return ( + fieldFormatsService.getInstance(fieldFormats.FIELD_FORMAT_IDS.PERCENT) || + fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER) + ); + }, + getValue(agg, bucket) { + return getPercentileValue(agg, bucket) / 100; + }, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.test.ts new file mode 100644 index 0000000000000..c9f4bcc3862a0 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.test.ts @@ -0,0 +1,74 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IPercentileAggConfig, percentilesMetricAgg } from './percentiles'; +import { AggConfigs } from '../agg_configs'; +import { METRIC_TYPES } from './metric_agg_types'; + +jest.mock('ui/new_platform'); + +describe('AggTypesMetricsPercentilesProvider class', () => { + let aggConfigs: AggConfigs; + + beforeEach(() => { + const field = { + name: 'bytes', + }; + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + aggConfigs = new AggConfigs( + indexPattern, + [ + { + id: METRIC_TYPES.PERCENTILES, + type: METRIC_TYPES.PERCENTILES, + schema: 'metric', + params: { + field: { + displayName: 'bytes', + format: { + convert: jest.fn(x => `${x}th`), + }, + }, + customLabel: 'prince', + percents: [95], + }, + }, + ], + null + ); + }); + + it('uses the custom label if it is set', () => { + const responseAggs: any = percentilesMetricAgg.getResponseAggs( + aggConfigs.aggs[0] as IPercentileAggConfig + ); + + const ninetyFifthPercentileLabel = responseAggs[0].makeLabel(); + + expect(ninetyFifthPercentileLabel).toBe('95th percentile of prince'); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts new file mode 100644 index 0000000000000..040324d8da5df --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts @@ -0,0 +1,80 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; + +import { MetricAggType } from './metric_agg_type'; +import { METRIC_TYPES } from './metric_agg_types'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; +import { getPercentileValue } from './percentiles_get_value'; + +// @ts-ignore +import { ordinalSuffix } from './lib/ordinal_suffix'; + +export type IPercentileAggConfig = IResponseAggConfig; + +const valueProps = { + makeLabel(this: IPercentileAggConfig) { + const customLabel = this.getParam('customLabel'); + const label = customLabel || this.getFieldDisplayName(); + + return i18n.translate('common.ui.aggTypes.metrics.percentiles.valuePropsLabel', { + defaultMessage: '{percentile} percentile of {label}', + values: { percentile: ordinalSuffix(this.key), label }, + }); + }, +}; + +export const percentilesMetricAgg = new MetricAggType({ + name: METRIC_TYPES.PERCENTILES, + title: i18n.translate('common.ui.aggTypes.metrics.percentilesTitle', { + defaultMessage: 'Percentiles', + }), + makeLabel(agg) { + return i18n.translate('common.ui.aggTypes.metrics.percentilesLabel', { + defaultMessage: 'Percentiles of {field}', + values: { field: agg.getFieldDisplayName() }, + }); + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE], + }, + { + name: 'percents', + default: [1, 5, 25, 50, 75, 95, 99], + }, + { + write(agg, output) { + output.params.keyed = false; + }, + }, + ], + getResponseAggs(agg) { + const ValueAggConfig = getResponseAggConfigClass(agg, valueProps); + + return agg.getParam('percents').map((percent: any) => new ValueAggConfig(percent)); + }, + + getValue: getPercentileValue, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles_get_value.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles_get_value.ts new file mode 100644 index 0000000000000..c357d7bb0a903 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles_get_value.ts @@ -0,0 +1,32 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { find } from 'lodash'; +import { IResponseAggConfig } from './lib/get_response_agg_config_class'; + +export const getPercentileValue = ( + agg: TAggConfig, + bucket: any +) => { + const { values } = bucket[agg.parentId] && bucket[agg.parentId]; + + const percentile: any = find(values, ({ key }) => key === agg.key); + + return percentile ? percentile.value : NaN; +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/serial_diff.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/serial_diff.ts new file mode 100644 index 0000000000000..bb5431fbbefd9 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/serial_diff.ts @@ -0,0 +1,41 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; +import { makeNestedLabel } from './lib/make_nested_label'; +import { METRIC_TYPES } from './metric_agg_types'; + +const serialDiffTitle = i18n.translate('common.ui.aggTypes.metrics.serialDiffTitle', { + defaultMessage: 'Serial Diff', +}); + +const serialDiffLabel = i18n.translate('common.ui.aggTypes.metrics.serialDiffLabel', { + defaultMessage: 'serial diff', +}); + +export const serialDiffMetricAgg = new MetricAggType({ + name: METRIC_TYPES.SERIAL_DIFF, + title: serialDiffTitle, + subtype: parentPipelineAggHelper.subtype, + makeLabel: agg => makeNestedLabel(agg, serialDiffLabel), + params: [...parentPipelineAggHelper.params()], + getFormat: parentPipelineAggHelper.getFormat, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts new file mode 100644 index 0000000000000..d643cf0d2a478 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts @@ -0,0 +1,182 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { spy } from 'sinon'; +import { bucketSumMetricAgg } from './bucket_sum'; +import { bucketAvgMetricAgg } from './bucket_avg'; +import { bucketMinMetricAgg } from './bucket_min'; +import { bucketMaxMetricAgg } from './bucket_max'; + +import { AggConfigs } from '../agg_configs'; +import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; + +jest.mock('../schemas', () => { + class MockedSchemas { + all = [{}]; + } + return { + Schemas: jest.fn().mockImplementation(() => new MockedSchemas()), + }; +}); + +jest.mock('ui/new_platform'); + +describe('sibling pipeline aggs', () => { + const metrics = [ + { 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 }, + ]; + + metrics.forEach(metric => { + describe(`${metric.title} metric`, () => { + let aggDsl: Record; + let metricAgg: MetricAggType; + let aggConfig: IMetricAggConfig; + + const init = (settings?: any) => { + const field = { + name: 'field', + format: { + type: { + id: 'bytes', + }, + }, + }; + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + const aggConfigs = new AggConfigs( + indexPattern, + [ + { + id: '1', + type: 'count', + schema: 'metric', + }, + { + id: '2', + type: metric.name, + schema: 'metric', + params: settings || { + customMetric: { + id: '5', + type: 'count', + schema: 'metric', + }, + customBucket: { + id: '6', + type: 'date_histogram', + schema: 'bucket', + params: { field: 'field', interval: '10s' }, + }, + }, + }, + ], + null + ); + + // Grab the aggConfig off the vis (we don't actually use the vis for anything else) + metricAgg = metric.provider; + aggConfig = aggConfigs.aggs[1] as IMetricAggConfig; + aggDsl = aggConfig.toDsl(aggConfigs); + }; + + it(`should return a label prefixed with ${metric.title} of`, () => { + init(); + + expect(metricAgg.makeLabel(aggConfig)).toEqual(`${metric.title} of Count`); + }); + + it('should set parent aggs', function() { + init(); + + expect(aggDsl[metric.name].buckets_path).toBe('2-bucket>_count'); + expect(aggDsl.parentAggs['2-bucket'].date_histogram).not.toBeUndefined(); + }); + + it('should set nested parent aggs', () => { + init({ + customMetric: { + id: '5', + type: 'avg', + schema: 'metric', + params: { field: 'field' }, + }, + customBucket: { + id: '6', + type: 'date_histogram', + schema: 'bucket', + params: { field: 'field', interval: '10s' }, + }, + }); + + expect(aggDsl[metric.name].buckets_path).toBe('2-bucket>2-metric'); + expect(aggDsl.parentAggs['2-bucket'].date_histogram).not.toBeUndefined(); + expect(aggDsl.parentAggs['2-bucket'].aggs['2-metric'].avg.field).toEqual('field'); + }); + + it('should have correct formatter', () => { + init({ + customMetric: { + id: '5', + type: 'avg', + schema: 'metric', + params: { field: 'field' }, + }, + customBucket: { + id: '6', + type: 'date_histogram', + schema: 'bucket', + params: { field: 'field', interval: '10s' }, + }, + }); + + expect(metricAgg.getFormat(aggConfig).type.id).toBe('bytes'); + }); + + it("should call modifyAggConfigOnSearchRequestStart for nested aggs' parameters", () => { + init(); + + const searchSource: any = {}; + const customMetricSpy = spy(); + const customBucketSpy = spy(); + const { customMetric, customBucket } = aggConfig.params; + + // Attach a modifyAggConfigOnSearchRequestStart with a spy to the first parameter + customMetric.type.params[0].modifyAggConfigOnSearchRequestStart = customMetricSpy; + customBucket.type.params[0].modifyAggConfigOnSearchRequestStart = customBucketSpy; + + aggConfig.type.params.forEach(param => { + param.modifyAggConfigOnSearchRequestStart(aggConfig, searchSource); + }); + + expect(customMetricSpy.calledWith(customMetric, searchSource)).toBe(true); + expect(customBucketSpy.calledWith(customBucket, searchSource)).toBe(true); + }); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.test.ts new file mode 100644 index 0000000000000..3125026a52185 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.test.ts @@ -0,0 +1,85 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IStdDevAggConfig, stdDeviationMetricAgg } from './std_deviation'; +import { AggConfigs } from '../agg_configs'; +import { METRIC_TYPES } from './metric_agg_types'; + +jest.mock('ui/new_platform'); + +describe('AggTypeMetricStandardDeviationProvider class', () => { + const getAggConfigs = (customLabel?: string) => { + const field = { + name: 'memory', + }; + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + return new AggConfigs( + indexPattern, + [ + { + id: METRIC_TYPES.STD_DEV, + type: METRIC_TYPES.STD_DEV, + schema: 'metric', + params: { + field: { + displayName: 'memory', + }, + customLabel, + }, + }, + ], + null + ); + }; + + it('uses the custom label if it is set', () => { + const aggConfigs = getAggConfigs('custom label'); + const responseAggs: any = stdDeviationMetricAgg.getResponseAggs( + aggConfigs.aggs[0] as IStdDevAggConfig + ); + + const lowerStdDevLabel = responseAggs[0].makeLabel(); + const upperStdDevLabel = responseAggs[1].makeLabel(); + + expect(lowerStdDevLabel).toBe('Lower custom label'); + expect(upperStdDevLabel).toBe('Upper custom label'); + }); + + it('uses the default labels if custom label is not set', () => { + const aggConfigs = getAggConfigs(); + + const responseAggs: any = stdDeviationMetricAgg.getResponseAggs( + aggConfigs.aggs[0] as IStdDevAggConfig + ); + + const lowerStdDevLabel = responseAggs[0].makeLabel(); + const upperStdDevLabel = responseAggs[1].makeLabel(); + + expect(lowerStdDevLabel).toBe('Lower Standard Deviation of memory'); + expect(upperStdDevLabel).toBe('Upper Standard Deviation of memory'); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts new file mode 100644 index 0000000000000..b2e6d3b3ca4d0 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts @@ -0,0 +1,107 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { get } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { METRIC_TYPES } from './metric_agg_types'; +import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +interface ValProp { + valProp: string[]; + title: string; +} + +export interface IStdDevAggConfig extends IResponseAggConfig { + keyedDetails: (customLabel: string, fieldDisplayName?: string) => { [key: string]: ValProp }; + valProp: () => ValProp; +} + +const responseAggConfigProps = { + valProp(this: IStdDevAggConfig) { + const customLabel = this.getParam('customLabel'); + const details = this.keyedDetails(customLabel)[this.key]; + + return details.valProp; + }, + makeLabel(this: IStdDevAggConfig) { + const fieldDisplayName = this.getFieldDisplayName(); + const customLabel = this.getParam('customLabel'); + const details = this.keyedDetails(customLabel, fieldDisplayName); + + return get(details, [this.key, 'title']); + }, + keyedDetails(this: IStdDevAggConfig, customLabel: string, fieldDisplayName: string) { + const label = + customLabel || + i18n.translate('common.ui.aggTypes.metrics.standardDeviation.keyDetailsLabel', { + defaultMessage: 'Standard Deviation of {fieldDisplayName}', + values: { fieldDisplayName }, + }); + + return { + std_lower: { + valProp: ['std_deviation_bounds', 'lower'], + title: i18n.translate('common.ui.aggTypes.metrics.standardDeviation.lowerKeyDetailsTitle', { + defaultMessage: 'Lower {label}', + values: { label }, + }), + }, + std_upper: { + valProp: ['std_deviation_bounds', 'upper'], + title: i18n.translate('common.ui.aggTypes.metrics.standardDeviation.upperKeyDetailsTitle', { + defaultMessage: 'Upper {label}', + values: { label }, + }), + }, + }; + }, +}; + +export const stdDeviationMetricAgg = new MetricAggType({ + name: METRIC_TYPES.STD_DEV, + dslName: 'extended_stats', + title: i18n.translate('common.ui.aggTypes.metrics.standardDeviationTitle', { + defaultMessage: 'Standard Deviation', + }), + makeLabel(agg) { + return i18n.translate('common.ui.aggTypes.metrics.standardDeviationLabel', { + defaultMessage: 'Standard Deviation of {field}', + values: { field: agg.getFieldDisplayName() }, + }); + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.NUMBER, + }, + ], + + getResponseAggs(agg) { + const ValueAggConfig = getResponseAggConfigClass(agg, responseAggConfigProps); + + return [new ValueAggConfig('std_lower'), new ValueAggConfig('std_upper')]; + }, + + getValue(agg, bucket) { + return get(bucket[agg.parentId], agg.valProp()); + }, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts new file mode 100644 index 0000000000000..ce79c761ce799 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts @@ -0,0 +1,48 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { MetricAggType } from './metric_agg_type'; +import { METRIC_TYPES } from './metric_agg_types'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +const sumTitle = i18n.translate('common.ui.aggTypes.metrics.sumTitle', { + defaultMessage: 'Sum', +}); + +export const sumMetricAgg = new MetricAggType({ + name: METRIC_TYPES.SUM, + title: sumTitle, + makeLabel(aggConfig) { + return i18n.translate('common.ui.aggTypes.metrics.sumLabel', { + defaultMessage: 'Sum of {field}', + values: { field: aggConfig.getFieldDisplayName() }, + }); + }, + isScalable() { + return true; + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.NUMBER, + }, + ], +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.test.ts new file mode 100644 index 0000000000000..3e861c052d367 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.test.ts @@ -0,0 +1,366 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { dropRight, last } from 'lodash'; +import { topHitMetricAgg } from './top_hit'; +import { AggConfigs } from '../agg_configs'; +import { IMetricAggConfig } from './metric_agg_type'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +jest.mock('ui/new_platform'); + +describe('Top hit metric', () => { + let aggDsl: Record; + let aggConfig: IMetricAggConfig; + + const init = ({ + fieldName = 'field', + sortOrder = 'desc', + aggregate = 'concat', + readFromDocValues = false, + fieldType = KBN_FIELD_TYPES.NUMBER, + size = 1, + }: any) => { + const field = { + name: fieldName, + displayName: fieldName, + type: fieldType, + readFromDocValues, + format: { + type: { + id: 'bytes', + }, + }, + }; + + const params = { + size, + field: fieldName, + sortField: field, + sortOrder: { + value: sortOrder, + }, + aggregate: { + value: aggregate, + }, + }; + + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + flattenHit: jest.fn(x => x!._source), + } as any; + + const aggConfigs = new AggConfigs( + indexPattern, + [ + { + id: '1', + type: 'top_hits', + schema: 'metric', + params, + }, + ], + null + ); + + // Grab the aggConfig off the vis (we don't actually use the vis for anything else) + aggConfig = aggConfigs.aggs[0] as IMetricAggConfig; + aggDsl = aggConfig.toDsl(aggConfigs); + }; + + it('should return a label prefixed with Last if sorting in descending order', () => { + init({ fieldName: 'bytes' }); + expect(topHitMetricAgg.makeLabel(aggConfig)).toEqual('Last bytes'); + }); + + it('should return a label prefixed with First if sorting in ascending order', () => { + init({ + fieldName: 'bytes', + sortOrder: 'asc', + }); + expect(topHitMetricAgg.makeLabel(aggConfig)).toEqual('First bytes'); + }); + + it('should request the _source field', () => { + init({ field: '_source' }); + expect(aggDsl.top_hits._source).toBeTruthy(); + expect(aggDsl.top_hits.docvalue_fields).toBeUndefined(); + }); + + it('requests both source and docvalues_fields for non-text aggregatable fields', () => { + init({ fieldName: 'bytes', readFromDocValues: true }); + expect(aggDsl.top_hits._source).toBe('bytes'); + expect(aggDsl.top_hits.docvalue_fields).toEqual([ + { field: 'bytes', format: 'use_field_mapping' }, + ]); + }); + + it('requests both source and docvalues_fields for date aggregatable fields', () => { + init({ fieldName: '@timestamp', readFromDocValues: true, fieldType: KBN_FIELD_TYPES.DATE }); + + expect(aggDsl.top_hits._source).toBe('@timestamp'); + expect(aggDsl.top_hits.docvalue_fields).toEqual([{ field: '@timestamp', format: 'date_time' }]); + }); + + it('requests just source for aggregatable text fields', () => { + init({ fieldName: 'machine.os' }); + expect(aggDsl.top_hits._source).toBe('machine.os'); + expect(aggDsl.top_hits.docvalue_fields).toBeUndefined(); + }); + + describe('try to get the value from the top hit', () => { + it('should return null if there is no hit', () => { + const bucket = { + '1': { + hits: { + hits: [], + }, + }, + }; + + init({ fieldName: '@tags' }); + expect(topHitMetricAgg.getValue(aggConfig, bucket)).toBe(null); + }); + // + it('should return undefined if the field does not appear in the source', () => { + const bucket = { + '1': { + hits: { + hits: [ + { + _source: { + bytes: 123, + }, + }, + ], + }, + }, + }; + + init({ fieldName: '@tags' }); + expect(topHitMetricAgg.getValue(aggConfig, bucket)).toBe(undefined); + }); + + it('should return the field value from the top hit', () => { + const bucket = { + '1': { + hits: { + hits: [ + { + _source: { + '@tags': 'aaa', + }, + }, + ], + }, + }, + }; + + init({ fieldName: '@tags' }); + expect(topHitMetricAgg.getValue(aggConfig, bucket)).toBe('aaa'); + }); + + it('should return the object if the field value is an object', () => { + const bucket = { + '1': { + hits: { + hits: [ + { + _source: { + '@tags': { + label: 'aaa', + }, + }, + }, + ], + }, + }, + }; + + init({ fieldName: '@tags' }); + + expect(topHitMetricAgg.getValue(aggConfig, bucket)).toEqual({ label: 'aaa' }); + }); + + it('should return an array if the field has more than one values', () => { + const bucket = { + '1': { + hits: { + hits: [ + { + _source: { + '@tags': ['aaa', 'bbb'], + }, + }, + ], + }, + }, + }; + + init({ fieldName: '@tags' }); + expect(topHitMetricAgg.getValue(aggConfig, bucket)).toEqual(['aaa', 'bbb']); + }); + + it('should return undefined if the field is not in the source nor in the doc_values field', () => { + const bucket = { + '1': { + hits: { + hits: [ + { + _source: { + bytes: 12345, + }, + fields: { + bytes: 12345, + }, + }, + ], + }, + }, + }; + + init({ fieldName: 'machine.os.raw', readFromDocValues: true }); + expect(topHitMetricAgg.getValue(aggConfig, bucket)).toBe(undefined); + }); + + describe('Multivalued field and first/last X docs', () => { + it('should return a label prefixed with Last X docs if sorting in descending order', () => { + init({ + fieldName: 'bytes', + size: 2, + }); + expect(topHitMetricAgg.makeLabel(aggConfig)).toEqual('Last 2 bytes'); + }); + + it('should return a label prefixed with First X docs if sorting in ascending order', () => { + init({ + fieldName: 'bytes', + size: 2, + sortOrder: 'asc', + }); + expect(topHitMetricAgg.makeLabel(aggConfig)).toEqual('First 2 bytes'); + }); + + [ + { + description: 'concat values with a comma', + type: 'concat', + data: [1, 2, 3], + result: [1, 2, 3], + }, + { + description: 'sum up the values', + type: 'sum', + data: [1, 2, 3], + result: 6, + }, + { + description: 'take the minimum value', + type: 'min', + data: [1, 2, 3], + result: 1, + }, + { + description: 'take the maximum value', + type: 'max', + data: [1, 2, 3], + result: 3, + }, + { + description: 'take the average value', + type: 'average', + data: [1, 2, 3], + result: 2, + }, + { + description: 'support null/undefined', + type: 'min', + data: [undefined, null], + result: null, + }, + { + description: 'support null/undefined', + type: 'max', + data: [undefined, null], + result: null, + }, + { + description: 'support null/undefined', + type: 'sum', + data: [undefined, null], + result: null, + }, + { + description: 'support null/undefined', + type: 'average', + data: [undefined, null], + result: null, + }, + ].forEach(agg => { + it(`should return the result of the ${agg.type} aggregation over the last doc - ${agg.description}`, () => { + const bucket = { + '1': { + hits: { + hits: [ + { + _source: { + bytes: agg.data, + }, + }, + ], + }, + }, + }; + + init({ fieldName: 'bytes', aggregate: agg.type }); + expect(topHitMetricAgg.getValue(aggConfig, bucket)).toEqual(agg.result); + }); + + it(`should return the result of the ${agg.type} aggregation over the last X docs - ${agg.description}`, () => { + const bucket = { + '1': { + hits: { + hits: [ + { + _source: { + bytes: dropRight(agg.data, 1), + }, + }, + { + _source: { + bytes: last(agg.data), + }, + }, + ], + }, + }, + }; + + init({ fieldName: 'bytes', aggregate: agg.type }); + expect(topHitMetricAgg.getValue(aggConfig, bucket)).toEqual(agg.result); + }); + }); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts new file mode 100644 index 0000000000000..43fe33bdebeb9 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts @@ -0,0 +1,255 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import _ from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; +import { aggTypeFieldFilters } from '../param_types/filter'; +import { METRIC_TYPES } from './metric_agg_types'; +import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +// @ts-ignore +import { wrapWithInlineComp } from '../buckets/inline_comp_wrapper'; + +const isNumericFieldSelected = (agg: IMetricAggConfig) => { + const field = agg.getParam('field'); + + return field && field.type && field.type === KBN_FIELD_TYPES.NUMBER; +}; + +aggTypeFieldFilters.addFilter((field, aggConfig) => { + if ( + aggConfig.type.name !== METRIC_TYPES.TOP_HITS || + _.get(aggConfig.schema, 'aggSettings.top_hits.allowStrings', false) + ) { + return true; + } + + return field.type === KBN_FIELD_TYPES.NUMBER; +}); + +export const topHitMetricAgg = new MetricAggType({ + name: METRIC_TYPES.TOP_HITS, + title: i18n.translate('common.ui.aggTypes.metrics.topHitTitle', { + defaultMessage: 'Top Hit', + }), + makeLabel(aggConfig) { + const lastPrefixLabel = i18n.translate('common.ui.aggTypes.metrics.topHit.lastPrefixLabel', { + defaultMessage: 'Last', + }); + const firstPrefixLabel = i18n.translate('common.ui.aggTypes.metrics.topHit.firstPrefixLabel', { + defaultMessage: 'First', + }); + + let prefix = + aggConfig.getParam('sortOrder').value === 'desc' ? lastPrefixLabel : firstPrefixLabel; + + const size = aggConfig.getParam('size'); + + if (size !== 1) { + prefix += ` ${size}`; + } + + const field = aggConfig.getParam('field'); + + return `${prefix} ${field ? field.displayName : ''}`; + }, + params: [ + { + name: 'field', + type: 'field', + onlyAggregatable: false, + filterFieldTypes: '*', + write(agg, output) { + const field = agg.getParam('field'); + output.params = {}; + + if (field.scripted) { + output.params.script_fields = { + [field.name]: { + script: { + source: field.script, + lang: field.lang, + }, + }, + }; + } else { + if (field.readFromDocValues) { + // always format date fields as date_time to avoid + // displaying unformatted dates like epoch_millis + // or other not-accepted momentjs formats + const format = field.type === KBN_FIELD_TYPES.DATE ? 'date_time' : 'use_field_mapping'; + output.params.docvalue_fields = [{ field: field.name, format }]; + } + output.params._source = field.name === '_source' ? true : field.name; + } + }, + }, + { + name: 'aggregate', + type: 'optioned', + options: [ + { + text: i18n.translate('common.ui.aggTypes.metrics.topHit.minLabel', { + defaultMessage: 'Min', + }), + isCompatible: isNumericFieldSelected, + disabled: true, + value: 'min', + }, + { + text: i18n.translate('common.ui.aggTypes.metrics.topHit.maxLabel', { + defaultMessage: 'Max', + }), + isCompatible: isNumericFieldSelected, + disabled: true, + value: 'max', + }, + { + text: i18n.translate('common.ui.aggTypes.metrics.topHit.sumLabel', { + defaultMessage: 'Sum', + }), + isCompatible: isNumericFieldSelected, + disabled: true, + value: 'sum', + }, + { + text: i18n.translate('common.ui.aggTypes.metrics.topHit.averageLabel', { + defaultMessage: 'Average', + }), + isCompatible: isNumericFieldSelected, + disabled: true, + value: 'average', + }, + { + text: i18n.translate('common.ui.aggTypes.metrics.topHit.concatenateLabel', { + defaultMessage: 'Concatenate', + }), + isCompatible(aggConfig: IMetricAggConfig) { + return _.get(aggConfig.schema, 'aggSettings.top_hits.allowStrings', false); + }, + disabled: true, + value: 'concat', + }, + ], + write: _.noop, + }, + { + name: 'size', + default: 1, + }, + { + name: 'sortField', + type: 'field', + filterFieldTypes: [ + KBN_FIELD_TYPES.NUMBER, + KBN_FIELD_TYPES.DATE, + KBN_FIELD_TYPES.IP, + KBN_FIELD_TYPES.STRING, + ], + default(agg: IMetricAggConfig) { + return agg.getIndexPattern().timeFieldName; + }, + write: _.noop, // prevent default write, it is handled below + }, + { + name: 'sortOrder', + type: 'optioned', + default: 'desc', + options: [ + { + text: i18n.translate('common.ui.aggTypes.metrics.topHit.descendingLabel', { + defaultMessage: 'Descending', + }), + value: 'desc', + }, + { + text: i18n.translate('common.ui.aggTypes.metrics.topHit.ascendingLabel', { + defaultMessage: 'Ascending', + }), + value: 'asc', + }, + ], + write(agg, output) { + const sortField = agg.params.sortField; + const sortOrder = agg.params.sortOrder; + + if (sortField.scripted) { + output.params.sort = [ + { + _script: { + script: { + source: sortField.script, + lang: sortField.lang, + }, + type: sortField.type, + order: sortOrder.value, + }, + }, + ]; + } else { + output.params.sort = [ + { + [sortField.name]: { + order: sortOrder.value, + }, + }, + ]; + } + }, + }, + ], + getValue(agg, bucket) { + const hits: any[] = _.get(bucket, `${agg.id}.hits.hits`); + if (!hits || !hits.length) { + return null; + } + const path = agg.getParam('field').name; + + let values = _.flatten( + hits.map(hit => + path === '_source' ? hit._source : agg.getIndexPattern().flattenHit(hit, true)[path] + ) + ); + + if (values.length === 1) { + values = values[0]; + } + + if (Array.isArray(values)) { + if (!_.compact(values).length) { + return null; + } + + const aggregate = agg.getParam('aggregate'); + + switch (aggregate.value) { + case 'max': + return _.max(values); + case 'min': + return _.min(values); + case 'sum': + return _.sum(values); + case 'average': + return _.sum(values) / values.length; + } + } + return values; + }, +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/agg.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/agg.ts new file mode 100644 index 0000000000000..2e7c11004b472 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/agg.ts @@ -0,0 +1,55 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AggConfig } from '../agg_config'; +import { BaseParamType } from './base'; + +export class AggParamType extends BaseParamType< + TAggConfig +> { + makeAgg: (agg: TAggConfig, state?: any) => TAggConfig; + + constructor(config: Record) { + super(config); + + if (!config.write) { + this.write = (aggConfig: TAggConfig, output: Record) => { + if (aggConfig.params[this.name] && aggConfig.params[this.name].length) { + output.params[this.name] = aggConfig.params[this.name]; + } + }; + } + if (!config.serialize) { + this.serialize = (agg: TAggConfig) => { + return agg.toJSON(); + }; + } + if (!config.deserialize) { + this.deserialize = (state: unknown, agg?: TAggConfig): TAggConfig => { + if (!agg) { + throw new Error('aggConfig was not provided to AggParamType deserialize function'); + } + return this.makeAgg(agg, state); + }; + } + + this.makeAgg = config.makeAgg; + this.valueType = AggConfig; + } +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts new file mode 100644 index 0000000000000..15ec44e2ca5ae --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts @@ -0,0 +1,84 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AggConfigs } from '../agg_configs'; +import { AggConfig } from '../agg_config'; +import { FetchOptions, ISearchSource } from '../../../../../plugins/data/public'; + +export class BaseParamType { + name: string; + type: string; + displayName: string; + required: boolean; + advanced: boolean; + default: any; + write: ( + aggConfig: TAggConfig, + output: Record, + aggConfigs?: AggConfigs, + locals?: Record + ) => void; + serialize: (value: any, aggConfig?: TAggConfig) => any; + deserialize: (value: any, aggConfig?: TAggConfig) => any; + options: any[]; + valueType?: any; + + onChange?(agg: TAggConfig): void; + shouldShow?(agg: TAggConfig): boolean; + + /** + * A function that will be called before an aggConfig is serialized and sent to ES. + * Allows aggConfig to retrieve values needed for serialization + * Example usage: an aggregation needs to know the min/max of a field to determine an appropriate interval + * + * @param {AggConfig} aggConfig + * @param {Courier.SearchSource} searchSource + * @returns {Promise|undefined} + */ + modifyAggConfigOnSearchRequestStart: ( + aggConfig: TAggConfig, + searchSource?: ISearchSource, + options?: FetchOptions + ) => void; + + constructor(config: Record) { + this.name = config.name; + this.type = config.type; + this.displayName = config.displayName || this.name; + this.required = config.required === true; + this.advanced = config.advanced || false; + this.onChange = config.onChange; + this.shouldShow = config.shouldShow; + this.default = config.default; + + const defaultWrite = (aggConfig: TAggConfig, output: Record) => { + if (aggConfig.params[this.name]) { + output.params[this.name] = aggConfig.params[this.name] || this.default; + } + }; + + this.write = config.write || defaultWrite; + this.serialize = config.serialize; + this.deserialize = config.deserialize; + this.options = config.options; + this.modifyAggConfigOnSearchRequestStart = + config.modifyAggConfigOnSearchRequestStart || function() {}; + this.valueType = config.valueType || config.type; + } +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts new file mode 100644 index 0000000000000..9cea2934d7459 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts @@ -0,0 +1,90 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { BaseParamType } from './base'; +import { FieldParamType } from './field'; +import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +jest.mock('ui/new_platform'); + +describe('Field', () => { + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: [ + { + name: 'field1', + type: KBN_FIELD_TYPES.NUMBER, + esTypes: [ES_FIELD_TYPES.INTEGER], + aggregatable: true, + filterable: true, + searchable: true, + }, + { + name: 'field2', + type: KBN_FIELD_TYPES.STRING, + esTypes: [ES_FIELD_TYPES.TEXT], + aggregatable: false, + filterable: false, + searchable: true, + }, + ], + } as any; + + describe('constructor', () => { + it('it is an instance of BaseParamType', () => { + const aggParam = new FieldParamType({ + name: 'field', + type: 'field', + }); + + expect(aggParam instanceof BaseParamType).toBeTruthy(); + }); + }); + + describe('getAvailableFields', () => { + it('should return only aggregatable fields by default', () => { + const aggParam = new FieldParamType({ + name: 'field', + type: 'field', + }); + + const fields = aggParam.getAvailableFields(indexPattern.fields); + + expect(fields.length).toBe(1); + + for (const field of fields) { + expect(field.aggregatable).toBe(true); + } + }); + + it('should return all fields if onlyAggregatable is false', () => { + const aggParam = new FieldParamType({ + name: 'field', + type: 'field', + }); + + aggParam.onlyAggregatable = false; + + const fields = aggParam.getAvailableFields(indexPattern.fields); + + expect(fields.length).toBe(2); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts new file mode 100644 index 0000000000000..4ce5bb29f8ff6 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts @@ -0,0 +1,133 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// @ts-ignore +import { i18n } from '@kbn/i18n'; +import { AggConfig } from '../agg_config'; +import { SavedObjectNotFound } from '../../../../../plugins/kibana_utils/public'; +import { BaseParamType } from './base'; +import { toastNotifications } from '../../notify'; +import { propFilter } from '../filter'; +import { Field, IFieldList } from '../../../../../plugins/data/public'; +import { isNestedField } from '../../../../../plugins/data/public'; + +const filterByType = propFilter('type'); + +export class FieldParamType extends BaseParamType { + required = true; + scriptable = true; + filterFieldTypes: string; + onlyAggregatable: boolean; + + constructor(config: Record) { + super(config); + + this.filterFieldTypes = config.filterFieldTypes || '*'; + this.onlyAggregatable = config.onlyAggregatable !== false; + + if (!config.write) { + this.write = (aggConfig: AggConfig, output: Record) => { + const field = aggConfig.getField(); + + if (!field) { + throw new TypeError( + i18n.translate( + 'common.ui.aggTypes.paramTypes.field.requiredFieldParameterErrorMessage', + { + defaultMessage: '{fieldParameter} is a required parameter', + values: { + fieldParameter: '"field"', + }, + } + ) + ); + } + + if (field.scripted) { + output.params.script = { + source: field.script, + lang: field.lang, + }; + } else { + output.params.field = field.name; + } + }; + } + + this.serialize = (field: Field) => { + return field.name; + }; + + this.deserialize = (fieldName: string, aggConfig?: AggConfig) => { + if (!aggConfig) { + throw new Error('aggConfig was not provided to FieldParamType deserialize function'); + } + const field = aggConfig.getIndexPattern().fields.getByName(fieldName); + + if (!field) { + throw new SavedObjectNotFound('index-pattern-field', fieldName); + } + + // @ts-ignore + const validField = this.getAvailableFields(aggConfig.getIndexPattern().fields).find( + (f: any) => f.name === fieldName + ); + if (!validField) { + toastNotifications.addDanger( + i18n.translate( + 'common.ui.aggTypes.paramTypes.field.invalidSavedFieldParameterErrorMessage', + { + defaultMessage: + 'Saved {fieldParameter} parameter is now invalid. Please select a new field.', + values: { + fieldParameter: '"field"', + }, + } + ) + ); + } + + return validField; + }; + } + + /** + * filter the fields to the available ones + */ + getAvailableFields = (fields: IFieldList) => { + const filteredFields = fields.filter((field: Field) => { + const { onlyAggregatable, scriptable, filterFieldTypes } = this; + + if ( + (onlyAggregatable && (!field.aggregatable || isNestedField(field))) || + (!scriptable && field.scripted) + ) { + return false; + } + + if (!filterFieldTypes) { + return true; + } + + return filterByType([field], filterFieldTypes).length !== 0; + }); + + return filteredFields; + }; +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts new file mode 100644 index 0000000000000..384c142408012 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts @@ -0,0 +1,62 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IndexedArray } from 'ui/indexed_array'; +import { AggTypeFieldFilters } from './field_filters'; +import { AggConfig } from '../../agg_config'; +import { Field } from '../../../../../../plugins/data/public'; + +describe('AggTypeFieldFilters', () => { + let registry: AggTypeFieldFilters; + const aggConfig = {} as AggConfig; + + beforeEach(() => { + registry = new AggTypeFieldFilters(); + }); + + it('should filter nothing without registered filters', async () => { + const fields = [{ name: 'foo' }, { name: 'bar' }] as IndexedArray; + const filtered = registry.filter(fields, aggConfig); + expect(filtered).toEqual(fields); + }); + + it('should pass all fields to the registered filter', async () => { + const fields = [{ name: 'foo' }, { name: 'bar' }] as IndexedArray; + const filter = jest.fn(); + registry.addFilter(filter); + registry.filter(fields, aggConfig); + expect(filter).toHaveBeenCalledWith(fields[0], aggConfig); + expect(filter).toHaveBeenCalledWith(fields[1], aggConfig); + }); + + it('should allow registered filters to filter out fields', async () => { + const fields = [{ name: 'foo' }, { name: 'bar' }] as IndexedArray; + let filtered = registry.filter(fields, aggConfig); + expect(filtered).toEqual(fields); + + registry.addFilter(() => true); + registry.addFilter(field => field.name !== 'foo'); + filtered = registry.filter(fields, aggConfig); + expect(filtered).toEqual([fields[1]]); + + registry.addFilter(field => field.name !== 'bar'); + filtered = registry.filter(fields, aggConfig); + expect(filtered).toEqual([]); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.ts new file mode 100644 index 0000000000000..7d44bedafa7e1 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.ts @@ -0,0 +1,60 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { Field } from 'src/plugins/data/public'; +import { AggConfig } from '../../agg_config'; + +type AggTypeFieldFilter = (field: Field, aggConfig: AggConfig) => boolean; + +/** + * A registry to store {@link AggTypeFieldFilter} which are used to filter down + * available fields for a specific visualization and {@link AggType}. + */ +class AggTypeFieldFilters { + private filters = new Set(); + + /** + * Register a new {@link AggTypeFieldFilter} with this registry. + * This will be used by the {@link #filter|filter method}. + * + * @param filter The filter to register. + */ + public addFilter(filter: AggTypeFieldFilter): void { + this.filters.add(filter); + } + + /** + * Returns the {@link any|fields} filtered by all registered filters. + * + * @param fields An IndexedArray of fields that will be filtered down by this registry. + * @param aggConfig The aggConfig for which the returning list will be used. + * @return A filtered list of the passed fields. + */ + public filter(fields: Field[], aggConfig: AggConfig) { + const allFilters = Array.from(this.filters); + const allowedAggTypeFields = fields.filter(field => { + const isAggTypeFieldAllowed = allFilters.every(filter => filter(field, aggConfig)); + return isAggTypeFieldAllowed; + }); + return allowedAggTypeFields; + } +} + +const aggTypeFieldFilters = new AggTypeFieldFilters(); + +export { aggTypeFieldFilters, AggTypeFieldFilters }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/index.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/index.ts new file mode 100644 index 0000000000000..ce5c7c4f9fea5 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/index.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { aggTypeFieldFilters } from './field_filters'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/index.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/index.ts new file mode 100644 index 0000000000000..3414e6a71ecdc --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/index.ts @@ -0,0 +1,24 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from './base'; +export * from './field'; +export * from './json'; +export * from './optioned'; +export * from './string'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/json.test.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/json.test.ts new file mode 100644 index 0000000000000..827299814c62a --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/json.test.ts @@ -0,0 +1,118 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { BaseParamType } from './base'; +import { JsonParamType } from './json'; +import { AggConfig } from '../agg_config'; + +jest.mock('ui/new_platform'); + +describe('JSON', function() { + const paramName = 'json_test'; + let aggConfig: AggConfig; + let output: Record; + + const initAggParam = (config: Record = {}) => + new JsonParamType({ + ...config, + type: 'json', + name: paramName, + }); + + beforeEach(function() { + aggConfig = { params: {} } as AggConfig; + output = { params: {} }; + }); + + describe('constructor', () => { + it('it is an instance of BaseParamType', () => { + const aggParam = initAggParam(); + + expect(aggParam instanceof BaseParamType).toBeTruthy(); + }); + }); + + describe('write', () => { + it('should do nothing when param is not defined', () => { + const aggParam = initAggParam(); + + expect(aggConfig.params).not.toHaveProperty(paramName); + + aggParam.write(aggConfig, output); + expect(output).not.toHaveProperty(paramName); + }); + + it('should not append param when invalid JSON', () => { + const aggParam = initAggParam(); + + aggConfig.params[paramName] = 'i am not json'; + + aggParam.write(aggConfig, output); + expect(aggConfig.params).toHaveProperty(paramName); + expect(output).not.toHaveProperty(paramName); + }); + + it('should append param when valid JSON', () => { + const aggParam = initAggParam(); + const jsonData = JSON.stringify({ + new_param: 'should exist in output', + }); + + output.params.existing = 'true'; + aggConfig.params[paramName] = jsonData; + + aggParam.write(aggConfig, output); + expect(aggConfig.params).toHaveProperty(paramName); + + expect(output.params).toEqual({ + existing: 'true', + new_param: 'should exist in output', + }); + }); + + it('should not overwrite existing params', () => { + const aggParam = initAggParam(); + const jsonData = JSON.stringify({ + new_param: 'should exist in output', + existing: 'should be used', + }); + + output.params.existing = 'true'; + aggConfig.params[paramName] = jsonData; + + aggParam.write(aggConfig, output); + expect(output.params).toEqual(JSON.parse(jsonData)); + }); + + it('should drop nulled params', () => { + const aggParam = initAggParam(); + const jsonData = JSON.stringify({ + new_param: 'should exist in output', + field: null, + }); + + output.params.field = 'extensions'; + aggConfig.params[paramName] = jsonData; + + aggParam.write(aggConfig, output); + expect(Object.keys(output.params)).toContain('new_param'); + expect(Object.keys(output.params)).not.toContain('field'); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/json.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/json.ts new file mode 100644 index 0000000000000..771919b0bb56b --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/json.ts @@ -0,0 +1,82 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import _ from 'lodash'; + +import { AggConfig } from '../agg_config'; +import { BaseParamType } from './base'; + +export class JsonParamType extends BaseParamType { + constructor(config: Record) { + super(config); + + this.name = config.name || 'json'; + + if (!config.write) { + this.write = (aggConfig: AggConfig, output: Record) => { + let paramJson; + const param = aggConfig.params[this.name]; + + if (!param) { + return; + } + + // handle invalid Json input + try { + paramJson = JSON.parse(param); + } catch (err) { + return; + } + + function filteredCombine(srcA: any, srcB: any) { + function mergeObjs(a: any, b: any) { + return _(a) + .keys() + .union(_.keys(b)) + .transform(function(dest, key) { + const val = compare(a[key], b[key]); + if (val !== undefined) dest[key] = val; + }, {}) + .value(); + } + + function mergeArrays(a: any, b: any): any { + // attempt to merge each value + return _.times(Math.max(a.length, b.length), function(i) { + return compare(a[i], b[i]); + }); + } + + function compare(a: any, b: any) { + if (_.isPlainObject(a) && _.isPlainObject(b)) return mergeObjs(a, b); + if (Array.isArray(a) && Array.isArray(b)) return mergeArrays(a, b); + if (b === null) return undefined; + if (b !== undefined) return b; + return a; + } + + return compare(srcA, srcB); + } + + output.params = filteredCombine(output.params, paramJson); + return; + }; + } + } +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.test.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.test.ts new file mode 100644 index 0000000000000..6b58d81914097 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.test.ts @@ -0,0 +1,36 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { BaseParamType } from './base'; +import { OptionedParamType } from './optioned'; + +jest.mock('ui/new_platform'); + +describe('Optioned', () => { + describe('constructor', () => { + it('it is an instance of BaseParamType', () => { + const aggParam = new OptionedParamType({ + name: 'some_param', + type: 'optioned', + }); + + expect(aggParam instanceof BaseParamType).toBeTruthy(); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.ts new file mode 100644 index 0000000000000..5ffda3740af49 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.ts @@ -0,0 +1,59 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AggConfig } from '../agg_config'; +import { BaseParamType } from './base'; + +export interface OptionedValueProp { + value: string; + text: string; + disabled?: boolean; + isCompatible: (agg: AggConfig) => boolean; +} + +export interface OptionedParamEditorProps { + aggParam: { + options: T[]; + }; +} + +export class OptionedParamType extends BaseParamType { + options: OptionedValueProp[]; + + constructor(config: Record) { + super(config); + + if (!config.write) { + this.write = (aggConfig: AggConfig, output: Record) => { + output.params[this.name] = aggConfig.params[this.name].value; + }; + } + if (!config.serialize) { + this.serialize = (selected: OptionedValueProp) => { + return selected.value; + }; + } + if (!config.deserialize) { + this.deserialize = (value: any) => { + return this.options.find((option: OptionedValueProp) => option.value === value); + }; + } + this.options = config.options || []; + } +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/string.test.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/string.test.ts new file mode 100644 index 0000000000000..fd5ccebde993e --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/string.test.ts @@ -0,0 +1,80 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { BaseParamType } from './base'; +import { StringParamType } from './string'; +import { AggConfig } from '../agg_config'; + +jest.mock('ui/new_platform'); + +describe('String', function() { + let paramName = 'json_test'; + let aggConfig: AggConfig; + let output: Record; + + const initAggParam = (config: Record = {}) => + new StringParamType({ + ...config, + type: 'string', + name: paramName, + }); + + beforeEach(() => { + aggConfig = { params: {} } as AggConfig; + output = { params: {} }; + }); + + describe('constructor', () => { + it('it is an instance of BaseParamType', () => { + const aggParam = initAggParam(); + + expect(aggParam instanceof BaseParamType).toBeTruthy(); + }); + }); + + describe('write', () => { + it('should append param by name', () => { + const params = { + [paramName]: 'some input', + }; + + const aggParam = initAggParam({ name: paramName }); + + aggConfig.params = params; + aggParam.write(aggConfig, output); + + expect(output.params).toEqual(params); + }); + + it('should not be in output with empty input', () => { + paramName = 'more_testing'; + + const params = { + [paramName]: '', + }; + + const aggParam = initAggParam({ name: paramName }); + + aggConfig.params = params; + aggParam.write(aggConfig, output); + + expect(output.params).toEqual({}); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/string.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/string.ts new file mode 100644 index 0000000000000..58ba99f8a6d63 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/string.ts @@ -0,0 +1,35 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AggConfig } from '../agg_config'; +import { BaseParamType } from './base'; + +export class StringParamType extends BaseParamType { + constructor(config: Record) { + super(config); + + if (!config.write) { + this.write = (aggConfig: AggConfig, output: Record) => { + if (aggConfig.params[this.name] && aggConfig.params[this.name].length) { + output.params[this.name] = aggConfig.params[this.name]; + } + }; + } + } +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/schemas.ts b/src/legacy/core_plugins/data/public/search/aggs/schemas.ts new file mode 100644 index 0000000000000..05723cac1869d --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/schemas.ts @@ -0,0 +1,107 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import _ from 'lodash'; + +import { Optional } from '@kbn/utility-types'; + +import { IndexedArray } from 'ui/indexed_array'; +import { AggGroupNames } from './agg_groups'; +import { AggParam } from './agg_params'; + +export interface ISchemas { + [AggGroupNames.Buckets]: Schema[]; + [AggGroupNames.Metrics]: Schema[]; +} + +export interface Schema { + aggFilter: string | string[]; + editor: boolean | string; + group: AggGroupNames; + max: number; + min: number; + name: string; + params: AggParam[]; + title: string; + defaults: unknown; + hideCustomLabel?: boolean; + mustBeFirst?: boolean; + aggSettings?: any; +} + +class Schemas { + // @ts-ignore + all: IndexedArray; + + constructor( + schemas: Array< + Optional< + Schema, + 'min' | 'max' | 'group' | 'title' | 'aggFilter' | 'editor' | 'params' | 'defaults' + > + > + ) { + _(schemas || []) + .map(schema => { + if (!schema.name) throw new Error('all schema must have a unique name'); + + if (schema.name === 'split') { + schema.params = [ + { + name: 'row', + default: true, + }, + ] as AggParam[]; + } + + _.defaults(schema, { + min: 0, + max: Infinity, + group: AggGroupNames.Buckets, + title: schema.name, + aggFilter: '*', + editor: false, + params: [], + }); + + return schema as Schema; + }) + .tap((fullSchemas: Schema[]) => { + this.all = new IndexedArray({ + index: ['name'], + group: ['group'], + immutable: true, + initialSet: fullSchemas, + }); + }) + .groupBy('group') + .forOwn((group, groupName) => { + // @ts-ignore + this[groupName] = new IndexedArray({ + index: ['name'], + immutable: true, + // @ts-ignore + initialSet: group, + }); + }) + .commit(); + } +} + +export { Schemas }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/utils.test.tsx b/src/legacy/core_plugins/data/public/search/aggs/utils.test.tsx new file mode 100644 index 0000000000000..a3c7f24f3927d --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/utils.test.tsx @@ -0,0 +1,51 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { isValidJson } from './utils'; + +jest.mock('ui/new_platform'); + +const input = { + valid: '{ "test": "json input" }', + invalid: 'strings are not json', +}; + +describe('AggType utils', () => { + describe('isValidJson', () => { + it('should return true when empty string', () => { + expect(isValidJson('')).toBeTruthy(); + }); + + it('should return true when undefine', () => { + expect(isValidJson(undefined as any)).toBeTruthy(); + }); + + it('should return false when invalid string', () => { + expect(isValidJson(input.invalid)).toBeFalsy(); + }); + + it('should return true when valid string', () => { + expect(isValidJson(input.valid)).toBeTruthy(); + }); + + it('should return false if a number', () => { + expect(isValidJson('0')).toBeFalsy(); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/utils.ts b/src/legacy/core_plugins/data/public/search/aggs/utils.ts new file mode 100644 index 0000000000000..fd405d49625ed --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/utils.ts @@ -0,0 +1,72 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { isValidEsInterval } from '../../../core_plugins/data/public'; +import { leastCommonInterval } from '../vis/lib/least_common_interval'; + +/** + * Check a string if it's a valid JSON. + * + * @param {string} value a string that should be validated + * @returns {boolean} true if value is a valid JSON or if value is an empty string, or a string with whitespaces, otherwise false + */ +function isValidJson(value: string): boolean { + if (!value || value.length === 0) { + return true; + } + + const trimmedValue = value.trim(); + + if (trimmedValue.length === 0) { + return true; + } + + if (trimmedValue[0] === '{' || trimmedValue[0] === '[') { + try { + JSON.parse(trimmedValue); + return true; + } catch (e) { + return false; + } + } else { + return false; + } +} + +function isValidInterval(value: string, baseInterval?: string) { + if (baseInterval) { + return _parseWithBase(value, baseInterval); + } else { + return isValidEsInterval(value); + } +} + +// When base interval is set, check for least common interval and allow +// input the value is the same. This means that the input interval is a +// multiple of the base interval. +function _parseWithBase(value: string, baseInterval: string) { + try { + const interval = leastCommonInterval(baseInterval, value); + return interval === value.replace(/\s/g, ''); + } catch (e) { + return false; + } +} + +export { isValidJson, isValidInterval }; From 99b043c39c9c361666a3689e10dc6c653318ede3 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Wed, 29 Jan 2020 16:20:53 -0700 Subject: [PATCH 02/10] Fix imports in core_plugins/data/public/search/aggs --- .../data/public/search/aggs/agg_config.ts | 18 +++++++++--------- .../data/public/search/aggs/agg_configs.ts | 2 +- .../data/public/search/aggs/agg_params.test.ts | 2 +- .../data/public/search/aggs/agg_type.ts | 10 +++++++--- .../search/aggs/buckets/_bucket_agg_type.ts | 2 +- .../aggs/buckets/_terms_other_bucket_helper.js | 2 +- .../create_filter/date_histogram.test.ts | 2 +- .../buckets/create_filter/date_histogram.ts | 2 +- .../buckets/create_filter/date_range.test.ts | 2 +- .../aggs/buckets/create_filter/date_range.ts | 2 +- .../aggs/buckets/create_filter/filters.ts | 2 +- .../buckets/create_filter/histogram.test.ts | 2 +- .../aggs/buckets/create_filter/histogram.ts | 2 +- .../buckets/create_filter/ip_range.test.ts | 2 +- .../aggs/buckets/create_filter/ip_range.ts | 2 +- .../aggs/buckets/create_filter/range.test.ts | 2 +- .../search/aggs/buckets/create_filter/range.ts | 2 +- .../aggs/buckets/create_filter/terms.test.ts | 2 +- .../search/aggs/buckets/create_filter/terms.ts | 2 +- .../search/aggs/buckets/date_histogram.ts | 6 +++--- .../public/search/aggs/buckets/date_range.ts | 2 +- .../data/public/search/aggs/buckets/filters.ts | 4 ++-- .../public/search/aggs/buckets/geo_hash.ts | 4 ++-- .../public/search/aggs/buckets/geo_tile.ts | 2 +- .../public/search/aggs/buckets/histogram.ts | 2 +- .../public/search/aggs/buckets/ip_range.ts | 2 +- .../search/aggs/buckets/lib/cidr_mask.ts | 2 +- .../public/search/aggs/buckets/range.test.ts | 2 +- .../data/public/search/aggs/buckets/range.ts | 2 +- .../search/aggs/buckets/significant_terms.ts | 2 +- .../data/public/search/aggs/buckets/terms.ts | 13 +++++++------ .../aggs/filter/agg_type_filters.test.ts | 2 +- .../data/public/search/aggs/metrics/avg.ts | 2 +- .../public/search/aggs/metrics/cardinality.ts | 2 +- .../data/public/search/aggs/metrics/count.ts | 2 +- .../public/search/aggs/metrics/geo_bounds.ts | 2 +- .../public/search/aggs/metrics/geo_centroid.ts | 2 +- .../data/public/search/aggs/metrics/max.ts | 2 +- .../data/public/search/aggs/metrics/median.ts | 2 +- .../search/aggs/metrics/metric_agg_type.ts | 2 +- .../data/public/search/aggs/metrics/min.ts | 2 +- .../search/aggs/metrics/percentile_ranks.ts | 2 +- .../public/search/aggs/metrics/percentiles.ts | 2 +- .../search/aggs/metrics/std_deviation.ts | 2 +- .../data/public/search/aggs/metrics/sum.ts | 2 +- .../public/search/aggs/metrics/top_hit.test.ts | 2 +- .../data/public/search/aggs/metrics/top_hit.ts | 2 +- .../public/search/aggs/param_types/base.ts | 2 +- .../search/aggs/param_types/field.test.ts | 2 +- .../public/search/aggs/param_types/field.ts | 7 +++---- .../param_types/filter/field_filters.test.ts | 2 +- .../data/public/search/aggs/utils.ts | 4 ++-- 52 files changed, 79 insertions(+), 75 deletions(-) diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts index 2ab701d4019fb..1637f053cd0fc 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts @@ -37,7 +37,7 @@ import { FetchOptions, fieldFormats, KBN_FIELD_TYPES, -} from '../../../../plugins/data/public'; +} from '../../../../../../plugins/data/public'; export interface AggConfigOptions { enabled: boolean; @@ -63,7 +63,7 @@ const unknownSchema: Schema = { const getTypeFromRegistry = (type: string): AggType => { // We need to inline require here, since we're having a cyclic dependency // from somewhere inside agg_types back to AggConfig. - const aggTypes = require('../agg_types').aggTypes; + const aggTypes = require('../aggs').aggTypes; const registeredType = aggTypes.metrics.find((agg: AggType) => agg.name === type) || aggTypes.buckets.find((agg: AggType) => agg.name === type); @@ -96,12 +96,12 @@ export class AggConfig { static ensureIds(list: AggConfig[]) { const have: AggConfig[] = []; const haveNot: AggConfig[] = []; - list.forEach(function (obj) { + list.forEach(function(obj) { (obj.id ? have : haveNot).push(obj); }); let nextId = AggConfig.nextId(have); - haveNot.forEach(function (obj) { + haveNot.forEach(function(obj) { obj.id = String(nextId++); }); @@ -116,7 +116,7 @@ export class AggConfig { static nextId(list: AggConfig[]) { return ( 1 + - list.reduce(function (max, obj) { + list.reduce(function(max, obj) { return Math.max(max, +obj.id || 0); }, 0) ); @@ -361,9 +361,9 @@ export class AggConfig { if (!this.type) return ''; return percentageMode ? i18n.translate('common.ui.vis.aggConfig.percentageOfLabel', { - defaultMessage: 'Percentage of {label}', - values: { label: this.type.makeLabel(this) }, - }) + defaultMessage: 'Percentage of {label}', + values: { label: this.type.makeLabel(this) }, + }) : `${this.type.makeLabel(this)}`; } @@ -415,7 +415,7 @@ export class AggConfig { if (this.__typeDecorations) { _.forOwn( this.__typeDecorations, - function (prop, name: string | undefined) { + function(prop, name: string | undefined) { // @ts-ignore delete this[name]; }, diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts index 47e2222abe1e8..b6d987136e364 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts @@ -35,7 +35,7 @@ import { ISearchSource, FetchOptions, TimeRange, -} from '../../../../plugins/data/public'; +} from '../../../../../../plugins/data/public'; type Schemas = Record; diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts index 25e62e06d52d7..30ab272537dad 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts @@ -21,7 +21,7 @@ import { initParams } from './agg_params'; import { BaseParamType } from './param_types/base'; import { FieldParamType } from './param_types/field'; import { OptionedParamType } from './param_types/optioned'; -import { AggParamType } from '../agg_types/param_types/agg'; +import { AggParamType } from '../aggs/param_types/agg'; jest.mock('ui/new_platform'); diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts index 7ec688277b9c4..64865d60fddaa 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts @@ -24,10 +24,14 @@ import { initParams } from './agg_params'; import { AggConfig } from './agg_config'; import { AggConfigs } from './agg_configs'; -import { Adapters } from '../../../../plugins/inspector/public'; +import { Adapters } from '../../../../../../plugins/inspector/public'; import { BaseParamType } from './param_types/base'; -import { AggParamType } from '../agg_types/param_types/agg'; -import { KBN_FIELD_TYPES, fieldFormats, ISearchSource } from '../../../../plugins/data/public'; +import { AggParamType } from './param_types/agg'; +import { + KBN_FIELD_TYPES, + fieldFormats, + ISearchSource, +} from '../../../../../../plugins/data/public'; export interface AggTypeConfig< TAggConfig extends AggConfig = AggConfig, diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts index 9b7c97a8f11b6..546d054c5af97 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts @@ -18,7 +18,7 @@ */ import { AggConfig } from '../agg_config'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { AggType, AggTypeConfig } from '../agg_type'; import { AggParamType } from '../param_types/agg'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js b/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js index c8580183756f4..ddab360161744 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js @@ -18,7 +18,7 @@ */ import _ from 'lodash'; -import { esFilters, esQuery } from '../../../../../plugins/data/public'; +import { esFilters, esQuery } from '../../../../../../../plugins/data/public'; import { AggGroupNames } from '../agg_groups'; /** diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts index 9426df7d34c29..e212132257ef6 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts @@ -23,7 +23,7 @@ import { intervalOptions } from '../_interval_options'; import { AggConfigs } from '../../agg_configs'; import { IBucketDateHistogramAggConfig } from '../date_histogram'; import { BUCKET_TYPES } from '../bucket_agg_types'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts index f91a92eab1c33..e634b5daf0ac3 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts @@ -19,7 +19,7 @@ import moment from 'moment'; import { IBucketDateHistogramAggConfig } from '../date_histogram'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterDateHistogram = ( agg: IBucketDateHistogramAggConfig, diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts index 9c2c4f72704f4..e224253a6e314 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts @@ -19,7 +19,7 @@ import moment from 'moment'; import { createFilterDateRange } from './date_range'; -import { fieldFormats } from '../../../../../../plugins/data/public'; +import { fieldFormats } from '../../../../../../../../plugins/data/public'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts index 01689d954a072..f7f2cfdb7bb61 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts @@ -20,7 +20,7 @@ import moment from 'moment'; import { IBucketAggConfig } from '../_bucket_agg_type'; import { DateRangeKey } from '../date_range'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterDateRange = (agg: IBucketAggConfig, { from, to }: DateRangeKey) => { const filter: esFilters.RangeFilterParams = {}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts index 6b614514580b6..715f6895374e6 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts @@ -19,7 +19,7 @@ import { get } from 'lodash'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterFilters = (aggConfig: IBucketAggConfig, key: string) => { // have the aggConfig write agg dsl params diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts index ef49636f9e0c1..1a78967261fa6 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts @@ -20,7 +20,7 @@ import { createFilterHistogram } from './histogram'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { fieldFormats } from '../../../../../../plugins/data/public'; +import { fieldFormats } from '../../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts index fc587fa9ecdb6..820f3de5ae9f0 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts @@ -18,7 +18,7 @@ */ import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterHistogram = (aggConfig: IBucketAggConfig, key: string) => { const value = parseInt(key, 10); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts index a9eca3bbb7a56..e92ba5cb2852a 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts @@ -19,7 +19,7 @@ import { createFilterIpRange } from './ip_range'; import { AggConfigs } from '../../agg_configs'; -import { fieldFormats } from '../../../../../../plugins/data/public'; +import { fieldFormats } from '../../../../../../../../plugins/data/public'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts index a513b8c782739..d78f4579cd713 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts @@ -20,7 +20,7 @@ import { CidrMask } from '../lib/cidr_mask'; import { IBucketAggConfig } from '../_bucket_agg_type'; import { IpRangeKey } from '../ip_range'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterIpRange = (aggConfig: IBucketAggConfig, key: IpRangeKey) => { let range: esFilters.RangeFilterParams; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts index 720e952c28821..2f74f23721813 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts @@ -18,7 +18,7 @@ */ import { createFilterRange } from './range'; -import { fieldFormats } from '../../../../../../plugins/data/public'; +import { fieldFormats } from '../../../../../../../../plugins/data/public'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts index 929827c6e3fec..125a30a1ab1dd 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts @@ -18,7 +18,7 @@ */ import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterRange = (aggConfig: IBucketAggConfig, params: any) => { return esFilters.buildRangeFilter( diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts index 86c0aa24f529a..d5fd1337f2cb2 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts @@ -21,7 +21,7 @@ import { createFilterTerms } from './terms'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts index 5bd770e672786..e0d1f91c1e16a 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts @@ -18,7 +18,7 @@ */ import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterTerms = (aggConfig: IBucketAggConfig, key: string, params: any) => { const field = aggConfig.params.field; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts index 33672b54b1f2e..8eb0c70964f95 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts @@ -22,16 +22,16 @@ import moment from 'moment-timezone'; import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; +import { timefilter } from 'ui/timefilter'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { createFilterDateHistogram } from './create_filter/date_histogram'; import { intervalOptions } from './_interval_options'; -import { timefilter } from '../../timefilter'; -import { dateHistogramInterval } from '../../../../core_plugins/data/public'; +import { dateHistogramInterval } from '../../../../common'; import { writeParams } from '../agg_params'; import { isMetricAggType } from '../metrics/metric_agg_type'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; // @ts-ignore import { TimeBuckets } from '../../time_buckets'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts index ee04e0657f317..53d75c7a1cb76 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts @@ -24,7 +24,7 @@ import { BUCKET_TYPES } from './bucket_agg_types'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { createFilterDateRange } from './create_filter/date_range'; -import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../../../plugins/data/public'; const dateRangeTitle = i18n.translate('common.ui.aggTypes.buckets.dateRangeTitle', { defaultMessage: 'Date Range', diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/filters.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/filters.ts index d9b78b3063e23..948d7525c19a5 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/filters.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/filters.ts @@ -25,8 +25,8 @@ import { i18n } from '@kbn/i18n'; import chrome from 'ui/chrome'; import { createFilterFilters } from './create_filter/filters'; import { BucketAggType } from './_bucket_agg_type'; -import { Storage } from '../../../../../plugins/kibana_utils/public'; -import { getQueryLog, esQuery, Query } from '../../../../../plugins/data/public'; +import { Storage } from '../../../../../../../plugins/kibana_utils/public'; +import { getQueryLog, esQuery, Query } from '../../../../../../../plugins/data/public'; import { BUCKET_TYPES } from './bucket_agg_types'; const config = chrome.getUiSettingsClient(); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts index b2519df6fb175..e44d9202d17d8 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts @@ -19,9 +19,9 @@ import { i18n } from '@kbn/i18n'; import { geohashColumns } from 'ui/vis/map/decode_geo_hash'; -import chrome from '../../chrome'; +import chrome from 'ui/chrome'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { geoContains, scaleBounds, GeoBoundingBox } from './lib/geo_utils'; import { BUCKET_TYPES } from './bucket_agg_types'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts index ef71e3947566a..a685073cc3cbe 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts @@ -23,7 +23,7 @@ import { AggConfigOptions } from '../agg_config'; import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { IBucketAggConfig } from './_bucket_agg_type'; import { METRIC_TYPES } from '../metrics/metric_agg_types'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts index 44327c7c19e6d..3af22d526c19d 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts @@ -24,7 +24,7 @@ import { toastNotifications } from 'ui/notify'; import { npStart } from 'ui/new_platform'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { createFilterHistogram } from './create_filter/histogram'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { BUCKET_TYPES } from './bucket_agg_types'; export interface AutoBounds { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts index 41141dabf507c..abcd3d83fca4f 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts @@ -25,7 +25,7 @@ import { BUCKET_TYPES } from './bucket_agg_types'; // @ts-ignore import { createFilterIpRange } from './create_filter/ip_range'; -import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../../../plugins/data/public'; const ipRangeTitle = i18n.translate('common.ui.aggTypes.buckets.ipRangeTitle', { defaultMessage: 'IPv4 Range', diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts index aadbbc8c82276..30c4e400fb806 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Ipv4Address } from '../../../../../../plugins/kibana_utils/public'; +import { Ipv4Address } from '../../../../../../../../plugins/kibana_utils/public'; const NUM_BITS = 32; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts index dd85c3b31939f..4c0fa7311461e 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts @@ -19,7 +19,7 @@ import { AggConfigs } from '../agg_configs'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { fieldFormats } from '../../../../../plugins/data/public'; +import { fieldFormats } from '../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts index f24473e0c68aa..f6c8dbafeda9c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { BucketAggType } from './_bucket_agg_type'; -import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { RangeKey } from './range_key'; import { createFilterRange } from './create_filter/range'; import { BUCKET_TYPES } from './bucket_agg_types'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts index 38ca0768d3bc1..fb7bf07fa7015 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts @@ -22,7 +22,7 @@ import { BucketAggType } from './_bucket_agg_type'; import { createFilterTerms } from './create_filter/terms'; import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const significantTermsTitle = i18n.translate('common.ui.aggTypes.buckets.significantTermsTitle', { defaultMessage: 'Significant Terms', diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts index 4ced1417402b5..2b009fe1a9297 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts @@ -19,10 +19,7 @@ import { noop } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { - getRequestInspectorStats, - getResponseInspectorStats, -} from '../../../../core_plugins/data/public'; +import { getRequestInspectorStats, getResponseInspectorStats } from '../../../index'; import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { IBucketAggConfig } from './_bucket_agg_type'; @@ -30,8 +27,12 @@ import { createFilterTerms } from './create_filter/terms'; import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; import { AggConfigs } from '../agg_configs'; -import { Adapters } from '../../../../../plugins/inspector/public'; -import { ISearchSource, fieldFormats, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { Adapters } from '../../../../../../../plugins/inspector/public'; +import { + ISearchSource, + fieldFormats, + KBN_FIELD_TYPES, +} from '../../../../../../../plugins/data/public'; import { buildOtherBucketAgg, diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts index 0344f304877f2..64bd6955e518e 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IndexPattern } from '../../../../../plugins/data/public'; +import { IndexPattern } from '../../../../../../../plugins/data/public'; import { AggTypeFilters } from './agg_type_filters'; import { AggConfig, AggType } from '..'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts index 0222a8e543223..e47d148cbad78 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const averageTitle = i18n.translate('common.ui.aggTypes.metrics.averageTitle', { defaultMessage: 'Average', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts index c69ffae3b4871..5f99febcd713f 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const uniqueCountTitle = i18n.translate('common.ui.aggTypes.metrics.uniqueCountTitle', { defaultMessage: 'Unique Count', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts index 22a939cd9a3fd..e063bdedf914d 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts index b8ce03cdf11ec..29ec2508e315c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const geoBoundsTitle = i18n.translate('common.ui.aggTypes.metrics.geoBoundsTitle', { defaultMessage: 'Geo Bounds', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts index 5313e31796a5b..e356133560307 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const geoCentroidTitle = i18n.translate('common.ui.aggTypes.metrics.geoCentroidTitle', { defaultMessage: 'Geo Centroid', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts index 5c43511acee72..887a61a69b763 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const maxTitle = i18n.translate('common.ui.aggTypes.metrics.maxTitle', { defaultMessage: 'Max', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts index 5792d4a7c2ba3..7eb9cfd54620f 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts @@ -22,7 +22,7 @@ import { METRIC_TYPES } from './metric_agg_types'; // @ts-ignore import { percentilesMetricAgg } from './percentiles'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const medianTitle = i18n.translate('common.ui.aggTypes.metrics.medianTitle', { defaultMessage: 'Median', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts index 5cd3dffb10b9d..1027ee5db3ac7 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts @@ -23,7 +23,7 @@ import { AggType, AggTypeConfig } from '../agg_type'; import { AggParamType } from '../param_types/agg'; import { AggConfig } from '../agg_config'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; export interface IMetricAggConfig extends AggConfig { type: InstanceType; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/min.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/min.ts index 5f8ca72954cc2..f5b6663d82e5a 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/min.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/min.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const minTitle = i18n.translate('common.ui.aggTypes.metrics.minTitle', { defaultMessage: 'Min', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts index cbd46e3f5b28d..75db586db7cd1 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts @@ -24,7 +24,7 @@ import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_respons import { getPercentileValue } from './percentiles_get_value'; import { METRIC_TYPES } from './metric_agg_types'; -import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; // required by the values editor diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts index 040324d8da5df..f6d18535723de 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; import { getPercentileValue } from './percentiles_get_value'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts index b2e6d3b3ca4d0..764c222e72b0c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts @@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; interface ValProp { valProp: string[]; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts index ce79c761ce799..835179a774fb7 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; const sumTitle = i18n.translate('common.ui.aggTypes.metrics.sumTitle', { defaultMessage: 'Sum', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.test.ts index 3e861c052d367..a973de4fe8659 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.test.ts @@ -21,7 +21,7 @@ import { dropRight, last } from 'lodash'; import { topHitMetricAgg } from './top_hit'; import { AggConfigs } from '../agg_configs'; import { IMetricAggConfig } from './metric_agg_type'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts index 43fe33bdebeb9..9dd690f778875 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts @@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n'; import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; import { aggTypeFieldFilters } from '../param_types/filter'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; // @ts-ignore import { wrapWithInlineComp } from '../buckets/inline_comp_wrapper'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts index 15ec44e2ca5ae..085bad76301c0 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts @@ -19,7 +19,7 @@ import { AggConfigs } from '../agg_configs'; import { AggConfig } from '../agg_config'; -import { FetchOptions, ISearchSource } from '../../../../../plugins/data/public'; +import { FetchOptions, ISearchSource } from '../../../../../../../plugins/data/public'; export class BaseParamType { name: string; diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts index 9cea2934d7459..d0fa711d89c70 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts @@ -19,7 +19,7 @@ import { BaseParamType } from './base'; import { FieldParamType } from './field'; -import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts index 4ce5bb29f8ff6..94c11f3ee4dd1 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts @@ -19,13 +19,12 @@ // @ts-ignore import { i18n } from '@kbn/i18n'; +import { toastNotifications } from 'ui/notify'; import { AggConfig } from '../agg_config'; -import { SavedObjectNotFound } from '../../../../../plugins/kibana_utils/public'; +import { SavedObjectNotFound } from '../../../../../../../plugins/kibana_utils/public'; import { BaseParamType } from './base'; -import { toastNotifications } from '../../notify'; import { propFilter } from '../filter'; -import { Field, IFieldList } from '../../../../../plugins/data/public'; -import { isNestedField } from '../../../../../plugins/data/public'; +import { Field, IFieldList, isNestedField } from '../../../../../../../plugins/data/public'; const filterByType = propFilter('type'); diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts index 384c142408012..fb53e72b85c60 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts @@ -20,7 +20,7 @@ import { IndexedArray } from 'ui/indexed_array'; import { AggTypeFieldFilters } from './field_filters'; import { AggConfig } from '../../agg_config'; -import { Field } from '../../../../../../plugins/data/public'; +import { Field } from '../../../../../../../../plugins/data/public'; describe('AggTypeFieldFilters', () => { let registry: AggTypeFieldFilters; diff --git a/src/legacy/core_plugins/data/public/search/aggs/utils.ts b/src/legacy/core_plugins/data/public/search/aggs/utils.ts index fd405d49625ed..62f07ce44ab46 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/utils.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/utils.ts @@ -17,8 +17,8 @@ * under the License. */ -import { isValidEsInterval } from '../../../core_plugins/data/public'; -import { leastCommonInterval } from '../vis/lib/least_common_interval'; +import { leastCommonInterval } from 'ui/vis/lib/least_common_interval'; +import { isValidEsInterval } from '../../../common'; /** * Check a string if it's a valid JSON. From 188f2c160d6e37773c0f66522a03188755e44663 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Wed, 29 Jan 2020 17:07:09 -0700 Subject: [PATCH 03/10] Export WIP contracts from data shim plugin. --- src/legacy/core_plugins/data/public/index.ts | 41 ++++++- src/legacy/core_plugins/data/public/plugin.ts | 28 ++++- .../data/public/search/aggs/agg_types.ts | 114 ++++++++++++++++++ .../data/public/search/aggs/index.ts | 94 +++------------ .../data/public/search/aggs/schemas.ts | 4 +- .../data/public/search/aggs/types.ts | 24 ++++ .../core_plugins/data/public/search/index.ts | 1 + .../data/public/search/search_service.ts | 87 +++++++++++++ .../core_plugins/data/public/search/types.ts | 1 + 9 files changed, 308 insertions(+), 86 deletions(-) create mode 100644 src/legacy/core_plugins/data/public/search/aggs/agg_types.ts create mode 100644 src/legacy/core_plugins/data/public/search/aggs/types.ts create mode 100644 src/legacy/core_plugins/data/public/search/search_service.ts diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts index 7fe487667f94e..8c7b47c9367a4 100644 --- a/src/legacy/core_plugins/data/public/index.ts +++ b/src/legacy/core_plugins/data/public/index.ts @@ -18,7 +18,7 @@ */ // /// Define plugin function -import { DataPlugin as Plugin, DataStart } from './plugin'; +import { DataPlugin as Plugin } from './plugin'; export function plugin() { return new Plugin(); @@ -27,14 +27,49 @@ export function plugin() { // /// Export types & static code /** @public types */ -export { DataStart }; +export { DataSetup, DataStart } from './plugin'; export { SavedQueryAttributes, SavedQuery, SavedQueryTimeFilter, } from '../../../../plugins/data/public'; +export { + // agg_types + AggParam, + AggParamOption, + DateRangeKey, + IpRangeKey, + ISchemas, + OptionedParamEditorProps, + OptionedValueProp, +} from './search/types'; /** @public static code */ export * from '../common'; export { FilterStateManager } from './filter/filter_manager'; -export { getRequestInspectorStats, getResponseInspectorStats } from './search'; +export { + // agg_types TODO need to group these under a namespace or prefix + AggParamType, + aggTypeFilters, + AggGroupNames, + aggGroupNamesMap, + BUCKET_TYPES, + CidrMask, + convertDateRangeToString, + convertIPRangeToString, + intervalOptions, // only used in Discover + isDateHistogramBucketAggConfig, + isStringType, + isType, + isValidInterval, + isValidJson, + METRIC_TYPES, + OptionedParamType, + propFilter, + Schema, + Schemas, + termsAggFilter, + // search_source + getRequestInspectorStats, + getResponseInspectorStats, +} from './search'; diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index da35366cdff31..ebc470555d87c 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -45,6 +45,8 @@ import { } from '../../../../plugins/embeddable/public/lib/triggers'; import { IUiActionsSetup, IUiActionsStart } from '../../../../plugins/ui_actions/public'; +import { SearchSetup, SearchStart, SearchService } from './search/search_service'; + export interface DataPluginSetupDependencies { data: DataPublicPluginSetup; expressions: ExpressionsSetup; @@ -56,12 +58,23 @@ export interface DataPluginStartDependencies { uiActions: IUiActionsStart; } +/** + * Interface for this plugin's returned `setup` contract. + * + * @public + */ +export interface DataSetup { + search: SearchSetup; +} + /** * Interface for this plugin's returned `start` contract. * * @public */ -export interface DataStart {} // eslint-disable-line @typescript-eslint/no-empty-interface +export interface DataStart { + search: SearchStart; +} /** * Data Plugin - public @@ -76,7 +89,10 @@ export interface DataStart {} // eslint-disable-line @typescript-eslint/no-empty */ export class DataPlugin - implements Plugin { + implements + Plugin { + private readonly search = new SearchService(); + public setup(core: CoreSetup, { data, uiActions }: DataPluginSetupDependencies) { setInjectedMetadata(core.injectedMetadata); @@ -89,6 +105,10 @@ export class DataPlugin uiActions.registerAction( valueClickAction(data.query.filterManager, data.query.timefilter.timefilter) ); + + return { + search: this.search.setup(core), + }; } public start(core: CoreStart, { data, uiActions }: DataPluginStartDependencies): DataStart { @@ -102,7 +122,9 @@ export class DataPlugin uiActions.attachAction(SELECT_RANGE_TRIGGER, SELECT_RANGE_ACTION); uiActions.attachAction(VALUE_CLICK_TRIGGER, VALUE_CLICK_ACTION); - return {}; + return { + search: this.search.start(core), + }; } public stop() {} diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_types.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_types.ts new file mode 100644 index 0000000000000..c16eb06eeb116 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_types.ts @@ -0,0 +1,114 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +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 { geoTileBucketAgg } from './buckets/geo_tile'; +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 const aggTypes = { + 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, + geoTileBucketAgg, + ], +}; + +export { AggType } from './agg_type'; +export { AggConfig } from './agg_config'; +export { AggConfigs } from './agg_configs'; +export { FieldParamType } from './param_types'; +export { aggTypeFieldFilters } from './param_types/filter'; +export { parentPipelineAggHelper } from './metrics/lib/parent_pipeline_agg_helper'; + +// static code +export { AggParamType } from './param_types/agg'; +export { AggGroupNames, aggGroupNamesMap } from './agg_groups'; +export { intervalOptions } from './buckets/_interval_options'; // only used in Discover +export { isDateHistogramBucketAggConfig, setBounds } from './buckets/date_histogram'; +export { termsAggFilter } from './buckets/terms'; +export { isType, isStringType } from './buckets/migrate_include_exclude_format'; +export { CidrMask } from './buckets/lib/cidr_mask'; +export { convertDateRangeToString } from './buckets/date_range'; +export { convertIPRangeToString } from './buckets/ip_range'; +export { aggTypeFilters, propFilter } from './filter'; +export { OptionedParamType } from './param_types/optioned'; +export { isValidJson, isValidInterval } from './utils'; +export { BUCKET_TYPES } from './buckets/bucket_agg_types'; +export { METRIC_TYPES } from './metrics/metric_agg_types'; +export { ISchemas, Schema, Schemas } from './schemas'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/index.ts b/src/legacy/core_plugins/data/public/search/aggs/index.ts index ca7c2f82023c9..6624bbf4e5f02 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/index.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/index.ts @@ -17,87 +17,27 @@ * under the License. */ -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, setBounds } 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, termsAggFilter } 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 { geoTileBucketAgg } from './buckets/geo_tile'; -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 { aggTypes } from './agg_types'; export { AggType } from './agg_type'; - -export const aggTypes = { - 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, - geoTileBucketAgg, - ], -}; - -export { AggParam } from './agg_params'; export { AggConfig } from './agg_config'; export { AggConfigs } from './agg_configs'; -export { AggGroupNames, aggGroupNamesMap } from './agg_groups'; export { FieldParamType } from './param_types'; +export { aggTypeFieldFilters } from './param_types/filter'; +export { parentPipelineAggHelper } from './metrics/lib/parent_pipeline_agg_helper'; + +// static code +export { AggParamType } from './param_types/agg'; +export { AggGroupNames, aggGroupNamesMap } from './agg_groups'; +export { intervalOptions } from './buckets/_interval_options'; // only used in Discover +export { isDateHistogramBucketAggConfig, setBounds } from './buckets/date_histogram'; +export { termsAggFilter } from './buckets/terms'; +export { isType, isStringType } from './buckets/migrate_include_exclude_format'; +export { CidrMask } from './buckets/lib/cidr_mask'; +export { convertDateRangeToString } from './buckets/date_range'; +export { convertIPRangeToString } from './buckets/ip_range'; +export { aggTypeFilters, propFilter } from './filter'; +export { OptionedParamType } from './param_types/optioned'; +export { isValidJson, isValidInterval } from './utils'; export { BUCKET_TYPES } from './buckets/bucket_agg_types'; export { METRIC_TYPES } from './metrics/metric_agg_types'; export { ISchemas, Schema, Schemas } from './schemas'; - -export { setBounds, termsAggFilter }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/schemas.ts b/src/legacy/core_plugins/data/public/search/aggs/schemas.ts index 05723cac1869d..1aa5ebe08656b 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/schemas.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/schemas.ts @@ -45,7 +45,7 @@ export interface Schema { aggSettings?: any; } -class Schemas { +export class Schemas { // @ts-ignore all: IndexedArray; @@ -103,5 +103,3 @@ class Schemas { .commit(); } } - -export { Schemas }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/types.ts b/src/legacy/core_plugins/data/public/search/aggs/types.ts new file mode 100644 index 0000000000000..0dfcf9e1ff25e --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/types.ts @@ -0,0 +1,24 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { AggParam, AggParamOption } from './agg_params'; +export { DateRangeKey } from './buckets/date_range'; +export { IpRangeKey } from './buckets/ip_range'; +export { OptionedValueProp, OptionedParamEditorProps } from './param_types/optioned'; +export { ISchemas } from './schemas'; diff --git a/src/legacy/core_plugins/data/public/search/index.ts b/src/legacy/core_plugins/data/public/search/index.ts index c975d5772e0a8..90e191b769a8d 100644 --- a/src/legacy/core_plugins/data/public/search/index.ts +++ b/src/legacy/core_plugins/data/public/search/index.ts @@ -17,5 +17,6 @@ * under the License. */ +export * from './aggs'; export { getRequestInspectorStats, getResponseInspectorStats } from './utils'; export { serializeAggConfig } from './expressions/utils'; diff --git a/src/legacy/core_plugins/data/public/search/search_service.ts b/src/legacy/core_plugins/data/public/search/search_service.ts new file mode 100644 index 0000000000000..1e7ee84835a98 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_service.ts @@ -0,0 +1,87 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Plugin, CoreSetup, CoreStart } from '../../../../../core/public'; +import { + aggTypes, + AggType, + AggConfig, + AggConfigs, + FieldParamType, + aggTypeFieldFilters, + setBounds, + parentPipelineAggHelper, +} from './aggs'; + +interface AggsSetup { + types: typeof aggTypes; +} + +interface AggsStart { + types: typeof aggTypes; + AggConfig: typeof AggConfig; + AggConfigs: typeof AggConfigs; + AggType: typeof AggType; + aggTypeFieldFilters: typeof aggTypeFieldFilters; + FieldParamType: typeof FieldParamType; + parentPipelineAggHelper: typeof parentPipelineAggHelper; + setBounds: typeof setBounds; +} + +export interface SearchSetup { + aggs: AggsSetup; +} + +export interface SearchStart { + aggs: AggsStart; +} + +/** + * The contract provided here is a new platform shim for ui/agg_types. + * + * Once it has been refactored to work with new platform services, + * it will move into the existing search service in src/plugins/data/public/search + */ +export class SearchService implements Plugin { + public setup(core: CoreSetup): SearchSetup { + return { + aggs: { + types: aggTypes, // TODO convert to registry + // TODO add other items as needed + }, + }; + } + + public start(core: CoreStart): SearchStart { + return { + aggs: { + types: aggTypes, // TODO convert to registry + AggConfig, // TODO make static + AggConfigs, + AggType, + aggTypeFieldFilters, + FieldParamType, + parentPipelineAggHelper, + setBounds, // TODO make static + }, + }; + } + + public stop() {} +} diff --git a/src/legacy/core_plugins/data/public/search/types.ts b/src/legacy/core_plugins/data/public/search/types.ts index 140ceea487099..47ea1d168f379 100644 --- a/src/legacy/core_plugins/data/public/search/types.ts +++ b/src/legacy/core_plugins/data/public/search/types.ts @@ -17,4 +17,5 @@ * under the License. */ +export * from './aggs/types'; export * from './utils/types'; From d92887de88309826079ba1211c9cccf1de02cbbc Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Wed, 29 Jan 2020 17:37:14 -0700 Subject: [PATCH 04/10] Remove everything we don't need from ui/agg_types and re-export contracts. --- .../buckets/_terms_other_bucket_helper.js | 320 ------------- src/legacy/ui/public/agg_types/agg_config.ts | 449 +----------------- src/legacy/ui/public/agg_types/agg_configs.ts | 300 +----------- src/legacy/ui/public/agg_types/agg_groups.ts | 37 -- .../ui/public/agg_types/agg_params.test.ts | 84 ---- src/legacy/ui/public/agg_types/agg_params.ts | 75 +-- .../ui/public/agg_types/agg_type.test.ts | 169 ------- src/legacy/ui/public/agg_types/agg_type.ts | 242 +--------- .../agg_types/buckets/_bucket_agg_type.ts | 62 --- .../agg_types/buckets/_interval_options.ts | 64 +-- .../buckets/_terms_other_bucket_helper.js | 261 ---------- .../agg_types/buckets/bucket_agg_types.ts | 32 -- .../create_filter/date_histogram.test.ts | 122 ----- .../buckets/create_filter/date_histogram.ts | 40 -- .../buckets/create_filter/date_range.test.ts | 79 --- .../buckets/create_filter/date_range.ts | 32 -- .../buckets/create_filter/filters.test.ts | 67 --- .../buckets/create_filter/filters.ts | 33 -- .../buckets/create_filter/histogram.test.ts | 75 --- .../buckets/create_filter/histogram.ts | 33 -- .../buckets/create_filter/ip_range.test.ts | 105 ---- .../buckets/create_filter/ip_range.ts | 42 -- .../buckets/create_filter/range.test.ts | 79 --- .../agg_types/buckets/create_filter/range.ts | 30 -- .../buckets/create_filter/terms.test.ts | 131 ----- .../agg_types/buckets/create_filter/terms.ts | 46 -- .../agg_types/buckets/date_histogram.ts | 249 +--------- .../agg_types/buckets/date_range.test.ts | 112 ----- .../ui/public/agg_types/buckets/date_range.ts | 103 +--- .../ui/public/agg_types/buckets/filter.ts | 35 -- .../ui/public/agg_types/buckets/filters.ts | 106 ----- .../public/agg_types/buckets/geo_hash.test.ts | 225 --------- .../ui/public/agg_types/buckets/geo_hash.ts | 201 -------- .../ui/public/agg_types/buckets/geo_tile.ts | 73 --- .../agg_types/buckets/histogram.test.ts | 292 ------------ .../ui/public/agg_types/buckets/histogram.ts | 201 -------- .../ui/public/agg_types/buckets/ip_range.ts | 91 +--- .../agg_types/buckets/lib/cidr_mask.test.ts | 75 --- .../public/agg_types/buckets/lib/cidr_mask.ts | 40 +- .../public/agg_types/buckets/lib/geo_utils.ts | 75 --- .../buckets/migrate_include_exclude_format.ts | 35 +- .../ui/public/agg_types/buckets/range.test.ts | 99 ---- .../ui/public/agg_types/buckets/range.ts | 106 ----- .../ui/public/agg_types/buckets/range_key.ts | 41 -- .../buckets/significant_terms.test.ts | 111 ----- .../agg_types/buckets/significant_terms.ts | 76 --- .../ui/public/agg_types/buckets/terms.test.ts | 78 --- .../ui/public/agg_types/buckets/terms.ts | 290 ----------- .../agg_types/filter/agg_type_filters.test.ts | 62 --- .../agg_types/filter/agg_type_filters.ts | 64 --- .../agg_types/filter/prop_filter.test.ts | 94 ---- .../ui/public/agg_types/filter/prop_filter.ts | 96 ---- src/legacy/ui/public/agg_types/index.test.ts | 46 -- src/legacy/ui/public/agg_types/index.ts | 67 ++- src/legacy/ui/public/agg_types/metrics/avg.ts | 45 -- .../ui/public/agg_types/metrics/bucket_avg.ts | 57 --- .../ui/public/agg_types/metrics/bucket_max.ts | 42 -- .../ui/public/agg_types/metrics/bucket_min.ts | 40 -- .../ui/public/agg_types/metrics/bucket_sum.ts | 41 -- .../public/agg_types/metrics/cardinality.ts | 50 -- .../ui/public/agg_types/metrics/count.ts | 48 -- .../agg_types/metrics/cumulative_sum.ts | 41 -- .../ui/public/agg_types/metrics/derivative.ts | 43 -- .../ui/public/agg_types/metrics/geo_bounds.ts | 44 -- .../public/agg_types/metrics/geo_centroid.ts | 47 -- .../lib/get_response_agg_config_class.ts | 74 --- .../metrics/lib/make_nested_label.test.ts | 59 --- .../metrics/lib/make_nested_label.ts | 49 -- .../metrics/lib/nested_agg_helpers.ts | 56 --- .../metrics/lib/ordinal_suffix.test.ts | 69 --- .../agg_types/metrics/lib/ordinal_suffix.ts | 36 -- .../metrics/lib/parent_pipeline_agg_helper.ts | 89 +--- .../metrics/lib/parent_pipeline_agg_writer.ts | 40 -- .../lib/sibling_pipeline_agg_helper.ts | 123 ----- .../lib/sibling_pipeline_agg_writer.ts | 40 -- src/legacy/ui/public/agg_types/metrics/max.ts | 45 -- .../public/agg_types/metrics/median.test.ts | 69 --- .../ui/public/agg_types/metrics/median.ts | 59 --- .../agg_types/metrics/metric_agg_type.ts | 96 ---- .../agg_types/metrics/metric_agg_types.ts | 42 -- src/legacy/ui/public/agg_types/metrics/min.ts | 44 -- .../ui/public/agg_types/metrics/moving_avg.ts | 64 --- .../agg_types/metrics/parent_pipeline.test.ts | 236 --------- .../metrics/percentile_ranks.test.ts | 76 --- .../agg_types/metrics/percentile_ranks.ts | 94 ---- .../agg_types/metrics/percentiles.test.ts | 74 --- .../public/agg_types/metrics/percentiles.ts | 80 ---- .../metrics/percentiles_get_value.ts | 32 -- .../public/agg_types/metrics/serial_diff.ts | 41 -- .../metrics/sibling_pipeline.test.ts | 182 ------- .../agg_types/metrics/std_deviation.test.ts | 85 ---- .../public/agg_types/metrics/std_deviation.ts | 107 ----- src/legacy/ui/public/agg_types/metrics/sum.ts | 48 -- .../public/agg_types/metrics/top_hit.test.ts | 366 -------------- .../ui/public/agg_types/metrics/top_hit.ts | 255 ---------- .../ui/public/agg_types/param_types/agg.ts | 37 +- .../ui/public/agg_types/param_types/base.ts | 84 ---- .../agg_types/param_types/field.test.ts | 90 ---- .../ui/public/agg_types/param_types/field.ts | 133 ------ .../param_types/filter/field_filters.test.ts | 62 --- .../param_types/filter/field_filters.ts | 60 --- .../ui/public/agg_types/param_types/index.ts | 4 - .../public/agg_types/param_types/json.test.ts | 118 ----- .../ui/public/agg_types/param_types/json.ts | 82 ---- .../agg_types/param_types/optioned.test.ts | 36 -- .../public/agg_types/param_types/optioned.ts | 41 +- .../agg_types/param_types/string.test.ts | 80 ---- .../ui/public/agg_types/param_types/string.ts | 35 -- src/legacy/ui/public/agg_types/schemas.ts | 107 ----- src/legacy/ui/public/agg_types/utils.test.tsx | 51 -- src/legacy/ui/public/agg_types/utils.ts | 54 +-- 111 files changed, 69 insertions(+), 10385 deletions(-) delete mode 100644 src/legacy/ui/public/agg_types/__tests__/buckets/_terms_other_bucket_helper.js delete mode 100644 src/legacy/ui/public/agg_types/agg_groups.ts delete mode 100644 src/legacy/ui/public/agg_types/agg_params.test.ts delete mode 100644 src/legacy/ui/public/agg_types/agg_type.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/_terms_other_bucket_helper.js delete mode 100644 src/legacy/ui/public/agg_types/buckets/bucket_agg_types.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/date_range.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/filters.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/filters.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/histogram.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/range.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/create_filter/terms.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/date_range.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/filter.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/filters.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/geo_hash.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/geo_hash.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/geo_tile.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/histogram.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/histogram.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/lib/geo_utils.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/range.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/range.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/range_key.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/significant_terms.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/terms.test.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/terms.ts delete mode 100644 src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts delete mode 100644 src/legacy/ui/public/agg_types/filter/agg_type_filters.ts delete mode 100644 src/legacy/ui/public/agg_types/filter/prop_filter.test.ts delete mode 100644 src/legacy/ui/public/agg_types/filter/prop_filter.ts delete mode 100644 src/legacy/ui/public/agg_types/index.test.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/avg.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/bucket_avg.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/bucket_max.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/bucket_min.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/bucket_sum.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/cardinality.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/count.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/cumulative_sum.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/derivative.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/geo_bounds.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/geo_centroid.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/lib/get_response_agg_config_class.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.test.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/lib/nested_agg_helpers.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.test.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_writer.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_writer.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/max.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/median.test.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/median.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/metric_agg_types.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/min.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/moving_avg.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/parent_pipeline.test.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/percentile_ranks.test.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/percentile_ranks.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/percentiles.test.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/percentiles.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/percentiles_get_value.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/serial_diff.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/sibling_pipeline.test.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/std_deviation.test.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/std_deviation.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/sum.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/top_hit.test.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/top_hit.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/base.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/field.test.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/field.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/filter/field_filters.test.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/filter/field_filters.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/json.test.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/json.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/optioned.test.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/string.test.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/string.ts delete mode 100644 src/legacy/ui/public/agg_types/schemas.ts delete mode 100644 src/legacy/ui/public/agg_types/utils.test.tsx diff --git a/src/legacy/ui/public/agg_types/__tests__/buckets/_terms_other_bucket_helper.js b/src/legacy/ui/public/agg_types/__tests__/buckets/_terms_other_bucket_helper.js deleted file mode 100644 index acf932c1fb451..0000000000000 --- a/src/legacy/ui/public/agg_types/__tests__/buckets/_terms_other_bucket_helper.js +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import expect from '@kbn/expect'; -import ngMock from 'ng_mock'; -import { - buildOtherBucketAgg, - mergeOtherBucketAggResponse, - updateMissingBucket, -} from '../../buckets/_terms_other_bucket_helper'; -import { Vis } from '../../../../../core_plugins/visualizations/public'; -import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; - -const visConfigSingleTerm = { - type: 'pie', - aggs: [ - { - type: 'terms', - schema: 'segment', - params: { field: 'machine.os.raw', otherBucket: true, missingBucket: true }, - }, - ], -}; - -const visConfigNestedTerm = { - type: 'pie', - aggs: [ - { - type: 'terms', - schema: 'segment', - params: { field: 'geo.src', size: 2, otherBucket: false, missingBucket: false }, - }, - { - type: 'terms', - schema: 'segment', - params: { field: 'machine.os.raw', size: 2, otherBucket: true, missingBucket: true }, - }, - ], -}; - -const singleTermResponse = { - took: 10, - timed_out: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: 14005, - max_score: 0, - hits: [], - }, - aggregations: { - '1': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 8325, - buckets: [ - { key: 'ios', doc_count: 2850 }, - { key: 'win xp', doc_count: 2830 }, - { key: '__missing__', doc_count: 1430 }, - ], - }, - }, - status: 200, -}; - -const nestedTermResponse = { - took: 10, - timed_out: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: 14005, - max_score: 0, - hits: [], - }, - aggregations: { - '1': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 8325, - buckets: [ - { - '2': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 8325, - buckets: [ - { key: 'ios', doc_count: 2850 }, - { key: 'win xp', doc_count: 2830 }, - { key: '__missing__', doc_count: 1430 }, - ], - }, - key: 'US', - doc_count: 2850, - }, - { - '2': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 8325, - buckets: [ - { key: 'ios', doc_count: 1850 }, - { key: 'win xp', doc_count: 1830 }, - { key: '__missing__', doc_count: 130 }, - ], - }, - key: 'IN', - doc_count: 2830, - }, - ], - }, - }, - status: 200, -}; - -const nestedTermResponseNoResults = { - took: 10, - timed_out: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: 0, - max_score: null, - hits: [], - }, - aggregations: { - '1': { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [], - }, - }, - status: 200, -}; - -const singleOtherResponse = { - took: 3, - timed_out: false, - _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, - hits: { total: 14005, max_score: 0, hits: [] }, - aggregations: { - 'other-filter': { - buckets: { '': { doc_count: 2805 } }, - }, - }, - status: 200, -}; - -const nestedOtherResponse = { - took: 3, - timed_out: false, - _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, - hits: { total: 14005, max_score: 0, hits: [] }, - aggregations: { - 'other-filter': { - buckets: { '-US': { doc_count: 2805 }, '-IN': { doc_count: 2804 } }, - }, - }, - status: 200, -}; - -describe('Terms Agg Other bucket helper', () => { - let vis; - - function init(aggConfig) { - ngMock.module('kibana'); - ngMock.inject(Private => { - const indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider); - - vis = new Vis(indexPattern, aggConfig); - }); - } - - describe('buildOtherBucketAgg', () => { - it('returns a function', () => { - init(visConfigSingleTerm); - const agg = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[0], singleTermResponse); - expect(agg).to.be.a('function'); - }); - - it('correctly builds query with single terms agg', () => { - init(visConfigSingleTerm); - const agg = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[0], singleTermResponse)(); - const expectedResponse = { - aggs: undefined, - filters: { - filters: { - '': { - bool: { - must: [], - filter: [{ exists: { field: 'machine.os.raw' } }], - should: [], - must_not: [ - { match_phrase: { 'machine.os.raw': 'ios' } }, - { match_phrase: { 'machine.os.raw': 'win xp' } }, - ], - }, - }, - }, - }, - }; - - expect(agg['other-filter']).to.eql(expectedResponse); - }); - - it('correctly builds query for nested terms agg', () => { - init(visConfigNestedTerm); - const agg = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[1], nestedTermResponse)(); - const expectedResponse = { - 'other-filter': { - aggs: undefined, - filters: { - filters: { - '-IN': { - bool: { - must: [], - filter: [ - { match_phrase: { 'geo.src': 'IN' } }, - { exists: { field: 'machine.os.raw' } }, - ], - should: [], - must_not: [ - { match_phrase: { 'machine.os.raw': 'ios' } }, - { match_phrase: { 'machine.os.raw': 'win xp' } }, - ], - }, - }, - '-US': { - bool: { - must: [], - filter: [ - { match_phrase: { 'geo.src': 'US' } }, - { exists: { field: 'machine.os.raw' } }, - ], - should: [], - must_not: [ - { match_phrase: { 'machine.os.raw': 'ios' } }, - { match_phrase: { 'machine.os.raw': 'win xp' } }, - ], - }, - }, - }, - }, - }, - }; - - expect(agg).to.eql(expectedResponse); - }); - - it('returns false when nested terms agg has no buckets', () => { - init(visConfigNestedTerm); - const agg = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[1], nestedTermResponseNoResults); - expect(agg).to.eql(false); - }); - }); - - describe('mergeOtherBucketAggResponse', () => { - it('correctly merges other bucket with single terms agg', () => { - init(visConfigSingleTerm); - const otherAggConfig = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[0], singleTermResponse)(); - const mergedResponse = mergeOtherBucketAggResponse( - vis.aggs, - singleTermResponse, - singleOtherResponse, - vis.aggs.aggs[0], - otherAggConfig - ); - - expect(mergedResponse.aggregations['1'].buckets[3].key).to.equal('__other__'); - }); - - it('correctly merges other bucket with nested terms agg', () => { - init(visConfigNestedTerm); - const otherAggConfig = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[1], nestedTermResponse)(); - const mergedResponse = mergeOtherBucketAggResponse( - vis.aggs, - nestedTermResponse, - nestedOtherResponse, - vis.aggs.aggs[1], - otherAggConfig - ); - - expect(mergedResponse.aggregations['1'].buckets[1]['2'].buckets[3].key).to.equal('__other__'); - }); - }); - - describe('updateMissingBucket', () => { - it('correctly updates missing bucket key', () => { - init(visConfigNestedTerm); - const updatedResponse = updateMissingBucket(singleTermResponse, vis.aggs, vis.aggs.aggs[0]); - expect( - updatedResponse.aggregations['1'].buckets.find(bucket => bucket.key === '__missing__') - ).to.not.be('undefined'); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/agg_config.ts b/src/legacy/ui/public/agg_types/agg_config.ts index 17a8b14b57d02..489751a83724d 100644 --- a/src/legacy/ui/public/agg_types/agg_config.ts +++ b/src/legacy/ui/public/agg_types/agg_config.ts @@ -17,451 +17,4 @@ * under the License. */ -/** - * @name AggConfig - * - * @description This class represents an aggregation, which is displayed in the left-hand nav of - * the Visualize app. - */ - -import _ from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { npStart } from 'ui/new_platform'; -import { AggType } from './agg_type'; -import { AggGroupNames } from './agg_groups'; -import { writeParams } from './agg_params'; -import { AggConfigs } from './agg_configs'; -import { Schema } from './schemas'; -import { - ISearchSource, - FetchOptions, - fieldFormats, - KBN_FIELD_TYPES, -} from '../../../../plugins/data/public'; - -export interface AggConfigOptions { - enabled: boolean; - type: string; - params: any; - id?: string; - schema?: string; -} - -const unknownSchema: Schema = { - name: 'unknown', - title: 'Unknown', - hideCustomLabel: true, - aggFilter: [], - min: 1, - max: 1, - params: [], - defaults: {}, - editor: false, - group: AggGroupNames.Metrics, -}; - -const getTypeFromRegistry = (type: string): AggType => { - // We need to inline require here, since we're having a cyclic dependency - // from somewhere inside agg_types back to AggConfig. - const aggTypes = require('./agg_types').aggTypes; - const registeredType = - aggTypes.metrics.find((agg: AggType) => agg.name === type) || - aggTypes.buckets.find((agg: AggType) => agg.name === type); - - if (!registeredType) { - throw new Error('unknown type'); - } - - return registeredType; -}; - -const getSchemaFromRegistry = (schemas: any, schema: string): Schema => { - let registeredSchema = schemas ? schemas.byName[schema] : null; - if (!registeredSchema) { - registeredSchema = Object.assign({}, unknownSchema); - registeredSchema.name = schema; - } - - return registeredSchema; -}; - -export class AggConfig { - /** - * Ensure that all of the objects in the list have ids, the objects - * and list are modified by reference. - * - * @param {array[object]} list - a list of objects, objects can be anything really - * @return {array} - the list that was passed in - */ - static ensureIds(list: AggConfig[]) { - const have: AggConfig[] = []; - const haveNot: AggConfig[] = []; - list.forEach(function(obj) { - (obj.id ? have : haveNot).push(obj); - }); - - let nextId = AggConfig.nextId(have); - haveNot.forEach(function(obj) { - obj.id = String(nextId++); - }); - - return list; - } - - /** - * Calculate the next id based on the ids in this list - * - * @return {array} list - a list of objects with id properties - */ - static nextId(list: AggConfig[]) { - return ( - 1 + - list.reduce(function(max, obj) { - return Math.max(max, +obj.id || 0); - }, 0) - ); - } - - public aggConfigs: AggConfigs; - public id: string; - public enabled: boolean; - public params: any; - public parent?: AggConfigs; - public brandNew?: boolean; - - private __schema: Schema; - private __type: AggType; - private __typeDecorations: any; - private subAggs: AggConfig[] = []; - - constructor(aggConfigs: AggConfigs, opts: AggConfigOptions) { - this.aggConfigs = aggConfigs; - this.id = String(opts.id || AggConfig.nextId(aggConfigs.aggs as any)); - this.enabled = typeof opts.enabled === 'boolean' ? opts.enabled : true; - - // start with empty params so that checks in type/schema setters don't freak - // because this.params is undefined - this.params = {}; - - // setters - this.setType(opts.type); - - if (opts.schema) { - this.setSchema(opts.schema); - } - - // set the params to the values from opts, or just to the defaults - this.setParams(opts.params || {}); - - // @ts-ignore - this.__type = this.__type; - // @ts-ignore - this.__schema = this.__schema; - } - - /** - * Write the current values to this.params, filling in the defaults as we go - * - * @param {object} [from] - optional object to read values from, - * used when initializing - * @return {undefined} - */ - setParams(from: any) { - from = from || this.params || {}; - const to = (this.params = {} as any); - - this.getAggParams().forEach(aggParam => { - let val = from[aggParam.name]; - - if (val == null) { - if (aggParam.default == null) return; - - if (!_.isFunction(aggParam.default)) { - val = aggParam.default; - } else { - val = aggParam.default(this); - if (val == null) return; - } - } - - if (aggParam.deserialize) { - const isTyped = _.isFunction(aggParam.valueType); - - const isType = isTyped && val instanceof aggParam.valueType; - const isObject = !isTyped && _.isObject(val); - const isDeserialized = isType || isObject; - - if (!isDeserialized) { - val = aggParam.deserialize(val, this); - } - - to[aggParam.name] = val; - return; - } - - to[aggParam.name] = _.cloneDeep(val); - }); - } - - getParam(key: string): any { - return _.get(this.params, key); - } - - write(aggs?: AggConfigs) { - return writeParams(this.type.params, this, aggs); - } - - isFilterable() { - return _.isFunction(this.type.createFilter); - } - - createFilter(key: string, params = {}) { - const createFilter = this.type.createFilter; - - if (!createFilter) { - throw new TypeError(`The "${this.type.title}" aggregation does not support filtering.`); - } - - const field = this.getField(); - const label = this.getFieldDisplayName(); - if (field && !field.filterable) { - let message = `The "${label}" field can not be used for filtering.`; - if (field.scripted) { - message = `The "${label}" field is scripted and can not be used for filtering.`; - } - throw new TypeError(message); - } - - return createFilter(this, key, params); - } - - /** - * Hook for pre-flight logic, see AggType#onSearchRequestStart - * @param {Courier.SearchSource} searchSource - * @param {Courier.FetchOptions} options - * @return {Promise} - */ - onSearchRequestStart(searchSource: ISearchSource, options?: FetchOptions) { - if (!this.type) { - return Promise.resolve(); - } - - return Promise.all( - this.type.params.map((param: any) => - param.modifyAggConfigOnSearchRequestStart(this, searchSource, options) - ) - ); - } - - /** - * Convert this aggConfig to its dsl syntax. - * - * Adds params and adhoc subaggs to a pojo, then returns it - * - * @param {AggConfigs} aggConfigs - the config object to convert - * @return {void|Object} - if the config has a dsl representation, it is - * returned, else undefined is returned - */ - toDsl(aggConfigs?: AggConfigs) { - if (this.type.hasNoDsl) return; - const output = this.write(aggConfigs) as any; - - const configDsl = {} as any; - configDsl[this.type.dslName || this.type.name] = output.params; - - // if the config requires subAggs, write them to the dsl as well - if (this.subAggs.length && !output.subAggs) output.subAggs = this.subAggs; - if (output.subAggs) { - const subDslLvl = configDsl.aggs || (configDsl.aggs = {}); - output.subAggs.forEach(function nestAdhocSubAggs(subAggConfig: any) { - subDslLvl[subAggConfig.id] = subAggConfig.toDsl(aggConfigs); - }); - } - - if (output.parentAggs) { - const subDslLvl = configDsl.parentAggs || (configDsl.parentAggs = {}); - output.parentAggs.forEach(function nestAdhocSubAggs(subAggConfig: any) { - subDslLvl[subAggConfig.id] = subAggConfig.toDsl(aggConfigs); - }); - } - - return configDsl; - } - - toJSON() { - const params = this.params; - - const outParams = _.transform( - this.getAggParams(), - (out, aggParam) => { - let val = params[aggParam.name]; - - // don't serialize undefined/null values - if (val == null) return; - if (aggParam.serialize) val = aggParam.serialize(val, this); - if (val == null) return; - - // to prevent accidental leaking, we will clone all complex values - out[aggParam.name] = _.cloneDeep(val); - }, - {} - ); - - return { - id: this.id, - enabled: this.enabled, - type: this.type && this.type.name, - schema: _.get(this, 'schema.name', this.schema), - params: outParams, - }; - } - - getAggParams() { - return [ - ...(_.has(this, 'type.params') ? this.type.params : []), - ...(_.has(this, 'schema.params') ? (this.schema as Schema).params : []), - ]; - } - - getRequestAggs() { - return (this.type && this.type.getRequestAggs(this)) || [this]; - } - - getResponseAggs() { - return (this.type && this.type.getResponseAggs(this)) || [this]; - } - - getValue(bucket: any) { - return this.type.getValue(this, bucket); - } - - getKey(bucket: any, key?: string) { - if (this.type.getKey) { - return this.type.getKey(bucket, key, this); - } else { - return ''; - } - } - - getFieldDisplayName() { - const field = this.getField(); - - return field ? field.displayName || this.fieldName() : ''; - } - - getField() { - return this.params.field; - } - - makeLabel(percentageMode = false) { - if (this.params.customLabel) { - return this.params.customLabel; - } - - if (!this.type) return ''; - return percentageMode - ? i18n.translate('common.ui.vis.aggConfig.percentageOfLabel', { - defaultMessage: 'Percentage of {label}', - values: { label: this.type.makeLabel(this) }, - }) - : `${this.type.makeLabel(this)}`; - } - - getIndexPattern() { - return this.aggConfigs.indexPattern; - } - - getTimeRange() { - return this.aggConfigs.timeRange; - } - - fieldFormatter(contentType?: fieldFormats.ContentType, defaultFormat?: any) { - const format = this.type && this.type.getFormat(this); - - if (format) { - return format.getConverterFor(contentType); - } - - return this.fieldOwnFormatter(contentType, defaultFormat); - } - - fieldOwnFormatter(contentType?: fieldFormats.ContentType, defaultFormat?: any) { - const fieldFormatsService = npStart.plugins.data.fieldFormats; - const field = this.getField(); - let format = field && field.format; - if (!format) format = defaultFormat; - if (!format) format = fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.STRING); - return format.getConverterFor(contentType); - } - - fieldName() { - const field = this.getField(); - return field ? field.name : ''; - } - - fieldIsTimeField() { - const indexPattern = this.getIndexPattern(); - if (!indexPattern) return false; - // @ts-ignore - const timeFieldName = indexPattern.timeFieldName; - return timeFieldName && this.fieldName() === timeFieldName; - } - - public get type() { - return this.__type; - } - - public set type(type) { - if (this.__typeDecorations) { - _.forOwn( - this.__typeDecorations, - function(prop, name: string | undefined) { - // @ts-ignore - delete this[name]; - }, - this - ); - } - - if (type && _.isFunction(type.decorateAggConfig)) { - this.__typeDecorations = type.decorateAggConfig(); - Object.defineProperties(this, this.__typeDecorations); - } - - this.__type = type; - let availableFields = []; - - const fieldParam = this.type && this.type.params.find((p: any) => p.type === 'field'); - - if (fieldParam) { - // @ts-ignore - availableFields = fieldParam.getAvailableFields(this.getIndexPattern().fields); - } - - // clear out the previous params except for a few special ones - this.setParams({ - // split row/columns is "outside" of the agg, so don't reset it - row: this.params.row, - - // almost every agg has fields, so we try to persist that when type changes - field: availableFields.find((field: any) => field.name === this.getField()), - }); - } - - public setType(type: string | AggType) { - this.type = typeof type === 'string' ? getTypeFromRegistry(type) : type; - } - - public get schema() { - return this.__schema; - } - - public set schema(schema) { - this.__schema = schema; - } - - public setSchema(schema: string | Schema) { - this.schema = - typeof schema === 'string' ? getSchemaFromRegistry(this.aggConfigs.schemas, schema) : schema; - } -} +export { AggConfig } from './index'; diff --git a/src/legacy/ui/public/agg_types/agg_configs.ts b/src/legacy/ui/public/agg_types/agg_configs.ts index 47e2222abe1e8..a04585dd82bdc 100644 --- a/src/legacy/ui/public/agg_types/agg_configs.ts +++ b/src/legacy/ui/public/agg_types/agg_configs.ts @@ -17,302 +17,4 @@ * under the License. */ -/** - * @name AggConfig - * - * @extends IndexedArray - * - * @description A "data structure"-like class with methods for indexing and - * accessing instances of AggConfig. - */ - -import _ from 'lodash'; -import { AggConfig, AggConfigOptions } from './agg_config'; -import { Schema } from './schemas'; -import { AggGroupNames } from './agg_groups'; -import { - IndexPattern, - ISearchSource, - FetchOptions, - TimeRange, -} from '../../../../plugins/data/public'; - -type Schemas = Record; - -function removeParentAggs(obj: any) { - for (const prop in obj) { - if (prop === 'parentAggs') delete obj[prop]; - else if (typeof obj[prop] === 'object') removeParentAggs(obj[prop]); - } -} - -function parseParentAggs(dslLvlCursor: any, dsl: any) { - if (dsl.parentAggs) { - _.each(dsl.parentAggs, (agg, key) => { - dslLvlCursor[key as string] = agg; - parseParentAggs(dslLvlCursor, agg); - }); - } -} - -export class AggConfigs { - public indexPattern: IndexPattern; - public schemas: any; - public timeRange?: TimeRange; - - aggs: AggConfig[]; - - constructor(indexPattern: IndexPattern, configStates = [] as any, schemas?: any) { - configStates = AggConfig.ensureIds(configStates); - - this.aggs = []; - this.indexPattern = indexPattern; - this.schemas = schemas; - - configStates.forEach((params: any) => this.createAggConfig(params)); - - if (this.schemas) { - this.initializeDefaultsFromSchemas(schemas); - } - } - - initializeDefaultsFromSchemas(schemas: Schemas) { - // Set the defaults for any schema which has them. If the defaults - // for some reason has more then the max only set the max number - // of defaults (not sure why a someone define more... - // but whatever). Also if a schema.name is already set then don't - // set anything. - _(schemas) - .filter((schema: Schema) => { - return Array.isArray(schema.defaults) && schema.defaults.length > 0; - }) - .each((schema: any) => { - if (!this.aggs.find((agg: AggConfig) => agg.schema && agg.schema.name === schema.name)) { - const defaults = schema.defaults.slice(0, schema.max); - _.each(defaults, defaultState => { - const state = _.defaults({ id: AggConfig.nextId(this.aggs) }, defaultState); - this.aggs.push(new AggConfig(this, state as AggConfigOptions)); - }); - } - }) - .commit(); - } - - setTimeRange(timeRange: TimeRange) { - this.timeRange = timeRange; - - const updateAggTimeRange = (agg: AggConfig) => { - _.each(agg.params, param => { - if (param instanceof AggConfig) { - updateAggTimeRange(param); - } - }); - if (_.get(agg, 'type.name') === 'date_histogram') { - agg.params.timeRange = timeRange; - } - }; - - this.aggs.forEach(updateAggTimeRange); - } - - // clone method will reuse existing AggConfig in the list (will not create new instances) - clone({ enabledOnly = true } = {}) { - const filterAggs = (agg: AggConfig) => { - if (!enabledOnly) return true; - return agg.enabled; - }; - const aggConfigs = new AggConfigs( - this.indexPattern, - this.aggs.filter(filterAggs), - this.schemas - ); - return aggConfigs; - } - - createAggConfig = ( - params: AggConfig | AggConfigOptions, - { addToAggConfigs = true } = {} - ) => { - let aggConfig; - if (params instanceof AggConfig) { - aggConfig = params; - params.parent = this; - } else { - aggConfig = new AggConfig(this, params); - } - if (addToAggConfigs) { - this.aggs.push(aggConfig); - } - return aggConfig as T; - }; - - /** - * Data-by-data comparison of this Aggregation - * Ignores the non-array indexes - * @param aggConfigs an AggConfigs instance - */ - jsonDataEquals(aggConfigs: AggConfig[]) { - if (aggConfigs.length !== this.aggs.length) { - return false; - } - for (let i = 0; i < this.aggs.length; i += 1) { - if (!_.isEqual(aggConfigs[i].toJSON(), this.aggs[i].toJSON())) { - return false; - } - } - return true; - } - - toDsl(hierarchical: boolean = false) { - const dslTopLvl = {}; - let dslLvlCursor: Record; - let nestedMetrics: Array<{ config: AggConfig; dsl: any }> | []; - - if (hierarchical) { - // collect all metrics, and filter out the ones that we won't be copying - nestedMetrics = this.aggs - .filter(function(agg) { - return agg.type.type === 'metrics' && agg.type.name !== 'count'; - }) - .map(agg => { - return { - config: agg, - dsl: agg.toDsl(this), - }; - }); - } - this.getRequestAggs() - .filter((config: AggConfig) => !config.type.hasNoDsl) - .forEach((config: AggConfig, i: number, list) => { - if (!dslLvlCursor) { - // start at the top level - dslLvlCursor = dslTopLvl; - } else { - const prevConfig: AggConfig = list[i - 1]; - const prevDsl = dslLvlCursor[prevConfig.id]; - - // advance the cursor and nest under the previous agg, or - // put it on the same level if the previous agg doesn't accept - // sub aggs - dslLvlCursor = prevDsl.aggs || dslLvlCursor; - } - - const dsl = (dslLvlCursor[config.id] = config.toDsl(this)); - let subAggs: any; - - parseParentAggs(dslLvlCursor, dsl); - - if (config.type.type === AggGroupNames.Buckets && i < list.length - 1) { - // buckets that are not the last item in the list accept sub-aggs - subAggs = dsl.aggs || (dsl.aggs = {}); - } - - if (subAggs && nestedMetrics) { - nestedMetrics.forEach((agg: any) => { - subAggs[agg.config.id] = agg.dsl; - // if a nested metric agg has parent aggs, we have to add them to every level of the tree - // to make sure "bucket_path" references in the nested metric agg itself are still working - if (agg.dsl.parentAggs) { - Object.entries(agg.dsl.parentAggs).forEach(([parentAggId, parentAgg]) => { - subAggs[parentAggId] = parentAgg; - }); - } - }); - } - }); - - removeParentAggs(dslTopLvl); - return dslTopLvl; - } - - getAll() { - return [...this.aggs]; - } - - byIndex(index: number) { - return this.aggs[index]; - } - - byId(id: string) { - return this.aggs.find(agg => agg.id === id); - } - - byName(name: string) { - return this.aggs.filter(agg => agg.type.name === name); - } - - byType(type: string) { - return this.aggs.filter(agg => agg.type.type === type); - } - - byTypeName(type: string) { - return this.aggs.filter(agg => agg.type.name === type); - } - - bySchemaName(schema: string) { - return this.aggs.filter(agg => agg.schema && agg.schema.name === schema); - } - - bySchemaGroup(group: string) { - return this.aggs.filter(agg => agg.schema && agg.schema.group === group); - } - - getRequestAggs(): AggConfig[] { - // collect all the aggregations - const aggregations = this.aggs - .filter(agg => agg.enabled && agg.type) - .reduce((requestValuesAggs, agg: AggConfig) => { - const aggs = agg.getRequestAggs(); - return aggs ? requestValuesAggs.concat(aggs) : requestValuesAggs; - }, [] as AggConfig[]); - // move metrics to the end - return _.sortBy(aggregations, (agg: AggConfig) => - agg.type.type === AggGroupNames.Metrics ? 1 : 0 - ); - } - - getRequestAggById(id: string) { - return this.aggs.find((agg: AggConfig) => agg.id === id); - } - - /** - * Gets the AggConfigs (and possibly ResponseAggConfigs) that - * represent the values that will be produced when all aggs - * are run. - * - * With multi-value metric aggs it is possible for a single agg - * request to result in multiple agg values, which is why the length - * of a vis' responseValuesAggs may be different than the vis' aggs - * - * @return {array[AggConfig]} - */ - getResponseAggs(): AggConfig[] { - return this.getRequestAggs().reduce(function(responseValuesAggs, agg: AggConfig) { - const aggs = agg.getResponseAggs(); - return aggs ? responseValuesAggs.concat(aggs) : responseValuesAggs; - }, [] as AggConfig[]); - } - - /** - * Find a response agg by it's id. This may be an agg in the aggConfigs, or one - * created specifically for a response value - * - * @param {string} id - the id of the agg to find - * @return {AggConfig} - */ - getResponseAggById(id: string): AggConfig | undefined { - id = String(id); - const reqAgg = _.find(this.getRequestAggs(), function(agg: AggConfig) { - return id.substr(0, String(agg.id).length) === agg.id; - }); - if (!reqAgg) return; - return _.find(reqAgg.getResponseAggs(), { id }); - } - - onSearchRequestStart(searchSource: ISearchSource, options?: FetchOptions) { - return Promise.all( - // @ts-ignore - this.getRequestAggs().map((agg: AggConfig) => agg.onSearchRequestStart(searchSource, options)) - ); - } -} +export { AggConfigs } from './index'; diff --git a/src/legacy/ui/public/agg_types/agg_groups.ts b/src/legacy/ui/public/agg_types/agg_groups.ts deleted file mode 100644 index d08e875bf213e..0000000000000 --- a/src/legacy/ui/public/agg_types/agg_groups.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { $Values } from '@kbn/utility-types'; - -export const AggGroupNames = Object.freeze({ - Buckets: 'buckets' as 'buckets', - Metrics: 'metrics' as 'metrics', - None: 'none' as 'none', -}); -export type AggGroupNames = $Values; - -export const aggGroupNamesMap = () => ({ - [AggGroupNames.Metrics]: i18n.translate('common.ui.aggTypes.aggGroups.metricsText', { - defaultMessage: 'Metrics', - }), - [AggGroupNames.Buckets]: i18n.translate('common.ui.aggTypes.aggGroups.bucketsText', { - defaultMessage: 'Buckets', - }), -}); diff --git a/src/legacy/ui/public/agg_types/agg_params.test.ts b/src/legacy/ui/public/agg_types/agg_params.test.ts deleted file mode 100644 index 25e62e06d52d7..0000000000000 --- a/src/legacy/ui/public/agg_types/agg_params.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { initParams } from './agg_params'; -import { BaseParamType } from './param_types/base'; -import { FieldParamType } from './param_types/field'; -import { OptionedParamType } from './param_types/optioned'; -import { AggParamType } from '../agg_types/param_types/agg'; - -jest.mock('ui/new_platform'); - -describe('AggParams class', () => { - describe('constructor args', () => { - it('accepts an array of param defs', () => { - const params = [{ name: 'one' }, { name: 'two' }] as AggParamType[]; - const aggParams = initParams(params); - - expect(aggParams).toHaveLength(params.length); - expect(Array.isArray(aggParams)).toBeTruthy(); - }); - }); - - describe('AggParam creation', () => { - it('Uses the FieldParamType class for params with the name "field"', () => { - const params = [{ name: 'field', type: 'field' }] as AggParamType[]; - const aggParams = initParams(params); - - expect(aggParams).toHaveLength(params.length); - expect(aggParams[0] instanceof FieldParamType).toBeTruthy(); - }); - - it('Uses the OptionedParamType class for params of type "optioned"', () => { - const params = [ - { - name: 'order', - type: 'optioned', - }, - ] as AggParamType[]; - const aggParams = initParams(params); - - expect(aggParams).toHaveLength(params.length); - expect(aggParams[0] instanceof OptionedParamType).toBeTruthy(); - }); - - it('Always converts the params to a BaseParamType', function() { - const params = [ - { - name: 'height', - displayName: 'height', - }, - { - name: 'weight', - displayName: 'weight', - }, - { - name: 'waist', - displayName: 'waist', - }, - ] as AggParamType[]; - - const aggParams = initParams(params); - - expect(aggParams).toHaveLength(params.length); - - aggParams.forEach(aggParam => expect(aggParam instanceof BaseParamType).toBeTruthy()); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/agg_params.ts b/src/legacy/ui/public/agg_types/agg_params.ts index 262a57f4a5aa3..d850be8039025 100644 --- a/src/legacy/ui/public/agg_types/agg_params.ts +++ b/src/legacy/ui/public/agg_types/agg_params.ts @@ -17,77 +17,4 @@ * under the License. */ -import { AggParamType } from './param_types/agg'; -import { FieldParamType } from './param_types/field'; -import { OptionedParamType } from './param_types/optioned'; -import { StringParamType } from './param_types/string'; -import { JsonParamType } from './param_types/json'; -import { BaseParamType } from './param_types/base'; - -import { AggConfig } from './agg_config'; -import { AggConfigs } from './agg_configs'; - -const paramTypeMap = { - field: FieldParamType, - optioned: OptionedParamType, - string: StringParamType, - json: JsonParamType, - agg: AggParamType, - _default: BaseParamType, -} as Record; - -export type AggParam = BaseParamType; - -export interface AggParamOption { - val: string; - display: string; - enabled?(agg: AggConfig): boolean; -} - -export const initParams = ( - params: TAggParam[] -): TAggParam[] => - params.map((config: TAggParam) => { - const Class = paramTypeMap[config.type] || paramTypeMap._default; - - return new Class(config); - }) as TAggParam[]; - -/** - * Reads an aggConfigs - * - * @method write - * @param {AggConfig} aggConfig - * the AggConfig object who's type owns these aggParams and contains the param values for our param defs - * @param {object} [locals] - * an array of locals that will be available to the write function (can be used to enhance - * the quality of things like date_histogram's "auto" interval) - * @return {object} output - * output of the write calls, reduced into a single object. A `params: {}` property is exposed on the - * output object which is used to create the agg dsl for the search request. All other properties - * are dependent on the AggParam#write methods which should be studied for each AggType. - */ -export const writeParams = < - TAggConfig extends AggConfig = AggConfig, - TAggParam extends AggParamType = AggParamType ->( - params: Array> = [], - aggConfig: TAggConfig, - aggs?: AggConfigs, - locals?: Record -) => { - const output = { params: {} as Record }; - locals = locals || {}; - - params.forEach(param => { - if (param.write) { - param.write(aggConfig, output, aggs, locals); - } else { - if (param && param.name) { - output.params[param.name] = aggConfig.params[param.name]; - } - } - }); - - return output; -}; +export { AggParam, AggParamOption } from './index'; diff --git a/src/legacy/ui/public/agg_types/agg_type.test.ts b/src/legacy/ui/public/agg_types/agg_type.test.ts deleted file mode 100644 index 9b34910e81e88..0000000000000 --- a/src/legacy/ui/public/agg_types/agg_type.test.ts +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { AggType, AggTypeConfig } from './agg_type'; -import { AggConfig } from './agg_config'; -import { npStart } from 'ui/new_platform'; - -jest.mock('ui/new_platform'); - -describe('AggType Class', () => { - describe('constructor', () => { - it("requires a valid config object as it's first param", () => { - expect(() => { - const aggConfig: AggTypeConfig = (undefined as unknown) as AggTypeConfig; - new AggType(aggConfig); - }).toThrowError(); - }); - - describe('application of config properties', () => { - it('assigns the config value to itself', () => { - const config: AggTypeConfig = { - name: 'name', - title: 'title', - }; - - const aggType = new AggType(config); - - expect(aggType.name).toBe('name'); - expect(aggType.title).toBe('title'); - }); - - describe('makeLabel', () => { - it('makes a function when the makeLabel config is not specified', () => { - const makeLabel = () => 'label'; - const aggConfig = {} as AggConfig; - const config: AggTypeConfig = { - name: 'name', - title: 'title', - makeLabel, - }; - - const aggType = new AggType(config); - - expect(aggType.makeLabel).toBe(makeLabel); - expect(aggType.makeLabel(aggConfig)).toBe('label'); - }); - }); - - describe('getResponseAggs/getRequestAggs', () => { - it('copies the value', () => { - const testConfig = (aggConfig: AggConfig) => [aggConfig]; - - const aggType = new AggType({ - name: 'name', - title: 'title', - getResponseAggs: testConfig, - getRequestAggs: testConfig, - }); - - expect(aggType.getResponseAggs).toBe(testConfig); - expect(aggType.getResponseAggs).toBe(testConfig); - }); - - it('defaults to noop', () => { - const aggConfig = {} as AggConfig; - const aggType = new AggType({ - name: 'name', - title: 'title', - }); - const responseAggs = aggType.getRequestAggs(aggConfig); - - expect(responseAggs).toBe(undefined); - }); - }); - - describe('params', () => { - it('defaults to AggParams object with JSON param', () => { - const aggType = new AggType({ - name: 'smart agg', - title: 'title', - }); - - expect(Array.isArray(aggType.params)).toBeTruthy(); - expect(aggType.params.length).toBe(2); - expect(aggType.params[0].name).toBe('json'); - expect(aggType.params[1].name).toBe('customLabel'); - }); - - it('can disable customLabel', () => { - const aggType = new AggType({ - name: 'smart agg', - title: 'title', - customLabels: false, - }); - - expect(aggType.params.length).toBe(1); - expect(aggType.params[0].name).toBe('json'); - }); - - it('passes the params arg directly to the AggParams constructor', () => { - const params = [{ name: 'one' }, { name: 'two' }]; - const paramLength = params.length + 2; // json and custom label are always appended - - const aggType = new AggType({ - name: 'bucketeer', - title: 'title', - params, - }); - - expect(Array.isArray(aggType.params)).toBeTruthy(); - expect(aggType.params.length).toBe(paramLength); - }); - }); - }); - - describe('getFormat', function() { - let aggConfig: AggConfig; - let field: any; - - beforeEach(() => { - aggConfig = ({ - getField: jest.fn(() => field), - } as unknown) as AggConfig; - }); - - it('returns the formatter for the aggConfig', () => { - const aggType = new AggType({ - name: 'name', - title: 'title', - }); - - field = { - format: 'format', - }; - - expect(aggType.getFormat(aggConfig)).toBe('format'); - }); - - it('returns default formatter', () => { - npStart.plugins.data.fieldFormats.getDefaultInstance = jest.fn(() => 'default') as any; - - const aggType = new AggType({ - name: 'name', - title: 'title', - }); - - field = undefined; - - expect(aggType.getFormat(aggConfig)).toBe('default'); - }); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/agg_type.ts b/src/legacy/ui/public/agg_types/agg_type.ts index 7ec688277b9c4..5a74495dd815b 100644 --- a/src/legacy/ui/public/agg_types/agg_type.ts +++ b/src/legacy/ui/public/agg_types/agg_type.ts @@ -17,244 +17,4 @@ * under the License. */ -import { constant, noop, identity } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { npStart } from 'ui/new_platform'; -import { initParams } from './agg_params'; - -import { AggConfig } from './agg_config'; -import { AggConfigs } from './agg_configs'; -import { Adapters } from '../../../../plugins/inspector/public'; -import { BaseParamType } from './param_types/base'; -import { AggParamType } from '../agg_types/param_types/agg'; -import { KBN_FIELD_TYPES, fieldFormats, ISearchSource } from '../../../../plugins/data/public'; - -export interface AggTypeConfig< - TAggConfig extends AggConfig = AggConfig, - TParam extends AggParamType = AggParamType -> { - name: string; - title: string; - createFilter?: (aggConfig: TAggConfig, key: any, params?: any) => any; - type?: string; - dslName?: string; - makeLabel?: ((aggConfig: TAggConfig) => string) | (() => string); - ordered?: any; - hasNoDsl?: boolean; - params?: Array>; - getRequestAggs?: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); - getResponseAggs?: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); - customLabels?: boolean; - decorateAggConfig?: () => any; - postFlightRequest?: ( - resp: any, - aggConfigs: AggConfigs, - aggConfig: TAggConfig, - searchSource: ISearchSource, - inspectorAdapters: Adapters, - abortSignal?: AbortSignal - ) => Promise; - getFormat?: (agg: TAggConfig) => fieldFormats.FieldFormat; - getValue?: (agg: TAggConfig, bucket: any) => any; - getKey?: (bucket: any, key: any, agg: TAggConfig) => any; -} - -const getFormat = (agg: AggConfig) => { - const field = agg.getField(); - const fieldFormatsService = npStart.plugins.data.fieldFormats; - - return field ? field.format : fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.STRING); -}; - -export class AggType< - TAggConfig extends AggConfig = AggConfig, - TParam extends AggParamType = AggParamType -> { - /** - * the unique, unchanging, name that we have assigned this aggType - * - * @property name - * @type {string} - */ - name: string; - - type: string; - subtype?: string; - /** - * the name of the elasticsearch aggregation that this aggType represents. Usually just this.name - * - * @property name - * @type {string} - */ - dslName: string; - /** - * the user friendly name that will be shown in the ui for this aggType - * - * @property title - * @type {string} - */ - title: string; - /** - * 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 describe the aggConfig - */ - makeLabel: ((aggConfig: TAggConfig) => string) | (() => string); - /** - * 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 "falsy". - * - * 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} - */ - ordered: any; - /** - * 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} - */ - hasNoDsl: boolean; - /** - * 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 - */ - createFilter: ((aggConfig: TAggConfig, key: any, params?: any) => any) | undefined; - /** - * An instance of {{#crossLink "AggParams"}}{{/crossLink}}. - * - * @property params - * @type {AggParams} - */ - params: TParam[]; - /** - * 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]} - an array of aggConfig objects - * that should replace this one, - * or undefined - */ - getRequestAggs: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); - /** - * 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 - */ - getResponseAggs: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); - /** - * 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 - */ - decorateAggConfig: () => any; - /** - * 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} - */ - postFlightRequest: ( - resp: any, - aggConfigs: AggConfigs, - aggConfig: TAggConfig, - searchSource: ISearchSource, - inspectorAdapters: Adapters, - abortSignal?: AbortSignal - ) => Promise; - /** - * Pick a format for the values produced by this agg type, - * overridden by several metrics that always output a simple - * number - * - * @param {agg} agg - the agg to pick a format for - * @return {FieldFormat} - */ - getFormat: (agg: TAggConfig) => fieldFormats.FieldFormat; - - getValue: (agg: TAggConfig, bucket: any) => any; - - getKey?: (bucket: any, key: any, agg: TAggConfig) => any; - - paramByName = (name: string) => { - return this.params.find((p: TParam) => p.name === name); - }; - - /** - * 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 - */ - constructor(config: AggTypeConfig) { - this.name = config.name; - this.type = config.type || 'metrics'; - this.dslName = config.dslName || config.name; - this.title = config.title; - this.makeLabel = config.makeLabel || constant(this.name); - this.ordered = config.ordered; - this.hasNoDsl = !!config.hasNoDsl; - - if (config.createFilter) { - this.createFilter = config.createFilter; - } - - if (config.params && config.params.length && config.params[0] instanceof BaseParamType) { - this.params = config.params as TParam[]; - } else { - // always append the raw JSON param - const params: any[] = config.params ? [...config.params] : []; - params.push({ - name: 'json', - type: 'json', - advanced: true, - }); - // always append custom label - - if (config.customLabels !== false) { - params.push({ - name: 'customLabel', - displayName: i18n.translate('common.ui.aggTypes.string.customLabel', { - defaultMessage: 'Custom label', - }), - type: 'string', - write: noop, - }); - } - - this.params = initParams(params); - } - - this.getRequestAggs = config.getRequestAggs || noop; - this.getResponseAggs = config.getResponseAggs || (() => {}); - this.decorateAggConfig = config.decorateAggConfig || (() => ({})); - this.postFlightRequest = config.postFlightRequest || identity; - this.getFormat = config.getFormat || getFormat; - this.getValue = config.getValue || ((agg: TAggConfig, bucket: any) => {}); - } -} +export { AggType } from './index'; diff --git a/src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts b/src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts deleted file mode 100644 index 9b7c97a8f11b6..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { AggConfig } from '../agg_config'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; -import { AggType, AggTypeConfig } from '../agg_type'; -import { AggParamType } from '../param_types/agg'; - -export interface IBucketAggConfig extends AggConfig { - type: InstanceType; -} - -export interface BucketAggParam - extends AggParamType { - scriptable?: boolean; - filterFieldTypes?: KBN_FIELD_TYPES | KBN_FIELD_TYPES[] | '*'; -} - -const bucketType = 'buckets'; - -interface BucketAggTypeConfig - extends AggTypeConfig> { - getKey?: (bucket: any, key: any, agg: AggConfig) => any; -} - -export class BucketAggType extends AggType< - TBucketAggConfig, - BucketAggParam -> { - getKey: (bucket: any, key: any, agg: TBucketAggConfig) => any; - type = bucketType; - - constructor(config: BucketAggTypeConfig) { - super(config); - - this.getKey = - config.getKey || - ((bucket, key) => { - return key || bucket.key; - }); - } -} - -export function isBucketAggType(aggConfig: any): aggConfig is BucketAggType { - return aggConfig && aggConfig.type === bucketType; -} diff --git a/src/legacy/ui/public/agg_types/buckets/_interval_options.ts b/src/legacy/ui/public/agg_types/buckets/_interval_options.ts index 01d0abb7a366c..d3838e280f873 100644 --- a/src/legacy/ui/public/agg_types/buckets/_interval_options.ts +++ b/src/legacy/ui/public/agg_types/buckets/_interval_options.ts @@ -16,67 +16,5 @@ * specific language governing permissions and limitations * under the License. */ -import { i18n } from '@kbn/i18n'; -import { IBucketAggConfig } from './_bucket_agg_type'; -export const intervalOptions = [ - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.autoDisplayName', { - defaultMessage: 'Auto', - }), - val: 'auto', - enabled(agg: IBucketAggConfig) { - // not only do we need a time field, but the selected field needs - // to be the time field. (see #3028) - return agg.fieldIsTimeField(); - }, - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.millisecondDisplayName', { - defaultMessage: 'Millisecond', - }), - val: 'ms', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.secondDisplayName', { - defaultMessage: 'Second', - }), - val: 's', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.minuteDisplayName', { - defaultMessage: 'Minute', - }), - val: 'm', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.hourlyDisplayName', { - defaultMessage: 'Hourly', - }), - val: 'h', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.dailyDisplayName', { - defaultMessage: 'Daily', - }), - val: 'd', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.weeklyDisplayName', { - defaultMessage: 'Weekly', - }), - val: 'w', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.monthlyDisplayName', { - defaultMessage: 'Monthly', - }), - val: 'M', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.yearlyDisplayName', { - defaultMessage: 'Yearly', - }), - val: 'y', - }, -]; +export { intervalOptions } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/_terms_other_bucket_helper.js b/src/legacy/ui/public/agg_types/buckets/_terms_other_bucket_helper.js deleted file mode 100644 index c8580183756f4..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/_terms_other_bucket_helper.js +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import _ from 'lodash'; -import { esFilters, esQuery } from '../../../../../plugins/data/public'; -import { AggGroupNames } from '../agg_groups'; - -/** - * walks the aggregation DSL and returns DSL starting at aggregation with id of startFromAggId - * @param aggNestedDsl: aggregation config DSL (top level) - * @param startFromId: id of an aggregation from where we want to get the nested DSL - */ -const getNestedAggDSL = (aggNestedDsl, startFromAggId) => { - if (aggNestedDsl[startFromAggId]) { - return aggNestedDsl[startFromAggId]; - } - const nestedAggs = _.values(aggNestedDsl); - let aggs; - for (let i = 0; i < nestedAggs.length; i++) { - if (nestedAggs[i].aggs && (aggs = getNestedAggDSL(nestedAggs[i].aggs, startFromAggId))) { - return aggs; - } - } -}; - -/** - * returns buckets from response for a specific other bucket - * @param aggConfigs: configuration for the aggregations - * @param response: response from elasticsearch - * @param aggWithOtherBucket: AggConfig of the aggregation with other bucket enabled - * @param key: key from the other bucket request for a specific other bucket - */ -const getAggResultBuckets = (aggConfigs, response, aggWithOtherBucket, key) => { - const keyParts = key.split('-'); - let responseAgg = response; - for (const i in keyParts) { - if (keyParts[i]) { - const responseAggs = _.values(responseAgg); - // If you have multi aggs, we cannot just assume the first one is the `other` bucket, - // so we need to loop over each agg until we find it. - for (let aggId = 0; aggId < responseAggs.length; aggId++) { - const agg = responseAggs[aggId]; - const aggKey = _.keys(responseAgg)[aggId]; - const aggConfig = _.find(aggConfigs.aggs, agg => agg.id === aggKey); - const bucket = _.find(agg.buckets, (bucket, bucketObjKey) => { - const bucketKey = aggConfig - .getKey(bucket, Number.isInteger(bucketObjKey) ? null : bucketObjKey) - .toString(); - return bucketKey === keyParts[i]; - }); - if (bucket) { - responseAgg = bucket; - break; - } - } - } - } - if (responseAgg[aggWithOtherBucket.id]) { - return responseAgg[aggWithOtherBucket.id].buckets; - } - return []; -}; - -/** - * gets all the missing buckets in our response for a specific aggregation id - * @param responseAggs: array of aggregations from response - * @param aggId: id of the aggregation with missing bucket - */ -const getAggConfigResultMissingBuckets = (responseAggs, aggId) => { - const missingKey = '__missing__'; - let resultBuckets = []; - if (responseAggs[aggId]) { - const matchingBucket = responseAggs[aggId].buckets.find(bucket => bucket.key === missingKey); - if (matchingBucket) resultBuckets.push(matchingBucket); - return resultBuckets; - } - _.each(responseAggs, agg => { - if (agg.buckets) { - _.each(agg.buckets, bucket => { - resultBuckets = [ - ...resultBuckets, - ...getAggConfigResultMissingBuckets(bucket, aggId, missingKey), - ]; - }); - } - }); - - return resultBuckets; -}; - -/** - * gets all the terms that are NOT in the other bucket - * @param requestAgg: an aggregation we are looking at - * @param key: the key for this specific other bucket - * @param otherAgg: AggConfig of the aggregation with other bucket - */ -const getOtherAggTerms = (requestAgg, key, otherAgg) => { - return requestAgg['other-filter'].filters.filters[key].bool.must_not - .filter(filter => filter.match_phrase && filter.match_phrase[otherAgg.params.field.name]) - .map(filter => filter.match_phrase[otherAgg.params.field.name]); -}; - -export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => { - const bucketAggs = aggConfigs.aggs.filter(agg => agg.type.type === AggGroupNames.Buckets); - const index = bucketAggs.findIndex(agg => agg.id === aggWithOtherBucket.id); - const aggs = aggConfigs.toDsl(); - const indexPattern = aggWithOtherBucket.params.field.indexPattern; - - // create filters aggregation - const filterAgg = aggConfigs.createAggConfig( - { - type: 'filters', - id: 'other', - params: { - filters: [], - }, - }, - { - addToAggConfigs: false, - } - ); - - // nest all the child aggregations of aggWithOtherBucket - const resultAgg = { - aggs: getNestedAggDSL(aggs, aggWithOtherBucket.id).aggs, - filters: filterAgg.toDsl(), - }; - - let noAggBucketResults = false; - - // recursively create filters for all parent aggregation buckets - const walkBucketTree = (aggIndex, aggs, aggId, filters, key) => { - // make sure there are actually results for the buckets - if (aggs[aggId].buckets.length < 1) { - noAggBucketResults = true; - return; - } - - 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.filters) || currentAgg.createFilter(bucketKey); - const newFilters = _.flatten([...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( - esFilters.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); - }); - - resultAgg.filters.filters[key] = { - bool: esQuery.buildQueryFromFilters(filters, indexPattern), - }; - }; - walkBucketTree(0, response.aggregations, bucketAggs[0].id, [], ''); - - // bail if there were no bucket results - if (noAggBucketResults) { - return false; - } - - return () => { - return { - 'other-filter': resultAgg, - }; - }; -}; - -export 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 = esFilters.buildPhrasesFilter( - otherAgg.params.field, - requestFilterTerms, - otherAgg.params.field.indexPattern - ); - phraseFilter.meta.negate = true; - bucket.filters = [phraseFilter]; - bucket.key = '__other__'; - - if (aggResultBuckets.some(bucket => bucket.key === '__missing__')) { - bucket.filters.push( - esFilters.buildExistsFilter(otherAgg.params.field, otherAgg.params.field.indexPattern) - ); - } - aggResultBuckets.push(bucket); - }); - return updatedResponse; -}; - -export const updateMissingBucket = (response, aggConfigs, agg) => { - const updatedResponse = _.cloneDeep(response); - const aggResultBuckets = getAggConfigResultMissingBuckets(updatedResponse.aggregations, agg.id); - aggResultBuckets.forEach(bucket => { - bucket.key = '__missing__'; - }); - return updatedResponse; -}; diff --git a/src/legacy/ui/public/agg_types/buckets/bucket_agg_types.ts b/src/legacy/ui/public/agg_types/buckets/bucket_agg_types.ts deleted file mode 100644 index a1321722cf294..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/bucket_agg_types.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export enum BUCKET_TYPES { - FILTER = 'filter', - FILTERS = 'filters', - HISTOGRAM = 'histogram', - IP_RANGE = 'ip_range', - DATE_RANGE = 'date_range', - RANGE = 'range', - TERMS = 'terms', - SIGNIFICANT_TERMS = 'significant_terms', - GEOHASH_GRID = 'geohash_grid', - GEOTILE_GRID = 'geotile_grid', - DATE_HISTOGRAM = 'date_histogram', -} diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.test.ts deleted file mode 100644 index 9426df7d34c29..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import moment from 'moment'; -import { createFilterDateHistogram } from './date_histogram'; -import { intervalOptions } from '../_interval_options'; -import { AggConfigs } from '../../agg_configs'; -import { IBucketDateHistogramAggConfig } from '../date_histogram'; -import { BUCKET_TYPES } from '../bucket_agg_types'; -import { esFilters } from '../../../../../../plugins/data/public'; - -jest.mock('ui/new_platform'); - -describe('AggConfig Filters', () => { - describe('date_histogram', () => { - let agg: IBucketDateHistogramAggConfig; - let filter: esFilters.RangeFilter; - let bucketStart: any; - let field: any; - - const init = (interval: string = 'auto', duration: any = moment.duration(15, 'minutes')) => { - field = { - name: 'date', - }; - - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - const aggConfigs = new AggConfigs( - indexPattern, - [ - { - type: BUCKET_TYPES.DATE_HISTOGRAM, - schema: 'segment', - params: { field: field.name, interval, customInterval: '5d' }, - }, - ], - null - ); - const bucketKey = 1422579600000; - - agg = aggConfigs.aggs[0] as IBucketDateHistogramAggConfig; - bucketStart = moment(bucketKey); - - const timePad = moment.duration(duration / 2); - - agg.buckets.setBounds({ - min: bucketStart.clone().subtract(timePad), - max: bucketStart.clone().add(timePad), - }); - agg.buckets.setInterval(interval); - filter = createFilterDateHistogram(agg, bucketKey); - }; - - it('creates a valid range filter', () => { - init(); - - expect(filter).toHaveProperty('range'); - expect(filter.range).toHaveProperty(field.name); - - const fieldParams = filter.range[field.name]; - expect(fieldParams).toHaveProperty('gte'); - expect(typeof fieldParams.gte).toBe('string'); - - expect(fieldParams).toHaveProperty('lt'); - expect(typeof fieldParams.lt).toBe('string'); - - expect(fieldParams).toHaveProperty('format'); - expect(fieldParams.format).toBe('strict_date_optional_time'); - - expect(filter).toHaveProperty('meta'); - expect(filter.meta).toHaveProperty('index', '1234'); - }); - - it('extends the filter edge to 1ms before the next bucket for all interval options', () => { - intervalOptions.forEach(option => { - let duration; - if (option.val !== 'custom' && moment(1, option.val).isValid()) { - // @ts-ignore - duration = moment.duration(10, option.val); - - if (+duration < 10) { - throw new Error('unable to create interval for ' + option.val); - } - } - init(option.val, duration); - - const interval = agg.buckets.getInterval(); - const params = filter.range[field.name]; - - expect(params.gte).toBe(bucketStart.toISOString()); - expect(params.lt).toBe( - bucketStart - .clone() - .add(interval) - .toISOString() - ); - }); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.ts deleted file mode 100644 index f91a92eab1c33..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import moment from 'moment'; -import { IBucketDateHistogramAggConfig } from '../date_histogram'; -import { esFilters } from '../../../../../../plugins/data/public'; - -export const createFilterDateHistogram = ( - agg: IBucketDateHistogramAggConfig, - key: string | number -) => { - const start = moment(key); - const interval = agg.buckets.getInterval(); - - return esFilters.buildRangeFilter( - agg.params.field, - { - gte: start.toISOString(), - lt: start.add(interval).toISOString(), - format: 'strict_date_optional_time', - }, - agg.getIndexPattern() - ); -}; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts deleted file mode 100644 index 9c2c4f72704f4..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import moment from 'moment'; -import { createFilterDateRange } from './date_range'; -import { fieldFormats } from '../../../../../../plugins/data/public'; -import { AggConfigs } from '../../agg_configs'; -import { BUCKET_TYPES } from '../bucket_agg_types'; -import { IBucketAggConfig } from '../_bucket_agg_type'; - -jest.mock('ui/new_platform'); - -describe('AggConfig Filters', () => { - describe('Date range', () => { - const getConfig = (() => {}) as fieldFormats.GetConfigFn; - const getAggConfigs = () => { - const field = { - name: '@timestamp', - format: new fieldFormats.DateFormat({}, getConfig), - }; - - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - return new AggConfigs( - indexPattern, - [ - { - type: BUCKET_TYPES.DATE_RANGE, - params: { - field: '@timestamp', - ranges: [{ from: '2014-01-01', to: '2014-12-31' }], - }, - }, - ], - null - ); - }; - - it('should return a range filter for date_range agg', () => { - const aggConfigs = getAggConfigs(); - const from = new Date('1 Feb 2015'); - const to = new Date('7 Feb 2015'); - const filter = createFilterDateRange(aggConfigs.aggs[0] as IBucketAggConfig, { - from: from.valueOf(), - to: to.valueOf(), - }); - - expect(filter).toHaveProperty('range'); - expect(filter).toHaveProperty('meta'); - expect(filter.meta).toHaveProperty('index', '1234'); - expect(filter.range).toHaveProperty('@timestamp'); - expect(filter.range['@timestamp']).toHaveProperty('gte', moment(from).toISOString()); - expect(filter.range['@timestamp']).toHaveProperty('lt', moment(to).toISOString()); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.ts deleted file mode 100644 index 01689d954a072..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import moment from 'moment'; -import { IBucketAggConfig } from '../_bucket_agg_type'; -import { DateRangeKey } from '../date_range'; -import { esFilters } from '../../../../../../plugins/data/public'; - -export const createFilterDateRange = (agg: IBucketAggConfig, { from, to }: DateRangeKey) => { - const filter: esFilters.RangeFilterParams = {}; - if (from) filter.gte = moment(from).toISOString(); - if (to) filter.lt = moment(to).toISOString(); - if (to && from) filter.format = 'strict_date_optional_time'; - - return esFilters.buildRangeFilter(agg.params.field, filter, agg.getIndexPattern()); -}; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/filters.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/filters.test.ts deleted file mode 100644 index 34cf996826865..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/filters.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { createFilterFilters } from './filters'; -import { AggConfigs } from '../../agg_configs'; -import { IBucketAggConfig } from '../_bucket_agg_type'; - -jest.mock('ui/new_platform'); - -describe('AggConfig Filters', () => { - describe('filters', () => { - const getAggConfigs = () => { - const field = { - name: 'bytes', - }; - - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - return new AggConfigs( - indexPattern, - [ - { - type: 'filters', - schema: 'segment', - params: { - filters: [ - { input: { query: 'type:apache', language: 'lucene' } }, - { input: { query: 'type:nginx', language: 'lucene' } }, - ], - }, - }, - ], - null - ); - }; - it('should return a filters filter', () => { - const aggConfigs = getAggConfigs(); - const filter = createFilterFilters(aggConfigs.aggs[0] as IBucketAggConfig, 'type:nginx'); - - expect(filter!.query.bool.must[0].query_string.query).toBe('type:nginx'); - expect(filter!.meta).toHaveProperty('index', '1234'); - expect(filter!.meta).toHaveProperty('alias', 'type:nginx'); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/filters.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/filters.ts deleted file mode 100644 index 6b614514580b6..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/filters.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { get } from 'lodash'; -import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; - -export const createFilterFilters = (aggConfig: IBucketAggConfig, key: string) => { - // have the aggConfig write agg dsl params - const dslFilters: any = get(aggConfig.toDsl(), 'filters.filters'); - const filter = dslFilters[key]; - const indexPattern = aggConfig.getIndexPattern(); - - if (filter && indexPattern && indexPattern.id) { - return esFilters.buildQueryFilter(filter.query, indexPattern.id, key); - } -}; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts deleted file mode 100644 index ef49636f9e0c1..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { createFilterHistogram } from './histogram'; -import { AggConfigs } from '../../agg_configs'; -import { BUCKET_TYPES } from '../bucket_agg_types'; -import { IBucketAggConfig } from '../_bucket_agg_type'; -import { fieldFormats } from '../../../../../../plugins/data/public'; - -jest.mock('ui/new_platform'); - -describe('AggConfig Filters', () => { - describe('histogram', () => { - const getConfig = (() => {}) as fieldFormats.GetConfigFn; - const getAggConfigs = () => { - const field = { - name: 'bytes', - format: new fieldFormats.BytesFormat({}, getConfig), - }; - - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - return new AggConfigs( - indexPattern, - [ - { - id: BUCKET_TYPES.HISTOGRAM, - type: BUCKET_TYPES.HISTOGRAM, - schema: 'buckets', - params: { - field: 'bytes', - interval: 1024, - }, - }, - ], - null - ); - }; - - it('should return an range filter for histogram', () => { - const aggConfigs = getAggConfigs(); - const filter = createFilterHistogram(aggConfigs.aggs[0] as IBucketAggConfig, '2048'); - - expect(filter).toHaveProperty('meta'); - expect(filter.meta).toHaveProperty('index', '1234'); - expect(filter).toHaveProperty('range'); - expect(filter.range).toHaveProperty('bytes'); - expect(filter.range.bytes).toHaveProperty('gte', 2048); - expect(filter.range.bytes).toHaveProperty('lt', 3072); - expect(filter.meta).toHaveProperty('formattedValue', '2,048'); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.ts deleted file mode 100644 index fc587fa9ecdb6..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; - -export const createFilterHistogram = (aggConfig: IBucketAggConfig, key: string) => { - const value = parseInt(key, 10); - const params: esFilters.RangeFilterParams = { gte: value, lt: value + aggConfig.params.interval }; - - return esFilters.buildRangeFilter( - aggConfig.params.field, - params, - aggConfig.getIndexPattern(), - aggConfig.fieldFormatter()(key) - ); -}; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts deleted file mode 100644 index a9eca3bbb7a56..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { createFilterIpRange } from './ip_range'; -import { AggConfigs } from '../../agg_configs'; -import { fieldFormats } from '../../../../../../plugins/data/public'; -import { BUCKET_TYPES } from '../bucket_agg_types'; -import { IBucketAggConfig } from '../_bucket_agg_type'; - -jest.mock('ui/new_platform'); - -describe('AggConfig Filters', () => { - describe('IP range', () => { - const getAggConfigs = (aggs: Array>) => { - const field = { - name: 'ip', - format: fieldFormats.IpFormat, - }; - - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - return new AggConfigs(indexPattern, aggs, null); - }; - - it('should return a range filter for ip_range agg', () => { - const aggConfigs = getAggConfigs([ - { - type: BUCKET_TYPES.IP_RANGE, - schema: 'segment', - params: { - field: 'ip', - ipRangeType: 'range', - ranges: { - fromTo: [{ from: '0.0.0.0', to: '1.1.1.1' }], - }, - }, - }, - ]); - - const filter = createFilterIpRange(aggConfigs.aggs[0] as IBucketAggConfig, { - type: 'range', - from: '0.0.0.0', - to: '1.1.1.1', - }); - - expect(filter).toHaveProperty('range'); - expect(filter).toHaveProperty('meta'); - expect(filter.meta).toHaveProperty('index', '1234'); - expect(filter.range).toHaveProperty('ip'); - expect(filter.range.ip).toHaveProperty('gte', '0.0.0.0'); - expect(filter.range.ip).toHaveProperty('lte', '1.1.1.1'); - }); - - it('should return a range filter for ip_range agg using a CIDR mask', () => { - const aggConfigs = getAggConfigs([ - { - type: BUCKET_TYPES.IP_RANGE, - schema: 'segment', - params: { - field: 'ip', - ipRangeType: 'mask', - ranges: { - mask: [{ mask: '67.129.65.201/27' }], - }, - }, - }, - ]); - - const filter = createFilterIpRange(aggConfigs.aggs[0] as IBucketAggConfig, { - type: 'mask', - mask: '67.129.65.201/27', - }); - - expect(filter).toHaveProperty('range'); - expect(filter).toHaveProperty('meta'); - expect(filter.meta).toHaveProperty('index', '1234'); - expect(filter.range).toHaveProperty('ip'); - expect(filter.range.ip).toHaveProperty('gte', '67.129.65.192'); - expect(filter.range.ip).toHaveProperty('lte', '67.129.65.223'); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts deleted file mode 100644 index a513b8c782739..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { CidrMask } from '../lib/cidr_mask'; -import { IBucketAggConfig } from '../_bucket_agg_type'; -import { IpRangeKey } from '../ip_range'; -import { esFilters } from '../../../../../../plugins/data/public'; - -export const createFilterIpRange = (aggConfig: IBucketAggConfig, key: IpRangeKey) => { - let range: esFilters.RangeFilterParams; - - if (key.type === 'mask') { - range = new CidrMask(key.mask).getRange(); - } else { - range = { - from: key.from ? key.from : -Infinity, - to: key.to ? key.to : Infinity, - }; - } - - return esFilters.buildRangeFilter( - aggConfig.params.field, - { gte: range.from, lte: range.to }, - aggConfig.getIndexPattern() - ); -}; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts deleted file mode 100644 index 720e952c28821..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { createFilterRange } from './range'; -import { fieldFormats } from '../../../../../../plugins/data/public'; -import { AggConfigs } from '../../agg_configs'; -import { BUCKET_TYPES } from '../bucket_agg_types'; -import { IBucketAggConfig } from '../_bucket_agg_type'; - -jest.mock('ui/new_platform'); - -describe('AggConfig Filters', () => { - describe('range', () => { - const getConfig = (() => {}) as fieldFormats.GetConfigFn; - const getAggConfigs = () => { - const field = { - name: 'bytes', - format: new fieldFormats.BytesFormat({}, getConfig), - }; - - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - return new AggConfigs( - indexPattern, - [ - { - id: BUCKET_TYPES.RANGE, - type: BUCKET_TYPES.RANGE, - schema: 'buckets', - params: { - field: 'bytes', - ranges: [{ from: 1024, to: 2048 }], - }, - }, - ], - null - ); - }; - - it('should return a range filter for range agg', () => { - const aggConfigs = getAggConfigs(); - const filter = createFilterRange(aggConfigs.aggs[0] as IBucketAggConfig, { - gte: 1024, - lt: 2048.0, - }); - - expect(filter).toHaveProperty('range'); - expect(filter).toHaveProperty('meta'); - expect(filter.meta).toHaveProperty('index', '1234'); - expect(filter.range).toHaveProperty('bytes'); - expect(filter.range.bytes).toHaveProperty('gte', 1024.0); - expect(filter.range.bytes).toHaveProperty('lt', 2048.0); - expect(filter.meta).toHaveProperty('formattedValue', '≥ 1,024 and < 2,048'); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/range.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/range.ts deleted file mode 100644 index 929827c6e3fec..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/range.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; - -export const createFilterRange = (aggConfig: IBucketAggConfig, params: any) => { - return esFilters.buildRangeFilter( - aggConfig.params.field, - params, - aggConfig.getIndexPattern(), - aggConfig.fieldFormatter()(params) - ); -}; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts deleted file mode 100644 index 86c0aa24f529a..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { createFilterTerms } from './terms'; -import { AggConfigs } from '../../agg_configs'; -import { BUCKET_TYPES } from '../bucket_agg_types'; -import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; - -jest.mock('ui/new_platform'); - -describe('AggConfig Filters', () => { - describe('terms', () => { - const getAggConfigs = (aggs: Array>) => { - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - const field = { - name: 'field', - indexPattern, - }; - - return new AggConfigs(indexPattern, aggs, null); - }; - - it('should return a match_phrase filter for terms', () => { - const aggConfigs = getAggConfigs([ - { type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } }, - ]); - - const filter = createFilterTerms( - aggConfigs.aggs[0] as IBucketAggConfig, - 'apache', - {} - ) as esFilters.Filter; - - expect(filter).toHaveProperty('query'); - expect(filter.query).toHaveProperty('match_phrase'); - expect(filter.query.match_phrase).toHaveProperty('field'); - expect(filter.query.match_phrase.field).toBe('apache'); - expect(filter).toHaveProperty('meta'); - expect(filter.meta).toHaveProperty('index', '1234'); - }); - - it('should set query to true or false for boolean filter', () => { - const aggConfigs = getAggConfigs([ - { type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } }, - ]); - - const filterFalse = createFilterTerms( - aggConfigs.aggs[0] as IBucketAggConfig, - '', - {} - ) as esFilters.Filter; - - expect(filterFalse).toHaveProperty('query'); - expect(filterFalse.query).toHaveProperty('match_phrase'); - expect(filterFalse.query.match_phrase).toHaveProperty('field'); - expect(filterFalse.query.match_phrase.field).toBeFalsy(); - - const filterTrue = createFilterTerms( - aggConfigs.aggs[0] as IBucketAggConfig, - '1', - {} - ) as esFilters.Filter; - - expect(filterTrue).toHaveProperty('query'); - expect(filterTrue.query).toHaveProperty('match_phrase'); - expect(filterTrue.query.match_phrase).toHaveProperty('field'); - expect(filterTrue.query.match_phrase.field).toBeTruthy(); - }); - - it('should generate correct __missing__ filter', () => { - const aggConfigs = getAggConfigs([ - { type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } }, - ]); - const filter = createFilterTerms( - aggConfigs.aggs[0] as IBucketAggConfig, - '__missing__', - {} - ) as esFilters.ExistsFilter; - - expect(filter).toHaveProperty('exists'); - expect(filter.exists).toHaveProperty('field', 'field'); - expect(filter).toHaveProperty('meta'); - expect(filter.meta).toHaveProperty('index', '1234'); - expect(filter.meta).toHaveProperty('negate', true); - }); - - it('should generate correct __other__ filter', () => { - const aggConfigs = getAggConfigs([ - { type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } }, - ]); - - const [filter] = createFilterTerms(aggConfigs.aggs[0] as IBucketAggConfig, '__other__', { - terms: ['apache'], - }) as esFilters.Filter[]; - - expect(filter).toHaveProperty('query'); - expect(filter.query).toHaveProperty('bool'); - expect(filter.query.bool).toHaveProperty('should'); - expect(filter.query.bool.should[0]).toHaveProperty('match_phrase'); - expect(filter.query.bool.should[0].match_phrase).toHaveProperty('field', 'apache'); - expect(filter).toHaveProperty('meta'); - expect(filter.meta).toHaveProperty('index', '1234'); - expect(filter.meta).toHaveProperty('negate', true); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/terms.ts deleted file mode 100644 index 5bd770e672786..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; - -export const createFilterTerms = (aggConfig: IBucketAggConfig, key: string, params: any) => { - const field = aggConfig.params.field; - const indexPattern = field.indexPattern; - - if (key === '__other__') { - const terms = params.terms; - - const phraseFilter = esFilters.buildPhrasesFilter(field, terms, indexPattern); - phraseFilter.meta.negate = true; - - const filters: esFilters.Filter[] = [phraseFilter]; - - if (terms.some((term: string) => term === '__missing__')) { - filters.push(esFilters.buildExistsFilter(field, indexPattern)); - } - - return filters; - } else if (key === '__missing__') { - const existsFilter = esFilters.buildExistsFilter(field, indexPattern); - existsFilter.meta.negate = true; - return existsFilter; - } - return esFilters.buildPhraseFilter(field, key, indexPattern); -}; diff --git a/src/legacy/ui/public/agg_types/buckets/date_histogram.ts b/src/legacy/ui/public/agg_types/buckets/date_histogram.ts index 33672b54b1f2e..35b14f620bdae 100644 --- a/src/legacy/ui/public/agg_types/buckets/date_histogram.ts +++ b/src/legacy/ui/public/agg_types/buckets/date_histogram.ts @@ -17,251 +17,4 @@ * under the License. */ -import _ from 'lodash'; -import moment from 'moment-timezone'; -import { i18n } from '@kbn/i18n'; - -import { npStart } from 'ui/new_platform'; -import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; -import { BUCKET_TYPES } from './bucket_agg_types'; -import { createFilterDateHistogram } from './create_filter/date_histogram'; -import { intervalOptions } from './_interval_options'; -import { timefilter } from '../../timefilter'; -import { dateHistogramInterval } from '../../../../core_plugins/data/public'; -import { writeParams } from '../agg_params'; -import { isMetricAggType } from '../metrics/metric_agg_type'; - -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -// @ts-ignore -import { TimeBuckets } from '../../time_buckets'; - -const detectedTimezone = moment.tz.guess(); -const tzOffset = moment().format('Z'); - -const getInterval = (agg: IBucketAggConfig): string => _.get(agg, ['params', 'interval']); - -export const setBounds = (agg: IBucketDateHistogramAggConfig, force?: boolean) => { - if (agg.buckets._alreadySet && !force) return; - agg.buckets._alreadySet = true; - const bounds = agg.params.timeRange ? timefilter.calculateBounds(agg.params.timeRange) : null; - agg.buckets.setBounds(agg.fieldIsTimeField() && bounds); -}; - -// will be replaced by src/legacy/ui/public/time_buckets/time_buckets.js -interface TimeBuckets { - _alreadySet?: boolean; - setBounds: Function; - getScaledDateFormatter: Function; - setInterval: Function; - getInterval: Function; -} - -export interface IBucketDateHistogramAggConfig extends IBucketAggConfig { - buckets: TimeBuckets; -} - -export function isDateHistogramBucketAggConfig(agg: any): agg is IBucketDateHistogramAggConfig { - return Boolean(agg.buckets); -} - -export const dateHistogramBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.DATE_HISTOGRAM, - title: i18n.translate('common.ui.aggTypes.buckets.dateHistogramTitle', { - defaultMessage: 'Date Histogram', - }), - ordered: { - date: true, - }, - makeLabel(agg) { - let output: Record = {}; - - if (this.params) { - output = writeParams(this.params, agg); - } - - const field = agg.getFieldDisplayName(); - return i18n.translate('common.ui.aggTypes.buckets.dateHistogramLabel', { - defaultMessage: '{fieldName} per {intervalDescription}', - values: { - fieldName: field, - intervalDescription: output.metricScaleText || output.bucketInterval.description, - }, - }); - }, - createFilter: createFilterDateHistogram, - decorateAggConfig() { - let buckets: any; - return { - buckets: { - configurable: true, - get() { - if (buckets) return buckets; - - buckets = new TimeBuckets(); - buckets.setInterval(getInterval(this)); - setBounds(this); - - return buckets; - }, - } as any, - }; - }, - getFormat(agg) { - return agg.buckets.getScaledDateFormatter(); - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.DATE, - default(agg: IBucketDateHistogramAggConfig) { - return agg.getIndexPattern().timeFieldName; - }, - onChange(agg: IBucketDateHistogramAggConfig) { - if (_.get(agg, 'params.interval') === 'auto' && !agg.fieldIsTimeField()) { - delete agg.params.interval; - } - - setBounds(agg, true); - }, - }, - { - name: 'timeRange', - default: null, - write: _.noop, - }, - { - name: 'useNormalizedEsInterval', - default: true, - write: _.noop, - }, - { - name: 'scaleMetricValues', - default: false, - write: _.noop, - advanced: true, - }, - { - name: 'interval', - deserialize(state: any, agg) { - // For upgrading from 7.0.x to 7.1.x - intervals are now stored as key of options or custom value - if (state === 'custom') { - return _.get(agg, 'params.customInterval'); - } - - const interval = _.find(intervalOptions, { val: state }); - - // 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 - if (!interval && state === 'year') { - return 'y'; - } - return state; - }, - default: 'auto', - options: intervalOptions, - modifyAggConfigOnSearchRequestStart(agg: IBucketDateHistogramAggConfig) { - setBounds(agg, true); - }, - write(agg, output, aggs) { - setBounds(agg, true); - agg.buckets.setInterval(getInterval(agg)); - const { useNormalizedEsInterval, scaleMetricValues } = agg.params; - const interval = agg.buckets.getInterval(useNormalizedEsInterval); - output.bucketInterval = interval; - if (interval.expression === '0ms') { - // We are hitting this code a couple of times while configuring in editor - // with an interval of 0ms because the overall time range has not yet been - // set. Since 0ms is not a valid ES interval, we cannot pass it through dateHistogramInterval - // below, since it would throw an exception. So in the cases we still have an interval of 0ms - // here we simply skip the rest of the method and never write an interval into the DSL, since - // this DSL will anyway not be used before we're passing this code with an actual interval. - return; - } - output.params = { - ...output.params, - ...dateHistogramInterval(interval.expression), - }; - - const scaleMetrics = scaleMetricValues && interval.scaled && interval.scale < 1; - if (scaleMetrics && aggs) { - const metrics = aggs.aggs.filter(a => isMetricAggType(a.type)); - const all = _.every(metrics, (a: IBucketAggConfig) => { - const { type } = a; - - if (isMetricAggType(type)) { - return type.isScalable(); - } - }); - if (all) { - output.metricScale = interval.scale; - output.metricScaleText = interval.preScaled.description; - } - } - }, - }, - { - name: 'time_zone', - default: undefined, - // We don't ever want this parameter to be serialized out (when saving or to URLs) - // since we do all the logic handling it "on the fly" in the `write` method, to prevent - // time_zones being persisted into saved_objects - serialize: _.noop, - write(agg, output) { - // If a time_zone has been set explicitly always prefer this. - let tz = agg.params.time_zone; - if (!tz && agg.params.field) { - // If a field has been configured check the index pattern's typeMeta if a date_histogram on that - // field requires a specific time_zone - tz = _.get(agg.getIndexPattern(), [ - 'typeMeta', - 'aggs', - 'date_histogram', - agg.params.field.name, - 'time_zone', - ]); - } - if (!tz) { - const config = npStart.core.uiSettings; - // If the index pattern typeMeta data, didn't had a time zone assigned for the selected field use the configured tz - const isDefaultTimezone = config.isDefault('dateFormat:tz'); - tz = isDefaultTimezone ? detectedTimezone || tzOffset : config.get('dateFormat:tz'); - } - output.params.time_zone = tz; - }, - }, - { - name: 'drop_partials', - default: false, - write: _.noop, - shouldShow: agg => { - const field = agg.params.field; - return field && field.name && field.name === agg.getIndexPattern().timeFieldName; - }, - }, - { - name: 'format', - }, - { - name: 'min_doc_count', - default: 1, - }, - { - name: 'extended_bounds', - default: {}, - write(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; - } - }, - }, - ], -}); +export { isDateHistogramBucketAggConfig, setBounds } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/date_range.test.ts b/src/legacy/ui/public/agg_types/buckets/date_range.test.ts deleted file mode 100644 index e34cb4e36720f..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/date_range.test.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { AggConfigs } from '../agg_configs'; -import { BUCKET_TYPES } from './bucket_agg_types'; -import { npStart } from 'ui/new_platform'; - -jest.mock('ui/new_platform'); - -describe('date_range params', () => { - const getAggConfigs = (params: Record = {}, hasIncludeTypeMeta: boolean = true) => { - const field = { - name: 'bytes', - }; - - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - typeMeta: hasIncludeTypeMeta - ? { - aggs: { - date_range: { - bytes: { - time_zone: 'defaultTimeZone', - }, - }, - }, - } - : undefined, - } as any; - - return new AggConfigs( - indexPattern, - [ - { - id: BUCKET_TYPES.DATE_RANGE, - type: BUCKET_TYPES.DATE_RANGE, - schema: 'buckets', - params, - }, - ], - null - ); - }; - - describe('getKey', () => { - it('should return object', () => { - const aggConfigs = getAggConfigs(); - const dateRange = aggConfigs.aggs[0]; - const bucket = { from: 'from-date', to: 'to-date', key: 'from-dateto-date' }; - - expect(dateRange.getKey(bucket)).toEqual({ from: 'from-date', to: 'to-date' }); - }); - }); - - describe('time_zone', () => { - it('should use the specified time_zone', () => { - const aggConfigs = getAggConfigs({ - time_zone: 'Europe/Minsk', - field: 'bytes', - }); - const dateRange = aggConfigs.aggs[0]; - const params = dateRange.toDsl()[BUCKET_TYPES.DATE_RANGE]; - - expect(params.time_zone).toBe('Europe/Minsk'); - }); - - it('should use the fixed time_zone from the index pattern typeMeta', () => { - const aggConfigs = getAggConfigs({ - field: 'bytes', - }); - const dateRange = aggConfigs.aggs[0]; - const params = dateRange.toDsl()[BUCKET_TYPES.DATE_RANGE]; - - expect(params.time_zone).toBe('defaultTimeZone'); - }); - - it('should use the Kibana time_zone if no parameter specified', () => { - npStart.core.uiSettings.get = jest.fn(() => 'kibanaTimeZone' as any); - - const aggConfigs = getAggConfigs( - { - field: 'bytes', - }, - false - ); - const dateRange = aggConfigs.aggs[0]; - const params = dateRange.toDsl()[BUCKET_TYPES.DATE_RANGE]; - - expect(params.time_zone).toBe('kibanaTimeZone'); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/date_range.ts b/src/legacy/ui/public/agg_types/buckets/date_range.ts index ee04e0657f317..34eae58375a06 100644 --- a/src/legacy/ui/public/agg_types/buckets/date_range.ts +++ b/src/legacy/ui/public/agg_types/buckets/date_range.ts @@ -16,106 +16,5 @@ * specific language governing permissions and limitations * under the License. */ -import { get } from 'lodash'; -import moment from 'moment-timezone'; -import { i18n } from '@kbn/i18n'; -import { npStart } from 'ui/new_platform'; -import { BUCKET_TYPES } from './bucket_agg_types'; -import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; -import { createFilterDateRange } from './create_filter/date_range'; -import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../plugins/data/public'; - -const dateRangeTitle = i18n.translate('common.ui.aggTypes.buckets.dateRangeTitle', { - defaultMessage: 'Date Range', -}); - -export interface DateRangeKey { - from: number; - to: number; -} - -export const dateRangeBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.DATE_RANGE, - title: dateRangeTitle, - createFilter: createFilterDateRange, - getKey({ from, to }): DateRangeKey { - return { from, to }; - }, - getFormat(agg) { - const fieldFormatsService = npStart.plugins.data.fieldFormats; - - const formatter = agg.fieldOwnFormatter( - fieldFormats.TEXT_CONTEXT_TYPE, - fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.DATE) - ); - const DateRangeFormat = fieldFormats.FieldFormat.from(function(range: DateRangeKey) { - return convertDateRangeToString(range, formatter); - }); - return new DateRangeFormat(); - }, - makeLabel(aggConfig) { - return aggConfig.getFieldDisplayName() + ' date ranges'; - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.DATE, - default(agg: IBucketAggConfig) { - return agg.getIndexPattern().timeFieldName; - }, - }, - { - name: 'ranges', - default: [ - { - from: 'now-1w/w', - to: 'now', - }, - ], - }, - { - name: 'time_zone', - default: undefined, - // Implimentation method is the same as that of date_histogram - serialize: () => undefined, - write: (agg, output) => { - const field = agg.getParam('field'); - let tz = agg.getParam('time_zone'); - - if (!tz && field) { - tz = get(agg.getIndexPattern(), [ - 'typeMeta', - 'aggs', - 'date_range', - field.name, - 'time_zone', - ]); - } - if (!tz) { - const config = npStart.core.uiSettings; - const detectedTimezone = moment.tz.guess(); - const tzOffset = moment().format('Z'); - const isDefaultTimezone = config.isDefault('dateFormat:tz'); - - tz = isDefaultTimezone ? detectedTimezone || tzOffset : config.get('dateFormat:tz'); - } - output.params.time_zone = tz; - }, - }, - ], -}); - -export const convertDateRangeToString = ( - { from, to }: DateRangeKey, - format: (val: any) => string -) => { - if (!from) { - return 'Before ' + format(to); - } else if (!to) { - return 'After ' + format(from); - } else { - return format(from) + ' to ' + format(to); - } -}; +export { DateRangeKey, convertDateRangeToString } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/filter.ts b/src/legacy/ui/public/agg_types/buckets/filter.ts deleted file mode 100644 index 3f8a898f4c963..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/filter.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { i18n } from '@kbn/i18n'; -import { BucketAggType } from './_bucket_agg_type'; -import { BUCKET_TYPES } from './bucket_agg_types'; - -const filterTitle = i18n.translate('common.ui.aggTypes.buckets.filterTitle', { - defaultMessage: 'Filter', -}); - -export const filterBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.FILTER, - title: filterTitle, - params: [ - { - name: 'geo_bounding_box', - }, - ], -}); diff --git a/src/legacy/ui/public/agg_types/buckets/filters.ts b/src/legacy/ui/public/agg_types/buckets/filters.ts deleted file mode 100644 index d9b78b3063e23..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/filters.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import _ from 'lodash'; -import angular from 'angular'; - -import { i18n } from '@kbn/i18n'; - -import chrome from 'ui/chrome'; -import { createFilterFilters } from './create_filter/filters'; -import { BucketAggType } from './_bucket_agg_type'; -import { Storage } from '../../../../../plugins/kibana_utils/public'; -import { getQueryLog, esQuery, Query } from '../../../../../plugins/data/public'; -import { BUCKET_TYPES } from './bucket_agg_types'; - -const config = chrome.getUiSettingsClient(); -const storage = new Storage(window.localStorage); - -const filtersTitle = i18n.translate('common.ui.aggTypes.buckets.filtersTitle', { - defaultMessage: 'Filters', - description: - 'The name of an aggregation, that allows to specify multiple individual filters to group data by.', -}); - -interface FilterValue { - input: Query; - label: string; - id: string; -} - -export const filtersBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.FILTERS, - title: filtersTitle, - createFilter: createFilterFilters, - customLabels: false, - params: [ - { - name: 'filters', - default: [{ input: { query: '', language: config.get('search:queryLanguage') }, label: '' }], - write(aggConfig, output) { - const inFilters: FilterValue[] = aggConfig.params.filters; - if (!_.size(inFilters)) return; - - inFilters.forEach(filter => { - const persistedLog = getQueryLog( - config, - storage, - 'vis_default_editor', - filter.input.language - ); - persistedLog.add(filter.input.query); - }); - - const outFilters = _.transform( - inFilters, - function(filters, filter) { - const input = _.cloneDeep(filter.input); - - if (!input) { - console.log('malformed filter agg params, missing "input" query'); // eslint-disable-line no-console - return; - } - - const query = esQuery.buildEsQuery(aggConfig.getIndexPattern(), [input], [], config); - - if (!query) { - console.log('malformed filter agg params, missing "query" on input'); // eslint-disable-line no-console - return; - } - - const matchAllLabel = filter.input.query === '' ? '*' : ''; - const label = - filter.label || - matchAllLabel || - (typeof filter.input.query === 'string' - ? filter.input.query - : angular.toJson(filter.input.query)); - filters[label] = { query }; - }, - {} - ); - - if (!_.size(outFilters)) return; - - const params = output.params || (output.params = {}); - params.filters = outFilters; - }, - }, - ], -}); diff --git a/src/legacy/ui/public/agg_types/buckets/geo_hash.test.ts b/src/legacy/ui/public/agg_types/buckets/geo_hash.test.ts deleted file mode 100644 index effa49f0ade6b..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/geo_hash.test.ts +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { geoHashBucketAgg, IBucketGeoHashGridAggConfig } from './geo_hash'; -import { AggConfigs } from '../agg_configs'; -import { BUCKET_TYPES } from './bucket_agg_types'; - -jest.mock('ui/new_platform'); - -describe('Geohash Agg', () => { - const getAggConfigs = (params?: Record) => { - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - const field = { - name: 'location', - indexPattern, - }; - - return new AggConfigs( - indexPattern, - [ - { - id: BUCKET_TYPES.GEOHASH_GRID, - type: BUCKET_TYPES.GEOHASH_GRID, - schema: 'segment', - params: { - field: { - name: 'location', - }, - isFilteredByCollar: true, - useGeocentroid: true, - mapZoom: 10, - mapBounds: { - top_left: { lat: 1.0, lon: -1.0 }, - bottom_right: { lat: -1.0, lon: 1.0 }, - }, - ...params, - }, - }, - ], - null - ); - }; - - describe('precision parameter', () => { - const PRECISION_PARAM_INDEX = 2; - - let precisionParam: any; - - beforeEach(() => { - precisionParam = geoHashBucketAgg.params[PRECISION_PARAM_INDEX]; - }); - - it('should select precision parameter', () => { - expect(precisionParam.name).toEqual('precision'); - }); - - describe('precision parameter write', () => { - const zoomToGeoHashPrecision: Record = { - 0: 1, - 1: 2, - 2: 2, - 3: 2, - 4: 3, - 5: 3, - 6: 4, - 7: 4, - 8: 4, - 9: 5, - 10: 5, - 11: 6, - 12: 6, - 13: 6, - 14: 7, - 15: 7, - 16: 8, - 17: 8, - 18: 8, - 19: 9, - 20: 9, - 21: 10, - }; - - Object.keys(zoomToGeoHashPrecision).forEach((zoomLevel: string) => { - it(`zoom level ${zoomLevel} should correspond to correct geohash-precision`, () => { - const aggConfigs = getAggConfigs({ - autoPrecision: true, - mapZoom: zoomLevel, - }); - - const { [BUCKET_TYPES.GEOHASH_GRID]: params } = aggConfigs.aggs[0].toDsl(); - - expect(params.precision).toEqual(zoomToGeoHashPrecision[zoomLevel]); - }); - }); - }); - }); - - describe('getRequestAggs', () => { - describe('initial aggregation creation', () => { - let aggConfigs: AggConfigs; - let geoHashGridAgg: IBucketGeoHashGridAggConfig; - - beforeEach(() => { - aggConfigs = getAggConfigs(); - geoHashGridAgg = aggConfigs.aggs[0] as IBucketGeoHashGridAggConfig; - }); - - it('should create filter, geohash_grid, and geo_centroid aggregations', () => { - const requestAggs = geoHashBucketAgg.getRequestAggs( - geoHashGridAgg - ) as IBucketGeoHashGridAggConfig[]; - - expect(requestAggs.length).toEqual(3); - expect(requestAggs[0].type.name).toEqual('filter'); - expect(requestAggs[1].type.name).toEqual('geohash_grid'); - expect(requestAggs[2].type.name).toEqual('geo_centroid'); - }); - - it('should set mapCollar in vis session state', () => { - const [, geoHashAgg] = geoHashBucketAgg.getRequestAggs( - geoHashGridAgg - ) as IBucketGeoHashGridAggConfig[]; - - expect(geoHashAgg).toHaveProperty('lastMapCollar'); - expect(geoHashAgg.lastMapCollar).toHaveProperty('top_left'); - expect(geoHashAgg.lastMapCollar).toHaveProperty('bottom_right'); - expect(geoHashAgg.lastMapCollar).toHaveProperty('zoom'); - }); - }); - }); - - describe('aggregation options', () => { - it('should only create geohash_grid and geo_centroid aggregations when isFilteredByCollar is false', () => { - const aggConfigs = getAggConfigs({ isFilteredByCollar: false }); - const requestAggs = geoHashBucketAgg.getRequestAggs( - aggConfigs.aggs[0] as IBucketGeoHashGridAggConfig - ) as IBucketGeoHashGridAggConfig[]; - - expect(requestAggs.length).toEqual(2); - expect(requestAggs[0].type.name).toEqual('geohash_grid'); - expect(requestAggs[1].type.name).toEqual('geo_centroid'); - }); - - it('should only create filter and geohash_grid aggregations when useGeocentroid is false', () => { - const aggConfigs = getAggConfigs({ useGeocentroid: false }); - const requestAggs = geoHashBucketAgg.getRequestAggs( - aggConfigs.aggs[0] as IBucketGeoHashGridAggConfig - ) as IBucketGeoHashGridAggConfig[]; - - expect(requestAggs.length).toEqual(2); - expect(requestAggs[0].type.name).toEqual('filter'); - expect(requestAggs[1].type.name).toEqual('geohash_grid'); - }); - }); - - describe('aggregation creation after map interaction', () => { - let originalRequestAggs: IBucketGeoHashGridAggConfig[]; - - beforeEach(() => { - originalRequestAggs = geoHashBucketAgg.getRequestAggs( - getAggConfigs().aggs[0] as IBucketGeoHashGridAggConfig - ) as IBucketGeoHashGridAggConfig[]; - }); - - it('should change geo_bounding_box filter aggregation and vis session state when map movement is outside map collar', () => { - const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs( - getAggConfigs({ - mapBounds: { - top_left: { lat: 10.0, lon: -10.0 }, - bottom_right: { lat: 9.0, lon: -9.0 }, - }, - }).aggs[0] as IBucketGeoHashGridAggConfig - ) as IBucketGeoHashGridAggConfig[]; - - expect(originalRequestAggs[1].params).not.toEqual(geoBoxingBox.params); - }); - - it('should not change geo_bounding_box filter aggregation and vis session state when map movement is within map collar', () => { - const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs( - getAggConfigs({ - mapBounds: { - top_left: { lat: 1, lon: -1 }, - bottom_right: { lat: -1, lon: 1 }, - }, - }).aggs[0] as IBucketGeoHashGridAggConfig - ) as IBucketGeoHashGridAggConfig[]; - - expect(originalRequestAggs[1].params).toEqual(geoBoxingBox.params); - }); - - it('should change geo_bounding_box filter aggregation and vis session state when map zoom level changes', () => { - const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs( - getAggConfigs({ - mapZoom: -1, - }).aggs[0] as IBucketGeoHashGridAggConfig - ) as IBucketGeoHashGridAggConfig[]; - - expect(originalRequestAggs[1].lastMapCollar).not.toEqual(geoBoxingBox.lastMapCollar); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/geo_hash.ts b/src/legacy/ui/public/agg_types/buckets/geo_hash.ts deleted file mode 100644 index b2519df6fb175..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/geo_hash.ts +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { geohashColumns } from 'ui/vis/map/decode_geo_hash'; -import chrome from '../../chrome'; -import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -import { geoContains, scaleBounds, GeoBoundingBox } from './lib/geo_utils'; -import { BUCKET_TYPES } from './bucket_agg_types'; -import { AggGroupNames } from '../agg_groups'; - -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: any = {}; -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(val: string) { - let precision = parseInt(val, 10); - - if (Number.isNaN(precision)) { - precision = defaultPrecision; - } - - if (precision > maxPrecision) { - return maxPrecision; - } - - return precision; -} - -const isOutsideCollar = (bounds: GeoBoundingBox, collar: MapCollar) => - bounds && collar && !geoContains(collar, bounds); - -const geohashGridTitle = i18n.translate('common.ui.aggTypes.buckets.geohashGridTitle', { - defaultMessage: 'Geohash', -}); - -interface MapCollar extends GeoBoundingBox { - zoom?: unknown; -} - -export interface IBucketGeoHashGridAggConfig extends IBucketAggConfig { - lastMapCollar: MapCollar; -} - -export const geoHashBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.GEOHASH_GRID, - title: geohashGridTitle, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT, - }, - { - name: 'autoPrecision', - default: true, - write: () => {}, - }, - { - name: 'precision', - default: defaultPrecision, - deserialize: getPrecision, - write(aggConfig, output) { - const currZoom = aggConfig.params.mapZoom; - const autoPrecisionVal = zoomPrecision[currZoom]; - output.params.precision = aggConfig.params.autoPrecision - ? autoPrecisionVal - : getPrecision(aggConfig.params.precision); - }, - }, - { - name: 'useGeocentroid', - default: true, - write: () => {}, - }, - { - name: 'isFilteredByCollar', - default: true, - write: () => {}, - }, - { - name: 'mapZoom', - default: 2, - write: () => {}, - }, - { - name: 'mapCenter', - default: [0, 0], - write: () => {}, - }, - { - name: 'mapBounds', - default: null, - write: () => {}, - }, - ], - getRequestAggs(agg) { - const aggs = []; - const params = agg.params; - - if (params.isFilteredByCollar && agg.getField()) { - const { mapBounds, mapZoom } = params; - if (mapBounds) { - let mapCollar: MapCollar; - - if ( - mapBounds && - (!agg.lastMapCollar || - agg.lastMapCollar.zoom !== mapZoom || - isOutsideCollar(mapBounds, agg.lastMapCollar)) - ) { - mapCollar = scaleBounds(mapBounds); - mapCollar.zoom = mapZoom; - agg.lastMapCollar = mapCollar; - } else { - mapCollar = agg.lastMapCollar; - } - const boundingBox = { - ignore_unmapped: true, - [agg.getField().name]: { - top_left: mapCollar.top_left, - bottom_right: mapCollar.bottom_right, - }, - }; - aggs.push( - agg.aggConfigs.createAggConfig( - { - type: 'filter', - id: 'filter_agg', - enabled: true, - params: { - geo_bounding_box: boundingBox, - }, - schema: { - group: AggGroupNames.Buckets, - }, - } as any, - { addToAggConfigs: false } - ) - ); - } - } - - aggs.push(agg); - - if (params.useGeocentroid) { - aggs.push( - agg.aggConfigs.createAggConfig( - { - type: 'geo_centroid', - enabled: true, - params: { - field: agg.getField(), - }, - }, - { addToAggConfigs: false } - ) - ); - } - - return aggs as IBucketGeoHashGridAggConfig[]; - }, -}); diff --git a/src/legacy/ui/public/agg_types/buckets/geo_tile.ts b/src/legacy/ui/public/agg_types/buckets/geo_tile.ts deleted file mode 100644 index ef71e3947566a..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/geo_tile.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { noop } from 'lodash'; -import { AggConfigOptions } from '../agg_config'; - -import { BucketAggType } from './_bucket_agg_type'; -import { BUCKET_TYPES } from './bucket_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; -import { IBucketAggConfig } from './_bucket_agg_type'; -import { METRIC_TYPES } from '../metrics/metric_agg_types'; - -const geotileGridTitle = i18n.translate('common.ui.aggTypes.buckets.geotileGridTitle', { - defaultMessage: 'Geotile', -}); - -export const geoTileBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.GEOTILE_GRID, - title: geotileGridTitle, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT, - }, - { - name: 'useGeocentroid', - default: true, - write: noop, - }, - { - name: 'precision', - default: 0, - }, - ], - getRequestAggs(agg) { - const aggs = []; - const useGeocentroid = agg.getParam('useGeocentroid'); - - aggs.push(agg); - - if (useGeocentroid) { - const aggConfig: AggConfigOptions = { - type: METRIC_TYPES.GEO_CENTROID, - enabled: true, - params: { - field: agg.getField(), - }, - }; - - aggs.push(agg.aggConfigs.createAggConfig(aggConfig, { addToAggConfigs: false })); - } - - return aggs as IBucketAggConfig[]; - }, -}); diff --git a/src/legacy/ui/public/agg_types/buckets/histogram.test.ts b/src/legacy/ui/public/agg_types/buckets/histogram.test.ts deleted file mode 100644 index 4e89d7db1ff64..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/histogram.test.ts +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { npStart } from 'ui/new_platform'; -import { AggConfigs } from '../index'; -import { BUCKET_TYPES } from './bucket_agg_types'; -import { IBucketHistogramAggConfig, histogramBucketAgg, AutoBounds } from './histogram'; -import { BucketAggType } from './_bucket_agg_type'; - -jest.mock('ui/new_platform'); - -describe('Histogram Agg', () => { - const getAggConfigs = (params: Record = {}) => { - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - const field = { - name: 'field', - indexPattern, - }; - - return new AggConfigs( - indexPattern, - [ - { - field: { - name: 'field', - }, - id: 'test', - type: BUCKET_TYPES.HISTOGRAM, - schema: 'segment', - params, - }, - ], - null - ); - }; - - const getParams = (options: Record) => { - const aggConfigs = getAggConfigs({ - ...options, - field: { - name: 'field', - }, - }); - return aggConfigs.aggs[0].toDsl()[BUCKET_TYPES.HISTOGRAM]; - }; - - describe('ordered', () => { - let histogramType: BucketAggType; - - beforeEach(() => { - histogramType = histogramBucketAgg; - }); - - it('is ordered', () => { - expect(histogramType.ordered).toBeDefined(); - }); - - it('is not ordered by date', () => { - expect(histogramType.ordered).not.toHaveProperty('date'); - }); - }); - - describe('params', () => { - describe('intervalBase', () => { - it('should not be written to the DSL', () => { - const aggConfigs = getAggConfigs({ - intervalBase: 100, - field: { - name: 'field', - }, - }); - const { [BUCKET_TYPES.HISTOGRAM]: params } = aggConfigs.aggs[0].toDsl(); - - expect(params).not.toHaveProperty('intervalBase'); - }); - }); - - describe('interval', () => { - it('accepts a whole number', () => { - const params = getParams({ - interval: 100, - }); - - expect(params).toHaveProperty('interval', 100); - }); - - it('accepts a decimal number', function() { - const params = getParams({ - interval: 0.1, - }); - - expect(params).toHaveProperty('interval', 0.1); - }); - - it('accepts a decimal number string', function() { - const params = getParams({ - interval: '0.1', - }); - - expect(params).toHaveProperty('interval', 0.1); - }); - - it('accepts a whole number string', function() { - const params = getParams({ - interval: '10', - }); - - expect(params).toHaveProperty('interval', 10); - }); - - it('fails on non-numeric values', function() { - const params = getParams({ - interval: [], - }); - - expect(params.interval).toBeNaN(); - }); - - describe('interval scaling', () => { - const getInterval = ( - maxBars: number, - params?: Record, - autoBounds?: AutoBounds - ) => { - const aggConfigs = getAggConfigs({ - ...params, - field: { - name: 'field', - }, - }); - const aggConfig = aggConfigs.aggs[0] as IBucketHistogramAggConfig; - - if (autoBounds) { - aggConfig.setAutoBounds(autoBounds); - } - - // mock histogram:maxBars value; - npStart.core.uiSettings.get = jest.fn(() => maxBars as any); - - return aggConfig.write(aggConfigs).params; - }; - - it('will respect the histogram:maxBars setting', () => { - const params = getInterval( - 5, - { interval: 5 }, - { - min: 0, - max: 10000, - } - ); - - expect(params).toHaveProperty('interval', 2000); - }); - - it('will return specified interval, if bars are below histogram:maxBars config', () => { - const params = getInterval(100, { interval: 5 }); - - expect(params).toHaveProperty('interval', 5); - }); - - it('will set to intervalBase if interval is below base', () => { - const params = getInterval(1000, { interval: 3, intervalBase: 8 }); - - expect(params).toHaveProperty('interval', 8); - }); - - it('will round to nearest intervalBase multiple if interval is above base', () => { - const roundUp = getInterval(1000, { interval: 46, intervalBase: 10 }); - expect(roundUp).toHaveProperty('interval', 50); - - const roundDown = getInterval(1000, { interval: 43, intervalBase: 10 }); - expect(roundDown).toHaveProperty('interval', 40); - }); - - it('will not change interval if it is a multiple of base', () => { - const output = getInterval(1000, { interval: 35, intervalBase: 5 }); - - expect(output).toHaveProperty('interval', 35); - }); - - it('will round to intervalBase after scaling histogram:maxBars', () => { - const output = getInterval(100, { interval: 5, intervalBase: 6 }, { min: 0, max: 1000 }); - - // 100 buckets in 0 to 1000 would result in an interval of 10, so we should - // round to the next multiple of 6 -> 12 - expect(output).toHaveProperty('interval', 12); - }); - }); - - describe('min_doc_count', () => { - let output: Record; - - it('casts true values to 0', () => { - output = getParams({ min_doc_count: true }); - expect(output).toHaveProperty('min_doc_count', 0); - - output = getParams({ min_doc_count: 'yes' }); - expect(output).toHaveProperty('min_doc_count', 0); - - output = getParams({ min_doc_count: 1 }); - expect(output).toHaveProperty('min_doc_count', 0); - - output = getParams({ min_doc_count: {} }); - expect(output).toHaveProperty('min_doc_count', 0); - }); - - it('writes 1 for falsy values', () => { - output = getParams({ min_doc_count: '' }); - expect(output).toHaveProperty('min_doc_count', 1); - - output = getParams({ min_doc_count: null }); - expect(output).toHaveProperty('min_doc_count', 1); - - output = getParams({ min_doc_count: undefined }); - expect(output).toHaveProperty('min_doc_count', 1); - }); - }); - - describe('extended_bounds', function() { - it('does not write when only eb.min is set', function() { - const output = getParams({ - has_extended_bounds: true, - extended_bounds: { min: 0 }, - }); - expect(output).not.toHaveProperty('extended_bounds'); - }); - - it('does not write when only eb.max is set', function() { - const output = getParams({ - has_extended_bounds: true, - extended_bounds: { max: 0 }, - }); - - expect(output).not.toHaveProperty('extended_bounds'); - }); - - it('writes when both eb.min and eb.max are set', function() { - const output = getParams({ - has_extended_bounds: true, - extended_bounds: { min: 99, max: 100 }, - }); - - expect(output.extended_bounds).toHaveProperty('min', 99); - expect(output.extended_bounds).toHaveProperty('max', 100); - }); - - it('does not write when nothing is set', function() { - const output = getParams({ - has_extended_bounds: true, - extended_bounds: {}, - }); - - expect(output).not.toHaveProperty('extended_bounds'); - }); - - it('does not write when has_extended_bounds is false', function() { - const output = getParams({ - has_extended_bounds: false, - extended_bounds: { min: 99, max: 100 }, - }); - - expect(output).not.toHaveProperty('extended_bounds'); - }); - }); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/histogram.ts b/src/legacy/ui/public/agg_types/buckets/histogram.ts deleted file mode 100644 index 44327c7c19e6d..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/histogram.ts +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import _ from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { toastNotifications } from 'ui/notify'; - -import { npStart } from 'ui/new_platform'; -import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; -import { createFilterHistogram } from './create_filter/histogram'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; -import { BUCKET_TYPES } from './bucket_agg_types'; - -export interface AutoBounds { - min: number; - max: number; -} - -export interface IBucketHistogramAggConfig extends IBucketAggConfig { - setAutoBounds: (bounds: AutoBounds) => void; - getAutoBounds: () => AutoBounds; -} - -const getUIConfig = () => npStart.core.uiSettings; - -export const histogramBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.HISTOGRAM, - title: i18n.translate('common.ui.aggTypes.buckets.histogramTitle', { - defaultMessage: 'Histogram', - }), - ordered: {}, - makeLabel(aggConfig) { - return aggConfig.getFieldDisplayName(); - }, - createFilter: createFilterHistogram, - decorateAggConfig() { - let autoBounds: AutoBounds; - - return { - setAutoBounds: { - configurable: true, - value(newValue: AutoBounds) { - autoBounds = newValue; - }, - }, - getAutoBounds: { - configurable: true, - value() { - return autoBounds; - }, - }, - }; - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.NUMBER, - }, - { - /* - * This parameter can be set if you want the auto scaled interval to always - * be a multiple of a specific base. - */ - name: 'intervalBase', - default: null, - write: () => {}, - }, - { - name: 'interval', - modifyAggConfigOnSearchRequestStart( - aggConfig: IBucketHistogramAggConfig, - searchSource: any, - options: any - ) { - const field = aggConfig.getField(); - const aggBody = field.scripted - ? { script: { source: field.script, lang: field.lang } } - : { field: field.name }; - - const childSearchSource = searchSource - .createChild() - .setField('size', 0) - .setField('aggs', { - maxAgg: { - max: aggBody, - }, - minAgg: { - min: aggBody, - }, - }); - - return childSearchSource - .fetch(options) - .then((resp: any) => { - aggConfig.setAutoBounds({ - min: _.get(resp, 'aggregations.minAgg.value'), - max: _.get(resp, 'aggregations.maxAgg.value'), - }); - }) - .catch((e: Error) => { - if (e.name === 'AbortError') return; - toastNotifications.addWarning( - i18n.translate('common.ui.aggTypes.histogram.missingMaxMinValuesWarning', { - defaultMessage: - 'Unable to retrieve max and min values to auto-scale histogram buckets. This may lead to poor visualization performance.', - }) - ); - }); - }, - write(aggConfig, output) { - let interval = parseFloat(aggConfig.params.interval); - if (interval <= 0) { - interval = 1; - } - const autoBounds = aggConfig.getAutoBounds(); - - // ensure interval does not create too many buckets and crash browser - if (autoBounds) { - const range = autoBounds.max - autoBounds.min; - const bars = range / interval; - - const config = getUIConfig(); - 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 orderOfMagnitude = Math.pow(10, Math.floor(Math.log10(minInterval))); - let roundInterval = orderOfMagnitude; - - while (roundInterval < minInterval) { - roundInterval += orderOfMagnitude; - } - interval = roundInterval; - } - } - const base = aggConfig.params.intervalBase; - - if (base) { - if (interval < base) { - // In case the specified interval is below the base, just increase it to it's base - interval = base; - } else if (interval % base !== 0) { - // In case the interval is not a multiple of the base round it to the next base - interval = Math.round(interval / base) * base; - } - } - - output.params.interval = interval; - }, - }, - { - name: 'min_doc_count', - default: false, - write(aggConfig, output) { - if (aggConfig.params.min_doc_count) { - output.params.min_doc_count = 0; - } else { - output.params.min_doc_count = 1; - } - }, - }, - { - name: 'has_extended_bounds', - default: false, - write: () => {}, - }, - { - name: 'extended_bounds', - default: { - min: '', - max: '', - }, - write(aggConfig, output) { - const { min, max } = aggConfig.params.extended_bounds; - - if (aggConfig.params.has_extended_bounds && (min || min === 0) && (max || max === 0)) { - output.params.extended_bounds = { min, max }; - } - }, - shouldShow: (aggConfig: IBucketAggConfig) => aggConfig.params.has_extended_bounds, - }, - ], -}); diff --git a/src/legacy/ui/public/agg_types/buckets/ip_range.ts b/src/legacy/ui/public/agg_types/buckets/ip_range.ts index 41141dabf507c..7a8fd4f89b1ff 100644 --- a/src/legacy/ui/public/agg_types/buckets/ip_range.ts +++ b/src/legacy/ui/public/agg_types/buckets/ip_range.ts @@ -17,93 +17,4 @@ * under the License. */ -import { noop, map, omit, isNull } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { npStart } from 'ui/new_platform'; -import { BucketAggType } from './_bucket_agg_type'; -import { BUCKET_TYPES } from './bucket_agg_types'; - -// @ts-ignore -import { createFilterIpRange } from './create_filter/ip_range'; -import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../plugins/data/public'; - -const ipRangeTitle = i18n.translate('common.ui.aggTypes.buckets.ipRangeTitle', { - defaultMessage: 'IPv4 Range', -}); - -export type IpRangeKey = - | { type: 'mask'; mask: string } - | { type: 'range'; from: string; to: string }; - -export const ipRangeBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.IP_RANGE, - title: ipRangeTitle, - createFilter: createFilterIpRange, - getKey(bucket, key, agg): IpRangeKey { - if (agg.params.ipRangeType === 'mask') { - return { type: 'mask', mask: key }; - } - return { type: 'range', from: bucket.from, to: bucket.to }; - }, - getFormat(agg) { - const fieldFormatsService = npStart.plugins.data.fieldFormats; - const formatter = agg.fieldOwnFormatter( - fieldFormats.TEXT_CONTEXT_TYPE, - fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.IP) - ); - const IpRangeFormat = fieldFormats.FieldFormat.from(function(range: IpRangeKey) { - return convertIPRangeToString(range, formatter); - }); - return new IpRangeFormat(); - }, - makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.buckets.ipRangeLabel', { - defaultMessage: '{fieldName} IP ranges', - values: { - fieldName: aggConfig.getFieldDisplayName(), - }, - }); - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.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' }], - }, - write(aggConfig, output) { - const ipRangeType = aggConfig.params.ipRangeType; - let ranges = aggConfig.params.ranges[ipRangeType]; - - if (ipRangeType === 'fromTo') { - ranges = map(ranges, (range: any) => omit(range, isNull)); - } - - output.params.ranges = ranges; - }, - }, - ], -}); - -export const convertIPRangeToString = (range: IpRangeKey, format: (val: any) => string) => { - if (range.type === 'mask') { - return format(range.mask); - } - const from = range.from ? format(range.from) : '-Infinity'; - const to = range.to ? format(range.to) : 'Infinity'; - - return `${from} to ${to}`; -}; +export { IpRangeKey, convertIPRangeToString } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.test.ts b/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.test.ts deleted file mode 100644 index 01dd3ddf1b874..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { CidrMask } from './cidr_mask'; - -describe('CidrMask', () => { - test('should throw errors with invalid CIDR masks', () => { - expect( - () => - // @ts-ignore - new CidrMask() - ).toThrowError(); - - expect(() => new CidrMask('')).toThrowError(); - expect(() => new CidrMask('hello, world')).toThrowError(); - expect(() => new CidrMask('0.0.0.0')).toThrowError(); - expect(() => new CidrMask('0.0.0.0/0')).toThrowError(); - expect(() => new CidrMask('0.0.0.0/33')).toThrowError(); - expect(() => new CidrMask('256.0.0.0/32')).toThrowError(); - expect(() => new CidrMask('0.0.0.0/32/32')).toThrowError(); - expect(() => new CidrMask('1.2.3/1')).toThrowError(); - expect(() => new CidrMask('0.0.0.0/123d')).toThrowError(); - }); - - test('should correctly grab IP address and prefix length', () => { - let mask = new CidrMask('0.0.0.0/1'); - expect(mask.initialAddress.toString()).toBe('0.0.0.0'); - expect(mask.prefixLength).toBe(1); - - mask = new CidrMask('128.0.0.1/31'); - expect(mask.initialAddress.toString()).toBe('128.0.0.1'); - expect(mask.prefixLength).toBe(31); - }); - - test('should calculate a range of IP addresses', () => { - let mask = new CidrMask('0.0.0.0/1'); - let range = mask.getRange(); - expect(range.from.toString()).toBe('0.0.0.0'); - expect(range.to.toString()).toBe('127.255.255.255'); - - mask = new CidrMask('1.2.3.4/2'); - range = mask.getRange(); - expect(range.from.toString()).toBe('0.0.0.0'); - expect(range.to.toString()).toBe('63.255.255.255'); - - mask = new CidrMask('67.129.65.201/27'); - range = mask.getRange(); - expect(range.from.toString()).toBe('67.129.65.192'); - expect(range.to.toString()).toBe('67.129.65.223'); - }); - - test('toString()', () => { - let mask = new CidrMask('.../1'); - expect(mask.toString()).toBe('0.0.0.0/1'); - - mask = new CidrMask('128.0.0.1/31'); - expect(mask.toString()).toBe('128.0.0.1/31'); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts b/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts index aadbbc8c82276..0774a89ee3f03 100644 --- a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts +++ b/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts @@ -17,42 +17,4 @@ * under the License. */ -import { Ipv4Address } from '../../../../../../plugins/kibana_utils/public'; - -const NUM_BITS = 32; - -function throwError(mask: string) { - throw Error('Invalid CIDR mask: ' + mask); -} - -export class CidrMask { - public readonly initialAddress: Ipv4Address; - public readonly prefixLength: number; - - constructor(mask: string) { - const splits = mask.split('/'); - if (splits.length !== 2) { - throwError(mask); - } - this.initialAddress = new Ipv4Address(splits[0]); - this.prefixLength = Number(splits[1]); - if (isNaN(this.prefixLength) || this.prefixLength < 1 || this.prefixLength > NUM_BITS) { - throwError(mask); - } - } - - public getRange() { - const variableBits = NUM_BITS - this.prefixLength; - // eslint-disable-next-line no-bitwise - const fromAddress = ((this.initialAddress.valueOf() >> variableBits) << variableBits) >>> 0; // >>> 0 coerces to unsigned - const numAddresses = Math.pow(2, variableBits); - return { - from: new Ipv4Address(fromAddress).toString(), - to: new Ipv4Address(fromAddress + numAddresses - 1).toString(), - }; - } - - public toString() { - return this.initialAddress.toString() + '/' + this.prefixLength; - } -} +export { CidrMask } from '../../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/lib/geo_utils.ts b/src/legacy/ui/public/agg_types/buckets/lib/geo_utils.ts deleted file mode 100644 index 639b6d1fbb03e..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/lib/geo_utils.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import _ from 'lodash'; - -interface GeoBoundingBoxCoordinate { - lat: number; - lon: number; -} - -export interface GeoBoundingBox { - top_left: GeoBoundingBoxCoordinate; - bottom_right: GeoBoundingBoxCoordinate; -} - -export function geoContains(collar: GeoBoundingBox, bounds: GeoBoundingBox) { - // test if bounds top_left is outside collar - if (bounds.top_left.lat > collar.top_left.lat || bounds.top_left.lon < collar.top_left.lon) { - return false; - } - - // test if bounds bottom_right is outside collar - if ( - bounds.bottom_right.lat < collar.bottom_right.lat || - bounds.bottom_right.lon > collar.bottom_right.lon - ) { - return false; - } - - // both corners are inside collar so collar contains bounds - return true; -} - -export function scaleBounds(bounds: GeoBoundingBox): GeoBoundingBox { - const scale = 0.5; // scale bounds by 50% - - const topLeft = bounds.top_left; - const bottomRight = bounds.bottom_right; - let latDiff = _.round(Math.abs(topLeft.lat - bottomRight.lat), 5); - const lonDiff = _.round(Math.abs(bottomRight.lon - topLeft.lon), 5); - // map height can be zero when vis is first created - if (latDiff === 0) latDiff = lonDiff; - - const latDelta = latDiff * scale; - let topLeftLat = _.round(topLeft.lat, 5) + latDelta; - if (topLeftLat > 90) topLeftLat = 90; - let bottomRightLat = _.round(bottomRight.lat, 5) - latDelta; - if (bottomRightLat < -90) bottomRightLat = -90; - const lonDelta = lonDiff * scale; - let topLeftLon = _.round(topLeft.lon, 5) - lonDelta; - if (topLeftLon < -180) topLeftLon = -180; - let bottomRightLon = _.round(bottomRight.lon, 5) + lonDelta; - if (bottomRightLon > 180) bottomRightLon = 180; - - return { - top_left: { lat: topLeftLat, lon: topLeftLon }, - bottom_right: { lat: bottomRightLat, lon: bottomRightLon }, - }; -} diff --git a/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts b/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts index 77e84e044de55..f86cc2b6a294b 100644 --- a/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts +++ b/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts @@ -17,37 +17,4 @@ * under the License. */ -import { isString, isObject } from 'lodash'; -import { IBucketAggConfig, BucketAggType, BucketAggParam } from './_bucket_agg_type'; -import { AggConfig } from '../agg_config'; - -export const isType = (type: string) => { - return (agg: AggConfig): boolean => { - const field = agg.params.field; - - return field && field.type === type; - }; -}; - -export const isStringType = isType('string'); - -export const migrateIncludeExcludeFormat = { - serialize(this: BucketAggParam, value: any, agg: IBucketAggConfig) { - if (this.shouldShow && !this.shouldShow(agg)) return; - if (!value || isString(value)) return value; - else return value.pattern; - }, - write( - this: BucketAggType, - aggConfig: IBucketAggConfig, - output: Record - ) { - const value = aggConfig.getParam(this.name); - - if (isObject(value)) { - output.params[this.name] = value.pattern; - } else if (value && isStringType(aggConfig)) { - output.params[this.name] = value; - } - }, -} as Partial>; +export { isType, isStringType } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/range.test.ts b/src/legacy/ui/public/agg_types/buckets/range.test.ts deleted file mode 100644 index dd85c3b31939f..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/range.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { AggConfigs } from '../agg_configs'; -import { BUCKET_TYPES } from './bucket_agg_types'; -import { fieldFormats } from '../../../../../plugins/data/public'; - -jest.mock('ui/new_platform'); - -const buckets = [ - { - to: 1024, - to_as_string: '1024.0', - doc_count: 20904, - }, - { - from: 1024, - from_as_string: '1024.0', - to: 2560, - to_as_string: '2560.0', - doc_count: 23358, - }, - { - from: 2560, - from_as_string: '2560.0', - doc_count: 174250, - }, -]; - -describe('Range Agg', () => { - const getConfig = (() => {}) as fieldFormats.GetConfigFn; - const getAggConfigs = () => { - const field = { - name: 'bytes', - format: new fieldFormats.NumberFormat( - { - pattern: '0,0.[000] b', - }, - getConfig - ), - }; - - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - return new AggConfigs( - indexPattern, - [ - { - type: BUCKET_TYPES.RANGE, - schema: 'segment', - params: { - field: 'bytes', - ranges: [ - { from: 0, to: 1000 }, - { from: 1000, to: 2000 }, - ], - }, - }, - ], - null - ); - }; - - describe('formating', () => { - it('formats bucket keys properly', () => { - const aggConfigs = getAggConfigs(); - const agg = aggConfigs.aggs[0]; - - const format = (val: any) => agg.fieldFormatter()(agg.getKey(val)); - - expect(format(buckets[0])).toBe('≥ -∞ and < 1 KB'); - expect(format(buckets[1])).toBe('≥ 1 KB and < 2.5 KB'); - expect(format(buckets[2])).toBe('≥ 2.5 KB and < +∞'); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/range.ts b/src/legacy/ui/public/agg_types/buckets/range.ts deleted file mode 100644 index f24473e0c68aa..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/range.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { BucketAggType } from './_bucket_agg_type'; -import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; -import { RangeKey } from './range_key'; -import { createFilterRange } from './create_filter/range'; -import { BUCKET_TYPES } from './bucket_agg_types'; - -const keyCaches = new WeakMap(); -const formats = new WeakMap(); - -const rangeTitle = i18n.translate('common.ui.aggTypes.buckets.rangeTitle', { - defaultMessage: 'Range', -}); - -export const rangeBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.RANGE, - title: rangeTitle, - createFilter: createFilterRange, - makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.buckets.rangesLabel', { - defaultMessage: '{fieldName} ranges', - values: { - fieldName: aggConfig.getFieldDisplayName(), - }, - }); - }, - getKey(bucket, key, agg) { - let keys = keyCaches.get(agg); - - 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(agg) { - let aggFormat = formats.get(agg); - if (aggFormat) return aggFormat; - - const RangeFormat = fieldFormats.FieldFormat.from((range: any) => { - const format = agg.fieldOwnFormatter(); - const gte = '\u2265'; - const lt = '\u003c'; - return i18n.translate('common.ui.aggTypes.buckets.ranges.rangesFormatMessage', { - defaultMessage: '{gte} {from} and {lt} {to}', - values: { - gte, - from: format(range.gte), - lt, - to: format(range.lt), - }, - }); - }); - - aggFormat = new RangeFormat(); - - formats.set(agg, aggFormat); - return aggFormat; - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: [KBN_FIELD_TYPES.NUMBER], - }, - { - name: 'ranges', - default: [ - { from: 0, to: 1000 }, - { from: 1000, to: 2000 }, - ], - write(aggConfig, output) { - output.params.ranges = aggConfig.params.ranges; - output.params.keyed = true; - }, - }, - ], -}); diff --git a/src/legacy/ui/public/agg_types/buckets/range_key.ts b/src/legacy/ui/public/agg_types/buckets/range_key.ts deleted file mode 100644 index cd781f7e082a2..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/range_key.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -const id = Symbol('id'); - -export class RangeKey { - [id]: string; - gte: string | number; - lt: string | number; - - constructor(bucket: any) { - this.gte = bucket.from == null ? -Infinity : bucket.from; - this.lt = bucket.to == null ? +Infinity : bucket.to; - - this[id] = RangeKey.idBucket(bucket); - } - - static idBucket(bucket: any) { - return `from:${bucket.from},to:${bucket.to}`; - } - - toString() { - return this[id]; - } -} diff --git a/src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts b/src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts deleted file mode 100644 index 8db9226e41eec..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { AggConfigs } from '../index'; -import { BUCKET_TYPES } from './bucket_agg_types'; -import { significantTermsBucketAgg } from './significant_terms'; -import { IBucketAggConfig } from './_bucket_agg_type'; - -jest.mock('ui/new_platform'); - -describe('Significant Terms Agg', () => { - describe('order agg editor UI', () => { - describe('convert include/exclude from old format', () => { - const getAggConfigs = (params: Record = {}) => { - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - const field = { - name: 'field', - indexPattern, - }; - - return new AggConfigs( - indexPattern, - [ - { - id: 'test', - type: BUCKET_TYPES.SIGNIFICANT_TERMS, - schema: 'segment', - params, - }, - ], - null - ); - }; - - const testSerializeAndWrite = (aggs: AggConfigs) => { - const agg = aggs.aggs[0]; - const { [BUCKET_TYPES.SIGNIFICANT_TERMS]: params } = agg.toDsl(); - - expect(params.field).toBe('field'); - expect(params.include).toBe('404'); - expect(params.exclude).toBe('400'); - }; - - it('should generate correct label', () => { - const aggConfigs = getAggConfigs({ - size: 'SIZE', - field: { - name: 'FIELD', - }, - }); - const label = significantTermsBucketAgg.makeLabel(aggConfigs.aggs[0] as IBucketAggConfig); - - expect(label).toBe('Top SIZE unusual terms in FIELD'); - }); - - it('should doesnt do anything with string type', () => { - const aggConfigs = getAggConfigs({ - include: '404', - exclude: '400', - field: { - name: 'field', - type: 'string', - }, - }); - - testSerializeAndWrite(aggConfigs); - }); - - it('should converts object to string type', () => { - const aggConfigs = getAggConfigs({ - include: { - pattern: '404', - }, - exclude: { - pattern: '400', - }, - field: { - name: 'field', - type: 'string', - }, - }); - - testSerializeAndWrite(aggConfigs); - }); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/significant_terms.ts b/src/legacy/ui/public/agg_types/buckets/significant_terms.ts deleted file mode 100644 index 38ca0768d3bc1..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/significant_terms.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { BucketAggType } from './_bucket_agg_type'; -import { createFilterTerms } from './create_filter/terms'; -import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; -import { BUCKET_TYPES } from './bucket_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -const significantTermsTitle = i18n.translate('common.ui.aggTypes.buckets.significantTermsTitle', { - defaultMessage: 'Significant Terms', -}); - -export const significantTermsBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.SIGNIFICANT_TERMS, - title: significantTermsTitle, - makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.buckets.significantTermsLabel', { - defaultMessage: 'Top {size} unusual terms in {fieldName}', - values: { - size: aggConfig.params.size, - fieldName: aggConfig.getFieldDisplayName(), - }, - }); - }, - createFilter: createFilterTerms, - params: [ - { - name: 'field', - type: 'field', - scriptable: false, - filterFieldTypes: KBN_FIELD_TYPES.STRING, - }, - { - name: 'size', - default: '', - }, - { - name: 'exclude', - displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.excludeLabel', { - defaultMessage: 'Exclude', - }), - type: 'string', - advanced: true, - shouldShow: isStringType, - ...migrateIncludeExcludeFormat, - }, - { - name: 'include', - displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.includeLabel', { - defaultMessage: 'Include', - }), - type: 'string', - advanced: true, - shouldShow: isStringType, - ...migrateIncludeExcludeFormat, - }, - ], -}); diff --git a/src/legacy/ui/public/agg_types/buckets/terms.test.ts b/src/legacy/ui/public/agg_types/buckets/terms.test.ts deleted file mode 100644 index 24ac332ae4d55..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/terms.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { AggConfigs } from '../index'; -import { BUCKET_TYPES } from './bucket_agg_types'; - -jest.mock('ui/new_platform'); - -describe('Terms Agg', () => { - describe('order agg editor UI', () => { - const getAggConfigs = (params: Record = {}) => { - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - const field = { - name: 'field', - indexPattern, - }; - - return new AggConfigs( - indexPattern, - [ - { - id: 'test', - params, - type: BUCKET_TYPES.TERMS, - }, - ], - null - ); - }; - - it('converts object to string type', function() { - const aggConfigs = getAggConfigs({ - include: { - pattern: '404', - }, - exclude: { - pattern: '400', - }, - field: { - name: 'field', - }, - orderAgg: { - type: 'count', - }, - }); - - const { [BUCKET_TYPES.TERMS]: params } = aggConfigs.aggs[0].toDsl(); - - expect(params.field).toBe('field'); - expect(params.include).toBe('404'); - expect(params.exclude).toBe('400'); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/buckets/terms.ts b/src/legacy/ui/public/agg_types/buckets/terms.ts deleted file mode 100644 index 4ced1417402b5..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/terms.ts +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { noop } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { - getRequestInspectorStats, - getResponseInspectorStats, -} from '../../../../core_plugins/data/public'; -import { BucketAggType } from './_bucket_agg_type'; -import { BUCKET_TYPES } from './bucket_agg_types'; -import { IBucketAggConfig } from './_bucket_agg_type'; -import { createFilterTerms } from './create_filter/terms'; -import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; -import { AggConfigs } from '../agg_configs'; - -import { Adapters } from '../../../../../plugins/inspector/public'; -import { ISearchSource, fieldFormats, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -import { - buildOtherBucketAgg, - mergeOtherBucketAggResponse, - updateMissingBucket, - // @ts-ignore -} from './_terms_other_bucket_helper'; -import { Schemas } from '../schemas'; -import { AggGroupNames } from '../agg_groups'; - -export const termsAggFilter = [ - '!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: AggGroupNames.None, - name: 'orderAgg', - // This string is never visible to the user so it doesn't need to be translated - title: 'Order Agg', - hideCustomLabel: true, - aggFilter: termsAggFilter, - }, -]).all; - -const termsTitle = i18n.translate('common.ui.aggTypes.buckets.termsTitle', { - defaultMessage: 'Terms', -}); - -export const termsBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.TERMS, - title: termsTitle, - makeLabel(agg) { - const params = agg.params; - return agg.getFieldDisplayName() + ': ' + params.order.text; - }, - getFormat(bucket): fieldFormats.FieldFormat { - return { - getConverterFor: (type: fieldFormats.ContentType) => { - return (val: any) => { - if (val === '__other__') { - return bucket.params.otherBucketLabel; - } - if (val === '__missing__') { - return bucket.params.missingBucketLabel; - } - - return bucket.params.field.format.convert(val, type); - }; - }, - } as fieldFormats.FieldFormat; - }, - createFilter: createFilterTerms, - postFlightRequest: async ( - resp: any, - aggConfigs: AggConfigs, - aggConfig: IBucketAggConfig, - searchSource: ISearchSource, - inspectorAdapters: Adapters, - abortSignal?: AbortSignal - ) => { - if (!resp.aggregations) return resp; - const nestedSearchSource = searchSource.createChild(); - if (aggConfig.params.otherBucket) { - const filterAgg = buildOtherBucketAgg(aggConfigs, aggConfig, resp); - if (!filterAgg) return resp; - - nestedSearchSource.setField('aggs', filterAgg); - - const request = inspectorAdapters.requests.start( - i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketTitle', { - defaultMessage: 'Other bucket', - }), - { - description: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketDescription', { - defaultMessage: - 'This request counts the number of documents that fall ' + - 'outside the criterion of the data buckets.', - }), - } - ); - nestedSearchSource.getSearchRequestBody().then((body: string) => { - request.json(body); - }); - request.stats(getRequestInspectorStats(nestedSearchSource)); - - const response = await nestedSearchSource.fetch({ abortSignal }); - request.stats(getResponseInspectorStats(nestedSearchSource, response)).ok({ json: response }); - resp = mergeOtherBucketAggResponse(aggConfigs, resp, response, aggConfig, filterAgg()); - } - if (aggConfig.params.missingBucket) { - resp = updateMissingBucket(resp, aggConfigs, aggConfig); - } - return resp; - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: [ - KBN_FIELD_TYPES.NUMBER, - KBN_FIELD_TYPES.BOOLEAN, - KBN_FIELD_TYPES.DATE, - KBN_FIELD_TYPES.IP, - KBN_FIELD_TYPES.STRING, - ], - }, - { - name: 'orderBy', - write: noop, // prevent default write, it's handled by orderAgg - }, - { - name: 'orderAgg', - type: 'agg', - default: null, - makeAgg(termsAgg, state) { - state = state || {}; - state.schema = orderAggSchema; - const orderAgg = termsAgg.aggConfigs.createAggConfig(state, { - addToAggConfigs: false, - }); - orderAgg.id = termsAgg.id + '-orderAgg'; - - return orderAgg; - }, - write(agg, output, aggs) { - const dir = agg.params.order.value; - const order: Record = (output.params.order = {}); - - let orderAgg = agg.params.orderAgg || 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.value_type = - 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') { - order._count = dir; - return; - } - - const orderAggId = orderAgg.id; - - if (orderAgg.parentId && aggs) { - orderAgg = aggs.byId(orderAgg.parentId); - } - - output.subAggs = (output.subAggs || []).concat(orderAgg); - order[orderAggId] = dir; - }, - }, - { - name: 'order', - type: 'optioned', - default: 'desc', - options: [ - { - text: i18n.translate('common.ui.aggTypes.buckets.terms.orderDescendingTitle', { - defaultMessage: 'Descending', - }), - value: 'desc', - }, - { - text: i18n.translate('common.ui.aggTypes.buckets.terms.orderAscendingTitle', { - defaultMessage: 'Ascending', - }), - value: 'asc', - }, - ], - write: noop, // prevent default write, it's handled by orderAgg - }, - { - name: 'size', - default: 5, - }, - { - name: 'otherBucket', - default: false, - write: noop, - }, - { - name: 'otherBucketLabel', - type: 'string', - default: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketLabel', { - defaultMessage: 'Other', - }), - displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForOtherBucketLabel', { - defaultMessage: 'Label for other bucket', - }), - shouldShow: agg => agg.getParam('otherBucket'), - write: noop, - }, - { - name: 'missingBucket', - default: false, - write: noop, - }, - { - name: 'missingBucketLabel', - default: i18n.translate('common.ui.aggTypes.buckets.terms.missingBucketLabel', { - defaultMessage: 'Missing', - description: `Default label used in charts when documents are missing a field. - Visible when you create a chart with a terms aggregation and enable "Show missing values"`, - }), - type: 'string', - displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForMissingValuesLabel', { - defaultMessage: 'Label for missing values', - }), - shouldShow: agg => agg.getParam('missingBucket'), - write: noop, - }, - { - name: 'exclude', - displayName: i18n.translate('common.ui.aggTypes.buckets.terms.excludeLabel', { - defaultMessage: 'Exclude', - }), - type: 'string', - advanced: true, - shouldShow: isStringType, - ...migrateIncludeExcludeFormat, - }, - { - name: 'include', - displayName: i18n.translate('common.ui.aggTypes.buckets.terms.includeLabel', { - defaultMessage: 'Include', - }), - type: 'string', - advanced: true, - shouldShow: isStringType, - ...migrateIncludeExcludeFormat, - }, - ], -}); diff --git a/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts b/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts deleted file mode 100644 index 0344f304877f2..0000000000000 --- a/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IndexPattern } from '../../../../../plugins/data/public'; -import { AggTypeFilters } from './agg_type_filters'; -import { AggConfig, AggType } from '..'; - -describe('AggTypeFilters', () => { - let registry: AggTypeFilters; - const indexPattern = ({ id: '1234', fields: [], title: 'foo' } as unknown) as IndexPattern; - const aggConfig = {} as AggConfig; - - beforeEach(() => { - registry = new AggTypeFilters(); - }); - - it('should filter nothing without registered filters', async () => { - const aggTypes = [{ name: 'count' }, { name: 'sum' }] as AggType[]; - const filtered = registry.filter(aggTypes, indexPattern, aggConfig); - expect(filtered).toEqual(aggTypes); - }); - - it('should pass all aggTypes to the registered filter', async () => { - const aggTypes = [{ name: 'count' }, { name: 'sum' }] as AggType[]; - const filter = jest.fn(); - registry.addFilter(filter); - registry.filter(aggTypes, indexPattern, aggConfig); - expect(filter).toHaveBeenCalledWith(aggTypes[0], indexPattern, aggConfig); - expect(filter).toHaveBeenCalledWith(aggTypes[1], indexPattern, aggConfig); - }); - - it('should allow registered filters to filter out aggTypes', async () => { - const aggTypes = [{ name: 'count' }, { name: 'sum' }, { name: 'avg' }] as AggType[]; - let filtered = registry.filter(aggTypes, indexPattern, aggConfig); - expect(filtered).toEqual(aggTypes); - - registry.addFilter(() => true); - registry.addFilter(aggType => aggType.name !== 'count'); - filtered = registry.filter(aggTypes, indexPattern, aggConfig); - expect(filtered).toEqual([aggTypes[1], aggTypes[2]]); - - registry.addFilter(aggType => aggType.name !== 'avg'); - filtered = registry.filter(aggTypes, indexPattern, aggConfig); - expect(filtered).toEqual([aggTypes[1]]); - }); -}); diff --git a/src/legacy/ui/public/agg_types/filter/agg_type_filters.ts b/src/legacy/ui/public/agg_types/filter/agg_type_filters.ts deleted file mode 100644 index 2cc4a6e962214..0000000000000 --- a/src/legacy/ui/public/agg_types/filter/agg_type_filters.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { IndexPattern } from 'src/plugins/data/public'; -import { AggType, AggConfig } from '..'; - -type AggTypeFilter = ( - aggType: AggType, - indexPattern: IndexPattern, - aggConfig: AggConfig -) => boolean; - -/** - * A registry to store {@link AggTypeFilter} which are used to filter down - * available aggregations for a specific visualization and {@link AggConfig}. - */ -class AggTypeFilters { - private filters = new Set(); - - /** - * Register a new {@link AggTypeFilter} with this registry. - * - * @param filter The filter to register. - */ - public addFilter(filter: AggTypeFilter): void { - this.filters.add(filter); - } - - /** - * Returns the {@link AggType|aggTypes} filtered by all registered filters. - * - * @param aggTypes A list of aggTypes that will be filtered down by this registry. - * @param indexPattern The indexPattern for which this list should be filtered down. - * @param aggConfig The aggConfig for which the returning list will be used. - * @return A filtered list of the passed aggTypes. - */ - public filter(aggTypes: AggType[], indexPattern: IndexPattern, aggConfig: AggConfig) { - const allFilters = Array.from(this.filters); - const allowedAggTypes = aggTypes.filter(aggType => { - const isAggTypeAllowed = allFilters.every(filter => filter(aggType, indexPattern, aggConfig)); - return isAggTypeAllowed; - }); - return allowedAggTypes; - } -} - -const aggTypeFilters = new AggTypeFilters(); - -export { aggTypeFilters, AggTypeFilters }; diff --git a/src/legacy/ui/public/agg_types/filter/prop_filter.test.ts b/src/legacy/ui/public/agg_types/filter/prop_filter.test.ts deleted file mode 100644 index 431e1161e0dbd..0000000000000 --- a/src/legacy/ui/public/agg_types/filter/prop_filter.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import expect from '@kbn/expect'; -import { propFilter } from './prop_filter'; - -describe('prop filter', () => { - let nameFilter: Function; - - beforeEach(() => { - nameFilter = propFilter('name'); - }); - - const getObjects = (...names: string[]) => { - const count = new Map(); - const objects = []; - - for (const name of names) { - if (!count.has(name)) { - count.set(name, 1); - } - objects.push({ - name, - title: `${name} ${count.get(name)}`, - }); - count.set(name, count.get(name) + 1); - } - - return objects; - }; - - it('returns list when no filters are provided', () => { - const objects = getObjects('table', 'table', 'pie'); - expect(nameFilter(objects)).to.eql(objects); - }); - - it('returns list when empty list of filters is provided', () => { - const objects = getObjects('table', 'table', 'pie'); - expect(nameFilter(objects, [])).to.eql(objects); - }); - - it('should keep only the tables', () => { - const objects = getObjects('table', 'table', 'pie'); - expect(nameFilter(objects, 'table')).to.eql(getObjects('table', 'table')); - }); - - it('should support comma-separated values', () => { - const objects = getObjects('table', 'line', 'pie'); - expect(nameFilter(objects, 'table,line')).to.eql(getObjects('table', 'line')); - }); - - it('should support an array of values', () => { - const objects = getObjects('table', 'line', 'pie'); - expect(nameFilter(objects, ['table', 'line'])).to.eql(getObjects('table', 'line')); - }); - - it('should return all objects', () => { - const objects = getObjects('table', 'line', 'pie'); - expect(nameFilter(objects, '*')).to.eql(objects); - }); - - it('should allow negation', () => { - const objects = getObjects('table', 'line', 'pie'); - expect(nameFilter(objects, ['!line'])).to.eql(getObjects('table', 'pie')); - }); - - it('should support a function for specifying what should be kept', () => { - const objects = getObjects('table', 'line', 'pie'); - const line = (value: string) => value === 'line'; - expect(nameFilter(objects, line)).to.eql(getObjects('line')); - }); - - it('gracefully handles a filter function with zero arity', () => { - const objects = getObjects('table', 'line', 'pie'); - const rejectEverything = () => false; - expect(nameFilter(objects, rejectEverything)).to.eql([]); - }); -}); diff --git a/src/legacy/ui/public/agg_types/filter/prop_filter.ts b/src/legacy/ui/public/agg_types/filter/prop_filter.ts deleted file mode 100644 index e6b5f3831e65d..0000000000000 --- a/src/legacy/ui/public/agg_types/filter/prop_filter.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { isFunction } from 'lodash'; - -type FilterFunc

= (item: T[P]) => boolean; - -/** - * Filters out a list by a given filter. This is currently used to implement: - * - fieldType filters a list of fields by their type property - * - aggFilter filters a list of aggs by their name property - * - * @returns the filter function which can be registered with angular - */ -function propFilter

(prop: P) { - /** - * List filtering function which accepts an array or list of values that a property - * must contain - * - * @param {array} list - array of items to filter - * @param {function|array|string} filters - the values to match against the list - * - if a function, it is expected to take the field property as argument and returns true to keep it. - * - Can be also an array, a single value as a string, or a comma-separated list of items - * @return {array} - the filtered list - */ - return function filterByName( - list: T[], - filters: string[] | string | FilterFunc = [] - ): T[] { - if (isFunction(filters)) { - return list.filter(item => (filters as FilterFunc)(item[prop])); - } - - if (!Array.isArray(filters)) { - filters = filters.split(','); - } - - if (filters.length === 0) { - return list; - } - - if (filters.includes('*')) { - return list; - } - - const options = filters.reduce((acc, filter) => { - let type = 'include'; - let value = filter; - - if (filter.charAt(0) === '!') { - type = 'exclude'; - value = filter.substr(1); - } - - if (!acc[type]) { - acc[type] = []; - } - acc[type].push(value); - return acc; - }, {} as { [type: string]: string[] }); - - return list.filter(item => { - const value = item[prop]; - - const excluded = options.exclude && options.exclude.includes(value); - if (excluded) { - return false; - } - - const included = !options.include || options.include.includes(value); - if (included) { - return true; - } - - return false; - }); - }; -} - -export { propFilter }; diff --git a/src/legacy/ui/public/agg_types/index.test.ts b/src/legacy/ui/public/agg_types/index.test.ts deleted file mode 100644 index a867769a77fc1..0000000000000 --- a/src/legacy/ui/public/agg_types/index.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { aggTypes } from './index'; - -import { isBucketAggType } from './buckets/_bucket_agg_type'; -import { isMetricAggType } from './metrics/metric_agg_type'; - -const bucketAggs = aggTypes.buckets; -const metricAggs = aggTypes.metrics; - -jest.mock('ui/new_platform'); - -describe('AggTypesComponent', () => { - describe('bucket aggs', () => { - it('all extend BucketAggType', () => { - bucketAggs.forEach(bucketAgg => { - expect(isBucketAggType(bucketAgg)).toBeTruthy(); - }); - }); - }); - - describe('metric aggs', () => { - it('all extend MetricAggType', () => { - metricAggs.forEach(metricAgg => { - expect(isMetricAggType(metricAgg)).toBeTruthy(); - }); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/index.ts b/src/legacy/ui/public/agg_types/index.ts index cf2733b9a9f36..c7f4dee9a8173 100644 --- a/src/legacy/ui/public/agg_types/index.ts +++ b/src/legacy/ui/public/agg_types/index.ts @@ -17,15 +17,58 @@ * under the License. */ -export { aggTypes } from './agg_types'; -export { AggParam } from './agg_params'; -export { AggConfig } from './agg_config'; -export { AggConfigs } from './agg_configs'; -export { AggGroupNames, aggGroupNamesMap } from './agg_groups'; -export { FieldParamType } from './param_types'; -export { BUCKET_TYPES } from './buckets/bucket_agg_types'; -export { METRIC_TYPES } from './metrics/metric_agg_types'; -export { ISchemas, Schema, Schemas } from './schemas'; -export { AggType } from './agg_type'; -export { setBounds } from './buckets/date_histogram'; -export { termsAggFilter } from './buckets/terms'; +/** + * Nothing to see here! + * + * Agg Types have moved to the data plugin, and are being + * re-exported from ui/agg_types for backwards compatibility. + */ + +import { start as dataStart } from '../../../core_plugins/data/public/legacy'; + +// runtime contracts +export const { + types: aggTypes, + AggConfig, + AggConfigs, + AggType, + aggTypeFieldFilters, + FieldParamType, + parentPipelineAggHelper, + setBounds, +} = dataStart.search.aggs; + +// types +export { + AggParam, + AggParamOption, + BUCKET_TYPES, + DateRangeKey, + IpRangeKey, + ISchemas, + METRIC_TYPES, + OptionedParamEditorProps, + OptionedValueProp, +} from '../../../core_plugins/data/public'; + +// static code +export { + AggParamType, + aggTypeFilters, + AggGroupNames, + aggGroupNamesMap, + CidrMask, + convertDateRangeToString, + convertIPRangeToString, + intervalOptions, + isDateHistogramBucketAggConfig, + isStringType, + isType, + isValidInterval, + isValidJson, + OptionedParamType, + propFilter, + Schema, + Schemas, + termsAggFilter, +} from '../../../core_plugins/data/public'; diff --git a/src/legacy/ui/public/agg_types/metrics/avg.ts b/src/legacy/ui/public/agg_types/metrics/avg.ts deleted file mode 100644 index 0222a8e543223..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/avg.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -const averageTitle = i18n.translate('common.ui.aggTypes.metrics.averageTitle', { - defaultMessage: 'Average', -}); - -export const avgMetricAgg = new MetricAggType({ - name: METRIC_TYPES.AVG, - title: averageTitle, - makeLabel: aggConfig => { - return i18n.translate('common.ui.aggTypes.metrics.averageLabel', { - defaultMessage: 'Average {field}', - values: { field: aggConfig.getFieldDisplayName() }, - }); - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.NUMBER, - }, - ], -}); diff --git a/src/legacy/ui/public/agg_types/metrics/bucket_avg.ts b/src/legacy/ui/public/agg_types/metrics/bucket_avg.ts deleted file mode 100644 index 7142546dbd494..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/bucket_avg.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { get } from 'lodash'; - -import { MetricAggType } from './metric_agg_type'; -import { makeNestedLabel } from './lib/make_nested_label'; -import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; -import { METRIC_TYPES } from './metric_agg_types'; - -const overallAverageLabel = i18n.translate('common.ui.aggTypes.metrics.overallAverageLabel', { - defaultMessage: 'overall average', -}); - -const averageBucketTitle = i18n.translate('common.ui.aggTypes.metrics.averageBucketTitle', { - defaultMessage: 'Average Bucket', -}); - -export const bucketAvgMetricAgg = new MetricAggType({ - name: METRIC_TYPES.AVG_BUCKET, - title: averageBucketTitle, - makeLabel: agg => makeNestedLabel(agg, overallAverageLabel), - subtype: siblingPipelineAggHelper.subtype, - params: [...siblingPipelineAggHelper.params()], - getFormat: siblingPipelineAggHelper.getFormat, - getValue(agg, bucket) { - const customMetric = agg.getParam('customMetric'); - const customBucket = agg.getParam('customBucket'); - const scaleMetrics = customMetric.type && customMetric.type.isScalable(); - - let value = bucket[agg.id] && bucket[agg.id].value; - - if (scaleMetrics && customBucket.type.name === 'date_histogram') { - const aggInfo = customBucket.write(); - - value *= get(aggInfo, 'bucketInterval.scale', 1); - } - return value; - }, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/bucket_max.ts b/src/legacy/ui/public/agg_types/metrics/bucket_max.ts deleted file mode 100644 index aa5b0521709a5..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/bucket_max.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; - -import { MetricAggType } from './metric_agg_type'; -import { makeNestedLabel } from './lib/make_nested_label'; -import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; -import { METRIC_TYPES } from './metric_agg_types'; - -const overallMaxLabel = i18n.translate('common.ui.aggTypes.metrics.overallMaxLabel', { - defaultMessage: 'overall max', -}); - -const maxBucketTitle = i18n.translate('common.ui.aggTypes.metrics.maxBucketTitle', { - defaultMessage: 'Max Bucket', -}); - -export const bucketMaxMetricAgg = new MetricAggType({ - name: METRIC_TYPES.MAX_BUCKET, - title: maxBucketTitle, - makeLabel: agg => makeNestedLabel(agg, overallMaxLabel), - subtype: siblingPipelineAggHelper.subtype, - params: [...siblingPipelineAggHelper.params()], - getFormat: siblingPipelineAggHelper.getFormat, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/bucket_min.ts b/src/legacy/ui/public/agg_types/metrics/bucket_min.ts deleted file mode 100644 index b5c0b8865e106..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/bucket_min.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { makeNestedLabel } from './lib/make_nested_label'; -import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; -import { METRIC_TYPES } from './metric_agg_types'; - -const overallMinLabel = i18n.translate('common.ui.aggTypes.metrics.overallMinLabel', { - defaultMessage: 'overall min', -}); - -const minBucketTitle = i18n.translate('common.ui.aggTypes.metrics.minBucketTitle', { - defaultMessage: 'Min Bucket', -}); - -export const bucketMinMetricAgg = new MetricAggType({ - name: METRIC_TYPES.MIN_BUCKET, - title: minBucketTitle, - makeLabel: agg => makeNestedLabel(agg, overallMinLabel), - subtype: siblingPipelineAggHelper.subtype, - params: [...siblingPipelineAggHelper.params()], - getFormat: siblingPipelineAggHelper.getFormat, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/bucket_sum.ts b/src/legacy/ui/public/agg_types/metrics/bucket_sum.ts deleted file mode 100644 index d4faa81c4041c..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/bucket_sum.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { makeNestedLabel } from './lib/make_nested_label'; -import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; -import { METRIC_TYPES } from './metric_agg_types'; - -const overallSumLabel = i18n.translate('common.ui.aggTypes.metrics.overallSumLabel', { - defaultMessage: 'overall sum', -}); - -const sumBucketTitle = i18n.translate('common.ui.aggTypes.metrics.sumBucketTitle', { - defaultMessage: 'Sum Bucket', -}); - -export const bucketSumMetricAgg = new MetricAggType({ - name: METRIC_TYPES.SUM_BUCKET, - title: sumBucketTitle, - makeLabel: agg => makeNestedLabel(agg, overallSumLabel), - subtype: siblingPipelineAggHelper.subtype, - params: [...siblingPipelineAggHelper.params()], - getFormat: siblingPipelineAggHelper.getFormat, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/cardinality.ts b/src/legacy/ui/public/agg_types/metrics/cardinality.ts deleted file mode 100644 index c69ffae3b4871..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/cardinality.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { npStart } from 'ui/new_platform'; -import { MetricAggType } from './metric_agg_type'; -import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -const uniqueCountTitle = i18n.translate('common.ui.aggTypes.metrics.uniqueCountTitle', { - defaultMessage: 'Unique Count', -}); - -export const cardinalityMetricAgg = new MetricAggType({ - name: METRIC_TYPES.CARDINALITY, - title: uniqueCountTitle, - makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.uniqueCountLabel', { - defaultMessage: 'Unique count of {field}', - values: { field: aggConfig.getFieldDisplayName() }, - }); - }, - getFormat() { - const fieldFormatsService = npStart.plugins.data.fieldFormats; - - return fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER); - }, - params: [ - { - name: 'field', - type: 'field', - }, - ], -}); diff --git a/src/legacy/ui/public/agg_types/metrics/count.ts b/src/legacy/ui/public/agg_types/metrics/count.ts deleted file mode 100644 index 22a939cd9a3fd..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/count.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { npStart } from 'ui/new_platform'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; -import { MetricAggType } from './metric_agg_type'; -import { METRIC_TYPES } from './metric_agg_types'; - -export const countMetricAgg = new MetricAggType({ - name: METRIC_TYPES.COUNT, - title: i18n.translate('common.ui.aggTypes.metrics.countTitle', { - defaultMessage: 'Count', - }), - hasNoDsl: true, - makeLabel() { - return i18n.translate('common.ui.aggTypes.metrics.countLabel', { - defaultMessage: 'Count', - }); - }, - getFormat() { - const fieldFormatsService = npStart.plugins.data.fieldFormats; - - return fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER); - }, - getValue(agg, bucket) { - return bucket.doc_count; - }, - isScalable() { - return true; - }, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/cumulative_sum.ts b/src/legacy/ui/public/agg_types/metrics/cumulative_sum.ts deleted file mode 100644 index bad2de8cb16dc..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/cumulative_sum.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; -import { makeNestedLabel } from './lib/make_nested_label'; -import { METRIC_TYPES } from './metric_agg_types'; - -const cumulativeSumLabel = i18n.translate('common.ui.aggTypes.metrics.cumulativeSumLabel', { - defaultMessage: 'cumulative sum', -}); - -const cumulativeSumTitle = i18n.translate('common.ui.aggTypes.metrics.cumulativeSumTitle', { - defaultMessage: 'Cumulative Sum', -}); - -export const cumulativeSumMetricAgg = new MetricAggType({ - name: METRIC_TYPES.CUMULATIVE_SUM, - title: cumulativeSumTitle, - subtype: parentPipelineAggHelper.subtype, - makeLabel: agg => makeNestedLabel(agg, cumulativeSumLabel), - params: [...parentPipelineAggHelper.params()], - getFormat: parentPipelineAggHelper.getFormat, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/derivative.ts b/src/legacy/ui/public/agg_types/metrics/derivative.ts deleted file mode 100644 index 42921621a2933..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/derivative.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; -import { makeNestedLabel } from './lib/make_nested_label'; -import { METRIC_TYPES } from './metric_agg_types'; - -const derivativeLabel = i18n.translate('common.ui.aggTypes.metrics.derivativeLabel', { - defaultMessage: 'derivative', -}); - -const derivativeTitle = i18n.translate('common.ui.aggTypes.metrics.derivativeTitle', { - defaultMessage: 'Derivative', -}); - -export const derivativeMetricAgg = new MetricAggType({ - name: METRIC_TYPES.DERIVATIVE, - title: derivativeTitle, - subtype: parentPipelineAggHelper.subtype, - makeLabel(agg) { - return makeNestedLabel(agg, derivativeLabel); - }, - params: [...parentPipelineAggHelper.params()], - getFormat: parentPipelineAggHelper.getFormat, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/geo_bounds.ts b/src/legacy/ui/public/agg_types/metrics/geo_bounds.ts deleted file mode 100644 index b8ce03cdf11ec..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/geo_bounds.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -const geoBoundsTitle = i18n.translate('common.ui.aggTypes.metrics.geoBoundsTitle', { - defaultMessage: 'Geo Bounds', -}); - -const geoBoundsLabel = i18n.translate('common.ui.aggTypes.metrics.geoBoundsLabel', { - defaultMessage: 'Geo Bounds', -}); - -export const geoBoundsMetricAgg = new MetricAggType({ - name: METRIC_TYPES.GEO_BOUNDS, - title: geoBoundsTitle, - makeLabel: () => geoBoundsLabel, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT, - }, - ], -}); diff --git a/src/legacy/ui/public/agg_types/metrics/geo_centroid.ts b/src/legacy/ui/public/agg_types/metrics/geo_centroid.ts deleted file mode 100644 index 5313e31796a5b..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/geo_centroid.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -const geoCentroidTitle = i18n.translate('common.ui.aggTypes.metrics.geoCentroidTitle', { - defaultMessage: 'Geo Centroid', -}); - -const geoCentroidLabel = i18n.translate('common.ui.aggTypes.metrics.geoCentroidLabel', { - defaultMessage: 'Geo Centroid', -}); - -export const geoCentroidMetricAgg = new MetricAggType({ - name: METRIC_TYPES.GEO_CENTROID, - title: geoCentroidTitle, - makeLabel: () => geoCentroidLabel, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT, - }, - ], - getValue(agg, bucket) { - return bucket[agg.id] && bucket[agg.id].location; - }, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/lib/get_response_agg_config_class.ts b/src/legacy/ui/public/agg_types/metrics/lib/get_response_agg_config_class.ts deleted file mode 100644 index 054543de3dd06..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/lib/get_response_agg_config_class.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { assign } from 'lodash'; -import { IMetricAggConfig } from '../metric_agg_type'; - -/** - * 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 const getResponseAggConfigClass = (agg: any, props: Partial) => { - if (agg.$$_ResponseAggConfigClass) { - return agg.$$_ResponseAggConfigClass; - } else { - return (agg.$$_ResponseAggConfigClass = create(agg, props)); - } -}; - -export interface IResponseAggConfig extends IMetricAggConfig { - key: string | number; - parentId: IMetricAggConfig['id']; -} - -export const create = (parentAgg: IMetricAggConfig, props: Partial) => { - /** - * 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(this: IResponseAggConfig, key: string) { - const parentId = parentAgg.id; - let id; - - const subId = String(key); - - if (subId.indexOf('.') > -1) { - id = parentId + "['" + subId.replace(/'/g, "\\'") + "']"; - } else { - id = parentId + '.' + subId; - } - - this.id = id; - this.key = key; - this.parentId = parentId; - } - - ResponseAggConfig.prototype = Object.create(parentAgg); - ResponseAggConfig.prototype.constructor = ResponseAggConfig; - - assign(ResponseAggConfig.prototype, props); - - return ResponseAggConfig; -}; diff --git a/src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.test.ts b/src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.test.ts deleted file mode 100644 index 479ff40b7c0ae..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { makeNestedLabel } from './make_nested_label'; -import { IMetricAggConfig } from '../metric_agg_type'; - -describe('metric agg make_nested_label', () => { - const generateAggConfig = (metricLabel: string): IMetricAggConfig => { - return ({ - params: { - customMetric: { - makeLabel: () => { - return metricLabel; - }, - }, - }, - getParam(this: IMetricAggConfig, key: string) { - return this.params[key]; - }, - } as unknown) as IMetricAggConfig; - }; - - it('should return a metric label with prefix', () => { - const aggConfig = generateAggConfig('Count'); - const label = makeNestedLabel(aggConfig, 'derivative'); - - expect(label).toEqual('Derivative of Count'); - }); - - it('should return a numbered prefix', () => { - const aggConfig = generateAggConfig('Derivative of Count'); - const label = makeNestedLabel(aggConfig, 'derivative'); - - expect(label).toEqual('2. derivative of Count'); - }); - - it('should return a prefix with correct order', () => { - const aggConfig = generateAggConfig('3. derivative of Count'); - const label = makeNestedLabel(aggConfig, 'derivative'); - - expect(label).toEqual('4. derivative of Count'); - }); -}); diff --git a/src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.ts b/src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.ts deleted file mode 100644 index 95bcdf6e99fd9..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { startCase } from 'lodash'; -import { IMetricAggConfig } from '../metric_agg_type'; - -export const makeNestedLabel = (aggConfig: IMetricAggConfig, label: string) => { - const uppercaseLabel = startCase(label); - const customMetric = aggConfig.getParam('customMetric'); - const metricAgg = aggConfig.getParam('metricAgg'); - - if (customMetric) { - let metricLabel = customMetric.makeLabel(); - - if (metricLabel.includes(`${uppercaseLabel} of `)) { - metricLabel = metricLabel.substring(`${uppercaseLabel} of `.length); - metricLabel = `2. ${label} of ${metricLabel}`; - } else if (metricLabel.includes(`${label} of `)) { - metricLabel = parseInt(metricLabel.substring(0, 1), 10) + 1 + metricLabel.substring(1); - } else { - metricLabel = `${uppercaseLabel} of ${metricLabel}`; - } - return metricLabel; - } - - const metric = aggConfig.aggConfigs.byId(metricAgg); - - if (!metric) { - return ''; - } - - return `${uppercaseLabel} of ${metric.makeLabel()}`; -}; diff --git a/src/legacy/ui/public/agg_types/metrics/lib/nested_agg_helpers.ts b/src/legacy/ui/public/agg_types/metrics/lib/nested_agg_helpers.ts deleted file mode 100644 index a7bfb7b82b97f..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/lib/nested_agg_helpers.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; - -/** - * Forwards modifyAggConfigOnSearchRequestStart calls to a nested AggConfig. - * This must be used for each parameter, that accepts a nested aggregation, otherwise - * some parameters of the nested aggregation might not work properly (like auto interval - * on a nested date histogram). - * You should assign the return value of this function to the modifyAggConfigOnSearchRequestStart - * of the parameter that accepts a nested aggregation. Example: - * { - * name: 'customBucket', - * modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart('customBucket') - * } - * - * @param {string} paramName - The name of the parameter, that this function should forward - * calls to. That should match the name of the parameter the function is called on. - * @returns {function} A function, that forwards the calls. - */ -export const forwardModifyAggConfigOnSearchRequestStart = (paramName: string) => { - return (aggConfig: IMetricAggConfig, searchSource?: any, request?: any) => { - if (!aggConfig || !aggConfig.params) { - return; - } - - const nestedAggConfig = aggConfig.getParam(paramName); - - if (nestedAggConfig && nestedAggConfig.type && nestedAggConfig.type.params) { - nestedAggConfig.type.params.forEach((param: MetricAggParam) => { - // Check if this parameter of the nested aggConfig has a modifyAggConfigOnSearchRequestStart - // function, that needs to be called. - if (param.modifyAggConfigOnSearchRequestStart) { - param.modifyAggConfigOnSearchRequestStart(nestedAggConfig, searchSource, request); - } - }); - } - }; -}; diff --git a/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.test.ts b/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.test.ts deleted file mode 100644 index 18ee6b4de3204..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { forOwn } from 'lodash'; -import { ordinalSuffix } from './ordinal_suffix'; - -describe('ordinal suffix util', () => { - const checks = { - 1: 'st', - 2: 'nd', - 3: 'rd', - 4: 'th', - 5: 'th', - 6: 'th', - 7: 'th', - 8: 'th', - 9: 'th', - 10: 'th', - 11: 'th', - 12: 'th', - 13: 'th', - 14: 'th', - 15: 'th', - 16: 'th', - 17: 'th', - 18: 'th', - 19: 'th', - 20: 'th', - 21: 'st', - 22: 'nd', - 23: 'rd', - 24: 'th', - 25: 'th', - 26: 'th', - 27: 'th', - 28: 'th', - 29: 'th', - 30: 'th', - }; - - forOwn(checks, (expected, num: any) => { - const int = parseInt(num, 10); - const float = int + Math.random(); - - it('knowns ' + int, () => { - expect(ordinalSuffix(num)).toBe(num + '' + expected); - }); - - it('knows ' + float, () => { - expect(ordinalSuffix(num)).toBe(num + '' + expected); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.ts b/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.ts deleted file mode 100644 index 21903995ebb2f..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -// adopted from http://stackoverflow.com/questions/3109978/php-display-number-with-ordinal-suffix -export function ordinalSuffix(num: any): string { - return num + '' + suffix(num); -} - -function suffix(num: any): string { - const int = Math.floor(parseFloat(num)); - - const hunth = int % 100; - if (hunth >= 11 && hunth <= 13) return 'th'; - - const tenth = int % 10; - if (tenth === 1) return 'st'; - if (tenth === 2) return 'nd'; - if (tenth === 3) return 'rd'; - return 'th'; -} diff --git a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts b/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts index 4d558e50304e6..26acf3c024592 100644 --- a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts +++ b/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts @@ -17,91 +17,4 @@ * under the License. */ -import { i18n } from '@kbn/i18n'; -import { noop } from 'lodash'; - -import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; -import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; -import { parentPipelineAggWriter } from './parent_pipeline_agg_writer'; - -import { Schemas } from '../../schemas'; - -const metricAggFilter = [ - '!top_hits', - '!percentiles', - '!percentile_ranks', - '!median', - '!std_dev', - '!geo_bounds', - '!geo_centroid', -]; - -const metricAggTitle = i18n.translate('common.ui.aggTypes.metrics.metricAggTitle', { - defaultMessage: 'Metric agg', -}); - -const [metricAggSchema] = new Schemas([ - { - group: 'none', - name: 'metricAgg', - title: metricAggTitle, - hideCustomLabel: true, - aggFilter: metricAggFilter, - }, -]).all; - -const parentPipelineType = i18n.translate( - 'common.ui.aggTypes.metrics.parentPipelineAggregationsSubtypeTitle', - { - defaultMessage: 'Parent Pipeline Aggregations', - } -); - -const parentPipelineAggHelper = { - subtype: parentPipelineType, - params() { - return [ - { - name: 'metricAgg', - default: 'custom', - write: parentPipelineAggWriter, - }, - { - name: 'customMetric', - type: 'agg', - makeAgg(termsAgg, state: any) { - state = state || { type: 'count' }; - state.schema = metricAggSchema; - - const metricAgg = termsAgg.aggConfigs.createAggConfig(state, { addToAggConfigs: false }); - - metricAgg.id = termsAgg.id + '-metric'; - - return metricAgg; - }, - modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart( - 'customMetric' - ), - write: noop, - }, - { - name: 'buckets_path', - write: noop, - }, - ] as Array>; - }, - - getFormat(agg: IMetricAggConfig) { - let subAgg; - const customMetric = agg.getParam('customMetric'); - - if (customMetric) { - subAgg = customMetric; - } else { - subAgg = agg.aggConfigs.byId(agg.getParam('metricAgg')); - } - return subAgg.type.getFormat(subAgg); - }, -}; - -export { parentPipelineAggHelper, parentPipelineType }; +export { parentPipelineAggHelper } from '../../index'; diff --git a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_writer.ts b/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_writer.ts deleted file mode 100644 index 684fe721a754a..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_writer.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { AggConfigs } from '../../agg_configs'; -import { IMetricAggConfig } from '../metric_agg_type'; - -export const parentPipelineAggWriter = ( - agg: IMetricAggConfig, - output: Record, - aggConfigs?: AggConfigs -): void => { - const customMetric = agg.getParam('customMetric'); - const metricAgg = agg.getParam('metricAgg'); - - const selectedMetric = customMetric || (aggConfigs && aggConfigs.getResponseAggById(metricAgg)); - - if (customMetric && customMetric.type.name !== 'count') { - output.parentAggs = (output.parentAggs || []).concat(selectedMetric); - } - - output.params = { - buckets_path: selectedMetric.type.name === 'count' ? '_count' : selectedMetric.id, - }; -}; diff --git a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts b/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts deleted file mode 100644 index 9dd737bd6708e..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { siblingPipelineAggWriter } from './sibling_pipeline_agg_writer'; -import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; - -import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; -import { Schemas } from '../../schemas'; - -const metricAggFilter: string[] = [ - '!top_hits', - '!percentiles', - '!percentile_ranks', - '!median', - '!std_dev', - '!sum_bucket', - '!avg_bucket', - '!min_bucket', - '!max_bucket', - '!derivative', - '!moving_avg', - '!serial_diff', - '!cumulative_sum', - '!geo_bounds', - '!geo_centroid', -]; -const bucketAggFilter: string[] = []; - -const [metricAggSchema] = new Schemas([ - { - group: 'none', - name: 'metricAgg', - title: i18n.translate('common.ui.aggTypes.metrics.metricAggTitle', { - defaultMessage: 'Metric agg', - }), - aggFilter: metricAggFilter, - }, -]).all; - -const [bucketAggSchema] = new Schemas([ - { - group: 'none', - title: i18n.translate('common.ui.aggTypes.metrics.bucketAggTitle', { - defaultMessage: 'Bucket agg', - }), - name: 'bucketAgg', - aggFilter: bucketAggFilter, - }, -]).all; - -const siblingPipelineType = i18n.translate( - 'common.ui.aggTypes.metrics.siblingPipelineAggregationsSubtypeTitle', - { - defaultMessage: 'Sibling pipeline aggregations', - } -); - -const siblingPipelineAggHelper = { - subtype: siblingPipelineType, - params() { - return [ - { - name: 'customBucket', - type: 'agg', - default: null, - makeAgg(agg: IMetricAggConfig, state: any) { - state = state || { type: 'date_histogram' }; - state.schema = bucketAggSchema; - const orderAgg = agg.aggConfigs.createAggConfig(state, { addToAggConfigs: false }); - orderAgg.id = agg.id + '-bucket'; - - return orderAgg; - }, - modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart( - 'customBucket' - ), - write: () => {}, - }, - { - name: 'customMetric', - type: 'agg', - default: null, - makeAgg(agg: IMetricAggConfig, state: any) { - state = state || { type: 'count' }; - state.schema = metricAggSchema; - const orderAgg = agg.aggConfigs.createAggConfig(state, { addToAggConfigs: false }); - orderAgg.id = agg.id + '-metric'; - - return orderAgg; - }, - modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart( - 'customMetric' - ), - write: siblingPipelineAggWriter, - }, - ] as Array>; - }, - - getFormat(agg: IMetricAggConfig) { - const customMetric = agg.getParam('customMetric'); - - return customMetric.type.getFormat(customMetric); - }, -}; - -export { siblingPipelineAggHelper, siblingPipelineType }; diff --git a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_writer.ts b/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_writer.ts deleted file mode 100644 index acdce8cb5f171..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_writer.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IMetricAggConfig } from '../metric_agg_type'; -import { METRIC_TYPES } from '../metric_agg_types'; - -export const siblingPipelineAggWriter = (agg: IMetricAggConfig, output: Record) => { - const customMetric = agg.getParam('customMetric'); - - if (!customMetric) return; - - const metricAgg = customMetric; - const bucketAgg = agg.getParam('customBucket'); - - // if a bucket is selected, we must add this agg as a sibling to it, and add a metric to that bucket (or select one of its) - if (metricAgg.type.name !== METRIC_TYPES.COUNT) { - bucketAgg.subAggs = (output.subAggs || []).concat(metricAgg); - output.params.buckets_path = `${bucketAgg.id}>${metricAgg.id}`; - } else { - output.params.buckets_path = bucketAgg.id + '>_count'; - } - - output.parentAggs = (output.parentAggs || []).concat(bucketAgg); -}; diff --git a/src/legacy/ui/public/agg_types/metrics/max.ts b/src/legacy/ui/public/agg_types/metrics/max.ts deleted file mode 100644 index 5c43511acee72..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/max.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -const maxTitle = i18n.translate('common.ui.aggTypes.metrics.maxTitle', { - defaultMessage: 'Max', -}); - -export const maxMetricAgg = new MetricAggType({ - name: METRIC_TYPES.MAX, - title: maxTitle, - makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.maxLabel', { - defaultMessage: 'Max {field}', - values: { field: aggConfig.getFieldDisplayName() }, - }); - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE], - }, - ], -}); diff --git a/src/legacy/ui/public/agg_types/metrics/median.test.ts b/src/legacy/ui/public/agg_types/metrics/median.test.ts deleted file mode 100644 index 819c24f135cdc..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/median.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { AggConfigs } from '../agg_configs'; -import { METRIC_TYPES } from './metric_agg_types'; - -jest.mock('ui/new_platform'); - -describe('AggTypeMetricMedianProvider class', () => { - let aggConfigs: AggConfigs; - - beforeEach(() => { - const field = { - name: 'bytes', - }; - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - aggConfigs = new AggConfigs( - indexPattern, - [ - { - id: METRIC_TYPES.MEDIAN, - type: METRIC_TYPES.MEDIAN, - schema: 'metric', - params: { - field: 'bytes', - percents: [70], - }, - }, - ], - null - ); - }); - - it('requests the percentiles aggregation in the Elasticsearch query DSL', () => { - const dsl: Record = aggConfigs.toDsl(); - - expect(dsl.median.percentiles.percents).toEqual([70]); - }); - - it('asks Elasticsearch for array-based values in the aggregation response', () => { - const dsl: Record = aggConfigs.toDsl(); - - expect(dsl.median.percentiles.keyed).toBeFalsy(); - }); -}); diff --git a/src/legacy/ui/public/agg_types/metrics/median.ts b/src/legacy/ui/public/agg_types/metrics/median.ts deleted file mode 100644 index 5792d4a7c2ba3..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/median.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { METRIC_TYPES } from './metric_agg_types'; - -// @ts-ignore -import { percentilesMetricAgg } from './percentiles'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -const medianTitle = i18n.translate('common.ui.aggTypes.metrics.medianTitle', { - defaultMessage: 'Median', -}); - -export const medianMetricAgg = new MetricAggType({ - name: METRIC_TYPES.MEDIAN, - dslName: 'percentiles', - title: medianTitle, - makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.medianLabel', { - defaultMessage: 'Median {field}', - values: { field: aggConfig.getFieldDisplayName() }, - }); - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE], - }, - { - name: 'percents', - default: [50], - }, - { - write(agg, output) { - output.params.keyed = false; - }, - }, - ], - getResponseAggs: percentilesMetricAgg.getResponseAggs, - getValue: percentilesMetricAgg.getValue, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts b/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts deleted file mode 100644 index 5cd3dffb10b9d..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { npStart } from 'ui/new_platform'; -import { AggType, AggTypeConfig } from '../agg_type'; -import { AggParamType } from '../param_types/agg'; -import { AggConfig } from '../agg_config'; -import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -export interface IMetricAggConfig extends AggConfig { - type: InstanceType; -} - -export interface MetricAggParam - extends AggParamType { - filterFieldTypes?: KBN_FIELD_TYPES | KBN_FIELD_TYPES[] | '*'; - onlyAggregatable?: boolean; -} - -const metricType = 'metrics'; - -interface MetricAggTypeConfig - extends AggTypeConfig> { - isScalable?: () => boolean; - subtype?: string; -} - -export class MetricAggType extends AggType< - TMetricAggConfig, - MetricAggParam -> { - subtype: string; - isScalable: () => boolean; - type = metricType; - - getKey = () => {}; - - constructor(config: MetricAggTypeConfig) { - super(config); - - this.getValue = - config.getValue || - ((agg, bucket) => { - // Metric types where an empty set equals `zero` - const isSettableToZero = [METRIC_TYPES.CARDINALITY, METRIC_TYPES.SUM].includes( - agg.type.name as METRIC_TYPES - ); - - // 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; - }); - - this.getFormat = - config.getFormat || - (agg => { - const fieldFormatsService = npStart.plugins.data.fieldFormats; - const field = agg.getField(); - return field - ? field.format - : fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER); - }); - - this.subtype = - config.subtype || - i18n.translate('common.ui.aggTypes.metrics.metricAggregationsSubtypeTitle', { - defaultMessage: 'Metric Aggregations', - }); - - this.isScalable = config.isScalable || (() => false); - } -} - -export function isMetricAggType(aggConfig: any): aggConfig is MetricAggType { - return aggConfig && aggConfig.type === metricType; -} diff --git a/src/legacy/ui/public/agg_types/metrics/metric_agg_types.ts b/src/legacy/ui/public/agg_types/metrics/metric_agg_types.ts deleted file mode 100644 index ae9904ffcfa6b..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/metric_agg_types.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export enum METRIC_TYPES { - AVG = 'avg', - CARDINALITY = 'cardinality', - AVG_BUCKET = 'avg_bucket', - MAX_BUCKET = 'max_bucket', - MIN_BUCKET = 'min_bucket', - SUM_BUCKET = 'sum_bucket', - COUNT = 'count', - CUMULATIVE_SUM = 'cumulative_sum', - DERIVATIVE = 'derivative', - GEO_BOUNDS = 'geo_bounds', - GEO_CENTROID = 'geo_centroid', - MEDIAN = 'median', - MIN = 'min', - MAX = 'max', - MOVING_FN = 'moving_avg', - SERIAL_DIFF = 'serial_diff', - SUM = 'sum', - TOP_HITS = 'top_hits', - PERCENTILES = 'percentiles', - PERCENTILE_RANKS = 'percentile_ranks', - STD_DEV = 'std_dev', -} diff --git a/src/legacy/ui/public/agg_types/metrics/min.ts b/src/legacy/ui/public/agg_types/metrics/min.ts deleted file mode 100644 index 5f8ca72954cc2..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/min.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -const minTitle = i18n.translate('common.ui.aggTypes.metrics.minTitle', { - defaultMessage: 'Min', -}); - -export const minMetricAgg = new MetricAggType({ - name: METRIC_TYPES.MIN, - title: minTitle, - makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.minLabel', { - defaultMessage: 'Min {field}', - values: { field: aggConfig.getFieldDisplayName() }, - }); - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE], - }, - ], -}); diff --git a/src/legacy/ui/public/agg_types/metrics/moving_avg.ts b/src/legacy/ui/public/agg_types/metrics/moving_avg.ts deleted file mode 100644 index b6a8e7a5d6a99..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/moving_avg.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; -import { makeNestedLabel } from './lib/make_nested_label'; -import { METRIC_TYPES } from './metric_agg_types'; - -const movingAvgTitle = i18n.translate('common.ui.aggTypes.metrics.movingAvgTitle', { - defaultMessage: 'Moving Avg', -}); - -const movingAvgLabel = i18n.translate('common.ui.aggTypes.metrics.movingAvgLabel', { - defaultMessage: 'moving avg', -}); - -export const movingAvgMetricAgg = new MetricAggType({ - name: METRIC_TYPES.MOVING_FN, - dslName: 'moving_fn', - title: movingAvgTitle, - subtype: parentPipelineAggHelper.subtype, - makeLabel: agg => makeNestedLabel(agg, movingAvgLabel), - params: [ - ...parentPipelineAggHelper.params(), - { - name: 'window', - default: 5, - }, - { - name: 'script', - default: 'MovingFunctions.unweightedAvg(values)', - }, - ], - getValue(agg, bucket) { - /** - * The previous implementation using `moving_avg` did not - * return any bucket in case there are no documents or empty window. - * The `moving_fn` aggregation returns buckets with the value null if the - * window is empty or doesn't return any value if the sibiling metric - * is null. Since our generic MetricAggType.getValue implementation - * would return the value 0 for null buckets, we need a specific - * implementation here, that preserves the null value. - */ - return bucket[agg.id] ? bucket[agg.id].value : null; - }, - getFormat: parentPipelineAggHelper.getFormat, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/parent_pipeline.test.ts b/src/legacy/ui/public/agg_types/metrics/parent_pipeline.test.ts deleted file mode 100644 index 11fc39c20bdc4..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/parent_pipeline.test.ts +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import sinon from 'sinon'; -import { derivativeMetricAgg } from './derivative'; -import { cumulativeSumMetricAgg } from './cumulative_sum'; -import { movingAvgMetricAgg } from './moving_avg'; -import { serialDiffMetricAgg } from './serial_diff'; -import { AggConfigs } from '../agg_configs'; -import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; - -jest.mock('../schemas', () => { - class MockedSchemas { - all = [{}]; - } - return { - Schemas: jest.fn().mockImplementation(() => new MockedSchemas()), - }; -}); - -jest.mock('ui/new_platform'); - -describe('parent pipeline aggs', function() { - const metrics = [ - { name: 'derivative', title: 'Derivative', provider: derivativeMetricAgg }, - { name: 'cumulative_sum', title: 'Cumulative Sum', provider: cumulativeSumMetricAgg }, - { name: 'moving_avg', title: 'Moving Avg', provider: movingAvgMetricAgg, dslName: 'moving_fn' }, - { name: 'serial_diff', title: 'Serial Diff', provider: serialDiffMetricAgg }, - ]; - - metrics.forEach(metric => { - describe(`${metric.title} metric`, () => { - let aggDsl: Record; - let metricAgg: MetricAggType; - let aggConfig: IMetricAggConfig; - - const init = ( - params: any = { - metricAgg: '1', - customMetric: null, - } - ) => { - const field = { - name: 'field', - format: { - type: { - id: 'bytes', - }, - }, - }; - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - const aggConfigs = new AggConfigs( - indexPattern, - [ - { - id: '1', - type: 'count', - schema: 'metric', - }, - { - id: '2', - type: metric.name, - schema: 'metric', - params, - }, - { - id: '3', - type: 'max', - params: { field: 'field' }, - schema: 'metric', - }, - ], - null - ); - - // Grab the aggConfig off the vis (we don't actually use the vis for anything else) - metricAgg = metric.provider; - aggConfig = aggConfigs.aggs[1] as IMetricAggConfig; - aggDsl = aggConfig.toDsl(aggConfigs); - }; - - it(`should return a label prefixed with ${metric.title} of`, () => { - init(); - - expect(metricAgg.makeLabel(aggConfig)).toEqual(`${metric.title} of Count`); - }); - - it(`should return a label ${metric.title} of max bytes`, () => { - init({ - metricAgg: 'custom', - customMetric: { - id: '1-orderAgg', - type: 'max', - params: { field: 'field' }, - schema: 'orderAgg', - }, - }); - expect(metricAgg.makeLabel(aggConfig)).toEqual(`${metric.title} of Max field`); - }); - - it(`should return a label prefixed with number of ${metric.title.toLowerCase()}`, () => { - init({ - metricAgg: 'custom', - customMetric: { - id: '2-orderAgg', - type: metric.name, - params: { - buckets_path: 'custom', - customMetric: { - id: '2-orderAgg-orderAgg', - type: 'count', - schema: 'orderAgg', - }, - }, - schema: 'orderAgg', - }, - }); - expect(metricAgg.makeLabel(aggConfig)).toEqual(`2. ${metric.title.toLowerCase()} of Count`); - }); - - it('should set parent aggs', () => { - init({ - metricAgg: 'custom', - customMetric: { - id: '2-metric', - type: 'max', - params: { field: 'field' }, - schema: 'orderAgg', - }, - }); - expect(aggDsl[metric.dslName || metric.name].buckets_path).toBe('2-metric'); - expect(aggDsl.parentAggs['2-metric'].max.field).toBe('field'); - }); - - it('should set nested parent aggs', () => { - init({ - metricAgg: 'custom', - customMetric: { - id: '2-metric', - type: metric.name, - params: { - buckets_path: 'custom', - customMetric: { - id: '2-metric-metric', - type: 'max', - params: { field: 'field' }, - schema: 'orderAgg', - }, - }, - schema: 'orderAgg', - }, - }); - expect(aggDsl[metric.dslName || metric.name].buckets_path).toBe('2-metric'); - expect(aggDsl.parentAggs['2-metric'][metric.dslName || metric.name].buckets_path).toBe( - '2-metric-metric' - ); - }); - - it('should have correct formatter', () => { - init({ - metricAgg: '3', - }); - expect(metricAgg.getFormat(aggConfig).type.id).toBe('bytes'); - }); - - it('should have correct customMetric nested formatter', () => { - init({ - metricAgg: 'custom', - customMetric: { - id: '2-metric', - type: metric.name, - params: { - buckets_path: 'custom', - customMetric: { - id: '2-metric-metric', - type: 'max', - params: { field: 'field' }, - schema: 'orderAgg', - }, - }, - schema: 'orderAgg', - }, - }); - expect(metricAgg.getFormat(aggConfig).type.id).toBe('bytes'); - }); - - it("should call modifyAggConfigOnSearchRequestStart for its customMetric's parameters", () => { - init({ - metricAgg: 'custom', - customMetric: { - id: '2-metric', - type: 'max', - params: { field: 'field' }, - schema: 'orderAgg', - }, - }); - - const searchSource: any = {}; - const customMetricSpy = sinon.spy(); - const customMetric = aggConfig.params.customMetric; - - // Attach a modifyAggConfigOnSearchRequestStart with a spy to the first parameter - customMetric.type.params[0].modifyAggConfigOnSearchRequestStart = customMetricSpy; - - aggConfig.type.params.forEach(param => { - param.modifyAggConfigOnSearchRequestStart(aggConfig, searchSource); - }); - expect(customMetricSpy.calledWith(customMetric, searchSource)).toBe(true); - }); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/metrics/percentile_ranks.test.ts b/src/legacy/ui/public/agg_types/metrics/percentile_ranks.test.ts deleted file mode 100644 index 7461b5cf07ee7..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/percentile_ranks.test.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IPercentileRanksAggConfig, percentileRanksMetricAgg } from './percentile_ranks'; -import { AggConfigs } from '../agg_configs'; -import { METRIC_TYPES } from './metric_agg_types'; - -jest.mock('ui/new_platform'); - -describe('AggTypesMetricsPercentileRanksProvider class', function() { - let aggConfigs: AggConfigs; - - beforeEach(() => { - const field = { - name: 'bytes', - }; - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - aggConfigs = new AggConfigs( - indexPattern, - [ - { - id: METRIC_TYPES.PERCENTILE_RANKS, - type: METRIC_TYPES.PERCENTILE_RANKS, - schema: 'metric', - params: { - field: { - displayName: 'bytes', - format: { - convert: jest.fn(x => x), - }, - }, - customLabel: 'my custom field label', - values: [5000, 10000], - }, - }, - ], - null - ); - }); - - it('uses the custom label if it is set', function() { - const responseAggs: any = percentileRanksMetricAgg.getResponseAggs( - aggConfigs.aggs[0] as IPercentileRanksAggConfig - ); - - const percentileRankLabelFor5kBytes = responseAggs[0].makeLabel(); - const percentileRankLabelFor10kBytes = responseAggs[1].makeLabel(); - - expect(percentileRankLabelFor5kBytes).toBe('Percentile rank 5000 of "my custom field label"'); - expect(percentileRankLabelFor10kBytes).toBe('Percentile rank 10000 of "my custom field label"'); - }); -}); diff --git a/src/legacy/ui/public/agg_types/metrics/percentile_ranks.ts b/src/legacy/ui/public/agg_types/metrics/percentile_ranks.ts deleted file mode 100644 index cbd46e3f5b28d..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/percentile_ranks.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { npStart } from 'ui/new_platform'; -import { MetricAggType } from './metric_agg_type'; -import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; - -import { getPercentileValue } from './percentiles_get_value'; -import { METRIC_TYPES } from './metric_agg_types'; -import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -// required by the values editor - -export type IPercentileRanksAggConfig = IResponseAggConfig; - -const getFieldFormats = () => npStart.plugins.data.fieldFormats; - -const valueProps = { - makeLabel(this: IPercentileRanksAggConfig) { - const fieldFormatsService = getFieldFormats(); - const field = this.getField(); - const format = - (field && field.format) || fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER); - const customLabel = this.getParam('customLabel'); - const label = customLabel || this.getFieldDisplayName(); - - return i18n.translate('common.ui.aggTypes.metrics.percentileRanks.valuePropsLabel', { - defaultMessage: 'Percentile rank {format} of "{label}"', - values: { format: format.convert(this.key, 'text'), label }, - }); - }, -}; - -export const percentileRanksMetricAgg = new MetricAggType({ - name: METRIC_TYPES.PERCENTILE_RANKS, - title: i18n.translate('common.ui.aggTypes.metrics.percentileRanksTitle', { - defaultMessage: 'Percentile Ranks', - }), - makeLabel(agg) { - return i18n.translate('common.ui.aggTypes.metrics.percentileRanksLabel', { - defaultMessage: 'Percentile ranks of {field}', - values: { field: agg.getFieldDisplayName() }, - }); - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.NUMBER, - }, - { - name: 'values', - default: [], - }, - { - write(agg, output) { - output.params.keyed = false; - }, - }, - ], - getResponseAggs(agg) { - const ValueAggConfig = getResponseAggConfigClass(agg, valueProps); - const values = agg.getParam('values'); - - return values.map((value: any) => new ValueAggConfig(value)); - }, - getFormat() { - const fieldFormatsService = getFieldFormats(); - return ( - fieldFormatsService.getInstance(fieldFormats.FIELD_FORMAT_IDS.PERCENT) || - fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER) - ); - }, - getValue(agg, bucket) { - return getPercentileValue(agg, bucket) / 100; - }, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/percentiles.test.ts b/src/legacy/ui/public/agg_types/metrics/percentiles.test.ts deleted file mode 100644 index c9f4bcc3862a0..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/percentiles.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IPercentileAggConfig, percentilesMetricAgg } from './percentiles'; -import { AggConfigs } from '../agg_configs'; -import { METRIC_TYPES } from './metric_agg_types'; - -jest.mock('ui/new_platform'); - -describe('AggTypesMetricsPercentilesProvider class', () => { - let aggConfigs: AggConfigs; - - beforeEach(() => { - const field = { - name: 'bytes', - }; - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - aggConfigs = new AggConfigs( - indexPattern, - [ - { - id: METRIC_TYPES.PERCENTILES, - type: METRIC_TYPES.PERCENTILES, - schema: 'metric', - params: { - field: { - displayName: 'bytes', - format: { - convert: jest.fn(x => `${x}th`), - }, - }, - customLabel: 'prince', - percents: [95], - }, - }, - ], - null - ); - }); - - it('uses the custom label if it is set', () => { - const responseAggs: any = percentilesMetricAgg.getResponseAggs( - aggConfigs.aggs[0] as IPercentileAggConfig - ); - - const ninetyFifthPercentileLabel = responseAggs[0].makeLabel(); - - expect(ninetyFifthPercentileLabel).toBe('95th percentile of prince'); - }); -}); diff --git a/src/legacy/ui/public/agg_types/metrics/percentiles.ts b/src/legacy/ui/public/agg_types/metrics/percentiles.ts deleted file mode 100644 index 040324d8da5df..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/percentiles.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; - -import { MetricAggType } from './metric_agg_type'; -import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; -import { getPercentileValue } from './percentiles_get_value'; - -// @ts-ignore -import { ordinalSuffix } from './lib/ordinal_suffix'; - -export type IPercentileAggConfig = IResponseAggConfig; - -const valueProps = { - makeLabel(this: IPercentileAggConfig) { - const customLabel = this.getParam('customLabel'); - const label = customLabel || this.getFieldDisplayName(); - - return i18n.translate('common.ui.aggTypes.metrics.percentiles.valuePropsLabel', { - defaultMessage: '{percentile} percentile of {label}', - values: { percentile: ordinalSuffix(this.key), label }, - }); - }, -}; - -export const percentilesMetricAgg = new MetricAggType({ - name: METRIC_TYPES.PERCENTILES, - title: i18n.translate('common.ui.aggTypes.metrics.percentilesTitle', { - defaultMessage: 'Percentiles', - }), - makeLabel(agg) { - return i18n.translate('common.ui.aggTypes.metrics.percentilesLabel', { - defaultMessage: 'Percentiles of {field}', - values: { field: agg.getFieldDisplayName() }, - }); - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE], - }, - { - name: 'percents', - default: [1, 5, 25, 50, 75, 95, 99], - }, - { - write(agg, output) { - output.params.keyed = false; - }, - }, - ], - getResponseAggs(agg) { - const ValueAggConfig = getResponseAggConfigClass(agg, valueProps); - - return agg.getParam('percents').map((percent: any) => new ValueAggConfig(percent)); - }, - - getValue: getPercentileValue, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/percentiles_get_value.ts b/src/legacy/ui/public/agg_types/metrics/percentiles_get_value.ts deleted file mode 100644 index c357d7bb0a903..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/percentiles_get_value.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { find } from 'lodash'; -import { IResponseAggConfig } from './lib/get_response_agg_config_class'; - -export const getPercentileValue = ( - agg: TAggConfig, - bucket: any -) => { - const { values } = bucket[agg.parentId] && bucket[agg.parentId]; - - const percentile: any = find(values, ({ key }) => key === agg.key); - - return percentile ? percentile.value : NaN; -}; diff --git a/src/legacy/ui/public/agg_types/metrics/serial_diff.ts b/src/legacy/ui/public/agg_types/metrics/serial_diff.ts deleted file mode 100644 index bb5431fbbefd9..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/serial_diff.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; -import { makeNestedLabel } from './lib/make_nested_label'; -import { METRIC_TYPES } from './metric_agg_types'; - -const serialDiffTitle = i18n.translate('common.ui.aggTypes.metrics.serialDiffTitle', { - defaultMessage: 'Serial Diff', -}); - -const serialDiffLabel = i18n.translate('common.ui.aggTypes.metrics.serialDiffLabel', { - defaultMessage: 'serial diff', -}); - -export const serialDiffMetricAgg = new MetricAggType({ - name: METRIC_TYPES.SERIAL_DIFF, - title: serialDiffTitle, - subtype: parentPipelineAggHelper.subtype, - makeLabel: agg => makeNestedLabel(agg, serialDiffLabel), - params: [...parentPipelineAggHelper.params()], - getFormat: parentPipelineAggHelper.getFormat, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/sibling_pipeline.test.ts b/src/legacy/ui/public/agg_types/metrics/sibling_pipeline.test.ts deleted file mode 100644 index d643cf0d2a478..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/sibling_pipeline.test.ts +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { spy } from 'sinon'; -import { bucketSumMetricAgg } from './bucket_sum'; -import { bucketAvgMetricAgg } from './bucket_avg'; -import { bucketMinMetricAgg } from './bucket_min'; -import { bucketMaxMetricAgg } from './bucket_max'; - -import { AggConfigs } from '../agg_configs'; -import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; - -jest.mock('../schemas', () => { - class MockedSchemas { - all = [{}]; - } - return { - Schemas: jest.fn().mockImplementation(() => new MockedSchemas()), - }; -}); - -jest.mock('ui/new_platform'); - -describe('sibling pipeline aggs', () => { - const metrics = [ - { 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 }, - ]; - - metrics.forEach(metric => { - describe(`${metric.title} metric`, () => { - let aggDsl: Record; - let metricAgg: MetricAggType; - let aggConfig: IMetricAggConfig; - - const init = (settings?: any) => { - const field = { - name: 'field', - format: { - type: { - id: 'bytes', - }, - }, - }; - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - const aggConfigs = new AggConfigs( - indexPattern, - [ - { - id: '1', - type: 'count', - schema: 'metric', - }, - { - id: '2', - type: metric.name, - schema: 'metric', - params: settings || { - customMetric: { - id: '5', - type: 'count', - schema: 'metric', - }, - customBucket: { - id: '6', - type: 'date_histogram', - schema: 'bucket', - params: { field: 'field', interval: '10s' }, - }, - }, - }, - ], - null - ); - - // Grab the aggConfig off the vis (we don't actually use the vis for anything else) - metricAgg = metric.provider; - aggConfig = aggConfigs.aggs[1] as IMetricAggConfig; - aggDsl = aggConfig.toDsl(aggConfigs); - }; - - it(`should return a label prefixed with ${metric.title} of`, () => { - init(); - - expect(metricAgg.makeLabel(aggConfig)).toEqual(`${metric.title} of Count`); - }); - - it('should set parent aggs', function() { - init(); - - expect(aggDsl[metric.name].buckets_path).toBe('2-bucket>_count'); - expect(aggDsl.parentAggs['2-bucket'].date_histogram).not.toBeUndefined(); - }); - - it('should set nested parent aggs', () => { - init({ - customMetric: { - id: '5', - type: 'avg', - schema: 'metric', - params: { field: 'field' }, - }, - customBucket: { - id: '6', - type: 'date_histogram', - schema: 'bucket', - params: { field: 'field', interval: '10s' }, - }, - }); - - expect(aggDsl[metric.name].buckets_path).toBe('2-bucket>2-metric'); - expect(aggDsl.parentAggs['2-bucket'].date_histogram).not.toBeUndefined(); - expect(aggDsl.parentAggs['2-bucket'].aggs['2-metric'].avg.field).toEqual('field'); - }); - - it('should have correct formatter', () => { - init({ - customMetric: { - id: '5', - type: 'avg', - schema: 'metric', - params: { field: 'field' }, - }, - customBucket: { - id: '6', - type: 'date_histogram', - schema: 'bucket', - params: { field: 'field', interval: '10s' }, - }, - }); - - expect(metricAgg.getFormat(aggConfig).type.id).toBe('bytes'); - }); - - it("should call modifyAggConfigOnSearchRequestStart for nested aggs' parameters", () => { - init(); - - const searchSource: any = {}; - const customMetricSpy = spy(); - const customBucketSpy = spy(); - const { customMetric, customBucket } = aggConfig.params; - - // Attach a modifyAggConfigOnSearchRequestStart with a spy to the first parameter - customMetric.type.params[0].modifyAggConfigOnSearchRequestStart = customMetricSpy; - customBucket.type.params[0].modifyAggConfigOnSearchRequestStart = customBucketSpy; - - aggConfig.type.params.forEach(param => { - param.modifyAggConfigOnSearchRequestStart(aggConfig, searchSource); - }); - - expect(customMetricSpy.calledWith(customMetric, searchSource)).toBe(true); - expect(customBucketSpy.calledWith(customBucket, searchSource)).toBe(true); - }); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/metrics/std_deviation.test.ts b/src/legacy/ui/public/agg_types/metrics/std_deviation.test.ts deleted file mode 100644 index 3125026a52185..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/std_deviation.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IStdDevAggConfig, stdDeviationMetricAgg } from './std_deviation'; -import { AggConfigs } from '../agg_configs'; -import { METRIC_TYPES } from './metric_agg_types'; - -jest.mock('ui/new_platform'); - -describe('AggTypeMetricStandardDeviationProvider class', () => { - const getAggConfigs = (customLabel?: string) => { - const field = { - name: 'memory', - }; - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - } as any; - - return new AggConfigs( - indexPattern, - [ - { - id: METRIC_TYPES.STD_DEV, - type: METRIC_TYPES.STD_DEV, - schema: 'metric', - params: { - field: { - displayName: 'memory', - }, - customLabel, - }, - }, - ], - null - ); - }; - - it('uses the custom label if it is set', () => { - const aggConfigs = getAggConfigs('custom label'); - const responseAggs: any = stdDeviationMetricAgg.getResponseAggs( - aggConfigs.aggs[0] as IStdDevAggConfig - ); - - const lowerStdDevLabel = responseAggs[0].makeLabel(); - const upperStdDevLabel = responseAggs[1].makeLabel(); - - expect(lowerStdDevLabel).toBe('Lower custom label'); - expect(upperStdDevLabel).toBe('Upper custom label'); - }); - - it('uses the default labels if custom label is not set', () => { - const aggConfigs = getAggConfigs(); - - const responseAggs: any = stdDeviationMetricAgg.getResponseAggs( - aggConfigs.aggs[0] as IStdDevAggConfig - ); - - const lowerStdDevLabel = responseAggs[0].makeLabel(); - const upperStdDevLabel = responseAggs[1].makeLabel(); - - expect(lowerStdDevLabel).toBe('Lower Standard Deviation of memory'); - expect(upperStdDevLabel).toBe('Upper Standard Deviation of memory'); - }); -}); diff --git a/src/legacy/ui/public/agg_types/metrics/std_deviation.ts b/src/legacy/ui/public/agg_types/metrics/std_deviation.ts deleted file mode 100644 index b2e6d3b3ca4d0..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/std_deviation.ts +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { get } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { METRIC_TYPES } from './metric_agg_types'; -import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -interface ValProp { - valProp: string[]; - title: string; -} - -export interface IStdDevAggConfig extends IResponseAggConfig { - keyedDetails: (customLabel: string, fieldDisplayName?: string) => { [key: string]: ValProp }; - valProp: () => ValProp; -} - -const responseAggConfigProps = { - valProp(this: IStdDevAggConfig) { - const customLabel = this.getParam('customLabel'); - const details = this.keyedDetails(customLabel)[this.key]; - - return details.valProp; - }, - makeLabel(this: IStdDevAggConfig) { - const fieldDisplayName = this.getFieldDisplayName(); - const customLabel = this.getParam('customLabel'); - const details = this.keyedDetails(customLabel, fieldDisplayName); - - return get(details, [this.key, 'title']); - }, - keyedDetails(this: IStdDevAggConfig, customLabel: string, fieldDisplayName: string) { - const label = - customLabel || - i18n.translate('common.ui.aggTypes.metrics.standardDeviation.keyDetailsLabel', { - defaultMessage: 'Standard Deviation of {fieldDisplayName}', - values: { fieldDisplayName }, - }); - - return { - std_lower: { - valProp: ['std_deviation_bounds', 'lower'], - title: i18n.translate('common.ui.aggTypes.metrics.standardDeviation.lowerKeyDetailsTitle', { - defaultMessage: 'Lower {label}', - values: { label }, - }), - }, - std_upper: { - valProp: ['std_deviation_bounds', 'upper'], - title: i18n.translate('common.ui.aggTypes.metrics.standardDeviation.upperKeyDetailsTitle', { - defaultMessage: 'Upper {label}', - values: { label }, - }), - }, - }; - }, -}; - -export const stdDeviationMetricAgg = new MetricAggType({ - name: METRIC_TYPES.STD_DEV, - dslName: 'extended_stats', - title: i18n.translate('common.ui.aggTypes.metrics.standardDeviationTitle', { - defaultMessage: 'Standard Deviation', - }), - makeLabel(agg) { - return i18n.translate('common.ui.aggTypes.metrics.standardDeviationLabel', { - defaultMessage: 'Standard Deviation of {field}', - values: { field: agg.getFieldDisplayName() }, - }); - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.NUMBER, - }, - ], - - getResponseAggs(agg) { - const ValueAggConfig = getResponseAggConfigClass(agg, responseAggConfigProps); - - return [new ValueAggConfig('std_lower'), new ValueAggConfig('std_upper')]; - }, - - getValue(agg, bucket) { - return get(bucket[agg.parentId], agg.valProp()); - }, -}); diff --git a/src/legacy/ui/public/agg_types/metrics/sum.ts b/src/legacy/ui/public/agg_types/metrics/sum.ts deleted file mode 100644 index ce79c761ce799..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/sum.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { MetricAggType } from './metric_agg_type'; -import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -const sumTitle = i18n.translate('common.ui.aggTypes.metrics.sumTitle', { - defaultMessage: 'Sum', -}); - -export const sumMetricAgg = new MetricAggType({ - name: METRIC_TYPES.SUM, - title: sumTitle, - makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.sumLabel', { - defaultMessage: 'Sum of {field}', - values: { field: aggConfig.getFieldDisplayName() }, - }); - }, - isScalable() { - return true; - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.NUMBER, - }, - ], -}); diff --git a/src/legacy/ui/public/agg_types/metrics/top_hit.test.ts b/src/legacy/ui/public/agg_types/metrics/top_hit.test.ts deleted file mode 100644 index 3e861c052d367..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/top_hit.test.ts +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { dropRight, last } from 'lodash'; -import { topHitMetricAgg } from './top_hit'; -import { AggConfigs } from '../agg_configs'; -import { IMetricAggConfig } from './metric_agg_type'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -jest.mock('ui/new_platform'); - -describe('Top hit metric', () => { - let aggDsl: Record; - let aggConfig: IMetricAggConfig; - - const init = ({ - fieldName = 'field', - sortOrder = 'desc', - aggregate = 'concat', - readFromDocValues = false, - fieldType = KBN_FIELD_TYPES.NUMBER, - size = 1, - }: any) => { - const field = { - name: fieldName, - displayName: fieldName, - type: fieldType, - readFromDocValues, - format: { - type: { - id: 'bytes', - }, - }, - }; - - const params = { - size, - field: fieldName, - sortField: field, - sortOrder: { - value: sortOrder, - }, - aggregate: { - value: aggregate, - }, - }; - - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: { - getByName: () => field, - filter: () => [field], - }, - flattenHit: jest.fn(x => x!._source), - } as any; - - const aggConfigs = new AggConfigs( - indexPattern, - [ - { - id: '1', - type: 'top_hits', - schema: 'metric', - params, - }, - ], - null - ); - - // Grab the aggConfig off the vis (we don't actually use the vis for anything else) - aggConfig = aggConfigs.aggs[0] as IMetricAggConfig; - aggDsl = aggConfig.toDsl(aggConfigs); - }; - - it('should return a label prefixed with Last if sorting in descending order', () => { - init({ fieldName: 'bytes' }); - expect(topHitMetricAgg.makeLabel(aggConfig)).toEqual('Last bytes'); - }); - - it('should return a label prefixed with First if sorting in ascending order', () => { - init({ - fieldName: 'bytes', - sortOrder: 'asc', - }); - expect(topHitMetricAgg.makeLabel(aggConfig)).toEqual('First bytes'); - }); - - it('should request the _source field', () => { - init({ field: '_source' }); - expect(aggDsl.top_hits._source).toBeTruthy(); - expect(aggDsl.top_hits.docvalue_fields).toBeUndefined(); - }); - - it('requests both source and docvalues_fields for non-text aggregatable fields', () => { - init({ fieldName: 'bytes', readFromDocValues: true }); - expect(aggDsl.top_hits._source).toBe('bytes'); - expect(aggDsl.top_hits.docvalue_fields).toEqual([ - { field: 'bytes', format: 'use_field_mapping' }, - ]); - }); - - it('requests both source and docvalues_fields for date aggregatable fields', () => { - init({ fieldName: '@timestamp', readFromDocValues: true, fieldType: KBN_FIELD_TYPES.DATE }); - - expect(aggDsl.top_hits._source).toBe('@timestamp'); - expect(aggDsl.top_hits.docvalue_fields).toEqual([{ field: '@timestamp', format: 'date_time' }]); - }); - - it('requests just source for aggregatable text fields', () => { - init({ fieldName: 'machine.os' }); - expect(aggDsl.top_hits._source).toBe('machine.os'); - expect(aggDsl.top_hits.docvalue_fields).toBeUndefined(); - }); - - describe('try to get the value from the top hit', () => { - it('should return null if there is no hit', () => { - const bucket = { - '1': { - hits: { - hits: [], - }, - }, - }; - - init({ fieldName: '@tags' }); - expect(topHitMetricAgg.getValue(aggConfig, bucket)).toBe(null); - }); - // - it('should return undefined if the field does not appear in the source', () => { - const bucket = { - '1': { - hits: { - hits: [ - { - _source: { - bytes: 123, - }, - }, - ], - }, - }, - }; - - init({ fieldName: '@tags' }); - expect(topHitMetricAgg.getValue(aggConfig, bucket)).toBe(undefined); - }); - - it('should return the field value from the top hit', () => { - const bucket = { - '1': { - hits: { - hits: [ - { - _source: { - '@tags': 'aaa', - }, - }, - ], - }, - }, - }; - - init({ fieldName: '@tags' }); - expect(topHitMetricAgg.getValue(aggConfig, bucket)).toBe('aaa'); - }); - - it('should return the object if the field value is an object', () => { - const bucket = { - '1': { - hits: { - hits: [ - { - _source: { - '@tags': { - label: 'aaa', - }, - }, - }, - ], - }, - }, - }; - - init({ fieldName: '@tags' }); - - expect(topHitMetricAgg.getValue(aggConfig, bucket)).toEqual({ label: 'aaa' }); - }); - - it('should return an array if the field has more than one values', () => { - const bucket = { - '1': { - hits: { - hits: [ - { - _source: { - '@tags': ['aaa', 'bbb'], - }, - }, - ], - }, - }, - }; - - init({ fieldName: '@tags' }); - expect(topHitMetricAgg.getValue(aggConfig, bucket)).toEqual(['aaa', 'bbb']); - }); - - it('should return undefined if the field is not in the source nor in the doc_values field', () => { - const bucket = { - '1': { - hits: { - hits: [ - { - _source: { - bytes: 12345, - }, - fields: { - bytes: 12345, - }, - }, - ], - }, - }, - }; - - init({ fieldName: 'machine.os.raw', readFromDocValues: true }); - expect(topHitMetricAgg.getValue(aggConfig, bucket)).toBe(undefined); - }); - - describe('Multivalued field and first/last X docs', () => { - it('should return a label prefixed with Last X docs if sorting in descending order', () => { - init({ - fieldName: 'bytes', - size: 2, - }); - expect(topHitMetricAgg.makeLabel(aggConfig)).toEqual('Last 2 bytes'); - }); - - it('should return a label prefixed with First X docs if sorting in ascending order', () => { - init({ - fieldName: 'bytes', - size: 2, - sortOrder: 'asc', - }); - expect(topHitMetricAgg.makeLabel(aggConfig)).toEqual('First 2 bytes'); - }); - - [ - { - description: 'concat values with a comma', - type: 'concat', - data: [1, 2, 3], - result: [1, 2, 3], - }, - { - description: 'sum up the values', - type: 'sum', - data: [1, 2, 3], - result: 6, - }, - { - description: 'take the minimum value', - type: 'min', - data: [1, 2, 3], - result: 1, - }, - { - description: 'take the maximum value', - type: 'max', - data: [1, 2, 3], - result: 3, - }, - { - description: 'take the average value', - type: 'average', - data: [1, 2, 3], - result: 2, - }, - { - description: 'support null/undefined', - type: 'min', - data: [undefined, null], - result: null, - }, - { - description: 'support null/undefined', - type: 'max', - data: [undefined, null], - result: null, - }, - { - description: 'support null/undefined', - type: 'sum', - data: [undefined, null], - result: null, - }, - { - description: 'support null/undefined', - type: 'average', - data: [undefined, null], - result: null, - }, - ].forEach(agg => { - it(`should return the result of the ${agg.type} aggregation over the last doc - ${agg.description}`, () => { - const bucket = { - '1': { - hits: { - hits: [ - { - _source: { - bytes: agg.data, - }, - }, - ], - }, - }, - }; - - init({ fieldName: 'bytes', aggregate: agg.type }); - expect(topHitMetricAgg.getValue(aggConfig, bucket)).toEqual(agg.result); - }); - - it(`should return the result of the ${agg.type} aggregation over the last X docs - ${agg.description}`, () => { - const bucket = { - '1': { - hits: { - hits: [ - { - _source: { - bytes: dropRight(agg.data, 1), - }, - }, - { - _source: { - bytes: last(agg.data), - }, - }, - ], - }, - }, - }; - - init({ fieldName: 'bytes', aggregate: agg.type }); - expect(topHitMetricAgg.getValue(aggConfig, bucket)).toEqual(agg.result); - }); - }); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/metrics/top_hit.ts b/src/legacy/ui/public/agg_types/metrics/top_hit.ts deleted file mode 100644 index 43fe33bdebeb9..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/top_hit.ts +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import _ from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; -import { aggTypeFieldFilters } from '../param_types/filter'; -import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -// @ts-ignore -import { wrapWithInlineComp } from '../buckets/inline_comp_wrapper'; - -const isNumericFieldSelected = (agg: IMetricAggConfig) => { - const field = agg.getParam('field'); - - return field && field.type && field.type === KBN_FIELD_TYPES.NUMBER; -}; - -aggTypeFieldFilters.addFilter((field, aggConfig) => { - if ( - aggConfig.type.name !== METRIC_TYPES.TOP_HITS || - _.get(aggConfig.schema, 'aggSettings.top_hits.allowStrings', false) - ) { - return true; - } - - return field.type === KBN_FIELD_TYPES.NUMBER; -}); - -export const topHitMetricAgg = new MetricAggType({ - name: METRIC_TYPES.TOP_HITS, - title: i18n.translate('common.ui.aggTypes.metrics.topHitTitle', { - defaultMessage: 'Top Hit', - }), - makeLabel(aggConfig) { - const lastPrefixLabel = i18n.translate('common.ui.aggTypes.metrics.topHit.lastPrefixLabel', { - defaultMessage: 'Last', - }); - const firstPrefixLabel = i18n.translate('common.ui.aggTypes.metrics.topHit.firstPrefixLabel', { - defaultMessage: 'First', - }); - - let prefix = - aggConfig.getParam('sortOrder').value === 'desc' ? lastPrefixLabel : firstPrefixLabel; - - const size = aggConfig.getParam('size'); - - if (size !== 1) { - prefix += ` ${size}`; - } - - const field = aggConfig.getParam('field'); - - return `${prefix} ${field ? field.displayName : ''}`; - }, - params: [ - { - name: 'field', - type: 'field', - onlyAggregatable: false, - filterFieldTypes: '*', - write(agg, output) { - const field = agg.getParam('field'); - output.params = {}; - - if (field.scripted) { - output.params.script_fields = { - [field.name]: { - script: { - source: field.script, - lang: field.lang, - }, - }, - }; - } else { - if (field.readFromDocValues) { - // always format date fields as date_time to avoid - // displaying unformatted dates like epoch_millis - // or other not-accepted momentjs formats - const format = field.type === KBN_FIELD_TYPES.DATE ? 'date_time' : 'use_field_mapping'; - output.params.docvalue_fields = [{ field: field.name, format }]; - } - output.params._source = field.name === '_source' ? true : field.name; - } - }, - }, - { - name: 'aggregate', - type: 'optioned', - options: [ - { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.minLabel', { - defaultMessage: 'Min', - }), - isCompatible: isNumericFieldSelected, - disabled: true, - value: 'min', - }, - { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.maxLabel', { - defaultMessage: 'Max', - }), - isCompatible: isNumericFieldSelected, - disabled: true, - value: 'max', - }, - { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.sumLabel', { - defaultMessage: 'Sum', - }), - isCompatible: isNumericFieldSelected, - disabled: true, - value: 'sum', - }, - { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.averageLabel', { - defaultMessage: 'Average', - }), - isCompatible: isNumericFieldSelected, - disabled: true, - value: 'average', - }, - { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.concatenateLabel', { - defaultMessage: 'Concatenate', - }), - isCompatible(aggConfig: IMetricAggConfig) { - return _.get(aggConfig.schema, 'aggSettings.top_hits.allowStrings', false); - }, - disabled: true, - value: 'concat', - }, - ], - write: _.noop, - }, - { - name: 'size', - default: 1, - }, - { - name: 'sortField', - type: 'field', - filterFieldTypes: [ - KBN_FIELD_TYPES.NUMBER, - KBN_FIELD_TYPES.DATE, - KBN_FIELD_TYPES.IP, - KBN_FIELD_TYPES.STRING, - ], - default(agg: IMetricAggConfig) { - return agg.getIndexPattern().timeFieldName; - }, - write: _.noop, // prevent default write, it is handled below - }, - { - name: 'sortOrder', - type: 'optioned', - default: 'desc', - options: [ - { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.descendingLabel', { - defaultMessage: 'Descending', - }), - value: 'desc', - }, - { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.ascendingLabel', { - defaultMessage: 'Ascending', - }), - value: 'asc', - }, - ], - write(agg, output) { - const sortField = agg.params.sortField; - const sortOrder = agg.params.sortOrder; - - if (sortField.scripted) { - output.params.sort = [ - { - _script: { - script: { - source: sortField.script, - lang: sortField.lang, - }, - type: sortField.type, - order: sortOrder.value, - }, - }, - ]; - } else { - output.params.sort = [ - { - [sortField.name]: { - order: sortOrder.value, - }, - }, - ]; - } - }, - }, - ], - getValue(agg, bucket) { - const hits: any[] = _.get(bucket, `${agg.id}.hits.hits`); - if (!hits || !hits.length) { - return null; - } - const path = agg.getParam('field').name; - - let values = _.flatten( - hits.map(hit => - path === '_source' ? hit._source : agg.getIndexPattern().flattenHit(hit, true)[path] - ) - ); - - if (values.length === 1) { - values = values[0]; - } - - if (Array.isArray(values)) { - if (!_.compact(values).length) { - return null; - } - - const aggregate = agg.getParam('aggregate'); - - switch (aggregate.value) { - case 'max': - return _.max(values); - case 'min': - return _.min(values); - case 'sum': - return _.sum(values); - case 'average': - return _.sum(values) / values.length; - } - } - return values; - }, -}); diff --git a/src/legacy/ui/public/agg_types/param_types/agg.ts b/src/legacy/ui/public/agg_types/param_types/agg.ts index 2e7c11004b472..68c58e1dd7e07 100644 --- a/src/legacy/ui/public/agg_types/param_types/agg.ts +++ b/src/legacy/ui/public/agg_types/param_types/agg.ts @@ -17,39 +17,4 @@ * under the License. */ -import { AggConfig } from '../agg_config'; -import { BaseParamType } from './base'; - -export class AggParamType extends BaseParamType< - TAggConfig -> { - makeAgg: (agg: TAggConfig, state?: any) => TAggConfig; - - constructor(config: Record) { - super(config); - - if (!config.write) { - this.write = (aggConfig: TAggConfig, output: Record) => { - if (aggConfig.params[this.name] && aggConfig.params[this.name].length) { - output.params[this.name] = aggConfig.params[this.name]; - } - }; - } - if (!config.serialize) { - this.serialize = (agg: TAggConfig) => { - return agg.toJSON(); - }; - } - if (!config.deserialize) { - this.deserialize = (state: unknown, agg?: TAggConfig): TAggConfig => { - if (!agg) { - throw new Error('aggConfig was not provided to AggParamType deserialize function'); - } - return this.makeAgg(agg, state); - }; - } - - this.makeAgg = config.makeAgg; - this.valueType = AggConfig; - } -} +export { AggParamType } from '../index'; diff --git a/src/legacy/ui/public/agg_types/param_types/base.ts b/src/legacy/ui/public/agg_types/param_types/base.ts deleted file mode 100644 index 15ec44e2ca5ae..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/base.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { AggConfigs } from '../agg_configs'; -import { AggConfig } from '../agg_config'; -import { FetchOptions, ISearchSource } from '../../../../../plugins/data/public'; - -export class BaseParamType { - name: string; - type: string; - displayName: string; - required: boolean; - advanced: boolean; - default: any; - write: ( - aggConfig: TAggConfig, - output: Record, - aggConfigs?: AggConfigs, - locals?: Record - ) => void; - serialize: (value: any, aggConfig?: TAggConfig) => any; - deserialize: (value: any, aggConfig?: TAggConfig) => any; - options: any[]; - valueType?: any; - - onChange?(agg: TAggConfig): void; - shouldShow?(agg: TAggConfig): boolean; - - /** - * A function that will be called before an aggConfig is serialized and sent to ES. - * Allows aggConfig to retrieve values needed for serialization - * Example usage: an aggregation needs to know the min/max of a field to determine an appropriate interval - * - * @param {AggConfig} aggConfig - * @param {Courier.SearchSource} searchSource - * @returns {Promise|undefined} - */ - modifyAggConfigOnSearchRequestStart: ( - aggConfig: TAggConfig, - searchSource?: ISearchSource, - options?: FetchOptions - ) => void; - - constructor(config: Record) { - this.name = config.name; - this.type = config.type; - this.displayName = config.displayName || this.name; - this.required = config.required === true; - this.advanced = config.advanced || false; - this.onChange = config.onChange; - this.shouldShow = config.shouldShow; - this.default = config.default; - - const defaultWrite = (aggConfig: TAggConfig, output: Record) => { - if (aggConfig.params[this.name]) { - output.params[this.name] = aggConfig.params[this.name] || this.default; - } - }; - - this.write = config.write || defaultWrite; - this.serialize = config.serialize; - this.deserialize = config.deserialize; - this.options = config.options; - this.modifyAggConfigOnSearchRequestStart = - config.modifyAggConfigOnSearchRequestStart || function() {}; - this.valueType = config.valueType || config.type; - } -} diff --git a/src/legacy/ui/public/agg_types/param_types/field.test.ts b/src/legacy/ui/public/agg_types/param_types/field.test.ts deleted file mode 100644 index 9cea2934d7459..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/field.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { BaseParamType } from './base'; -import { FieldParamType } from './field'; -import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -jest.mock('ui/new_platform'); - -describe('Field', () => { - const indexPattern = { - id: '1234', - title: 'logstash-*', - fields: [ - { - name: 'field1', - type: KBN_FIELD_TYPES.NUMBER, - esTypes: [ES_FIELD_TYPES.INTEGER], - aggregatable: true, - filterable: true, - searchable: true, - }, - { - name: 'field2', - type: KBN_FIELD_TYPES.STRING, - esTypes: [ES_FIELD_TYPES.TEXT], - aggregatable: false, - filterable: false, - searchable: true, - }, - ], - } as any; - - describe('constructor', () => { - it('it is an instance of BaseParamType', () => { - const aggParam = new FieldParamType({ - name: 'field', - type: 'field', - }); - - expect(aggParam instanceof BaseParamType).toBeTruthy(); - }); - }); - - describe('getAvailableFields', () => { - it('should return only aggregatable fields by default', () => { - const aggParam = new FieldParamType({ - name: 'field', - type: 'field', - }); - - const fields = aggParam.getAvailableFields(indexPattern.fields); - - expect(fields.length).toBe(1); - - for (const field of fields) { - expect(field.aggregatable).toBe(true); - } - }); - - it('should return all fields if onlyAggregatable is false', () => { - const aggParam = new FieldParamType({ - name: 'field', - type: 'field', - }); - - aggParam.onlyAggregatable = false; - - const fields = aggParam.getAvailableFields(indexPattern.fields); - - expect(fields.length).toBe(2); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/param_types/field.ts b/src/legacy/ui/public/agg_types/param_types/field.ts deleted file mode 100644 index d01e059c6c616..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/field.ts +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -// @ts-ignore -import { i18n } from '@kbn/i18n'; -import { AggConfig } from '../agg_config'; -import { SavedObjectNotFound } from '../../../../../plugins/kibana_utils/public'; -import { BaseParamType } from './base'; -import { npStart } from '../../new_platform'; -import { propFilter } from '../filter'; -import { Field, IFieldList } from '../../../../../plugins/data/public'; -import { isNestedField } from '../../../../../plugins/data/public'; - -const filterByType = propFilter('type'); - -export class FieldParamType extends BaseParamType { - required = true; - scriptable = true; - filterFieldTypes: string; - onlyAggregatable: boolean; - - constructor(config: Record) { - super(config); - - this.filterFieldTypes = config.filterFieldTypes || '*'; - this.onlyAggregatable = config.onlyAggregatable !== false; - - if (!config.write) { - this.write = (aggConfig: AggConfig, output: Record) => { - const field = aggConfig.getField(); - - if (!field) { - throw new TypeError( - i18n.translate( - 'common.ui.aggTypes.paramTypes.field.requiredFieldParameterErrorMessage', - { - defaultMessage: '{fieldParameter} is a required parameter', - values: { - fieldParameter: '"field"', - }, - } - ) - ); - } - - if (field.scripted) { - output.params.script = { - source: field.script, - lang: field.lang, - }; - } else { - output.params.field = field.name; - } - }; - } - - this.serialize = (field: Field) => { - return field.name; - }; - - this.deserialize = (fieldName: string, aggConfig?: AggConfig) => { - if (!aggConfig) { - throw new Error('aggConfig was not provided to FieldParamType deserialize function'); - } - const field = aggConfig.getIndexPattern().fields.getByName(fieldName); - - if (!field) { - throw new SavedObjectNotFound('index-pattern-field', fieldName); - } - - // @ts-ignore - const validField = this.getAvailableFields(aggConfig.getIndexPattern().fields).find( - (f: any) => f.name === fieldName - ); - if (!validField) { - npStart.core.notifications.toasts.addDanger( - i18n.translate( - 'common.ui.aggTypes.paramTypes.field.invalidSavedFieldParameterErrorMessage', - { - defaultMessage: - 'Saved {fieldParameter} parameter is now invalid. Please select a new field.', - values: { - fieldParameter: '"field"', - }, - } - ) - ); - } - - return validField; - }; - } - - /** - * filter the fields to the available ones - */ - getAvailableFields = (fields: IFieldList) => { - const filteredFields = fields.filter((field: Field) => { - const { onlyAggregatable, scriptable, filterFieldTypes } = this; - - if ( - (onlyAggregatable && (!field.aggregatable || isNestedField(field))) || - (!scriptable && field.scripted) - ) { - return false; - } - - if (!filterFieldTypes) { - return true; - } - - return filterByType([field], filterFieldTypes).length !== 0; - }); - - return filteredFields; - }; -} diff --git a/src/legacy/ui/public/agg_types/param_types/filter/field_filters.test.ts b/src/legacy/ui/public/agg_types/param_types/filter/field_filters.test.ts deleted file mode 100644 index 384c142408012..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/filter/field_filters.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IndexedArray } from 'ui/indexed_array'; -import { AggTypeFieldFilters } from './field_filters'; -import { AggConfig } from '../../agg_config'; -import { Field } from '../../../../../../plugins/data/public'; - -describe('AggTypeFieldFilters', () => { - let registry: AggTypeFieldFilters; - const aggConfig = {} as AggConfig; - - beforeEach(() => { - registry = new AggTypeFieldFilters(); - }); - - it('should filter nothing without registered filters', async () => { - const fields = [{ name: 'foo' }, { name: 'bar' }] as IndexedArray; - const filtered = registry.filter(fields, aggConfig); - expect(filtered).toEqual(fields); - }); - - it('should pass all fields to the registered filter', async () => { - const fields = [{ name: 'foo' }, { name: 'bar' }] as IndexedArray; - const filter = jest.fn(); - registry.addFilter(filter); - registry.filter(fields, aggConfig); - expect(filter).toHaveBeenCalledWith(fields[0], aggConfig); - expect(filter).toHaveBeenCalledWith(fields[1], aggConfig); - }); - - it('should allow registered filters to filter out fields', async () => { - const fields = [{ name: 'foo' }, { name: 'bar' }] as IndexedArray; - let filtered = registry.filter(fields, aggConfig); - expect(filtered).toEqual(fields); - - registry.addFilter(() => true); - registry.addFilter(field => field.name !== 'foo'); - filtered = registry.filter(fields, aggConfig); - expect(filtered).toEqual([fields[1]]); - - registry.addFilter(field => field.name !== 'bar'); - filtered = registry.filter(fields, aggConfig); - expect(filtered).toEqual([]); - }); -}); diff --git a/src/legacy/ui/public/agg_types/param_types/filter/field_filters.ts b/src/legacy/ui/public/agg_types/param_types/filter/field_filters.ts deleted file mode 100644 index 7d44bedafa7e1..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/filter/field_filters.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { Field } from 'src/plugins/data/public'; -import { AggConfig } from '../../agg_config'; - -type AggTypeFieldFilter = (field: Field, aggConfig: AggConfig) => boolean; - -/** - * A registry to store {@link AggTypeFieldFilter} which are used to filter down - * available fields for a specific visualization and {@link AggType}. - */ -class AggTypeFieldFilters { - private filters = new Set(); - - /** - * Register a new {@link AggTypeFieldFilter} with this registry. - * This will be used by the {@link #filter|filter method}. - * - * @param filter The filter to register. - */ - public addFilter(filter: AggTypeFieldFilter): void { - this.filters.add(filter); - } - - /** - * Returns the {@link any|fields} filtered by all registered filters. - * - * @param fields An IndexedArray of fields that will be filtered down by this registry. - * @param aggConfig The aggConfig for which the returning list will be used. - * @return A filtered list of the passed fields. - */ - public filter(fields: Field[], aggConfig: AggConfig) { - const allFilters = Array.from(this.filters); - const allowedAggTypeFields = fields.filter(field => { - const isAggTypeFieldAllowed = allFilters.every(filter => filter(field, aggConfig)); - return isAggTypeFieldAllowed; - }); - return allowedAggTypeFields; - } -} - -const aggTypeFieldFilters = new AggTypeFieldFilters(); - -export { aggTypeFieldFilters, AggTypeFieldFilters }; diff --git a/src/legacy/ui/public/agg_types/param_types/index.ts b/src/legacy/ui/public/agg_types/param_types/index.ts index 3414e6a71ecdc..5f085e498c788 100644 --- a/src/legacy/ui/public/agg_types/param_types/index.ts +++ b/src/legacy/ui/public/agg_types/param_types/index.ts @@ -17,8 +17,4 @@ * under the License. */ -export * from './base'; -export * from './field'; -export * from './json'; export * from './optioned'; -export * from './string'; diff --git a/src/legacy/ui/public/agg_types/param_types/json.test.ts b/src/legacy/ui/public/agg_types/param_types/json.test.ts deleted file mode 100644 index 827299814c62a..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/json.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { BaseParamType } from './base'; -import { JsonParamType } from './json'; -import { AggConfig } from '../agg_config'; - -jest.mock('ui/new_platform'); - -describe('JSON', function() { - const paramName = 'json_test'; - let aggConfig: AggConfig; - let output: Record; - - const initAggParam = (config: Record = {}) => - new JsonParamType({ - ...config, - type: 'json', - name: paramName, - }); - - beforeEach(function() { - aggConfig = { params: {} } as AggConfig; - output = { params: {} }; - }); - - describe('constructor', () => { - it('it is an instance of BaseParamType', () => { - const aggParam = initAggParam(); - - expect(aggParam instanceof BaseParamType).toBeTruthy(); - }); - }); - - describe('write', () => { - it('should do nothing when param is not defined', () => { - const aggParam = initAggParam(); - - expect(aggConfig.params).not.toHaveProperty(paramName); - - aggParam.write(aggConfig, output); - expect(output).not.toHaveProperty(paramName); - }); - - it('should not append param when invalid JSON', () => { - const aggParam = initAggParam(); - - aggConfig.params[paramName] = 'i am not json'; - - aggParam.write(aggConfig, output); - expect(aggConfig.params).toHaveProperty(paramName); - expect(output).not.toHaveProperty(paramName); - }); - - it('should append param when valid JSON', () => { - const aggParam = initAggParam(); - const jsonData = JSON.stringify({ - new_param: 'should exist in output', - }); - - output.params.existing = 'true'; - aggConfig.params[paramName] = jsonData; - - aggParam.write(aggConfig, output); - expect(aggConfig.params).toHaveProperty(paramName); - - expect(output.params).toEqual({ - existing: 'true', - new_param: 'should exist in output', - }); - }); - - it('should not overwrite existing params', () => { - const aggParam = initAggParam(); - const jsonData = JSON.stringify({ - new_param: 'should exist in output', - existing: 'should be used', - }); - - output.params.existing = 'true'; - aggConfig.params[paramName] = jsonData; - - aggParam.write(aggConfig, output); - expect(output.params).toEqual(JSON.parse(jsonData)); - }); - - it('should drop nulled params', () => { - const aggParam = initAggParam(); - const jsonData = JSON.stringify({ - new_param: 'should exist in output', - field: null, - }); - - output.params.field = 'extensions'; - aggConfig.params[paramName] = jsonData; - - aggParam.write(aggConfig, output); - expect(Object.keys(output.params)).toContain('new_param'); - expect(Object.keys(output.params)).not.toContain('field'); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/param_types/json.ts b/src/legacy/ui/public/agg_types/param_types/json.ts deleted file mode 100644 index 771919b0bb56b..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/json.ts +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import _ from 'lodash'; - -import { AggConfig } from '../agg_config'; -import { BaseParamType } from './base'; - -export class JsonParamType extends BaseParamType { - constructor(config: Record) { - super(config); - - this.name = config.name || 'json'; - - if (!config.write) { - this.write = (aggConfig: AggConfig, output: Record) => { - let paramJson; - const param = aggConfig.params[this.name]; - - if (!param) { - return; - } - - // handle invalid Json input - try { - paramJson = JSON.parse(param); - } catch (err) { - return; - } - - function filteredCombine(srcA: any, srcB: any) { - function mergeObjs(a: any, b: any) { - return _(a) - .keys() - .union(_.keys(b)) - .transform(function(dest, key) { - const val = compare(a[key], b[key]); - if (val !== undefined) dest[key] = val; - }, {}) - .value(); - } - - function mergeArrays(a: any, b: any): any { - // attempt to merge each value - return _.times(Math.max(a.length, b.length), function(i) { - return compare(a[i], b[i]); - }); - } - - function compare(a: any, b: any) { - if (_.isPlainObject(a) && _.isPlainObject(b)) return mergeObjs(a, b); - if (Array.isArray(a) && Array.isArray(b)) return mergeArrays(a, b); - if (b === null) return undefined; - if (b !== undefined) return b; - return a; - } - - return compare(srcA, srcB); - } - - output.params = filteredCombine(output.params, paramJson); - return; - }; - } - } -} diff --git a/src/legacy/ui/public/agg_types/param_types/optioned.test.ts b/src/legacy/ui/public/agg_types/param_types/optioned.test.ts deleted file mode 100644 index 6b58d81914097..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/optioned.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { BaseParamType } from './base'; -import { OptionedParamType } from './optioned'; - -jest.mock('ui/new_platform'); - -describe('Optioned', () => { - describe('constructor', () => { - it('it is an instance of BaseParamType', () => { - const aggParam = new OptionedParamType({ - name: 'some_param', - type: 'optioned', - }); - - expect(aggParam instanceof BaseParamType).toBeTruthy(); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/param_types/optioned.ts b/src/legacy/ui/public/agg_types/param_types/optioned.ts index 5ffda3740af49..d6ce116b996c6 100644 --- a/src/legacy/ui/public/agg_types/param_types/optioned.ts +++ b/src/legacy/ui/public/agg_types/param_types/optioned.ts @@ -17,43 +17,4 @@ * under the License. */ -import { AggConfig } from '../agg_config'; -import { BaseParamType } from './base'; - -export interface OptionedValueProp { - value: string; - text: string; - disabled?: boolean; - isCompatible: (agg: AggConfig) => boolean; -} - -export interface OptionedParamEditorProps { - aggParam: { - options: T[]; - }; -} - -export class OptionedParamType extends BaseParamType { - options: OptionedValueProp[]; - - constructor(config: Record) { - super(config); - - if (!config.write) { - this.write = (aggConfig: AggConfig, output: Record) => { - output.params[this.name] = aggConfig.params[this.name].value; - }; - } - if (!config.serialize) { - this.serialize = (selected: OptionedValueProp) => { - return selected.value; - }; - } - if (!config.deserialize) { - this.deserialize = (value: any) => { - return this.options.find((option: OptionedValueProp) => option.value === value); - }; - } - this.options = config.options || []; - } -} +export { OptionedParamEditorProps, OptionedParamType, OptionedValueProp } from '../index'; diff --git a/src/legacy/ui/public/agg_types/param_types/string.test.ts b/src/legacy/ui/public/agg_types/param_types/string.test.ts deleted file mode 100644 index fd5ccebde993e..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/string.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { BaseParamType } from './base'; -import { StringParamType } from './string'; -import { AggConfig } from '../agg_config'; - -jest.mock('ui/new_platform'); - -describe('String', function() { - let paramName = 'json_test'; - let aggConfig: AggConfig; - let output: Record; - - const initAggParam = (config: Record = {}) => - new StringParamType({ - ...config, - type: 'string', - name: paramName, - }); - - beforeEach(() => { - aggConfig = { params: {} } as AggConfig; - output = { params: {} }; - }); - - describe('constructor', () => { - it('it is an instance of BaseParamType', () => { - const aggParam = initAggParam(); - - expect(aggParam instanceof BaseParamType).toBeTruthy(); - }); - }); - - describe('write', () => { - it('should append param by name', () => { - const params = { - [paramName]: 'some input', - }; - - const aggParam = initAggParam({ name: paramName }); - - aggConfig.params = params; - aggParam.write(aggConfig, output); - - expect(output.params).toEqual(params); - }); - - it('should not be in output with empty input', () => { - paramName = 'more_testing'; - - const params = { - [paramName]: '', - }; - - const aggParam = initAggParam({ name: paramName }); - - aggConfig.params = params; - aggParam.write(aggConfig, output); - - expect(output.params).toEqual({}); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/param_types/string.ts b/src/legacy/ui/public/agg_types/param_types/string.ts deleted file mode 100644 index 58ba99f8a6d63..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/string.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { AggConfig } from '../agg_config'; -import { BaseParamType } from './base'; - -export class StringParamType extends BaseParamType { - constructor(config: Record) { - super(config); - - if (!config.write) { - this.write = (aggConfig: AggConfig, output: Record) => { - if (aggConfig.params[this.name] && aggConfig.params[this.name].length) { - output.params[this.name] = aggConfig.params[this.name]; - } - }; - } - } -} diff --git a/src/legacy/ui/public/agg_types/schemas.ts b/src/legacy/ui/public/agg_types/schemas.ts deleted file mode 100644 index 05723cac1869d..0000000000000 --- a/src/legacy/ui/public/agg_types/schemas.ts +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import _ from 'lodash'; - -import { Optional } from '@kbn/utility-types'; - -import { IndexedArray } from 'ui/indexed_array'; -import { AggGroupNames } from './agg_groups'; -import { AggParam } from './agg_params'; - -export interface ISchemas { - [AggGroupNames.Buckets]: Schema[]; - [AggGroupNames.Metrics]: Schema[]; -} - -export interface Schema { - aggFilter: string | string[]; - editor: boolean | string; - group: AggGroupNames; - max: number; - min: number; - name: string; - params: AggParam[]; - title: string; - defaults: unknown; - hideCustomLabel?: boolean; - mustBeFirst?: boolean; - aggSettings?: any; -} - -class Schemas { - // @ts-ignore - all: IndexedArray; - - constructor( - schemas: Array< - Optional< - Schema, - 'min' | 'max' | 'group' | 'title' | 'aggFilter' | 'editor' | 'params' | 'defaults' - > - > - ) { - _(schemas || []) - .map(schema => { - if (!schema.name) throw new Error('all schema must have a unique name'); - - if (schema.name === 'split') { - schema.params = [ - { - name: 'row', - default: true, - }, - ] as AggParam[]; - } - - _.defaults(schema, { - min: 0, - max: Infinity, - group: AggGroupNames.Buckets, - title: schema.name, - aggFilter: '*', - editor: false, - params: [], - }); - - return schema as Schema; - }) - .tap((fullSchemas: Schema[]) => { - this.all = new IndexedArray({ - index: ['name'], - group: ['group'], - immutable: true, - initialSet: fullSchemas, - }); - }) - .groupBy('group') - .forOwn((group, groupName) => { - // @ts-ignore - this[groupName] = new IndexedArray({ - index: ['name'], - immutable: true, - // @ts-ignore - initialSet: group, - }); - }) - .commit(); - } -} - -export { Schemas }; diff --git a/src/legacy/ui/public/agg_types/utils.test.tsx b/src/legacy/ui/public/agg_types/utils.test.tsx deleted file mode 100644 index a3c7f24f3927d..0000000000000 --- a/src/legacy/ui/public/agg_types/utils.test.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { isValidJson } from './utils'; - -jest.mock('ui/new_platform'); - -const input = { - valid: '{ "test": "json input" }', - invalid: 'strings are not json', -}; - -describe('AggType utils', () => { - describe('isValidJson', () => { - it('should return true when empty string', () => { - expect(isValidJson('')).toBeTruthy(); - }); - - it('should return true when undefine', () => { - expect(isValidJson(undefined as any)).toBeTruthy(); - }); - - it('should return false when invalid string', () => { - expect(isValidJson(input.invalid)).toBeFalsy(); - }); - - it('should return true when valid string', () => { - expect(isValidJson(input.valid)).toBeTruthy(); - }); - - it('should return false if a number', () => { - expect(isValidJson('0')).toBeFalsy(); - }); - }); -}); diff --git a/src/legacy/ui/public/agg_types/utils.ts b/src/legacy/ui/public/agg_types/utils.ts index e382f821b31a9..ec1eab7e4b115 100644 --- a/src/legacy/ui/public/agg_types/utils.ts +++ b/src/legacy/ui/public/agg_types/utils.ts @@ -17,56 +17,4 @@ * under the License. */ -import { isValidEsInterval } from '../../../core_plugins/data/common/parse_es_interval/is_valid_es_interval'; -import { leastCommonInterval } from '../vis/lib/least_common_interval'; - -/** - * Check a string if it's a valid JSON. - * - * @param {string} value a string that should be validated - * @returns {boolean} true if value is a valid JSON or if value is an empty string, or a string with whitespaces, otherwise false - */ -function isValidJson(value: string): boolean { - if (!value || value.length === 0) { - return true; - } - - const trimmedValue = value.trim(); - - if (trimmedValue.length === 0) { - return true; - } - - if (trimmedValue[0] === '{' || trimmedValue[0] === '[') { - try { - JSON.parse(trimmedValue); - return true; - } catch (e) { - return false; - } - } else { - return false; - } -} - -function isValidInterval(value: string, baseInterval?: string) { - if (baseInterval) { - return _parseWithBase(value, baseInterval); - } else { - return isValidEsInterval(value); - } -} - -// When base interval is set, check for least common interval and allow -// input the value is the same. This means that the input interval is a -// multiple of the base interval. -function _parseWithBase(value: string, baseInterval: string) { - try { - const interval = leastCommonInterval(baseInterval, value); - return interval === value.replace(/\s/g, ''); - } catch (e) { - return false; - } -} - -export { isValidJson, isValidInterval }; +export { isValidJson, isValidInterval } from './index'; From 14adb25795f452c96ea75bd7a24923cade6be7e7 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Thu, 30 Jan 2020 17:33:19 -0700 Subject: [PATCH 05/10] Create IAggConfig, IAggConfigs, IAggType, IFieldParamType, IMetricAggType. --- src/legacy/core_plugins/data/public/index.ts | 7 +++++ .../data/public/search/aggs/agg_config.ts | 27 ++++++++++--------- .../data/public/search/aggs/agg_configs.ts | 3 +++ .../data/public/search/aggs/agg_params.ts | 4 +-- .../data/public/search/aggs/agg_type.test.ts | 12 ++++----- .../data/public/search/aggs/agg_type.ts | 9 ++++--- .../search/aggs/buckets/geo_hash.test.ts | 4 +-- .../aggs/buckets/significant_terms.test.ts | 3 ++- .../data/public/search/aggs/buckets/terms.ts | 4 +-- .../aggs/filter/agg_type_filters.test.ts | 9 ++++--- .../search/aggs/filter/agg_type_filters.ts | 8 +++--- .../data/public/search/aggs/index.ts | 10 ++++++- .../metrics/lib/parent_pipeline_agg_writer.ts | 4 +-- .../public/search/aggs/metrics/median.test.ts | 4 +-- .../search/aggs/metrics/metric_agg_type.ts | 3 +++ .../aggs/metrics/percentile_ranks.test.ts | 4 +-- .../search/aggs/metrics/percentiles.test.ts | 4 +-- .../public/search/aggs/param_types/base.ts | 4 +-- .../public/search/aggs/param_types/field.ts | 3 +++ .../data/public/search/aggs/types.ts | 5 ++++ .../data/public/search/expressions/esaggs.ts | 4 +-- .../data/public/search/search_service.ts | 8 +++++- .../public/components/agg.test.tsx | 14 +++++----- .../public/components/agg.tsx | 4 +-- .../public/components/agg_add.tsx | 4 +-- .../public/components/agg_common_props.ts | 12 ++++----- .../public/components/agg_group.test.tsx | 12 ++++----- .../public/components/agg_group.tsx | 8 +++--- .../components/agg_group_helper.test.ts | 8 +++--- .../public/components/agg_group_helper.tsx | 14 +++++----- .../public/components/agg_group_state.tsx | 4 +-- .../public/components/agg_param_props.ts | 6 ++--- .../public/components/agg_params.test.tsx | 4 +-- .../public/components/agg_params.tsx | 4 +-- .../components/agg_params_helper.test.ts | 22 +++++++-------- .../public/components/agg_params_helper.ts | 18 ++++++------- .../public/components/agg_select.tsx | 12 ++++----- .../components/controls/agg_control_props.tsx | 4 +-- .../components/controls/agg_utils.test.tsx | 8 +++--- .../public/components/controls/field.test.tsx | 6 ++--- .../public/components/controls/field.tsx | 6 ++--- .../public/components/controls/filter.tsx | 4 +-- .../components/controls/metric_agg.test.tsx | 6 ++--- .../public/components/controls/order_agg.tsx | 8 +++--- .../public/components/controls/sub_agg.tsx | 4 +-- .../public/components/controls/sub_metric.tsx | 4 +-- .../public/components/controls/test_utils.ts | 6 ++--- .../controls/top_aggregate.test.tsx | 18 ++++++------- .../components/controls/top_aggregate.tsx | 6 ++--- .../components/controls/utils/agg_utils.ts | 10 +++---- .../components/controls/utils/use_handlers.ts | 8 +++--- .../public/components/sidebar/data_tab.tsx | 8 +++--- .../components/sidebar/state/actions.ts | 18 ++++++------- .../components/sidebar/state/reducers.ts | 4 +-- .../public/legacy_imports.ts | 7 +++-- .../public/vis_options_props.tsx | 4 +-- .../public/vis_type_agg_filter.ts | 4 +-- .../vis_type_table/public/legacy_imports.ts | 2 +- .../public/table_vis_controller.test.ts | 4 +-- .../options/metrics_axes/index.test.tsx | 12 ++++----- .../components/options/metrics_axes/index.tsx | 4 +-- .../vis_type_vislib/public/legacy_imports.ts | 2 +- .../public/embeddable/query_geohash_bounds.ts | 4 +-- .../visualizations/public/legacy_imports.ts | 4 +-- .../public/legacy/build_pipeline.test.ts | 8 +++--- .../np_ready/public/legacy/build_pipeline.ts | 12 ++++----- .../public/np_ready/public/vis.d.ts | 4 +-- .../public/np_ready/public/vis.js | 2 +- .../agg_response/tabify/_get_columns.ts | 8 +++--- src/legacy/ui/public/agg_types/agg_config.ts | 2 +- src/legacy/ui/public/agg_types/agg_configs.ts | 2 +- src/legacy/ui/public/agg_types/index.ts | 9 +++++++ .../metrics/lib/parent_pipeline_agg_helper.ts | 2 +- .../lib/sibling_pipeline_agg_helper.ts | 20 ++++++++++++++ .../agg_types/metrics/metric_agg_type.ts | 20 ++++++++++++++ .../ui/public/vis/__tests__/_agg_configs.js | 2 +- .../config/editor_config_providers.test.ts | 8 +++--- .../vis/config/editor_config_providers.ts | 6 ++--- .../loader/pipeline_helpers/utilities.ts | 6 ++--- 79 files changed, 335 insertions(+), 240 deletions(-) create mode 100644 src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts create mode 100644 src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts index 8c7b47c9367a4..2ab73bdf02d3d 100644 --- a/src/legacy/core_plugins/data/public/index.ts +++ b/src/legacy/core_plugins/data/public/index.ts @@ -38,6 +38,11 @@ export { AggParam, AggParamOption, DateRangeKey, + IAggConfig, + IAggConfigs, + IAggType, + IFieldParamType, + IMetricAggType, IpRangeKey, ISchemas, OptionedParamEditorProps, @@ -65,9 +70,11 @@ export { isValidJson, METRIC_TYPES, OptionedParamType, + parentPipelineType, propFilter, Schema, Schemas, + siblingPipelineType, termsAggFilter, // search_source getRequestInspectorStats, diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts index 1637f053cd0fc..b15ab2c2b1578 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts @@ -27,10 +27,10 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; -import { AggType } from './agg_type'; +import { IAggType } from './agg_type'; import { AggGroupNames } from './agg_groups'; import { writeParams } from './agg_params'; -import { AggConfigs } from './agg_configs'; +import { IAggConfigs } from './agg_configs'; import { Schema } from './schemas'; import { ISearchSource, @@ -60,13 +60,13 @@ const unknownSchema: Schema = { group: AggGroupNames.Metrics, }; -const getTypeFromRegistry = (type: string): AggType => { +const getTypeFromRegistry = (type: string): IAggType => { // We need to inline require here, since we're having a cyclic dependency // from somewhere inside agg_types back to AggConfig. const aggTypes = require('../aggs').aggTypes; const registeredType = - aggTypes.metrics.find((agg: AggType) => agg.name === type) || - aggTypes.buckets.find((agg: AggType) => agg.name === type); + aggTypes.metrics.find((agg: IAggType) => agg.name === type) || + aggTypes.buckets.find((agg: IAggType) => agg.name === type); if (!registeredType) { throw new Error('unknown type'); @@ -85,6 +85,9 @@ const getSchemaFromRegistry = (schemas: any, schema: string): Schema => { return registeredSchema; }; +// TODO need to make a more explicit interface for this +export type IAggConfig = AggConfig; + export class AggConfig { /** * Ensure that all of the objects in the list have ids, the objects @@ -122,19 +125,19 @@ export class AggConfig { ); } - public aggConfigs: AggConfigs; + public aggConfigs: IAggConfigs; public id: string; public enabled: boolean; public params: any; - public parent?: AggConfigs; + public parent?: IAggConfigs; public brandNew?: boolean; private __schema: Schema; - private __type: AggType; + private __type: IAggType; private __typeDecorations: any; private subAggs: AggConfig[] = []; - constructor(aggConfigs: AggConfigs, opts: AggConfigOptions) { + constructor(aggConfigs: IAggConfigs, opts: AggConfigOptions) { this.aggConfigs = aggConfigs; this.id = String(opts.id || AggConfig.nextId(aggConfigs.aggs as any)); this.enabled = typeof opts.enabled === 'boolean' ? opts.enabled : true; @@ -207,7 +210,7 @@ export class AggConfig { return _.get(this.params, key); } - write(aggs?: AggConfigs) { + write(aggs?: IAggConfigs) { return writeParams(this.type.params, this, aggs); } @@ -262,7 +265,7 @@ export class AggConfig { * @return {void|Object} - if the config has a dsl representation, it is * returned, else undefined is returned */ - toDsl(aggConfigs?: AggConfigs) { + toDsl(aggConfigs?: IAggConfigs) { if (this.type.hasNoDsl) return; const output = this.write(aggConfigs) as any; @@ -448,7 +451,7 @@ export class AggConfig { }); } - public setType(type: string | AggType) { + public setType(type: string | IAggType) { this.type = typeof type === 'string' ? getTypeFromRegistry(type) : type; } diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts index b6d987136e364..7e7e4944b00da 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts @@ -55,6 +55,9 @@ function parseParentAggs(dslLvlCursor: any, dsl: any) { } } +// TODO need to make a more explicit interface for this +export type IAggConfigs = AggConfigs; + export class AggConfigs { public indexPattern: IndexPattern; public schemas: any; diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_params.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_params.ts index 262a57f4a5aa3..34727ff4614b9 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_params.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_params.ts @@ -25,7 +25,7 @@ import { JsonParamType } from './param_types/json'; import { BaseParamType } from './param_types/base'; import { AggConfig } from './agg_config'; -import { AggConfigs } from './agg_configs'; +import { IAggConfigs } from './agg_configs'; const paramTypeMap = { field: FieldParamType, @@ -73,7 +73,7 @@ export const writeParams = < >( params: Array> = [], aggConfig: TAggConfig, - aggs?: AggConfigs, + aggs?: IAggConfigs, locals?: Record ) => { const output = { params: {} as Record }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts index 9b34910e81e88..6d4c2d1317f50 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts @@ -18,7 +18,7 @@ */ import { AggType, AggTypeConfig } from './agg_type'; -import { AggConfig } from './agg_config'; +import { IAggConfig } from './agg_config'; import { npStart } from 'ui/new_platform'; jest.mock('ui/new_platform'); @@ -48,7 +48,7 @@ describe('AggType Class', () => { describe('makeLabel', () => { it('makes a function when the makeLabel config is not specified', () => { const makeLabel = () => 'label'; - const aggConfig = {} as AggConfig; + const aggConfig = {} as IAggConfig; const config: AggTypeConfig = { name: 'name', title: 'title', @@ -64,7 +64,7 @@ describe('AggType Class', () => { describe('getResponseAggs/getRequestAggs', () => { it('copies the value', () => { - const testConfig = (aggConfig: AggConfig) => [aggConfig]; + const testConfig = (aggConfig: IAggConfig) => [aggConfig]; const aggType = new AggType({ name: 'name', @@ -78,7 +78,7 @@ describe('AggType Class', () => { }); it('defaults to noop', () => { - const aggConfig = {} as AggConfig; + const aggConfig = {} as IAggConfig; const aggType = new AggType({ name: 'name', title: 'title', @@ -130,13 +130,13 @@ describe('AggType Class', () => { }); describe('getFormat', function() { - let aggConfig: AggConfig; + let aggConfig: IAggConfig; let field: any; beforeEach(() => { aggConfig = ({ getField: jest.fn(() => field), - } as unknown) as AggConfig; + } as unknown) as IAggConfig; }); it('returns the formatter for the aggConfig', () => { diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts index 64865d60fddaa..c767a3e91c078 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts @@ -23,7 +23,7 @@ import { npStart } from 'ui/new_platform'; import { initParams } from './agg_params'; import { AggConfig } from './agg_config'; -import { AggConfigs } from './agg_configs'; +import { IAggConfigs } from './agg_configs'; import { Adapters } from '../../../../../../plugins/inspector/public'; import { BaseParamType } from './param_types/base'; import { AggParamType } from './param_types/agg'; @@ -52,7 +52,7 @@ export interface AggTypeConfig< decorateAggConfig?: () => any; postFlightRequest?: ( resp: any, - aggConfigs: AggConfigs, + aggConfigs: IAggConfigs, aggConfig: TAggConfig, searchSource: ISearchSource, inspectorAdapters: Adapters, @@ -70,6 +70,9 @@ const getFormat = (agg: AggConfig) => { return field ? field.format : fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.STRING); }; +// TODO need to make a more explicit interface for this +export type IAggType = AggType; + export class AggType< TAggConfig extends AggConfig = AggConfig, TParam extends AggParamType = AggParamType @@ -182,7 +185,7 @@ export class AggType< */ postFlightRequest: ( resp: any, - aggConfigs: AggConfigs, + aggConfigs: IAggConfigs, aggConfig: TAggConfig, searchSource: ISearchSource, inspectorAdapters: Adapters, diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts index effa49f0ade6b..5ff68c5426e34 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts @@ -18,7 +18,7 @@ */ import { geoHashBucketAgg, IBucketGeoHashGridAggConfig } from './geo_hash'; -import { AggConfigs } from '../agg_configs'; +import { AggConfigs, IAggConfigs } from '../agg_configs'; import { BUCKET_TYPES } from './bucket_agg_types'; jest.mock('ui/new_platform'); @@ -121,7 +121,7 @@ describe('Geohash Agg', () => { describe('getRequestAggs', () => { describe('initial aggregation creation', () => { - let aggConfigs: AggConfigs; + let aggConfigs: IAggConfigs; let geoHashGridAgg: IBucketGeoHashGridAggConfig; beforeEach(() => { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts index 8db9226e41eec..37b829bfc20fb 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts @@ -18,6 +18,7 @@ */ import { AggConfigs } from '../index'; +import { IAggConfigs } from '../types'; import { BUCKET_TYPES } from './bucket_agg_types'; import { significantTermsBucketAgg } from './significant_terms'; import { IBucketAggConfig } from './_bucket_agg_type'; @@ -56,7 +57,7 @@ describe('Significant Terms Agg', () => { ); }; - const testSerializeAndWrite = (aggs: AggConfigs) => { + const testSerializeAndWrite = (aggs: IAggConfigs) => { const agg = aggs.aggs[0]; const { [BUCKET_TYPES.SIGNIFICANT_TERMS]: params } = agg.toDsl(); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts index 2b009fe1a9297..a78fe9a386934 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts @@ -25,7 +25,7 @@ import { BUCKET_TYPES } from './bucket_agg_types'; import { IBucketAggConfig } from './_bucket_agg_type'; import { createFilterTerms } from './create_filter/terms'; import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; -import { AggConfigs } from '../agg_configs'; +import { IAggConfigs } from '../agg_configs'; import { Adapters } from '../../../../../../../plugins/inspector/public'; import { @@ -99,7 +99,7 @@ export const termsBucketAgg = new BucketAggType({ createFilter: createFilterTerms, postFlightRequest: async ( resp: any, - aggConfigs: AggConfigs, + aggConfigs: IAggConfigs, aggConfig: IBucketAggConfig, searchSource: ISearchSource, inspectorAdapters: Adapters, diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts index 64bd6955e518e..cc1288d339692 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts @@ -19,7 +19,8 @@ import { IndexPattern } from '../../../../../../../plugins/data/public'; import { AggTypeFilters } from './agg_type_filters'; -import { AggConfig, AggType } from '..'; +import { AggConfig } from '..'; +import { IAggType } from '../types'; describe('AggTypeFilters', () => { let registry: AggTypeFilters; @@ -31,13 +32,13 @@ describe('AggTypeFilters', () => { }); it('should filter nothing without registered filters', async () => { - const aggTypes = [{ name: 'count' }, { name: 'sum' }] as AggType[]; + const aggTypes = [{ name: 'count' }, { name: 'sum' }] as IAggType[]; const filtered = registry.filter(aggTypes, indexPattern, aggConfig); expect(filtered).toEqual(aggTypes); }); it('should pass all aggTypes to the registered filter', async () => { - const aggTypes = [{ name: 'count' }, { name: 'sum' }] as AggType[]; + const aggTypes = [{ name: 'count' }, { name: 'sum' }] as IAggType[]; const filter = jest.fn(); registry.addFilter(filter); registry.filter(aggTypes, indexPattern, aggConfig); @@ -46,7 +47,7 @@ describe('AggTypeFilters', () => { }); it('should allow registered filters to filter out aggTypes', async () => { - const aggTypes = [{ name: 'count' }, { name: 'sum' }, { name: 'avg' }] as AggType[]; + const aggTypes = [{ name: 'count' }, { name: 'sum' }, { name: 'avg' }] as IAggType[]; let filtered = registry.filter(aggTypes, indexPattern, aggConfig); expect(filtered).toEqual(aggTypes); diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts index 2cc4a6e962214..d3b38ce041d7e 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts @@ -17,12 +17,12 @@ * under the License. */ import { IndexPattern } from 'src/plugins/data/public'; -import { AggType, AggConfig } from '..'; +import { IAggConfig, IAggType } from '../types'; type AggTypeFilter = ( - aggType: AggType, + aggType: IAggType, indexPattern: IndexPattern, - aggConfig: AggConfig + aggConfig: IAggConfig ) => boolean; /** @@ -49,7 +49,7 @@ class AggTypeFilters { * @param aggConfig The aggConfig for which the returning list will be used. * @return A filtered list of the passed aggTypes. */ - public filter(aggTypes: AggType[], indexPattern: IndexPattern, aggConfig: AggConfig) { + public filter(aggTypes: IAggType[], indexPattern: IndexPattern, aggConfig: IAggConfig) { const allFilters = Array.from(this.filters); const allowedAggTypes = aggTypes.filter(aggType => { const isAggTypeAllowed = allFilters.every(filter => filter(aggType, indexPattern, aggConfig)); diff --git a/src/legacy/core_plugins/data/public/search/aggs/index.ts b/src/legacy/core_plugins/data/public/search/aggs/index.ts index 6624bbf4e5f02..1c3e8d4184494 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/index.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/index.ts @@ -22,8 +22,16 @@ export { AggType } from './agg_type'; export { AggConfig } from './agg_config'; export { AggConfigs } from './agg_configs'; export { FieldParamType } from './param_types'; +export { MetricAggType } from './metrics/metric_agg_type'; export { aggTypeFieldFilters } from './param_types/filter'; -export { parentPipelineAggHelper } from './metrics/lib/parent_pipeline_agg_helper'; +export { + parentPipelineAggHelper, + parentPipelineType, +} from './metrics/lib/parent_pipeline_agg_helper'; +export { + siblingPipelineAggHelper, + siblingPipelineType, +} from './metrics/lib/sibling_pipeline_agg_helper'; // static code export { AggParamType } from './param_types/agg'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts index 684fe721a754a..bc0359b2a213d 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts @@ -17,13 +17,13 @@ * under the License. */ -import { AggConfigs } from '../../agg_configs'; +import { IAggConfigs } from '../../agg_configs'; import { IMetricAggConfig } from '../metric_agg_type'; export const parentPipelineAggWriter = ( agg: IMetricAggConfig, output: Record, - aggConfigs?: AggConfigs + aggConfigs?: IAggConfigs ): void => { const customMetric = agg.getParam('customMetric'); const metricAgg = agg.getParam('metricAgg'); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts index 819c24f135cdc..9affb0e3b2814 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts @@ -17,13 +17,13 @@ * under the License. */ -import { AggConfigs } from '../agg_configs'; +import { AggConfigs, IAggConfigs } from '../agg_configs'; import { METRIC_TYPES } from './metric_agg_types'; jest.mock('ui/new_platform'); describe('AggTypeMetricMedianProvider class', () => { - let aggConfigs: AggConfigs; + let aggConfigs: IAggConfigs; beforeEach(() => { const field = { diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts index 1027ee5db3ac7..2f54d18809ca2 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts @@ -43,6 +43,9 @@ interface MetricAggTypeConfig subtype?: string; } +// TODO need to make a more explicit interface for this +export type IMetricAggType = MetricAggType; + export class MetricAggType extends AggType< TMetricAggConfig, MetricAggParam diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts index 7461b5cf07ee7..655e918ce07de 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts @@ -18,13 +18,13 @@ */ import { IPercentileRanksAggConfig, percentileRanksMetricAgg } from './percentile_ranks'; -import { AggConfigs } from '../agg_configs'; +import { AggConfigs, IAggConfigs } from '../agg_configs'; import { METRIC_TYPES } from './metric_agg_types'; jest.mock('ui/new_platform'); describe('AggTypesMetricsPercentileRanksProvider class', function() { - let aggConfigs: AggConfigs; + let aggConfigs: IAggConfigs; beforeEach(() => { const field = { diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.test.ts index c9f4bcc3862a0..dd1aaca973e47 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.test.ts @@ -18,13 +18,13 @@ */ import { IPercentileAggConfig, percentilesMetricAgg } from './percentiles'; -import { AggConfigs } from '../agg_configs'; +import { AggConfigs, IAggConfigs } from '../agg_configs'; import { METRIC_TYPES } from './metric_agg_types'; jest.mock('ui/new_platform'); describe('AggTypesMetricsPercentilesProvider class', () => { - let aggConfigs: AggConfigs; + let aggConfigs: IAggConfigs; beforeEach(() => { const field = { diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts index 085bad76301c0..1523cb03eb966 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts @@ -17,7 +17,7 @@ * under the License. */ -import { AggConfigs } from '../agg_configs'; +import { IAggConfigs } from '../agg_configs'; import { AggConfig } from '../agg_config'; import { FetchOptions, ISearchSource } from '../../../../../../../plugins/data/public'; @@ -31,7 +31,7 @@ export class BaseParamType { write: ( aggConfig: TAggConfig, output: Record, - aggConfigs?: AggConfigs, + aggConfigs?: IAggConfigs, locals?: Record ) => void; serialize: (value: any, aggConfig?: TAggConfig) => any; diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts index 94c11f3ee4dd1..581ff98ea42f2 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts @@ -28,6 +28,9 @@ import { Field, IFieldList, isNestedField } from '../../../../../../../plugins/d const filterByType = propFilter('type'); +// TODO need to make a more explicit interface for this +export type IFieldParamType = FieldParamType; + export class FieldParamType extends BaseParamType { required = true; scriptable = true; diff --git a/src/legacy/core_plugins/data/public/search/aggs/types.ts b/src/legacy/core_plugins/data/public/search/aggs/types.ts index 0dfcf9e1ff25e..2c918abf99fca 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/types.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/types.ts @@ -17,7 +17,12 @@ * under the License. */ +export { IAggConfig } from './agg_config'; +export { IAggConfigs } from './agg_configs'; +export { IAggType } from './agg_type'; export { AggParam, AggParamOption } from './agg_params'; +export { IFieldParamType } from './param_types'; +export { IMetricAggType } from './metrics/metric_agg_type'; export { DateRangeKey } from './buckets/date_range'; export { IpRangeKey } from './buckets/ip_range'; export { OptionedValueProp, OptionedParamEditorProps } from './param_types/optioned'; diff --git a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts index b4ea2cd378d61..5c3d68acda5de 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts +++ b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts @@ -19,7 +19,7 @@ import { get, has } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { AggConfigs } from 'ui/agg_types/agg_configs'; +import { AggConfigs, IAggConfigs } from 'ui/agg_types/agg_configs'; import { createFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; import { KibanaContext, @@ -50,7 +50,7 @@ import { serializeAggConfig } from './utils'; export interface RequestHandlerParams { searchSource: ISearchSource; - aggs: AggConfigs; + aggs: IAggConfigs; timeRange?: TimeRange; query?: Query; filters?: esFilters.Filter[]; diff --git a/src/legacy/core_plugins/data/public/search/search_service.ts b/src/legacy/core_plugins/data/public/search/search_service.ts index 1e7ee84835a98..b57a637a49e71 100644 --- a/src/legacy/core_plugins/data/public/search/search_service.ts +++ b/src/legacy/core_plugins/data/public/search/search_service.ts @@ -24,9 +24,11 @@ import { AggConfig, AggConfigs, FieldParamType, + MetricAggType, aggTypeFieldFilters, setBounds, parentPipelineAggHelper, + siblingPipelineAggHelper, } from './aggs'; interface AggsSetup { @@ -40,7 +42,9 @@ interface AggsStart { AggType: typeof AggType; aggTypeFieldFilters: typeof aggTypeFieldFilters; FieldParamType: typeof FieldParamType; + MetricAggType: typeof MetricAggType; parentPipelineAggHelper: typeof parentPipelineAggHelper; + siblingPipelineAggHelper: typeof siblingPipelineAggHelper; setBounds: typeof setBounds; } @@ -77,7 +81,9 @@ export class SearchService implements Plugin { AggType, aggTypeFieldFilters, FieldParamType, - parentPipelineAggHelper, + MetricAggType, + parentPipelineAggHelper, // TODO make static + siblingPipelineAggHelper, // TODO make static setBounds, // TODO make static }, }; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg.test.tsx index 81c866923232e..f5ce55e82967d 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg.test.tsx @@ -24,7 +24,7 @@ import { act } from 'react-dom/test-utils'; import { IndexPattern } from 'src/plugins/data/public'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; -import { AggType, AggGroupNames } from '../legacy_imports'; +import { IAggType, AggGroupNames } from '../legacy_imports'; import { DefaultEditorAgg, DefaultEditorAggProps } from './agg'; import { DefaultEditorAggParams } from './agg_params'; import { AGGS_ACTION_KEYS } from './agg_group_state'; @@ -117,7 +117,7 @@ describe('DefaultEditorAgg component', () => { (defaultProps.agg as any).brandNew = false; defaultProps.agg.type = { makeLabel: () => 'Agg description', - } as AggType; + } as IAggType; const comp = mount(); act(() => { @@ -258,11 +258,11 @@ describe('DefaultEditorAgg component', () => { it('should disable min_doc_count when agg is histogram or date_histogram', () => { defaultProps.agg.type = { name: 'histogram', - } as AggType; + } as IAggType; const compHistogram = shallow(); defaultProps.agg.type = { name: 'date_histogram', - } as AggType; + } as IAggType; const compDateHistogram = shallow(); expect(compHistogram.find(DefaultEditorAggParams).props()).toHaveProperty('disabledParams', [ @@ -276,7 +276,7 @@ describe('DefaultEditorAgg component', () => { it('should set error when agg is not histogram or date_histogram', () => { defaultProps.agg.type = { name: 'aggType', - } as AggType; + } as IAggType; const comp = shallow(); expect(comp.find(DefaultEditorAggParams).prop('aggError')).toBeDefined(); @@ -285,7 +285,7 @@ describe('DefaultEditorAgg component', () => { it('should set min_doc_count to true when agg type was changed to histogram', () => { defaultProps.agg.type = { name: 'aggType', - } as AggType; + } as IAggType; const comp = mount(); comp.setProps({ agg: { ...defaultProps.agg, type: { name: 'histogram' } } }); @@ -299,7 +299,7 @@ describe('DefaultEditorAgg component', () => { it('should set min_doc_count to 0 when agg type was changed to date_histogram', () => { defaultProps.agg.type = { name: 'aggType', - } as AggType; + } as IAggType; const comp = mount(); comp.setProps({ agg: { ...defaultProps.agg, type: { name: 'date_histogram' } } }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg.tsx index 871bd0cdf6811..5450c29450bac 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg.tsx @@ -28,7 +28,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { AggConfig } from '../legacy_imports'; +import { IAggConfig } from '../legacy_imports'; import { DefaultEditorAggParams } from './agg_params'; import { DefaultEditorAggCommonProps } from './agg_common_props'; import { AGGS_ACTION_KEYS, AggsAction } from './agg_group_state'; @@ -36,7 +36,7 @@ import { RowsOrColumnsControl } from './controls/rows_or_columns'; import { RadiusRatioOptionControl } from './controls/radius_ratio_option'; export interface DefaultEditorAggProps extends DefaultEditorAggCommonProps { - agg: AggConfig; + agg: IAggConfig; aggIndex: number; aggIsTooLow: boolean; dragHandleProps: {} | null; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_add.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_add.tsx index f5175126c31c1..d8df5b315fca0 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_add.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_add.tsx @@ -29,10 +29,10 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { AggConfig, AggGroupNames, Schema } from '../legacy_imports'; +import { IAggConfig, AggGroupNames, Schema } from '../legacy_imports'; interface DefaultEditorAggAddProps { - group?: AggConfig[]; + group?: IAggConfig[]; groupName: string; schemas: Schema[]; stats: { diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts index 8d803810b647a..17d2c18d2532c 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts @@ -18,25 +18,25 @@ */ import { VisState, VisParams } from 'src/legacy/core_plugins/visualizations/public'; -import { AggType, AggConfig, AggGroupNames, Schema } from '../legacy_imports'; +import { IAggType, IAggConfig, AggGroupNames, Schema } from '../legacy_imports'; -type AggId = AggConfig['id']; -type AggParams = AggConfig['params']; +type AggId = IAggConfig['id']; +type AggParams = IAggConfig['params']; export type AddSchema = (schemas: Schema) => void; -export type ReorderAggs = (sourceAgg: AggConfig, destinationAgg: AggConfig) => void; +export type ReorderAggs = (sourceAgg: IAggConfig, destinationAgg: IAggConfig) => void; export interface DefaultEditorCommonProps { formIsTouched: boolean; groupName: AggGroupNames; - metricAggs: AggConfig[]; + metricAggs: IAggConfig[]; state: VisState; setAggParamValue: ( aggId: AggId, paramName: T, value: AggParams[T] ) => void; - onAggTypeChange: (aggId: AggId, aggType: AggType) => void; + onAggTypeChange: (aggId: AggId, aggType: IAggType) => void; } export interface DefaultEditorAggCommonProps extends DefaultEditorCommonProps { diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx index 9cbcc31bdc60e..c36c0176439f9 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx @@ -21,7 +21,7 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; import { act } from 'react-dom/test-utils'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; -import { AggConfigs, AggConfig, Schema } from '../legacy_imports'; +import { IAggConfigs, IAggConfig, Schema } from '../legacy_imports'; import { DefaultEditorAggGroup, DefaultEditorAggGroupProps } from './agg_group'; import { DefaultEditorAgg } from './agg'; import { DefaultEditorAggAdd } from './agg_add'; @@ -56,7 +56,7 @@ jest.mock('./agg_add', () => ({ describe('DefaultEditorAgg component', () => { let defaultProps: DefaultEditorAggGroupProps; - let aggs: AggConfigs; + let aggs: IAggConfigs; let setTouched: jest.Mock; let setValidity: jest.Mock; let reorderAggs: jest.Mock; @@ -76,7 +76,7 @@ describe('DefaultEditorAgg component', () => { }, }, schema: { group: 'metrics' }, - } as AggConfig, + } as IAggConfig, { id: '3', params: { @@ -85,7 +85,7 @@ describe('DefaultEditorAgg component', () => { }, }, schema: { group: 'metrics' }, - } as AggConfig, + } as IAggConfig, { id: '2', params: { @@ -94,9 +94,9 @@ describe('DefaultEditorAgg component', () => { }, }, schema: { group: 'buckets' }, - } as AggConfig, + } as IAggConfig, ], - } as AggConfigs; + } as IAggConfigs; defaultProps = { formIsTouched: false, diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.tsx index 3491414bec809..768a9669025e4 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.tsx @@ -30,7 +30,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { AggConfig, aggGroupNamesMap, AggGroupNames, Schema } from '../legacy_imports'; +import { IAggConfig, aggGroupNamesMap, AggGroupNames, Schema } from '../legacy_imports'; import { DefaultEditorAgg } from './agg'; import { DefaultEditorAggAdd } from './agg_add'; import { AddSchema, ReorderAggs, DefaultEditorAggCommonProps } from './agg_common_props'; @@ -69,8 +69,8 @@ function DefaultEditorAggGroup({ }: DefaultEditorAggGroupProps) { const groupNameLabel = (aggGroupNamesMap() as any)[groupName]; // e.g. buckets can have no aggs - const group: AggConfig[] = useMemo( - () => state.aggs.aggs.filter((agg: AggConfig) => agg.schema.group === groupName) || [], + const group: IAggConfig[] = useMemo( + () => state.aggs.aggs.filter((agg: IAggConfig) => agg.schema.group === groupName) || [], [groupName, state.aggs.aggs] ); @@ -151,7 +151,7 @@ function DefaultEditorAggGroup({ )} <> - {group.map((agg: AggConfig, index: number) => ( + {group.map((agg: IAggConfig, index: number) => ( { - let group: AggConfig[]; + let group: IAggConfig[]; beforeEach(() => { group = [ @@ -39,7 +39,7 @@ describe('DefaultEditorGroup helpers', () => { }, }, schema: { name: 'metric', min: 1, mustBeFirst: true }, - } as AggConfig, + } as IAggConfig, { id: '2', params: { @@ -48,7 +48,7 @@ describe('DefaultEditorGroup helpers', () => { }, }, schema: { name: 'metric', min: 2 }, - } as AggConfig, + } as IAggConfig, ]; }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_helper.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_helper.tsx index 87f0d00d50a1d..d2e8e5401c0f7 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_helper.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_helper.tsx @@ -18,12 +18,12 @@ */ import { findIndex, isEmpty } from 'lodash'; -import { AggConfig } from '../legacy_imports'; +import { IAggConfig } from '../legacy_imports'; import { AggsState } from './agg_group_state'; -const isAggRemovable = (agg: AggConfig, group: AggConfig[]) => { +const isAggRemovable = (agg: IAggConfig, group: IAggConfig[]) => { const metricCount = group.reduce( - (count, aggregation: AggConfig) => + (count, aggregation: IAggConfig) => aggregation.schema.name === agg.schema.name ? ++count : count, 0 ); @@ -31,20 +31,20 @@ const isAggRemovable = (agg: AggConfig, group: AggConfig[]) => { return metricCount > agg.schema.min; }; -const getEnabledMetricAggsCount = (group: AggConfig[]) => { +const getEnabledMetricAggsCount = (group: IAggConfig[]) => { return group.reduce( - (count, aggregation: AggConfig) => + (count, aggregation: IAggConfig) => aggregation.schema.name === 'metric' && aggregation.enabled ? ++count : count, 0 ); }; -const calcAggIsTooLow = (agg: AggConfig, aggIndex: number, group: AggConfig[]) => { +const calcAggIsTooLow = (agg: IAggConfig, aggIndex: number, group: IAggConfig[]) => { if (!agg.schema.mustBeFirst) { return false; } - const firstDifferentSchema = findIndex(group, (aggr: AggConfig) => { + const firstDifferentSchema = findIndex(group, (aggr: IAggConfig) => { return aggr.schema !== agg.schema; }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_state.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_state.tsx index b06ca1c2ce57a..d022297ae72b3 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_state.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group_state.tsx @@ -17,7 +17,7 @@ * under the License. */ -import { AggConfig } from '../legacy_imports'; +import { IAggConfig } from '../legacy_imports'; export enum AGGS_ACTION_KEYS { TOUCHED = 'aggsTouched', @@ -52,7 +52,7 @@ function aggGroupReducer(state: AggsState, action: AggsAction): AggsState { } } -function initAggsState(group: AggConfig[]): AggsState { +function initAggsState(group: IAggConfig[]): AggsState { return group.reduce((state, agg) => { state[agg.id] = { touched: false, valid: true }; return state; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_param_props.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_param_props.ts index 01a41d3c412c2..fc535884c69ff 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_param_props.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_param_props.ts @@ -19,7 +19,7 @@ import { Field } from 'src/plugins/data/public'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; -import { AggConfig, AggParam, EditorConfig } from '../legacy_imports'; +import { IAggConfig, AggParam, EditorConfig } from '../legacy_imports'; import { ComboBoxGroupedOptions } from '../utils'; // NOTE: we cannot export the interface with export { InterfaceName } @@ -27,7 +27,7 @@ import { ComboBoxGroupedOptions } from '../utils'; // https://github.com/babel/babel/issues/7641 // export interface AggParamCommonProps { - agg: AggConfig; + agg: IAggConfig; aggParam: P; disabled?: boolean; editorConfig: EditorConfig; @@ -36,7 +36,7 @@ export interface AggParamCommonProps { showValidation: boolean; state: VisState; value?: T; - metricAggs: AggConfig[]; + metricAggs: IAggConfig[]; } export interface AggParamEditorProps extends AggParamCommonProps { diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.test.tsx index d782c819c7c41..5636059394bac 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.test.tsx @@ -23,7 +23,7 @@ import { mount, shallow } from 'enzyme'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { IndexPattern } from 'src/plugins/data/public'; import { DefaultEditorAggParams, DefaultEditorAggParamsProps } from './agg_params'; -import { AggConfig, AggGroupNames } from '../legacy_imports'; +import { IAggConfig, AggGroupNames } from '../legacy_imports'; const mockEditorConfig = { useNormalizedEsInterval: { hidden: false, fixedValue: false }, @@ -97,7 +97,7 @@ describe('DefaultEditorAggParams component', () => { schema: { title: '', }, - } as any) as AggConfig, + } as any) as IAggConfig, groupName: AggGroupNames.Metrics, formIsTouched: false, indexPattern: {} as IndexPattern, diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.tsx index 47e98f175ab73..1b450957f3b26 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.tsx @@ -24,7 +24,7 @@ import useUnmount from 'react-use/lib/useUnmount'; import { IndexPattern } from 'src/plugins/data/public'; import { - AggConfig, + IAggConfig, AggGroupNames, editorConfigProviders, FixedParam, @@ -54,7 +54,7 @@ type EditorParamConfigType = EditorParamConfig & { }; export interface DefaultEditorAggParamsProps extends DefaultEditorCommonProps { - agg: AggConfig; + agg: IAggConfig; aggError?: string; aggIndex?: number; aggIsTooLow?: boolean; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.test.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.test.ts index 6f584b4329500..ec56d22143699 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.test.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.test.ts @@ -20,8 +20,8 @@ import { IndexPattern, Field } from 'src/plugins/data/public'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { - AggConfig, - AggType, + IAggConfig, + IAggType, AggGroupNames, BUCKET_TYPES, IndexedArray, @@ -42,10 +42,10 @@ jest.mock('ui/new_platform'); describe('DefaultEditorAggParams helpers', () => { describe('getAggParamsToRender', () => { - let agg: AggConfig; + let agg: IAggConfig; let editorConfig: EditorConfig; const state = {} as VisState; - const metricAggs: AggConfig[] = []; + const metricAggs: IAggConfig[] = []; const emptyParams = { basic: [], advanced: [], @@ -57,14 +57,14 @@ describe('DefaultEditorAggParams helpers', () => { params: [{ name: 'interval' }], }, schema: {}, - } as AggConfig; + } as IAggConfig; const params = getAggParamsToRender({ agg, editorConfig, metricAggs, state }); expect(params).toEqual(emptyParams); }); it('should not create any param if there is no agg type', () => { - agg = {} as AggConfig; + agg = {} as IAggConfig; const params = getAggParamsToRender({ agg, editorConfig, metricAggs, state }); expect(params).toEqual(emptyParams); @@ -75,7 +75,7 @@ describe('DefaultEditorAggParams helpers', () => { type: { params: [{ name: 'interval' }], }, - } as AggConfig; + } as IAggConfig; editorConfig = { interval: { hidden: true, @@ -94,7 +94,7 @@ describe('DefaultEditorAggParams helpers', () => { schema: { hideCustomLabel: true, }, - } as AggConfig; + } as IAggConfig; const params = getAggParamsToRender({ agg, editorConfig, metricAggs, state }); expect(params).toEqual(emptyParams); @@ -131,7 +131,7 @@ describe('DefaultEditorAggParams helpers', () => { orderBy: 'orderBy', field: 'field', }, - } as any) as AggConfig; + } as any) as IAggConfig; const params = getAggParamsToRender({ agg, editorConfig, metricAggs, state }); expect(params).toEqual({ @@ -166,14 +166,14 @@ describe('DefaultEditorAggParams helpers', () => { describe('getAggTypeOptions', () => { it('should return agg type options grouped by subtype', () => { const indexPattern = {} as IndexPattern; - const aggs = getAggTypeOptions({} as AggConfig, indexPattern, 'metrics'); + const aggs = getAggTypeOptions({} as IAggConfig, indexPattern, 'metrics'); expect(aggs).toEqual(['indexedFields']); }); }); describe('isInvalidParamsTouched', () => { - let aggType: AggType; + let aggType: IAggType; const aggTypeState = { touched: false, valid: true, diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.ts index 21154bd7ad603..5a9d95725c8e4 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.ts @@ -29,17 +29,17 @@ import { aggTypeFilters, aggTypeFieldFilters, aggTypes, - AggConfig, + IAggConfig, AggParam, - FieldParamType, - AggType, + IFieldParamType, + IAggType, EditorConfig, } from '../legacy_imports'; interface ParamInstanceBase { - agg: AggConfig; + agg: IAggConfig; editorConfig: EditorConfig; - metricAggs: AggConfig[]; + metricAggs: IAggConfig[]; state: VisState; } @@ -73,7 +73,7 @@ function getAggParamsToRender({ agg, editorConfig, metricAggs, state }: ParamIns } // if field param exists, compute allowed fields if (param.type === 'field') { - const availableFields: Field[] = (param as FieldParamType).getAvailableFields( + const availableFields: Field[] = (param as IFieldParamType).getAvailableFields( agg.getIndexPattern().fields ); fields = aggTypeFieldFilters.filter(availableFields, agg); @@ -117,10 +117,10 @@ function getAggParamsToRender({ agg, editorConfig, metricAggs, state }: ParamIns } function getAggTypeOptions( - agg: AggConfig, + agg: IAggConfig, indexPattern: IndexPattern, groupName: string -): ComboBoxGroupedOptions { +): ComboBoxGroupedOptions { const aggTypeOptions = aggTypeFilters.filter((aggTypes as any)[groupName], indexPattern, agg); return groupAndSortBy(aggTypeOptions as any[], 'subtype', 'title'); } @@ -135,7 +135,7 @@ function getAggTypeOptions( * @param aggParams State of aggregation parameters. */ function isInvalidParamsTouched( - aggType: AggType, + aggType: IAggType, aggTypeState: AggTypeState, aggParams: AggParamsState ) { diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_select.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_select.tsx index 2a9c74521e525..0ec19bfa1b843 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_select.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_select.tsx @@ -24,20 +24,20 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { IndexPattern } from 'src/plugins/data/public'; -import { AggType, documentationLinks } from '../legacy_imports'; +import { IAggType, documentationLinks } from '../legacy_imports'; import { ComboBoxGroupedOptions } from '../utils'; import { AGG_TYPE_ACTION_KEYS, AggTypeAction } from './agg_params_state'; interface DefaultEditorAggSelectProps { aggError?: string; - aggTypeOptions: ComboBoxGroupedOptions; + aggTypeOptions: ComboBoxGroupedOptions; id: string; indexPattern: IndexPattern; showValidation: boolean; isSubAggregation: boolean; - value: AggType; + value: IAggType; onChangeAggType: React.Dispatch; - setValue: (aggType: AggType) => void; + setValue: (aggType: IAggType) => void; } function DefaultEditorAggSelect({ @@ -51,7 +51,7 @@ function DefaultEditorAggSelect({ isSubAggregation, onChangeAggType, }: DefaultEditorAggSelectProps) { - const selectedOptions: ComboBoxGroupedOptions = value + const selectedOptions: ComboBoxGroupedOptions = value ? [{ label: value.title, target: value }] : []; @@ -104,7 +104,7 @@ function DefaultEditorAggSelect({ (options: EuiComboBoxOptionProps[]) => { const selectedOption = get(options, '0.target'); if (selectedOption) { - setValue(selectedOption as AggType); + setValue(selectedOption as IAggType); } }, [setValue] diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_control_props.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_control_props.tsx index c8b5196d3b299..7f04b851902de 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_control_props.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_control_props.tsx @@ -18,11 +18,11 @@ */ import { VisParams } from 'src/legacy/core_plugins/visualizations/public'; -import { AggConfig } from '../../legacy_imports'; +import { IAggConfig } from '../../legacy_imports'; import { DefaultEditorAggCommonProps } from '../agg_common_props'; export interface AggControlProps { - agg: AggConfig; + agg: IAggConfig; editorStateParams: VisParams; setAggParamValue: DefaultEditorAggCommonProps['setAggParamValue']; setStateParamValue: DefaultEditorAggCommonProps['setStateParamValue']; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_utils.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_utils.test.tsx index 5c69fd0f1c091..0b847e3747b30 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_utils.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/agg_utils.test.tsx @@ -20,7 +20,7 @@ import React, { FunctionComponent } from 'react'; import { mount, ReactWrapper } from 'enzyme'; -import { AggConfig } from '../../legacy_imports'; +import { IAggConfig } from '../../legacy_imports'; import { safeMakeLabel, useAvailableOptions, @@ -57,7 +57,7 @@ const metricAggs = [ return 'avg'; }, }, -] as AggConfig[]; +] as IAggConfig[]; const incompatibleAggs = [ { @@ -74,7 +74,7 @@ const incompatibleAggs = [ return 'percentiles'; }, }, -] as AggConfig[]; +] as IAggConfig[]; const aggFilter = ['!top_hits', '!percentiles']; describe('Aggregations utils', () => { @@ -222,7 +222,7 @@ describe('Aggregations utils', () => { }); test('should not fail and return a safety string if makeLabel func is not exist', () => { - const label = safeMakeLabel({} as AggConfig); + const label = safeMakeLabel({} as IAggConfig); expect(label).toEqual(expect.any(String)); }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.test.tsx index e43304fe07347..636ef8f872d0e 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.test.tsx @@ -26,7 +26,7 @@ import { Field } from 'src/plugins/data/public'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { ComboBoxGroupedOptions } from '../../utils'; import { FieldParamEditor, FieldParamEditorProps } from './field'; -import { AggConfig } from '../../legacy_imports'; +import { IAggConfig } from '../../legacy_imports'; function callComboBoxOnChange(comp: ReactWrapper, value: any = []) { const comboBoxProps: EuiComboBoxProps = comp.find(EuiComboBox).props(); @@ -64,7 +64,7 @@ describe('FieldParamEditor component', () => { ]; defaultProps = { - agg: {} as AggConfig, + agg: {} as IAggConfig, aggParam: { name: 'field', type: 'field', @@ -80,7 +80,7 @@ describe('FieldParamEditor component', () => { setValidity, setTouched, state: {} as VisState, - metricAggs: [] as AggConfig[], + metricAggs: [] as IAggConfig[], }; }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx index 38c55e8fe3f24..d3eeb37fa9887 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx @@ -24,7 +24,7 @@ import { EuiComboBox, EuiComboBoxOptionProps, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Field } from 'src/plugins/data/public'; -import { AggConfig, AggParam, FieldParamType } from '../../legacy_imports'; +import { AggParam, IAggConfig, IFieldParamType } from '../../legacy_imports'; import { formatListAsProse, parseCommaSeparatedList, useValidation } from './utils'; import { AggParamEditorProps } from '../agg_param_props'; import { ComboBoxGroupedOptions } from '../../utils'; @@ -126,9 +126,9 @@ function FieldParamEditor({ ); } -function getFieldTypesString(agg: AggConfig) { +function getFieldTypesString(agg: IAggConfig) { const param = - get(agg, 'type.params', []).find((p: AggParam) => p.name === 'field') || ({} as FieldParamType); + get(agg, 'type.params', []).find((p: AggParam) => p.name === 'field') || ({} as IFieldParamType); return formatListAsProse(parseCommaSeparatedList(param.filterFieldTypes), { inclusive: false }); } diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/filter.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/filter.tsx index 38c5b552553ae..3622b27bad403 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/filter.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/filter.tsx @@ -22,7 +22,7 @@ import { EuiForm, EuiButtonIcon, EuiFieldText, EuiFormRow, EuiSpacer } from '@el import { i18n } from '@kbn/i18n'; import { Query, QueryStringInput } from '../../../../../../plugins/data/public'; -import { AggConfig } from '../../legacy_imports'; +import { IAggConfig } from '../../legacy_imports'; interface FilterRowProps { id: string; @@ -34,7 +34,7 @@ interface FilterRowProps { dataTestSubj: string; onChangeValue(id: string, query: Query, label: string): void; onRemoveFilter(id: string): void; - agg: AggConfig; + agg: IAggConfig; } function FilterRow({ diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/metric_agg.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/metric_agg.test.tsx index 9b6fd204e7207..cf7af1aa5cb3a 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/metric_agg.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/metric_agg.test.tsx @@ -20,7 +20,7 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; -import { AggConfig } from '../../legacy_imports'; +import { IAggConfig } from '../../legacy_imports'; import { DEFAULT_OPTIONS, aggFilter, MetricAggParamEditor } from './metric_agg'; jest.mock('./utils', () => ({ @@ -44,7 +44,7 @@ const agg = { makeLabel() { return 'cumulative_sum'; }, -} as AggConfig; +} as IAggConfig; const metricAggs = [ agg, @@ -69,7 +69,7 @@ const metricAggs = [ return 'max'; }, }, -] as AggConfig[]; +] as IAggConfig[]; describe('MetricAggParamEditor', () => { let defaultProps: Partial>; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/order_agg.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/order_agg.tsx index 6bb9ad334d149..10679b578d54e 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/order_agg.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/order_agg.tsx @@ -20,7 +20,7 @@ import React, { useEffect } from 'react'; import { EuiSpacer } from '@elastic/eui'; -import { AggParamType, AggConfig, AggGroupNames } from '../../legacy_imports'; +import { AggParamType, IAggConfig, AggGroupNames } from '../../legacy_imports'; import { useSubAggParamsHandlers } from './utils'; import { AggParamEditorProps } from '../agg_param_props'; import { DefaultEditorAggParams } from '../agg_params'; @@ -35,7 +35,7 @@ function OrderAggParamEditor({ setValue, setValidity, setTouched, -}: AggParamEditorProps) { +}: AggParamEditorProps) { const orderBy = agg.params.orderBy; useEffect(() => { @@ -51,7 +51,7 @@ function OrderAggParamEditor({ const { onAggTypeChange, setAggParamValue } = useSubAggParamsHandlers( agg, aggParam, - value as AggConfig, + value as IAggConfig, setValue ); @@ -63,7 +63,7 @@ function OrderAggParamEditor({ <> ) { +}: AggParamEditorProps) { useEffect(() => { // we aren't creating a custom aggConfig if (agg.params.metricAgg !== 'custom') { diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/sub_metric.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/sub_metric.tsx index 9898d943870bc..45ff0610d88ed 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/sub_metric.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/sub_metric.tsx @@ -21,7 +21,7 @@ import React, { useEffect } from 'react'; import { EuiFormLabel, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { AggParamType, AggConfig, AggGroupNames } from '../../legacy_imports'; +import { AggParamType, IAggConfig, AggGroupNames } from '../../legacy_imports'; import { useSubAggParamsHandlers } from './utils'; import { AggParamEditorProps } from '../agg_param_props'; import { DefaultEditorAggParams } from '../agg_params'; @@ -35,7 +35,7 @@ function SubMetricParamEditor({ setValue, setValidity, setTouched, -}: AggParamEditorProps) { +}: AggParamEditorProps) { const metricTitle = i18n.translate('visDefaultEditor.controls.metrics.metricTitle', { defaultMessage: 'Metric', }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/test_utils.ts b/src/legacy/core_plugins/vis_default_editor/public/components/controls/test_utils.ts index 4e811f4543412..894bc594a08d7 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/test_utils.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/test_utils.ts @@ -18,14 +18,14 @@ */ import { VisState } from 'src/legacy/core_plugins/visualizations/public'; -import { AggConfig, AggParam, EditorConfig } from '../../legacy_imports'; +import { IAggConfig, AggParam, EditorConfig } from '../../legacy_imports'; export const aggParamCommonPropsMock = { - agg: {} as AggConfig, + agg: {} as IAggConfig, aggParam: {} as AggParam, editorConfig: {} as EditorConfig, formIsTouched: false, - metricAggs: [] as AggConfig[], + metricAggs: [] as IAggConfig[], state: {} as VisState, showValidation: false, }; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.test.tsx index b0c3fe00606aa..4ce0712040bd5 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.test.tsx @@ -25,10 +25,10 @@ import { TopAggregateParamEditorProps, } from './top_aggregate'; import { aggParamCommonPropsMock } from './test_utils'; -import { AggConfig } from '../../legacy_imports'; +import { IAggConfig } from '../../legacy_imports'; describe('TopAggregateParamEditor', () => { - let agg: AggConfig; + let agg: IAggConfig; let aggParam: any; let defaultProps: TopAggregateParamEditorProps; let options: AggregateValueProp[]; @@ -37,17 +37,17 @@ describe('TopAggregateParamEditor', () => { options = [ { text: 'Min', - isCompatible: jest.fn((aggr: AggConfig) => aggr.params.field.type === 'number'), + isCompatible: jest.fn((aggr: IAggConfig) => aggr.params.field.type === 'number'), value: 'min', }, { text: 'Max', - isCompatible: jest.fn((aggr: AggConfig) => aggr.params.field.type === 'number'), + isCompatible: jest.fn((aggr: IAggConfig) => aggr.params.field.type === 'number'), value: 'max', }, { text: 'Average', - isCompatible: jest.fn((aggr: AggConfig) => aggr.params.field.type === 'string'), + isCompatible: jest.fn((aggr: IAggConfig) => aggr.params.field.type === 'string'), value: 'average', }, ]; @@ -69,7 +69,7 @@ describe('TopAggregateParamEditor', () => { }, }, getAggParams: jest.fn(() => [{ name: 'aggregate', options }]), - } as any) as AggConfig; + } as any) as IAggConfig; defaultProps = { ...aggParamCommonPropsMock, agg, @@ -150,7 +150,7 @@ describe('TopAggregateParamEditor', () => { type: 'string', }, }, - } as AggConfig; + } as IAggConfig; comp.setProps({ agg }); @@ -165,7 +165,7 @@ describe('TopAggregateParamEditor', () => { type: 'date', }, }, - } as AggConfig; + } as IAggConfig; comp.setProps({ agg }); @@ -179,7 +179,7 @@ describe('TopAggregateParamEditor', () => { type: 'string', }, }, - } as AggConfig; + } as IAggConfig; comp.setProps({ agg, value: undefined }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.tsx index 338e2fe463a80..346dfc0156f07 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/top_aggregate.tsx @@ -23,7 +23,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { - AggConfig, + IAggConfig, AggParam, OptionedValueProp, OptionedParamEditorProps, @@ -32,13 +32,13 @@ import { import { AggParamEditorProps } from '../agg_param_props'; export interface AggregateValueProp extends OptionedValueProp { - isCompatible(aggConfig: AggConfig): boolean; + isCompatible(aggConfig: IAggConfig): boolean; } export type TopAggregateParamEditorProps = AggParamEditorProps & OptionedParamEditorProps; -export function getCompatibleAggs(agg: AggConfig): AggregateValueProp[] { +export function getCompatibleAggs(agg: IAggConfig): AggregateValueProp[] { const { options = [] } = agg .getAggParams() .find(({ name }: AggParam) => name === 'aggregate') as OptionedParamType; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/agg_utils.ts b/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/agg_utils.ts index 4c8ba23e63268..8aeae488942cd 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/agg_utils.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/agg_utils.ts @@ -20,7 +20,7 @@ import { useEffect, useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; -import { AggConfig } from '../../../legacy_imports'; +import { IAggConfig } from '../../../legacy_imports'; type AggFilter = string[]; @@ -43,7 +43,7 @@ function useCompatibleAggCallback(aggFilter: AggFilter) { function useFallbackMetric( setValue: (value?: string) => void, aggFilter: AggFilter, - metricAggs?: AggConfig[], + metricAggs?: IAggConfig[], value?: string, fallbackValue?: string ) { @@ -69,7 +69,7 @@ function useFallbackMetric( */ function useAvailableOptions( aggFilter: AggFilter, - metricAggs: AggConfig[] = [], + metricAggs: IAggConfig[] = [], defaultOptions: Array<{ text: string; value: string }> = [] ) { const isCompatibleAgg = useCompatibleAggCallback(aggFilter); @@ -107,7 +107,7 @@ function useValidation(setValidity: (isValid: boolean) => void, isValid: boolean }, [isValid, setValidity]); } -function safeMakeLabel(agg: AggConfig): string { +function safeMakeLabel(agg: IAggConfig): string { try { return agg.makeLabel(); } catch (e) { @@ -118,7 +118,7 @@ function safeMakeLabel(agg: AggConfig): string { } function isCompatibleAggregation(aggFilter: string[]) { - return (agg: AggConfig) => { + return (agg: IAggConfig) => { return !aggFilter.includes(`!${agg.type.name}`); }; } diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/use_handlers.ts b/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/use_handlers.ts index c2da648edcf81..c7816d5a9d305 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/use_handlers.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/utils/use_handlers.ts @@ -19,14 +19,14 @@ import { useCallback } from 'react'; -import { AggConfig, AggParamType } from '../../../legacy_imports'; +import { IAggConfig, AggParamType } from '../../../legacy_imports'; -type SetValue = (value?: AggConfig) => void; +type SetValue = (value?: IAggConfig) => void; function useSubAggParamsHandlers( - agg: AggConfig, + agg: IAggConfig, aggParam: AggParamType, - subAgg: AggConfig, + subAgg: IAggConfig, setValue: SetValue ) { const setAggParamValue = useCallback( diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/data_tab.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/data_tab.tsx index c7597ef43dfa6..efd17f02a0e09 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/data_tab.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/data_tab.tsx @@ -23,11 +23,11 @@ import { EuiSpacer } from '@elastic/eui'; import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { - AggConfig, + IAggConfig, AggGroupNames, ISchemas, parentPipelineType, - MetricAggType, + IMetricAggType, } from '../../legacy_imports'; import { DefaultEditorAggGroup } from '../agg_group'; import { @@ -45,7 +45,7 @@ export interface DefaultEditorDataTabProps { dispatch: React.Dispatch; formIsTouched: boolean; isTabSelected: boolean; - metricAggs: AggConfig[]; + metricAggs: IAggConfig[]; schemas: ISchemas; state: VisState; setTouched(isTouched: boolean): void; @@ -67,7 +67,7 @@ function DefaultEditorDataTab({ () => findLast( metricAggs, - ({ type }: { type: MetricAggType }) => type.subtype === parentPipelineType + ({ type }: { type: IMetricAggType }) => type.subtype === parentPipelineType ), [metricAggs] ); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/actions.ts b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/actions.ts index 5738916d2ff80..93fa1083bebf9 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/actions.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/actions.ts @@ -18,7 +18,7 @@ */ import { Vis, VisParams } from 'src/legacy/core_plugins/visualizations/public'; -import { AggConfig, Schema } from '../../../legacy_imports'; +import { IAggConfig, Schema } from '../../../legacy_imports'; import { EditorStateActionTypes } from './constants'; export interface ActionType { @@ -26,14 +26,14 @@ export interface ActionType { payload: P; } -type AggId = AggConfig['id']; -type AggParams = AggConfig['params']; +type AggId = IAggConfig['id']; +type AggParams = IAggConfig['params']; type AddNewAgg = ActionType; type DiscardChanges = ActionType; type ChangeAggType = ActionType< EditorStateActionTypes.CHANGE_AGG_TYPE, - { aggId: AggId; value: AggConfig['type'] } + { aggId: AggId; value: IAggConfig['type'] } >; type SetAggParamValue = ActionType< EditorStateActionTypes.SET_AGG_PARAM_VALUE, @@ -50,11 +50,11 @@ type SetStateParamValue = ActionTyp type RemoveAgg = ActionType; type ReorderAggs = ActionType< EditorStateActionTypes.REORDER_AGGS, - { sourceAgg: AggConfig; destinationAgg: AggConfig } + { sourceAgg: IAggConfig; destinationAgg: IAggConfig } >; type ToggleEnabledAgg = ActionType< EditorStateActionTypes.TOGGLE_ENABLED_AGG, - { aggId: AggId; enabled: AggConfig['enabled'] } + { aggId: AggId; enabled: IAggConfig['enabled'] } >; type UpdateStateParams = ActionType< EditorStateActionTypes.UPDATE_STATE_PARAMS, @@ -75,7 +75,7 @@ export type EditorAction = export interface EditorActions { addNewAgg(schema: Schema): AddNewAgg; discardChanges(vis: Vis): DiscardChanges; - changeAggType(aggId: AggId, value: AggConfig['type']): ChangeAggType; + changeAggType(aggId: AggId, value: IAggConfig['type']): ChangeAggType; setAggParamValue( aggId: AggId, paramName: T, @@ -86,8 +86,8 @@ export interface EditorActions { value: AggParams[T] ): SetStateParamValue; removeAgg(aggId: AggId): RemoveAgg; - reorderAggs(sourceAgg: AggConfig, destinationAgg: AggConfig): ReorderAggs; - toggleEnabledAgg(aggId: AggId, enabled: AggConfig['enabled']): ToggleEnabledAgg; + reorderAggs(sourceAgg: IAggConfig, destinationAgg: IAggConfig): ReorderAggs; + toggleEnabledAgg(aggId: AggId, enabled: IAggConfig['enabled']): ToggleEnabledAgg; updateStateParams(params: VisParams): UpdateStateParams; } diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/reducers.ts b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/reducers.ts index 8e1cfd6bc9c13..851263f0ed702 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/reducers.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/reducers.ts @@ -20,7 +20,7 @@ import { cloneDeep } from 'lodash'; import { Vis, VisState } from 'src/legacy/core_plugins/visualizations/public'; -import { AggConfigs, AggConfig, AggGroupNames, move } from '../../../legacy_imports'; +import { AggConfigs, IAggConfig, AggGroupNames, move } from '../../../legacy_imports'; import { EditorStateActionTypes } from './constants'; import { getEnabledMetricAggsCount } from '../../agg_group_helper'; import { EditorAction } from './actions'; @@ -32,7 +32,7 @@ function initEditorState(vis: Vis) { function editorStateReducer(state: VisState, action: EditorAction): VisState { switch (action.type) { case EditorStateActionTypes.ADD_NEW_AGG: { - const aggConfig = state.aggs.createAggConfig(action.payload as AggConfig, { + const aggConfig = state.aggs.createAggConfig(action.payload as IAggConfig, { addToAggConfigs: false, }); aggConfig.brandNew = true; diff --git a/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts b/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts index 5c617f3dc8681..793806c735b19 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts @@ -20,13 +20,16 @@ /* `ui/agg_types` dependencies */ export { AggType, - AggConfig, + IAggType, + IAggConfig, AggConfigs, + IAggConfigs, AggParam, AggGroupNames, aggGroupNamesMap, aggTypes, FieldParamType, + IFieldParamType, BUCKET_TYPES, METRIC_TYPES, ISchemas, @@ -36,7 +39,7 @@ export { export { aggTypeFilters, propFilter } from 'ui/agg_types/filter'; export { aggTypeFieldFilters } from 'ui/agg_types/param_types/filter'; export { AggParamType } from 'ui/agg_types/param_types/agg'; -export { MetricAggType } from 'ui/agg_types/metrics/metric_agg_type'; +export { MetricAggType, IMetricAggType } from 'ui/agg_types/metrics/metric_agg_type'; export { parentPipelineType } from 'ui/agg_types/metrics/lib/parent_pipeline_agg_helper'; export { siblingPipelineType } from 'ui/agg_types/metrics/lib/sibling_pipeline_agg_helper'; export { isType, isStringType } from 'ui/agg_types/buckets/migrate_include_exclude_format'; diff --git a/src/legacy/core_plugins/vis_default_editor/public/vis_options_props.tsx b/src/legacy/core_plugins/vis_default_editor/public/vis_options_props.tsx index f51e359d99573..babcb59c6582e 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/vis_options_props.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/vis_options_props.tsx @@ -17,11 +17,11 @@ * under the License. */ -import { AggConfigs, PersistedState } from './legacy_imports'; +import { IAggConfigs, PersistedState } from './legacy_imports'; import { Vis } from '../../visualizations/public'; export interface VisOptionsProps { - aggs: AggConfigs; + aggs: IAggConfigs; hasHistogramAgg: boolean; isTabSelected: boolean; stateParams: VisParamType; diff --git a/src/legacy/core_plugins/vis_default_editor/public/vis_type_agg_filter.ts b/src/legacy/core_plugins/vis_default_editor/public/vis_type_agg_filter.ts index c1832d5512817..c0dbdcf310c7d 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/vis_type_agg_filter.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/vis_type_agg_filter.ts @@ -17,7 +17,7 @@ * under the License. */ import { IndexPattern } from 'src/plugins/data/public'; -import { AggType, AggConfig, aggTypeFilters, propFilter } from './legacy_imports'; +import { IAggType, IAggConfig, aggTypeFilters, propFilter } from './legacy_imports'; const filterByName = propFilter('name'); @@ -25,7 +25,7 @@ const filterByName = propFilter('name'); * This filter checks the defined aggFilter in the schemas of that visualization * and limits available aggregations based on that. */ -aggTypeFilters.addFilter((aggType: AggType, indexPatterns: IndexPattern, aggConfig: AggConfig) => { +aggTypeFilters.addFilter((aggType: IAggType, indexPatterns: IndexPattern, aggConfig: IAggConfig) => { const doesSchemaAllowAggType = filterByName([aggType], aggConfig.schema.aggFilter).length !== 0; return doesSchemaAllowAggType; }); diff --git a/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts index 8a454957b7ab9..efa6c0029e6d1 100644 --- a/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts @@ -19,7 +19,7 @@ export { npSetup, npStart } from 'ui/new_platform'; export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; -export { AggConfig, AggGroupNames, Schemas } from 'ui/agg_types'; +export { IAggConfig, AggGroupNames, Schemas } from 'ui/agg_types'; // @ts-ignore export { PrivateProvider } from 'ui/private/private'; diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts index 16181a3f70ff1..d8912975227bf 100644 --- a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts +++ b/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts @@ -27,7 +27,7 @@ import './table_vis.mock'; import StubIndexPattern from 'test_utils/stub_index_pattern'; import { getAngularModule } from './get_inner_angular'; import { initTableVisLegacyModule } from './table_vis_legacy_module'; -import { npStart, AggConfig, tabifyAggResponse } from './legacy_imports'; +import { npStart, IAggConfig, tabifyAggResponse } from './legacy_imports'; import { tableVisTypeDefinition } from './table_vis_type'; import { Vis } from '../../visualizations/public'; import { setup as visualizationsSetup } from '../../visualizations/public/np_ready/public/legacy'; @@ -148,7 +148,7 @@ describe('Table Vis - Controller', () => { // basically a parameterized beforeEach function initController(vis: Vis) { - vis.aggs.aggs.forEach((agg: AggConfig, i: number) => { + vis.aggs.aggs.forEach((agg: IAggConfig, i: number) => { agg.id = 'agg_' + (i + 1); }); diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.test.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.test.tsx index 514b957765a99..944ed7e20d1f7 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.test.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.test.tsx @@ -27,7 +27,7 @@ import { Positions } from '../../../utils/collections'; import { ValueAxesPanel } from './value_axes_panel'; import { CategoryAxisPanel } from './category_axis_panel'; import { ChartTypes } from '../../../utils/collections'; -import { AggConfig, AggType } from '../../../legacy_imports'; +import { IAggConfig, IAggType } from '../../../legacy_imports'; import { defaultValueAxisId, valueAxis, seriesParam, categoryAxis } from './mocks'; jest.mock('ui/new_platform'); @@ -44,17 +44,17 @@ jest.mock('./value_axes_panel', () => ({ const SERIES_PARAMS = 'seriesParams'; const VALUE_AXES = 'valueAxes'; -const aggCount: AggConfig = { +const aggCount: IAggConfig = { id: '1', type: { name: 'count' }, makeLabel: () => 'Count', -} as AggConfig; +} as IAggConfig; -const aggAverage: AggConfig = { +const aggAverage: IAggConfig = { id: '2', - type: { name: 'average' } as AggType, + type: { name: 'average' } as IAggType, makeLabel: () => 'Average', -} as AggConfig; +} as IAggConfig; const createAggs = (aggs: any[]) => ({ aggs, diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx index c4dcbfaa47265..cdc8996f3fdeb 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx @@ -21,7 +21,7 @@ import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { cloneDeep, uniq, get } from 'lodash'; import { EuiSpacer } from '@elastic/eui'; -import { AggConfig } from '../../../legacy_imports'; +import { IAggConfig } from '../../../legacy_imports'; import { BasicVislibParams, ValueAxis, SeriesParam, Axis } from '../../../types'; import { ValidationVisOptionsProps } from '../../common'; import { SeriesPanel } from './series_panel'; @@ -99,7 +99,7 @@ function MetricsAxisOptions(props: ValidationVisOptionsProps) stateParams.valueAxes.forEach((axis, axisNumber) => { let newCustomLabel = ''; - const matchingSeries: AggConfig[] = []; + const matchingSeries: IAggConfig[] = []; series.forEach((serie, seriesIndex) => { if ((axisNumber === 0 && !serie.valueAxis) || serie.valueAxis === axis.id) { diff --git a/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts index df7278f2b761f..50a91df01de7c 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts @@ -17,7 +17,7 @@ * under the License. */ -export { AggType, AggConfig, AggGroupNames, Schemas } from 'ui/agg_types'; +export { AggType, AggGroupNames, IAggConfig, IAggType, Schemas } from 'ui/agg_types'; // @ts-ignore export { SimpleEmitter } from 'ui/utils/simple_emitter'; // @ts-ignore diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/query_geohash_bounds.ts b/src/legacy/core_plugins/visualizations/public/embeddable/query_geohash_bounds.ts index 46ade8ce465c0..719d69e21a826 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/query_geohash_bounds.ts +++ b/src/legacy/core_plugins/visualizations/public/embeddable/query_geohash_bounds.ts @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; import { toastNotifications } from 'ui/notify'; -import { AggConfig } from 'ui/agg_types'; +import { IAggConfig } from 'ui/agg_types'; import { timefilter } from 'ui/timefilter'; import { Vis } from '../np_ready/public'; import { esFilters, Query, SearchSource, ISearchSource } from '../../../../../plugins/data/public'; @@ -42,7 +42,7 @@ interface QueryGeohashBoundsParams { * TODO: Remove this as a part of elastic/kibana#30593 */ export async function queryGeohashBounds(vis: Vis, params: QueryGeohashBoundsParams) { - const agg = vis.getAggConfig().aggs.find((a: AggConfig) => { + const agg = vis.getAggConfig().aggs.find((a: IAggConfig) => { return get(a, 'type.dslName') === 'geohash_grid'; }); diff --git a/src/legacy/core_plugins/visualizations/public/legacy_imports.ts b/src/legacy/core_plugins/visualizations/public/legacy_imports.ts index 3088c4e67a3b7..02db300437d34 100644 --- a/src/legacy/core_plugins/visualizations/public/legacy_imports.ts +++ b/src/legacy/core_plugins/visualizations/public/legacy_imports.ts @@ -18,8 +18,8 @@ */ export { PersistedState } from '../../../ui/public/persisted_state'; -export { AggConfig } from '../../../ui/public/agg_types/agg_config'; -export { AggConfigs } from '../../../ui/public/agg_types/agg_configs'; +export { IAggConfig } from '../../../ui/public/agg_types/agg_config'; +export { IAggConfigs } from '../../../ui/public/agg_types/agg_configs'; export { isDateHistogramBucketAggConfig, setBounds, diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts index e733bad2c0127..0680ecbec9206 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts @@ -27,7 +27,7 @@ import { Schemas, } from './build_pipeline'; import { Vis, VisState } from '..'; -import { AggConfig } from '../../../legacy_imports'; +import { IAggConfig } from '../../../legacy_imports'; import { searchSourceMock } from '../../../legacy_mocks'; jest.mock('ui/new_platform'); @@ -367,7 +367,7 @@ describe('visualize loader pipeline helpers: build pipeline', () => { }); describe('buildVislibDimensions', () => { - let aggs: AggConfig[]; + let aggs: IAggConfig[]; let visState: any; let vis: Vis; let params: any; @@ -385,7 +385,7 @@ describe('visualize loader pipeline helpers: build pipeline', () => { name: 'metric', }, params: {}, - } as AggConfig, + } as IAggConfig, ]; params = { @@ -453,7 +453,7 @@ describe('visualize loader pipeline helpers: build pipeline', () => { it('with two numeric metrics, mixed normal and percent mode should have corresponding formatters', async () => { const aggConfig = aggs[0]; - aggs = [{ ...aggConfig } as AggConfig, { ...aggConfig, id: '5' } as AggConfig]; + aggs = [{ ...aggConfig } as IAggConfig, { ...aggConfig, id: '5' } as IAggConfig]; visState = { params: { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts index 6749a44b4d5b3..04a296a888e87 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts @@ -23,7 +23,7 @@ import moment from 'moment'; import { SerializedFieldFormat } from 'src/plugins/expressions/public'; import { ISearchSource } from 'src/plugins/data/public'; import { - AggConfig, + IAggConfig, setBounds, isDateHistogramBucketAggConfig, createFormat, @@ -85,7 +85,7 @@ const vislibCharts: string[] = [ ]; export const getSchemas = (vis: Vis, timeRange?: any): Schemas => { - const createSchemaConfig = (accessor: number, agg: AggConfig): SchemaConfig => { + const createSchemaConfig = (accessor: number, agg: IAggConfig): SchemaConfig => { if (isDateHistogramBucketAggConfig(agg)) { agg.params.timeRange = timeRange; setBounds(agg, true); @@ -130,10 +130,10 @@ export const getSchemas = (vis: Vis, timeRange?: any): Schemas => { const schemas: Schemas = { metric: [], }; - const responseAggs = vis.aggs.getResponseAggs().filter((agg: AggConfig) => agg.enabled); + const responseAggs = vis.aggs.getResponseAggs().filter((agg: IAggConfig) => agg.enabled); const isHierarchical = vis.isHierarchical(); - const metrics = responseAggs.filter((agg: AggConfig) => agg.type.type === 'metrics'); - responseAggs.forEach((agg: AggConfig) => { + const metrics = responseAggs.filter((agg: IAggConfig) => agg.type.type === 'metrics'); + responseAggs.forEach((agg: IAggConfig) => { let skipMetrics = false; let schemaName = agg.schema ? agg.schema.name || agg.schema : null; if (typeof schemaName === 'object') { @@ -224,7 +224,7 @@ export const prepareDimension = (variable: string, data: any) => { const adjustVislibDimensionFormmaters = (vis: Vis, dimensions: { y: any[] }): void => { const visState = vis.getCurrentState(); const visConfig = visState.params; - const responseAggs = vis.aggs.getResponseAggs().filter((agg: AggConfig) => agg.enabled); + const responseAggs = vis.aggs.getResponseAggs().filter((agg: IAggConfig) => agg.enabled); (dimensions.y || []).forEach(yDimension => { const yAgg = responseAggs[yDimension.accessor]; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.d.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.d.ts index 6e6a2174d6ad1..71bf9bcf983ff 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.d.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.d.ts @@ -18,7 +18,7 @@ */ import { VisType } from './types'; -import { AggConfigs } from '../../legacy_imports'; +import { IAggConfigs } from '../../legacy_imports'; import { Status } from './legacy/update_status'; export interface Vis { @@ -39,7 +39,7 @@ export interface VisState { title: string; type: VisType; params: VisParams; - aggs: AggConfigs; + aggs: IAggConfigs; } export declare class VisualizationController { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.js index 4f1526c20cb6f..0c2e5012df439 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.js +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.js @@ -21,7 +21,7 @@ * @name Vis * * @description This class consists of aggs, params, listeners, title, and type. - * - Aggs: Instances of AggConfig. + * - Aggs: Instances of IAggConfig. * - Params: The settings in the Options tab. * * Not to be confused with vislib/vis.js. diff --git a/src/legacy/ui/public/agg_response/tabify/_get_columns.ts b/src/legacy/ui/public/agg_response/tabify/_get_columns.ts index a3127c039049b..4144d5be16012 100644 --- a/src/legacy/ui/public/agg_response/tabify/_get_columns.ts +++ b/src/legacy/ui/public/agg_response/tabify/_get_columns.ts @@ -18,15 +18,15 @@ */ import { groupBy } from 'lodash'; -import { AggConfig } from '../../agg_types'; +import { IAggConfig } from '../../agg_types'; export interface AggColumn { - aggConfig: AggConfig; + aggConfig: IAggConfig; id: string; name: string; } -const getColumn = (agg: AggConfig, i: number): AggColumn => { +const getColumn = (agg: IAggConfig, i: number): AggColumn => { return { aggConfig: agg, id: `col-${i}-${agg.id}`, @@ -40,7 +40,7 @@ const getColumn = (agg: AggConfig, i: number): AggColumn => { * @param {AggConfigs} aggs - the agg configs object to which the aggregation response correlates * @param {boolean} minimalColumns - setting to true will only return a column for the last bucket/metric instead of one for each level */ -export function tabifyGetColumns(aggs: AggConfig[], minimalColumns: boolean) { +export function tabifyGetColumns(aggs: IAggConfig[], minimalColumns: boolean) { // pick the columns if (minimalColumns) { return aggs.map((agg, i) => getColumn(agg, i)); diff --git a/src/legacy/ui/public/agg_types/agg_config.ts b/src/legacy/ui/public/agg_types/agg_config.ts index 489751a83724d..ce343aa531020 100644 --- a/src/legacy/ui/public/agg_types/agg_config.ts +++ b/src/legacy/ui/public/agg_types/agg_config.ts @@ -17,4 +17,4 @@ * under the License. */ -export { AggConfig } from './index'; +export { AggConfig, IAggConfig } from './index'; diff --git a/src/legacy/ui/public/agg_types/agg_configs.ts b/src/legacy/ui/public/agg_types/agg_configs.ts index a04585dd82bdc..ab15e58702cae 100644 --- a/src/legacy/ui/public/agg_types/agg_configs.ts +++ b/src/legacy/ui/public/agg_types/agg_configs.ts @@ -17,4 +17,4 @@ * under the License. */ -export { AggConfigs } from './index'; +export { AggConfigs, IAggConfigs } from './index'; diff --git a/src/legacy/ui/public/agg_types/index.ts b/src/legacy/ui/public/agg_types/index.ts index c7f4dee9a8173..c6db5b00cb780 100644 --- a/src/legacy/ui/public/agg_types/index.ts +++ b/src/legacy/ui/public/agg_types/index.ts @@ -34,12 +34,19 @@ export const { AggType, aggTypeFieldFilters, FieldParamType, + MetricAggType, parentPipelineAggHelper, + siblingPipelineAggHelper, setBounds, } = dataStart.search.aggs; // types export { + IAggConfig, + IAggConfigs, + IAggType, + IFieldParamType, + IMetricAggType, AggParam, AggParamOption, BUCKET_TYPES, @@ -67,8 +74,10 @@ export { isValidInterval, isValidJson, OptionedParamType, + parentPipelineType, propFilter, Schema, Schemas, + siblingPipelineType, termsAggFilter, } from '../../../core_plugins/data/public'; diff --git a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts b/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts index 26acf3c024592..69156da79dca8 100644 --- a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts +++ b/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts @@ -17,4 +17,4 @@ * under the License. */ -export { parentPipelineAggHelper } from '../../index'; +export { parentPipelineAggHelper, parentPipelineType } from '../../index'; diff --git a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts b/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts new file mode 100644 index 0000000000000..ea316d2028151 --- /dev/null +++ b/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { siblingPipelineAggHelper, siblingPipelineType } from '../../index'; diff --git a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts b/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts new file mode 100644 index 0000000000000..5df0e5009ad12 --- /dev/null +++ b/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { MetricAggType, IMetricAggType } from '../index'; diff --git a/src/legacy/ui/public/vis/__tests__/_agg_configs.js b/src/legacy/ui/public/vis/__tests__/_agg_configs.js index 62ad9a40ad058..436fb6c9a22e0 100644 --- a/src/legacy/ui/public/vis/__tests__/_agg_configs.js +++ b/src/legacy/ui/public/vis/__tests__/_agg_configs.js @@ -21,7 +21,7 @@ import _ from 'lodash'; import sinon from 'sinon'; import expect from '@kbn/expect'; import ngMock from 'ng_mock'; -import { AggConfig, AggConfigs, AggGroupNames, Schemas } from '../../agg_types'; +import { IAggConfig, AggConfig, AggConfigs, AggGroupNames, Schemas } from '../../agg_types'; import { Vis } from '../../../../core_plugins/visualizations/public'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; diff --git a/src/legacy/ui/public/vis/config/editor_config_providers.test.ts b/src/legacy/ui/public/vis/config/editor_config_providers.test.ts index 9d93930c09ebc..d52c9119dd76a 100644 --- a/src/legacy/ui/public/vis/config/editor_config_providers.test.ts +++ b/src/legacy/ui/public/vis/config/editor_config_providers.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { AggConfig } from 'ui/agg_types'; +import { IAggConfig } from 'ui/agg_types'; import { EditorConfigProviderRegistry } from './editor_config_providers'; import { EditorParamConfig, FixedParam, NumericIntervalParam, TimeIntervalParam } from './types'; @@ -48,7 +48,7 @@ describe('EditorConfigProvider', () => { const provider = jest.fn(() => ({})); registry.register(provider); expect(provider).not.toHaveBeenCalled(); - const aggConfig = {} as AggConfig; + const aggConfig = {} as IAggConfig; registry.getConfigForAgg(indexPattern, aggConfig); expect(provider).toHaveBeenCalledWith(indexPattern, aggConfig); }); @@ -60,7 +60,7 @@ describe('EditorConfigProvider', () => { registry.register(provider2); expect(provider).not.toHaveBeenCalled(); expect(provider2).not.toHaveBeenCalled(); - const aggConfig = {} as AggConfig; + const aggConfig = {} as IAggConfig; registry.getConfigForAgg(indexPattern, aggConfig); expect(provider).toHaveBeenCalledWith(indexPattern, aggConfig); expect(provider2).toHaveBeenCalledWith(indexPattern, aggConfig); @@ -72,7 +72,7 @@ describe('EditorConfigProvider', () => { } function getOutputConfig(reg: EditorConfigProviderRegistry) { - return reg.getConfigForAgg(indexPattern, {} as AggConfig).singleParam; + return reg.getConfigForAgg(indexPattern, {} as IAggConfig).singleParam; } it('should have hidden true if at least one config was hidden true', () => { diff --git a/src/legacy/ui/public/vis/config/editor_config_providers.ts b/src/legacy/ui/public/vis/config/editor_config_providers.ts index 1e82a3ca2762e..ec82597d5fb19 100644 --- a/src/legacy/ui/public/vis/config/editor_config_providers.ts +++ b/src/legacy/ui/public/vis/config/editor_config_providers.ts @@ -18,7 +18,7 @@ */ import { IndexPattern } from 'src/plugins/data/public'; -import { AggConfig } from 'ui/agg_types'; +import { IAggConfig } from 'ui/agg_types'; import { parseEsInterval } from '../../../../core_plugins/data/public'; import { TimeIntervalParam, @@ -29,7 +29,7 @@ import { } from './types'; import { leastCommonInterval, leastCommonMultiple } from '../lib'; -type EditorConfigProvider = (indexPattern: IndexPattern, aggConfig: AggConfig) => EditorConfig; +type EditorConfigProvider = (indexPattern: IndexPattern, aggConfig: IAggConfig) => EditorConfig; class EditorConfigProviderRegistry { private providers: Set = new Set(); @@ -38,7 +38,7 @@ class EditorConfigProviderRegistry { this.providers.add(configProvider); } - public getConfigForAgg(indexPattern: IndexPattern, aggConfig: AggConfig): EditorConfig { + public getConfigForAgg(indexPattern: IndexPattern, aggConfig: IAggConfig): EditorConfig { const configs = Array.from(this.providers).map(provider => provider(indexPattern, aggConfig)); return this.mergeConfigs(configs); } diff --git a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts index e763eb1b90791..fdbe216621b66 100644 --- a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts +++ b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { identity } from 'lodash'; -import { AggConfig } from 'ui/agg_types'; +import { IAggConfig } from 'ui/agg_types'; import { npStart } from 'ui/new_platform'; import { SerializedFieldFormat } from 'src/plugins/expressions/public'; import { fieldFormats } from '../../../../../../plugins/data/public'; @@ -62,7 +62,7 @@ const getFieldFormat = ( return new DefaultFieldFormat(); }; -export const createFormat = (agg: AggConfig): SerializedFieldFormat => { +export const createFormat = (agg: IAggConfig): SerializedFieldFormat => { const format: SerializedFieldFormat = agg.params.field ? agg.params.field.format.toJSON() : {}; const formats: Record SerializedFieldFormat> = { date_range: () => ({ id: 'date_range', params: format }), @@ -155,7 +155,7 @@ export const getFormat: FormatFactory = mapping => { } }; -export const getTableAggs = (vis: Vis): AggConfig[] => { +export const getTableAggs = (vis: Vis): IAggConfig[] => { if (!vis.aggs || !vis.aggs.getResponseAggs) { return []; } From a523b3c076672b9040536c6afd0c5e868750323c Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Fri, 31 Jan 2020 14:32:44 -0700 Subject: [PATCH 06/10] Remove nested ui/agg_types/* items and only use ui/agg_types --- .../data/public/search/expressions/esaggs.ts | 2 +- .../kibana/public/discover/kibana_services.ts | 2 +- .../public/components/controls/field.tsx | 3 ++- .../public/legacy_imports.ts | 26 ++++++++----------- .../public/vis_type_agg_filter.ts | 10 ++++--- .../visualizations/public/legacy_imports.ts | 9 +++---- .../public/legacy/build_pipeline.test.ts | 2 +- src/legacy/ui/public/agg_types/agg_config.ts | 20 -------------- src/legacy/ui/public/agg_types/agg_configs.ts | 20 -------------- src/legacy/ui/public/agg_types/agg_params.ts | 20 -------------- src/legacy/ui/public/agg_types/agg_type.ts | 20 -------------- .../agg_types/buckets/_interval_options.ts | 20 -------------- .../agg_types/buckets/date_histogram.ts | 20 -------------- .../ui/public/agg_types/buckets/date_range.ts | 20 -------------- .../ui/public/agg_types/buckets/ip_range.ts | 20 -------------- .../public/agg_types/buckets/lib/cidr_mask.ts | 20 -------------- .../buckets/migrate_include_exclude_format.ts | 20 -------------- .../ui/public/agg_types/filter/index.ts | 21 --------------- .../metrics/lib/parent_pipeline_agg_helper.ts | 20 -------------- .../lib/sibling_pipeline_agg_helper.ts | 20 -------------- .../agg_types/metrics/metric_agg_type.ts | 20 -------------- .../ui/public/agg_types/param_types/agg.ts | 20 -------------- .../agg_types/param_types/filter/index.ts | 20 -------------- .../ui/public/agg_types/param_types/index.ts | 20 -------------- .../public/agg_types/param_types/optioned.ts | 20 -------------- src/legacy/ui/public/agg_types/utils.ts | 20 -------------- .../ui/public/time_buckets/time_buckets.js | 2 +- .../ui/public/vis/__tests__/_agg_config.js | 4 +-- .../ui/public/vis/__tests__/_agg_configs.js | 2 +- .../loader/pipeline_helpers/utilities.ts | 4 +-- .../operations/definitions/date_histogram.tsx | 2 +- .../public/visualize/agg_type_field_filter.js | 6 +++++ .../public/visualize/agg_type_filter.js | 6 +++++ .../watcher/public/legacy/time_buckets.js | 2 +- 34 files changed, 45 insertions(+), 418 deletions(-) delete mode 100644 src/legacy/ui/public/agg_types/agg_config.ts delete mode 100644 src/legacy/ui/public/agg_types/agg_configs.ts delete mode 100644 src/legacy/ui/public/agg_types/agg_params.ts delete mode 100644 src/legacy/ui/public/agg_types/agg_type.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/_interval_options.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/date_histogram.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/date_range.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/ip_range.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts delete mode 100644 src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts delete mode 100644 src/legacy/ui/public/agg_types/filter/index.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts delete mode 100644 src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/agg.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/filter/index.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/index.ts delete mode 100644 src/legacy/ui/public/agg_types/param_types/optioned.ts delete mode 100644 src/legacy/ui/public/agg_types/utils.ts diff --git a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts index 5c3d68acda5de..43927337ce574 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts +++ b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts @@ -19,7 +19,7 @@ import { get, has } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { AggConfigs, IAggConfigs } from 'ui/agg_types/agg_configs'; +import { AggConfigs, IAggConfigs } from 'ui/agg_types'; import { createFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; import { KibanaContext, diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts index 9a0b0731b6b11..3786752849a60 100644 --- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts @@ -59,7 +59,7 @@ export { buildVislibDimensions } from '../../../visualizations/public'; export { callAfterBindingsWorkaround } from 'ui/compat'; export { getRequestInspectorStats, getResponseInspectorStats } from '../../../data/public'; // @ts-ignore -export { intervalOptions } from 'ui/agg_types/buckets/_interval_options'; +export { intervalOptions } from 'ui/agg_types'; // @ts-ignore export { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query'; export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal'; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx index d3eeb37fa9887..f374353afabec 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx @@ -128,7 +128,8 @@ function FieldParamEditor({ function getFieldTypesString(agg: IAggConfig) { const param = - get(agg, 'type.params', []).find((p: AggParam) => p.name === 'field') || ({} as IFieldParamType); + get(agg, 'type.params', []).find((p: AggParam) => p.name === 'field') || + ({} as IFieldParamType); return formatListAsProse(parseCommaSeparatedList(param.filterFieldTypes), { inclusive: false }); } diff --git a/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts b/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts index 793806c735b19..f023b808cb0a7 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts @@ -36,21 +36,17 @@ export { Schema, termsAggFilter, } from 'ui/agg_types'; -export { aggTypeFilters, propFilter } from 'ui/agg_types/filter'; -export { aggTypeFieldFilters } from 'ui/agg_types/param_types/filter'; -export { AggParamType } from 'ui/agg_types/param_types/agg'; -export { MetricAggType, IMetricAggType } from 'ui/agg_types/metrics/metric_agg_type'; -export { parentPipelineType } from 'ui/agg_types/metrics/lib/parent_pipeline_agg_helper'; -export { siblingPipelineType } from 'ui/agg_types/metrics/lib/sibling_pipeline_agg_helper'; -export { isType, isStringType } from 'ui/agg_types/buckets/migrate_include_exclude_format'; -export { - OptionedValueProp, - OptionedParamEditorProps, - OptionedParamType, -} from 'ui/agg_types/param_types/optioned'; -export { isValidJson, isValidInterval } from 'ui/agg_types/utils'; -export { AggParamOption } from 'ui/agg_types/agg_params'; -export { CidrMask } from 'ui/agg_types/buckets/lib/cidr_mask'; +export { aggTypeFilters, propFilter } from 'ui/agg_types'; +export { aggTypeFieldFilters } from 'ui/agg_types'; +export { AggParamType } from 'ui/agg_types'; +export { MetricAggType, IMetricAggType } from 'ui/agg_types'; +export { parentPipelineType } from 'ui/agg_types'; +export { siblingPipelineType } from 'ui/agg_types'; +export { isType, isStringType } from 'ui/agg_types'; +export { OptionedValueProp, OptionedParamEditorProps, OptionedParamType } from 'ui/agg_types'; +export { isValidJson, isValidInterval } from 'ui/agg_types'; +export { AggParamOption } from 'ui/agg_types'; +export { CidrMask } from 'ui/agg_types'; export { PersistedState } from 'ui/persisted_state'; export { IndexedArray } from 'ui/indexed_array'; diff --git a/src/legacy/core_plugins/vis_default_editor/public/vis_type_agg_filter.ts b/src/legacy/core_plugins/vis_default_editor/public/vis_type_agg_filter.ts index c0dbdcf310c7d..60b675f50a342 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/vis_type_agg_filter.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/vis_type_agg_filter.ts @@ -25,7 +25,9 @@ const filterByName = propFilter('name'); * This filter checks the defined aggFilter in the schemas of that visualization * and limits available aggregations based on that. */ -aggTypeFilters.addFilter((aggType: IAggType, indexPatterns: IndexPattern, aggConfig: IAggConfig) => { - const doesSchemaAllowAggType = filterByName([aggType], aggConfig.schema.aggFilter).length !== 0; - return doesSchemaAllowAggType; -}); +aggTypeFilters.addFilter( + (aggType: IAggType, indexPatterns: IndexPattern, aggConfig: IAggConfig) => { + const doesSchemaAllowAggType = filterByName([aggType], aggConfig.schema.aggFilter).length !== 0; + return doesSchemaAllowAggType; + } +); diff --git a/src/legacy/core_plugins/visualizations/public/legacy_imports.ts b/src/legacy/core_plugins/visualizations/public/legacy_imports.ts index 02db300437d34..3ea521a8231f8 100644 --- a/src/legacy/core_plugins/visualizations/public/legacy_imports.ts +++ b/src/legacy/core_plugins/visualizations/public/legacy_imports.ts @@ -18,12 +18,9 @@ */ export { PersistedState } from '../../../ui/public/persisted_state'; -export { IAggConfig } from '../../../ui/public/agg_types/agg_config'; -export { IAggConfigs } from '../../../ui/public/agg_types/agg_configs'; -export { - isDateHistogramBucketAggConfig, - setBounds, -} from '../../../ui/public/agg_types/buckets/date_histogram'; +export { IAggConfig } from '../../../ui/public/agg_types'; +export { IAggConfigs } from '../../../ui/public/agg_types'; +export { isDateHistogramBucketAggConfig, setBounds } from '../../../ui/public/agg_types'; export { createFormat } from '../../../ui/public/visualize/loader/pipeline_helpers/utilities'; export { I18nContext } from '../../../ui/public/i18n'; import chrome from '../../../ui/public/chrome'; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts index 0680ecbec9206..d1017de35474a 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts @@ -31,7 +31,7 @@ import { IAggConfig } from '../../../legacy_imports'; import { searchSourceMock } from '../../../legacy_mocks'; jest.mock('ui/new_platform'); -jest.mock('ui/agg_types/buckets/date_histogram', () => ({ +jest.mock('ui/agg_types', () => ({ setBounds: () => {}, dateHistogramBucketAgg: () => {}, isDateHistogramBucketAggConfig: () => true, diff --git a/src/legacy/ui/public/agg_types/agg_config.ts b/src/legacy/ui/public/agg_types/agg_config.ts deleted file mode 100644 index ce343aa531020..0000000000000 --- a/src/legacy/ui/public/agg_types/agg_config.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { AggConfig, IAggConfig } from './index'; diff --git a/src/legacy/ui/public/agg_types/agg_configs.ts b/src/legacy/ui/public/agg_types/agg_configs.ts deleted file mode 100644 index ab15e58702cae..0000000000000 --- a/src/legacy/ui/public/agg_types/agg_configs.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { AggConfigs, IAggConfigs } from './index'; diff --git a/src/legacy/ui/public/agg_types/agg_params.ts b/src/legacy/ui/public/agg_types/agg_params.ts deleted file mode 100644 index d850be8039025..0000000000000 --- a/src/legacy/ui/public/agg_types/agg_params.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { AggParam, AggParamOption } from './index'; diff --git a/src/legacy/ui/public/agg_types/agg_type.ts b/src/legacy/ui/public/agg_types/agg_type.ts deleted file mode 100644 index 5a74495dd815b..0000000000000 --- a/src/legacy/ui/public/agg_types/agg_type.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { AggType } from './index'; diff --git a/src/legacy/ui/public/agg_types/buckets/_interval_options.ts b/src/legacy/ui/public/agg_types/buckets/_interval_options.ts deleted file mode 100644 index d3838e280f873..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/_interval_options.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { intervalOptions } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/date_histogram.ts b/src/legacy/ui/public/agg_types/buckets/date_histogram.ts deleted file mode 100644 index 35b14f620bdae..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/date_histogram.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { isDateHistogramBucketAggConfig, setBounds } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/date_range.ts b/src/legacy/ui/public/agg_types/buckets/date_range.ts deleted file mode 100644 index 34eae58375a06..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/date_range.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { DateRangeKey, convertDateRangeToString } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/ip_range.ts b/src/legacy/ui/public/agg_types/buckets/ip_range.ts deleted file mode 100644 index 7a8fd4f89b1ff..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/ip_range.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { IpRangeKey, convertIPRangeToString } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts b/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts deleted file mode 100644 index 0774a89ee3f03..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { CidrMask } from '../../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts b/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts deleted file mode 100644 index f86cc2b6a294b..0000000000000 --- a/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { isType, isStringType } from '../index'; diff --git a/src/legacy/ui/public/agg_types/filter/index.ts b/src/legacy/ui/public/agg_types/filter/index.ts deleted file mode 100644 index 35d06807d0ec2..0000000000000 --- a/src/legacy/ui/public/agg_types/filter/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { aggTypeFilters, AggTypeFilters } from './agg_type_filters'; -export { propFilter } from './prop_filter'; diff --git a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts b/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts deleted file mode 100644 index 69156da79dca8..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { parentPipelineAggHelper, parentPipelineType } from '../../index'; diff --git a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts b/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts deleted file mode 100644 index ea316d2028151..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { siblingPipelineAggHelper, siblingPipelineType } from '../../index'; diff --git a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts b/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts deleted file mode 100644 index 5df0e5009ad12..0000000000000 --- a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { MetricAggType, IMetricAggType } from '../index'; diff --git a/src/legacy/ui/public/agg_types/param_types/agg.ts b/src/legacy/ui/public/agg_types/param_types/agg.ts deleted file mode 100644 index 68c58e1dd7e07..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/agg.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { AggParamType } from '../index'; diff --git a/src/legacy/ui/public/agg_types/param_types/filter/index.ts b/src/legacy/ui/public/agg_types/param_types/filter/index.ts deleted file mode 100644 index 2e0039c96a192..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/filter/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { aggTypeFieldFilters, AggTypeFieldFilters } from './field_filters'; diff --git a/src/legacy/ui/public/agg_types/param_types/index.ts b/src/legacy/ui/public/agg_types/param_types/index.ts deleted file mode 100644 index 5f085e498c788..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export * from './optioned'; diff --git a/src/legacy/ui/public/agg_types/param_types/optioned.ts b/src/legacy/ui/public/agg_types/param_types/optioned.ts deleted file mode 100644 index d6ce116b996c6..0000000000000 --- a/src/legacy/ui/public/agg_types/param_types/optioned.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { OptionedParamEditorProps, OptionedParamType, OptionedValueProp } from '../index'; diff --git a/src/legacy/ui/public/agg_types/utils.ts b/src/legacy/ui/public/agg_types/utils.ts deleted file mode 100644 index ec1eab7e4b115..0000000000000 --- a/src/legacy/ui/public/agg_types/utils.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { isValidJson, isValidInterval } from './index'; diff --git a/src/legacy/ui/public/time_buckets/time_buckets.js b/src/legacy/ui/public/time_buckets/time_buckets.js index 50a57d866099e..a611de45fa859 100644 --- a/src/legacy/ui/public/time_buckets/time_buckets.js +++ b/src/legacy/ui/public/time_buckets/time_buckets.js @@ -144,7 +144,7 @@ TimeBuckets.prototype.getDuration = function() { * generated. * * Input can be one of the following: - * - Any object from src/legacy/ui/agg_types/buckets/_interval_options.js + * - Any object from src/legacy/ui/agg_types.js * - "auto" * - Pass a valid moment unit * - a moment.duration object. diff --git a/src/legacy/ui/public/vis/__tests__/_agg_config.js b/src/legacy/ui/public/vis/__tests__/_agg_config.js index 2ccbaf6c1645e..7dccf3eec18aa 100644 --- a/src/legacy/ui/public/vis/__tests__/_agg_config.js +++ b/src/legacy/ui/public/vis/__tests__/_agg_config.js @@ -21,8 +21,8 @@ import sinon from 'sinon'; import expect from '@kbn/expect'; import ngMock from 'ng_mock'; import { Vis } from '../../../../core_plugins/visualizations/public'; -import { AggType } from '../../agg_types/agg_type'; -import { AggConfig } from '../../agg_types/agg_config'; +import { AggType, AggConfig } from '../../agg_types'; + import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; describe('AggConfig', function() { diff --git a/src/legacy/ui/public/vis/__tests__/_agg_configs.js b/src/legacy/ui/public/vis/__tests__/_agg_configs.js index 436fb6c9a22e0..62ad9a40ad058 100644 --- a/src/legacy/ui/public/vis/__tests__/_agg_configs.js +++ b/src/legacy/ui/public/vis/__tests__/_agg_configs.js @@ -21,7 +21,7 @@ import _ from 'lodash'; import sinon from 'sinon'; import expect from '@kbn/expect'; import ngMock from 'ng_mock'; -import { IAggConfig, AggConfig, AggConfigs, AggGroupNames, Schemas } from '../../agg_types'; +import { AggConfig, AggConfigs, AggGroupNames, Schemas } from '../../agg_types'; import { Vis } from '../../../../core_plugins/visualizations/public'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; diff --git a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts index fdbe216621b66..0aa43dfbdaf35 100644 --- a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts +++ b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts @@ -26,8 +26,8 @@ import { fieldFormats } from '../../../../../../plugins/data/public'; import { Vis } from '../../../../../core_plugins/visualizations/public'; import { tabifyGetColumns } from '../../../agg_response/tabify/_get_columns'; -import { DateRangeKey, convertDateRangeToString } from '../../../agg_types/buckets/date_range'; -import { IpRangeKey, convertIPRangeToString } from '../../../agg_types/buckets/ip_range'; +import { DateRangeKey, convertDateRangeToString } from '../../../agg_types'; +import { IpRangeKey, convertIPRangeToString } from '../../../agg_types'; interface TermsFieldFormatParams { otherBucketLabel: string; diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.tsx index dbb6278352f09..ae12be90ddd05 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.tsx @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; // TODO: make this new-platform compatible -import { isValidInterval } from 'ui/agg_types/utils'; +import { isValidInterval } from 'ui/agg_types'; import { EuiForm, diff --git a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js b/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js index 6f44e0ef90efd..65c8db7f29460 100644 --- a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js +++ b/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js @@ -4,7 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +<<<<<<< HEAD export function initAggTypeFieldFilter(aggTypeFieldFilters) { +======= +import { aggTypeFieldFilters } from 'ui/agg_types'; + +export function initAggTypeFieldFilter() { +>>>>>>> Remove nested ui/agg_types/* items and only use ui/agg_types /** * If rollup index pattern, check its capabilities * and limit available fields for a given aggType based on that. diff --git a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js b/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js index 5f9fab3061a19..ba6ab10907219 100644 --- a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js +++ b/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js @@ -4,7 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +<<<<<<< HEAD export function initAggTypeFilter(aggTypeFilters) { +======= +import { aggTypeFilters } from 'ui/agg_types'; + +export function initAggTypeFilter() { +>>>>>>> Remove nested ui/agg_types/* items and only use ui/agg_types /** * If rollup index pattern, check its capabilities * and limit available aggregations based on that. diff --git a/x-pack/plugins/watcher/public/legacy/time_buckets.js b/x-pack/plugins/watcher/public/legacy/time_buckets.js index 8b7e4be784fe7..5d5e9e8dcb1a4 100644 --- a/x-pack/plugins/watcher/public/legacy/time_buckets.js +++ b/x-pack/plugins/watcher/public/legacy/time_buckets.js @@ -130,7 +130,7 @@ TimeBuckets.prototype.getDuration = function() { * generated. * * Input can be one of the following: - * - Any object from src/legacy/ui/agg_types/buckets/_interval_options.js + * - Any object from src/plugins/data/public/search/aggs/buckets/_interval_options.ts * - "auto" * - Pass a valid moment unit * - a moment.duration object. From 6b32d2ae8be9ec0a31a2c54ef206a89e7ea4ecf5 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Fri, 31 Jan 2020 14:54:16 -0700 Subject: [PATCH 07/10] Add AggTypeFilters, AggTypeFieldFilters from #53503 --- src/legacy/core_plugins/data/public/index.ts | 2 ++ .../data/public/search/aggs/buckets/date_histogram.ts | 4 +--- .../core_plugins/data/public/search/aggs/filter/index.ts | 2 +- src/legacy/core_plugins/data/public/search/aggs/index.ts | 3 ++- .../data/public/search/aggs/param_types/filter/index.ts | 2 +- src/legacy/ui/public/agg_types/index.ts | 2 ++ x-pack/legacy/plugins/rollup/public/legacy.ts | 4 ++-- x-pack/legacy/plugins/rollup/public/legacy_imports.ts | 4 ++-- .../rollup/public/visualize/agg_type_field_filter.js | 6 ------ .../plugins/rollup/public/visualize/agg_type_filter.js | 6 ------ 10 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts index 2ab73bdf02d3d..50120292a627a 100644 --- a/src/legacy/core_plugins/data/public/index.ts +++ b/src/legacy/core_plugins/data/public/index.ts @@ -55,7 +55,9 @@ export { FilterStateManager } from './filter/filter_manager'; export { // agg_types TODO need to group these under a namespace or prefix AggParamType, + AggTypeFilters, // TODO convert to interface aggTypeFilters, + AggTypeFieldFilters, // TODO convert to interface AggGroupNames, aggGroupNamesMap, BUCKET_TYPES, diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts index 8eb0c70964f95..eb3fcc65b316b 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts @@ -23,6 +23,7 @@ import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; import { timefilter } from 'ui/timefilter'; +import { TimeBuckets } from 'ui/time_buckets'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { createFilterDateHistogram } from './create_filter/date_histogram'; @@ -33,9 +34,6 @@ import { isMetricAggType } from '../metrics/metric_agg_type'; import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -// @ts-ignore -import { TimeBuckets } from '../../time_buckets'; - const detectedTimezone = moment.tz.guess(); const tzOffset = moment().format('Z'); diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/index.ts b/src/legacy/core_plugins/data/public/search/aggs/filter/index.ts index 3fc577e7e9a23..35d06807d0ec2 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/filter/index.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/filter/index.ts @@ -17,5 +17,5 @@ * under the License. */ -export { aggTypeFilters } from './agg_type_filters'; +export { aggTypeFilters, AggTypeFilters } from './agg_type_filters'; export { propFilter } from './prop_filter'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/index.ts b/src/legacy/core_plugins/data/public/search/aggs/index.ts index 1c3e8d4184494..0fef7f38aae74 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/index.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/index.ts @@ -23,7 +23,8 @@ export { AggConfig } from './agg_config'; export { AggConfigs } from './agg_configs'; export { FieldParamType } from './param_types'; export { MetricAggType } from './metrics/metric_agg_type'; -export { aggTypeFieldFilters } from './param_types/filter'; +export { AggTypeFilters } from './filter'; +export { aggTypeFieldFilters, AggTypeFieldFilters } from './param_types/filter'; export { parentPipelineAggHelper, parentPipelineType, diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/index.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/index.ts index ce5c7c4f9fea5..2e0039c96a192 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/index.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export { aggTypeFieldFilters } from './field_filters'; +export { aggTypeFieldFilters, AggTypeFieldFilters } from './field_filters'; diff --git a/src/legacy/ui/public/agg_types/index.ts b/src/legacy/ui/public/agg_types/index.ts index c6db5b00cb780..ac5d0bed7ef15 100644 --- a/src/legacy/ui/public/agg_types/index.ts +++ b/src/legacy/ui/public/agg_types/index.ts @@ -61,7 +61,9 @@ export { // static code export { AggParamType, + AggTypeFilters, aggTypeFilters, + AggTypeFieldFilters, AggGroupNames, aggGroupNamesMap, CidrMask, diff --git a/x-pack/legacy/plugins/rollup/public/legacy.ts b/x-pack/legacy/plugins/rollup/public/legacy.ts index a2738372ff346..a70f181dc86fb 100644 --- a/x-pack/legacy/plugins/rollup/public/legacy.ts +++ b/x-pack/legacy/plugins/rollup/public/legacy.ts @@ -6,8 +6,8 @@ import { npSetup, npStart } from 'ui/new_platform'; import { editorConfigProviders } from 'ui/vis/config'; -import { aggTypeFilters } from 'ui/agg_types/filter'; -import { aggTypeFieldFilters } from 'ui/agg_types/param_types/filter'; +import { aggTypeFilters } from 'ui/agg_types'; +import { aggTypeFieldFilters } from 'ui/agg_types'; import { addSearchStrategy } from '../../../../../src/plugins/data/public'; import { RollupPlugin } from './plugin'; import { setup as management } from '../../../../../src/legacy/core_plugins/management/public/legacy'; diff --git a/x-pack/legacy/plugins/rollup/public/legacy_imports.ts b/x-pack/legacy/plugins/rollup/public/legacy_imports.ts index 981f97963591e..4fece0fddfa3e 100644 --- a/x-pack/legacy/plugins/rollup/public/legacy_imports.ts +++ b/x-pack/legacy/plugins/rollup/public/legacy_imports.ts @@ -7,6 +7,6 @@ // @ts-ignore export { findIllegalCharactersInIndexName, INDEX_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/indices'; -export { AggTypeFilters } from 'ui/agg_types/filter'; -export { AggTypeFieldFilters } from 'ui/agg_types/param_types/filter'; +export { AggTypeFilters } from 'ui/agg_types'; +export { AggTypeFieldFilters } from 'ui/agg_types'; export { EditorConfigProviderRegistry } from 'ui/vis/config'; diff --git a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js b/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js index 65c8db7f29460..6f44e0ef90efd 100644 --- a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js +++ b/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js @@ -4,13 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -<<<<<<< HEAD export function initAggTypeFieldFilter(aggTypeFieldFilters) { -======= -import { aggTypeFieldFilters } from 'ui/agg_types'; - -export function initAggTypeFieldFilter() { ->>>>>>> Remove nested ui/agg_types/* items and only use ui/agg_types /** * If rollup index pattern, check its capabilities * and limit available fields for a given aggType based on that. diff --git a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js b/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js index ba6ab10907219..5f9fab3061a19 100644 --- a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js +++ b/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js @@ -4,13 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -<<<<<<< HEAD export function initAggTypeFilter(aggTypeFilters) { -======= -import { aggTypeFilters } from 'ui/agg_types'; - -export function initAggTypeFilter() { ->>>>>>> Remove nested ui/agg_types/* items and only use ui/agg_types /** * If rollup index pattern, check its capabilities * and limit available aggregations based on that. From 926423db8da085eeed5621e6aa39c78d6bc81b01 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Mon, 3 Feb 2020 10:55:41 -0700 Subject: [PATCH 08/10] Address feedback & fix conflicts. --- .../public/search/aggs/param_types/field.ts | 4 +- .../data/public/search/expressions/utils.ts | 6 +- .../data/public/search/search_service.ts | 4 +- .../visualizations/public/legacy_imports.ts | 9 +- src/legacy/ui/public/agg_types/agg_types.ts | 92 ------------------- 5 files changed, 13 insertions(+), 102 deletions(-) delete mode 100644 src/legacy/ui/public/agg_types/agg_types.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts index 581ff98ea42f2..1f49059131d21 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts @@ -19,7 +19,7 @@ // @ts-ignore import { i18n } from '@kbn/i18n'; -import { toastNotifications } from 'ui/notify'; +import { npStart } from 'ui/new_platform'; import { AggConfig } from '../agg_config'; import { SavedObjectNotFound } from '../../../../../../../plugins/kibana_utils/public'; import { BaseParamType } from './base'; @@ -91,7 +91,7 @@ export class FieldParamType extends BaseParamType { (f: any) => f.name === fieldName ); if (!validField) { - toastNotifications.addDanger( + npStart.core.notifications.toasts.addDanger( i18n.translate( 'common.ui.aggTypes.paramTypes.field.invalidSavedFieldParameterErrorMessage', { diff --git a/src/legacy/core_plugins/data/public/search/expressions/utils.ts b/src/legacy/core_plugins/data/public/search/expressions/utils.ts index 4f104f2569a98..f0958ba20820f 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/utils.ts +++ b/src/legacy/core_plugins/data/public/search/expressions/utils.ts @@ -17,12 +17,12 @@ * under the License. */ -import { AggConfig } from 'ui/agg_types/agg_config'; -import { AggConfigs } from '../../../../../ui/public/agg_types/agg_configs'; +import { AggConfigs } from '../aggs'; +import { IAggConfig } from '../aggs/types'; import { KibanaDatatableColumnMeta } from '../../../../../../plugins/expressions/common/expression_types'; import { IndexPattern } from '../../../../../../plugins/data/public'; -export const serializeAggConfig = (aggConfig: AggConfig): KibanaDatatableColumnMeta => { +export const serializeAggConfig = (aggConfig: IAggConfig): KibanaDatatableColumnMeta => { return { type: aggConfig.type.name, indexPatternId: aggConfig.getIndexPattern().id, diff --git a/src/legacy/core_plugins/data/public/search/search_service.ts b/src/legacy/core_plugins/data/public/search/search_service.ts index b57a637a49e71..45f9ff17328ad 100644 --- a/src/legacy/core_plugins/data/public/search/search_service.ts +++ b/src/legacy/core_plugins/data/public/search/search_service.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Plugin, CoreSetup, CoreStart } from '../../../../../core/public'; +import { CoreSetup, CoreStart } from '../../../../../core/public'; import { aggTypes, AggType, @@ -62,7 +62,7 @@ export interface SearchStart { * Once it has been refactored to work with new platform services, * it will move into the existing search service in src/plugins/data/public/search */ -export class SearchService implements Plugin { +export class SearchService { public setup(core: CoreSetup): SearchSetup { return { aggs: { diff --git a/src/legacy/core_plugins/visualizations/public/legacy_imports.ts b/src/legacy/core_plugins/visualizations/public/legacy_imports.ts index 3ea521a8231f8..9fc3f24046229 100644 --- a/src/legacy/core_plugins/visualizations/public/legacy_imports.ts +++ b/src/legacy/core_plugins/visualizations/public/legacy_imports.ts @@ -18,9 +18,12 @@ */ export { PersistedState } from '../../../ui/public/persisted_state'; -export { IAggConfig } from '../../../ui/public/agg_types'; -export { IAggConfigs } from '../../../ui/public/agg_types'; -export { isDateHistogramBucketAggConfig, setBounds } from '../../../ui/public/agg_types'; +export { + IAggConfig, + IAggConfigs, + isDateHistogramBucketAggConfig, + setBounds, +} from '../../../ui/public/agg_types'; export { createFormat } from '../../../ui/public/visualize/loader/pipeline_helpers/utilities'; export { I18nContext } from '../../../ui/public/i18n'; import chrome from '../../../ui/public/chrome'; diff --git a/src/legacy/ui/public/agg_types/agg_types.ts b/src/legacy/ui/public/agg_types/agg_types.ts deleted file mode 100644 index 1b05f5926ebfc..0000000000000 --- a/src/legacy/ui/public/agg_types/agg_types.ts +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -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 { geoTileBucketAgg } from './buckets/geo_tile'; -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 { AggType } from './agg_type'; - -export const aggTypes = { - 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, - geoTileBucketAgg, - ], -}; From 441cf76bcb2c6e065ea769520fc480ddf5781d02 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Mon, 3 Feb 2020 12:17:26 -0700 Subject: [PATCH 09/10] Fix test failures. --- .../actions/filters/brush_event.test.js | 2 +- .../buckets/_terms_other_bucket_helper.js | 2 +- .../visualizations/public/legacy_imports.ts | 1 + .../editor_frame_plugin/plugin.test.tsx | 3 -- .../definitions/date_histogram.test.tsx | 34 +++++++++---------- 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js b/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js index a6fe58503cd02..743f6caee4edd 100644 --- a/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js +++ b/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js @@ -21,7 +21,7 @@ import _ from 'lodash'; import moment from 'moment'; import expect from '@kbn/expect'; -jest.mock('../../../../../ui/public/agg_types/agg_configs', () => ({ +jest.mock('../../search/aggs', () => ({ AggConfigs: function AggConfigs() { return { createAggConfig: ({ params }) => ({ diff --git a/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js b/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js index acf932c1fb451..247290731df57 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js +++ b/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js @@ -24,7 +24,7 @@ import { mergeOtherBucketAggResponse, updateMissingBucket, } from '../../buckets/_terms_other_bucket_helper'; -import { Vis } from '../../../../../core_plugins/visualizations/public'; +import { Vis } from '../../../../../../../core_plugins/visualizations/public'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; const visConfigSingleTerm = { diff --git a/src/legacy/core_plugins/visualizations/public/legacy_imports.ts b/src/legacy/core_plugins/visualizations/public/legacy_imports.ts index 9fc3f24046229..5cff588d951b0 100644 --- a/src/legacy/core_plugins/visualizations/public/legacy_imports.ts +++ b/src/legacy/core_plugins/visualizations/public/legacy_imports.ts @@ -19,6 +19,7 @@ export { PersistedState } from '../../../ui/public/persisted_state'; export { + AggConfigs, IAggConfig, IAggConfigs, isDateHistogramBucketAggConfig, diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/plugin.test.tsx b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/plugin.test.tsx index da9fdd7927d60..7a6067dd5f23c 100644 --- a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/plugin.test.tsx +++ b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/plugin.test.tsx @@ -14,9 +14,6 @@ import { } from './mocks'; jest.mock('ui/new_platform'); -jest.mock('ui/chrome', () => ({ - getSavedObjectsClient: jest.fn(), -})); // mock away actual dependencies to prevent all of it being loaded jest.mock('../../../../../../src/legacy/core_plugins/interpreter/public/registries', () => {}); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.test.tsx index 2bd6c7106a952..5be92e31f4934 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.test.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.test.tsx @@ -14,33 +14,31 @@ import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { createMockedIndexPattern } from '../../mocks'; import { IndexPatternPrivateState } from '../../types'; -jest.mock('ui/new_platform', () => { +jest.mock(`ui/new_platform`, () => { // Due to the way we are handling shims in the NP migration, we need // to mock core here so that upstream services don't cause these // tests to fail. Ordinarly `jest.mock('ui/new_platform')` would be // sufficient, however we need to mock one of the `uiSettings` return // values for this suite, so we must manually assemble the mock. // Because babel hoists `jest` we must use an inline `require` - // to ensure the core mocks are available (`jest.doMock` doesn't + // to ensure the mocks are available (`jest.doMock` doesn't // work in this case). This mock should be able to be replaced // altogether once Lens has migrated to the new platform. - const { coreMock } = require('src/core/public/mocks'); // eslint-disable-line @typescript-eslint/no-var-requires + const { + createUiNewPlatformMock, + } = require('../../../../../../../../src/legacy/ui/public/new_platform/__mocks__/helpers'); // eslint-disable-line @typescript-eslint/no-var-requires + // This is basically duplicating what would ordinarily happen in + // `ui/new_platform/__mocks__` + const { npSetup, npStart } = createUiNewPlatformMock(); + // Override the core mock provided by `ui/new_platform` + npStart.core.uiSettings.get = (path: string) => { + if (path === 'histogram:maxBars') { + return 10; + } + }; return { - npSetup: { - core: coreMock.createSetup(), - }, - npStart: { - core: { - ...coreMock.createStart(), - uiSettings: { - get: (path: string) => { - if (path === 'histogram:maxBars') { - return 10; - } - }, - }, - }, - }, + npSetup, + npStart, }; }); From dbec747dec6e3da090dc7949df617c7b017477bc Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Mon, 3 Feb 2020 16:27:42 -0700 Subject: [PATCH 10/10] i18n. --- .../data/public/search/aggs/agg_config.ts | 2 +- .../data/public/search/aggs/agg_groups.ts | 4 +- .../data/public/search/aggs/agg_type.ts | 2 +- .../search/aggs/buckets/_interval_options.ts | 18 +- .../search/aggs/buckets/date_histogram.ts | 4 +- .../public/search/aggs/buckets/date_range.ts | 2 +- .../data/public/search/aggs/buckets/filter.ts | 2 +- .../public/search/aggs/buckets/filters.ts | 2 +- .../public/search/aggs/buckets/geo_hash.ts | 2 +- .../public/search/aggs/buckets/geo_tile.ts | 2 +- .../public/search/aggs/buckets/histogram.ts | 4 +- .../public/search/aggs/buckets/ip_range.ts | 4 +- .../data/public/search/aggs/buckets/range.ts | 6 +- .../search/aggs/buckets/significant_terms.ts | 8 +- .../data/public/search/aggs/buckets/terms.ts | 22 +- .../data/public/search/aggs/metrics/avg.ts | 4 +- .../public/search/aggs/metrics/bucket_avg.ts | 4 +- .../public/search/aggs/metrics/bucket_max.ts | 4 +- .../public/search/aggs/metrics/bucket_min.ts | 4 +- .../public/search/aggs/metrics/bucket_sum.ts | 4 +- .../public/search/aggs/metrics/cardinality.ts | 4 +- .../data/public/search/aggs/metrics/count.ts | 4 +- .../search/aggs/metrics/cumulative_sum.ts | 4 +- .../public/search/aggs/metrics/derivative.ts | 4 +- .../public/search/aggs/metrics/geo_bounds.ts | 4 +- .../search/aggs/metrics/geo_centroid.ts | 4 +- .../metrics/lib/parent_pipeline_agg_helper.ts | 4 +- .../lib/sibling_pipeline_agg_helper.ts | 6 +- .../data/public/search/aggs/metrics/max.ts | 4 +- .../data/public/search/aggs/metrics/median.ts | 4 +- .../search/aggs/metrics/metric_agg_type.ts | 2 +- .../data/public/search/aggs/metrics/min.ts | 4 +- .../public/search/aggs/metrics/moving_avg.ts | 4 +- .../search/aggs/metrics/percentile_ranks.ts | 6 +- .../public/search/aggs/metrics/percentiles.ts | 6 +- .../public/search/aggs/metrics/serial_diff.ts | 4 +- .../search/aggs/metrics/std_deviation.ts | 10 +- .../data/public/search/aggs/metrics/sum.ts | 4 +- .../public/search/aggs/metrics/top_hit.ts | 20 +- .../public/search/aggs/param_types/field.ts | 17 +- .../loader/pipeline_helpers/utilities.ts | 2 +- .../translations/translations/ja-JP.json | 209 +++++++++--------- .../translations/translations/zh-CN.json | 209 +++++++++--------- 43 files changed, 321 insertions(+), 322 deletions(-) diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts index b15ab2c2b1578..769347a26c34c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts @@ -363,7 +363,7 @@ export class AggConfig { if (!this.type) return ''; return percentageMode - ? i18n.translate('common.ui.vis.aggConfig.percentageOfLabel', { + ? i18n.translate('data.search.aggs.percentageOfLabel', { defaultMessage: 'Percentage of {label}', values: { label: this.type.makeLabel(this) }, }) diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts index d08e875bf213e..d21f5c8968840 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts @@ -28,10 +28,10 @@ export const AggGroupNames = Object.freeze({ export type AggGroupNames = $Values; export const aggGroupNamesMap = () => ({ - [AggGroupNames.Metrics]: i18n.translate('common.ui.aggTypes.aggGroups.metricsText', { + [AggGroupNames.Metrics]: i18n.translate('data.search.aggs.aggGroups.metricsText', { defaultMessage: 'Metrics', }), - [AggGroupNames.Buckets]: i18n.translate('common.ui.aggTypes.aggGroups.bucketsText', { + [AggGroupNames.Buckets]: i18n.translate('data.search.aggs.aggGroups.bucketsText', { defaultMessage: 'Buckets', }), }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts index c767a3e91c078..56299839d0a6d 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts @@ -246,7 +246,7 @@ export class AggType< if (config.customLabels !== false) { params.push({ name: 'customLabel', - displayName: i18n.translate('common.ui.aggTypes.string.customLabel', { + displayName: i18n.translate('data.search.aggs.string.customLabel', { defaultMessage: 'Custom label', }), type: 'string', diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts index 01d0abb7a366c..e196687607d19 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts @@ -21,7 +21,7 @@ import { IBucketAggConfig } from './_bucket_agg_type'; export const intervalOptions = [ { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.autoDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.autoDisplayName', { defaultMessage: 'Auto', }), val: 'auto', @@ -32,49 +32,49 @@ export const intervalOptions = [ }, }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.millisecondDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.millisecondDisplayName', { defaultMessage: 'Millisecond', }), val: 'ms', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.secondDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.secondDisplayName', { defaultMessage: 'Second', }), val: 's', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.minuteDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.minuteDisplayName', { defaultMessage: 'Minute', }), val: 'm', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.hourlyDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.hourlyDisplayName', { defaultMessage: 'Hourly', }), val: 'h', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.dailyDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.dailyDisplayName', { defaultMessage: 'Daily', }), val: 'd', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.weeklyDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.weeklyDisplayName', { defaultMessage: 'Weekly', }), val: 'w', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.monthlyDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.monthlyDisplayName', { defaultMessage: 'Monthly', }), val: 'M', }, { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.yearlyDisplayName', { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.yearlyDisplayName', { defaultMessage: 'Yearly', }), val: 'y', diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts index eb3fcc65b316b..dc0f9baa6d0cc 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts @@ -65,7 +65,7 @@ export function isDateHistogramBucketAggConfig(agg: any): agg is IBucketDateHist export const dateHistogramBucketAgg = new BucketAggType({ name: BUCKET_TYPES.DATE_HISTOGRAM, - title: i18n.translate('common.ui.aggTypes.buckets.dateHistogramTitle', { + title: i18n.translate('data.search.aggs.buckets.dateHistogramTitle', { defaultMessage: 'Date Histogram', }), ordered: { @@ -79,7 +79,7 @@ export const dateHistogramBucketAgg = new BucketAggType bounds && collar && !geoContains(collar, bounds); -const geohashGridTitle = i18n.translate('common.ui.aggTypes.buckets.geohashGridTitle', { +const geohashGridTitle = i18n.translate('data.search.aggs.buckets.geohashGridTitle', { defaultMessage: 'Geohash', }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts index a685073cc3cbe..57e8f6e8c5ded 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts @@ -27,7 +27,7 @@ import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { IBucketAggConfig } from './_bucket_agg_type'; import { METRIC_TYPES } from '../metrics/metric_agg_types'; -const geotileGridTitle = i18n.translate('common.ui.aggTypes.buckets.geotileGridTitle', { +const geotileGridTitle = i18n.translate('data.search.aggs.buckets.geotileGridTitle', { defaultMessage: 'Geotile', }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts index 3af22d526c19d..f7e9ef45961e0 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts @@ -41,7 +41,7 @@ const getUIConfig = () => npStart.core.uiSettings; export const histogramBucketAgg = new BucketAggType({ name: BUCKET_TYPES.HISTOGRAM, - title: i18n.translate('common.ui.aggTypes.buckets.histogramTitle', { + title: i18n.translate('data.search.aggs.buckets.histogramTitle', { defaultMessage: 'Histogram', }), ordered: {}, @@ -117,7 +117,7 @@ export const histogramBucketAgg = new BucketAggType({ .catch((e: Error) => { if (e.name === 'AbortError') return; toastNotifications.addWarning( - i18n.translate('common.ui.aggTypes.histogram.missingMaxMinValuesWarning', { + i18n.translate('data.search.aggs.histogram.missingMaxMinValuesWarning', { defaultMessage: 'Unable to retrieve max and min values to auto-scale histogram buckets. This may lead to poor visualization performance.', }) diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts index abcd3d83fca4f..e5497bef49165 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts @@ -27,7 +27,7 @@ import { BUCKET_TYPES } from './bucket_agg_types'; import { createFilterIpRange } from './create_filter/ip_range'; import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../../../plugins/data/public'; -const ipRangeTitle = i18n.translate('common.ui.aggTypes.buckets.ipRangeTitle', { +const ipRangeTitle = i18n.translate('data.search.aggs.buckets.ipRangeTitle', { defaultMessage: 'IPv4 Range', }); @@ -57,7 +57,7 @@ export const ipRangeBucketAgg = new BucketAggType({ return new IpRangeFormat(); }, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.buckets.ipRangeLabel', { + return i18n.translate('data.search.aggs.buckets.ipRangeLabel', { defaultMessage: '{fieldName} IP ranges', values: { fieldName: aggConfig.getFieldDisplayName(), diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts index f6c8dbafeda9c..f35db2cc759bd 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts @@ -27,7 +27,7 @@ import { BUCKET_TYPES } from './bucket_agg_types'; const keyCaches = new WeakMap(); const formats = new WeakMap(); -const rangeTitle = i18n.translate('common.ui.aggTypes.buckets.rangeTitle', { +const rangeTitle = i18n.translate('data.search.aggs.buckets.rangeTitle', { defaultMessage: 'Range', }); @@ -36,7 +36,7 @@ export const rangeBucketAgg = new BucketAggType({ title: rangeTitle, createFilter: createFilterRange, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.buckets.rangesLabel', { + return i18n.translate('data.search.aggs.aggTypesLabel', { defaultMessage: '{fieldName} ranges', values: { fieldName: aggConfig.getFieldDisplayName(), @@ -69,7 +69,7 @@ export const rangeBucketAgg = new BucketAggType({ const format = agg.fieldOwnFormatter(); const gte = '\u2265'; const lt = '\u003c'; - return i18n.translate('common.ui.aggTypes.buckets.ranges.rangesFormatMessage', { + return i18n.translate('data.search.aggs.aggTypes.rangesFormatMessage', { defaultMessage: '{gte} {from} and {lt} {to}', values: { gte, diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts index fb7bf07fa7015..bc6c63d569b11 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts @@ -24,7 +24,7 @@ import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exc import { BUCKET_TYPES } from './bucket_agg_types'; import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const significantTermsTitle = i18n.translate('common.ui.aggTypes.buckets.significantTermsTitle', { +const significantTermsTitle = i18n.translate('data.search.aggs.buckets.significantTermsTitle', { defaultMessage: 'Significant Terms', }); @@ -32,7 +32,7 @@ export const significantTermsBucketAgg = new BucketAggType({ name: BUCKET_TYPES.SIGNIFICANT_TERMS, title: significantTermsTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.buckets.significantTermsLabel', { + return i18n.translate('data.search.aggs.buckets.significantTermsLabel', { defaultMessage: 'Top {size} unusual terms in {fieldName}', values: { size: aggConfig.params.size, @@ -54,7 +54,7 @@ export const significantTermsBucketAgg = new BucketAggType({ }, { name: 'exclude', - displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.excludeLabel', { + displayName: i18n.translate('data.search.aggs.buckets.significantTerms.excludeLabel', { defaultMessage: 'Exclude', }), type: 'string', @@ -64,7 +64,7 @@ export const significantTermsBucketAgg = new BucketAggType({ }, { name: 'include', - displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.includeLabel', { + displayName: i18n.translate('data.search.aggs.buckets.significantTerms.includeLabel', { defaultMessage: 'Include', }), type: 'string', diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts index a78fe9a386934..b41b16af122fa 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts @@ -69,7 +69,7 @@ const [orderAggSchema] = new Schemas([ }, ]).all; -const termsTitle = i18n.translate('common.ui.aggTypes.buckets.termsTitle', { +const termsTitle = i18n.translate('data.search.aggs.buckets.termsTitle', { defaultMessage: 'Terms', }); @@ -114,11 +114,11 @@ export const termsBucketAgg = new BucketAggType({ nestedSearchSource.setField('aggs', filterAgg); const request = inspectorAdapters.requests.start( - i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketTitle', { + i18n.translate('data.search.aggs.buckets.terms.otherBucketTitle', { defaultMessage: 'Other bucket', }), { - description: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketDescription', { + description: i18n.translate('data.search.aggs.buckets.terms.otherBucketDescription', { defaultMessage: 'This request counts the number of documents that fall ' + 'outside the criterion of the data buckets.', @@ -213,13 +213,13 @@ export const termsBucketAgg = new BucketAggType({ default: 'desc', options: [ { - text: i18n.translate('common.ui.aggTypes.buckets.terms.orderDescendingTitle', { + text: i18n.translate('data.search.aggs.buckets.terms.orderDescendingTitle', { defaultMessage: 'Descending', }), value: 'desc', }, { - text: i18n.translate('common.ui.aggTypes.buckets.terms.orderAscendingTitle', { + text: i18n.translate('data.search.aggs.buckets.terms.orderAscendingTitle', { defaultMessage: 'Ascending', }), value: 'asc', @@ -239,10 +239,10 @@ export const termsBucketAgg = new BucketAggType({ { name: 'otherBucketLabel', type: 'string', - default: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketLabel', { + default: i18n.translate('data.search.aggs.buckets.terms.otherBucketLabel', { defaultMessage: 'Other', }), - displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForOtherBucketLabel', { + displayName: i18n.translate('data.search.aggs.otherBucket.labelForOtherBucketLabel', { defaultMessage: 'Label for other bucket', }), shouldShow: agg => agg.getParam('otherBucket'), @@ -255,13 +255,13 @@ export const termsBucketAgg = new BucketAggType({ }, { name: 'missingBucketLabel', - default: i18n.translate('common.ui.aggTypes.buckets.terms.missingBucketLabel', { + default: i18n.translate('data.search.aggs.buckets.terms.missingBucketLabel', { defaultMessage: 'Missing', description: `Default label used in charts when documents are missing a field. Visible when you create a chart with a terms aggregation and enable "Show missing values"`, }), type: 'string', - displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForMissingValuesLabel', { + displayName: i18n.translate('data.search.aggs.otherBucket.labelForMissingValuesLabel', { defaultMessage: 'Label for missing values', }), shouldShow: agg => agg.getParam('missingBucket'), @@ -269,7 +269,7 @@ export const termsBucketAgg = new BucketAggType({ }, { name: 'exclude', - displayName: i18n.translate('common.ui.aggTypes.buckets.terms.excludeLabel', { + displayName: i18n.translate('data.search.aggs.buckets.terms.excludeLabel', { defaultMessage: 'Exclude', }), type: 'string', @@ -279,7 +279,7 @@ export const termsBucketAgg = new BucketAggType({ }, { name: 'include', - displayName: i18n.translate('common.ui.aggTypes.buckets.terms.includeLabel', { + displayName: i18n.translate('data.search.aggs.buckets.terms.includeLabel', { defaultMessage: 'Include', }), type: 'string', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts index e47d148cbad78..b80671a43d2af 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts @@ -22,7 +22,7 @@ import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const averageTitle = i18n.translate('common.ui.aggTypes.metrics.averageTitle', { +const averageTitle = i18n.translate('data.search.aggs.metrics.averageTitle', { defaultMessage: 'Average', }); @@ -30,7 +30,7 @@ export const avgMetricAgg = new MetricAggType({ name: METRIC_TYPES.AVG, title: averageTitle, makeLabel: aggConfig => { - return i18n.translate('common.ui.aggTypes.metrics.averageLabel', { + return i18n.translate('data.search.aggs.metrics.averageLabel', { defaultMessage: 'Average {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts index 7142546dbd494..9fb28f8631bc6 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts @@ -25,11 +25,11 @@ import { makeNestedLabel } from './lib/make_nested_label'; import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; import { METRIC_TYPES } from './metric_agg_types'; -const overallAverageLabel = i18n.translate('common.ui.aggTypes.metrics.overallAverageLabel', { +const overallAverageLabel = i18n.translate('data.search.aggs.metrics.overallAverageLabel', { defaultMessage: 'overall average', }); -const averageBucketTitle = i18n.translate('common.ui.aggTypes.metrics.averageBucketTitle', { +const averageBucketTitle = i18n.translate('data.search.aggs.metrics.averageBucketTitle', { defaultMessage: 'Average Bucket', }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts index aa5b0521709a5..83837f0de5114 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts @@ -24,11 +24,11 @@ import { makeNestedLabel } from './lib/make_nested_label'; import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; import { METRIC_TYPES } from './metric_agg_types'; -const overallMaxLabel = i18n.translate('common.ui.aggTypes.metrics.overallMaxLabel', { +const overallMaxLabel = i18n.translate('data.search.aggs.metrics.overallMaxLabel', { defaultMessage: 'overall max', }); -const maxBucketTitle = i18n.translate('common.ui.aggTypes.metrics.maxBucketTitle', { +const maxBucketTitle = i18n.translate('data.search.aggs.metrics.maxBucketTitle', { defaultMessage: 'Max Bucket', }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts index b5c0b8865e106..d96197693dc2e 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts @@ -22,11 +22,11 @@ import { makeNestedLabel } from './lib/make_nested_label'; import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; import { METRIC_TYPES } from './metric_agg_types'; -const overallMinLabel = i18n.translate('common.ui.aggTypes.metrics.overallMinLabel', { +const overallMinLabel = i18n.translate('data.search.aggs.metrics.overallMinLabel', { defaultMessage: 'overall min', }); -const minBucketTitle = i18n.translate('common.ui.aggTypes.metrics.minBucketTitle', { +const minBucketTitle = i18n.translate('data.search.aggs.metrics.minBucketTitle', { defaultMessage: 'Min Bucket', }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts index d4faa81c4041c..1f9392c5bec35 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts @@ -23,11 +23,11 @@ import { makeNestedLabel } from './lib/make_nested_label'; import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; import { METRIC_TYPES } from './metric_agg_types'; -const overallSumLabel = i18n.translate('common.ui.aggTypes.metrics.overallSumLabel', { +const overallSumLabel = i18n.translate('data.search.aggs.metrics.overallSumLabel', { defaultMessage: 'overall sum', }); -const sumBucketTitle = i18n.translate('common.ui.aggTypes.metrics.sumBucketTitle', { +const sumBucketTitle = i18n.translate('data.search.aggs.metrics.sumBucketTitle', { defaultMessage: 'Sum Bucket', }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts index 5f99febcd713f..147e925521088 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts @@ -23,7 +23,7 @@ import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const uniqueCountTitle = i18n.translate('common.ui.aggTypes.metrics.uniqueCountTitle', { +const uniqueCountTitle = i18n.translate('data.search.aggs.metrics.uniqueCountTitle', { defaultMessage: 'Unique Count', }); @@ -31,7 +31,7 @@ export const cardinalityMetricAgg = new MetricAggType({ name: METRIC_TYPES.CARDINALITY, title: uniqueCountTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.uniqueCountLabel', { + return i18n.translate('data.search.aggs.metrics.uniqueCountLabel', { defaultMessage: 'Unique count of {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts index e063bdedf914d..14a9bd073ff2b 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts @@ -25,12 +25,12 @@ import { METRIC_TYPES } from './metric_agg_types'; export const countMetricAgg = new MetricAggType({ name: METRIC_TYPES.COUNT, - title: i18n.translate('common.ui.aggTypes.metrics.countTitle', { + title: i18n.translate('data.search.aggs.metrics.countTitle', { defaultMessage: 'Count', }), hasNoDsl: true, makeLabel() { - return i18n.translate('common.ui.aggTypes.metrics.countLabel', { + return i18n.translate('data.search.aggs.metrics.countLabel', { defaultMessage: 'Count', }); }, diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts index bad2de8cb16dc..a5d02459900bb 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts @@ -23,11 +23,11 @@ import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; import { makeNestedLabel } from './lib/make_nested_label'; import { METRIC_TYPES } from './metric_agg_types'; -const cumulativeSumLabel = i18n.translate('common.ui.aggTypes.metrics.cumulativeSumLabel', { +const cumulativeSumLabel = i18n.translate('data.search.aggs.metrics.cumulativeSumLabel', { defaultMessage: 'cumulative sum', }); -const cumulativeSumTitle = i18n.translate('common.ui.aggTypes.metrics.cumulativeSumTitle', { +const cumulativeSumTitle = i18n.translate('data.search.aggs.metrics.cumulativeSumTitle', { defaultMessage: 'Cumulative Sum', }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts index 42921621a2933..1169a527b0668 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts @@ -23,11 +23,11 @@ import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; import { makeNestedLabel } from './lib/make_nested_label'; import { METRIC_TYPES } from './metric_agg_types'; -const derivativeLabel = i18n.translate('common.ui.aggTypes.metrics.derivativeLabel', { +const derivativeLabel = i18n.translate('data.search.aggs.metrics.derivativeLabel', { defaultMessage: 'derivative', }); -const derivativeTitle = i18n.translate('common.ui.aggTypes.metrics.derivativeTitle', { +const derivativeTitle = i18n.translate('data.search.aggs.metrics.derivativeTitle', { defaultMessage: 'Derivative', }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts index 29ec2508e315c..53bc72f9ce1da 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts @@ -22,11 +22,11 @@ import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const geoBoundsTitle = i18n.translate('common.ui.aggTypes.metrics.geoBoundsTitle', { +const geoBoundsTitle = i18n.translate('data.search.aggs.metrics.geoBoundsTitle', { defaultMessage: 'Geo Bounds', }); -const geoBoundsLabel = i18n.translate('common.ui.aggTypes.metrics.geoBoundsLabel', { +const geoBoundsLabel = i18n.translate('data.search.aggs.metrics.geoBoundsLabel', { defaultMessage: 'Geo Bounds', }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts index e356133560307..a79b2b34ad1ca 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts @@ -22,11 +22,11 @@ import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const geoCentroidTitle = i18n.translate('common.ui.aggTypes.metrics.geoCentroidTitle', { +const geoCentroidTitle = i18n.translate('data.search.aggs.metrics.geoCentroidTitle', { defaultMessage: 'Geo Centroid', }); -const geoCentroidLabel = i18n.translate('common.ui.aggTypes.metrics.geoCentroidLabel', { +const geoCentroidLabel = i18n.translate('data.search.aggs.metrics.geoCentroidLabel', { defaultMessage: 'Geo Centroid', }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts index 4d558e50304e6..0d1b2472bb8e2 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts @@ -36,7 +36,7 @@ const metricAggFilter = [ '!geo_centroid', ]; -const metricAggTitle = i18n.translate('common.ui.aggTypes.metrics.metricAggTitle', { +const metricAggTitle = i18n.translate('data.search.aggs.metrics.metricAggTitle', { defaultMessage: 'Metric agg', }); @@ -51,7 +51,7 @@ const [metricAggSchema] = new Schemas([ ]).all; const parentPipelineType = i18n.translate( - 'common.ui.aggTypes.metrics.parentPipelineAggregationsSubtypeTitle', + 'data.search.aggs.metrics.parentPipelineAggregationsSubtypeTitle', { defaultMessage: 'Parent Pipeline Aggregations', } diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts index 9dd737bd6708e..3956bda1812ad 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts @@ -47,7 +47,7 @@ const [metricAggSchema] = new Schemas([ { group: 'none', name: 'metricAgg', - title: i18n.translate('common.ui.aggTypes.metrics.metricAggTitle', { + title: i18n.translate('data.search.aggs.metrics.metricAggTitle', { defaultMessage: 'Metric agg', }), aggFilter: metricAggFilter, @@ -57,7 +57,7 @@ const [metricAggSchema] = new Schemas([ const [bucketAggSchema] = new Schemas([ { group: 'none', - title: i18n.translate('common.ui.aggTypes.metrics.bucketAggTitle', { + title: i18n.translate('data.search.aggs.metrics.bucketAggTitle', { defaultMessage: 'Bucket agg', }), name: 'bucketAgg', @@ -66,7 +66,7 @@ const [bucketAggSchema] = new Schemas([ ]).all; const siblingPipelineType = i18n.translate( - 'common.ui.aggTypes.metrics.siblingPipelineAggregationsSubtypeTitle', + 'data.search.aggs.metrics.siblingPipelineAggregationsSubtypeTitle', { defaultMessage: 'Sibling pipeline aggregations', } diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts index 887a61a69b763..d561788936b51 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts @@ -22,7 +22,7 @@ import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const maxTitle = i18n.translate('common.ui.aggTypes.metrics.maxTitle', { +const maxTitle = i18n.translate('data.search.aggs.metrics.maxTitle', { defaultMessage: 'Max', }); @@ -30,7 +30,7 @@ export const maxMetricAgg = new MetricAggType({ name: METRIC_TYPES.MAX, title: maxTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.maxLabel', { + return i18n.translate('data.search.aggs.metrics.maxLabel', { defaultMessage: 'Max {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts index 7eb9cfd54620f..be080aaa5ee6f 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts @@ -24,7 +24,7 @@ import { METRIC_TYPES } from './metric_agg_types'; import { percentilesMetricAgg } from './percentiles'; import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const medianTitle = i18n.translate('common.ui.aggTypes.metrics.medianTitle', { +const medianTitle = i18n.translate('data.search.aggs.metrics.medianTitle', { defaultMessage: 'Median', }); @@ -33,7 +33,7 @@ export const medianMetricAgg = new MetricAggType({ dslName: 'percentiles', title: medianTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.medianLabel', { + return i18n.translate('data.search.aggs.metrics.medianLabel', { defaultMessage: 'Median {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts index 2f54d18809ca2..e7d286c187ef8 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts @@ -86,7 +86,7 @@ export class MetricAggType({ name: METRIC_TYPES.PERCENTILE_RANKS, - title: i18n.translate('common.ui.aggTypes.metrics.percentileRanksTitle', { + title: i18n.translate('data.search.aggs.metrics.percentileRanksTitle', { defaultMessage: 'Percentile Ranks', }), makeLabel(agg) { - return i18n.translate('common.ui.aggTypes.metrics.percentileRanksLabel', { + return i18n.translate('data.search.aggs.metrics.percentileRanksLabel', { defaultMessage: 'Percentile ranks of {field}', values: { field: agg.getFieldDisplayName() }, }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts index f6d18535723de..39dc0d0f181e9 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles.ts @@ -36,7 +36,7 @@ const valueProps = { const customLabel = this.getParam('customLabel'); const label = customLabel || this.getFieldDisplayName(); - return i18n.translate('common.ui.aggTypes.metrics.percentiles.valuePropsLabel', { + return i18n.translate('data.search.aggs.metrics.percentiles.valuePropsLabel', { defaultMessage: '{percentile} percentile of {label}', values: { percentile: ordinalSuffix(this.key), label }, }); @@ -45,11 +45,11 @@ const valueProps = { export const percentilesMetricAgg = new MetricAggType({ name: METRIC_TYPES.PERCENTILES, - title: i18n.translate('common.ui.aggTypes.metrics.percentilesTitle', { + title: i18n.translate('data.search.aggs.metrics.percentilesTitle', { defaultMessage: 'Percentiles', }), makeLabel(agg) { - return i18n.translate('common.ui.aggTypes.metrics.percentilesLabel', { + return i18n.translate('data.search.aggs.metrics.percentilesLabel', { defaultMessage: 'Percentiles of {field}', values: { field: agg.getFieldDisplayName() }, }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/serial_diff.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/serial_diff.ts index bb5431fbbefd9..5af6e1952d135 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/serial_diff.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/serial_diff.ts @@ -23,11 +23,11 @@ import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; import { makeNestedLabel } from './lib/make_nested_label'; import { METRIC_TYPES } from './metric_agg_types'; -const serialDiffTitle = i18n.translate('common.ui.aggTypes.metrics.serialDiffTitle', { +const serialDiffTitle = i18n.translate('data.search.aggs.metrics.serialDiffTitle', { defaultMessage: 'Serial Diff', }); -const serialDiffLabel = i18n.translate('common.ui.aggTypes.metrics.serialDiffLabel', { +const serialDiffLabel = i18n.translate('data.search.aggs.metrics.serialDiffLabel', { defaultMessage: 'serial diff', }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts index 764c222e72b0c..caf3bb71dd89a 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/std_deviation.ts @@ -51,7 +51,7 @@ const responseAggConfigProps = { keyedDetails(this: IStdDevAggConfig, customLabel: string, fieldDisplayName: string) { const label = customLabel || - i18n.translate('common.ui.aggTypes.metrics.standardDeviation.keyDetailsLabel', { + i18n.translate('data.search.aggs.metrics.standardDeviation.keyDetailsLabel', { defaultMessage: 'Standard Deviation of {fieldDisplayName}', values: { fieldDisplayName }, }); @@ -59,14 +59,14 @@ const responseAggConfigProps = { return { std_lower: { valProp: ['std_deviation_bounds', 'lower'], - title: i18n.translate('common.ui.aggTypes.metrics.standardDeviation.lowerKeyDetailsTitle', { + title: i18n.translate('data.search.aggs.metrics.standardDeviation.lowerKeyDetailsTitle', { defaultMessage: 'Lower {label}', values: { label }, }), }, std_upper: { valProp: ['std_deviation_bounds', 'upper'], - title: i18n.translate('common.ui.aggTypes.metrics.standardDeviation.upperKeyDetailsTitle', { + title: i18n.translate('data.search.aggs.metrics.standardDeviation.upperKeyDetailsTitle', { defaultMessage: 'Upper {label}', values: { label }, }), @@ -78,11 +78,11 @@ const responseAggConfigProps = { export const stdDeviationMetricAgg = new MetricAggType({ name: METRIC_TYPES.STD_DEV, dslName: 'extended_stats', - title: i18n.translate('common.ui.aggTypes.metrics.standardDeviationTitle', { + title: i18n.translate('data.search.aggs.metrics.standardDeviationTitle', { defaultMessage: 'Standard Deviation', }), makeLabel(agg) { - return i18n.translate('common.ui.aggTypes.metrics.standardDeviationLabel', { + return i18n.translate('data.search.aggs.metrics.standardDeviationLabel', { defaultMessage: 'Standard Deviation of {field}', values: { field: agg.getFieldDisplayName() }, }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts index 835179a774fb7..f3450ba1700c8 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/sum.ts @@ -22,7 +22,7 @@ import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const sumTitle = i18n.translate('common.ui.aggTypes.metrics.sumTitle', { +const sumTitle = i18n.translate('data.search.aggs.metrics.sumTitle', { defaultMessage: 'Sum', }); @@ -30,7 +30,7 @@ export const sumMetricAgg = new MetricAggType({ name: METRIC_TYPES.SUM, title: sumTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.sumLabel', { + return i18n.translate('data.search.aggs.metrics.sumLabel', { defaultMessage: 'Sum of {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts index 9dd690f778875..81bd14ded75b0 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts @@ -46,14 +46,14 @@ aggTypeFieldFilters.addFilter((field, aggConfig) => { export const topHitMetricAgg = new MetricAggType({ name: METRIC_TYPES.TOP_HITS, - title: i18n.translate('common.ui.aggTypes.metrics.topHitTitle', { + title: i18n.translate('data.search.aggs.metrics.topHitTitle', { defaultMessage: 'Top Hit', }), makeLabel(aggConfig) { - const lastPrefixLabel = i18n.translate('common.ui.aggTypes.metrics.topHit.lastPrefixLabel', { + const lastPrefixLabel = i18n.translate('data.search.aggs.metrics.topHit.lastPrefixLabel', { defaultMessage: 'Last', }); - const firstPrefixLabel = i18n.translate('common.ui.aggTypes.metrics.topHit.firstPrefixLabel', { + const firstPrefixLabel = i18n.translate('data.search.aggs.metrics.topHit.firstPrefixLabel', { defaultMessage: 'First', }); @@ -106,7 +106,7 @@ export const topHitMetricAgg = new MetricAggType({ type: 'optioned', options: [ { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.minLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.minLabel', { defaultMessage: 'Min', }), isCompatible: isNumericFieldSelected, @@ -114,7 +114,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'min', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.maxLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.maxLabel', { defaultMessage: 'Max', }), isCompatible: isNumericFieldSelected, @@ -122,7 +122,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'max', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.sumLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.sumLabel', { defaultMessage: 'Sum', }), isCompatible: isNumericFieldSelected, @@ -130,7 +130,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'sum', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.averageLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.averageLabel', { defaultMessage: 'Average', }), isCompatible: isNumericFieldSelected, @@ -138,7 +138,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'average', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.concatenateLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.concatenateLabel', { defaultMessage: 'Concatenate', }), isCompatible(aggConfig: IMetricAggConfig) { @@ -174,13 +174,13 @@ export const topHitMetricAgg = new MetricAggType({ default: 'desc', options: [ { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.descendingLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.descendingLabel', { defaultMessage: 'Descending', }), value: 'desc', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.ascendingLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.ascendingLabel', { defaultMessage: 'Ascending', }), value: 'asc', diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts index 1f49059131d21..c41c159ad0f78 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts @@ -49,15 +49,12 @@ export class FieldParamType extends BaseParamType { if (!field) { throw new TypeError( - i18n.translate( - 'common.ui.aggTypes.paramTypes.field.requiredFieldParameterErrorMessage', - { - defaultMessage: '{fieldParameter} is a required parameter', - values: { - fieldParameter: '"field"', - }, - } - ) + i18n.translate('data.search.aggs.paramTypes.field.requiredFieldParameterErrorMessage', { + defaultMessage: '{fieldParameter} is a required parameter', + values: { + fieldParameter: '"field"', + }, + }) ); } @@ -93,7 +90,7 @@ export class FieldParamType extends BaseParamType { if (!validField) { npStart.core.notifications.toasts.addDanger( i18n.translate( - 'common.ui.aggTypes.paramTypes.field.invalidSavedFieldParameterErrorMessage', + 'data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage', { defaultMessage: 'Saved {fieldParameter} parameter is now invalid. Please select a new field.', diff --git a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts index 0aa43dfbdaf35..d8227343159e6 100644 --- a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts +++ b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts @@ -106,7 +106,7 @@ export const getFormat: FormatFactory = mapping => { const format = getFieldFormat(id, mapping.params); const gte = '\u2265'; const lt = '\u003c'; - return i18n.translate('common.ui.aggTypes.buckets.ranges.rangesFormatMessage', { + return i18n.translate('common.ui.aggTypes.rangesFormatMessage', { defaultMessage: '{gte} {from} and {lt} {to}', values: { gte, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 47e11817ffa5d..5b25d1faca04c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -77,109 +77,110 @@ }, "messages": { "common.ui.aggResponse.allDocsTitle": "すべてのドキュメント", - "common.ui.aggTypes.aggGroups.bucketsText": "バケット", - "common.ui.aggTypes.aggGroups.metricsText": "メトリック", - "common.ui.aggTypes.buckets.dateHistogramLabel": "{intervalDescription}ごとの {fieldName}", - "common.ui.aggTypes.buckets.dateHistogramTitle": "日付ヒストグラム", - "common.ui.aggTypes.buckets.dateRangeTitle": "日付範囲", - "common.ui.aggTypes.buckets.filtersTitle": "フィルター", - "common.ui.aggTypes.buckets.filterTitle": "フィルター", - "common.ui.aggTypes.buckets.geohashGridTitle": "ジオハッシュ", - "common.ui.aggTypes.buckets.geotileGridTitle": "ジオタイル", - "common.ui.aggTypes.buckets.histogramTitle": "ヒストグラム", - "common.ui.aggTypes.buckets.intervalOptions.autoDisplayName": "自動", - "common.ui.aggTypes.buckets.intervalOptions.dailyDisplayName": "日ごと", - "common.ui.aggTypes.buckets.intervalOptions.hourlyDisplayName": "1 時間ごと", - "common.ui.aggTypes.buckets.intervalOptions.millisecondDisplayName": "ミリ秒", - "common.ui.aggTypes.buckets.intervalOptions.minuteDisplayName": "分", - "common.ui.aggTypes.buckets.intervalOptions.monthlyDisplayName": "月ごと", - "common.ui.aggTypes.buckets.intervalOptions.secondDisplayName": "秒", - "common.ui.aggTypes.buckets.intervalOptions.weeklyDisplayName": "週ごと", - "common.ui.aggTypes.buckets.intervalOptions.yearlyDisplayName": "1 年ごと", - "common.ui.aggTypes.buckets.ipRangeLabel": "{fieldName} IP 範囲", - "common.ui.aggTypes.buckets.ipRangeTitle": "IPv4 範囲", - "common.ui.aggTypes.buckets.ranges.rangesFormatMessage": "{gte} {from} と {lt} {to}", - "common.ui.aggTypes.buckets.rangesLabel": "{fieldName} の範囲", - "common.ui.aggTypes.buckets.rangeTitle": "範囲", - "common.ui.aggTypes.buckets.significantTerms.excludeLabel": "除外", - "common.ui.aggTypes.buckets.significantTerms.includeLabel": "含める", - "common.ui.aggTypes.buckets.significantTermsLabel": "{fieldName} のトップ {size} の珍しいアイテム", - "common.ui.aggTypes.buckets.significantTermsTitle": "重要な用語", - "common.ui.aggTypes.buckets.terms.excludeLabel": "除外", - "common.ui.aggTypes.buckets.terms.includeLabel": "含める", - "common.ui.aggTypes.buckets.terms.missingBucketLabel": "欠測値", - "common.ui.aggTypes.buckets.terms.orderAscendingTitle": "昇順", - "common.ui.aggTypes.buckets.terms.orderDescendingTitle": "降順", - "common.ui.aggTypes.buckets.terms.otherBucketDescription": "このリクエストは、データバケットの基準外のドキュメントの数をカウントします。", - "common.ui.aggTypes.buckets.terms.otherBucketLabel": "その他", - "common.ui.aggTypes.buckets.terms.otherBucketTitle": "他のバケット", - "common.ui.aggTypes.buckets.termsTitle": "用語", - "common.ui.aggTypes.histogram.missingMaxMinValuesWarning": "自動スケールヒストグラムバケットから最高値と最低値を取得できません。これによりビジュアライゼーションのパフォーマンスが低下する可能性があります。", - "common.ui.aggTypes.metrics.averageBucketTitle": "平均バケット", - "common.ui.aggTypes.metrics.averageLabel": "平均 {field}", - "common.ui.aggTypes.metrics.averageTitle": "平均", - "common.ui.aggTypes.metrics.bucketAggTitle": "バケット集約", - "common.ui.aggTypes.metrics.countLabel": "カウント", - "common.ui.aggTypes.metrics.countTitle": "カウント", - "common.ui.aggTypes.metrics.cumulativeSumLabel": "累積合計", - "common.ui.aggTypes.metrics.cumulativeSumTitle": "累積合計", - "common.ui.aggTypes.metrics.derivativeLabel": "派生", - "common.ui.aggTypes.metrics.derivativeTitle": "派生", - "common.ui.aggTypes.metrics.geoBoundsLabel": "境界", - "common.ui.aggTypes.metrics.geoBoundsTitle": "境界", - "common.ui.aggTypes.metrics.geoCentroidLabel": "ジオセントロイド", - "common.ui.aggTypes.metrics.geoCentroidTitle": "ジオセントロイド", - "common.ui.aggTypes.metrics.maxBucketTitle": "最高バケット", - "common.ui.aggTypes.metrics.maxLabel": "最高 {field}", - "common.ui.aggTypes.metrics.maxTitle": "最高", - "common.ui.aggTypes.metrics.medianLabel": "中央 {field}", - "common.ui.aggTypes.metrics.medianTitle": "中央", - "common.ui.aggTypes.metrics.metricAggregationsSubtypeTitle": "メトリック集約", - "common.ui.aggTypes.metrics.metricAggTitle": "メトリック集約", - "common.ui.aggTypes.metrics.minBucketTitle": "最低バケット", - "common.ui.aggTypes.metrics.minLabel": "最低 {field}", - "common.ui.aggTypes.metrics.minTitle": "最低", - "common.ui.aggTypes.metrics.movingAvgLabel": "移動平均", - "common.ui.aggTypes.metrics.movingAvgTitle": "移動平均", - "common.ui.aggTypes.metrics.overallAverageLabel": "全体平均", - "common.ui.aggTypes.metrics.overallMaxLabel": "全体最高", - "common.ui.aggTypes.metrics.overallMinLabel": "全体最低", - "common.ui.aggTypes.metrics.overallSumLabel": "全体合計", - "common.ui.aggTypes.metrics.parentPipelineAggregationsSubtypeTitle": "親パイプライン集約", - "common.ui.aggTypes.metrics.percentileRanks.valuePropsLabel": "「{label}」の {format} のパーセンタイル順位", - "common.ui.aggTypes.metrics.percentileRanksLabel": "{field} のパーセンタイル順位", - "common.ui.aggTypes.metrics.percentileRanksTitle": "パーセンタイル順位", - "common.ui.aggTypes.metrics.percentiles.valuePropsLabel": "{label} の {percentile} パーセンタイル", - "common.ui.aggTypes.metrics.percentilesLabel": "{field} のパーセンタイル", - "common.ui.aggTypes.metrics.percentilesTitle": "パーセンタイル", - "common.ui.aggTypes.metrics.serialDiffLabel": "差分の推移", - "common.ui.aggTypes.metrics.serialDiffTitle": "差分の推移", - "common.ui.aggTypes.metrics.siblingPipelineAggregationsSubtypeTitle": "シブリングパイプラインアグリゲーション", - "common.ui.aggTypes.metrics.standardDeviation.keyDetailsLabel": "{fieldDisplayName} の標準偏差", - "common.ui.aggTypes.metrics.standardDeviation.lowerKeyDetailsTitle": "下の{label}", - "common.ui.aggTypes.metrics.standardDeviation.upperKeyDetailsTitle": "上の{label}", - "common.ui.aggTypes.metrics.standardDeviationLabel": "{field} の標準偏差", - "common.ui.aggTypes.metrics.standardDeviationTitle": "標準偏差", - "common.ui.aggTypes.metrics.sumBucketTitle": "合計バケット", - "common.ui.aggTypes.metrics.sumLabel": "{field} の合計", - "common.ui.aggTypes.metrics.sumTitle": "合計", - "common.ui.aggTypes.metrics.topHit.ascendingLabel": "昇順", - "common.ui.aggTypes.metrics.topHit.averageLabel": "平均", - "common.ui.aggTypes.metrics.topHit.concatenateLabel": "連結", - "common.ui.aggTypes.metrics.topHit.descendingLabel": "降順", - "common.ui.aggTypes.metrics.topHit.firstPrefixLabel": "最初", - "common.ui.aggTypes.metrics.topHit.lastPrefixLabel": "最後", - "common.ui.aggTypes.metrics.topHit.maxLabel": "最高", - "common.ui.aggTypes.metrics.topHit.minLabel": "最低", - "common.ui.aggTypes.metrics.topHit.sumLabel": "合計", - "common.ui.aggTypes.metrics.topHitTitle": "トップヒット", - "common.ui.aggTypes.metrics.uniqueCountLabel": "{field} のユニークカウント", - "common.ui.aggTypes.metrics.uniqueCountTitle": "ユニークカウント", - "common.ui.aggTypes.otherBucket.labelForMissingValuesLabel": "欠測値のラベル", - "common.ui.aggTypes.otherBucket.labelForOtherBucketLabel": "他のバケットのラベル", - "common.ui.aggTypes.paramTypes.field.invalidSavedFieldParameterErrorMessage": "保存された {fieldParameter} パラメーターが無効になりました。新しいフィールドを選択してください。", - "common.ui.aggTypes.paramTypes.field.requiredFieldParameterErrorMessage": "{fieldParameter} は必須パラメーターです", - "common.ui.aggTypes.string.customLabel": "カスタムラベル", + "common.ui.aggTypes.rangesFormatMessage": "{gte} {from} と {lt} {to}", + "data.search.aggs.aggGroups.bucketsText": "バケット", + "data.search.aggs.aggGroups.metricsText": "メトリック", + "data.search.aggs.buckets.dateHistogramLabel": "{intervalDescription}ごとの {fieldName}", + "data.search.aggs.buckets.dateHistogramTitle": "日付ヒストグラム", + "data.search.aggs.buckets.dateRangeTitle": "日付範囲", + "data.search.aggs.buckets.filtersTitle": "フィルター", + "data.search.aggs.buckets.filterTitle": "フィルター", + "data.search.aggs.buckets.geohashGridTitle": "ジオハッシュ", + "data.search.aggs.buckets.geotileGridTitle": "ジオタイル", + "data.search.aggs.buckets.histogramTitle": "ヒストグラム", + "data.search.aggs.buckets.intervalOptions.autoDisplayName": "自動", + "data.search.aggs.buckets.intervalOptions.dailyDisplayName": "日ごと", + "data.search.aggs.buckets.intervalOptions.hourlyDisplayName": "1 時間ごと", + "data.search.aggs.buckets.intervalOptions.millisecondDisplayName": "ミリ秒", + "data.search.aggs.buckets.intervalOptions.minuteDisplayName": "分", + "data.search.aggs.buckets.intervalOptions.monthlyDisplayName": "月ごと", + "data.search.aggs.buckets.intervalOptions.secondDisplayName": "秒", + "data.search.aggs.buckets.intervalOptions.weeklyDisplayName": "週ごと", + "data.search.aggs.buckets.intervalOptions.yearlyDisplayName": "1 年ごと", + "data.search.aggs.buckets.ipRangeLabel": "{fieldName} IP 範囲", + "data.search.aggs.buckets.ipRangeTitle": "IPv4 範囲", + "data.search.aggs.aggTypes.rangesFormatMessage": "{gte} {from} と {lt} {to}", + "data.search.aggs.aggTypesLabel": "{fieldName} の範囲", + "data.search.aggs.buckets.rangeTitle": "範囲", + "data.search.aggs.buckets.significantTerms.excludeLabel": "除外", + "data.search.aggs.buckets.significantTerms.includeLabel": "含める", + "data.search.aggs.buckets.significantTermsLabel": "{fieldName} のトップ {size} の珍しいアイテム", + "data.search.aggs.buckets.significantTermsTitle": "重要な用語", + "data.search.aggs.buckets.terms.excludeLabel": "除外", + "data.search.aggs.buckets.terms.includeLabel": "含める", + "data.search.aggs.buckets.terms.missingBucketLabel": "欠測値", + "data.search.aggs.buckets.terms.orderAscendingTitle": "昇順", + "data.search.aggs.buckets.terms.orderDescendingTitle": "降順", + "data.search.aggs.buckets.terms.otherBucketDescription": "このリクエストは、データバケットの基準外のドキュメントの数をカウントします。", + "data.search.aggs.buckets.terms.otherBucketLabel": "その他", + "data.search.aggs.buckets.terms.otherBucketTitle": "他のバケット", + "data.search.aggs.buckets.termsTitle": "用語", + "data.search.aggs.histogram.missingMaxMinValuesWarning": "自動スケールヒストグラムバケットから最高値と最低値を取得できません。これによりビジュアライゼーションのパフォーマンスが低下する可能性があります。", + "data.search.aggs.metrics.averageBucketTitle": "平均バケット", + "data.search.aggs.metrics.averageLabel": "平均 {field}", + "data.search.aggs.metrics.averageTitle": "平均", + "data.search.aggs.metrics.bucketAggTitle": "バケット集約", + "data.search.aggs.metrics.countLabel": "カウント", + "data.search.aggs.metrics.countTitle": "カウント", + "data.search.aggs.metrics.cumulativeSumLabel": "累積合計", + "data.search.aggs.metrics.cumulativeSumTitle": "累積合計", + "data.search.aggs.metrics.derivativeLabel": "派生", + "data.search.aggs.metrics.derivativeTitle": "派生", + "data.search.aggs.metrics.geoBoundsLabel": "境界", + "data.search.aggs.metrics.geoBoundsTitle": "境界", + "data.search.aggs.metrics.geoCentroidLabel": "ジオセントロイド", + "data.search.aggs.metrics.geoCentroidTitle": "ジオセントロイド", + "data.search.aggs.metrics.maxBucketTitle": "最高バケット", + "data.search.aggs.metrics.maxLabel": "最高 {field}", + "data.search.aggs.metrics.maxTitle": "最高", + "data.search.aggs.metrics.medianLabel": "中央 {field}", + "data.search.aggs.metrics.medianTitle": "中央", + "data.search.aggs.metrics.metricAggregationsSubtypeTitle": "メトリック集約", + "data.search.aggs.metrics.metricAggTitle": "メトリック集約", + "data.search.aggs.metrics.minBucketTitle": "最低バケット", + "data.search.aggs.metrics.minLabel": "最低 {field}", + "data.search.aggs.metrics.minTitle": "最低", + "data.search.aggs.metrics.movingAvgLabel": "移動平均", + "data.search.aggs.metrics.movingAvgTitle": "移動平均", + "data.search.aggs.metrics.overallAverageLabel": "全体平均", + "data.search.aggs.metrics.overallMaxLabel": "全体最高", + "data.search.aggs.metrics.overallMinLabel": "全体最低", + "data.search.aggs.metrics.overallSumLabel": "全体合計", + "data.search.aggs.metrics.parentPipelineAggregationsSubtypeTitle": "親パイプライン集約", + "data.search.aggs.metrics.percentileRanks.valuePropsLabel": "「{label}」の {format} のパーセンタイル順位", + "data.search.aggs.metrics.percentileRanksLabel": "{field} のパーセンタイル順位", + "data.search.aggs.metrics.percentileRanksTitle": "パーセンタイル順位", + "data.search.aggs.metrics.percentiles.valuePropsLabel": "{label} の {percentile} パーセンタイル", + "data.search.aggs.metrics.percentilesLabel": "{field} のパーセンタイル", + "data.search.aggs.metrics.percentilesTitle": "パーセンタイル", + "data.search.aggs.metrics.serialDiffLabel": "差分の推移", + "data.search.aggs.metrics.serialDiffTitle": "差分の推移", + "data.search.aggs.metrics.siblingPipelineAggregationsSubtypeTitle": "シブリングパイプラインアグリゲーション", + "data.search.aggs.metrics.standardDeviation.keyDetailsLabel": "{fieldDisplayName} の標準偏差", + "data.search.aggs.metrics.standardDeviation.lowerKeyDetailsTitle": "下の{label}", + "data.search.aggs.metrics.standardDeviation.upperKeyDetailsTitle": "上の{label}", + "data.search.aggs.metrics.standardDeviationLabel": "{field} の標準偏差", + "data.search.aggs.metrics.standardDeviationTitle": "標準偏差", + "data.search.aggs.metrics.sumBucketTitle": "合計バケット", + "data.search.aggs.metrics.sumLabel": "{field} の合計", + "data.search.aggs.metrics.sumTitle": "合計", + "data.search.aggs.metrics.topHit.ascendingLabel": "昇順", + "data.search.aggs.metrics.topHit.averageLabel": "平均", + "data.search.aggs.metrics.topHit.concatenateLabel": "連結", + "data.search.aggs.metrics.topHit.descendingLabel": "降順", + "data.search.aggs.metrics.topHit.firstPrefixLabel": "最初", + "data.search.aggs.metrics.topHit.lastPrefixLabel": "最後", + "data.search.aggs.metrics.topHit.maxLabel": "最高", + "data.search.aggs.metrics.topHit.minLabel": "最低", + "data.search.aggs.metrics.topHit.sumLabel": "合計", + "data.search.aggs.metrics.topHitTitle": "トップヒット", + "data.search.aggs.metrics.uniqueCountLabel": "{field} のユニークカウント", + "data.search.aggs.metrics.uniqueCountTitle": "ユニークカウント", + "data.search.aggs.otherBucket.labelForMissingValuesLabel": "欠測値のラベル", + "data.search.aggs.otherBucket.labelForOtherBucketLabel": "他のバケットのラベル", + "data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage": "保存された {fieldParameter} パラメーターが無効になりました。新しいフィールドを選択してください。", + "data.search.aggs.paramTypes.field.requiredFieldParameterErrorMessage": "{fieldParameter} は必須パラメーターです", + "data.search.aggs.string.customLabel": "カスタムラベル", "common.ui.chrome.bigUrlWarningNotificationMessage": "{advancedSettingsLink}で{storeInSessionStorageParam}オプションを有効にするか、オンスクリーンビジュアルを簡素化してください。", "common.ui.chrome.bigUrlWarningNotificationMessage.advancedSettingsLinkText": "高度な設定", "common.ui.chrome.bigUrlWarningNotificationTitle": "URLが大きく、Kibanaの動作が停止する可能性があります", @@ -386,7 +387,7 @@ "common.ui.stateManagement.unableToStoreHistoryInSessionErrorMessage": "セッションがいっぱいで安全に削除できるアイテムが見つからないため、Kibana は履歴アイテムを保存できません。\n\nこれは大抵新規タブに移動することで解決されますが、より大きな問題が原因である可能性もあります。このメッセージが定期的に表示される場合は、{gitHubIssuesUrl} で問題を報告してください。", "common.ui.url.replacementFailedErrorMessage": "置換に失敗、未解決の表現式: {expr}", "common.ui.url.savedObjectIsMissingNotificationMessage": "保存されたオブジェクトがありません", - "common.ui.vis.aggConfig.percentageOfLabel": "{label} のパーセンテージ", + "data.search.aggs.percentageOfLabel": "{label} のパーセンテージ", "common.ui.vis.defaultFeedbackMessage": "フィードバックがありますか?{link} で問題を報告してください。", "common.ui.vis.kibanaMap.leaflet.fitDataBoundsAriaLabel": "データバウンドを合わせる", "common.ui.vis.kibanaMap.zoomWarning": "ズームレベルが最大に達しました。完全にズームインするには、Elasticsearch と Kibana の {defaultDistribution} にアップグレードしてください。{ems} でより多くのズームレベルが利用できます。または、独自のマップサーバーを構成できます。詳細は { wms } または { configSettings} をご覧ください。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 86d9a69dc0900..f85e41469683f 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -77,109 +77,110 @@ }, "messages": { "common.ui.aggResponse.allDocsTitle": "所有文档", - "common.ui.aggTypes.aggGroups.bucketsText": "存储桶", - "common.ui.aggTypes.aggGroups.metricsText": "指标", - "common.ui.aggTypes.buckets.dateHistogramLabel": "{fieldName}/{intervalDescription}", - "common.ui.aggTypes.buckets.dateHistogramTitle": "Date Histogram", - "common.ui.aggTypes.buckets.dateRangeTitle": "日期范围", - "common.ui.aggTypes.buckets.filtersTitle": "筛选", - "common.ui.aggTypes.buckets.filterTitle": "筛选", - "common.ui.aggTypes.buckets.geohashGridTitle": "Geohash", - "common.ui.aggTypes.buckets.geotileGridTitle": "地理磁贴", - "common.ui.aggTypes.buckets.histogramTitle": "Histogram", - "common.ui.aggTypes.buckets.intervalOptions.autoDisplayName": "自动", - "common.ui.aggTypes.buckets.intervalOptions.dailyDisplayName": "每日", - "common.ui.aggTypes.buckets.intervalOptions.hourlyDisplayName": "每小时", - "common.ui.aggTypes.buckets.intervalOptions.millisecondDisplayName": "毫秒", - "common.ui.aggTypes.buckets.intervalOptions.minuteDisplayName": "分钟", - "common.ui.aggTypes.buckets.intervalOptions.monthlyDisplayName": "每月", - "common.ui.aggTypes.buckets.intervalOptions.secondDisplayName": "秒", - "common.ui.aggTypes.buckets.intervalOptions.weeklyDisplayName": "每周", - "common.ui.aggTypes.buckets.intervalOptions.yearlyDisplayName": "每年", - "common.ui.aggTypes.buckets.ipRangeLabel": "{fieldName} IP 范围", - "common.ui.aggTypes.buckets.ipRangeTitle": "IPv4 范围", - "common.ui.aggTypes.buckets.ranges.rangesFormatMessage": "{gte} {from} 且 {lt} {to}", - "common.ui.aggTypes.buckets.rangesLabel": "{fieldName} 范围", - "common.ui.aggTypes.buckets.rangeTitle": "范围", - "common.ui.aggTypes.buckets.significantTerms.excludeLabel": "排除", - "common.ui.aggTypes.buckets.significantTerms.includeLabel": "包括", - "common.ui.aggTypes.buckets.significantTermsLabel": "{fieldName} 中排名前 {size} 的罕见词", - "common.ui.aggTypes.buckets.significantTermsTitle": "重要词", - "common.ui.aggTypes.buckets.terms.excludeLabel": "排除", - "common.ui.aggTypes.buckets.terms.includeLabel": "包括", - "common.ui.aggTypes.buckets.terms.missingBucketLabel": "缺失", - "common.ui.aggTypes.buckets.terms.orderAscendingTitle": "升序", - "common.ui.aggTypes.buckets.terms.orderDescendingTitle": "降序", - "common.ui.aggTypes.buckets.terms.otherBucketDescription": "此请求计数不符合数据存储桶条件的文档数目。", - "common.ui.aggTypes.buckets.terms.otherBucketLabel": "其他", - "common.ui.aggTypes.buckets.terms.otherBucketTitle": "其他存储桶", - "common.ui.aggTypes.buckets.termsTitle": "词", - "common.ui.aggTypes.histogram.missingMaxMinValuesWarning": "无法检索最大值和最小值以自动缩放直方图存储桶。这可能会导致可视化性能低下。", - "common.ui.aggTypes.metrics.averageBucketTitle": "平均存储桶", - "common.ui.aggTypes.metrics.averageLabel": "{field}平均值", - "common.ui.aggTypes.metrics.averageTitle": "平均值", - "common.ui.aggTypes.metrics.bucketAggTitle": "存储桶聚合", - "common.ui.aggTypes.metrics.countLabel": "计数", - "common.ui.aggTypes.metrics.countTitle": "计数", - "common.ui.aggTypes.metrics.cumulativeSumLabel": "累计和", - "common.ui.aggTypes.metrics.cumulativeSumTitle": "累计和", - "common.ui.aggTypes.metrics.derivativeLabel": "导数", - "common.ui.aggTypes.metrics.derivativeTitle": "导数", - "common.ui.aggTypes.metrics.geoBoundsLabel": "地理边界", - "common.ui.aggTypes.metrics.geoBoundsTitle": "地理边界", - "common.ui.aggTypes.metrics.geoCentroidLabel": "地理重心", - "common.ui.aggTypes.metrics.geoCentroidTitle": "地理重心", - "common.ui.aggTypes.metrics.maxBucketTitle": "最大存储桶", - "common.ui.aggTypes.metrics.maxLabel": "{field}最大值", - "common.ui.aggTypes.metrics.maxTitle": "最大值", - "common.ui.aggTypes.metrics.medianLabel": "{field}中值", - "common.ui.aggTypes.metrics.medianTitle": "中值", - "common.ui.aggTypes.metrics.metricAggregationsSubtypeTitle": "指标聚合", - "common.ui.aggTypes.metrics.metricAggTitle": "指标聚合", - "common.ui.aggTypes.metrics.minBucketTitle": "最小存储桶", - "common.ui.aggTypes.metrics.minLabel": "{field}最小值", - "common.ui.aggTypes.metrics.minTitle": "最小值", - "common.ui.aggTypes.metrics.movingAvgLabel": "移动平均值", - "common.ui.aggTypes.metrics.movingAvgTitle": "移动平均值", - "common.ui.aggTypes.metrics.overallAverageLabel": "总体平均值", - "common.ui.aggTypes.metrics.overallMaxLabel": "总体最大值", - "common.ui.aggTypes.metrics.overallMinLabel": "总体最大值", - "common.ui.aggTypes.metrics.overallSumLabel": "总和", - "common.ui.aggTypes.metrics.parentPipelineAggregationsSubtypeTitle": "父级管道聚合", - "common.ui.aggTypes.metrics.percentileRanks.valuePropsLabel": "“{label}” 的百分位数排名 {format}", - "common.ui.aggTypes.metrics.percentileRanksLabel": "“{field}” 的百分位数排名", - "common.ui.aggTypes.metrics.percentileRanksTitle": "百分位数排名", - "common.ui.aggTypes.metrics.percentiles.valuePropsLabel": "“{label}” 的 {percentile} 百分位数", - "common.ui.aggTypes.metrics.percentilesLabel": "“{field}” 的百分位数", - "common.ui.aggTypes.metrics.percentilesTitle": "百分位数", - "common.ui.aggTypes.metrics.serialDiffLabel": "序列差异", - "common.ui.aggTypes.metrics.serialDiffTitle": "序列差异", - "common.ui.aggTypes.metrics.siblingPipelineAggregationsSubtypeTitle": "同级管道聚合", - "common.ui.aggTypes.metrics.standardDeviation.keyDetailsLabel": "“{fieldDisplayName}” 的标准偏差", - "common.ui.aggTypes.metrics.standardDeviation.lowerKeyDetailsTitle": "下{label}", - "common.ui.aggTypes.metrics.standardDeviation.upperKeyDetailsTitle": "上{label}", - "common.ui.aggTypes.metrics.standardDeviationLabel": "“{field}” 的标准偏差", - "common.ui.aggTypes.metrics.standardDeviationTitle": "标准偏差", - "common.ui.aggTypes.metrics.sumBucketTitle": "求和存储桶", - "common.ui.aggTypes.metrics.sumLabel": "“{field}” 的和", - "common.ui.aggTypes.metrics.sumTitle": "和", - "common.ui.aggTypes.metrics.topHit.ascendingLabel": "升序", - "common.ui.aggTypes.metrics.topHit.averageLabel": "平均值", - "common.ui.aggTypes.metrics.topHit.concatenateLabel": "连接", - "common.ui.aggTypes.metrics.topHit.descendingLabel": "降序", - "common.ui.aggTypes.metrics.topHit.firstPrefixLabel": "第一", - "common.ui.aggTypes.metrics.topHit.lastPrefixLabel": "最后", - "common.ui.aggTypes.metrics.topHit.maxLabel": "最大值", - "common.ui.aggTypes.metrics.topHit.minLabel": "最小值", - "common.ui.aggTypes.metrics.topHit.sumLabel": "和", - "common.ui.aggTypes.metrics.topHitTitle": "最高命中结果", - "common.ui.aggTypes.metrics.uniqueCountLabel": "“{field}” 的唯一计数", - "common.ui.aggTypes.metrics.uniqueCountTitle": "唯一计数", - "common.ui.aggTypes.otherBucket.labelForMissingValuesLabel": "缺失值的标签", - "common.ui.aggTypes.otherBucket.labelForOtherBucketLabel": "其他存储桶的标签", - "common.ui.aggTypes.paramTypes.field.invalidSavedFieldParameterErrorMessage": "已保存的 {fieldParameter} 参数现在无效。请选择新字段。", - "common.ui.aggTypes.paramTypes.field.requiredFieldParameterErrorMessage": "{fieldParameter} 是必需字段", - "common.ui.aggTypes.string.customLabel": "定制标签", + "common.ui.aggTypes.rangesFormatMessage": "{gte} {from} 且 {lt} {to}", + "data.search.aggs.aggGroups.bucketsText": "存储桶", + "data.search.aggs.aggGroups.metricsText": "指标", + "data.search.aggs.buckets.dateHistogramLabel": "{fieldName}/{intervalDescription}", + "data.search.aggs.buckets.dateHistogramTitle": "Date Histogram", + "data.search.aggs.buckets.dateRangeTitle": "日期范围", + "data.search.aggs.buckets.filtersTitle": "筛选", + "data.search.aggs.buckets.filterTitle": "筛选", + "data.search.aggs.buckets.geohashGridTitle": "Geohash", + "data.search.aggs.buckets.geotileGridTitle": "地理磁贴", + "data.search.aggs.buckets.histogramTitle": "Histogram", + "data.search.aggs.buckets.intervalOptions.autoDisplayName": "自动", + "data.search.aggs.buckets.intervalOptions.dailyDisplayName": "每日", + "data.search.aggs.buckets.intervalOptions.hourlyDisplayName": "每小时", + "data.search.aggs.buckets.intervalOptions.millisecondDisplayName": "毫秒", + "data.search.aggs.buckets.intervalOptions.minuteDisplayName": "分钟", + "data.search.aggs.buckets.intervalOptions.monthlyDisplayName": "每月", + "data.search.aggs.buckets.intervalOptions.secondDisplayName": "秒", + "data.search.aggs.buckets.intervalOptions.weeklyDisplayName": "每周", + "data.search.aggs.buckets.intervalOptions.yearlyDisplayName": "每年", + "data.search.aggs.buckets.ipRangeLabel": "{fieldName} IP 范围", + "data.search.aggs.buckets.ipRangeTitle": "IPv4 范围", + "data.search.aggs.aggTypes.rangesFormatMessage": "{gte} {from} 且 {lt} {to}", + "data.search.aggs.aggTypesLabel": "{fieldName} 范围", + "data.search.aggs.buckets.rangeTitle": "范围", + "data.search.aggs.buckets.significantTerms.excludeLabel": "排除", + "data.search.aggs.buckets.significantTerms.includeLabel": "包括", + "data.search.aggs.buckets.significantTermsLabel": "{fieldName} 中排名前 {size} 的罕见词", + "data.search.aggs.buckets.significantTermsTitle": "重要词", + "data.search.aggs.buckets.terms.excludeLabel": "排除", + "data.search.aggs.buckets.terms.includeLabel": "包括", + "data.search.aggs.buckets.terms.missingBucketLabel": "缺失", + "data.search.aggs.buckets.terms.orderAscendingTitle": "升序", + "data.search.aggs.buckets.terms.orderDescendingTitle": "降序", + "data.search.aggs.buckets.terms.otherBucketDescription": "此请求计数不符合数据存储桶条件的文档数目。", + "data.search.aggs.buckets.terms.otherBucketLabel": "其他", + "data.search.aggs.buckets.terms.otherBucketTitle": "其他存储桶", + "data.search.aggs.buckets.termsTitle": "词", + "data.search.aggs.histogram.missingMaxMinValuesWarning": "无法检索最大值和最小值以自动缩放直方图存储桶。这可能会导致可视化性能低下。", + "data.search.aggs.metrics.averageBucketTitle": "平均存储桶", + "data.search.aggs.metrics.averageLabel": "{field}平均值", + "data.search.aggs.metrics.averageTitle": "平均值", + "data.search.aggs.metrics.bucketAggTitle": "存储桶聚合", + "data.search.aggs.metrics.countLabel": "计数", + "data.search.aggs.metrics.countTitle": "计数", + "data.search.aggs.metrics.cumulativeSumLabel": "累计和", + "data.search.aggs.metrics.cumulativeSumTitle": "累计和", + "data.search.aggs.metrics.derivativeLabel": "导数", + "data.search.aggs.metrics.derivativeTitle": "导数", + "data.search.aggs.metrics.geoBoundsLabel": "地理边界", + "data.search.aggs.metrics.geoBoundsTitle": "地理边界", + "data.search.aggs.metrics.geoCentroidLabel": "地理重心", + "data.search.aggs.metrics.geoCentroidTitle": "地理重心", + "data.search.aggs.metrics.maxBucketTitle": "最大存储桶", + "data.search.aggs.metrics.maxLabel": "{field}最大值", + "data.search.aggs.metrics.maxTitle": "最大值", + "data.search.aggs.metrics.medianLabel": "{field}中值", + "data.search.aggs.metrics.medianTitle": "中值", + "data.search.aggs.metrics.metricAggregationsSubtypeTitle": "指标聚合", + "data.search.aggs.metrics.metricAggTitle": "指标聚合", + "data.search.aggs.metrics.minBucketTitle": "最小存储桶", + "data.search.aggs.metrics.minLabel": "{field}最小值", + "data.search.aggs.metrics.minTitle": "最小值", + "data.search.aggs.metrics.movingAvgLabel": "移动平均值", + "data.search.aggs.metrics.movingAvgTitle": "移动平均值", + "data.search.aggs.metrics.overallAverageLabel": "总体平均值", + "data.search.aggs.metrics.overallMaxLabel": "总体最大值", + "data.search.aggs.metrics.overallMinLabel": "总体最大值", + "data.search.aggs.metrics.overallSumLabel": "总和", + "data.search.aggs.metrics.parentPipelineAggregationsSubtypeTitle": "父级管道聚合", + "data.search.aggs.metrics.percentileRanks.valuePropsLabel": "“{label}” 的百分位数排名 {format}", + "data.search.aggs.metrics.percentileRanksLabel": "“{field}” 的百分位数排名", + "data.search.aggs.metrics.percentileRanksTitle": "百分位数排名", + "data.search.aggs.metrics.percentiles.valuePropsLabel": "“{label}” 的 {percentile} 百分位数", + "data.search.aggs.metrics.percentilesLabel": "“{field}” 的百分位数", + "data.search.aggs.metrics.percentilesTitle": "百分位数", + "data.search.aggs.metrics.serialDiffLabel": "序列差异", + "data.search.aggs.metrics.serialDiffTitle": "序列差异", + "data.search.aggs.metrics.siblingPipelineAggregationsSubtypeTitle": "同级管道聚合", + "data.search.aggs.metrics.standardDeviation.keyDetailsLabel": "“{fieldDisplayName}” 的标准偏差", + "data.search.aggs.metrics.standardDeviation.lowerKeyDetailsTitle": "下{label}", + "data.search.aggs.metrics.standardDeviation.upperKeyDetailsTitle": "上{label}", + "data.search.aggs.metrics.standardDeviationLabel": "“{field}” 的标准偏差", + "data.search.aggs.metrics.standardDeviationTitle": "标准偏差", + "data.search.aggs.metrics.sumBucketTitle": "求和存储桶", + "data.search.aggs.metrics.sumLabel": "“{field}” 的和", + "data.search.aggs.metrics.sumTitle": "和", + "data.search.aggs.metrics.topHit.ascendingLabel": "升序", + "data.search.aggs.metrics.topHit.averageLabel": "平均值", + "data.search.aggs.metrics.topHit.concatenateLabel": "连接", + "data.search.aggs.metrics.topHit.descendingLabel": "降序", + "data.search.aggs.metrics.topHit.firstPrefixLabel": "第一", + "data.search.aggs.metrics.topHit.lastPrefixLabel": "最后", + "data.search.aggs.metrics.topHit.maxLabel": "最大值", + "data.search.aggs.metrics.topHit.minLabel": "最小值", + "data.search.aggs.metrics.topHit.sumLabel": "和", + "data.search.aggs.metrics.topHitTitle": "最高命中结果", + "data.search.aggs.metrics.uniqueCountLabel": "“{field}” 的唯一计数", + "data.search.aggs.metrics.uniqueCountTitle": "唯一计数", + "data.search.aggs.otherBucket.labelForMissingValuesLabel": "缺失值的标签", + "data.search.aggs.otherBucket.labelForOtherBucketLabel": "其他存储桶的标签", + "data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage": "已保存的 {fieldParameter} 参数现在无效。请选择新字段。", + "data.search.aggs.paramTypes.field.requiredFieldParameterErrorMessage": "{fieldParameter} 是必需字段", + "data.search.aggs.string.customLabel": "定制标签", "common.ui.chrome.bigUrlWarningNotificationMessage": "在{advancedSettingsLink}中启用“{storeInSessionStorageParam}”选项或简化屏幕视觉效果。", "common.ui.chrome.bigUrlWarningNotificationMessage.advancedSettingsLinkText": "高级设置", "common.ui.chrome.bigUrlWarningNotificationTitle": "URL 过长,Kibana 可能无法工作", @@ -386,7 +387,7 @@ "common.ui.stateManagement.unableToStoreHistoryInSessionErrorMessage": "Kibana 无法将历史记录项存储在您的会话中,因为其已满,并且似乎没有任何可安全删除的项。\n\n通常可通过移至新的标签页来解决此问题,但这会导致更大的问题。如果您有规律地看到此消息,请在 {gitHubIssuesUrl} 提交问题。", "common.ui.url.replacementFailedErrorMessage": "替换失败,未解析的表达式:{expr}", "common.ui.url.savedObjectIsMissingNotificationMessage": "已保存对象缺失", - "common.ui.vis.aggConfig.percentageOfLabel": "{label} 的百分比", + "data.search.aggs.percentageOfLabel": "{label} 的百分比", "common.ui.vis.defaultFeedbackMessage": "想反馈?请在“{link}中创建问题。", "common.ui.vis.kibanaMap.leaflet.fitDataBoundsAriaLabel": "适应数据边界", "common.ui.vis.kibanaMap.zoomWarning": "已达到缩放级别最大数目。要一直放大,请升级到 Elasticsearch 和 Kibana 的 {defaultDistribution}。您可以通过 {ems} 免费使用其他缩放级别。或者,您可以配置自己的地图服务器。请前往 { wms } 或 { configSettings} 以获取详细信息。",