From 18137c3a23050098f6b1f0648659101df5dd68fb Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Mon, 16 Sep 2019 17:55:53 +0300 Subject: [PATCH] Convert filter_manager/lib to TypeScript / Jest Fix: #44952 --- .../src/filters/lib/exists_filter.ts | 5 + .../kbn-es-query/src/filters/lib/index.ts | 9 +- .../src/filters/lib/match_all_filter.ts | 30 +++++ .../src/filters/lib/meta_filter.ts | 2 +- .../src/filters/lib/missing_filter.ts | 17 ++- .../src/filters/lib/query_string_filter.ts | 5 + .../src/filters/lib/range_filter.ts | 16 ++- .../filter/filter_manager/filter_manager.ts | 12 +- .../lib/__tests__/dedup_filters.js | 68 ----------- .../lib/__tests__/extract_time_filter.js | 61 ---------- .../lib/__tests__/generate_mapping_chain.js | 111 ------------------ .../lib/__tests__/map_default.js | 62 ---------- .../lib/__tests__/map_match_all.js | 68 ----------- .../lib/__tests__/uniq_filters.js | 65 ---------- .../change_time_filter.test.mocks.ts | 2 +- ...ter.test.js => change_time_filter.test.ts} | 55 +++++---- ...e_time_filter.js => change_time_filter.ts} | 27 +++-- ...{compare_filters.js => compare_filters.ts} | 30 ++--- .../filter_manager/lib/dedup_filters.test.ts | 79 +++++++++++++ .../{dedup_filters.js => dedup_filters.ts} | 33 ++++-- .../lib/extract_time_filter.test.ts | 59 ++++++++++ ..._time_filter.js => extract_time_filter.ts} | 27 +++-- .../lib/generate_mapping_chain.test.ts | 111 ++++++++++++++++++ ...ing_chain.js => generate_mapping_chain.ts} | 16 +-- .../map_missing.js => map_default.test.ts} | 36 +++--- .../lib/{map_default.js => map_default.ts} | 18 +-- .../map_exists.js => map_exists.test.ts} | 39 +++--- .../lib/{map_match_all.js => map_exists.ts} | 19 +-- .../filter_manager/lib/map_match_all.test.ts | 66 +++++++++++ .../filter_manager/lib/map_match_all.ts | 32 +++++ ...ap_query_string.js => map_missing.test.ts} | 38 +++--- .../lib/{map_missing.js => map_missing.ts} | 17 ++- .../lib/{map_phrases.js => map_phrases.ts} | 11 +- .../lib/map_query_string.test.ts | 47 ++++++++ ...ap_query_string.js => map_query_string.ts} | 17 ++- .../lib/{map_range.js => map_range.ts} | 35 ++++-- .../filter_manager/lib/only_disabled.test.ts | 66 ++++++----- .../filter_manager/lib/only_disabled.ts | 18 +-- .../filter_manager/lib/uniq_filters.test.ts | 60 ++++++++++ .../lib/{uniq_filters.js => uniq_filters.ts} | 15 ++- .../data/public/timefilter/timefilter.ts | 3 + 41 files changed, 829 insertions(+), 678 deletions(-) create mode 100644 packages/kbn-es-query/src/filters/lib/match_all_filter.ts rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_exists.js => packages/kbn-es-query/src/filters/lib/missing_filter.ts (79%) delete mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/dedup_filters.js delete mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/extract_time_filter.js delete mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/generate_mapping_chain.js delete mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_default.js delete mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_match_all.js delete mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/uniq_filters.js rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{__tests__ => }/change_time_filter.test.mocks.ts (92%) rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{__tests__/change_time_filter.test.js => change_time_filter.test.ts} (62%) rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{change_time_filter.js => change_time_filter.ts} (67%) rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{compare_filters.js => compare_filters.ts} (62%) create mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/dedup_filters.test.ts rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{dedup_filters.js => dedup_filters.ts} (61%) create mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/extract_time_filter.test.ts rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{extract_time_filter.js => extract_time_filter.ts} (66%) create mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/generate_mapping_chain.test.ts rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{generate_mapping_chain.js => generate_mapping_chain.ts} (75%) rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{__tests__/map_missing.js => map_default.test.ts} (51%) rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{map_default.js => map_default.ts} (74%) rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{__tests__/map_exists.js => map_exists.test.ts} (51%) rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{map_match_all.js => map_exists.ts} (76%) create mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_match_all.test.ts create mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_match_all.ts rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{__tests__/map_query_string.js => map_missing.test.ts} (51%) rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{map_missing.js => map_missing.ts} (78%) rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{map_phrases.js => map_phrases.ts} (85%) create mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_query_string.test.ts rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{map_query_string.js => map_query_string.ts} (77%) rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{map_range.js => map_range.ts} (66%) create mode 100644 src/legacy/core_plugins/data/public/filter/filter_manager/lib/uniq_filters.test.ts rename src/legacy/core_plugins/data/public/filter/filter_manager/lib/{uniq_filters.js => uniq_filters.ts} (80%) diff --git a/packages/kbn-es-query/src/filters/lib/exists_filter.ts b/packages/kbn-es-query/src/filters/lib/exists_filter.ts index 356d039f4d19b..4e24ab9b1d1dd 100644 --- a/packages/kbn-es-query/src/filters/lib/exists_filter.ts +++ b/packages/kbn-es-query/src/filters/lib/exists_filter.ts @@ -21,6 +21,11 @@ import { Filter, FilterMeta } from './meta_filter'; export type ExistsFilterMeta = FilterMeta; +export interface FilterExistsProperty { + field: any; +} + export type ExistsFilter = Filter & { meta: ExistsFilterMeta; + exists?: FilterExistsProperty; }; diff --git a/packages/kbn-es-query/src/filters/lib/index.ts b/packages/kbn-es-query/src/filters/lib/index.ts index fdf87c84eb5ca..e69b949e55918 100644 --- a/packages/kbn-es-query/src/filters/lib/index.ts +++ b/packages/kbn-es-query/src/filters/lib/index.ts @@ -29,6 +29,9 @@ import { PhraseFilter } from './phrase_filter'; import { PhrasesFilter } from './phrases_filter'; import { QueryStringFilter } from './query_string_filter'; import { RangeFilter } from './range_filter'; +import { MatchAllFilter } from './match_all_filter'; +import { MissingFilter } from './missing_filter'; + export { CustomFilter, ExistsFilter, @@ -38,6 +41,8 @@ export { PhrasesFilter, QueryStringFilter, RangeFilter, + MatchAllFilter, + MissingFilter, }; // Any filter associated with a field (used in the filter bar/editor) @@ -47,4 +52,6 @@ export type FieldFilter = | GeoPolygonFilter | PhraseFilter | PhrasesFilter - | RangeFilter; + | RangeFilter + | MatchAllFilter + | MissingFilter; diff --git a/packages/kbn-es-query/src/filters/lib/match_all_filter.ts b/packages/kbn-es-query/src/filters/lib/match_all_filter.ts new file mode 100644 index 0000000000000..f099ec2974208 --- /dev/null +++ b/packages/kbn-es-query/src/filters/lib/match_all_filter.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 { Filter, FilterMeta } from './meta_filter'; + +export interface MatchAllFilterMeta extends FilterMeta { + field: any; + formattedValue: string; +} + +export type MatchAllFilter = Filter & { + meta: MatchAllFilterMeta; + match_all?: any; +}; diff --git a/packages/kbn-es-query/src/filters/lib/meta_filter.ts b/packages/kbn-es-query/src/filters/lib/meta_filter.ts index c11fb592f0e29..d814d434ab975 100644 --- a/packages/kbn-es-query/src/filters/lib/meta_filter.ts +++ b/packages/kbn-es-query/src/filters/lib/meta_filter.ts @@ -40,7 +40,7 @@ export interface FilterMeta { export interface Filter { $state?: FilterState; meta: FilterMeta; - query?: object; + query?: any; } export interface LatLon { diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_exists.js b/packages/kbn-es-query/src/filters/lib/missing_filter.ts similarity index 79% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_exists.js rename to packages/kbn-es-query/src/filters/lib/missing_filter.ts index 3e26d93f20433..232539160635f 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_exists.js +++ b/packages/kbn-es-query/src/filters/lib/missing_filter.ts @@ -17,12 +17,11 @@ * under the License. */ -export async function mapExists(filter) { - if (filter.exists) { - const type = 'exists'; - const key = filter.exists.field; - const value = type; - return { type, key, value }; - } - throw filter; -} +import { Filter, FilterMeta } from './meta_filter'; + +export type MissingFilterMeta = FilterMeta; + +export type MissingFilter = Filter & { + meta: MissingFilterMeta; + missing?: any; +}; diff --git a/packages/kbn-es-query/src/filters/lib/query_string_filter.ts b/packages/kbn-es-query/src/filters/lib/query_string_filter.ts index 1f6a95844437a..3c8e18feddef9 100644 --- a/packages/kbn-es-query/src/filters/lib/query_string_filter.ts +++ b/packages/kbn-es-query/src/filters/lib/query_string_filter.ts @@ -23,4 +23,9 @@ export type QueryStringFilterMeta = FilterMeta; export type QueryStringFilter = Filter & { meta: QueryStringFilterMeta; + query?: { + query_string: { + query: string; + }; + }; }; diff --git a/packages/kbn-es-query/src/filters/lib/range_filter.ts b/packages/kbn-es-query/src/filters/lib/range_filter.ts index 214652fb3f332..055f3080d84de 100644 --- a/packages/kbn-es-query/src/filters/lib/range_filter.ts +++ b/packages/kbn-es-query/src/filters/lib/range_filter.ts @@ -19,17 +19,29 @@ import { Filter, FilterMeta } from './meta_filter'; -export interface RangeFilterParams { +interface FilterRange { + from?: number | string; + to?: number | string; +} + +interface FilterRangeGt { gt?: number | string; + lt?: number | string; +} + +interface FilterRangeGte { gte?: number | string; lte?: number | string; - lt?: number | string; } +export type RangeFilterParams = FilterRange & FilterRangeGt & FilterRangeGte; + export type RangeFilterMeta = FilterMeta & { params: RangeFilterParams; + field?: any; }; export type RangeFilter = Filter & { meta: RangeFilterMeta; + range?: { [key: string]: RangeFilterParams }; }; diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/filter_manager.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/filter_manager.ts index f230b035de352..7e1d996f878e8 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/filter_manager.ts +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/filter_manager.ts @@ -23,18 +23,16 @@ import _ from 'lodash'; import { Subject } from 'rxjs'; import { UiSettingsClientContract } from 'src/core/public'; -// @ts-ignore + import { compareFilters } from './lib/compare_filters'; -// @ts-ignore -import { mapAndFlattenFilters } from './lib/map_and_flatten_filters'; -// @ts-ignore +import { changeTimeFilter } from './lib/change_time_filter'; +import { onlyDisabledFiltersChanged } from './lib/only_disabled'; import { uniqFilters } from './lib/uniq_filters'; + // @ts-ignore import { extractTimeFilter } from './lib/extract_time_filter'; // @ts-ignore -import { changeTimeFilter } from './lib/change_time_filter'; - -import { onlyDisabledFiltersChanged } from './lib/only_disabled'; +import { mapAndFlattenFilters } from './lib/map_and_flatten_filters'; import { PartitionedFilters } from './partitioned_filters'; diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/dedup_filters.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/dedup_filters.js deleted file mode 100644 index cbe511b326c0b..0000000000000 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/dedup_filters.js +++ /dev/null @@ -1,68 +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 { dedupFilters } from '../dedup_filters'; -import expect from '@kbn/expect'; - -describe('Filter Bar Directive', function () { - describe('dedupFilters(existing, filters)', function () { - - it('should return only filters which are not in the existing', function () { - const existing = [ - { range: { bytes: { from: 0, to: 1024 } } }, - { query: { match: { _term: { query: 'apache', type: 'phrase' } } } } - ]; - const filters = [ - { range: { bytes: { from: 1024, to: 2048 } } }, - { query: { match: { _term: { query: 'apache', type: 'phrase' } } } } - ]; - const results = dedupFilters(existing, filters); - expect(results).to.contain(filters[0]); - expect(results).to.not.contain(filters[1]); - }); - - it('should ignore the disabled attribute when comparing ', function () { - const existing = [ - { range: { bytes: { from: 0, to: 1024 } } }, - { meta: { disabled: true }, query: { match: { _term: { query: 'apache', type: 'phrase' } } } } - ]; - const filters = [ - { range: { bytes: { from: 1024, to: 2048 } } }, - { query: { match: { _term: { query: 'apache', type: 'phrase' } } } } - ]; - const results = dedupFilters(existing, filters); - expect(results).to.contain(filters[0]); - expect(results).to.not.contain(filters[1]); - }); - - it('should ignore $state attribute', function () { - const existing = [ - { range: { bytes: { from: 0, to: 1024 } } }, - { $state: { store: 'appState' }, query: { match: { _term: { query: 'apache', type: 'phrase' } } } } - ]; - const filters = [ - { range: { bytes: { from: 1024, to: 2048 } } }, - { $state: { store: 'globalState' }, query: { match: { _term: { query: 'apache', type: 'phrase' } } } } - ]; - const results = dedupFilters(existing, filters); - expect(results).to.contain(filters[0]); - expect(results).to.not.contain(filters[1]); - }); - }); -}); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/extract_time_filter.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/extract_time_filter.js deleted file mode 100644 index fe2a642199cd9..0000000000000 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/extract_time_filter.js +++ /dev/null @@ -1,61 +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 { extractTimeFilter } from '../extract_time_filter'; -import IndexPatternMock from 'fixtures/mock_index_patterns'; - -describe('Filter Bar Directive', function () { - describe('extractTimeFilter()', function () { - let mockIndexPatterns; - - beforeEach(ngMock.module( - 'kibana', - 'kibana/courier' - )); - - beforeEach(ngMock.inject(function (Private) { - mockIndexPatterns = Private(IndexPatternMock); - })); - - it('should return the matching filter for the default time field', function (done) { - const filters = [ - { meta: { index: 'logstash-*' }, query: { match: { _type: { query: 'apache', type: 'phrase' } } } }, - { meta: { index: 'logstash-*' }, range: { 'time': { gt: 1388559600000, lt: 1388646000000 } } } - ]; - extractTimeFilter(mockIndexPatterns, filters).then(function (filter) { - expect(filter).to.eql(filters[1]); - done(); - }); - }); - - it('should not return the non-matching filter for the default time field', function (done) { - const filters = [ - { meta: { index: 'logstash-*' }, query: { match: { _type: { query: 'apache', type: 'phrase' } } } }, - { meta: { index: 'logstash-*' }, range: { '@timestamp': { gt: 1388559600000, lt: 1388646000000 } } } - ]; - extractTimeFilter(mockIndexPatterns, filters).then(function (filter) { - expect(filter).to.be(undefined); - done(); - }); - }); - - }); -}); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/generate_mapping_chain.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/generate_mapping_chain.js deleted file mode 100644 index 3344b938181e5..0000000000000 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/generate_mapping_chain.js +++ /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 sinon from 'sinon'; -import expect from '@kbn/expect'; -import ngMock from 'ng_mock'; -import { generateMappingChain } from '../generate_mapping_chain'; - -describe('Filter Bar Directive', function () { - describe('generateMappingChain()', function () { - beforeEach(ngMock.module('kibana')); - - - it('should create a chaining function which calls the next function if the promise is rejected', function (done) { - const filter = {}; - const mapping = sinon.stub(); - mapping.rejects(filter); - const next = sinon.stub(); - next.resolves('good'); - const chain = generateMappingChain(mapping, next); - chain(filter).then(function (result) { - expect(result).to.be('good'); - sinon.assert.calledOnce(next); - done(); - }); - }); - - it('should create a chaining function which DOES NOT call the next function if the result is resolved', function (done) { - const mapping = sinon.stub(); - mapping.resolves('good'); - const next = sinon.stub(); - next.resolves('bad'); - const chain = generateMappingChain(mapping, next); - chain({}).then(function (result) { - expect(result).to.be('good'); - sinon.assert.notCalled(next); - done(); - }); - }); - - it('should resolve result for the mapping function', function (done) { - const mapping = sinon.stub(); - mapping.resolves({ key: 'test', value: 'example' }); - const next = sinon.stub(); - const chain = generateMappingChain(mapping, next); - chain({}).then(function (result) { - sinon.assert.notCalled(next); - expect(result).to.eql({ key: 'test', value: 'example' }); - done(); - }); - }); - - it('should call the mapping function with the argument to the chain', function (done) { - const mapping = sinon.stub(); - mapping.resolves({ key: 'test', value: 'example' }); - const next = sinon.stub(); - const chain = generateMappingChain(mapping, next); - chain({ test: 'example' }).then(function (result) { - sinon.assert.calledOnce(mapping); - expect(mapping.args[0][0]).to.eql({ test: 'example' }); - sinon.assert.notCalled(next); - expect(result).to.eql({ key: 'test', value: 'example' }); - done(); - }); - }); - - it('should resolve result for the next function', function (done) { - const filter = {}; - const mapping = sinon.stub(); - mapping.rejects(filter); - const next = sinon.stub(); - next.resolves({ key: 'test', value: 'example' }); - const chain = generateMappingChain(mapping, next); - chain(filter).then(function (result) { - sinon.assert.calledOnce(mapping); - sinon.assert.calledOnce(next); - expect(result).to.eql({ key: 'test', value: 'example' }); - done(); - }); - }); - - it('should reject with an error if no functions match', function (done) { - const filter = {}; - const mapping = sinon.stub(); - mapping.rejects(filter); - const chain = generateMappingChain(mapping); - chain(filter).catch(function (err) { - expect(err).to.be.an(Error); - expect(err.message).to.be('No mappings have been found for filter.'); - done(); - }); - }); - - }); -}); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_default.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_default.js deleted file mode 100644 index d97860ade56f5..0000000000000 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_default.js +++ /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 expect from '@kbn/expect'; -import { mapDefault } from '../map_default'; - -describe('Filter Bar Directive', function () { - describe('mapDefault()', function () { - - it('should return the key and value for matching filters', function (done) { - const filter = { query: { match_all: {} } }; - mapDefault(filter).then(function (result) { - expect(result).to.have.property('key', 'query'); - expect(result).to.have.property('value', '{"match_all":{}}'); - done(); - }); - }); - - it('should work with undefined filter types', function (done) { - const filter = { - 'bool': { - 'must': { - 'term': { - 'geo.src': 'US' - } - } - } - }; - mapDefault(filter).then(function (result) { - expect(result).to.have.property('key', 'bool'); - expect(result).to.have.property('value', JSON.stringify(filter.bool)); - done(); - }); - }); - - it('should return undefined if there is no valid key', function (done) { - const filter = { meta: {} }; - mapDefault(filter).catch(function (result) { - expect(result).to.be(filter); - done(); - }); - }); - - - }); -}); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_match_all.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_match_all.js deleted file mode 100644 index e0d8fdc88f448..0000000000000 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_match_all.js +++ /dev/null @@ -1,68 +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 { mapMatchAll } from '../map_match_all'; - -describe('filter_manager/lib', function () { - describe('mapMatchAll()', function () { - let filter; - - - beforeEach(ngMock.module('kibana')); - beforeEach(ngMock.inject(function () { - filter = { - match_all: {}, - meta: { - field: 'foo', - formattedValue: 'bar' - } - }; - })); - - describe('when given a filter that is not match_all', function () { - it('filter is rejected', function (done) { - delete filter.match_all; - mapMatchAll(filter).catch(result => { - expect(result).to.be(filter); - done(); - }); - }); - }); - - describe('when given a match_all filter', function () { - let result; - beforeEach(function (done) { - mapMatchAll(filter).then(r => { - result = r; - done(); - }); - }); - - it('key is set to meta field', function () { - expect(result).to.have.property('key', filter.meta.field); - }); - - it('value is set to meta formattedValue', function () { - expect(result).to.have.property('value', filter.meta.formattedValue); - }); - }); - }); -}); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/uniq_filters.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/uniq_filters.js deleted file mode 100644 index 569f03f28192b..0000000000000 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/uniq_filters.js +++ /dev/null @@ -1,65 +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 { uniqFilters } from '../uniq_filters'; -import expect from '@kbn/expect'; - -describe('Filter Bar Directive', function () { - describe('uniqFilter', function () { - - it('should filter out dups', function () { - const before = [ - { query: { _type: { match: { query: 'apache', type: 'phrase' } } } }, - { query: { _type: { match: { query: 'apache', type: 'phrase' } } } } - ]; - const results = uniqFilters(before); - expect(results).to.have.length(1); - }); - - it('should filter out duplicates, ignoring meta attributes', function () { - const before = [ - { - meta: { negate: true }, - query: { _type: { match: { query: 'apache', type: 'phrase' } } } - }, - { - meta: { negate: false }, - query: { _type: { match: { query: 'apache', type: 'phrase' } } } - } - ]; - const results = uniqFilters(before); - expect(results).to.have.length(1); - }); - - it('should filter out duplicates, ignoring $state attributes', function () { - const before = [ - { - $state: { store: 'appState' }, - query: { _type: { match: { query: 'apache', type: 'phrase' } } } - }, - { - $state: { store: 'globalState' }, - query: { _type: { match: { query: 'apache', type: 'phrase' } } } - } - ]; - const results = uniqFilters(before); - expect(results).to.have.length(1); - }); - }); -}); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/change_time_filter.test.mocks.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/change_time_filter.test.mocks.ts similarity index 92% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/change_time_filter.test.mocks.ts rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/change_time_filter.test.mocks.ts index add054c492510..f0de2f88dcb82 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/change_time_filter.test.mocks.ts +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/change_time_filter.test.mocks.ts @@ -17,7 +17,7 @@ * under the License. */ -import { chromeServiceMock } from '../../../../../../../../core/public/mocks'; +import { chromeServiceMock } from '../../../../../../../core/public/mocks'; jest.doMock('ui/new_platform', () => ({ npStart: { diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/change_time_filter.test.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/change_time_filter.test.ts similarity index 62% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/change_time_filter.test.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/change_time_filter.test.ts index 3a3cc176308c6..333391c6bf476 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/change_time_filter.test.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/change_time_filter.test.ts @@ -16,16 +16,19 @@ * specific language governing permissions and limitations * under the License. */ - import './change_time_filter.test.mocks'; +import { RangeFilter, buildRangeFilter } from '@kbn/es-query'; +import { timefilter } from 'ui/timefilter'; +import { changeTimeFilter } from './change_time_filter'; -jest.mock('ui/chrome', +jest.mock( + 'ui/chrome', () => ({ getBasePath: () => `/some/base/path`, getUiSettingsClient: () => { return { - get: (key) => { - switch(key) { + get: (key: string) => { + switch (key) { case 'timepicker:timeDefaults': return { from: 'now-15m', to: 'now' }; case 'timepicker:refreshIntervalDefaults': @@ -33,33 +36,37 @@ jest.mock('ui/chrome', default: throw new Error(`Unexpected config key: ${key}`); } - } + }, }; }, - }), { virtual: true }); + }), + { virtual: true } +); -import expect from '@kbn/expect'; -import { changeTimeFilter } from '../change_time_filter'; -import { timefilter } from 'ui/timefilter'; +describe('changeTimeFilter()', () => { + test('should change the timefilter to match the range gt/lt', () => { + const gt = 1488559600000; + const lt = 1488646000000; + const filter: RangeFilter = buildRangeFilter({ name: '@timestamp' }, { gt, lt }, 'index'); -describe('changeTimeFilter()', function () { - const gt = 1388559600000; - const lt = 1388646000000; - - test('should change the timefilter to match the range gt/lt', function () { - const filter = { range: { '@timestamp': { gt, lt } } }; changeTimeFilter(filter); - const { to, from } = timefilter.getTime(); - expect(to).to.be(new Date(lt).toISOString()); - expect(from).to.be(new Date(gt).toISOString()); + + const time = timefilter.getTime(); + + expect(time.from).toBe(new Date(gt).toISOString()); + expect(time.to).toBe(new Date(lt).toISOString()); }); - test('should change the timefilter to match the range gte/lte', function () { - const filter = { range: { '@timestamp': { gte: gt, lte: lt } } }; + test('should change the timefilter to match the range gte/lte', () => { + const gte = 1588559600000; + const lte = 1588646000000; + const filter: RangeFilter = buildRangeFilter({ name: '@timestamp' }, { gte, lte }, 'index'); + changeTimeFilter(filter); - const { to, from } = timefilter.getTime(); - expect(to).to.be(new Date(lt).toISOString()); - expect(from).to.be(new Date(gt).toISOString()); - }); + const time = timefilter.getTime(); + + expect(time.from).toBe(new Date(gte).toISOString()); + expect(time.to).toBe(new Date(lte).toISOString()); + }); }); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/change_time_filter.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/change_time_filter.ts similarity index 67% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/change_time_filter.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/change_time_filter.ts index eae71d244f888..21f9946fb4a02 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/change_time_filter.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/change_time_filter.ts @@ -17,16 +17,21 @@ * under the License. */ -import moment from 'moment'; -import _ from 'lodash'; +import { RangeFilter } from '@kbn/es-query'; import { timefilter } from 'ui/timefilter'; +import moment from 'moment'; + +export const changeTimeFilter = (filter: RangeFilter) => { + if (filter.range) { + const firstRange: string = Object.keys(filter.range)[0]; + const values = filter.range[firstRange]; -export function changeTimeFilter(filter) { - const key = _.keys(filter.range)[0]; - const values = filter.range[key]; - timefilter.setTime({ - from: moment(values.gt || values.gte), - to: moment(values.lt || values.lte), - mode: 'absolute', - }); -} + if (values) { + timefilter.setTime({ + from: moment(values.gt || values.gte), + to: moment(values.lt || values.lte), + mode: 'absolute', + }); + } + } +}; diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/compare_filters.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/compare_filters.ts similarity index 62% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/compare_filters.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/compare_filters.ts index f9f11f96d194f..f69d39e460272 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/compare_filters.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/compare_filters.ts @@ -17,9 +17,8 @@ * under the License. */ -import _ from 'lodash'; -let excludedAttributes; -let comparators; +import { Filter, FilterMeta } from '@kbn/es-query'; +import { defaults, isEqual, omit } from 'lodash'; /** * Compare two filters to see if they match @@ -28,9 +27,19 @@ let comparators; * @param {object} comparatorOptions Parameters to use for comparison * @returns {bool} Filters are the same */ -export function compareFilters(first, second, comparatorOptions) { - excludedAttributes = ['$$hashKey', 'meta']; - comparators = _.defaults(comparatorOptions || {}, { +export function compareFilters(first: Filter, second: Filter, comparatorOptions: any = {}) { + let comparators: any = {}; + const mapFilter = (filter: Filter) => { + const cleaned: FilterMeta = omit(filter, excludedAttributes); + + if (comparators.negate) cleaned.negate = filter.meta && Boolean(filter.meta.negate); + if (comparators.disabled) cleaned.disabled = filter.meta && Boolean(filter.meta.disabled); + + return cleaned; + }; + const excludedAttributes: string[] = ['$$hashKey', 'meta']; + + comparators = defaults(comparatorOptions || {}, { state: false, negate: false, disabled: false, @@ -38,12 +47,5 @@ export function compareFilters(first, second, comparatorOptions) { if (!comparators.state) excludedAttributes.push('$state'); - return _.isEqual(mapFilter(first), mapFilter(second)); -} - -function mapFilter(filter) { - const cleaned = _.omit(filter, excludedAttributes); - if (comparators.negate) cleaned.negate = filter.meta && !!filter.meta.negate; - if (comparators.disabled) cleaned.disabled = filter.meta && !!filter.meta.disabled; - return cleaned; + return isEqual(mapFilter(first), mapFilter(second)); } diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/dedup_filters.test.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/dedup_filters.test.ts new file mode 100644 index 0000000000000..46d57842de806 --- /dev/null +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/dedup_filters.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 { Filter, buildRangeFilter, FilterStateStore, buildQueryFilter } from '@kbn/es-query'; +import { dedupFilters } from './dedup_filters'; + +describe('Filter Bar Directive', () => { + describe('dedupFilters(existing, filters)', () => { + test('should return only filters which are not in the existing', () => { + const existing: Filter[] = [ + buildRangeFilter({ name: 'bytes' }, { from: 0, to: 1024 }, 'index'), + buildQueryFilter({ match: { _term: { query: 'apache', type: 'phrase' } } }, 'index'), + ]; + const filters: Filter[] = [ + buildRangeFilter({ name: 'bytes' }, { from: 1024, to: 2048 }, 'index'), + buildQueryFilter({ match: { _term: { query: 'apache', type: 'phrase' } } }, 'index'), + ]; + const results = dedupFilters(existing, filters); + + expect(results).toContain(filters[0]); + expect(results).not.toContain(filters[1]); + }); + + test('should ignore the disabled attribute when comparing ', () => { + const existing: Filter[] = [ + buildRangeFilter({ name: 'bytes' }, { from: 0, to: 1024 }, 'index'), + { + ...buildQueryFilter({ match: { _term: { query: 'apache', type: 'phrase' } } }, 'index'), + meta: { disabled: true, negate: false, alias: null }, + }, + ]; + const filters: Filter[] = [ + buildRangeFilter({ name: 'bytes' }, { from: 1024, to: 2048 }, 'index'), + buildQueryFilter({ match: { _term: { query: 'apache', type: 'phrase' } } }, 'index'), + ]; + const results = dedupFilters(existing, filters); + + expect(results).toContain(filters[0]); + expect(results).not.toContain(filters[1]); + }); + + test('should ignore $state attribute', () => { + const existing: Filter[] = [ + buildRangeFilter({ name: 'bytes' }, { from: 0, to: 1024 }, 'index'), + { + ...buildQueryFilter({ match: { _term: { query: 'apache', type: 'phrase' } } }, 'index'), + $state: { store: FilterStateStore.APP_STATE }, + }, + ]; + const filters: Filter[] = [ + buildRangeFilter({ name: 'bytes' }, { from: 1024, to: 2048 }, 'index'), + { + ...buildQueryFilter({ match: { _term: { query: 'apache', type: 'phrase' } } }, 'index'), + $state: { store: FilterStateStore.GLOBAL_STATE }, + }, + ]; + const results = dedupFilters(existing, filters); + + expect(results).toContain(filters[0]); + expect(results).not.toContain(filters[1]); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/dedup_filters.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/dedup_filters.ts similarity index 61% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/dedup_filters.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/dedup_filters.ts index 055e23ab2f25f..99613cef191fd 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/dedup_filters.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/dedup_filters.ts @@ -17,22 +17,33 @@ * under the License. */ -import _ from 'lodash'; +import { Filter } from '@kbn/es-query'; +import { filter, find } from 'lodash'; import { compareFilters } from './compare_filters'; /** * Combine 2 filter collections, removing duplicates - * @param {object} existing The filters to compare to - * @param {object} filters The filters being added - * @param {object} comparatorOptions Parameters to use for comparison + * + * @param {object} existingFilters - The filters to compare to + * @param {object} filters - The filters being added + * @param {object} comparatorOptions - Parameters to use for comparison + * * @returns {object} An array of filters that were not in existing */ -export function dedupFilters(existingFilters, filters, comparatorOptions) { - if (!Array.isArray(filters)) filters = [filters]; +export function dedupFilters( + existingFilters: Filter[], + filters: Filter[], + comparatorOptions: any = {} +) { + if (!Array.isArray(filters)) { + filters = [filters]; + } - return _.filter(filters, function (filter) { - return !_.find(existingFilters, function (existingFilter) { - return compareFilters(existingFilter, filter, comparatorOptions); - }); - }); + return filter( + filters, + (f: Filter) => + !find(existingFilters, (existingFilter: Filter) => + compareFilters(existingFilter, f, comparatorOptions) + ) + ); } diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/extract_time_filter.test.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/extract_time_filter.test.ts new file mode 100644 index 0000000000000..8774f2fbd5369 --- /dev/null +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/extract_time_filter.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 { Filter, buildRangeFilter, buildQueryFilter } from '@kbn/es-query'; +import { extractTimeFilter } from './extract_time_filter'; +import { IndexPatterns } from '../../../index_patterns'; + +const mockIndexPatterns = jest.fn( + () => + ({ + get: () => ({ + timeFieldName: 'time', + }), + } as any) +); + +describe('Filter Bar Directive', () => { + describe('extractTimeFilter()', () => { + const indexPatterns = mockIndexPatterns() as IndexPatterns; + + it('should return the matching filter for the default time field', async () => { + const filters: Filter[] = [ + buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'logstash-*'), + buildRangeFilter({ name: 'time' }, { gt: 1388559600000, lt: 1388646000000 }, 'logstash-*'), + ]; + + const result = await extractTimeFilter(indexPatterns, filters); + + expect(result).toEqual(filters[1]); + }); + + it('should not return the non-matching filter for the default time field', async () => { + const filters: Filter[] = [ + buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'logstash-*'), + buildRangeFilter({ name: '@timestamp' }, { from: 1, to: 2 }, 'logstash-*'), + ]; + + const result = await extractTimeFilter(indexPatterns, filters); + + expect(result).toBeUndefined(); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/extract_time_filter.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/extract_time_filter.ts similarity index 66% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/extract_time_filter.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/extract_time_filter.ts index 3d3fb92046507..338237a012d17 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/extract_time_filter.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/extract_time_filter.ts @@ -17,21 +17,28 @@ * under the License. */ -import _ from 'lodash'; +import { get, keys, find } from 'lodash'; +import { Filter, RangeFilter } from '@kbn/es-query'; +import { IndexPatterns } from '../../../index_patterns'; -export async function extractTimeFilter(indexPatterns, filters) { +export const extractTimeFilter = async (indexPatterns: IndexPatterns, filters: Filter[]) => { // Assume all the index patterns are the same since they will be added // from the same visualization. - const id = _.get(filters, '[0].meta.index'); - if (id == null) return; + const id: string = get(filters, '[0].meta.index'); + + if (!id) { + return; + } const indexPattern = await indexPatterns.get(id); - const filter = _.find(filters, function (obj) { - const key = _.keys(obj.range)[0]; + const rangeFilter = find(filters, (obj: RangeFilter) => { + const key = keys(obj.range)[0]; + return key === indexPattern.timeFieldName; - }); - if (filter && filter.range) { - return filter; + }) as RangeFilter; + + if (rangeFilter && rangeFilter.range) { + return rangeFilter; } -} +}; diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/generate_mapping_chain.test.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/generate_mapping_chain.test.ts new file mode 100644 index 0000000000000..9e82e7e548d76 --- /dev/null +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/generate_mapping_chain.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 sinon from 'sinon'; +import { Filter, buildEmptyFilter } from '@kbn/es-query'; +import { generateMappingChain } from './generate_mapping_chain'; + +describe('Filter Bar Directive', () => { + let mapping: any; + let next: any; + + beforeEach(() => { + mapping = sinon.stub(); + next = sinon.stub(); + }); + + describe('generateMappingChain()', () => { + it('should create a chaining function which calls the next function if the promise is rejected', async () => { + const filter: Filter = buildEmptyFilter(true); + + mapping.rejects(filter); + next.resolves('good'); + + const chain = generateMappingChain(mapping, next); + const result = await chain(filter); + + expect(result).toBe('good'); + sinon.assert.calledOnce(next); + }); + + it('should create a chaining function which DOES NOT call the next function if the result is resolved', async () => { + const filter: Filter = buildEmptyFilter(true); + mapping.resolves('good'); + next.resolves('bad'); + + const chain = generateMappingChain(mapping, next); + const result = await chain(filter); + + expect(result).toBe('good'); + }); + + it('should resolve result for the mapping function', async () => { + const filter: Filter = buildEmptyFilter(true); + + mapping.resolves({ key: 'test', value: 'example' }); + + const chain = generateMappingChain(mapping, next); + const result = await chain(filter); + + sinon.assert.notCalled(next); + expect(result).toEqual({ key: 'test', value: 'example' }); + }); + + it('should call the mapping function with the argument to the chain', async () => { + // @ts-ignore + const filter: Filter = { test: 'example' }; + mapping.resolves({ key: 'test', value: 'example' }); + + const chain = generateMappingChain(mapping, next); + const result = await chain(filter); + + sinon.assert.calledOnce(mapping); + expect(mapping.args[0][0]).toEqual({ test: 'example' }); + sinon.assert.notCalled(next); + expect(result).toEqual({ key: 'test', value: 'example' }); + }); + + it('should resolve result for the next function', async () => { + const filter: Filter = buildEmptyFilter(true); + + mapping.rejects(filter); + next.resolves({ key: 'test', value: 'example' }); + + const chain = generateMappingChain(mapping, next); + const result = await chain(filter); + + sinon.assert.calledOnce(mapping); + sinon.assert.calledOnce(next); + expect(result).toEqual({ key: 'test', value: 'example' }); + }); + + it('should reject with an error if no functions match', async done => { + const filter: Filter = buildEmptyFilter(true); + + mapping.rejects(filter); + + const chain = generateMappingChain(mapping); + chain(filter).catch(err => { + expect(err).toBeInstanceOf(Error); + expect(err.message).toBe('No mappings have been found for filter.'); + done(); + }); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/generate_mapping_chain.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/generate_mapping_chain.ts similarity index 75% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/generate_mapping_chain.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/generate_mapping_chain.ts index 02905999464fd..38c83f3f4a821 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/generate_mapping_chain.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/generate_mapping_chain.ts @@ -16,19 +16,19 @@ * specific language governing permissions and limitations * under the License. */ +import { Filter } from '@kbn/es-query'; -export function generateMappingChain(fn, next) { - const noop = function () { - throw new Error('No mappings have been found for filter.'); - }; +const noop = () => { + throw new Error('No mappings have been found for filter.'); +}; - next = next || noop; - return async function (filter) { - return await fn(filter).catch(function (result) { +export const generateMappingChain = (fn: Function, next: Function = noop) => { + return async (filter: Filter) => { + return await fn(filter).catch((result: any) => { if (result === filter) { return next(filter); } throw result; }); }; -} +}; diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_missing.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_default.test.ts similarity index 51% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_missing.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_default.test.ts index a05c21b6928fb..5c8000722686e 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_missing.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_default.test.ts @@ -16,29 +16,27 @@ * specific language governing permissions and limitations * under the License. */ +import { CustomFilter, buildEmptyFilter, buildQueryFilter } from '@kbn/es-query'; +import { mapDefault } from './map_default'; -import expect from '@kbn/expect'; -import { mapMissing } from '../map_missing'; +describe('Filter Bar Directive', () => { + describe('mapDefault()', () => { + test('should return the key and value for matching filters', async () => { + const filter: CustomFilter = buildQueryFilter({ match_all: {} }, 'index'); + const result = await mapDefault(filter); -describe('Filter Bar Directive', function () { - describe('mapMissing()', function () { - - it('should return the key and value for matching filters', function (done) { - const filter = { missing: { field: '_type' } }; - mapMissing(filter).then(function (result) { - expect(result).to.have.property('key', '_type'); - expect(result).to.have.property('value', 'missing'); - done(); - }); + expect(result).toHaveProperty('key', 'query'); + expect(result).toHaveProperty('value', '{"match_all":{}}'); }); - it('should return undefined for none matching', function (done) { - const filter = { query: { match: { query: 'foo' } } }; - mapMissing(filter).catch(function (result) { - expect(result).to.be(filter); - done(); - }); - }); + test('should return undefined if there is no valid key', async () => { + const filter = buildEmptyFilter(true) as CustomFilter; + try { + await mapDefault(filter); + } catch (e) { + expect(e).toBe(filter); + } + }); }); }); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_default.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_default.ts similarity index 74% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_default.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_default.ts index 6b9b09829c839..c8821e8d36367 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_default.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_default.ts @@ -17,19 +17,19 @@ * under the License. */ -import angular from 'angular'; -import _ from 'lodash'; +import { CustomFilter } from '@kbn/es-query'; +import { find, keys, get } from 'lodash'; -export async function mapDefault(filter) { - const metaProperty = /(^\$|meta)/; +const TYPE = 'custom'; - const key = _.find(_.keys(filter), function (key) { - return !key.match(metaProperty); - }); +export async function mapDefault(filter: CustomFilter) { + const metaProperty = /(^\$|meta)/; + const key = find(keys(filter), item => !item.match(metaProperty)); if (key) { - const type = 'custom'; - const value = angular.toJson(filter[key]); + const type = TYPE; + const value = JSON.stringify(get(filter, key, {})); + return { type, key, value }; } diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_exists.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_exists.test.ts similarity index 51% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_exists.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_exists.test.ts index b9ff72e6fb22c..bfd23dad122b1 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_exists.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_exists.test.ts @@ -16,32 +16,29 @@ * specific language governing permissions and limitations * under the License. */ +import { ExistsFilter, buildEmptyFilter, buildExistsFilter } from '@kbn/es-query'; +import { mapExists } from './map_exists'; +import { mapQueryString } from './map_query_string'; -import expect from '@kbn/expect'; -import ngMock from 'ng_mock'; -import { mapExists } from '../map_exists'; +describe('Filter Bar Directive', () => { + describe('mapExists()', () => { + test('should return the key and value for matching filters', async () => { + const filter: ExistsFilter = buildExistsFilter({ name: '_type' }, 'index'); + const result = await mapExists(filter); -describe('Filter Bar Directive', function () { - describe('mapExists()', function () { - - beforeEach(ngMock.module('kibana')); - - it('should return the key and value for matching filters', function (done) { - const filter = { exists: { field: '_type' } }; - mapExists(filter).then(function (result) { - expect(result).to.have.property('key', '_type'); - expect(result).to.have.property('value', 'exists'); - done(); - }); + expect(result).toHaveProperty('key', '_type'); + expect(result).toHaveProperty('value', 'exists'); }); - it('should return undefined for none matching', function (done) { - const filter = { query: { match: { query: 'foo' } } }; - mapExists(filter).catch(function (result) { - expect(result).to.be(filter); + test('should return undefined for none matching', async done => { + const filter = buildEmptyFilter(true) as ExistsFilter; + + try { + await mapQueryString(filter); + } catch (e) { + expect(e).toBe(filter); done(); - }); + } }); - }); }); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_match_all.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_exists.ts similarity index 76% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_match_all.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_exists.ts index 2e830946dcd03..8f38df4f7630b 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_match_all.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_exists.ts @@ -17,12 +17,17 @@ * under the License. */ -export async function mapMatchAll(filter) { - if (filter.match_all) { - const type = 'match_all'; - const key = filter.meta.field; - const value = filter.meta.formattedValue || 'all'; - return { type, key, value }; +import { ExistsFilter } from '@kbn/es-query'; + +const TYPE = 'exists'; + +export const mapExists = async (filter: ExistsFilter) => { + if (filter.exists) { + return { + type: TYPE, + value: TYPE, + key: filter.exists.field, + }; } throw filter; -} +}; diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_match_all.test.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_match_all.test.ts new file mode 100644 index 0000000000000..1139f98f51335 --- /dev/null +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_match_all.test.ts @@ -0,0 +1,66 @@ +/* + * 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 { MatchAllFilter } from '@kbn/es-query'; +import { mapMatchAll } from './map_match_all'; + +describe('filter_manager/lib', () => { + describe('mapMatchAll()', () => { + let filter: MatchAllFilter; + + beforeEach(() => { + filter = { + match_all: {}, + meta: { + alias: null, + negate: true, + disabled: false, + field: 'foo', + formattedValue: 'bar', + }, + }; + }); + + describe('when given a filter that is not match_all', () => { + test('filter is rejected', async done => { + delete filter.match_all; + + try { + await mapMatchAll(filter); + } catch (e) { + expect(e).toBe(filter); + done(); + } + }); + }); + + describe('when given a match_all filter', () => { + test('key is set to meta field', async () => { + const result = await mapMatchAll(filter); + + expect(result).toHaveProperty('key', filter.meta.field); + }); + + test('value is set to meta formattedValue', async () => { + const result = await mapMatchAll(filter); + + expect(result).toHaveProperty('value', filter.meta.formattedValue); + }); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_match_all.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_match_all.ts new file mode 100644 index 0000000000000..721b7ee583de1 --- /dev/null +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_match_all.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 { MatchAllFilter } from '@kbn/es-query'; + +const TYPE = 'match_all'; + +export const mapMatchAll = async (filter: MatchAllFilter) => { + if (filter.match_all) { + return { + type: TYPE, + key: filter.meta.field, + value: filter.meta.formattedValue || 'all', + }; + } + throw filter; +}; diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_query_string.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_missing.test.ts similarity index 51% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_query_string.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_missing.test.ts index dfcfd56fa9f7d..413f8fc9fe70c 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/__tests__/map_query_string.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_missing.test.ts @@ -16,29 +16,31 @@ * specific language governing permissions and limitations * under the License. */ +import { MissingFilter, buildEmptyFilter, ExistsFilter } from '@kbn/es-query'; +import { mapMissing } from './map_missing'; -import expect from '@kbn/expect'; -import { mapQueryString } from '../map_query_string'; +describe('Filter Bar Directive', () => { + describe('mapMissing()', () => { + test('should return the key and value for matching filters', async () => { + const filter: MissingFilter = { + missing: { field: '_type' }, + ...buildEmptyFilter(true), + }; + const result = await mapMissing(filter); -describe('Filter Bar Directive', function () { - describe('mapQueryString()', function () { - - it('should return the key and value for matching filters', function (done) { - const filter = { query: { query_string: { query: 'foo:bar' } } }; - mapQueryString(filter).then(function (result) { - expect(result).to.have.property('key', 'query'); - expect(result).to.have.property('value', 'foo:bar'); - done(); - }); + expect(result).toHaveProperty('key', '_type'); + expect(result).toHaveProperty('value', 'missing'); }); - it('should return undefined for none matching', function (done) { - const filter = { query: { match: { query: 'foo' } } }; - mapQueryString(filter).catch(function (result) { - expect(result).to.be(filter); + test('should return undefined for none matching', async done => { + const filter = buildEmptyFilter(true) as ExistsFilter; + + try { + await mapMissing(filter); + } catch (e) { + expect(e).toBe(filter); done(); - }); + } }); - }); }); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_missing.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_missing.ts similarity index 78% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_missing.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_missing.ts index e2476fc003a47..ceabeb0a92f8f 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_missing.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_missing.ts @@ -16,13 +16,18 @@ * specific language governing permissions and limitations * under the License. */ +import { MissingFilter } from '@kbn/es-query'; -export async function mapMissing(filter) { +const TYPE = 'missing'; + +export const mapMissing = async (filter: MissingFilter) => { if (filter.missing) { - const type = 'missing'; - const key = filter.missing.field; - const value = type; - return { type, key, value }; + return { + type: TYPE, + value: TYPE, + key: filter.missing.field, + }; } + throw filter; -} +}; diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_phrases.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_phrases.ts similarity index 85% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_phrases.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_phrases.ts index 88c0272c71805..0d23ec6fb60af 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_phrases.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_phrases.ts @@ -17,11 +17,16 @@ * under the License. */ -export async function mapPhrases(filter) { +import { PhrasesFilter } from '@kbn/es-query'; + +const TYPE = 'phrases'; + +export const mapPhrases = async (filter: PhrasesFilter) => { const { type, key, value, params } = filter.meta; - if (type !== 'phrases') { + + if (type !== TYPE) { throw filter; } else { return { type, key, value, params }; } -} +}; diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_query_string.test.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_query_string.test.ts new file mode 100644 index 0000000000000..5c3dc5c691d25 --- /dev/null +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_query_string.test.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 { QueryStringFilter, buildQueryFilter, buildEmptyFilter } from '@kbn/es-query'; +import { mapQueryString } from './map_query_string'; + +describe('Filter Bar Directive', () => { + describe('mapQueryString()', () => { + test('should return the key and value for matching filters', async () => { + const filter: QueryStringFilter = buildQueryFilter( + { query_string: { query: 'foo:bar' } }, + 'index' + ); + const result = await mapQueryString(filter); + + expect(result).toHaveProperty('key', 'query'); + expect(result).toHaveProperty('value', 'foo:bar'); + }); + + test('should return undefined for none matching', async done => { + const filter = buildEmptyFilter(true) as QueryStringFilter; + + try { + await mapQueryString(filter); + } catch (e) { + expect(e).toBe(filter); + done(); + } + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_query_string.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_query_string.ts similarity index 77% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_query_string.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_query_string.ts index adb6db3d03143..cd5e3cf9b529e 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_query_string.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_query_string.ts @@ -16,13 +16,18 @@ * specific language governing permissions and limitations * under the License. */ +import { QueryStringFilter } from '@kbn/es-query'; -export async function mapQueryString(filter) { +const TYPE = 'query_string'; + +export const mapQueryString = (filter: QueryStringFilter) => { if (filter.query && filter.query.query_string) { - const type = 'query_string'; - const key = 'query'; - const value = filter.query.query_string.query; - return { type, key, value }; + return { + type: TYPE, + key: 'query', + value: filter.query.query_string.query, + }; } + throw filter; -} +}; diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_range.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_range.ts similarity index 66% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_range.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_range.ts index 3c76998989580..4c16985b61117 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_range.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/map_range.ts @@ -17,20 +17,31 @@ * under the License. */ +import { RangeFilter } from '@kbn/es-query'; import { has, get } from 'lodash'; import { SavedObjectNotFound } from '../../../../../../../plugins/kibana_utils/public'; +import { IndexPatterns, IndexPattern } from '../../../index_patterns'; +const TYPE = 'range'; -function isScriptedRange(filter) { - const params = get(filter, ['script', 'script', 'params']); - return params && Object.keys(params).find(key => ['gte', 'gt', 'lte', 'lt'].includes(key)); +function isScriptedRange(filter: RangeFilter) { + const params = get(filter, ['script', 'script', 'params'], {}); + + return ( + params && Object.keys(params).find((key: string) => ['gte', 'gt', 'lte', 'lt'].includes(key)) + ); } -function getParams(filter, indexPattern) { +const getFirstRangeKey = (filter: RangeFilter) => filter.range && Object.keys(filter.range)[0]; +const getRangeByKey = (filter: RangeFilter, key: string) => + get(filter, `filter.range.${key}`, null); + +function getParams(filter: RangeFilter, indexPattern?: IndexPattern) { const isScriptedRangeFilter = isScriptedRange(filter); - const type = 'range'; - const key = isScriptedRangeFilter ? filter.meta.field : Object.keys(filter.range)[0]; - const params = isScriptedRangeFilter ? filter.script.script.params : filter.range[key]; + const key: string = (isScriptedRangeFilter ? filter.meta.field : getFirstRangeKey(filter)) || ''; + const params: any = isScriptedRangeFilter + ? get(filter, 'script.script.params') + : getRangeByKey(filter, key); let left = has(params, 'gte') ? params.gte : params.gt; if (left == null) left = -Infinity; @@ -43,23 +54,23 @@ function getParams(filter, indexPattern) { // external factors e.g. a reindex. We only need the index in order to grab the field formatter, so we fallback // on displaying the raw value if the index is invalid. let value = `${left} to ${right}`; - if (indexPattern && indexPattern.fields.byName[key]) { + if (key && indexPattern && indexPattern.fields.byName[key]) { const convert = indexPattern.fields.byName[key].format.getConverterFor('text'); value = `${convert(left)} to ${convert(right)}`; } - return { type, key, value, params }; + return { type: TYPE, key, value, params }; } -export function mapRange(indexPatterns) { - return async function (filter) { +export function mapRange(indexPatterns: IndexPatterns) { + return async function(filter: RangeFilter) { const isScriptedRangeFilter = isScriptedRange(filter); if (!filter.range && !isScriptedRangeFilter) { throw filter; } try { - const indexPattern = await indexPatterns.get(filter.meta.index); + const indexPattern = await indexPatterns.get(filter.meta.index || ''); return getParams(filter, indexPattern); } catch (error) { if (error instanceof SavedObjectNotFound) { diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/only_disabled.test.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/only_disabled.test.ts index 7a3b767b97b1b..ebae657b2a435 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/only_disabled.test.ts +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/only_disabled.test.ts @@ -18,83 +18,89 @@ */ import { Filter } from '@kbn/es-query'; - import { onlyDisabledFiltersChanged } from './only_disabled'; -import expect from '@kbn/expect'; -describe('Filter Bar Directive', function() { - describe('onlyDisabledFiltersChanged()', function() { - it('should return true if all filters are disabled', function() { +describe('Filter Bar Directive', () => { + describe('onlyDisabledFiltersChanged()', () => { + test('should return true if all filters are disabled', () => { const filters = [ { meta: { disabled: true } }, { meta: { disabled: true } }, { meta: { disabled: true } }, ] as Filter[]; const newFilters = [{ meta: { disabled: true } }] as Filter[]; - expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(true); + + expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(true); }); - it('should return false if there are no old filters', function() { + test('should return false if there are no old filters', () => { const newFilters = [{ meta: { disabled: false } }] as Filter[]; - expect(onlyDisabledFiltersChanged(newFilters, undefined)).to.be(false); + + expect(onlyDisabledFiltersChanged(newFilters, undefined)).toBe(false); }); - it('should return false if there are no new filters', function() { + test('should return false if there are no new filters', () => { const filters = [{ meta: { disabled: false } }] as Filter[]; - expect(onlyDisabledFiltersChanged(undefined, filters)).to.be(false); + + expect(onlyDisabledFiltersChanged(undefined, filters)).toBe(false); }); - it('should return false if all filters are not disabled', function() { + test('should return false if all filters are not disabled', () => { const filters = [ { meta: { disabled: false } }, { meta: { disabled: false } }, { meta: { disabled: false } }, ] as Filter[]; const newFilters = [{ meta: { disabled: false } }] as Filter[]; - expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(false); + + expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(false); }); - it('should return false if only old filters are disabled', function() { + test('should return false if only old filters are disabled', () => { const filters = [ { meta: { disabled: true } }, { meta: { disabled: true } }, { meta: { disabled: true } }, ] as Filter[]; const newFilters = [{ meta: { disabled: false } }] as Filter[]; - expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(false); + + expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(false); }); - it('should return false if new filters are not disabled', function() { + test('should return false if new filters are not disabled', () => { const filters = [ { meta: { disabled: false } }, { meta: { disabled: false } }, { meta: { disabled: false } }, ] as Filter[]; const newFilters = [{ meta: { disabled: true } }] as Filter[]; - expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(false); + + expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(false); }); - it('should return true when all removed filters were disabled', function() { + test('should return true when all removed filters were disabled', () => { const filters = [ { meta: { disabled: true } }, { meta: { disabled: true } }, { meta: { disabled: true } }, ] as Filter[]; const newFilters = [] as Filter[]; - expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(true); + + expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(true); }); - it('should return false when all removed filters were not disabled', function() { + test('should return false when all removed filters were not disabled', () => { const filters = [ { meta: { disabled: false } }, { meta: { disabled: false } }, { meta: { disabled: false } }, ] as Filter[]; const newFilters = [] as Filter[]; - expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(false); + + expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(false); }); - it('should return true if all changed filters are disabled', function() { + test('should return true if all changed filters are disabled', () => { const filters = [ { meta: { disabled: true, negate: false } }, { meta: { disabled: true, negate: false } }, @@ -103,35 +109,39 @@ describe('Filter Bar Directive', function() { { meta: { disabled: true, negate: true } }, { meta: { disabled: true, negate: true } }, ] as Filter[]; - expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(true); + + expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(true); }); - it('should return false if all filters remove were not disabled', function() { + test('should return false if all filters remove were not disabled', () => { const filters = [ { meta: { disabled: false } }, { meta: { disabled: false } }, { meta: { disabled: true } }, ] as Filter[]; const newFilters = [{ meta: { disabled: false } }] as Filter[]; - expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(false); + + expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(false); }); - it('should return false when all removed filters are not disabled', function() { + test('should return false when all removed filters are not disabled', () => { const filters = [ { meta: { disabled: true } }, { meta: { disabled: false } }, { meta: { disabled: true } }, ] as Filter[]; const newFilters = [] as Filter[]; - expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(false); + + expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(false); }); - it('should not throw with null filters', function() { + test('should not throw with null filters', () => { const filters = [null, { meta: { disabled: true } }] as Filter[]; const newFilters = [] as Filter[]; + expect(function() { onlyDisabledFiltersChanged(newFilters, filters); - }).to.not.throwError(); + }).not.toThrowError(); }); }); }); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/only_disabled.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/only_disabled.ts index 24f6b6db5352b..9c0b5f43acb3e 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/only_disabled.ts +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/only_disabled.ts @@ -17,20 +17,20 @@ * under the License. */ -import _ from 'lodash'; import { Filter } from '@kbn/es-query'; +import { filter, isEqual } from 'lodash'; + +const isEnabled = (f: Filter) => f && f.meta && !f.meta.disabled; -const isEnabled = function(filter: Filter) { - return filter && filter.meta && !filter.meta.disabled; -}; /** * Checks to see if only disabled filters have been changed + * * @returns {bool} Only disabled filters */ -export function onlyDisabledFiltersChanged(newFilters?: Filter[], oldFilters?: Filter[]) { +export const onlyDisabledFiltersChanged = (newFilters?: Filter[], oldFilters?: Filter[]) => { // If it's the same - compare only enabled filters - const newEnabledFilters = _.filter(newFilters || [], isEnabled); - const oldEnabledFilters = _.filter(oldFilters || [], isEnabled); + const newEnabledFilters = filter(newFilters || [], isEnabled); + const oldEnabledFilters = filter(oldFilters || [], isEnabled); - return _.isEqual(oldEnabledFilters, newEnabledFilters); -} + return isEqual(oldEnabledFilters, newEnabledFilters); +}; diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/uniq_filters.test.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/uniq_filters.test.ts new file mode 100644 index 0000000000000..465b5810c91fd --- /dev/null +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/uniq_filters.test.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 { Filter, buildQueryFilter, FilterStateStore } from '@kbn/es-query'; +import { uniqFilters } from './uniq_filters'; + +describe('Filter Bar Directive', () => { + describe('niqFilter', () => { + it('should filter out dups', () => { + const before: Filter[] = [ + buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index'), + buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index'), + ]; + const results = uniqFilters(before); + + expect(results).toHaveLength(1); + }); + + it('should filter out duplicates, ignoring meta attributes', () => { + const before: Filter[] = [ + buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index1'), + buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index2'), + ]; + const results = uniqFilters(before); + + expect(results).toHaveLength(1); + }); + + it('should filter out duplicates, ignoring $state attributes', () => { + const before: Filter[] = [ + { + $state: { store: FilterStateStore.APP_STATE }, + ...buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index'), + }, + { + $state: { store: FilterStateStore.GLOBAL_STATE }, + ...buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index'), + }, + ]; + const results = uniqFilters(before); + + expect(results).toHaveLength(1); + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/uniq_filters.js b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/uniq_filters.ts similarity index 80% rename from src/legacy/core_plugins/data/public/filter/filter_manager/lib/uniq_filters.js rename to src/legacy/core_plugins/data/public/filter/filter_manager/lib/uniq_filters.ts index f8e6d350f8dd9..aefdea40c5496 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/lib/uniq_filters.js +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/lib/uniq_filters.ts @@ -16,19 +16,22 @@ * specific language governing permissions and limitations * under the License. */ - -import _ from 'lodash'; +import { Filter } from '@kbn/es-query'; +import { each, union } from 'lodash'; import { dedupFilters } from './dedup_filters'; /** * Remove duplicate filters from an array of filters + * * @param {array} filters The filters to remove duplicates from * @returns {object} The original filters array with duplicates removed */ -export function uniqFilters(filters, comparatorOptions) { - let results = []; - _.each(filters, function (filter) { - results = _.union(results, dedupFilters(results, [filter], comparatorOptions)); +export function uniqFilters(filters: Filter[]) { + let results: Filter[] = []; + + each(filters, (filter: Filter) => { + results = union(results, dedupFilters(results, [filter])); }); + return results; } diff --git a/src/legacy/core_plugins/data/public/timefilter/timefilter.ts b/src/legacy/core_plugins/data/public/timefilter/timefilter.ts index b07060018f9d7..c6dd3a45adbd7 100644 --- a/src/legacy/core_plugins/data/public/timefilter/timefilter.ts +++ b/src/legacy/core_plugins/data/public/timefilter/timefilter.ts @@ -32,12 +32,15 @@ export interface TimefilterConfig { refreshIntervalDefaults: RefreshInterval; } +export type InputTimeRangeMode = 'absolute' | 'relative'; + // Timefilter accepts moment input but always returns string output export type InputTimeRange = | TimeRange | { from: Moment; to: Moment; + mode?: InputTimeRangeMode; }; export class Timefilter {