mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
* Update filter meta to not include formatter functions
* Fix failing tests
* Update tests
* Fix functional test & phrase mapper
* Update scripted field handling
* Look up field from getFilterField
* Make meta optional
* Fix failing tests
* Fix dataTestSubj values
* Fix scripted range filter display
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
(cherry picked from commit 2f1f9e0b5d
)
Co-authored-by: Lukas Olson <lukas@elastic.co>
This commit is contained in:
parent
efb77454a4
commit
6318cfd3c5
20 changed files with 301 additions and 136 deletions
|
@ -8,8 +8,8 @@
|
|||
|
||||
import { getExistsFilterField, isExistsFilter } from './exists_filter';
|
||||
import { getPhrasesFilterField, isPhrasesFilter } from './phrases_filter';
|
||||
import { getPhraseFilterField, isPhraseFilter } from './phrase_filter';
|
||||
import { getRangeFilterField, isRangeFilter } from './range_filter';
|
||||
import { getPhraseFilterField, isPhraseFilter, isScriptedPhraseFilter } from './phrase_filter';
|
||||
import { getRangeFilterField, isRangeFilter, isScriptedRangeFilter } from './range_filter';
|
||||
import type { Filter } from './types';
|
||||
|
||||
/** @internal */
|
||||
|
@ -17,13 +17,13 @@ export const getFilterField = (filter: Filter) => {
|
|||
if (isExistsFilter(filter)) {
|
||||
return getExistsFilterField(filter);
|
||||
}
|
||||
if (isPhraseFilter(filter)) {
|
||||
if (isPhraseFilter(filter) || isScriptedPhraseFilter(filter)) {
|
||||
return getPhraseFilterField(filter);
|
||||
}
|
||||
if (isPhrasesFilter(filter)) {
|
||||
return getPhrasesFilterField(filter);
|
||||
}
|
||||
if (isRangeFilter(filter)) {
|
||||
if (isRangeFilter(filter) || isScriptedRangeFilter(filter)) {
|
||||
return getRangeFilterField(filter);
|
||||
}
|
||||
|
||||
|
|
|
@ -186,4 +186,14 @@ describe('isScriptedPhraseFilter', () => {
|
|||
expect(isScriptedPhraseFilter(filter)).toBe(true);
|
||||
expect(isPhraseFilter(unknownFilter)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if the filter is a range filter', () => {
|
||||
const filter: Filter = set({ meta: {} }, 'query.script.script.params', {
|
||||
gt: 0,
|
||||
lt: 100,
|
||||
value: 100,
|
||||
}) as Filter;
|
||||
|
||||
expect(isScriptedPhraseFilter(filter)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ import { get, has, isPlainObject } from 'lodash';
|
|||
import type { Filter, FilterMeta } from './types';
|
||||
import type { DataViewFieldBase, DataViewBase } from '../../es_query';
|
||||
import { getConvertedValueForField } from './get_converted_value_for_field';
|
||||
import { hasRangeKeys } from './range_filter';
|
||||
|
||||
export type PhraseFilterValue = string | number | boolean;
|
||||
|
||||
|
@ -60,10 +61,12 @@ export const isPhraseFilter = (filter: Filter): filter is PhraseFilter => {
|
|||
* @public
|
||||
*/
|
||||
export const isScriptedPhraseFilter = (filter: Filter): filter is ScriptedPhraseFilter =>
|
||||
has(filter, 'query.script.script.params.value');
|
||||
has(filter, 'query.script.script.params.value') &&
|
||||
!hasRangeKeys(filter.query?.script?.script?.params);
|
||||
|
||||
/** @internal */
|
||||
export const getPhraseFilterField = (filter: PhraseFilter) => {
|
||||
export const getPhraseFilterField = (filter: PhraseFilter | ScriptedPhraseFilter) => {
|
||||
if (filter.meta?.field) return filter.meta.field;
|
||||
const queryConfig = filter.query.match_phrase ?? filter.query.match ?? {};
|
||||
return Object.keys(queryConfig)[0];
|
||||
};
|
||||
|
|
|
@ -47,7 +47,7 @@ export interface RangeFilterParams {
|
|||
format?: string;
|
||||
}
|
||||
|
||||
const hasRangeKeys = (params: RangeFilterParams) =>
|
||||
export const hasRangeKeys = (params: RangeFilterParams) =>
|
||||
Boolean(
|
||||
keys(params).find((key: string) => ['gte', 'gt', 'lte', 'lt', 'from', 'to'].includes(key))
|
||||
);
|
||||
|
@ -108,8 +108,8 @@ export const isScriptedRangeFilter = (filter: Filter): filter is ScriptedRangeFi
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const getRangeFilterField = (filter: RangeFilter) => {
|
||||
return filter.query.range && Object.keys(filter.query.range)[0];
|
||||
export const getRangeFilterField = (filter: RangeFilter | ScriptedRangeFilter) => {
|
||||
return filter.meta?.field ?? (filter.query.range && Object.keys(filter.query.range)[0]);
|
||||
};
|
||||
|
||||
const formatValue = (params: any[]) =>
|
||||
|
|
|
@ -24,5 +24,9 @@ export const phraseFilter: PhraseFilter = {
|
|||
$state: {
|
||||
store: FilterStateStore.APP_STATE,
|
||||
},
|
||||
query: {},
|
||||
query: {
|
||||
match_phrase: {
|
||||
'machine.os': 'ios',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -25,5 +25,5 @@ export const rangeFilter: RangeFilter = {
|
|||
$state: {
|
||||
store: FilterStateStore.APP_STATE,
|
||||
},
|
||||
query: { range: {} },
|
||||
query: { range: { bytes: { gt: 0, lt: 10 } } },
|
||||
};
|
||||
|
|
|
@ -33,7 +33,6 @@ export type {
|
|||
SavedQuery,
|
||||
SavedQueryAttributes,
|
||||
SavedQueryTimeFilter,
|
||||
FilterValueFormatter,
|
||||
KbnFieldTypeOptions,
|
||||
Query,
|
||||
} from './types';
|
||||
|
|
|
@ -20,9 +20,3 @@ export * from './kbn_field_types/types';
|
|||
* not possible.
|
||||
*/
|
||||
export type GetConfigFn = <T = any>(key: string, defaultOverride?: T) => T;
|
||||
|
||||
type FilterFormatterFunction = (value: any) => string;
|
||||
export interface FilterValueFormatter {
|
||||
convert: FilterFormatterFunction;
|
||||
getConverterFor: (type: string) => FilterFormatterFunction;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,12 @@
|
|||
*/
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { FilterStateStore, PhraseFilter } from '@kbn/es-query';
|
||||
import { stubIndexPattern, phraseFilter } from '../../../../common/stubs';
|
||||
import {
|
||||
stubIndexPattern,
|
||||
phraseFilter,
|
||||
phrasesFilter,
|
||||
rangeFilter,
|
||||
} from '../../../../common/stubs';
|
||||
import { getDisplayValueFromFilter, getFieldDisplayValueFromFilter } from './get_display_value';
|
||||
import { FieldFormat } from '@kbn/field-formats-plugin/common';
|
||||
|
||||
|
@ -17,38 +22,57 @@ describe('getDisplayValueFromFilter', () => {
|
|||
});
|
||||
|
||||
it('returns the value if string', () => {
|
||||
phraseFilter.meta.value = 'abc';
|
||||
const displayValue = getDisplayValueFromFilter(phraseFilter, [stubIndexPattern]);
|
||||
const filter = { ...phraseFilter, meta: { ...phraseFilter.meta, value: 'abc' } };
|
||||
const displayValue = getDisplayValueFromFilter(filter, [stubIndexPattern]);
|
||||
expect(displayValue).toBe('abc');
|
||||
});
|
||||
|
||||
it('returns the value if undefined', () => {
|
||||
phraseFilter.meta.value = undefined;
|
||||
const displayValue = getDisplayValueFromFilter(phraseFilter, [stubIndexPattern]);
|
||||
const filter = {
|
||||
...phraseFilter,
|
||||
meta: { ...phraseFilter.meta, value: undefined, params: { query: undefined } },
|
||||
};
|
||||
const displayValue = getDisplayValueFromFilter(filter, [stubIndexPattern]);
|
||||
expect(displayValue).toBe('');
|
||||
});
|
||||
|
||||
it('calls the value function if provided', () => {
|
||||
// The type of value currently doesn't match how it's used. Refactor needed.
|
||||
phraseFilter.meta.value = jest.fn((x) => {
|
||||
return 'abc';
|
||||
}) as any;
|
||||
it('phrase filters without formatter', () => {
|
||||
jest.spyOn(stubIndexPattern, 'getFormatterForField').mockImplementation(() => undefined!);
|
||||
const displayValue = getDisplayValueFromFilter(phraseFilter, [stubIndexPattern]);
|
||||
expect(displayValue).toBe('abc');
|
||||
expect(phraseFilter.meta.value).toHaveBeenCalledWith(undefined);
|
||||
expect(displayValue).toBe('ios');
|
||||
});
|
||||
|
||||
it('calls the value function if provided, with formatter', () => {
|
||||
it('phrase filters with formatter', () => {
|
||||
const mockFormatter = new (FieldFormat.from((value: string) => 'banana' + value))();
|
||||
jest.spyOn(stubIndexPattern, 'getFormatterForField').mockImplementation(() => mockFormatter);
|
||||
phraseFilter.meta.value = jest.fn((x) => {
|
||||
return x.convert('abc');
|
||||
}) as any;
|
||||
const displayValue = getDisplayValueFromFilter(phraseFilter, [stubIndexPattern]);
|
||||
expect(stubIndexPattern.getFormatterForField).toHaveBeenCalledTimes(1);
|
||||
expect(phraseFilter.meta.value).toHaveBeenCalledWith(mockFormatter);
|
||||
expect(displayValue).toBe('bananaabc');
|
||||
expect(displayValue).toBe('bananaios');
|
||||
});
|
||||
|
||||
it('phrases filters without formatter', () => {
|
||||
jest.spyOn(stubIndexPattern, 'getFormatterForField').mockImplementation(() => undefined!);
|
||||
const displayValue = getDisplayValueFromFilter(phrasesFilter, [stubIndexPattern]);
|
||||
expect(displayValue).toBe('win xp, osx');
|
||||
});
|
||||
|
||||
it('phrases filters with formatter', () => {
|
||||
const mockFormatter = new (FieldFormat.from((value: string) => 'banana' + value))();
|
||||
jest.spyOn(stubIndexPattern, 'getFormatterForField').mockImplementation(() => mockFormatter);
|
||||
const displayValue = getDisplayValueFromFilter(phrasesFilter, [stubIndexPattern]);
|
||||
expect(displayValue).toBe('bananawin xp, bananaosx');
|
||||
});
|
||||
|
||||
it('range filters without formatter', () => {
|
||||
jest.spyOn(stubIndexPattern, 'getFormatterForField').mockImplementation(() => undefined!);
|
||||
const displayValue = getDisplayValueFromFilter(rangeFilter, [stubIndexPattern]);
|
||||
expect(displayValue).toBe('0 to 10');
|
||||
});
|
||||
|
||||
it('range filters with formatter', () => {
|
||||
const mockFormatter = new (FieldFormat.from((value: string) => 'banana' + value))();
|
||||
jest.spyOn(stubIndexPattern, 'getFormatterForField').mockImplementation(() => mockFormatter);
|
||||
const displayValue = getDisplayValueFromFilter(rangeFilter, [stubIndexPattern]);
|
||||
expect(displayValue).toBe('banana0 to banana10');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -8,7 +8,18 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { DataView, DataViewField } from '@kbn/data-views-plugin/public';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import {
|
||||
Filter,
|
||||
isPhraseFilter,
|
||||
isPhrasesFilter,
|
||||
isRangeFilter,
|
||||
isScriptedPhraseFilter,
|
||||
isScriptedRangeFilter,
|
||||
getFilterField,
|
||||
} from '@kbn/es-query';
|
||||
import { getPhraseDisplayValue } from './mappers/map_phrase';
|
||||
import { getPhrasesDisplayValue } from './mappers/map_phrases';
|
||||
import { getRangeDisplayValue } from './mappers/map_range';
|
||||
import { getIndexPatternFromFilter } from './get_index_pattern_from_filter';
|
||||
|
||||
function getValueFormatter(indexPattern?: DataView, key?: string) {
|
||||
|
@ -29,22 +40,26 @@ function getValueFormatter(indexPattern?: DataView, key?: string) {
|
|||
}
|
||||
|
||||
export function getFieldDisplayValueFromFilter(filter: Filter, indexPatterns: DataView[]): string {
|
||||
const { key } = filter.meta;
|
||||
const indexPattern = getIndexPatternFromFilter(filter, indexPatterns);
|
||||
if (!indexPattern) return '';
|
||||
const field = indexPattern.fields.find((f: DataViewField) => f.name === key);
|
||||
|
||||
const fieldName = getFilterField(filter);
|
||||
if (!fieldName) return '';
|
||||
|
||||
const field = indexPattern.fields.find((f: DataViewField) => f.name === fieldName);
|
||||
return field?.customLabel ?? '';
|
||||
}
|
||||
|
||||
export function getDisplayValueFromFilter(filter: Filter, indexPatterns: DataView[]): string {
|
||||
const { key, value } = filter.meta;
|
||||
if (typeof value === 'function') {
|
||||
const indexPattern = getIndexPatternFromFilter(filter, indexPatterns);
|
||||
const valueFormatter = getValueFormatter(indexPattern, key);
|
||||
// TODO: distinguish between FilterMeta which is serializable to mapped FilterMeta
|
||||
// Where value can be a function.
|
||||
return (value as any)(valueFormatter);
|
||||
} else {
|
||||
return value || '';
|
||||
}
|
||||
const indexPattern = getIndexPatternFromFilter(filter, indexPatterns);
|
||||
const fieldName = getFilterField(filter);
|
||||
const valueFormatter = getValueFormatter(indexPattern, fieldName);
|
||||
|
||||
if (isPhraseFilter(filter) || isScriptedPhraseFilter(filter)) {
|
||||
return getPhraseDisplayValue(filter, valueFormatter);
|
||||
} else if (isPhrasesFilter(filter)) {
|
||||
return getPhrasesDisplayValue(filter, valueFormatter);
|
||||
} else if (isRangeFilter(filter) || isScriptedRangeFilter(filter)) {
|
||||
return getRangeDisplayValue(filter, valueFormatter);
|
||||
} else return filter.meta.value ?? '';
|
||||
}
|
||||
|
|
|
@ -13,12 +13,6 @@ describe('filter manager utilities', () => {
|
|||
describe('mapAndFlattenFilters()', () => {
|
||||
let filters: unknown;
|
||||
|
||||
function getDisplayName(filter: Filter) {
|
||||
return typeof filter.meta.value === 'function'
|
||||
? (filter.meta.value as any)()
|
||||
: filter.meta.value;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
filters = [
|
||||
null,
|
||||
|
@ -51,11 +45,8 @@ describe('filter manager utilities', () => {
|
|||
expect(results[2].meta).toHaveProperty('key', 'query');
|
||||
expect(results[2].meta).toHaveProperty('value', 'foo:bar');
|
||||
expect(results[3].meta).toHaveProperty('key', 'bytes');
|
||||
expect(results[3].meta).toHaveProperty('value');
|
||||
expect(getDisplayName(results[3])).toBe('1024 to 2048');
|
||||
expect(results[3].meta).toHaveProperty('value', { gt: 1024, lt: 2048 });
|
||||
expect(results[4].meta).toHaveProperty('key', '_type');
|
||||
expect(results[4].meta).toHaveProperty('value');
|
||||
expect(getDisplayName(results[4])).toBe('apache');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,27 +7,22 @@
|
|||
*/
|
||||
|
||||
import { mapFilter } from './map_filter';
|
||||
import type { Filter } from '@kbn/es-query';
|
||||
import type { Filter, PhraseFilter } from '@kbn/es-query';
|
||||
import { getDisplayValueFromFilter } from '../../..';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
function getDisplayName(filter: Filter) {
|
||||
return typeof filter.meta.value === 'function'
|
||||
? (filter.meta.value as any)()
|
||||
: filter.meta.value;
|
||||
}
|
||||
|
||||
describe('mapFilter()', () => {
|
||||
test('should map query filters', async () => {
|
||||
const before = {
|
||||
meta: { index: 'logstash-*' },
|
||||
query: { match: { _type: { query: 'apache', type: 'phrase' } } },
|
||||
};
|
||||
const after = mapFilter(before as Filter);
|
||||
const after = mapFilter(before as Filter) as PhraseFilter;
|
||||
|
||||
expect(after).toHaveProperty('meta');
|
||||
expect(after.meta).toHaveProperty('key', '_type');
|
||||
expect(after.meta).toHaveProperty('value');
|
||||
expect(getDisplayName(after)).toBe('apache');
|
||||
expect(getDisplayValueFromFilter(after, [])).toBe('apache');
|
||||
expect(after.meta).toHaveProperty('disabled', false);
|
||||
expect(after.meta).toHaveProperty('negate', false);
|
||||
});
|
||||
|
@ -42,7 +37,7 @@ describe('filter manager utilities', () => {
|
|||
expect(after).toHaveProperty('meta');
|
||||
expect(after.meta).toHaveProperty('key', '@timestamp');
|
||||
expect(after.meta).toHaveProperty('value');
|
||||
expect(getDisplayName(after)).toBe('exists');
|
||||
expect(getDisplayValueFromFilter(after, [])).toBe('exists');
|
||||
expect(after.meta).toHaveProperty('disabled', false);
|
||||
expect(after.meta).toHaveProperty('negate', false);
|
||||
});
|
||||
|
@ -54,7 +49,7 @@ describe('filter manager utilities', () => {
|
|||
expect(after).toHaveProperty('meta');
|
||||
expect(after.meta).toHaveProperty('key', 'query');
|
||||
expect(after.meta).toHaveProperty('value');
|
||||
expect(getDisplayName(after)).toBe('{"test":{}}');
|
||||
expect(getDisplayValueFromFilter(after, [])).toBe('{"test":{}}');
|
||||
expect(after.meta).toHaveProperty('disabled', false);
|
||||
expect(after.meta).toHaveProperty('negate', false);
|
||||
});
|
||||
|
|
|
@ -6,12 +6,13 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { mapPhrase } from './map_phrase';
|
||||
import { getPhraseDisplayValue, mapPhrase } from './map_phrase';
|
||||
import type { PhraseFilter, Filter } from '@kbn/es-query';
|
||||
import { FieldFormat } from '@kbn/field-formats-plugin/common';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('mapPhrase()', () => {
|
||||
test('should return the key and value for matching filters', async () => {
|
||||
test('should return the key for matching filters', async () => {
|
||||
const filter = {
|
||||
meta: { index: 'logstash-*' },
|
||||
query: { match: { _type: { query: 'apache', type: 'phrase' } } },
|
||||
|
@ -19,13 +20,7 @@ describe('filter manager utilities', () => {
|
|||
|
||||
const result = mapPhrase(filter);
|
||||
|
||||
expect(result).toHaveProperty('value');
|
||||
expect(result).toHaveProperty('key', '_type');
|
||||
|
||||
if (result.value) {
|
||||
const displayName = result.value();
|
||||
expect(displayName).toBe('apache');
|
||||
}
|
||||
});
|
||||
|
||||
test('should return undefined for none matching', async (done) => {
|
||||
|
@ -42,4 +37,31 @@ describe('filter manager utilities', () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPhraseDisplayValue()', () => {
|
||||
test('without formatter with value', () => {
|
||||
const filter = { meta: { value: 'hello' } } as PhraseFilter;
|
||||
const result = getPhraseDisplayValue(filter);
|
||||
expect(result).toMatchInlineSnapshot(`"hello"`);
|
||||
});
|
||||
|
||||
test('without formatter empty value', () => {
|
||||
const filter = { meta: { value: '' } } as PhraseFilter;
|
||||
const result = getPhraseDisplayValue(filter);
|
||||
expect(result).toMatchInlineSnapshot(`""`);
|
||||
});
|
||||
|
||||
test('without formatter with undefined value', () => {
|
||||
const filter = { meta: { params: {} } } as PhraseFilter;
|
||||
const result = getPhraseDisplayValue(filter);
|
||||
expect(result).toMatchInlineSnapshot(`""`);
|
||||
});
|
||||
|
||||
test('with formatter', () => {
|
||||
const filter = { meta: { value: 'hello' } } as PhraseFilter;
|
||||
const formatter = { convert: (val) => `formatted ${val}` } as FieldFormat;
|
||||
const result = getPhraseDisplayValue(filter, formatter);
|
||||
expect(result).toMatchInlineSnapshot(`"formatted hello"`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,27 +6,27 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { Filter, PhraseFilter, ScriptedPhraseFilter } from '@kbn/es-query';
|
||||
import { get } from 'lodash';
|
||||
import {
|
||||
PhraseFilter,
|
||||
getPhraseFilterValue,
|
||||
getPhraseFilterField,
|
||||
FILTERS,
|
||||
isScriptedPhraseFilter,
|
||||
Filter,
|
||||
isPhraseFilter,
|
||||
} from '@kbn/es-query';
|
||||
|
||||
import { FilterValueFormatter } from '../../../../../common';
|
||||
import { FieldFormat } from '@kbn/field-formats-plugin/common';
|
||||
|
||||
const getScriptedPhraseValue = (filter: PhraseFilter) =>
|
||||
get(filter, ['query', 'script', 'script', 'params', 'value']);
|
||||
|
||||
const getFormattedValueFn = (value: any) => {
|
||||
return (formatter?: FilterValueFormatter) => {
|
||||
return formatter ? formatter.convert(value) : value;
|
||||
};
|
||||
};
|
||||
export function getPhraseDisplayValue(
|
||||
filter: PhraseFilter | ScriptedPhraseFilter,
|
||||
formatter?: FieldFormat
|
||||
) {
|
||||
const value = filter.meta.value ?? filter.meta.params.query;
|
||||
return formatter?.convert(value) ?? value ?? '';
|
||||
}
|
||||
|
||||
const getParams = (filter: PhraseFilter) => {
|
||||
const scriptedPhraseValue = getScriptedPhraseValue(filter);
|
||||
|
@ -39,7 +39,6 @@ const getParams = (filter: PhraseFilter) => {
|
|||
key,
|
||||
params,
|
||||
type: FILTERS.PHRASE,
|
||||
value: getFormattedValueFn(query),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { PhrasesFilter, Filter } from '@kbn/es-query';
|
||||
import { FILTERS } from '@kbn/es-query';
|
||||
import { getPhrasesDisplayValue, mapPhrases } from './map_phrases';
|
||||
import { FieldFormat } from '@kbn/field-formats-plugin/common';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('mapPhrases()', () => {
|
||||
test('should return the key and value for matching filters', async () => {
|
||||
const filter = {
|
||||
meta: {
|
||||
type: FILTERS.PHRASES,
|
||||
index: 'logstash-*',
|
||||
key: '_type',
|
||||
params: ['hello', 1, 'world'],
|
||||
},
|
||||
} as PhrasesFilter;
|
||||
|
||||
const result = mapPhrases(filter);
|
||||
|
||||
expect(result).toHaveProperty('key', '_type');
|
||||
expect(result).toHaveProperty('value', ['hello', 1, 'world']);
|
||||
});
|
||||
|
||||
test('should return undefined for none matching', async (done) => {
|
||||
const filter = {
|
||||
meta: { index: 'logstash-*' },
|
||||
query: { query_string: { query: 'foo:bar' } },
|
||||
} as Filter;
|
||||
|
||||
try {
|
||||
mapPhrases(filter);
|
||||
} catch (e) {
|
||||
expect(e).toBe(filter);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPhrasesDisplayValue()', () => {
|
||||
test('without formatter', () => {
|
||||
const filter = { meta: { params: ['hello', 1, 'world'] } } as PhrasesFilter;
|
||||
const result = getPhrasesDisplayValue(filter);
|
||||
expect(result).toMatchInlineSnapshot(`"hello, 1, world"`);
|
||||
});
|
||||
|
||||
test('with formatter', () => {
|
||||
const filter = { meta: { params: ['hello', 1, 'world'] } } as PhrasesFilter;
|
||||
const formatter = { convert: (val) => `formatted ${val}` } as FieldFormat;
|
||||
const result = getPhrasesDisplayValue(filter, formatter);
|
||||
expect(result).toMatchInlineSnapshot(`"formatted hello, formatted 1, formatted world"`);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -6,19 +6,16 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Filter, isPhrasesFilter } from '@kbn/es-query';
|
||||
import { Filter, PhrasesFilter, isPhrasesFilter } from '@kbn/es-query';
|
||||
import { FieldFormat } from '@kbn/field-formats-plugin/common';
|
||||
|
||||
import { FilterValueFormatter } from '../../../../../common';
|
||||
|
||||
const getFormattedValueFn = (params: any) => {
|
||||
return (formatter?: FilterValueFormatter) => {
|
||||
return params
|
||||
.map((v: any) => {
|
||||
return formatter ? formatter.convert(v) : v;
|
||||
})
|
||||
.join(', ');
|
||||
};
|
||||
};
|
||||
export function getPhrasesDisplayValue(filter: PhrasesFilter, formatter?: FieldFormat) {
|
||||
return filter.meta.params
|
||||
.map((v: string) => {
|
||||
return formatter?.convert(v) ?? v;
|
||||
})
|
||||
.join(', ');
|
||||
}
|
||||
|
||||
export const mapPhrases = (filter: Filter) => {
|
||||
if (!isPhrasesFilter(filter)) {
|
||||
|
@ -30,7 +27,7 @@ export const mapPhrases = (filter: Filter) => {
|
|||
return {
|
||||
type,
|
||||
key,
|
||||
value: getFormattedValueFn(params),
|
||||
value: params,
|
||||
params,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { mapRange } from './map_range';
|
||||
import { getRangeDisplayValue, mapRange } from './map_range';
|
||||
import { FilterMeta, RangeFilter, Filter } from '@kbn/es-query';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
|
@ -19,11 +19,7 @@ describe('filter manager utilities', () => {
|
|||
const result = mapRange(filter);
|
||||
|
||||
expect(result).toHaveProperty('key', 'bytes');
|
||||
expect(result).toHaveProperty('value');
|
||||
if (result.value) {
|
||||
const displayName = result.value();
|
||||
expect(displayName).toBe('1024 to 2048');
|
||||
}
|
||||
expect(result).toHaveProperty('value', { gt: 1024, lt: 2048 });
|
||||
});
|
||||
|
||||
test('should return undefined for none matching', async (done) => {
|
||||
|
@ -41,4 +37,62 @@ describe('filter manager utilities', () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRangeDisplayValue()', () => {
|
||||
test('gt & lt', () => {
|
||||
const params = { gt: 10, lt: 100 };
|
||||
const filter = { meta: { params } } as RangeFilter;
|
||||
const result = getRangeDisplayValue(filter);
|
||||
expect(result).toMatchInlineSnapshot(`"10 to 100"`);
|
||||
});
|
||||
|
||||
test('gt & lte', () => {
|
||||
const params = { gt: 20, lte: 200 };
|
||||
const filter = { meta: { params } } as RangeFilter;
|
||||
const result = getRangeDisplayValue(filter);
|
||||
expect(result).toMatchInlineSnapshot(`"20 to 200"`);
|
||||
});
|
||||
|
||||
test('gte & lt', () => {
|
||||
const params = { gte: 'low', lt: 'high' };
|
||||
const filter = { meta: { params } } as RangeFilter;
|
||||
const result = getRangeDisplayValue(filter);
|
||||
expect(result).toMatchInlineSnapshot(`"low to high"`);
|
||||
});
|
||||
|
||||
test('gte & lte', () => {
|
||||
const params = { gte: 40, lte: 400 };
|
||||
const filter = { meta: { params } } as RangeFilter;
|
||||
const result = getRangeDisplayValue(filter);
|
||||
expect(result).toMatchInlineSnapshot(`"40 to 400"`);
|
||||
});
|
||||
|
||||
test('gt', () => {
|
||||
const params = { gt: 50 };
|
||||
const filter = { meta: { params } } as RangeFilter;
|
||||
const result = getRangeDisplayValue(filter);
|
||||
expect(result).toMatchInlineSnapshot(`"50 to Infinity"`);
|
||||
});
|
||||
|
||||
test('gte', () => {
|
||||
const params = { gte: 60 };
|
||||
const filter = { meta: { params } } as RangeFilter;
|
||||
const result = getRangeDisplayValue(filter);
|
||||
expect(result).toMatchInlineSnapshot(`"60 to Infinity"`);
|
||||
});
|
||||
|
||||
test('lt', () => {
|
||||
const params = { lt: 70 };
|
||||
const filter = { meta: { params } } as RangeFilter;
|
||||
const result = getRangeDisplayValue(filter);
|
||||
expect(result).toMatchInlineSnapshot(`"-Infinity to 70"`);
|
||||
});
|
||||
|
||||
test('lte', () => {
|
||||
const params = { lte: 80 };
|
||||
const filter = { meta: { params } } as RangeFilter;
|
||||
const result = getRangeDisplayValue(filter);
|
||||
expect(result).toMatchInlineSnapshot(`"-Infinity to 80"`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,21 +6,27 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { get, hasIn } from 'lodash';
|
||||
import { RangeFilter, isScriptedRangeFilter, isRangeFilter, Filter, FILTERS } from '@kbn/es-query';
|
||||
import { get } from 'lodash';
|
||||
import {
|
||||
ScriptedRangeFilter,
|
||||
RangeFilter,
|
||||
isScriptedRangeFilter,
|
||||
isRangeFilter,
|
||||
Filter,
|
||||
FILTERS,
|
||||
} from '@kbn/es-query';
|
||||
import { FieldFormat } from '@kbn/field-formats-plugin/common';
|
||||
|
||||
import { FilterValueFormatter } from '../../../../../common';
|
||||
|
||||
const getFormattedValueFn = (left: any, right: any) => {
|
||||
return (formatter?: FilterValueFormatter) => {
|
||||
let displayValue = `${left} to ${right}`;
|
||||
if (formatter) {
|
||||
const convert = formatter.getConverterFor('text');
|
||||
displayValue = `${convert(left)} to ${convert(right)}`;
|
||||
}
|
||||
return displayValue;
|
||||
};
|
||||
};
|
||||
export function getRangeDisplayValue(
|
||||
{ meta: { params } }: RangeFilter | ScriptedRangeFilter,
|
||||
formatter?: FieldFormat
|
||||
) {
|
||||
const left = params.gte ?? params.gt ?? -Infinity;
|
||||
const right = params.lte ?? params.lt ?? Infinity;
|
||||
if (!formatter) return `${left} to ${right}`;
|
||||
const convert = formatter.getConverterFor('text');
|
||||
return `${convert(left)} to ${convert(right)}`;
|
||||
}
|
||||
|
||||
const getFirstRangeKey = (filter: RangeFilter) =>
|
||||
filter.query.range && Object.keys(filter.query.range)[0];
|
||||
|
@ -33,15 +39,7 @@ function getParams(filter: RangeFilter) {
|
|||
? get(filter.query, 'script.script.params')
|
||||
: getRangeByKey(filter, key);
|
||||
|
||||
let left = hasIn(params, 'gte') ? params.gte : params.gt;
|
||||
if (left == null) left = -Infinity;
|
||||
|
||||
let right = hasIn(params, 'lte') ? params.lte : params.lt;
|
||||
if (right == null) right = Infinity;
|
||||
|
||||
const value = getFormattedValueFn(left, right);
|
||||
|
||||
return { type: FILTERS.RANGE, key, value, params };
|
||||
return { type: FILTERS.RANGE, key, value: params, params };
|
||||
}
|
||||
|
||||
export const isMapRangeFilter = (filter: any): filter is RangeFilter =>
|
||||
|
|
|
@ -133,7 +133,7 @@ describe('Test Discover Context State', () => {
|
|||
"query": "jpg",
|
||||
},
|
||||
"type": "phrase",
|
||||
"value": [Function],
|
||||
"value": undefined,
|
||||
},
|
||||
"query": Object {
|
||||
"match_phrase": Object {
|
||||
|
@ -157,7 +157,7 @@ describe('Test Discover Context State', () => {
|
|||
"query": "png",
|
||||
},
|
||||
"type": "phrase",
|
||||
"value": [Function],
|
||||
"value": undefined,
|
||||
},
|
||||
"query": Object {
|
||||
"match_phrase": Object {
|
||||
|
|
|
@ -158,9 +158,8 @@ export function FilterItem(props: FilterItemProps) {
|
|||
|
||||
function getDataTestSubj(labelConfig: LabelOptions) {
|
||||
const dataTestSubjKey = filter.meta.key ? `filter-key-${filter.meta.key}` : '';
|
||||
const dataTestSubjValue = filter.meta.value
|
||||
? `filter-value-${isValidLabel(labelConfig) ? labelConfig.title : labelConfig.status}`
|
||||
: '';
|
||||
const valueLabel = isValidLabel(labelConfig) ? labelConfig.title : labelConfig.status;
|
||||
const dataTestSubjValue = valueLabel ? `filter-value-${valueLabel}` : '';
|
||||
const dataTestSubjNegated = filter.meta.negate ? 'filter-negated' : '';
|
||||
const dataTestSubjDisabled = `filter-${isDisabled(labelConfig) ? 'disabled' : 'enabled'}`;
|
||||
const dataTestSubjPinned = `filter-${isFilterPinned(filter) ? 'pinned' : 'unpinned'}`;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue