From d5064e2de1dcb4a6a40fc378080578a69f0e6617 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Wed, 19 Jun 2019 13:27:42 +0200 Subject: [PATCH 01/20] typescript indexPatterns service --- .../filter/filter_bar/filter_editor/index.tsx | 2 +- .../lib/filter_editor_utils.test.ts | 65 ++- src/legacy/core_plugins/data/public/index.ts | 2 +- .../data/public/index_patterns/index.ts | 1 - .../index_patterns/index_patterns_service.ts | 5 +- .../query_bar/components/query_bar.test.tsx | 2 +- .../components/query_bar_input.test.tsx | 2 +- .../query_bar/components/query_bar_input.tsx | 2 +- .../kibana/public/context/api/context.ts | 5 +- .../public/dashboard/dashboard_state.test.ts | 1 + .../kibana/public/home/sample_data_client.js | 2 +- .../agg_types/filter/agg_type_filters.test.ts | 2 +- .../__tests__/_get_computed_fields.js | 2 - .../__tests__/_index_pattern.test.js | 58 +- .../__tests__/_index_patterns.test.js | 7 - .../index_patterns/__tests__/flatten_hit.js | 194 ------- .../ui/public/index_patterns/_field.d.ts | 31 - src/legacy/ui/public/index_patterns/_field.js | 130 ----- src/legacy/ui/public/index_patterns/_field.ts | 187 ++++++ .../{_field_list.js => _field_list.ts} | 17 +- .../{_format_hit.js => _format_hit.ts} | 24 +- .../index_patterns/_get_computed_fields.js | 52 -- .../public/index_patterns/_index_pattern.d.ts | 53 -- .../public/index_patterns/_index_pattern.js | 427 -------------- .../public/index_patterns/_index_pattern.ts | 532 ++++++++++++++++++ .../{_pattern_cache.js => _pattern_cache.ts} | 23 +- ...ern_select.js => index_pattern_select.tsx} | 93 +-- .../constants/{index.js => index.ts} | 4 +- .../index_patterns/{errors.js => errors.ts} | 28 +- .../public/index_patterns/fields_fetcher.js | 41 -- .../public/index_patterns/fields_fetcher.ts | 50 ++ .../public/index_patterns/fixtures/index.ts | 7 +- .../{get_routes.js => get_routes.ts} | 2 +- .../ui/public/index_patterns/index.d.ts | 25 - .../index_patterns/{index.js => index.ts} | 3 +- .../public/index_patterns/index_patterns.js | 94 ---- .../public/index_patterns/index_patterns.ts | 119 ++++ ...client.js => index_patterns_api_client.ts} | 75 ++- .../index_patterns/static_utils/index.d.ts | 23 - .../static_utils/{index.js => index.ts} | 21 +- .../validate/{index.js => index.ts} | 0 ...test.js => validate_index_pattern.test.ts} | 4 +- ...x_pattern.js => validate_index_pattern.ts} | 25 +- .../ui/public/indices/constants/index.js | 2 +- .../indices/validate/validate_index.test.js | 8 - .../ui/public/timefilter/get_time.test.ts | 2 +- .../config/editor_config_providers.test.ts | 2 +- src/test_utils/public/stub_index_pattern.js | 6 +- .../components/metrics_explorer/group_by.tsx | 4 +- .../pages/infrastructure/snapshot/toolbar.tsx | 2 +- .../full_time_range_selector/index.test.tsx | 2 +- .../use_source_index_data.ts | 4 +- .../step_create/step_create_form.test.tsx | 5 +- .../components/step_define/common.test.ts | 4 +- .../step_define/pivot_preview.test.tsx | 2 +- .../step_define/step_define_form.test.tsx | 2 +- .../use_pivot_preview_data.test.tsx | 4 +- 57 files changed, 1155 insertions(+), 1336 deletions(-) delete mode 100644 src/legacy/ui/public/index_patterns/__tests__/flatten_hit.js delete mode 100644 src/legacy/ui/public/index_patterns/_field.d.ts delete mode 100644 src/legacy/ui/public/index_patterns/_field.js create mode 100644 src/legacy/ui/public/index_patterns/_field.ts rename src/legacy/ui/public/index_patterns/{_field_list.js => _field_list.ts} (63%) rename src/legacy/ui/public/index_patterns/{_format_hit.js => _format_hit.ts} (76%) delete mode 100644 src/legacy/ui/public/index_patterns/_get_computed_fields.js delete mode 100644 src/legacy/ui/public/index_patterns/_index_pattern.d.ts delete mode 100644 src/legacy/ui/public/index_patterns/_index_pattern.js create mode 100644 src/legacy/ui/public/index_patterns/_index_pattern.ts rename src/legacy/ui/public/index_patterns/{_pattern_cache.js => _pattern_cache.ts} (72%) rename src/legacy/ui/public/index_patterns/components/{index_pattern_select.js => index_pattern_select.tsx} (73%) rename src/legacy/ui/public/index_patterns/constants/{index.js => index.ts} (95%) rename src/legacy/ui/public/index_patterns/{errors.js => errors.ts} (71%) delete mode 100644 src/legacy/ui/public/index_patterns/fields_fetcher.js create mode 100644 src/legacy/ui/public/index_patterns/fields_fetcher.ts rename src/legacy/ui/public/index_patterns/{get_routes.js => get_routes.ts} (98%) delete mode 100644 src/legacy/ui/public/index_patterns/index.d.ts rename src/legacy/ui/public/index_patterns/{index.js => index.ts} (90%) delete mode 100644 src/legacy/ui/public/index_patterns/index_patterns.js create mode 100644 src/legacy/ui/public/index_patterns/index_patterns.ts rename src/legacy/ui/public/index_patterns/{index_patterns_api_client.js => index_patterns_api_client.ts} (57%) delete mode 100644 src/legacy/ui/public/index_patterns/static_utils/index.d.ts rename src/legacy/ui/public/index_patterns/static_utils/{index.js => index.ts} (72%) rename src/legacy/ui/public/index_patterns/validate/{index.js => index.ts} (100%) rename src/legacy/ui/public/index_patterns/validate/{validate_index_pattern.test.js => validate_index_pattern.test.ts} (92%) rename src/legacy/ui/public/index_patterns/validate/{validate_index_pattern.js => validate_index_pattern.ts} (78%) diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx index 892ba2bcd9407..f544e4e3e6149 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx @@ -449,7 +449,7 @@ class FilterEditorUI extends Component { if (isCustomEditorOpen) { const { index, disabled, negate } = this.props.filter.meta; - const newIndex = index || this.props.indexPatterns[0].id; + const newIndex = index || (this.props.indexPatterns[0].id as string); const body = JSON.parse(queryDsl); const filter = buildCustomFilter(newIndex, body, disabled, negate, alias, $state.store); this.props.onSubmit(filter); diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts index d3006ceb10a2c..4921b57f47818 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts @@ -42,6 +42,9 @@ import { phraseFilter } from './fixtures/phrase_filter'; import { phrasesFilter } from './fixtures/phrases_filter'; import { rangeFilter } from './fixtures/range_filter'; +const mockedFields = mockFields as any; +const mockedIndexPattern = mockIndexPattern as any; + describe('Filter editor utils', () => { describe('getQueryDslFromFilter', () => { it('should return query DSL without meta and $state', () => { @@ -53,14 +56,14 @@ describe('Filter editor utils', () => { describe('getIndexPatternFromFilter', () => { it('should return the index pattern from the filter', () => { - const indexPattern = getIndexPatternFromFilter(phraseFilter, [mockIndexPattern]); - expect(indexPattern).toBe(mockIndexPattern); + const indexPattern = getIndexPatternFromFilter(phraseFilter, [mockedIndexPattern]); + expect(indexPattern).toBe(mockedIndexPattern); }); }); describe('getFieldFromFilter', () => { it('should return the field from the filter', () => { - const field = getFieldFromFilter(phraseFilter, mockIndexPattern); + const field = getFieldFromFilter(phraseFilter, mockedIndexPattern); expect(field).not.toBeUndefined(); expect(field && field.name).toBe(phraseFilter.meta.key); }); @@ -152,12 +155,12 @@ describe('Filter editor utils', () => { describe('getFilterableFields', () => { it('returns the list of fields from the given index pattern', () => { - const fieldOptions = getFilterableFields(mockIndexPattern); + const fieldOptions = getFilterableFields(mockedIndexPattern); expect(fieldOptions.length).toBeGreaterThan(0); }); it('limits the fields to the filterable fields', () => { - const fieldOptions = getFilterableFields(mockIndexPattern); + const fieldOptions = getFilterableFields(mockedIndexPattern); const nonFilterableFields = fieldOptions.filter(field => !field.filterable); expect(nonFilterableFields.length).toBe(0); }); @@ -166,14 +169,14 @@ describe('Filter editor utils', () => { describe('getOperatorOptions', () => { it('returns range for number fields', () => { const [field] = mockFields.filter(({ type }) => type === 'number'); - const operatorOptions = getOperatorOptions(field); + const operatorOptions = getOperatorOptions(field as any); const rangeOperator = operatorOptions.find(operator => operator.type === 'range'); expect(rangeOperator).not.toBeUndefined(); }); it('does not return range for string fields', () => { const [field] = mockFields.filter(({ type }) => type === 'string'); - const operatorOptions = getOperatorOptions(field); + const operatorOptions = getOperatorOptions(field as any); const rangeOperator = operatorOptions.find(operator => operator.type === 'range'); expect(rangeOperator).toBeUndefined(); }); @@ -181,44 +184,49 @@ describe('Filter editor utils', () => { describe('isFilterValid', () => { it('should return false if index pattern is not provided', () => { - const isValid = isFilterValid(undefined, mockFields[0], isOperator, 'foo'); + const isValid = isFilterValid(undefined, mockedFields[0], isOperator, 'foo'); expect(isValid).toBe(false); }); it('should return false if field is not provided', () => { - const isValid = isFilterValid(mockIndexPattern, undefined, isOperator, 'foo'); + const isValid = isFilterValid(mockedIndexPattern, undefined, isOperator, 'foo'); expect(isValid).toBe(false); }); it('should return false if operator is not provided', () => { - const isValid = isFilterValid(mockIndexPattern, mockFields[0], undefined, 'foo'); + const isValid = isFilterValid(mockedIndexPattern, mockedFields[0], undefined, 'foo'); expect(isValid).toBe(false); }); it('should return false for phrases filter without phrases', () => { - const isValid = isFilterValid(mockIndexPattern, mockFields[0], isOneOfOperator, []); + const isValid = isFilterValid(mockedIndexPattern, mockedFields[0], isOneOfOperator, []); expect(isValid).toBe(false); }); it('should return true for phrases filter with phrases', () => { - const isValid = isFilterValid(mockIndexPattern, mockFields[0], isOneOfOperator, ['foo']); + const isValid = isFilterValid(mockedIndexPattern, mockedFields[0], isOneOfOperator, ['foo']); expect(isValid).toBe(true); }); it('should return false for range filter without range', () => { - const isValid = isFilterValid(mockIndexPattern, mockFields[0], isBetweenOperator, undefined); + const isValid = isFilterValid( + mockedIndexPattern, + mockedFields[0], + isBetweenOperator, + undefined + ); expect(isValid).toBe(false); }); it('should return true for range filter with from', () => { - const isValid = isFilterValid(mockIndexPattern, mockFields[0], isBetweenOperator, { + const isValid = isFilterValid(mockedIndexPattern, mockedFields[0], isBetweenOperator, { from: 'foo', }); expect(isValid).toBe(true); }); it('should return true for range filter with from/to', () => { - const isValid = isFilterValid(mockIndexPattern, mockFields[0], isBetweenOperator, { + const isValid = isFilterValid(mockedIndexPattern, mockedFields[0], isBetweenOperator, { from: 'foo', too: 'goo', }); @@ -226,7 +234,7 @@ describe('Filter editor utils', () => { }); it('should return true for exists filter without params', () => { - const isValid = isFilterValid(mockIndexPattern, mockFields[0], existsOperator); + const isValid = isFilterValid(mockedIndexPattern, mockedFields[0], existsOperator); expect(isValid).toBe(true); }); }); @@ -236,7 +244,14 @@ describe('Filter editor utils', () => { const params = 'foo'; const alias = 'bar'; const state = FilterStateStore.APP_STATE; - const filter = buildFilter(mockIndexPattern, mockFields[0], isOperator, params, alias, state); + const filter = buildFilter( + mockedIndexPattern, + mockedFields[0], + isOperator, + params, + alias, + state + ); expect(filter.meta.negate).toBe(isOperator.negate); expect(filter.meta.alias).toBe(alias); @@ -251,8 +266,8 @@ describe('Filter editor utils', () => { const alias = 'bar'; const state = FilterStateStore.APP_STATE; const filter = buildFilter( - mockIndexPattern, - mockFields[0], + mockedIndexPattern, + mockedFields[0], isOneOfOperator, params, alias, @@ -272,8 +287,8 @@ describe('Filter editor utils', () => { const alias = 'bar'; const state = FilterStateStore.APP_STATE; const filter = buildFilter( - mockIndexPattern, - mockFields[0], + mockedIndexPattern, + mockedFields[0], isBetweenOperator, params, alias, @@ -292,8 +307,8 @@ describe('Filter editor utils', () => { const alias = 'bar'; const state = FilterStateStore.APP_STATE; const filter = buildFilter( - mockIndexPattern, - mockFields[0], + mockedIndexPattern, + mockedFields[0], existsOperator, params, alias, @@ -312,8 +327,8 @@ describe('Filter editor utils', () => { const alias = 'bar'; const state = FilterStateStore.APP_STATE; const filter = buildFilter( - mockIndexPattern, - mockFields[0], + mockedIndexPattern, + mockedFields[0], doesNotExistOperator, params, alias, diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts index adfcc2f03c25a..2b6061e4b1846 100644 --- a/src/legacy/core_plugins/data/public/index.ts +++ b/src/legacy/core_plugins/data/public/index.ts @@ -88,7 +88,7 @@ export interface DataSetup { export { ExpressionRenderer, ExpressionRendererProps, ExpressionRunner } from './expressions'; /** @public types */ -export { IndexPattern, StaticIndexPattern, StaticIndexPatternField, Field } from './index_patterns'; +export { IndexPattern, StaticIndexPattern, Field } from './index_patterns'; export { Query } from './query'; export { SearchBar, SearchBarProps } from './search'; export { FilterManager, FilterStateManager, uniqFilters } from './filter/filter_manager'; diff --git a/src/legacy/core_plugins/data/public/index_patterns/index.ts b/src/legacy/core_plugins/data/public/index_patterns/index.ts index c7ff48407ff7c..665a0e106f7a7 100644 --- a/src/legacy/core_plugins/data/public/index_patterns/index.ts +++ b/src/legacy/core_plugins/data/public/index_patterns/index.ts @@ -24,6 +24,5 @@ export { IndexPatternsSetup, IndexPattern, StaticIndexPattern, - StaticIndexPatternField, Field, } from './index_patterns_service'; diff --git a/src/legacy/core_plugins/data/public/index_patterns/index_patterns_service.ts b/src/legacy/core_plugins/data/public/index_patterns/index_patterns_service.ts index 8210ed8aad5f7..c48bfa5c50224 100644 --- a/src/legacy/core_plugins/data/public/index_patterns/index_patterns_service.ts +++ b/src/legacy/core_plugins/data/public/index_patterns/index_patterns_service.ts @@ -31,7 +31,7 @@ import { IndexPatterns } from 'ui/index_patterns/index'; // @ts-ignore import { validateIndexPattern } from 'ui/index_patterns/index'; -// IndexPattern, StaticIndexPattern, StaticIndexPatternField, Field +// IndexPattern, StaticIndexPattern, Field import * as types from 'ui/index_patterns'; const config = chrome.getUiSettingsClient(); @@ -86,8 +86,5 @@ export type IndexPattern = types.IndexPattern; /** @public */ export type StaticIndexPattern = types.StaticIndexPattern; -/** @public */ -export type StaticIndexPatternField = types.StaticIndexPatternField; - /** @public */ export type Field = types.Field; diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar.test.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar.test.tsx index 87bcebc4c510a..65c0ba7118c2e 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar.test.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar.test.tsx @@ -63,7 +63,7 @@ const mockIndexPattern = { searchable: true, }, ], -}; +} as any; describe('QueryBar', () => { const QUERY_INPUT_SELECTOR = 'InjectIntl(QueryBarInputUI)'; diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx index d51dda1e4f5d3..5ebef3e05f010 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx @@ -73,7 +73,7 @@ const mockIndexPattern = { searchable: true, }, ], -}; +} as any; describe('QueryBarInput', () => { beforeEach(() => { diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index 1256ef5dc5104..875eb3a982175 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -114,7 +114,7 @@ export class QueryBarInputUI extends Component { const objectPatternsFromStrings = await fetchIndexPatterns(stringPatterns); this.setState({ - indexPatterns: [...objectPatterns, ...objectPatternsFromStrings], + indexPatterns: [...(objectPatterns as any), ...objectPatternsFromStrings], }); }; diff --git a/src/legacy/core_plugins/kibana/public/context/api/context.ts b/src/legacy/core_plugins/kibana/public/context/api/context.ts index 28bf73ecfd6dd..55a4ac4945db1 100644 --- a/src/legacy/core_plugins/kibana/public/context/api/context.ts +++ b/src/legacy/core_plugins/kibana/public/context/api/context.ts @@ -20,7 +20,6 @@ // @ts-ignore import { SearchSourceProvider, SearchSource } from 'ui/courier'; import { IPrivate } from 'ui/private'; -import { IndexPatternEnhanced, IndexPatternGetProvider } from 'ui/index_patterns/_index_pattern'; import { Filter } from '@kbn/es-query'; import { reverseSortDir, SortDirection } from './utils/sorting'; import { extractNanos, convertIsoToMillis } from './utils/date_conversion'; @@ -42,7 +41,7 @@ const DAY_MILLIS = 24 * 60 * 60 * 1000; // look from 1 day up to 10000 days into the past and future const LOOKUP_OFFSETS = [0, 1, 7, 30, 365, 10000].map(days => days * DAY_MILLIS); -function fetchContextProvider(indexPatterns: IndexPatternGetProvider, Private: IPrivate) { +function fetchContextProvider(indexPatterns: any, Private: IPrivate) { const SearchSourcePrivate: any = Private(SearchSourceProvider); return { @@ -112,7 +111,7 @@ function fetchContextProvider(indexPatterns: IndexPatternGetProvider, Private: I return documents; } - async function createSearchSource(indexPattern: IndexPatternEnhanced, filters: Filter[]) { + async function createSearchSource(indexPattern: any, filters: Filter[]) { return new SearchSourcePrivate() .setParent(false) .setField('index', indexPattern) diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state.test.ts b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state.test.ts index 81a894985c57f..eac9c18670c89 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state.test.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state.test.ts @@ -49,6 +49,7 @@ describe('DashboardState', function() { isAutoRefreshSelectorEnabled: true, isTimeRangeSelectorEnabled: true, }; + function initDashboardState() { dashboardState = new DashboardStateManager({ savedDashboard, diff --git a/src/legacy/core_plugins/kibana/public/home/sample_data_client.js b/src/legacy/core_plugins/kibana/public/home/sample_data_client.js index 943eedb290f8c..da46b3e16c093 100644 --- a/src/legacy/core_plugins/kibana/public/home/sample_data_client.js +++ b/src/legacy/core_plugins/kibana/public/home/sample_data_client.js @@ -24,7 +24,7 @@ import { indexPatternService } from './kibana_services'; const sampleDataUrl = '/api/sample_data'; function clearIndexPatternsCache() { - indexPatternService.getIds.clearCache(); + indexPatternService.clearCache(); } export async function listSampleDataSets() { diff --git a/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts b/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts index 416e9c1b45fd2..460b2d1649162 100644 --- a/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts +++ b/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts @@ -21,7 +21,7 @@ import { AggTypeFilters } from './agg_type_filters'; describe('AggTypeFilters', () => { let registry: AggTypeFilters; - const indexPattern = { id: '1234', fields: [], title: 'foo' }; + const indexPattern = { id: '1234', fields: [], title: 'foo' } as any; const aggConfig = {}; beforeEach(() => { diff --git a/src/legacy/ui/public/index_patterns/__tests__/_get_computed_fields.js b/src/legacy/ui/public/index_patterns/__tests__/_get_computed_fields.js index 3d5fd961c9b51..2c89c6bc27569 100644 --- a/src/legacy/ui/public/index_patterns/__tests__/_get_computed_fields.js +++ b/src/legacy/ui/public/index_patterns/__tests__/_get_computed_fields.js @@ -20,7 +20,6 @@ import expect from '@kbn/expect'; import ngMock from 'ng_mock'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; -import { getComputedFields } from '../_get_computed_fields'; describe('get computed fields', function () { @@ -30,7 +29,6 @@ describe('get computed fields', function () { beforeEach(ngMock.module('kibana')); beforeEach(ngMock.inject(function (Private) { indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider); - indexPattern.getComputedFields = getComputedFields.bind(indexPattern); fn = indexPattern.getComputedFields; })); diff --git a/src/legacy/ui/public/index_patterns/__tests__/_index_pattern.test.js b/src/legacy/ui/public/index_patterns/__tests__/_index_pattern.test.js index 8e0e6237b9d30..976a6ab86b9f2 100644 --- a/src/legacy/ui/public/index_patterns/__tests__/_index_pattern.test.js +++ b/src/legacy/ui/public/index_patterns/__tests__/_index_pattern.test.js @@ -20,6 +20,7 @@ import _ from 'lodash'; import { IndexedArray } from '../../indexed_array'; import { IndexPattern } from '../_index_pattern'; +import { createFieldsFetcher } from '../fields_fetcher'; import mockLogstashFields from '../../../../../fixtures/logstash_fields'; import { stubbedSavedObjectIndexPattern } from '../../../../../fixtures/stubbed_saved_object_index_pattern'; @@ -57,28 +58,22 @@ jest.mock('../../notify', () => ({ } })); -jest.mock('../_format_hit', () => ({ - formatHitProvider: jest.fn().mockImplementation(() => ({ - formatField: jest.fn(), - })) -})); - -jest.mock('../_get', () => ({ - IndexPatternsGetProvider: jest.fn().mockImplementation(() => ({ - clearCache: jest.fn(), - })) -})); - -jest.mock('../_flatten_hit', () => ({ - flattenHitWrapper: jest.fn(), -})); - jest.mock('../../saved_objects', () => { return { findObjectByTitle: jest.fn(), }; }); +let fields = []; +jest.mock('../fields_fetcher'); + +createFieldsFetcher.mockImplementation(() => ({ + fetch: jest.fn().mockImplementation(() => { + return new Promise(resolve => resolve(fields)); + }), + every: jest.fn(), +})); + let object; const savedObjectsClient = { create: jest.fn(), @@ -106,21 +101,18 @@ const patternCache = { clear: jest.fn(), }; -let fields = []; -const fieldsFetcher = { - fetch: jest.fn().mockImplementation(() => fields), - every: jest.fn(), +const config = { + get: jest.fn(), }; -const getIds = { - clearCache: jest.fn(), +const apiClient = { + getFieldsForTimePattern: jest.fn(), + getFieldsForWildcard: jest.fn(), }; -const getConfig = jest.fn(); - // helper function to create index patterns function create(id, payload) { - const indexPattern = new IndexPattern(id, getConfig, savedObjectsClient, patternCache, fieldsFetcher, getIds); + const indexPattern = new IndexPattern(id, cfg => config.get(cfg), savedObjectsClient, apiClient, patternCache); setDocsourcePayload(id, payload); @@ -204,7 +196,6 @@ describe('IndexPattern', () => { await indexPattern.refreshFields(); - expect(fieldsFetcher.fetch).toHaveBeenCalledTimes(1); fields = []; const newFields = indexPattern.getNonScriptedFields(); @@ -258,12 +249,15 @@ describe('IndexPattern', () => { expect(indexPattern.fields.byName[scriptedField.name]).toEqual(undefined); }); - it('should not allow duplicate names', function () { + it('should not allow duplicate names', async () => { const scriptedFields = indexPattern.getScriptedFields(); const scriptedField = _.last(scriptedFields); - expect(function () { - indexPattern.addScriptedField(scriptedField.name, '\'new script\'', 'string'); - }).toThrow(); + expect.assertions(1); + try { + await indexPattern.addScriptedField(scriptedField.name, '\'new script\'', 'string'); + } catch (e) { + expect(e).toEqual({}); + } }); }); @@ -324,13 +318,13 @@ describe('IndexPattern', () => { } }); // Create a normal index pattern - const pattern = new IndexPattern('foo', getConfig, savedObjectsClient, patternCache, fieldsFetcher, getIds); + const pattern = new IndexPattern('foo', cfg => config.get(cfg), savedObjectsClient, apiClient, patternCache); await pattern.init(); expect(pattern.version).toBe('fooa'); // Create the same one - we're going to handle concurrency - const samePattern = new IndexPattern('foo', getConfig, savedObjectsClient, patternCache, fieldsFetcher, getIds); + const samePattern = new IndexPattern('foo', cfg => config.get(cfg), savedObjectsClient, apiClient, patternCache); await samePattern.init(); expect(samePattern.version).toBe('fooaa'); diff --git a/src/legacy/ui/public/index_patterns/__tests__/_index_patterns.test.js b/src/legacy/ui/public/index_patterns/__tests__/_index_patterns.test.js index ea288800443ff..54251347df2f7 100644 --- a/src/legacy/ui/public/index_patterns/__tests__/_index_patterns.test.js +++ b/src/legacy/ui/public/index_patterns/__tests__/_index_patterns.test.js @@ -36,13 +36,6 @@ jest.mock('../../notify', () => ({ } })); - -jest.mock('../_get', () => ({ - indexPatternsGetProvider: jest.fn().mockImplementation(() => { - return () => {}; - }) -})); - jest.mock('../_index_pattern', () => { class IndexPattern { init = async () => { diff --git a/src/legacy/ui/public/index_patterns/__tests__/flatten_hit.js b/src/legacy/ui/public/index_patterns/__tests__/flatten_hit.js deleted file mode 100644 index 76c0e54241dcf..0000000000000 --- a/src/legacy/ui/public/index_patterns/__tests__/flatten_hit.js +++ /dev/null @@ -1,194 +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 { flattenHitWrapper } from '../_flatten_hit'; - -const indexPattern = { - fields: { - byName: { - 'tags.text': { type: 'string' }, - 'tags.label': { type: 'string' }, - 'message': { type: 'string' }, - 'geo.coordinates': { type: 'geo_point' }, - 'geo.dest': { type: 'string' }, - 'geo.src': { type: 'string' }, - 'bytes': { type: 'number' }, - '@timestamp': { type: 'date' }, - 'team': { type: 'nested' }, - 'team.name': { type: 'string' }, - 'team.role': { type: 'string' }, - 'user': { type: 'conflict' }, - 'user.name': { type: 'string' }, - 'user.id': { type: 'conflict' }, - 'delta': { type: 'number', scripted: true } - } - } -}; - -describe('IndexPattern#flattenHit()', function () { - let flattenHit; - let hit; - - beforeEach(ngMock.module('kibana')); - beforeEach(ngMock.inject(function () { - - - flattenHit = flattenHitWrapper(indexPattern, []); - - hit = { - _source: { - message: 'Hello World', - geo: { - coordinates: { lat: 33.4500, lon: 112.0667 }, - dest: 'US', - src: 'IN' - }, - bytes: 10039103, - '@timestamp': (new Date()).toString(), - tags: [ - { text: 'foo', label: [ 'FOO1', 'FOO2' ] }, - { text: 'bar', label: 'BAR' } - ], - groups: ['loners'], - noMapping: true, - team: [ - { name: 'foo', role: 'leader' }, - { name: 'bar', role: 'follower' }, - { name: 'baz', role: 'party boy' }, - ], - user: { name: 'smith', id: 123 } - }, - fields: { - delta: [42], - random: [0.12345] - } - }; - })); - - it('flattens keys as far down as the mapping goes', function () { - const flat = flattenHit(hit); - - expect(flat).to.have.property('geo.coordinates', hit._source.geo.coordinates); - expect(flat).to.not.have.property('geo.coordinates.lat'); - expect(flat).to.not.have.property('geo.coordinates.lon'); - expect(flat).to.have.property('geo.dest', 'US'); - expect(flat).to.have.property('geo.src', 'IN'); - expect(flat).to.have.property('@timestamp', hit._source['@timestamp']); - expect(flat).to.have.property('message', 'Hello World'); - expect(flat).to.have.property('bytes', 10039103); - }); - - it('flattens keys not in the mapping', function () { - const flat = flattenHit(hit); - - expect(flat).to.have.property('noMapping', true); - expect(flat).to.have.property('groups'); - expect(flat.groups).to.eql(['loners']); - }); - - it('flattens conflicting types in the mapping', function () { - const flat = flattenHit(hit); - - expect(flat).to.not.have.property('user'); - expect(flat).to.have.property('user.name', hit._source.user.name); - expect(flat).to.have.property('user.id', hit._source.user.id); - }); - - it('should preserve objects in arrays if deep argument is false', function () { - const flat = flattenHit(hit); - - expect(flat).to.have.property('tags', hit._source.tags); - }); - - it('should expand objects in arrays if deep argument is true', function () { - const flat = flattenHit(hit, true); - - expect(flat['tags.text']).to.be.eql([ 'foo', 'bar' ]); - }); - - it('should support arrays when expanding objects in arrays if deep argument is true', function () { - const flat = flattenHit(hit, true); - - expect(flat['tags.label']).to.be.eql([ 'FOO1', 'FOO2', 'BAR' ]); - }); - - it('does not enter into nested fields', function () { - const flat = flattenHit(hit); - - expect(flat).to.have.property('team', hit._source.team); - expect(flat).to.not.have.property('team.name'); - expect(flat).to.not.have.property('team.role'); - expect(flat).to.not.have.property('team[0]'); - expect(flat).to.not.have.property('team.0'); - }); - - it('unwraps script fields', function () { - const flat = flattenHit(hit); - - expect(flat).to.have.property('delta', 42); - }); - - it('assumes that all fields are "computed fields"', function () { - const flat = flattenHit(hit); - - expect(flat).to.have.property('random', 0.12345); - }); - - it('ignores fields that start with an _ and are not in the metaFields', function () { - flattenHit = flattenHitWrapper(indexPattern, ['_metaKey']); - hit.fields._notMetaKey = [100]; - const flat = flattenHit(hit); - expect(flat).to.not.have.property('_notMetaKey'); - }); - - it('includes underscore-prefixed keys that are in the metaFields', function () { - flattenHit = flattenHitWrapper(indexPattern, ['_metaKey']); - hit.fields._metaKey = [100]; - const flat = flattenHit(hit); - expect(flat).to.have.property('_metaKey', 100); - }); - - it('adapts to changes in the metaFields', function () { - hit.fields._metaKey = [100]; - - flattenHit = flattenHitWrapper(indexPattern, ['_metaKey']); - let flat = flattenHit(hit); - expect(flat).to.have.property('_metaKey', 100); - - flattenHit = flattenHitWrapper(indexPattern, []); - flat = flattenHit(hit); - expect(flat).to.not.have.property('_metaKey'); - }); - - it('handles fields that are not arrays, like _timestamp', function () { - hit.fields._metaKey = 20000; - flattenHit = flattenHitWrapper(indexPattern, ['_metaKey']); - const flat = flattenHit(hit); - expect(flat).to.have.property('_metaKey', 20000); - }); - - it('does not change the contents of the hit object', function () { - const originalHit = JSON.stringify(hit); - flattenHit(hit); - - expect(JSON.stringify(hit)).to.eql(originalHit); - }); -}); diff --git a/src/legacy/ui/public/index_patterns/_field.d.ts b/src/legacy/ui/public/index_patterns/_field.d.ts deleted file mode 100644 index 18d8c4ee111c3..0000000000000 --- a/src/legacy/ui/public/index_patterns/_field.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export interface Field { - name: string; - type: string; - // esTypes might be undefined on old index patterns that have not been refreshed since we added - // this prop. It is also undefined on scripted fields. - esTypes?: string[]; - aggregatable: boolean; - filterable: boolean; - searchable: boolean; - parent?: string; - subType?: string; -} diff --git a/src/legacy/ui/public/index_patterns/_field.js b/src/legacy/ui/public/index_patterns/_field.js deleted file mode 100644 index 067b1a78ec3cc..0000000000000 --- a/src/legacy/ui/public/index_patterns/_field.js +++ /dev/null @@ -1,130 +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 { ObjDefine } from 'ui/utils/obj_define'; -import { FieldFormat } from '../../field_formats/field_format'; -import { fieldFormats } from 'ui/registry/field_formats'; -import { getKbnFieldType } from '../../../utils'; -import { shortenDottedString } from '../../../core_plugins/kibana/common/utils/shorten_dotted_string'; -import { toastNotifications } from 'ui/notify'; -import { i18n } from '@kbn/i18n'; - -export function Field(indexPattern, spec) { - // unwrap old instances of Field - if (spec instanceof Field) spec = spec.$$spec; - - // construct this object using ObjDefine class, which - // extends the Field.prototype but gets it's properties - // defined using the logic below - const obj = new ObjDefine(spec, Field.prototype); - - if (spec.name === '_source') { - spec.type = '_source'; - } - - const shortDotsEnable = indexPattern.shortDotsEnable; - - // find the type for this field, fallback to unknown type - let type = getKbnFieldType(spec.type); - if (spec.type && !type) { - const title = i18n.translate('common.ui.indexPattern.unknownFieldHeader', - { values: { type: spec.type }, defaultMessage: 'Unknown field type {type}' }); - const text = i18n.translate('common.ui.indexPattern.unknownFieldErrorMessage', { - values: { name: spec.name, title: indexPattern.title }, - defaultMessage: 'Field {name} in indexPattern {title} is using an unknown field type.' }); - - toastNotifications.addDanger({ - title, - text, - }); - } - - if (!type) type = getKbnFieldType('unknown'); - - let format = spec.format; - if (!format || !(format instanceof FieldFormat)) { - format = indexPattern.fieldFormatMap[spec.name] || fieldFormats.getDefaultInstance(spec.type, spec.esTypes); - } - - const indexed = !!spec.indexed; - const scripted = !!spec.scripted; - const searchable = !!spec.searchable || scripted; - const aggregatable = !!spec.aggregatable || scripted; - const readFromDocValues = !!spec.readFromDocValues && !scripted; - const sortable = spec.name === '_score' || ((indexed || aggregatable) && type.sortable); - const filterable = spec.name === '_id' || scripted || ((indexed || searchable) && type.filterable); - const visualizable = aggregatable; - - obj.fact('name'); - obj.fact('type'); - obj.fact('esTypes'); - obj.writ('count', spec.count || 0); - - // scripted objs - obj.fact('scripted', scripted); - obj.writ('script', scripted ? spec.script : null); - obj.writ('lang', scripted ? (spec.lang || 'painless') : null); - - // stats - obj.fact('searchable', searchable); - obj.fact('aggregatable', aggregatable); - obj.fact('readFromDocValues', readFromDocValues); - - // usage flags, read-only and won't be saved - obj.comp('format', format); - obj.comp('sortable', sortable); - obj.comp('filterable', filterable); - obj.comp('visualizable', visualizable); - - // computed values - obj.comp('indexPattern', indexPattern); - obj.comp('displayName', shortDotsEnable ? shortenDottedString(spec.name) : spec.name); - obj.comp('$$spec', spec); - - // conflict info - obj.writ('conflictDescriptions'); - - // multi info - obj.fact('parent'); - obj.fact('subType'); - - return obj.create(); -} - -Object.defineProperties(Field.prototype, { - indexed: { - get() { - throw new Error('field.indexed has been removed, see https://github.com/elastic/kibana/pull/11969'); - } - }, - analyzed: { - get() { - throw new Error('field.analyzed has been removed, see https://github.com/elastic/kibana/pull/11969'); - } - }, - doc_values: { - get() { - throw new Error('field.doc_values has been removed, see https://github.com/elastic/kibana/pull/11969'); - } - }, -}); - -Field.prototype.routes = { - edit: '/management/kibana/index_patterns/{{indexPattern.id}}/field/{{name}}' -}; diff --git a/src/legacy/ui/public/index_patterns/_field.ts b/src/legacy/ui/public/index_patterns/_field.ts new file mode 100644 index 0000000000000..e678c4cc824f1 --- /dev/null +++ b/src/legacy/ui/public/index_patterns/_field.ts @@ -0,0 +1,187 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// @ts-ignore +import { ObjDefine } from 'ui/utils/obj_define'; +// @ts-ignore +import { fieldFormats } from 'ui/registry/field_formats'; +import { toastNotifications } from 'ui/notify'; +import { i18n } from '@kbn/i18n'; +// @ts-ignore +import { FieldFormat } from '../../field_formats/field_format'; +// @ts-ignore +import { getKbnFieldType } from '../../../utils'; +// @ts-ignore +import { shortenDottedString } from '../../../core_plugins/kibana/common/utils/shorten_dotted_string'; +import { IndexPattern } from './_index_pattern'; + +export type FieldSpec = Record; +export interface FieldType { + name: string; + type: string; + script?: string; + lang?: string; + count?: number; + // esTypes might be undefined on old index patterns that have not been refreshed since we added + // this prop. It is also undefined on scripted fields. + esTypes?: string[]; + aggregatable?: boolean; + filterable?: boolean; + searchable?: boolean; + readFromDocValues?: boolean; + scripted?: boolean; + parent?: string; + subType?: string; + displayName?: string; + format?: any; +} + +export class Field implements FieldType { + name: string; + type: string; + script?: string; + lang?: string; + count?: number; + // esTypes might be undefined on old index patterns that have not been refreshed since we added + // this prop. It is also undefined on scripted fields. + esTypes?: string[]; + aggregatable?: boolean; + filterable?: boolean; + searchable?: boolean; + scripted?: boolean; + parent?: string; + subType?: string; + displayName?: string; + format: any; + routes: Record = { + edit: '/management/kibana/index_patterns/{{indexPattern.id}}/field/{{name}}', + }; + $$spec: FieldSpec; + + constructor( + indexPattern: IndexPattern, + spec: FieldSpec | Field, + shortDotsEnable: boolean = false + ) { + // unwrap old instances of Field + if (spec instanceof Field) spec = spec.$$spec; + + // construct this object using ObjDefine class, which + // extends the Field.prototype but gets it's properties + // defined using the logic below + const obj = new ObjDefine(spec, Field.prototype); + + if (spec.name === '_source') { + spec.type = '_source'; + } + + // find the type for this field, fallback to unknown type + let type = getKbnFieldType(spec.type); + if (spec.type && !type) { + const title = i18n.translate('common.ui.indexPattern.unknownFieldHeader', { + values: { type: spec.type }, + defaultMessage: 'Unknown field type {type}', + }); + const text = i18n.translate('common.ui.indexPattern.unknownFieldErrorMessage', { + values: { name: spec.name, title: indexPattern.title }, + defaultMessage: 'Field {name} in indexPattern {title} is using an unknown field type.', + }); + + toastNotifications.addDanger({ + title, + text, + }); + } + + if (!type) type = getKbnFieldType('unknown'); + + let format = spec.format; + if (!format || !(format instanceof FieldFormat)) { + format = + indexPattern.fieldFormatMap[spec.name] || + fieldFormats.getDefaultInstance(spec.type, spec.esTypes); + } + + const indexed = !!spec.indexed; + const scripted = !!spec.scripted; + const searchable = !!spec.searchable || scripted; + const aggregatable = !!spec.aggregatable || scripted; + const readFromDocValues = !!spec.readFromDocValues && !scripted; + const sortable = spec.name === '_score' || ((indexed || aggregatable) && type.sortable); + const filterable = + spec.name === '_id' || scripted || ((indexed || searchable) && type.filterable); + const visualizable = aggregatable; + + this.name = ''; + obj.fact('name'); + this.type = ''; + obj.fact('type'); + obj.fact('esTypes'); + obj.writ('count', spec.count || 0); + + // scripted objs + obj.fact('scripted', scripted); + obj.writ('script', scripted ? spec.script : null); + obj.writ('lang', scripted ? spec.lang || 'painless' : null); + + // stats + obj.fact('searchable', searchable); + obj.fact('aggregatable', aggregatable); + obj.fact('readFromDocValues', readFromDocValues); + + // usage flags, read-only and won't be saved + obj.comp('format', format); + obj.comp('sortable', sortable); + obj.comp('filterable', filterable); + obj.comp('visualizable', visualizable); + + // computed values + obj.comp('indexPattern', indexPattern); + obj.comp('displayName', shortDotsEnable ? shortenDottedString(spec.name) : spec.name); + this.$$spec = spec; + obj.comp('$$spec', spec); + + // conflict info + obj.writ('conflictDescriptions'); + + // multi info + obj.fact('parent'); + obj.fact('subType'); + + return obj.create(); + } + + get indexed() { + throw new Error( + 'field.indexed has been removed, see https://github.com/elastic/kibana/pull/11969' + ); + } + get analyzed() { + throw new Error( + 'field.analyzed has been removed, see https://github.com/elastic/kibana/pull/11969' + ); + } + get doc_values() { // eslint-disable-line + throw new Error( + 'field.doc_values has been removed, see https://github.com/elastic/kibana/pull/11969' + ); + } +} + +Object.defineProperties(Field.prototype, {}); diff --git a/src/legacy/ui/public/index_patterns/_field_list.js b/src/legacy/ui/public/index_patterns/_field_list.ts similarity index 63% rename from src/legacy/ui/public/index_patterns/_field_list.js rename to src/legacy/ui/public/index_patterns/_field_list.ts index 999bb8dd14796..5ce73880b8a31 100644 --- a/src/legacy/ui/public/index_patterns/_field_list.js +++ b/src/legacy/ui/public/index_patterns/_field_list.ts @@ -18,16 +18,21 @@ */ import { IndexedArray } from 'ui/indexed_array'; -import { Field } from './_field'; +import { IndexPattern } from 'ui/index_patterns/_index_pattern'; +import { Field, FieldSpec } from './_field'; -export class FieldList extends IndexedArray { - constructor(indexPattern, specs) { +export class FieldList extends IndexedArray { + // makes typescript work, but breaks kibana + //public byType: Record = {}; + //public byName: Record = {}; + + constructor(indexPattern: IndexPattern, specs: FieldSpec[], shortDotsEnable: boolean = false) { super({ index: ['name'], group: ['type'], - initialSet: specs.map(function (field) { - return new Field(indexPattern, field); - }) + initialSet: specs.map(function(field) { + return new Field(indexPattern, field, shortDotsEnable); + }), }); } } diff --git a/src/legacy/ui/public/index_patterns/_format_hit.js b/src/legacy/ui/public/index_patterns/_format_hit.ts similarity index 76% rename from src/legacy/ui/public/index_patterns/_format_hit.js rename to src/legacy/ui/public/index_patterns/_format_hit.ts index 024d4b6845b12..8d85d78ed30a1 100644 --- a/src/legacy/ui/public/index_patterns/_format_hit.js +++ b/src/legacy/ui/public/index_patterns/_format_hit.ts @@ -18,26 +18,25 @@ */ import _ from 'lodash'; +import { IndexPattern } from './_index_pattern'; const formattedCache = new WeakMap(); const partialFormattedCache = new WeakMap(); // Takes a hit, merges it with any stored/scripted fields, and with the metaFields // returns a formatted version -export function formatHitProvider(indexPattern, defaultFormat) { - - function convert(hit, val, fieldName) { +export function formatHitProvider(indexPattern: IndexPattern, defaultFormat: any) { + function convert(hit: any, val: any, fieldName: string) { const field = indexPattern.fields.byName[fieldName]; if (!field) return defaultFormat.convert(val, 'html'); const parsedUrl = { origin: window.location.origin, pathname: window.location.pathname, - basePath: indexPattern.fieldsFetcher.apiClient.basePath, }; return field.format.getConverterFor('html')(val, field, hit, parsedUrl); } - function formatHit(hit) { + function formatHit(hit: any) { const cached = formattedCache.get(hit); if (cached) { return cached; @@ -48,19 +47,23 @@ export function formatHitProvider(indexPattern, defaultFormat) { const partials = partialFormattedCache.get(hit) || {}; partialFormattedCache.set(hit, partials); - const cache = {}; + const cache = {} as any; formattedCache.set(hit, cache); - _.forOwn(indexPattern.flattenHit(hit), function (val, fieldName) { + _.forOwn(indexPattern.flattenHit(hit), function(val: any, fieldName: any) { // sync the formatted and partial cache - const formatted = partials[fieldName] == null ? convert(hit, val, fieldName) : partials[fieldName]; + if (!fieldName) { + return; + } + const formatted = + partials[fieldName] == null ? convert(hit, val, fieldName) : partials[fieldName]; cache[fieldName] = partials[fieldName] = formatted; }); return cache; } - formatHit.formatField = function (hit, fieldName) { + formatHit.formatField = function(hit: any, fieldName: string) { let partials = partialFormattedCache.get(hit); if (partials && partials[fieldName] != null) { return partials[fieldName]; @@ -71,7 +74,8 @@ export function formatHitProvider(indexPattern, defaultFormat) { partialFormattedCache.set(hit, partials); } - const val = fieldName === '_source' ? hit._source : indexPattern.flattenHit(hit)[fieldName]; + const val: any = + fieldName === '_source' ? hit._source : indexPattern.flattenHit(hit)[fieldName]; return convert(hit, val, fieldName); }; diff --git a/src/legacy/ui/public/index_patterns/_get_computed_fields.js b/src/legacy/ui/public/index_patterns/_get_computed_fields.js deleted file mode 100644 index 192b40fd34b8a..0000000000000 --- a/src/legacy/ui/public/index_patterns/_get_computed_fields.js +++ /dev/null @@ -1,52 +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 { each, reject } from 'lodash'; - -export function getComputedFields() { - const self = this; - const scriptFields = {}; - - // Date value returned in "_source" could be in any number of formats - // Use a docvalue for each date field to ensure standardized formats when working with date fields - // indexPattern.flattenHit will override "_source" values when the same field is also defined in "fields" - const docvalueFields = reject(self.fields.byType.date, 'scripted') - .map((dateField) => { - return { - field: dateField.name, - format: dateField.esTypes && dateField.esTypes.indexOf('date_nanos') !== -1 ? 'strict_date_time' : 'date_time', - }; - }); - - each(self.getScriptedFields(), function (field) { - scriptFields[field.name] = { - script: { - source: field.script, - lang: field.lang - } - }; - }); - - return { - storedFields: ['*'], - scriptFields: scriptFields, - docvalueFields: docvalueFields - }; - -} diff --git a/src/legacy/ui/public/index_patterns/_index_pattern.d.ts b/src/legacy/ui/public/index_patterns/_index_pattern.d.ts deleted file mode 100644 index d3856b79b1d09..0000000000000 --- a/src/legacy/ui/public/index_patterns/_index_pattern.d.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Field } from 'ui/index_patterns/_field'; - -/** - * WARNING: these types are incomplete - */ - -export interface IndexPattern { - id: string; - fields: Field[]; - title: string; - timeFieldName?: string; -} -// 'enhanced' IndexPattern returned by IndexPatternProvider -// reason for having this seperate interface are several tests -// that currently depend on an interface without methods to succeed -export interface IndexPatternEnhanced extends IndexPattern { - isTimeNanosBased: () => boolean; -} - -export interface IndexPatternGetProvider { - get: (id: string) => IndexPatternEnhanced; -} - -export interface StaticIndexPatternField { - name: string; - type: string; - aggregatable: boolean; - searchable: boolean; -} - -export interface StaticIndexPattern { - fields: StaticIndexPatternField[]; - title: string; -} diff --git a/src/legacy/ui/public/index_patterns/_index_pattern.js b/src/legacy/ui/public/index_patterns/_index_pattern.js deleted file mode 100644 index 3dcc24cf8a2b0..0000000000000 --- a/src/legacy/ui/public/index_patterns/_index_pattern.js +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import _ from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { SavedObjectNotFound, DuplicateField } from 'ui/errors'; -import { fieldFormats } from 'ui/registry/field_formats'; -import { expandShorthand } from 'ui/utils/mapping_setup'; -import { toastNotifications } from 'ui/notify'; -import { findObjectByTitle } from 'ui/saved_objects'; - -import { IndexPatternMissingIndices } from './errors'; -import { getComputedFields } from './_get_computed_fields'; -import { getRoutes } from './get_routes'; -import { formatHitProvider } from './_format_hit'; -import { FieldList } from './_field_list'; -import { flattenHitWrapper } from './_flatten_hit'; - -const MAX_ATTEMPTS_TO_RESOLVE_CONFLICTS = 3; -const type = 'index-pattern'; - -export class IndexPattern { - constructor(id, getConfig, savedObjectsClient, patternCache, fieldsFetcher, getIds) { - this._setId(id); - this.getConfig = getConfig; - this.savedObjectsClient = savedObjectsClient; - this.patternCache = patternCache; - this.fieldsFetcher = fieldsFetcher; - this.getIds = getIds; - - this.metaFields = getConfig('metaFields'); - this.shortDotsEnable = getConfig('shortDots:enable'); - this.getComputedFields = getComputedFields.bind(this); - - this.flattenHit = flattenHitWrapper(this, this.metaFields); - this.formatHit = formatHitProvider(this, fieldFormats.getDefaultInstance('string')); - this.formatField = this.formatHit.formatField; - - function serializeFieldFormatMap(flat, format, field) { - if (format) { - flat[field] = format; - } - } - - function deserializeFieldFormatMap(mapping) { - const FieldFormat = fieldFormats.byId[mapping.id]; - return FieldFormat && new FieldFormat(mapping.params, getConfig); - } - - this.mapping = expandShorthand({ - title: 'text', - timeFieldName: 'keyword', - intervalName: 'keyword', - fields: 'json', - sourceFilters: 'json', - fieldFormatMap: { - type: 'text', - _serialize(map = {}) { - const serialized = _.transform(map, serializeFieldFormatMap); - return _.isEmpty(serialized) ? undefined : JSON.stringify(serialized); - }, - _deserialize(map = '{}') { - return _.mapValues(JSON.parse(map), mapping => { return deserializeFieldFormatMap(mapping); }); - } - }, - type: 'keyword', - typeMeta: 'json', - }); - } - - _setId(id) { - this.id = id; - return this; - } - - _setVersion(version) { - this.version = version; - return this; - } - - _initFields(input) { - const oldValue = this.fields; - const newValue = input || oldValue || []; - this.fields = new FieldList(this, newValue); - } - - async _indexFields(forceFieldRefresh = false) { - if (!this.id) { - return; - } - - function isFieldRefreshRequired(indexPattern) { - if (!indexPattern.fields) { - return true; - } - - return indexPattern.fields.every(field => { - // See https://github.com/elastic/kibana/pull/8421 - const hasFieldCaps = ('aggregatable' in field) && ('searchable' in field); - - // See https://github.com/elastic/kibana/pull/11969 - const hasDocValuesFlag = ('readFromDocValues' in field); - - return !hasFieldCaps || !hasDocValuesFlag; - }); - } - - if (forceFieldRefresh || isFieldRefreshRequired(this)) { - await this.refreshFields(); - } - - this._initFields(); - } - - _updateFromElasticSearch(response, forceFieldRefresh = false) { - if (!response.found) { - throw new SavedObjectNotFound( - type, - this.id, - '#/management/kibana/index_pattern', - ); - } - - _.forOwn(this.mapping, (fieldMapping, name) => { - if (!fieldMapping._deserialize) { - return; - } - response._source[name] = fieldMapping._deserialize(response._source[name]); - }); - - // give index pattern all of the values in _source - _.assign(this, response._source); - - if (!this.title) { - this.title = this.id; - } - - return this._indexFields(forceFieldRefresh); - } - - get routes() { - return getRoutes(); - } - - async init(forceFieldRefresh = false) { - - if (!this.id) { - return this; // no id === no elasticsearch document - } - - const savedObject = await this.savedObjectsClient.get(type, this.id); - this._setVersion(savedObject._version); - - const response = { - _id: savedObject.id, - _type: savedObject.type, - _source: _.cloneDeep(savedObject.attributes), - found: savedObject._version ? true : false - }; - // Do this before we attempt to update from ES since that call can potentially perform a save - this.originalBody = this.prepBody(); - await this._updateFromElasticSearch(response, forceFieldRefresh); - // Do it after to ensure we have the most up to date information - this.originalBody = this.prepBody(); - - return this; - } - - // Get the source filtering configuration for that index. - getSourceFiltering() { - return { - excludes: this.sourceFilters && this.sourceFilters.map(filter => filter.value) || [] - }; - } - - addScriptedField(name, script, type = 'string', lang) { - const scriptedFields = this.getScriptedFields(); - const names = _.pluck(scriptedFields, 'name'); - - if (_.contains(names, name)) { - throw new DuplicateField(name); - } - - this.fields.push({ - name: name, - script: script, - type: type, - scripted: true, - lang: lang - }); - - this.save(); - } - - removeScriptedField(name) { - const fieldIndex = _.findIndex(this.fields, { - name: name, - scripted: true - }); - - if(fieldIndex > -1) { - this.fields.splice(fieldIndex, 1); - delete this.fieldFormatMap[name]; - return this.save(); - } - } - - popularizeField(fieldName, unit = 1) { - const field = _.get(this, ['fields', 'byName', fieldName]); - if (!field) { - return; - } - const count = Math.max((field.count || 0) + unit, 0); - if (field.count === count) { - return; - } - field.count = count; - this.save(); - } - - getNonScriptedFields() { - return _.where(this.fields, { scripted: false }); - } - - getScriptedFields() { - return _.where(this.fields, { scripted: true }); - } - - isTimeBased() { - return !!this.timeFieldName && (!this.fields || !!this.getTimeField()); - } - - isTimeNanosBased() { - const timeField = this.getTimeField(); - return timeField && timeField.esTypes && timeField.esTypes.indexOf('date_nanos') !== -1; - } - - isTimeBasedWildcard() { - return this.isTimeBased() && this.isWildcard(); - } - - getTimeField() { - if (!this.timeFieldName || !this.fields || !this.fields.byName) return; - return this.fields.byName[this.timeFieldName]; - } - - isWildcard() { - return _.includes(this.title, '*'); - } - - prepBody() { - const body = {}; - - // serialize json fields - _.forOwn(this.mapping, (fieldMapping, fieldName) => { - if (this[fieldName] != null) { - body[fieldName] = (fieldMapping._serialize) - ? fieldMapping._serialize(this[fieldName]) - : this[fieldName]; - } - }); - - // clear the indexPattern list cache - this.getIds.clearCache(); - return body; - } - - async create(allowOverride = false) { - const _create = async (duplicateId) => { - if (duplicateId) { - const duplicatePattern = new IndexPattern(duplicateId, - this.getConfig, - this.savedObjectsClient, - this.patternCache, - this.fieldsFetcher, - this.getIds); - await duplicatePattern.destroy(); - } - - const body = this.prepBody(); - const response = await this.savedObjectsClient.create(type, body, { id: this.id }); - - this._setId(response.id); - return response.id; - }; - - const potentialDuplicateByTitle = await findObjectByTitle(this.savedObjectsClient, type, this.title); - // If there is potentially duplicate title, just create it - if (!potentialDuplicateByTitle) { - return await _create(); - } - - // We found a duplicate but we aren't allowing override, show the warn modal - if (!allowOverride) { - return false; - } - - return await _create(potentialDuplicateByTitle.id); - } - - save(saveAttempts = 0) { - const body = this.prepBody(); - // What keys changed since they last pulled the index pattern - const originalChangedKeys = Object.keys(body).filter(key => body[key] !== this.originalBody[key]); - return this.savedObjectsClient.update(type, this.id, body, { version: this.version }) - .then(({ id, _version }) => { - this._setId(id); - this._setVersion(_version); - }) - .catch(err => { - if (_.get(err, 'res.status') === 409 && saveAttempts++ < MAX_ATTEMPTS_TO_RESOLVE_CONFLICTS) { - const samePattern = new IndexPattern(this.id, - this.getConfig, - this.savedObjectsClient, - this.patternCache, - this.fieldsFetcher, - this.getIds); - return samePattern.init() - .then(() => { - // What keys changed from now and what the server returned - const updatedBody = samePattern.prepBody(); - - // Build a list of changed keys from the server response - // and ensure we ignore the key if the server response - // is the same as the original response (since that is expected - // if we made a change in that key) - const serverChangedKeys = Object.keys(updatedBody).filter(key => { - return updatedBody[key] !== body[key] && this.originalBody[key] !== updatedBody[key]; - }); - - let unresolvedCollision = false; - for (const originalKey of originalChangedKeys) { - for (const serverKey of serverChangedKeys) { - if (originalKey === serverKey) { - unresolvedCollision = true; - break; - } - } - } - - if (unresolvedCollision) { - const message = i18n.translate( - 'common.ui.indexPattern.unableWriteLabel', - { defaultMessage: 'Unable to write index pattern! Refresh the page to get the most up to date changes for this index pattern.' } // eslint-disable-line max-len - ); - toastNotifications.addDanger(message); - throw err; - } - - // Set the updated response on this object - serverChangedKeys.forEach(key => { - this[key] = samePattern[key]; - }); - - this._setVersion(samePattern.version); - - // Clear cache - this.patternCache.clear(this.id); - - // Try the save again - return this.save(saveAttempts); - }); - } - throw err; - }); - } - - async _fetchFields() { - const fields = await this.fieldsFetcher.fetch(this); - const scripted = this.getScriptedFields(); - const all = fields.concat(scripted); - await this._initFields(all); - } - - refreshFields() { - return this._fetchFields() - .then(() => this.save()) - .catch((err) => { - // https://github.com/elastic/kibana/issues/9224 - // This call will attempt to remap fields from the matching - // ES index which may not actually exist. In that scenario, - // we still want to notify the user that there is a problem - // but we do not want to potentially make any pages unusable - // so do not rethrow the error here - if (err instanceof IndexPatternMissingIndices) { - toastNotifications.addDanger(err.message); - return []; - } - - toastNotifications.addError(err, { - title: i18n.translate('common.ui.indexPattern.fetchFieldErrorTitle', { - defaultMessage: 'Error fetching fields', - }), - }); - throw err; - }); - } - - toJSON() { - return this.id; - } - - toString() { - return '' + this.toJSON(); - } - - destroy() { - this.patternCache.clear(this.id); - return this.savedObjectsClient.delete(type, this.id); - } -} diff --git a/src/legacy/ui/public/index_patterns/_index_pattern.ts b/src/legacy/ui/public/index_patterns/_index_pattern.ts new file mode 100644 index 0000000000000..faaf7da7bfa13 --- /dev/null +++ b/src/legacy/ui/public/index_patterns/_index_pattern.ts @@ -0,0 +1,532 @@ +/* + * 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 _, { each, reject } from 'lodash'; +import { i18n } from '@kbn/i18n'; +// @ts-ignore +import { SavedObjectNotFound, DuplicateField } from 'ui/errors'; +// @ts-ignore +import { fieldFormats } from 'ui/registry/field_formats'; +// @ts-ignore +import { expandShorthand } from 'ui/utils/mapping_setup'; +import { toastNotifications } from 'ui/notify'; +import { findObjectByTitle, SavedObjectsClient } from 'ui/saved_objects'; + +import { IndexPatternsApiClient } from 'ui/index_patterns/index_patterns_api_client'; +import { IndexPatternMissingIndices } from './errors'; +import { getRoutes } from './get_routes'; +import { FieldList } from './_field_list'; +import { createFieldsFetcher } from './fields_fetcher'; +import { Field, FieldType } from './_field'; +// @ts-ignore +import { flattenHitWrapper } from './_flatten_hit'; +// @ts-ignore +import { formatHitProvider } from './_format_hit'; + +const MAX_ATTEMPTS_TO_RESOLVE_CONFLICTS = 3; +const type = 'index-pattern'; + +interface FieldMappingSpec { + _serialize: (mapping: any) => string; + _deserialize: (mapping: string) => any; +} + +interface MappingObject { + [key: string]: FieldMappingSpec; +} + +export interface StaticIndexPattern { + fields: FieldType[]; + title: string; + id?: string; + type?: string; + timeFieldName?: string; +} + +export const createIndexPatternMock = (params: Record): StaticIndexPattern => { + return { + ...params, + id: params.id || 'testIndexPattern', + title: params.title || 'testIndexPattern', + type: params.type || '', + fields: params.fields || [], + }; +}; + +export class IndexPattern implements StaticIndexPattern { + [key: string]: any; + + public id?: string; + public title: string = ''; + public type: string = ''; + public fieldFormatMap: any; + public typeMeta: any; + public fields: FieldList; + public timeFieldName: string | undefined; + public formatHit: any; + public flattenHit: any; + + private version: string | undefined; + private savedObjectsClient: SavedObjectsClient; + private patternCache: any; + private getConfig: any; + private sourceFilters: [] = []; + private originalBody: { [key: string]: any } = {}; + private fieldsFetcher: any; + private shortDotsEnable: boolean = false; + + private mapping: MappingObject = expandShorthand({ + title: 'text', + timeFieldName: 'keyword', + intervalName: 'keyword', + fields: 'json', + sourceFilters: 'json', + fieldFormatMap: { + type: 'text', + _serialize: (map = {}) => { + const serialized = _.transform(map, this.serializeFieldFormatMap); + return _.isEmpty(serialized) ? undefined : JSON.stringify(serialized); + }, + _deserialize: (map = '{}') => { + return _.mapValues(JSON.parse(map), mapping => { + return this.deserializeFieldFormatMap(mapping); + }); + }, + }, + type: 'keyword', + typeMeta: 'json', + }); + + constructor( + id: string | undefined, + getConfig: any, + savedObjectsClient: SavedObjectsClient, + apiClient: IndexPatternsApiClient, + patternCache: any + ) { + this.id = id; + this.savedObjectsClient = savedObjectsClient; + this.patternCache = patternCache; + // instead of storing config we rather store the getter only as np uiSettingsClient has circular references + // which cause problems when being consumed from angular + this.getConfig = getConfig; + + this.shortDotsEnable = this.getConfig('shortDots:enable'); + + this.fields = new FieldList(this, [], this.shortDotsEnable); + this.fieldsFetcher = createFieldsFetcher(this, apiClient, this.getConfig('metaFields')); + this.flattenHit = flattenHitWrapper(this, this.getConfig('metaFields')); + this.formatHit = formatHitProvider(this, fieldFormats.getDefaultInstance('string')); + this.formatField = this.formatHit.formatField; + } + + private serializeFieldFormatMap(flat: any, format: string, field: string | undefined) { + if (format && field) { + flat[field] = format; + } + } + + private deserializeFieldFormatMap(mapping: any) { + const FieldFormat = fieldFormats.byId[mapping.id]; + return FieldFormat && new FieldFormat(mapping.params, this.getConfig); + } + + private initFields(input?: any) { + const newValue = input || this.fields; + this.fields = new FieldList(this, newValue, this.shortDotsEnable); + } + + private isFieldRefreshRequired(): boolean { + if (!this.fields) { + return true; + } + + return this.fields.every(field => { + // See https://github.com/elastic/kibana/pull/8421 + const hasFieldCaps = 'aggregatable' in field && 'searchable' in field; + + // See https://github.com/elastic/kibana/pull/11969 + const hasDocValuesFlag = 'readFromDocValues' in field; + + return !hasFieldCaps || !hasDocValuesFlag; + }); + } + + private async indexFields(forceFieldRefresh: boolean = false) { + if (!this.id) { + return; + } + + if (forceFieldRefresh || this.isFieldRefreshRequired()) { + await this.refreshFields(); + } + + this.initFields(); + } + + private updateFromElasticSearch(response: any, forceFieldRefresh: boolean = false) { + if (!response.found) { + throw new SavedObjectNotFound(type, this.id, '#/management/kibana/index_pattern'); + } + + _.forOwn(this.mapping, (fieldMapping: FieldMappingSpec, name: string | undefined) => { + if (!fieldMapping._deserialize || !name) { + return; + } + response._source[name] = fieldMapping._deserialize(response._source[name]); + }); + + // give index pattern all of the values in _source + _.assign(this, response._source); + + if (!this.title && this.id) { + this.title = this.id; + } + + return this.indexFields(forceFieldRefresh); + } + + get routes() { + return getRoutes(); + } + + getComputedFields() { + const scriptFields: any = {}; + if (!this.fields) { + return { + storedFields: ['*'], + scriptFields, + docvalueFields: [], + }; + } + + // Date value returned in "_source" could be in any number of formats + // Use a docvalue for each date field to ensure standardized formats when working with date fields + // indexPattern.flattenHit will override "_source" values when the same field is also defined in "fields" + const docvalueFields = reject(this.fields.byType.date, 'scripted').map((dateField: any) => { + return { + field: dateField.name, + format: + dateField.esTypes && dateField.esTypes.indexOf('date_nanos') !== -1 + ? 'strict_date_time' + : 'date_time', + }; + }); + + each(this.getScriptedFields(), function(field) { + scriptFields[field.name] = { + script: { + source: field.script, + lang: field.lang, + }, + }; + }); + + return { + storedFields: ['*'], + scriptFields, + docvalueFields, + }; + } + + async init(forceFieldRefresh = false) { + if (!this.id) { + return this; // no id === no elasticsearch document + } + + const savedObject = await this.savedObjectsClient.get(type, this.id); + this.version = savedObject._version; + + const response = { + _id: savedObject.id, + _type: savedObject.type, + _source: _.cloneDeep(savedObject.attributes), + found: savedObject._version ? true : false, + }; + // Do this before we attempt to update from ES since that call can potentially perform a save + this.originalBody = this.prepBody(); + await this.updateFromElasticSearch(response, forceFieldRefresh); + // Do it after to ensure we have the most up to date information + this.originalBody = this.prepBody(); + + return this; + } + + // Get the source filtering configuration for that index. + getSourceFiltering() { + return { + excludes: (this.sourceFilters && this.sourceFilters.map((filter: any) => filter.value)) || [], + }; + } + + async addScriptedField(name: string, script: string, fieldType: string = 'string', lang: string) { + const scriptedFields = this.getScriptedFields(); + const names = _.pluck(scriptedFields, 'name'); + + if (_.contains(names, name)) { + throw new DuplicateField(name); + } + + this.fields.push( + new Field(this, { + name, + script, + fieldType, + scripted: true, + lang, + aggregatable: true, + filterable: true, + searchable: true, + }) + ); + + await this.save(); + } + + removeScriptedField(name: string) { + const fieldIndex = _.findIndex(this.fields, { + name, + scripted: true, + }); + + if (fieldIndex > -1) { + this.fields.splice(fieldIndex, 1); + delete this.fieldFormatMap[name]; + return this.save(); + } + } + + async popularizeField(fieldName: string, unit = 1) { + const field = this.fields.byName[fieldName]; + if (!field) { + return; + } + const count = Math.max((field.count || 0) + unit, 0); + if (field.count === count) { + return; + } + field.count = count; + await this.save(); + } + + getNonScriptedFields() { + return _.where(this.fields, { scripted: false }); + } + + getScriptedFields() { + return _.where(this.fields, { scripted: true }); + } + + isTimeBased(): boolean { + return !!this.timeFieldName && (!this.fields || !!this.getTimeField()); + } + + isTimeNanosBased(): boolean { + const timeField: any = this.getTimeField(); + return timeField && timeField.esTypes && timeField.esTypes.indexOf('date_nanos') !== -1; + } + + isTimeBasedWildcard(): boolean { + return this.isTimeBased() && this.isWildcard(); + } + + getTimeField() { + if (!this.timeFieldName || !this.fields || !this.fields.byName) return; + return this.fields.byName[this.timeFieldName]; + } + + isWildcard() { + return _.includes(this.title, '*'); + } + + prepBody() { + const body: { [key: string]: any } = {}; + + // serialize json fields + _.forOwn(this.mapping, (fieldMapping, fieldName) => { + if (!fieldName || this[fieldName] == null) return; + + body[fieldName] = fieldMapping._serialize + ? fieldMapping._serialize(this[fieldName]) + : this[fieldName]; + }); + + return body; + } + + async create(allowOverride: boolean = false) { + const _create = async (duplicateId?: string) => { + if (duplicateId) { + const duplicatePattern = new IndexPattern( + duplicateId, + this.getConfig, + this.savedObjectsClient, + this.patternCache, + this.fieldsFetcher + ); + await duplicatePattern.destroy(); + } + + const body = this.prepBody(); + const response = await this.savedObjectsClient.create(type, body, { id: this.id }); + + this.id = response.id; + return response.id; + }; + + const potentialDuplicateByTitle = await findObjectByTitle( + this.savedObjectsClient, + type, + this.title + ); + // If there is potentially duplicate title, just create it + if (!potentialDuplicateByTitle) { + return await _create(); + } + + // We found a duplicate but we aren't allowing override, show the warn modal + if (!allowOverride) { + return false; + } + + return await _create(potentialDuplicateByTitle.id); + } + + async save(saveAttempts = 0): Promise { + if (!this.id) return; + const body = this.prepBody(); + // What keys changed since they last pulled the index pattern + const originalChangedKeys = Object.keys(body).filter( + key => body[key] !== this.originalBody[key] + ); + return this.savedObjectsClient + .update(type, this.id, body, { version: this.version }) + .then((resp: any) => { + this.id = resp.id; + this.version = resp._version; + }) + .catch(err => { + if ( + _.get(err, 'res.status') === 409 && + saveAttempts++ < MAX_ATTEMPTS_TO_RESOLVE_CONFLICTS + ) { + const samePattern = new IndexPattern( + this.id, + this.getConfig, + this.savedObjectsClient, + this.patternCache, + this.fieldsFetcher + ); + return samePattern.init().then(() => { + // What keys changed from now and what the server returned + const updatedBody = samePattern.prepBody(); + + // Build a list of changed keys from the server response + // and ensure we ignore the key if the server response + // is the same as the original response (since that is expected + // if we made a change in that key) + const serverChangedKeys = Object.keys(updatedBody).filter(key => { + return updatedBody[key] !== body[key] && this.originalBody[key] !== updatedBody[key]; + }); + + let unresolvedCollision = false; + for (const originalKey of originalChangedKeys) { + for (const serverKey of serverChangedKeys) { + if (originalKey === serverKey) { + unresolvedCollision = true; + break; + } + } + } + + if (unresolvedCollision) { + const message = i18n.translate( + 'common.ui.indexPattern.unableWriteLabel', + { + defaultMessage: + 'Unable to write index pattern! Refresh the page to get the most up to date changes for this index pattern.', + } // eslint-disable-line max-len + ); + toastNotifications.addDanger(message); + throw err; + } + + // Set the updated response on this object + serverChangedKeys.forEach(key => { + this[key] = samePattern[key]; + }); + this.version = samePattern.version; + + // Clear cache + this.patternCache.clear(this.id); + + // Try the save again + return this.save(saveAttempts); + }); + } + throw err; + }); + } + + async _fetchFields() { + const fields = await this.fieldsFetcher.fetch(this); + const scripted = this.getScriptedFields(); + const all = fields.concat(scripted); + await this.initFields(all); + } + + refreshFields() { + return this._fetchFields() + .then(() => this.save()) + .catch(err => { + // https://github.com/elastic/kibana/issues/9224 + // This call will attempt to remap fields from the matching + // ES index which may not actually exist. In that scenario, + // we still want to notify the user that there is a problem + // but we do not want to potentially make any pages unusable + // so do not rethrow the error here + if (err instanceof IndexPatternMissingIndices) { + toastNotifications.addDanger((err as any).message); + return []; + } + + toastNotifications.addError(err, { + title: i18n.translate('common.ui.indexPattern.fetchFieldErrorTitle', { + defaultMessage: 'Error fetching fields', + }), + }); + throw err; + }); + } + + toJSON() { + return this.id; + } + + toString() { + return '' + this.toJSON(); + } + + destroy() { + this.patternCache.clear(this.id); + if (this.id) { + return this.savedObjectsClient.delete(type, this.id); + } + } +} diff --git a/src/legacy/ui/public/index_patterns/_pattern_cache.js b/src/legacy/ui/public/index_patterns/_pattern_cache.ts similarity index 72% rename from src/legacy/ui/public/index_patterns/_pattern_cache.js rename to src/legacy/ui/public/index_patterns/_pattern_cache.ts index 0ace69d1ec8b2..31dbadcde3838 100644 --- a/src/legacy/ui/public/index_patterns/_pattern_cache.js +++ b/src/legacy/ui/public/index_patterns/_pattern_cache.ts @@ -18,28 +18,23 @@ */ export function createIndexPatternCache() { + const vals: any = {}; + const cache: any = {}; - const vals = {}; - const cache = {}; - - const validId = function (id) { - return typeof id !== 'object'; - }; - - cache.get = function (id) { - if (validId(id)) return vals[id]; + cache.get = function(id: string) { + return vals[id]; }; - cache.set = function (id, prom) { - if (validId(id)) vals[id] = prom; + cache.set = function(id: string, prom: any) { + vals[id] = prom; return prom; }; - cache.clear = cache.delete = function (id) { - if (validId(id)) delete vals[id]; + cache.clear = cache.delete = function(id: string) { + delete vals[id]; }; - cache.clearAll = function () { + cache.clearAll = function() { for (const id in vals) { if (vals.hasOwnProperty(id)) { delete vals[id]; diff --git a/src/legacy/ui/public/index_patterns/components/index_pattern_select.js b/src/legacy/ui/public/index_patterns/components/index_pattern_select.tsx similarity index 73% rename from src/legacy/ui/public/index_patterns/components/index_pattern_select.js rename to src/legacy/ui/public/index_patterns/components/index_pattern_select.tsx index 980b356ff581e..e8e5f8c08278f 100644 --- a/src/legacy/ui/public/index_patterns/components/index_pattern_select.js +++ b/src/legacy/ui/public/index_patterns/components/index_pattern_select.tsx @@ -18,24 +18,38 @@ */ import _ from 'lodash'; -import PropTypes from 'prop-types'; import React, { Component } from 'react'; import chrome from 'ui/chrome'; import { EuiComboBox } from '@elastic/eui'; -const getIndexPatterns = async (search, fields) => { +interface IndexPatternSelectProps { + onChange: (opt: any) => void; + indexPatternId: string; + placeholder: string; + fieldTypes: string[]; + onNoIndexPatterns: () => void; +} + +interface IndexPatternSelectState { + isLoading: boolean; + options: []; + selectedIndexPattern: string | undefined; + searchValue: string | undefined; +} + +const getIndexPatterns = async (search: string, fields: string[]) => { const resp = await chrome.getSavedObjectsClient().find({ type: 'index-pattern', fields, search: `${search}*`, - search_fields: ['title'], - perPage: 100 + searchFields: ['title'], + perPage: 100, }); return resp.savedObjects; }; -const getIndexPatternTitle = async (indexPatternId) => { +const getIndexPatternTitle = async (indexPatternId: string) => { const savedObject = await chrome.getSavedObjectsClient().get('index-pattern', indexPatternId); if (savedObject.error) { throw new Error(`Unable to get index-pattern title: ${savedObject.error.message}`); @@ -43,8 +57,11 @@ const getIndexPatternTitle = async (indexPatternId) => { return savedObject.attributes.title; }; -export class IndexPatternSelect extends Component { - constructor(props) { +export class IndexPatternSelect extends Component { + private isMounted: boolean = false; + state: IndexPatternSelectState; + + constructor(props: IndexPatternSelectProps) { super(props); this.state = { @@ -56,26 +73,26 @@ export class IndexPatternSelect extends Component { } componentWillUnmount() { - this._isMounted = false; + this.isMounted = false; this.debouncedFetch.cancel(); } componentDidMount() { - this._isMounted = true; + this.isMounted = true; this.fetchOptions(); this.fetchSelectedIndexPattern(this.props.indexPatternId); } - componentWillReceiveProps(nextProps) { + componentWillReceiveProps(nextProps: IndexPatternSelectProps) { if (nextProps.indexPatternId !== this.props.indexPatternId) { this.fetchSelectedIndexPattern(nextProps.indexPatternId); } } - fetchSelectedIndexPattern = async (indexPatternId) => { + fetchSelectedIndexPattern = async (indexPatternId: string) => { if (!indexPatternId) { this.setState({ - selectedIndexPattern: undefined + selectedIndexPattern: undefined, }); return; } @@ -88,7 +105,7 @@ export class IndexPatternSelect extends Component { return; } - if (!this._isMounted) { + if (!this.isMounted) { return; } @@ -96,11 +113,11 @@ export class IndexPatternSelect extends Component { selectedIndexPattern: { value: indexPatternId, label: indexPatternTitle, - } + }, }); - } + }; - debouncedFetch = _.debounce(async (searchValue) => { + debouncedFetch = _.debounce(async (searchValue: string) => { const { fieldTypes, onNoIndexPatterns } = this.props; const savedObjectFields = ['title']; @@ -112,9 +129,9 @@ export class IndexPatternSelect extends Component { if (fieldTypes) { savedObjects = savedObjects.filter(savedObject => { try { - const indexPatternFields = JSON.parse(savedObject.attributes.fields); - return indexPatternFields.some(({ type }) => { - return fieldTypes.includes(type); + const indexPatternFields = JSON.parse(savedObject.attributes.fields as any); + return indexPatternFields.some((field: any) => { + return fieldTypes.includes(field.type); }); } catch (err) { // Unable to parse fields JSON, invalid index pattern @@ -123,17 +140,17 @@ export class IndexPatternSelect extends Component { }); } - if (!this._isMounted) { + if (!this.isMounted) { return; } // We need this check to handle the case where search results come back in a different // order than they were sent out. Only load results for the most recent search. if (searchValue === this.state.searchValue) { - const options = savedObjects.map((indexPatternSavedObject) => { + const options = savedObjects.map(indexPatternSavedObject => { return { label: indexPatternSavedObject.attributes.title, - value: indexPatternSavedObject.id + value: indexPatternSavedObject.id, }; }); this.setState({ @@ -148,15 +165,18 @@ export class IndexPatternSelect extends Component { }, 300); fetchOptions = (searchValue = '') => { - this.setState({ - isLoading: true, - searchValue - }, this.debouncedFetch.bind(null, searchValue)); - } + this.setState( + { + isLoading: true, + searchValue, + }, + this.debouncedFetch.bind(null, searchValue) + ); + }; - onChange = (selectedOptions) => { + onChange = (selectedOptions: any) => { this.props.onChange(_.get(selectedOptions, '0.value')); - } + }; render() { const { @@ -182,18 +202,3 @@ export class IndexPatternSelect extends Component { ); } } - -IndexPatternSelect.propTypes = { - onChange: PropTypes.func.isRequired, - indexPatternId: PropTypes.string, - placeholder: PropTypes.string, - /** - * Filter index patterns to only those that include the field types - */ - fieldTypes: PropTypes.arrayOf(PropTypes.string), - /** - * Callback called when there are no Kibana index patterns (or none that match the field types filter). - * Does not get called when user provided index pattern title search does match any index patterns. - */ - onNoIndexPatterns: PropTypes.func, -}; diff --git a/src/legacy/ui/public/index_patterns/constants/index.js b/src/legacy/ui/public/index_patterns/constants/index.ts similarity index 95% rename from src/legacy/ui/public/index_patterns/constants/index.js rename to src/legacy/ui/public/index_patterns/constants/index.ts index b22c1682173ca..716e59c25309e 100644 --- a/src/legacy/ui/public/index_patterns/constants/index.js +++ b/src/legacy/ui/public/index_patterns/constants/index.ts @@ -18,4 +18,6 @@ */ export const INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE = ['\\', '/', '?', '"', '<', '>', '|']; -export const INDEX_PATTERN_ILLEGAL_CHARACTERS = INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE.concat(' '); +export const INDEX_PATTERN_ILLEGAL_CHARACTERS = INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE.concat( + ' ' +); diff --git a/src/legacy/ui/public/index_patterns/errors.js b/src/legacy/ui/public/index_patterns/errors.ts similarity index 71% rename from src/legacy/ui/public/index_patterns/errors.js rename to src/legacy/ui/public/index_patterns/errors.ts index ad3e91ca749f7..31d632ae5c5dd 100644 --- a/src/legacy/ui/public/index_patterns/errors.js +++ b/src/legacy/ui/public/index_patterns/errors.ts @@ -16,18 +16,17 @@ * specific language governing permissions and limitations * under the License. */ - -import { KbnError } from 'ui/errors'; +/* eslint-disable */ +// @ts-ignore +import { KbnError } from '../errors'; /** * when a mapping already exists for a field the user is attempting to add * @param {String} name - the field name */ export class IndexPatternAlreadyExists extends KbnError { - constructor(name) { - super( - `An index pattern of "${name}" already exists`, - IndexPatternAlreadyExists); + constructor(name: string) { + super(`An index pattern of "${name}" already exists`, IndexPatternAlreadyExists); } } @@ -35,12 +34,13 @@ export class IndexPatternAlreadyExists extends KbnError { * Tried to call a method that relies on SearchSource having an indexPattern assigned */ export class IndexPatternMissingIndices extends KbnError { - constructor(message) { - const defaultMessage = 'IndexPattern\'s configured pattern does not match any indices'; + constructor(message: string) { + const defaultMessage = "IndexPattern's configured pattern does not match any indices"; super( - (message && message.length) ? `No matching indices found: ${message}` : defaultMessage, - IndexPatternMissingIndices); + message && message.length ? `No matching indices found: ${message}` : defaultMessage, + IndexPatternMissingIndices + ); } } @@ -49,9 +49,7 @@ export class IndexPatternMissingIndices extends KbnError { */ export class NoDefinedIndexPatterns extends KbnError { constructor() { - super( - 'Define at least one index pattern to continue', - NoDefinedIndexPatterns); + super('Define at least one index pattern to continue', NoDefinedIndexPatterns); } } @@ -60,8 +58,6 @@ export class NoDefinedIndexPatterns extends KbnError { */ export class NoDefaultIndexPattern extends KbnError { constructor() { - super( - 'Please specify a default index pattern', - NoDefaultIndexPattern); + super('Please specify a default index pattern', NoDefaultIndexPattern); } } diff --git a/src/legacy/ui/public/index_patterns/fields_fetcher.js b/src/legacy/ui/public/index_patterns/fields_fetcher.js deleted file mode 100644 index ef543e8804ade..0000000000000 --- a/src/legacy/ui/public/index_patterns/fields_fetcher.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export class FieldsFetcher { - constructor(apiClient, metaFields) { - this.apiClient = apiClient; - this.metaFields = metaFields; - } - fetch(indexPattern, options) { - return this.fetchForWildcard(indexPattern.title, { - ...options, - type: indexPattern.type, - params: indexPattern.typeMeta && indexPattern.typeMeta.params, - }); - } - - fetchForWildcard(indexPatternId, options = {}) { - return this.apiClient.getFieldsForWildcard({ - pattern: indexPatternId, - metaFields: this.metaFields, - type: options.type, - params: options.params || {}, - }); - } -} diff --git a/src/legacy/ui/public/index_patterns/fields_fetcher.ts b/src/legacy/ui/public/index_patterns/fields_fetcher.ts new file mode 100644 index 0000000000000..d320bbd718d47 --- /dev/null +++ b/src/legacy/ui/public/index_patterns/fields_fetcher.ts @@ -0,0 +1,50 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + GetFieldsOptions, + IndexPatternsApiClient, +} from 'ui/index_patterns/index_patterns_api_client'; +import { IndexPattern } from './_index_pattern'; + +export const createFieldsFetcher = ( + indexPattern: IndexPattern, + apiClient: IndexPatternsApiClient, + metaFields: string +) => { + const fieldFetcher = { + fetch: (options: GetFieldsOptions) => { + return fieldFetcher.fetchForWildcard(indexPattern.title, { + ...options, + type: indexPattern.type, + params: indexPattern.typeMeta && indexPattern.typeMeta.params, + }); + }, + fetchForWildcard: (pattern: string, options: GetFieldsOptions = {}) => { + return apiClient.getFieldsForWildcard({ + pattern, + metaFields, + type: options.type, + params: options.params || {}, + }); + }, + }; + + return fieldFetcher; +}; diff --git a/src/legacy/ui/public/index_patterns/fixtures/index.ts b/src/legacy/ui/public/index_patterns/fixtures/index.ts index 0bbfdcf03be12..5c79d7f99f842 100644 --- a/src/legacy/ui/public/index_patterns/fixtures/index.ts +++ b/src/legacy/ui/public/index_patterns/fixtures/index.ts @@ -17,9 +17,10 @@ * under the License. */ -import { Field, IndexPattern } from '../index'; +import { FieldType } from '../_field'; +import { StaticIndexPattern } from '../_index_pattern'; -export const mockFields: Field[] = [ +export const mockFields: FieldType[] = [ { name: 'machine.os', esTypes: ['text'], @@ -78,7 +79,7 @@ export const mockFields: Field[] = [ }, ]; -export const mockIndexPattern: IndexPattern = { +export const mockIndexPattern: StaticIndexPattern = { id: 'logstash-*', fields: mockFields, title: 'logstash-*', diff --git a/src/legacy/ui/public/index_patterns/get_routes.js b/src/legacy/ui/public/index_patterns/get_routes.ts similarity index 98% rename from src/legacy/ui/public/index_patterns/get_routes.js rename to src/legacy/ui/public/index_patterns/get_routes.ts index 9c29638483c90..52d42ea204532 100644 --- a/src/legacy/ui/public/index_patterns/get_routes.js +++ b/src/legacy/ui/public/index_patterns/get_routes.ts @@ -23,6 +23,6 @@ export function getRoutes() { addField: '/management/kibana/index_patterns/{{id}}/create-field', indexedFields: '/management/kibana/index_patterns/{{id}}?_a=(tab:indexedFields)', scriptedFields: '/management/kibana/index_patterns/{{id}}?_a=(tab:scriptedFields)', - sourceFilters: '/management/kibana/index_patterns/{{id}}?_a=(tab:sourceFilters)' + sourceFilters: '/management/kibana/index_patterns/{{id}}?_a=(tab:sourceFilters)', }; } diff --git a/src/legacy/ui/public/index_patterns/index.d.ts b/src/legacy/ui/public/index_patterns/index.d.ts deleted file mode 100644 index e2d7ddd8c5254..0000000000000 --- a/src/legacy/ui/public/index_patterns/index.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { - IndexPattern, - StaticIndexPattern, - StaticIndexPatternField, -} from 'ui/index_patterns/_index_pattern'; -export { Field } from 'ui/index_patterns/_field'; diff --git a/src/legacy/ui/public/index_patterns/index.js b/src/legacy/ui/public/index_patterns/index.ts similarity index 90% rename from src/legacy/ui/public/index_patterns/index.js rename to src/legacy/ui/public/index_patterns/index.ts index 25bd04dc70f29..0a3e3e650b83c 100644 --- a/src/legacy/ui/public/index_patterns/index.js +++ b/src/legacy/ui/public/index_patterns/index.ts @@ -18,7 +18,8 @@ */ export { IndexPatternSelect } from './components/index_pattern_select'; - +export { Field, FieldType } from './_field'; +export { IndexPattern, StaticIndexPattern } from './_index_pattern'; export { IndexPatterns, IndexPatternsProvider } from './index_patterns'; export { diff --git a/src/legacy/ui/public/index_patterns/index_patterns.js b/src/legacy/ui/public/index_patterns/index_patterns.js deleted file mode 100644 index 72e8c3dacd858..0000000000000 --- a/src/legacy/ui/public/index_patterns/index_patterns.js +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { fieldFormats } from '../registry/field_formats'; - -import { IndexPatternMissingIndices } from './errors'; -import { IndexPattern } from './_index_pattern'; -import { createIndexPatternCache } from './_pattern_cache'; -import { indexPatternsGetProvider } from './_get'; -import { FieldsFetcher } from './fields_fetcher'; -import { IndexPatternsApiClient } from './index_patterns_api_client'; - -export class IndexPatterns { - constructor(config, savedObjectsClient) { - const getProvider = indexPatternsGetProvider(savedObjectsClient); - const apiClient = new IndexPatternsApiClient(); - - this.config = config; - this.savedObjectsClient = savedObjectsClient; - - this.errors = { - MissingIndices: IndexPatternMissingIndices - }; - - this.fieldsFetcher = new FieldsFetcher(apiClient, config.get('metaFields')); - this.cache = createIndexPatternCache(); - this.getIds = getProvider('id'); - this.getTitles = getProvider('attributes.title'); - this.getFields = getProvider.multiple; - this.fieldFormats = fieldFormats; - } - - - get = (id) => { - if (!id) return this.make(); - - const cache = this.cache.get(id); - return cache || this.cache.set(id, this.make(id)); - }; - - getDefault = async () => { - const defaultIndexPatternId = this.config.get('defaultIndex'); - if (defaultIndexPatternId) { - return await this.get(defaultIndexPatternId); - } - - return null; - }; - - make = (id) => { - return (new IndexPattern(id, - cfg => this.config.get(cfg), - this.savedObjectsClient, - this.cache, - this.fieldsFetcher, - this.getIds, - )).init(); - }; - - delete = (pattern) => { - this.getIds.clearCache(); - return pattern.destroy(); - }; -} - -// add angular service for backward compatibility -import { uiModules } from '../modules'; -const module = uiModules.get('kibana/index_patterns'); -let _service; -module.service('indexPatterns', function (chrome) { - if (!_service) _service = new IndexPatterns(chrome.getUiSettingsClient(), chrome.getSavedObjectsClient()); - return _service; -}); - -export const IndexPatternsProvider = (chrome) => { - if (!_service) _service = new IndexPatterns(chrome.getUiSettingsClient(), chrome.getSavedObjectsClient()); - return _service; -}; diff --git a/src/legacy/ui/public/index_patterns/index_patterns.ts b/src/legacy/ui/public/index_patterns/index_patterns.ts new file mode 100644 index 0000000000000..d0642286b9bdc --- /dev/null +++ b/src/legacy/ui/public/index_patterns/index_patterns.ts @@ -0,0 +1,119 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// @ts-ignore +import { fieldFormats } from '../registry/field_formats'; + +import { IndexPattern } from './_index_pattern'; +import { createIndexPatternCache } from './_pattern_cache'; +import { IndexPatternsApiClient } from './index_patterns_api_client'; +import { SavedObjectsClient, SimpleSavedObject } from '../saved_objects'; +import { UiSettingsClient } from '../../../../../target/types/public/ui_settings'; +import { SavedObjectAttributes } from '../../../../../target/types/server/saved_objects/service'; + +const indexPatternCache = createIndexPatternCache(); +const apiClient = new IndexPatternsApiClient(); + +export class IndexPatterns { + fieldFormats: fieldFormats; + + private config: UiSettingsClient; + private savedObjectsClient: SavedObjectsClient; + private savedObjectsCache?: Array> | null; + + constructor(config: UiSettingsClient, savedObjectsClient: SavedObjectsClient) { + this.config = config; + this.savedObjectsClient = savedObjectsClient; + } + + private async loadSavedObjects() { + this.savedObjectsCache = (await this.savedObjectsClient.find({ + type: 'index-pattern', + fields: [], + perPage: 10000, + })).savedObjects; + } + + getIds = async (refresh: boolean) => { + if (!this.savedObjectsCache || refresh) { + await this.loadSavedObjects(); + } + if (this.savedObjectsCache) { + return this.savedObjectsCache.map(obj => _.get(obj, 'id')); + } + }; + + getTitles = async (refresh: boolean) => { + if (!this.savedObjectsCache || refresh) { + await this.loadSavedObjects(); + } + if (this.savedObjectsCache) { + return this.savedObjectsCache.map(obj => _.get(obj, 'title')); + } + }; + + clearCache = () => { + this.savedObjectsCache = null; + indexPatternCache.clearAll(); + }; + + getDefault = async () => { + const defaultIndexPatternId = this.config.get('defaultIndex'); + if (defaultIndexPatternId) { + return await this.get(defaultIndexPatternId); + } + + return null; + }; + + get = (id?: string) => { + if (!id) return this.make(); + + const cache = indexPatternCache.get(id); + return cache || indexPatternCache.set(id, this.make(id)); + }; + + make = (id?: string) => { + return new IndexPattern( + id, + (cfg: any) => this.config.get(cfg), + this.savedObjectsClient, + apiClient, + indexPatternCache + ).init(); + }; +} + +// add angular service for backward compatibility +// @ts-ignore +import { uiModules } from '../modules'; + +const module = uiModules.get('kibana/index_patterns'); +let _service: any; +module.service('indexPatterns', function(chrome: any) { + if (!_service) + _service = new IndexPatterns(chrome.getUiSettingsClient(), chrome.getSavedObjectsClient()); + return _service; +}); + +export const IndexPatternsProvider = (chrome: any) => { + if (!_service) + _service = new IndexPatterns(chrome.getUiSettingsClient(), chrome.getSavedObjectsClient()); + return _service; +}; diff --git a/src/legacy/ui/public/index_patterns/index_patterns_api_client.js b/src/legacy/ui/public/index_patterns/index_patterns_api_client.ts similarity index 57% rename from src/legacy/ui/public/index_patterns/index_patterns_api_client.js rename to src/legacy/ui/public/index_patterns/index_patterns_api_client.ts index 036bc6e239cc7..ae71157aea829 100644 --- a/src/legacy/ui/public/index_patterns/index_patterns_api_client.js +++ b/src/legacy/ui/public/index_patterns/index_patterns_api_client.ts @@ -17,71 +17,66 @@ * under the License. */ -import { kfetch } from '../kfetch'; +import { kfetch, KFetchQuery } from '../kfetch'; import { IndexPatternMissingIndices } from './errors'; -function join(...uriComponents) { - return uriComponents.filter(Boolean).map(encodeURIComponent).join('/'); -} - -function request(method, url, query, body) { +function request(url: string, query: KFetchQuery) { return kfetch({ - method, + method: 'GET', pathname: url, query, - body, - }) - .catch((resp) => { - if (resp.body.statusCode === 404 && resp.body.statuscode === 'no_matching_indices') { - throw new IndexPatternMissingIndices(resp.body.message); - } + }).catch(resp => { + if (resp.body.statusCode === 404 && resp.body.statuscode === 'no_matching_indices') { + throw new IndexPatternMissingIndices(resp.body.message); + } + + throw new Error(resp.body.message || resp.body.error || `${resp.body.statusCode} Response`); + }); +} - const err = new Error(resp.body.message || resp.body.error || `${resp.body.statusCode} Response`); - err.status = resp.body.statusCode; - err.body = resp.body.message; - throw err; - }); +const API_BASE_URL: string = `/api/index_patterns/`; + +export interface GetFieldsOptions { + pattern?: string; + type?: string; + params?: any; + lookBack?: boolean; + metaFields?: string; } export class IndexPatternsApiClient { - constructor() { - this.apiBaseUrl = `/api/index_patterns/`; - } + constructor() {} - _getUrl(path) { - return this.apiBaseUrl + join(...path); + _getUrl(path: string[]) { + return ( + API_BASE_URL + + path + .filter(Boolean) + .map(encodeURIComponent) + .join('/') + ); } - - getFieldsForTimePattern(options = {}) { - const { - pattern, - lookBack, - metaFields, - } = options; + getFieldsForTimePattern(options: GetFieldsOptions = {}) { + const { pattern, lookBack, metaFields } = options; const url = this._getUrl(['_fields_for_time_pattern']); - return request('GET', url, { + return request(url, { pattern, look_back: lookBack, meta_fields: metaFields, }).then(resp => resp.fields); } - getFieldsForWildcard(options = {}) { - const { - pattern, - metaFields, - type, - params, - } = options; + getFieldsForWildcard(options: GetFieldsOptions = {}) { + const { pattern, metaFields, type, params } = options; let url; let query; - if(type) { + if (type) { url = this._getUrl([type, '_fields_for_wildcard']); query = { pattern, @@ -96,6 +91,6 @@ export class IndexPatternsApiClient { }; } - return request('GET', url, query).then(resp => resp.fields); + return request(url, query).then(resp => resp.fields); } } diff --git a/src/legacy/ui/public/index_patterns/static_utils/index.d.ts b/src/legacy/ui/public/index_patterns/static_utils/index.d.ts deleted file mode 100644 index b833485971166..0000000000000 --- a/src/legacy/ui/public/index_patterns/static_utils/index.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Field, StaticIndexPattern } from 'ui/index_patterns'; - -export function isFilterable(field: Field): boolean; -export function getFromSavedObject(savedObject: any): StaticIndexPattern; diff --git a/src/legacy/ui/public/index_patterns/static_utils/index.js b/src/legacy/ui/public/index_patterns/static_utils/index.ts similarity index 72% rename from src/legacy/ui/public/index_patterns/static_utils/index.js rename to src/legacy/ui/public/index_patterns/static_utils/index.ts index bf07eacbbfe5c..7131ea300b97c 100644 --- a/src/legacy/ui/public/index_patterns/static_utils/index.js +++ b/src/legacy/ui/public/index_patterns/static_utils/index.ts @@ -17,18 +17,27 @@ * under the License. */ -import { KBN_FIELD_TYPES } from '../../../../utils/kbn_field_types'; +// @ts-ignore import { get } from 'lodash'; +// @ts-ignore +import { KBN_FIELD_TYPES } from '../../../../utils/kbn_field_types'; +import { Field } from '../_field'; -const filterableTypes = KBN_FIELD_TYPES.filter(type => type.filterable).map(type => type.name); +const filterableTypes = KBN_FIELD_TYPES.filter((type: any) => type.filterable).map( + (type: any) => type.name +); -export function isFilterable(field) { - return field.name === '_id' || field.scripted || (field.searchable && filterableTypes.includes(field.type)); +export function isFilterable(field: Field): boolean { + return ( + field.name === '_id' || + field.scripted || + (field.searchable && filterableTypes.includes(field.type)) + ); } -export function getFromSavedObject(savedObject) { +export function getFromSavedObject(savedObject: any) { if (get(savedObject, 'attributes.fields') === undefined) { - return null; + return; } return { diff --git a/src/legacy/ui/public/index_patterns/validate/index.js b/src/legacy/ui/public/index_patterns/validate/index.ts similarity index 100% rename from src/legacy/ui/public/index_patterns/validate/index.js rename to src/legacy/ui/public/index_patterns/validate/index.ts diff --git a/src/legacy/ui/public/index_patterns/validate/validate_index_pattern.test.js b/src/legacy/ui/public/index_patterns/validate/validate_index_pattern.test.ts similarity index 92% rename from src/legacy/ui/public/index_patterns/validate/validate_index_pattern.test.js rename to src/legacy/ui/public/index_patterns/validate/validate_index_pattern.test.ts index bd141e5fb2b90..cfd4049c1398d 100644 --- a/src/legacy/ui/public/index_patterns/validate/validate_index_pattern.test.js +++ b/src/legacy/ui/public/index_patterns/validate/validate_index_pattern.test.ts @@ -32,9 +32,9 @@ describe('Index Pattern Validation', () => { }); it('should not allow illegal characters', () => { - INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE.forEach((char) => { + INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE.forEach(char => { const errors = validateIndexPattern(`pattern${char}`); - expect(errors[ILLEGAL_CHARACTERS]).toEqual([ char ]); + expect(errors[ILLEGAL_CHARACTERS]).toEqual([char]); }); }); diff --git a/src/legacy/ui/public/index_patterns/validate/validate_index_pattern.js b/src/legacy/ui/public/index_patterns/validate/validate_index_pattern.ts similarity index 78% rename from src/legacy/ui/public/index_patterns/validate/validate_index_pattern.js rename to src/legacy/ui/public/index_patterns/validate/validate_index_pattern.ts index 22e6cd167544c..f59d6d5abd89d 100644 --- a/src/legacy/ui/public/index_patterns/validate/validate_index_pattern.js +++ b/src/legacy/ui/public/index_patterns/validate/validate_index_pattern.ts @@ -22,24 +22,27 @@ import { INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE } from '../constants'; export const ILLEGAL_CHARACTERS = 'ILLEGAL_CHARACTERS'; export const CONTAINS_SPACES = 'CONTAINS_SPACES'; -function findIllegalCharacters(indexPattern) { - const illegalCharacters = INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE.reduce((chars, char) => { - if (indexPattern.includes(char)) { - chars.push(char); - } - - return chars; - }, []); +function findIllegalCharacters(indexPattern: string) { + const illegalCharacters = INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE.reduce( + (chars, char: string) => { + if (indexPattern.includes(char)) { + // @ts-ignore + chars.push(char); + } + return chars; + }, + [] + ); return illegalCharacters; } -function indexPatternContainsSpaces(indexPattern) { +function indexPatternContainsSpaces(indexPattern: string) { return indexPattern.includes(' '); } -export function validateIndexPattern(indexPattern) { - const errors = {}; +export function validateIndexPattern(indexPattern: string) { + const errors: any = {}; const illegalCharacters = findIllegalCharacters(indexPattern); diff --git a/src/legacy/ui/public/indices/constants/index.js b/src/legacy/ui/public/indices/constants/index.js index 8f15dcca096b2..3cf1f4ff0bcb0 100644 --- a/src/legacy/ui/public/indices/constants/index.js +++ b/src/legacy/ui/public/indices/constants/index.js @@ -17,7 +17,7 @@ * under the License. */ -import { INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/index_patterns'; +import { INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE } from '../../index_patterns/constants'; export const INDEX_ILLEGAL_CHARACTERS_VISIBLE = [ ...INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE, '*' ]; diff --git a/src/legacy/ui/public/indices/validate/validate_index.test.js b/src/legacy/ui/public/indices/validate/validate_index.test.js index c7732c58a316c..a13b09da35ed5 100644 --- a/src/legacy/ui/public/indices/validate/validate_index.test.js +++ b/src/legacy/ui/public/indices/validate/validate_index.test.js @@ -25,14 +25,6 @@ import { indexNameContainsSpaces, } from './validate_index'; -jest.mock('ui/index_patterns/index_patterns.js', () => ({ - IndexPatterns: jest.fn(), -})); - -jest.mock('ui/index_patterns/index_patterns_api_client.js', () => ({ - IndexPatternsApiClient: jest.fn(), -})); - describe('Index name validation', () => { it('should not allow name to begin with a period', () => { const beginsWithPeriod = indexNameBeginsWithPeriod('.system_index'); diff --git a/src/legacy/ui/public/timefilter/get_time.test.ts b/src/legacy/ui/public/timefilter/get_time.test.ts index 7360fcc7d0645..0602f61d003ec 100644 --- a/src/legacy/ui/public/timefilter/get_time.test.ts +++ b/src/legacy/ui/public/timefilter/get_time.test.ts @@ -43,7 +43,7 @@ describe('get_time', () => { filterable: true, }, ], - }, + } as any, { from: 'now-60y', to: 'now' } ) as Filter; expect(filter.range.date).to.eql({ diff --git a/src/legacy/ui/public/vis/editors/config/editor_config_providers.test.ts b/src/legacy/ui/public/vis/editors/config/editor_config_providers.test.ts index 187772f859e1f..d9234f23cd457 100644 --- a/src/legacy/ui/public/vis/editors/config/editor_config_providers.test.ts +++ b/src/legacy/ui/public/vis/editors/config/editor_config_providers.test.ts @@ -35,7 +35,7 @@ describe('EditorConfigProvider', () => { searchable: true, }, ], - }; + } as any; beforeEach(() => { registry = new EditorConfigProviderRegistry(); diff --git a/src/test_utils/public/stub_index_pattern.js b/src/test_utils/public/stub_index_pattern.js index e7afef2a94a4c..6c327a9425be7 100644 --- a/src/test_utils/public/stub_index_pattern.js +++ b/src/test_utils/public/stub_index_pattern.js @@ -20,9 +20,7 @@ import sinon from 'sinon'; import { IndexPattern } from 'ui/index_patterns/_index_pattern'; import { getRoutes } from 'ui/index_patterns/get_routes'; -import { formatHitProvider } from 'ui/index_patterns/_format_hit'; -import { getComputedFields } from 'ui/index_patterns/_get_computed_fields'; -import { fieldFormats } from 'ui/registry/field_formats'; +import { formatHitProvider } from 'ui/index_patterns/_format_hit'; import { fieldFormats } from 'ui/registry/field_formats'; import { flattenHitWrapper } from 'ui/index_patterns/_flatten_hit'; import { FieldList } from 'ui/index_patterns/_field_list'; @@ -41,7 +39,7 @@ export default function () { this.fieldFormatMap = {}; this.routes = getRoutes(); - this.getComputedFields = getComputedFields.bind(this); + this.getComputedFields = sinon.spy(IndexPattern.prototype.getComputedFields); this.flattenHit = flattenHitWrapper(this, this.metaFields); this.formatHit = formatHitProvider(this, fieldFormats.getDefaultInstance('string')); this.fieldsFetcher = { apiClient: { baseUrl: '' } }; diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/group_by.tsx b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/group_by.tsx index 9188bf7cadacb..77be28f8ca6ec 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/group_by.tsx +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/group_by.tsx @@ -7,14 +7,14 @@ import { EuiComboBox } from '@elastic/eui'; import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import React, { useCallback } from 'react'; -import { StaticIndexPatternField } from 'ui/index_patterns'; +import { FieldType } from 'ui/index_patterns'; import { MetricsExplorerOptions } from '../../containers/metrics_explorer/use_metrics_explorer_options'; interface Props { intl: InjectedIntl; options: MetricsExplorerOptions; onChange: (groupBy: string | null) => void; - fields: StaticIndexPatternField[]; + fields: FieldType[]; } export const MetricsExplorerGroupBy = injectI18n(({ intl, options, onChange, fields }: Props) => { diff --git a/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx b/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx index e70e79a18a66a..dd8f9d4098b77 100644 --- a/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx @@ -106,7 +106,7 @@ export const SnapshotToolbar = injectI18n(({ intl }) => ( groupBy={groupBy} nodeType={nodeType} onChange={changeGroupBy} - fields={derivedIndexPattern.fields} + fields={derivedIndexPattern.fields as any} onChangeCustomOptions={changeCustomOptions} customOptions={customOptions} /> diff --git a/x-pack/legacy/plugins/ml/public/components/full_time_range_selector/index.test.tsx b/x-pack/legacy/plugins/ml/public/components/full_time_range_selector/index.test.tsx index 41e8fa014907e..83c351d1e5da7 100644 --- a/x-pack/legacy/plugins/ml/public/components/full_time_range_selector/index.test.tsx +++ b/x-pack/legacy/plugins/ml/public/components/full_time_range_selector/index.test.tsx @@ -20,7 +20,7 @@ jest.mock('./full_time_range_selector_service', () => ({ })); describe('FullTimeRangeSelector', () => { - const indexPattern: IndexPattern = { + const indexPattern: any = { id: '0844fc70-5ab5-11e9-935e-836737467b0f', fields: [], title: 'test-index-pattern', diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.ts b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.ts index 1e1ecea8f62fb..ca97c9f247d7e 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.ts +++ b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.ts @@ -10,7 +10,7 @@ import React, { useEffect, useState } from 'react'; import { SearchResponse } from 'elasticsearch'; -import { IndexPattern } from 'ui/index_patterns'; +import { IndexPattern, StaticIndexPattern } from 'ui/index_patterns'; import { ml } from '../../../../../services/ml_api_service'; @@ -39,7 +39,7 @@ export interface UseSourceIndexDataReturnType { } export const useSourceIndexData = ( - indexPattern: IndexPattern, + indexPattern: IndexPattern | StaticIndexPattern, query: PivotQuery, selectedFields: EsFieldName[], setSelectedFields: React.Dispatch> diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/step_create_form.test.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/step_create_form.test.tsx index 9705fe3aef774..4a641244dfb49 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/step_create_form.test.tsx +++ b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/step_create_form.test.tsx @@ -10,6 +10,7 @@ import React from 'react'; import { KibanaContext } from '../../../../common'; import { StepCreateForm } from './step_create_form'; +import { IndexPattern } from 'ui/index_patterns'; // workaround to make React.memo() work with enzyme jest.mock('react', () => { @@ -27,11 +28,11 @@ describe('Data Frame: ', () => { onChange() {}, }; - const currentIndexPattern = { + const currentIndexPattern = ({ id: 'the-index-pattern-id', title: 'the-index-pattern-title', fields: [], - }; + } as any) as IndexPattern; // Using a wrapping
element because shallow() would fail // with the Provider being the outer most component. diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.test.ts b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.test.ts index 45280fee58a50..edd5637213c58 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.test.ts +++ b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.test.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IndexPattern } from 'ui/index_patterns'; - import { getPreviewRequestBody, PivotAggsConfig, @@ -22,7 +20,7 @@ describe('Data Frame: Define Pivot Common', () => { // The field name includes the characters []> as well as a leading and ending space charcter // which cannot be used for aggregation names. The test results verifies that the characters // should still be present in field and dropDownName values, but should be stripped for aggName values. - const indexPattern: IndexPattern = { + const indexPattern: any = { id: 'the-index-pattern-id', title: 'the-index-pattern-title', fields: [ diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/pivot_preview.test.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/pivot_preview.test.tsx index ca5a613eca334..9d18f5fdf6806 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/pivot_preview.test.tsx +++ b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/pivot_preview.test.tsx @@ -30,7 +30,7 @@ describe('Data Frame: ', () => { id: 'the-index-pattern-id', title: 'the-index-pattern-title', fields: [], - }; + } as any; const groupBy: PivotGroupByConfig = { agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_form.test.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_form.test.tsx index 03735a57169ad..223c6ada8c165 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_form.test.tsx +++ b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_form.test.tsx @@ -28,7 +28,7 @@ describe('Data Frame: ', () => { id: 'the-index-pattern-id', title: 'the-index-pattern-title', fields: [], - }; + } as any; // Using a wrapping
element because shallow() would fail // with the Provider being the outer most component. diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/use_pivot_preview_data.test.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/use_pivot_preview_data.test.tsx index b9dba2d455922..6748eba654a05 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/use_pivot_preview_data.test.tsx +++ b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/use_pivot_preview_data.test.tsx @@ -46,7 +46,7 @@ describe('usePivotPreviewData', () => { test('indexPattern not defined', () => { testHook(() => { pivotPreviewObj = usePivotPreviewData( - { id: 'the-id', title: 'the-title', fields: [] }, + { id: 'the-id', title: 'the-title', fields: [] } as any, query, {}, {} @@ -62,7 +62,7 @@ describe('usePivotPreviewData', () => { test('indexPattern set triggers loading', () => { testHook(() => { pivotPreviewObj = usePivotPreviewData( - { id: 'the-id', title: 'the-title', fields: [] }, + { id: 'the-id', title: 'the-title', fields: [] } as any, query, {}, {} From 23846c37e16adca5341a30adffc0e77db0977238 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Fri, 21 Jun 2019 17:08:35 -0600 Subject: [PATCH 02/20] Fix TS issue with IndexedArray interface. --- src/legacy/ui/public/index_patterns/_field_list.ts | 4 ---- src/legacy/ui/public/indexed_array/index.d.ts | 5 ++++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/legacy/ui/public/index_patterns/_field_list.ts b/src/legacy/ui/public/index_patterns/_field_list.ts index 5ce73880b8a31..2342db5c1df89 100644 --- a/src/legacy/ui/public/index_patterns/_field_list.ts +++ b/src/legacy/ui/public/index_patterns/_field_list.ts @@ -22,10 +22,6 @@ import { IndexPattern } from 'ui/index_patterns/_index_pattern'; import { Field, FieldSpec } from './_field'; export class FieldList extends IndexedArray { - // makes typescript work, but breaks kibana - //public byType: Record = {}; - //public byName: Record = {}; - constructor(indexPattern: IndexPattern, specs: FieldSpec[], shortDotsEnable: boolean = false) { super({ index: ['name'], diff --git a/src/legacy/ui/public/indexed_array/index.d.ts b/src/legacy/ui/public/indexed_array/index.d.ts index 9041a35cb3ab0..21c0a818731ac 100644 --- a/src/legacy/ui/public/indexed_array/index.d.ts +++ b/src/legacy/ui/public/indexed_array/index.d.ts @@ -30,8 +30,11 @@ interface IndexedArrayConfig { declare class IndexedArray extends Array { public immutable: boolean; public raw: T[]; - // May not actually be present, is dynamically defined. + + // These may not actually be present, as they are dynamically defined public inOrder: T[]; + public byType: Record; + public byName: Record; constructor(config: IndexedArrayConfig); From c98489ba04d514f24938bdec846baa9097b37cc6 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Fri, 21 Jun 2019 17:26:42 -0600 Subject: [PATCH 03/20] Tighten up types in the formatHitProvider. --- src/legacy/ui/public/index_patterns/_format_hit.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/legacy/ui/public/index_patterns/_format_hit.ts b/src/legacy/ui/public/index_patterns/_format_hit.ts index 8d85d78ed30a1..8f0243bc1924e 100644 --- a/src/legacy/ui/public/index_patterns/_format_hit.ts +++ b/src/legacy/ui/public/index_patterns/_format_hit.ts @@ -26,7 +26,7 @@ const partialFormattedCache = new WeakMap(); // Takes a hit, merges it with any stored/scripted fields, and with the metaFields // returns a formatted version export function formatHitProvider(indexPattern: IndexPattern, defaultFormat: any) { - function convert(hit: any, val: any, fieldName: string) { + function convert(hit: Record, val: any, fieldName: string) { const field = indexPattern.fields.byName[fieldName]; if (!field) return defaultFormat.convert(val, 'html'); const parsedUrl = { @@ -36,7 +36,7 @@ export function formatHitProvider(indexPattern: IndexPattern, defaultFormat: any return field.format.getConverterFor('html')(val, field, hit, parsedUrl); } - function formatHit(hit: any) { + function formatHit(hit: Record) { const cached = formattedCache.get(hit); if (cached) { return cached; @@ -47,10 +47,10 @@ export function formatHitProvider(indexPattern: IndexPattern, defaultFormat: any const partials = partialFormattedCache.get(hit) || {}; partialFormattedCache.set(hit, partials); - const cache = {} as any; + const cache: Record = {}; formattedCache.set(hit, cache); - _.forOwn(indexPattern.flattenHit(hit), function(val: any, fieldName: any) { + _.forOwn(indexPattern.flattenHit(hit), function(val: any, fieldName?: string) { // sync the formatted and partial cache if (!fieldName) { return; @@ -63,7 +63,7 @@ export function formatHitProvider(indexPattern: IndexPattern, defaultFormat: any return cache; } - formatHit.formatField = function(hit: any, fieldName: string) { + formatHit.formatField = function(hit: Record, fieldName: string) { let partials = partialFormattedCache.get(hit); if (partials && partials[fieldName] != null) { return partials[fieldName]; @@ -74,8 +74,7 @@ export function formatHitProvider(indexPattern: IndexPattern, defaultFormat: any partialFormattedCache.set(hit, partials); } - const val: any = - fieldName === '_source' ? hit._source : indexPattern.flattenHit(hit)[fieldName]; + const val = fieldName === '_source' ? hit._source : indexPattern.flattenHit(hit)[fieldName]; return convert(hit, val, fieldName); }; From dca0f0761e898f470178f287b7189ca16d2dc4a8 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Mon, 24 Jun 2019 11:44:21 +0200 Subject: [PATCH 04/20] fixes --- .../filter_state_manager.test.ts | 2 +- .../__jest__/step_time_field.test.js | 11 +++-- .../step_time_field/step_time_field.js | 7 ++- .../create_index_pattern_wizard.js | 2 +- .../edit_index_pattern/edit_index_pattern.js | 2 +- .../__jest__/objects_table.test.js | 2 +- .../components/objects_table/objects_table.js | 2 +- .../objects/lib/resolve_saved_objects.js | 2 +- src/legacy/ui/public/index_patterns/_field.ts | 4 +- .../public/index_patterns/_index_pattern.ts | 2 + .../public/index_patterns/_pattern_cache.ts | 47 ++++++++++--------- .../public/index_patterns/index_patterns.ts | 13 +++-- src/test_utils/public/stub_index_pattern.js | 3 +- .../auto_follow_pattern_form.test.js | 8 +++- .../auto_follow_pattern_validators.test.js | 8 +++- 15 files changed, 70 insertions(+), 45 deletions(-) diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/filter_state_manager.test.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/filter_state_manager.test.ts index b413efc0ba0f5..2d549f7c6697f 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/filter_state_manager.test.ts +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/filter_state_manager.test.ts @@ -57,7 +57,7 @@ describe('filter_state_manager', () => { appStateStub = new StubState(); globalStateStub = new StubState(); const indexPatterns = new StubIndexPatterns(); - filterManager = new FilterManager(indexPatterns); + filterManager = new FilterManager(indexPatterns as any); }); afterEach(() => { diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/__jest__/step_time_field.test.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/__jest__/step_time_field.test.js index 954cda4776256..ab6eef146c1b1 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/__jest__/step_time_field.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/__jest__/step_time_field.test.js @@ -35,13 +35,16 @@ jest.mock('ui/chrome', () => ({ const mockIndexPatternCreationType = { getIndexPatternType: () => 'default', - getIndexPatternName: () => 'name' + getIndexPatternName: () => 'name', + getFetchForWildcardOptions: () => {} }; const noop = () => {}; const indexPatternsService = { - fieldsFetcher: { - fetchForWildcard: noop, - } + make: async () => ({ + fieldsFetcher: { + fetch: noop + } + }) }; describe('StepTimeField', () => { diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.js index d500924376df3..4476ad868cbcf 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/step_time_field.js @@ -81,12 +81,15 @@ export class StepTimeFieldComponent extends Component { } fetchTimeFields = async () => { - const { indexPatternsService, indexPattern } = this.props; + const { indexPatternsService, indexPattern: pattern } = this.props; const { getFetchForWildcardOptions } = this.props.indexPatternCreationType; + const indexPattern = await indexPatternsService.make(); + indexPattern.title = pattern; + this.setState({ isFetchingTimeFields: true }); const fields = await ensureMinimumTime( - indexPatternsService.fieldsFetcher.fetchForWildcard(indexPattern, getFetchForWildcardOptions()) + indexPattern.fieldsFetcher.fetch(getFetchForWildcardOptions()) ); const timeFields = extractTimeFields(fields); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/create_index_pattern_wizard.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/create_index_pattern_wizard.js index 5bf791d4a662c..f12f9e9356ff0 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/create_index_pattern_wizard.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/create_index_pattern_wizard.js @@ -146,7 +146,7 @@ export class CreateIndexPatternWizard extends Component { await services.config.set('defaultIndex', createdId); } - services.indexPatterns.cache.clear(createdId); + services.indexPatterns.clearCache(createdId); services.changeUrl(`/management/kibana/index_patterns/${createdId}`); } diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js index a67c3ed995505..4e4443f6761b2 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js @@ -263,7 +263,7 @@ uiModules.get('apps/management') } } - Promise.resolve(indexPatterns.delete($scope.indexPattern)) + Promise.resolve($scope.indexPattern.destroy()) .then(function () { $location.url('/management/kibana/index_patterns'); }) diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js index 236970cf3c3f3..42a724547f105 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js @@ -531,7 +531,7 @@ describe('ObjectsTable', () => { await component.instance().delete(); - expect(defaultProps.indexPatterns.cache.clearAll).toHaveBeenCalled(); + expect(defaultProps.indexPatterns.clearCache).toHaveBeenCalled(); expect(mockSavedObjectsClient.bulkGet).toHaveBeenCalledWith(mockSelectedSavedObjects); expect(mockSavedObjectsClient.delete).toHaveBeenCalledWith(mockSavedObjects[0].type, mockSavedObjects[0].id); expect(mockSavedObjectsClient.delete).toHaveBeenCalledWith(mockSavedObjects[1].type, mockSavedObjects[1].id); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js index 9c1f1a84e1bb6..263b23859c8a5 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js @@ -369,7 +369,7 @@ class ObjectsTableUI extends Component { object => object.type === 'index-pattern' ); if (indexPatterns.length) { - await this.props.indexPatterns.cache.clearAll(); + await this.props.indexPatterns.clearCache(); } const objects = await savedObjectsClient.bulkGet(selectedSavedObjects); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js index cb6e81c714939..1468b3d90400d 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js @@ -96,7 +96,7 @@ async function importIndexPattern(doc, indexPatterns, overwriteAll, confirmModal return; } } - indexPatterns.cache.clear(newId); + indexPatterns.clearCache(newId); return newId; } diff --git a/src/legacy/ui/public/index_patterns/_field.ts b/src/legacy/ui/public/index_patterns/_field.ts index e678c4cc824f1..67aefc00b63b6 100644 --- a/src/legacy/ui/public/index_patterns/_field.ts +++ b/src/legacy/ui/public/index_patterns/_field.ts @@ -184,4 +184,6 @@ export class Field implements FieldType { } } -Object.defineProperties(Field.prototype, {}); +Field.prototype.routes = { + edit: '/management/kibana/index_patterns/{{indexPattern.id}}/field/{{name}}', +}; diff --git a/src/legacy/ui/public/index_patterns/_index_pattern.ts b/src/legacy/ui/public/index_patterns/_index_pattern.ts index faaf7da7bfa13..49e8b87c3e8ab 100644 --- a/src/legacy/ui/public/index_patterns/_index_pattern.ts +++ b/src/legacy/ui/public/index_patterns/_index_pattern.ts @@ -81,6 +81,7 @@ export class IndexPattern implements StaticIndexPattern { public timeFieldName: string | undefined; public formatHit: any; public flattenHit: any; + public metaFields: string[]; private version: string | undefined; private savedObjectsClient: SavedObjectsClient; @@ -128,6 +129,7 @@ export class IndexPattern implements StaticIndexPattern { this.getConfig = getConfig; this.shortDotsEnable = this.getConfig('shortDots:enable'); + this.metaFields = this.getConfig('metaFields'); this.fields = new FieldList(this, [], this.shortDotsEnable); this.fieldsFetcher = createFieldsFetcher(this, apiClient, this.getConfig('metaFields')); diff --git a/src/legacy/ui/public/index_patterns/_pattern_cache.ts b/src/legacy/ui/public/index_patterns/_pattern_cache.ts index 31dbadcde3838..a846fcd5d9f9b 100644 --- a/src/legacy/ui/public/index_patterns/_pattern_cache.ts +++ b/src/legacy/ui/public/index_patterns/_pattern_cache.ts @@ -17,30 +17,33 @@ * under the License. */ -export function createIndexPatternCache() { - const vals: any = {}; - const cache: any = {}; - - cache.get = function(id: string) { - return vals[id]; - }; - - cache.set = function(id: string, prom: any) { - vals[id] = prom; - return prom; - }; - - cache.clear = cache.delete = function(id: string) { - delete vals[id]; - }; +export interface PatternCache { + get: (id: string) => any; + set: (id: string, value: any) => any; + clear: (id: string) => void; + clearAll: () => void; +} - cache.clearAll = function() { - for (const id in vals) { - if (vals.hasOwnProperty(id)) { - delete vals[id]; +export function createIndexPatternCache(): PatternCache { + const vals: Record = {}; + const cache: PatternCache = { + get: (id: string) => { + return vals[id]; + }, + set: (id: string, prom: any) => { + vals[id] = prom; + return prom; + }, + clear: (id: string) => { + delete vals[id]; + }, + clearAll: () => { + for (const id in vals) { + if (vals.hasOwnProperty(id)) { + delete vals[id]; + } } - } + }, }; - return cache; } diff --git a/src/legacy/ui/public/index_patterns/index_patterns.ts b/src/legacy/ui/public/index_patterns/index_patterns.ts index d0642286b9bdc..08e5d150c3710 100644 --- a/src/legacy/ui/public/index_patterns/index_patterns.ts +++ b/src/legacy/ui/public/index_patterns/index_patterns.ts @@ -25,7 +25,6 @@ import { createIndexPatternCache } from './_pattern_cache'; import { IndexPatternsApiClient } from './index_patterns_api_client'; import { SavedObjectsClient, SimpleSavedObject } from '../saved_objects'; import { UiSettingsClient } from '../../../../../target/types/public/ui_settings'; -import { SavedObjectAttributes } from '../../../../../target/types/server/saved_objects/service'; const indexPatternCache = createIndexPatternCache(); const apiClient = new IndexPatternsApiClient(); @@ -35,7 +34,7 @@ export class IndexPatterns { private config: UiSettingsClient; private savedObjectsClient: SavedObjectsClient; - private savedObjectsCache?: Array> | null; + private savedObjectsCache?: Array> | null; constructor(config: UiSettingsClient, savedObjectsClient: SavedObjectsClient) { this.config = config; @@ -64,13 +63,17 @@ export class IndexPatterns { await this.loadSavedObjects(); } if (this.savedObjectsCache) { - return this.savedObjectsCache.map(obj => _.get(obj, 'title')); + return this.savedObjectsCache.map(obj => _.get(obj, 'attributes.title')); } }; - clearCache = () => { + clearCache = (id?: string) => { this.savedObjectsCache = null; - indexPatternCache.clearAll(); + if (id) { + indexPatternCache.clear(id); + } else { + indexPatternCache.clearAll(); + } }; getDefault = async () => { diff --git a/src/test_utils/public/stub_index_pattern.js b/src/test_utils/public/stub_index_pattern.js index 6c327a9425be7..683cc08bdbc7d 100644 --- a/src/test_utils/public/stub_index_pattern.js +++ b/src/test_utils/public/stub_index_pattern.js @@ -20,7 +20,8 @@ import sinon from 'sinon'; import { IndexPattern } from 'ui/index_patterns/_index_pattern'; import { getRoutes } from 'ui/index_patterns/get_routes'; -import { formatHitProvider } from 'ui/index_patterns/_format_hit'; import { fieldFormats } from 'ui/registry/field_formats'; +import { formatHitProvider } from 'ui/index_patterns/_format_hit'; +import { fieldFormats } from 'ui/registry/field_formats'; import { flattenHitWrapper } from 'ui/index_patterns/_flatten_hit'; import { FieldList } from 'ui/index_patterns/_field_list'; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_form.test.js b/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_form.test.js index de0a89153e2b8..61ca7359efbda 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_form.test.js +++ b/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_form.test.js @@ -11,11 +11,15 @@ jest.mock('../services/auto_follow_pattern_validators', () => ({ validateLeaderIndexPattern: jest.fn(), })); -jest.mock('ui/index_patterns/index_patterns.js', () => ({ +jest.mock('../../../../../../../src/legacy/ui/public/index_patterns/_index_pattern', () => ({ + IndexPattern: jest.fn(), +})); + +jest.mock('../../../../../../../src/legacy/ui/public/index_patterns/index_patterns', () => ({ IndexPatterns: jest.fn(), })); -jest.mock('ui/index_patterns/index_patterns_api_client.js', () => ({ +jest.mock('../../../../../../../src/legacy/ui/public/index_patterns/index_patterns_api_client', () => ({ IndexPatternsApiClient: jest.fn(), })); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.test.js b/x-pack/legacy/plugins/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.test.js index 8a5a8290a899d..be12bdecf56bc 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.test.js +++ b/x-pack/legacy/plugins/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.test.js @@ -7,11 +7,15 @@ import { validateAutoFollowPattern } from './auto_follow_pattern_validators'; -jest.mock('ui/index_patterns/index_patterns.js', () => ({ +jest.mock('../../../../../../../src/legacy/ui/public/index_patterns/_index_pattern', () => ({ + IndexPattern: jest.fn(), +})); + +jest.mock('../../../../../../../src/legacy/ui/public/index_patterns/index_patterns', () => ({ IndexPatterns: jest.fn(), })); -jest.mock('ui/index_patterns/index_patterns_api_client.js', () => ({ +jest.mock('../../../../../../../src/legacy/ui/public/index_patterns/index_patterns_api_client', () => ({ IndexPatternsApiClient: jest.fn(), })); From 8f828d2ad910e1ca9cf45d1115df6c7585824711 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Thu, 27 Jun 2019 15:12:22 +0200 Subject: [PATCH 05/20] fixing uisettingsclient type import --- src/legacy/ui/public/index_patterns/index_patterns.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/legacy/ui/public/index_patterns/index_patterns.ts b/src/legacy/ui/public/index_patterns/index_patterns.ts index 08e5d150c3710..64da14a9ca854 100644 --- a/src/legacy/ui/public/index_patterns/index_patterns.ts +++ b/src/legacy/ui/public/index_patterns/index_patterns.ts @@ -24,7 +24,7 @@ import { IndexPattern } from './_index_pattern'; import { createIndexPatternCache } from './_pattern_cache'; import { IndexPatternsApiClient } from './index_patterns_api_client'; import { SavedObjectsClient, SimpleSavedObject } from '../saved_objects'; -import { UiSettingsClient } from '../../../../../target/types/public/ui_settings'; +import { UiSettingsClient } from '../../../../core/public'; const indexPatternCache = createIndexPatternCache(); const apiClient = new IndexPatternsApiClient(); From 2cbffd7acd8257817f675f7eb87db11dd42c0cdd Mon Sep 17 00:00:00 2001 From: ppisljar Date: Thu, 27 Jun 2019 15:31:29 +0200 Subject: [PATCH 06/20] adding back getFields --- .../objects_table/components/flyout/flyout.js | 4 ++-- .../ui/public/index_patterns/index_patterns.ts | 13 +++++++++++++ x-pack/legacy/plugins/graph/public/app.js | 2 +- .../index_or_search/index_or_search_controller.js | 2 +- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js index dc4eaa9360ecd..1bdf6dede4dee 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js @@ -488,9 +488,9 @@ class FlyoutUI extends Component { }), render: id => { const options = this.state.indexPatterns.map(indexPattern => ({ - text: indexPattern.get('title'), + text: indexPattern.title, value: indexPattern.id, - ['data-test-subj']: `indexPatternOption-${indexPattern.get('title')}`, + ['data-test-subj']: `indexPatternOption-${indexPattern.title}`, })); options.unshift({ diff --git a/src/legacy/ui/public/index_patterns/index_patterns.ts b/src/legacy/ui/public/index_patterns/index_patterns.ts index 64da14a9ca854..d0f326fb6705f 100644 --- a/src/legacy/ui/public/index_patterns/index_patterns.ts +++ b/src/legacy/ui/public/index_patterns/index_patterns.ts @@ -67,6 +67,19 @@ export class IndexPatterns { } }; + getFields = async (fields: string[], refresh: boolean) => { + if (!this.savedObjectsCache || refresh) { + await this.loadSavedObjects(); + } + if (this.savedObjectsCache) { + return this.savedObjectsCache.map(obj => { + const result: Record = {}; + fields.forEach(f => (result[f] = _.get(obj, f) || _.get(obj, `attribute.${f}`))); + return result; + }); + } + }; + clearCache = (id?: string) => { this.savedObjectsCache = null; if (id) { diff --git a/x-pack/legacy/plugins/graph/public/app.js b/x-pack/legacy/plugins/graph/public/app.js index 77f92693b3561..e4dadfd04751e 100644 --- a/x-pack/legacy/plugins/graph/public/app.js +++ b/x-pack/legacy/plugins/graph/public/app.js @@ -742,7 +742,7 @@ app.controller('graphuiPlugin', function ( } } - $scope.indices = $route.current.locals.indexPatterns.filter(indexPattern => !indexPattern.get('type')); + $scope.indices = $route.current.locals.indexPatterns.filter(indexPattern => !indexPattern.type); $scope.setDetail = function (data) { diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/index_or_search/index_or_search_controller.js b/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/index_or_search/index_or_search_controller.js index 7f2295128312c..b3e54f93ebda1 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/index_or_search/index_or_search_controller.js +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/index_or_search/index_or_search_controller.js @@ -66,7 +66,7 @@ module.controller('MlNewJobStepIndexOrSearch', timefilter.disableTimeRangeSelector(); // remove time picker from top of page timefilter.disableAutoRefreshSelector(); // remove time picker from top of page - $scope.indexPatterns = getIndexPatterns().filter(indexPattern => !indexPattern.get('type')); + $scope.indexPatterns = getIndexPatterns().filter(indexPattern => !indexPattern.type); const path = $route.current.locals.nextStepPath; From 7d675b2a8d2019baa1c9cf76e979970edd1d4867 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Fri, 28 Jun 2019 06:09:39 +0200 Subject: [PATCH 07/20] fixing kbn-es-query --- packages/kbn-es-query/src/filters/index.d.ts | 4 +++- packages/kbn-es-query/src/kuery/ast/ast.d.ts | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/kbn-es-query/src/filters/index.d.ts b/packages/kbn-es-query/src/filters/index.d.ts index c46a767e38ea4..aca2a827ba2c8 100644 --- a/packages/kbn-es-query/src/filters/index.d.ts +++ b/packages/kbn-es-query/src/filters/index.d.ts @@ -17,10 +17,12 @@ * under the License. */ -import { Field, IndexPattern } from 'ui/index_patterns'; import { CustomFilter, ExistsFilter, PhraseFilter, PhrasesFilter, RangeFilter } from './lib'; import { RangeFilterParams } from './lib/range_filter'; +type Field = any; +type IndexPattern = any; + export * from './lib'; export function buildExistsFilter(field: Field, indexPattern: IndexPattern): ExistsFilter; diff --git a/packages/kbn-es-query/src/kuery/ast/ast.d.ts b/packages/kbn-es-query/src/kuery/ast/ast.d.ts index 484abac809bcd..915c024f2ab48 100644 --- a/packages/kbn-es-query/src/kuery/ast/ast.d.ts +++ b/packages/kbn-es-query/src/kuery/ast/ast.d.ts @@ -21,8 +21,6 @@ * WARNING: these typings are incomplete */ -import { StaticIndexPattern } from 'ui/index_patterns'; - export type KueryNode = any; export interface KueryParseOptions { @@ -46,6 +44,6 @@ export function fromKueryExpression( parseOptions?: KueryParseOptions ): KueryNode; -export function toElasticsearchQuery(node: KueryNode, indexPattern: StaticIndexPattern): JsonObject; +export function toElasticsearchQuery(node: KueryNode, indexPattern: any): JsonObject; export function doesKueryExpressionHaveLuceneSyntaxError(expression: string): boolean; From a4c8f43bbf342e2686aea7d2fceab2d06b1cbe2e Mon Sep 17 00:00:00 2001 From: ppisljar Date: Fri, 28 Jun 2019 08:31:10 +0200 Subject: [PATCH 08/20] updating jest tests --- .../__jest__/create_index_pattern_wizard.test.js | 3 ++- .../__jest__/__snapshots__/objects_table.test.js.snap | 4 +--- .../components/objects_table/__jest__/objects_table.test.js | 4 +--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/__jest__/create_index_pattern_wizard.test.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/__jest__/create_index_pattern_wizard.test.js index 8ddb89797361e..20e2fb779abeb 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/__jest__/create_index_pattern_wizard.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/__jest__/create_index_pattern_wizard.test.js @@ -55,6 +55,7 @@ const services = { config: {}, changeUrl: () => {}, scopeApply: () => {}, + indexPatternCreationType: mockIndexPatternCreationType, }; @@ -183,7 +184,7 @@ describe('CreateIndexPatternWizard', () => { get: () => ({ create, }), - cache: { clear } + clearCache: clear, }, changeUrl, indexPatternCreationType: mockIndexPatternCreationType diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/__snapshots__/objects_table.test.js.snap b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/__snapshots__/objects_table.test.js.snap index 9dbfc9866536b..f9b79266d4253 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/__snapshots__/objects_table.test.js.snap +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/__snapshots__/objects_table.test.js.snap @@ -209,9 +209,7 @@ exports[`ObjectsTable import should show the flyout 1`] = ` done={[Function]} indexPatterns={ Object { - "cache": Object { - "clearAll": [MockFunction], - }, + "clearCache": [MockFunction], } } newIndexPatternUrl="" diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js index 42a724547f105..51f33f7568369 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js @@ -123,9 +123,7 @@ const defaultProps = { bulkGet: jest.fn(), }, indexPatterns: { - cache: { - clearAll: jest.fn(), - } + clearCache: jest.fn(), }, $http, basePath: '', From 655faf2b7d84c0fe2a87efee182e07082bcd88d3 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Mon, 1 Jul 2019 12:17:26 +0200 Subject: [PATCH 09/20] fixing more tests --- src/legacy/ui/public/index_patterns/index_patterns.ts | 2 +- .../infra/public/components/metrics_explorer/metrics.tsx | 4 ++-- .../components/step_define/step_define_summary.test.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/legacy/ui/public/index_patterns/index_patterns.ts b/src/legacy/ui/public/index_patterns/index_patterns.ts index d0f326fb6705f..055cff0ca97a5 100644 --- a/src/legacy/ui/public/index_patterns/index_patterns.ts +++ b/src/legacy/ui/public/index_patterns/index_patterns.ts @@ -74,7 +74,7 @@ export class IndexPatterns { if (this.savedObjectsCache) { return this.savedObjectsCache.map(obj => { const result: Record = {}; - fields.forEach(f => (result[f] = _.get(obj, f) || _.get(obj, `attribute.${f}`))); + fields.forEach(f => (result[f] = _.get(obj, f) || _.get(obj, `attributes.${f}`))); return result; }); } diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/metrics.tsx b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/metrics.tsx index cfe24b51113ef..1ba512ef08eab 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/metrics.tsx +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/metrics.tsx @@ -7,7 +7,7 @@ import { EuiComboBox } from '@elastic/eui'; import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import React, { useCallback, useState, useEffect } from 'react'; -import { StaticIndexPatternField } from 'ui/index_patterns'; +import { FieldType } from 'ui/index_patterns'; import { colorTransformer, MetricsExplorerColor } from '../../../common/color_palette'; import { MetricsExplorerMetric, @@ -20,7 +20,7 @@ interface Props { autoFocus?: boolean; options: MetricsExplorerOptions; onChange: (metrics: MetricsExplorerMetric[]) => void; - fields: StaticIndexPatternField[]; + fields: FieldType[]; } interface SelectedOption { diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_summary.test.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_summary.test.tsx index 48eb8596f2f3e..f2f704da95450 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_summary.test.tsx +++ b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_summary.test.tsx @@ -30,7 +30,7 @@ describe('Data Frame: ', () => { id: 'the-index-pattern-id', title: 'the-index-pattern-title', fields: [], - }; + } as any; const groupBy: PivotGroupByConfig = { agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS, From 1bec2a107545608f7de243486131db2bc5c0431c Mon Sep 17 00:00:00 2001 From: ppisljar Date: Tue, 2 Jul 2019 09:52:50 +0200 Subject: [PATCH 10/20] jest --- .../__snapshots__/step_time_field.test.js.snap | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/__jest__/__snapshots__/step_time_field.test.js.snap b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/__jest__/__snapshots__/step_time_field.test.js.snap index 7b442d569ae83..3f25b180c9e1c 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/__jest__/__snapshots__/step_time_field.test.js.snap +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/__jest__/__snapshots__/step_time_field.test.js.snap @@ -31,7 +31,7 @@ exports[`StepTimeField should render "Custom index pattern ID already exists" wh /> Date: Tue, 2 Jul 2019 11:58:36 +0200 Subject: [PATCH 11/20] more type fixes --- .../data/public/filter/filter_manager/filter_manager.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/filter_manager.test.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/filter_manager.test.ts index 5f894cc8d8a9e..479ade24312a9 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/filter_manager.test.ts +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/filter_manager.test.ts @@ -78,7 +78,7 @@ describe('filter_manager', () => { appStateStub = new StubState(); globalStateStub = new StubState(); indexPatterns = new StubIndexPatterns(); - filterManager = new FilterManager(indexPatterns); + filterManager = new FilterManager(indexPatterns as any); readyFilters = getFiltersArray(); // FilterStateManager is tested indirectly. From 2a14385e09805977891bae73dcedb70b453a495c Mon Sep 17 00:00:00 2001 From: ppisljar Date: Tue, 2 Jul 2019 13:33:49 +0200 Subject: [PATCH 12/20] more type fixes --- src/legacy/ui/public/index_patterns/_index_pattern.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/legacy/ui/public/index_patterns/_index_pattern.ts b/src/legacy/ui/public/index_patterns/_index_pattern.ts index 49e8b87c3e8ab..7405ff66961f3 100644 --- a/src/legacy/ui/public/index_patterns/_index_pattern.ts +++ b/src/legacy/ui/public/index_patterns/_index_pattern.ts @@ -64,7 +64,7 @@ export const createIndexPatternMock = (params: Record): StaticIndex ...params, id: params.id || 'testIndexPattern', title: params.title || 'testIndexPattern', - type: params.type || '', + type: params.type, fields: params.fields || [], }; }; @@ -74,7 +74,7 @@ export class IndexPattern implements StaticIndexPattern { public id?: string; public title: string = ''; - public type: string = ''; + public type?: string; public fieldFormatMap: any; public typeMeta: any; public fields: FieldList; @@ -87,7 +87,7 @@ export class IndexPattern implements StaticIndexPattern { private savedObjectsClient: SavedObjectsClient; private patternCache: any; private getConfig: any; - private sourceFilters: [] = []; + private sourceFilters?: []; private originalBody: { [key: string]: any } = {}; private fieldsFetcher: any; private shortDotsEnable: boolean = false; From 5587c7ec2f53f0c89cf8c4a4afd13ca32f3701a3 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Wed, 3 Jul 2019 10:55:45 +0200 Subject: [PATCH 13/20] fixing stubindexpattern --- src/test_utils/public/stub_index_pattern.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test_utils/public/stub_index_pattern.js b/src/test_utils/public/stub_index_pattern.js index 683cc08bdbc7d..a2a41c08e0542 100644 --- a/src/test_utils/public/stub_index_pattern.js +++ b/src/test_utils/public/stub_index_pattern.js @@ -40,7 +40,7 @@ export default function () { this.fieldFormatMap = {}; this.routes = getRoutes(); - this.getComputedFields = sinon.spy(IndexPattern.prototype.getComputedFields); + this.getComputedFields = IndexPattern.prototype.getComputedFields.bind(this); this.flattenHit = flattenHitWrapper(this, this.metaFields); this.formatHit = formatHitProvider(this, fieldFormats.getDefaultInstance('string')); this.fieldsFetcher = { apiClient: { baseUrl: '' } }; From 2de599fbefe47baca152739e6dd6221156933bee Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Fri, 19 Jul 2019 13:29:04 -0600 Subject: [PATCH 14/20] Fix broken type checks --- src/legacy/ui/public/index_patterns/_index_pattern.ts | 1 + .../source_index_preview/source_index_preview.test.tsx | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/legacy/ui/public/index_patterns/_index_pattern.ts b/src/legacy/ui/public/index_patterns/_index_pattern.ts index 7405ff66961f3..d2ea47bed40e2 100644 --- a/src/legacy/ui/public/index_patterns/_index_pattern.ts +++ b/src/legacy/ui/public/index_patterns/_index_pattern.ts @@ -80,6 +80,7 @@ export class IndexPattern implements StaticIndexPattern { public fields: FieldList; public timeFieldName: string | undefined; public formatHit: any; + public formatField: any; public flattenHit: any; public metaFields: string[]; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/source_index_preview.test.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/source_index_preview.test.tsx index f827322629cc8..6e39365bd9b85 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/source_index_preview.test.tsx +++ b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/source_index_preview.test.tsx @@ -7,6 +7,7 @@ import { shallow } from 'enzyme'; import React from 'react'; +import { IndexPattern } from 'ui/index_patterns'; import { getPivotQuery, KibanaContext } from '../../../../common'; import { SourceIndexPreview } from './source_index_preview'; @@ -19,11 +20,11 @@ jest.mock('react', () => { describe('Data Frame: ', () => { test('Minimal initialization', () => { - const currentIndexPattern = { + const currentIndexPattern = ({ id: 'the-index-pattern-id', title: 'the-index-pattern-title', fields: [], - }; + } as unknown) as IndexPattern; const props = { query: getPivotQuery('the-query'), From ee0eb068ed1fc79945a4df9eabcbaf507c0e4751 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Fri, 19 Jul 2019 17:05:40 -0600 Subject: [PATCH 15/20] Remove some `any` types and fix eslint errors. --- packages/kbn-es-query/src/filters/index.d.ts | 4 +--- packages/kbn-es-query/src/kuery/ast/ast.d.ts | 4 +++- .../public/filter/filter_bar/filter_editor/index.tsx | 2 +- .../filter_editor/lib/filter_editor_utils.test.ts | 5 +++-- .../public/filter/filter_manager/filter_manager.test.ts | 3 ++- .../filter/filter_manager/filter_state_manager.test.ts | 3 ++- .../public/query/query_bar/components/query_bar.test.tsx | 3 ++- .../query/query_bar/components/query_bar_input.test.tsx | 3 ++- .../query/query_bar/components/query_bar_input.tsx | 2 +- .../core_plugins/kibana/public/context/api/context.ts | 5 +++-- .../ui/public/agg_types/filter/agg_type_filters.test.ts | 3 ++- src/legacy/ui/public/index_patterns/_field.ts | 9 ++++++--- src/legacy/ui/public/index_patterns/_index_pattern.ts | 2 +- 13 files changed, 29 insertions(+), 19 deletions(-) diff --git a/packages/kbn-es-query/src/filters/index.d.ts b/packages/kbn-es-query/src/filters/index.d.ts index aca2a827ba2c8..c46a767e38ea4 100644 --- a/packages/kbn-es-query/src/filters/index.d.ts +++ b/packages/kbn-es-query/src/filters/index.d.ts @@ -17,12 +17,10 @@ * under the License. */ +import { Field, IndexPattern } from 'ui/index_patterns'; import { CustomFilter, ExistsFilter, PhraseFilter, PhrasesFilter, RangeFilter } from './lib'; import { RangeFilterParams } from './lib/range_filter'; -type Field = any; -type IndexPattern = any; - export * from './lib'; export function buildExistsFilter(field: Field, indexPattern: IndexPattern): ExistsFilter; diff --git a/packages/kbn-es-query/src/kuery/ast/ast.d.ts b/packages/kbn-es-query/src/kuery/ast/ast.d.ts index 915c024f2ab48..484abac809bcd 100644 --- a/packages/kbn-es-query/src/kuery/ast/ast.d.ts +++ b/packages/kbn-es-query/src/kuery/ast/ast.d.ts @@ -21,6 +21,8 @@ * WARNING: these typings are incomplete */ +import { StaticIndexPattern } from 'ui/index_patterns'; + export type KueryNode = any; export interface KueryParseOptions { @@ -44,6 +46,6 @@ export function fromKueryExpression( parseOptions?: KueryParseOptions ): KueryNode; -export function toElasticsearchQuery(node: KueryNode, indexPattern: any): JsonObject; +export function toElasticsearchQuery(node: KueryNode, indexPattern: StaticIndexPattern): JsonObject; export function doesKueryExpressionHaveLuceneSyntaxError(expression: string): boolean; diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx index f544e4e3e6149..da3837b3c61f1 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx @@ -449,7 +449,7 @@ class FilterEditorUI extends Component { if (isCustomEditorOpen) { const { index, disabled, negate } = this.props.filter.meta; - const newIndex = index || (this.props.indexPatterns[0].id as string); + const newIndex = index || this.props.indexPatterns[0].id!; const body = JSON.parse(queryDsl); const filter = buildCustomFilter(newIndex, body, disabled, negate, alias, $state.store); this.props.onSubmit(filter); diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts index 4921b57f47818..05bc8bb740387 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts @@ -18,6 +18,7 @@ */ import { FilterStateStore, toggleFilterNegated } from '@kbn/es-query'; +import { IndexPattern, Field } from '../../../../index'; import { mockFields, mockIndexPattern } from 'ui/index_patterns/fixtures'; import { buildFilter, @@ -42,8 +43,8 @@ import { phraseFilter } from './fixtures/phrase_filter'; import { phrasesFilter } from './fixtures/phrases_filter'; import { rangeFilter } from './fixtures/range_filter'; -const mockedFields = mockFields as any; -const mockedIndexPattern = mockIndexPattern as any; +const mockedFields = mockFields as Field[]; +const mockedIndexPattern = mockIndexPattern as IndexPattern; describe('Filter editor utils', () => { describe('getQueryDslFromFilter', () => { diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/filter_manager.test.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/filter_manager.test.ts index 479ade24312a9..f23951f6f0914 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/filter_manager.test.ts +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/filter_manager.test.ts @@ -26,6 +26,7 @@ import { Filter, FilterStateStore } from '@kbn/es-query'; import { FilterStateManager } from './filter_state_manager'; import { FilterManager } from './filter_manager'; +import { IndexPatterns } from 'ui/index_patterns'; import { getFilter } from './test_helpers/get_stub_filter'; import { StubIndexPatterns } from './test_helpers/stub_index_pattern'; import { StubState } from './test_helpers/stub_state'; @@ -78,7 +79,7 @@ describe('filter_manager', () => { appStateStub = new StubState(); globalStateStub = new StubState(); indexPatterns = new StubIndexPatterns(); - filterManager = new FilterManager(indexPatterns as any); + filterManager = new FilterManager(indexPatterns as IndexPatterns); readyFilters = getFiltersArray(); // FilterStateManager is tested indirectly. diff --git a/src/legacy/core_plugins/data/public/filter/filter_manager/filter_state_manager.test.ts b/src/legacy/core_plugins/data/public/filter/filter_manager/filter_state_manager.test.ts index 2d549f7c6697f..255aceea7c3d8 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_manager/filter_state_manager.test.ts +++ b/src/legacy/core_plugins/data/public/filter/filter_manager/filter_state_manager.test.ts @@ -24,6 +24,7 @@ import { FilterStateStore } from '@kbn/es-query'; import { Subscription } from 'rxjs'; import { FilterStateManager } from './filter_state_manager'; +import { IndexPatterns } from 'ui/index_patterns'; import { StubState } from './test_helpers/stub_state'; import { getFilter } from './test_helpers/get_stub_filter'; import { FilterManager } from './filter_manager'; @@ -57,7 +58,7 @@ describe('filter_state_manager', () => { appStateStub = new StubState(); globalStateStub = new StubState(); const indexPatterns = new StubIndexPatterns(); - filterManager = new FilterManager(indexPatterns as any); + filterManager = new FilterManager(indexPatterns as IndexPatterns); }); afterEach(() => { diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar.test.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar.test.tsx index 65c0ba7118c2e..6b56ad49a23c4 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar.test.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar.test.tsx @@ -23,6 +23,7 @@ import React from 'react'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; import './query_bar.test.mocks'; import { QueryBar } from './query_bar'; +import { IndexPattern } from '../../../index'; const noop = () => { return; @@ -63,7 +64,7 @@ const mockIndexPattern = { searchable: true, }, ], -} as any; +} as IndexPattern; describe('QueryBar', () => { const QUERY_INPUT_SELECTOR = 'InjectIntl(QueryBarInputUI)'; diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx index 5ebef3e05f010..ff155dfccdac2 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx @@ -28,6 +28,7 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { QueryLanguageSwitcher } from './language_switcher'; import { QueryBarInput, QueryBarInputUI } from './query_bar_input'; +import { IndexPattern } from '../../../index'; const noop = () => { return; @@ -73,7 +74,7 @@ const mockIndexPattern = { searchable: true, }, ], -} as any; +} as IndexPattern; describe('QueryBarInput', () => { beforeEach(() => { diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index 875eb3a982175..a3239d73530cd 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -29,12 +29,12 @@ import { getAutocompleteProvider, } from 'ui/autocomplete_providers'; import { debounce, compact, isEqual, omit } from 'lodash'; -import { IndexPattern, StaticIndexPattern } from 'ui/index_patterns'; import { PersistedLog } from 'ui/persisted_log'; import chrome from 'ui/chrome'; import { kfetch } from 'ui/kfetch'; import { Storage } from 'ui/storage'; import { localStorage } from 'ui/storage/storage_service'; +import { IndexPattern, StaticIndexPattern } from '../../../index'; import { Query } from '../index'; import { fromUser, matchPairs, toUser } from '../lib'; import { QueryLanguageSwitcher } from './language_switcher'; diff --git a/src/legacy/core_plugins/kibana/public/context/api/context.ts b/src/legacy/core_plugins/kibana/public/context/api/context.ts index 55a4ac4945db1..be99fa63b07cc 100644 --- a/src/legacy/core_plugins/kibana/public/context/api/context.ts +++ b/src/legacy/core_plugins/kibana/public/context/api/context.ts @@ -21,6 +21,7 @@ import { SearchSourceProvider, SearchSource } from 'ui/courier'; import { IPrivate } from 'ui/private'; import { Filter } from '@kbn/es-query'; +import { IndexPatterns, IndexPattern } from 'ui/index_patterns'; import { reverseSortDir, SortDirection } from './utils/sorting'; import { extractNanos, convertIsoToMillis } from './utils/date_conversion'; import { fetchHitsInInterval } from './utils/fetch_hits_in_interval'; @@ -41,7 +42,7 @@ const DAY_MILLIS = 24 * 60 * 60 * 1000; // look from 1 day up to 10000 days into the past and future const LOOKUP_OFFSETS = [0, 1, 7, 30, 365, 10000].map(days => days * DAY_MILLIS); -function fetchContextProvider(indexPatterns: any, Private: IPrivate) { +function fetchContextProvider(indexPatterns: IndexPatterns, Private: IPrivate) { const SearchSourcePrivate: any = Private(SearchSourceProvider); return { @@ -111,7 +112,7 @@ function fetchContextProvider(indexPatterns: any, Private: IPrivate) { return documents; } - async function createSearchSource(indexPattern: any, filters: Filter[]) { + async function createSearchSource(indexPattern: IndexPattern, filters: Filter[]) { return new SearchSourcePrivate() .setParent(false) .setField('index', indexPattern) diff --git a/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts b/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts index 460b2d1649162..7361c8a852c98 100644 --- a/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts +++ b/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts @@ -17,11 +17,12 @@ * under the License. */ +import { IndexPattern } from 'ui/index_patterns'; import { AggTypeFilters } from './agg_type_filters'; describe('AggTypeFilters', () => { let registry: AggTypeFilters; - const indexPattern = { id: '1234', fields: [], title: 'foo' } as any; + const indexPattern = ({ id: '1234', fields: [], title: 'foo' } as unknown) as IndexPattern; const aggConfig = {}; beforeEach(() => { diff --git a/src/legacy/ui/public/index_patterns/_field.ts b/src/legacy/ui/public/index_patterns/_field.ts index 67aefc00b63b6..8ae4f0c0ac42c 100644 --- a/src/legacy/ui/public/index_patterns/_field.ts +++ b/src/legacy/ui/public/index_patterns/_field.ts @@ -167,17 +167,20 @@ export class Field implements FieldType { return obj.create(); } - get indexed() { + /** @deprecated */ + public get indexed() { throw new Error( 'field.indexed has been removed, see https://github.com/elastic/kibana/pull/11969' ); } - get analyzed() { + /** @deprecated */ + public get analyzed() { throw new Error( 'field.analyzed has been removed, see https://github.com/elastic/kibana/pull/11969' ); } - get doc_values() { // eslint-disable-line + /** @deprecated */ + public get doc_values() { // eslint-disable-line throw new Error( 'field.doc_values has been removed, see https://github.com/elastic/kibana/pull/11969' ); diff --git a/src/legacy/ui/public/index_patterns/_index_pattern.ts b/src/legacy/ui/public/index_patterns/_index_pattern.ts index d2ea47bed40e2..7c62602e8d93b 100644 --- a/src/legacy/ui/public/index_patterns/_index_pattern.ts +++ b/src/legacy/ui/public/index_patterns/_index_pattern.ts @@ -205,7 +205,7 @@ export class IndexPattern implements StaticIndexPattern { return this.indexFields(forceFieldRefresh); } - get routes() { + public get routes() { return getRoutes(); } From 6e56609fd8470dae9de46e33a82bda70aed76b0c Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Sun, 21 Jul 2019 21:28:10 -0600 Subject: [PATCH 16/20] Revert kbn-es-query changes. --- packages/kbn-es-query/src/filters/index.d.ts | 5 ++++- packages/kbn-es-query/src/kuery/ast/ast.d.ts | 4 +--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/kbn-es-query/src/filters/index.d.ts b/packages/kbn-es-query/src/filters/index.d.ts index c46a767e38ea4..d7e09f65d98a4 100644 --- a/packages/kbn-es-query/src/filters/index.d.ts +++ b/packages/kbn-es-query/src/filters/index.d.ts @@ -17,10 +17,13 @@ * under the License. */ -import { Field, IndexPattern } from 'ui/index_patterns'; import { CustomFilter, ExistsFilter, PhraseFilter, PhrasesFilter, RangeFilter } from './lib'; import { RangeFilterParams } from './lib/range_filter'; +// we can't import the real types from ui/public here +type Field = any; +type IndexPattern = any; + export * from './lib'; export function buildExistsFilter(field: Field, indexPattern: IndexPattern): ExistsFilter; diff --git a/packages/kbn-es-query/src/kuery/ast/ast.d.ts b/packages/kbn-es-query/src/kuery/ast/ast.d.ts index 484abac809bcd..915c024f2ab48 100644 --- a/packages/kbn-es-query/src/kuery/ast/ast.d.ts +++ b/packages/kbn-es-query/src/kuery/ast/ast.d.ts @@ -21,8 +21,6 @@ * WARNING: these typings are incomplete */ -import { StaticIndexPattern } from 'ui/index_patterns'; - export type KueryNode = any; export interface KueryParseOptions { @@ -46,6 +44,6 @@ export function fromKueryExpression( parseOptions?: KueryParseOptions ): KueryNode; -export function toElasticsearchQuery(node: KueryNode, indexPattern: StaticIndexPattern): JsonObject; +export function toElasticsearchQuery(node: KueryNode, indexPattern: any): JsonObject; export function doesKueryExpressionHaveLuceneSyntaxError(expression: string): boolean; From 3e81fb6feea798525acf3cd910daad4b3dd2a424 Mon Sep 17 00:00:00 2001 From: Jason Rhodes Date: Mon, 22 Jul 2019 07:50:45 -0400 Subject: [PATCH 17/20] Uses core FieldType instead of custom type --- .../legacy/plugins/infra/public/graphql/types.ts | 14 ++++---------- .../pages/infrastructure/snapshot/toolbar.tsx | 2 +- .../legacy/plugins/infra/server/graphql/types.ts | 13 +++---------- 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/graphql/types.ts b/x-pack/legacy/plugins/infra/public/graphql/types.ts index 5f085f67e73fa..fe300de0aa76a 100644 --- a/x-pack/legacy/plugins/infra/public/graphql/types.ts +++ b/x-pack/legacy/plugins/infra/public/graphql/types.ts @@ -8,6 +8,8 @@ // Types // ==================================================== +import { FieldType } from 'ui/index_patterns'; + export interface Query { /** Get an infrastructure data source by id.The resolution order for the source configuration attributes is as followswith the first defined value winning:1. The attributes of the saved object with the given 'id'.2. The attributes defined in the static Kibana configuration key'xpack.infra.sources.default'.3. The hard-coded default values.As a consequence, querying a source that doesn't exist doesn't error out,but returns the configured or hardcoded defaults. */ source: InfraSource; @@ -122,16 +124,8 @@ export interface InfraSourceStatus { indexFields: InfraIndexField[]; } /** A descriptor of a field in an index */ -export interface InfraIndexField { - /** The name of the field */ - name: string; - /** The type of the field's values as recognized by Kibana */ - type: string; - /** Whether the field's values can be efficiently searched for */ - searchable: boolean; - /** Whether the field's values can be aggregated */ - aggregatable: boolean; -} +export interface InfraIndexField extends FieldType {} + /** One metadata entry for a node. */ export interface InfraNodeMetadata { id: string; diff --git a/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx b/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx index dd8f9d4098b77..e70e79a18a66a 100644 --- a/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx @@ -106,7 +106,7 @@ export const SnapshotToolbar = injectI18n(({ intl }) => ( groupBy={groupBy} nodeType={nodeType} onChange={changeGroupBy} - fields={derivedIndexPattern.fields as any} + fields={derivedIndexPattern.fields} onChangeCustomOptions={changeCustomOptions} customOptions={customOptions} /> diff --git a/x-pack/legacy/plugins/infra/server/graphql/types.ts b/x-pack/legacy/plugins/infra/server/graphql/types.ts index d161dfac59f31..6624de544ca66 100644 --- a/x-pack/legacy/plugins/infra/server/graphql/types.ts +++ b/x-pack/legacy/plugins/infra/server/graphql/types.ts @@ -1,6 +1,7 @@ /* tslint:disable */ import { InfraContext } from '../lib/infra_types'; import { GraphQLResolveInfo } from 'graphql'; +import { FieldType } from 'ui/index_patterns'; export type Resolver = ( parent: Parent, @@ -150,16 +151,8 @@ export interface InfraSourceStatus { indexFields: InfraIndexField[]; } /** A descriptor of a field in an index */ -export interface InfraIndexField { - /** The name of the field */ - name: string; - /** The type of the field's values as recognized by Kibana */ - type: string; - /** Whether the field's values can be efficiently searched for */ - searchable: boolean; - /** Whether the field's values can be aggregated */ - aggregatable: boolean; -} +export interface InfraIndexField extends FieldType {} + /** One metadata entry for a node. */ export interface InfraNodeMetadata { id: string; From aebb3b2fee4b9b7e62412bfec51b28c5e5c46958 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Mon, 22 Jul 2019 15:41:56 -0600 Subject: [PATCH 18/20] Fix tests. --- .../public/search/search_bar/components/search_bar.test.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx index 2b631e1f547db..8387b4814bf77 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx @@ -21,6 +21,8 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { SearchBar } from './search_bar'; +import { IndexPattern } from '../../../../public'; + jest.mock('../../../filter/filter_bar', () => { return { FilterBar: () =>
, @@ -65,7 +67,7 @@ const mockIndexPattern = { searchable: true, }, ], -}; +} as IndexPattern; const kqlQuery = { query: 'response:200', From a19d557fd3e9bfe46cdcae8d99e585a1db4afdc3 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Mon, 22 Jul 2019 17:45:44 -0600 Subject: [PATCH 19/20] Address feedback. --- packages/kbn-es-query/src/filters/index.d.ts | 5 +---- packages/kbn-es-query/src/kuery/ast/ast.d.ts | 4 +++- .../filter_editor/lib/filter_editor_utils.test.ts | 4 ++-- .../query/query_bar/components/query_bar_input.tsx | 6 +++--- src/legacy/ui/public/index_patterns/_index_pattern.ts | 2 +- .../index_patterns/validate/validate_index_pattern.ts | 9 ++++----- .../components/full_time_range_selector/index.test.tsx | 4 ++-- .../source_index_preview/use_source_index_data.ts | 4 ++-- .../components/step_define/common.test.ts | 5 +++-- 9 files changed, 21 insertions(+), 22 deletions(-) diff --git a/packages/kbn-es-query/src/filters/index.d.ts b/packages/kbn-es-query/src/filters/index.d.ts index d7e09f65d98a4..20b510977f0af 100644 --- a/packages/kbn-es-query/src/filters/index.d.ts +++ b/packages/kbn-es-query/src/filters/index.d.ts @@ -17,13 +17,10 @@ * under the License. */ +import { Field, IndexPattern } from '../../../../src/legacy/ui/public/index_patterns'; import { CustomFilter, ExistsFilter, PhraseFilter, PhrasesFilter, RangeFilter } from './lib'; import { RangeFilterParams } from './lib/range_filter'; -// we can't import the real types from ui/public here -type Field = any; -type IndexPattern = any; - export * from './lib'; export function buildExistsFilter(field: Field, indexPattern: IndexPattern): ExistsFilter; diff --git a/packages/kbn-es-query/src/kuery/ast/ast.d.ts b/packages/kbn-es-query/src/kuery/ast/ast.d.ts index 915c024f2ab48..fc403f26cc359 100644 --- a/packages/kbn-es-query/src/kuery/ast/ast.d.ts +++ b/packages/kbn-es-query/src/kuery/ast/ast.d.ts @@ -17,6 +17,8 @@ * under the License. */ +import { StaticIndexPattern } from '../../../../../src/legacy/ui/public/index_patterns'; + /** * WARNING: these typings are incomplete */ @@ -44,6 +46,6 @@ export function fromKueryExpression( parseOptions?: KueryParseOptions ): KueryNode; -export function toElasticsearchQuery(node: KueryNode, indexPattern: any): JsonObject; +export function toElasticsearchQuery(node: KueryNode, indexPattern: StaticIndexPattern): JsonObject; export function doesKueryExpressionHaveLuceneSyntaxError(expression: string): boolean; diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts index 05bc8bb740387..10301a32c4454 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/lib/filter_editor_utils.test.ts @@ -170,14 +170,14 @@ describe('Filter editor utils', () => { describe('getOperatorOptions', () => { it('returns range for number fields', () => { const [field] = mockFields.filter(({ type }) => type === 'number'); - const operatorOptions = getOperatorOptions(field as any); + const operatorOptions = getOperatorOptions(field as Field); const rangeOperator = operatorOptions.find(operator => operator.type === 'range'); expect(rangeOperator).not.toBeUndefined(); }); it('does not return range for string fields', () => { const [field] = mockFields.filter(({ type }) => type === 'string'); - const operatorOptions = getOperatorOptions(field as any); + const operatorOptions = getOperatorOptions(field as Field); const rangeOperator = operatorOptions.find(operator => operator.type === 'range'); expect(rangeOperator).toBeUndefined(); }); diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index a3239d73530cd..122db8d8dc41a 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -34,7 +34,7 @@ import chrome from 'ui/chrome'; import { kfetch } from 'ui/kfetch'; import { Storage } from 'ui/storage'; import { localStorage } from 'ui/storage/storage_service'; -import { IndexPattern, StaticIndexPattern } from '../../../index'; +import { IndexPattern, StaticIndexPattern } from '../../../../public'; import { Query } from '../index'; import { fromUser, matchPairs, toUser } from '../lib'; import { QueryLanguageSwitcher } from './language_switcher'; @@ -111,10 +111,10 @@ export class QueryBarInputUI extends Component { indexPattern => typeof indexPattern !== 'string' ) as IndexPattern[]; - const objectPatternsFromStrings = await fetchIndexPatterns(stringPatterns); + const objectPatternsFromStrings = (await fetchIndexPatterns(stringPatterns)) as IndexPattern[]; this.setState({ - indexPatterns: [...(objectPatterns as any), ...objectPatternsFromStrings], + indexPatterns: [...objectPatterns, ...objectPatternsFromStrings], }); }; diff --git a/src/legacy/ui/public/index_patterns/_index_pattern.ts b/src/legacy/ui/public/index_patterns/_index_pattern.ts index 7c62602e8d93b..f36278ae80a6a 100644 --- a/src/legacy/ui/public/index_patterns/_index_pattern.ts +++ b/src/legacy/ui/public/index_patterns/_index_pattern.ts @@ -411,7 +411,7 @@ export class IndexPattern implements StaticIndexPattern { return await _create(potentialDuplicateByTitle.id); } - async save(saveAttempts = 0): Promise { + async save(saveAttempts: number = 0): Promise { if (!this.id) return; const body = this.prepBody(); // What keys changed since they last pulled the index pattern diff --git a/src/legacy/ui/public/index_patterns/validate/validate_index_pattern.ts b/src/legacy/ui/public/index_patterns/validate/validate_index_pattern.ts index f59d6d5abd89d..cca38b7a33264 100644 --- a/src/legacy/ui/public/index_patterns/validate/validate_index_pattern.ts +++ b/src/legacy/ui/public/index_patterns/validate/validate_index_pattern.ts @@ -22,11 +22,10 @@ import { INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE } from '../constants'; export const ILLEGAL_CHARACTERS = 'ILLEGAL_CHARACTERS'; export const CONTAINS_SPACES = 'CONTAINS_SPACES'; -function findIllegalCharacters(indexPattern: string) { +function findIllegalCharacters(indexPattern: string): string[] { const illegalCharacters = INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE.reduce( - (chars, char: string) => { + (chars: string[], char: string) => { if (indexPattern.includes(char)) { - // @ts-ignore chars.push(char); } return chars; @@ -37,12 +36,12 @@ function findIllegalCharacters(indexPattern: string) { return illegalCharacters; } -function indexPatternContainsSpaces(indexPattern: string) { +function indexPatternContainsSpaces(indexPattern: string): boolean { return indexPattern.includes(' '); } export function validateIndexPattern(indexPattern: string) { - const errors: any = {}; + const errors: Record = {}; const illegalCharacters = findIllegalCharacters(indexPattern); diff --git a/x-pack/legacy/plugins/ml/public/components/full_time_range_selector/index.test.tsx b/x-pack/legacy/plugins/ml/public/components/full_time_range_selector/index.test.tsx index 83c351d1e5da7..4da2a040e9975 100644 --- a/x-pack/legacy/plugins/ml/public/components/full_time_range_selector/index.test.tsx +++ b/x-pack/legacy/plugins/ml/public/components/full_time_range_selector/index.test.tsx @@ -20,12 +20,12 @@ jest.mock('./full_time_range_selector_service', () => ({ })); describe('FullTimeRangeSelector', () => { - const indexPattern: any = { + const indexPattern = ({ id: '0844fc70-5ab5-11e9-935e-836737467b0f', fields: [], title: 'test-index-pattern', timeFieldName: '@timestamp', - }; + } as unknown) as IndexPattern; const query: Query = { language: 'kuery', diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.ts b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.ts index ca97c9f247d7e..4e6ec7f88314a 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.ts +++ b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.ts @@ -10,7 +10,7 @@ import React, { useEffect, useState } from 'react'; import { SearchResponse } from 'elasticsearch'; -import { IndexPattern, StaticIndexPattern } from 'ui/index_patterns'; +import { StaticIndexPattern } from 'ui/index_patterns'; import { ml } from '../../../../../services/ml_api_service'; @@ -39,7 +39,7 @@ export interface UseSourceIndexDataReturnType { } export const useSourceIndexData = ( - indexPattern: IndexPattern | StaticIndexPattern, + indexPattern: StaticIndexPattern, query: PivotQuery, selectedFields: EsFieldName[], setSelectedFields: React.Dispatch> diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.test.ts b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.test.ts index edd5637213c58..f96bab17df715 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.test.ts +++ b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.test.ts @@ -14,13 +14,14 @@ import { } from '../../../../common'; import { getPivotPreviewDevConsoleStatement, getPivotDropdownOptions } from './common'; +import { IndexPattern } from 'ui/index_patterns'; describe('Data Frame: Define Pivot Common', () => { test('getPivotDropdownOptions()', () => { // The field name includes the characters []> as well as a leading and ending space charcter // which cannot be used for aggregation names. The test results verifies that the characters // should still be present in field and dropDownName values, but should be stripped for aggName values. - const indexPattern: any = { + const indexPattern = { id: 'the-index-pattern-id', title: 'the-index-pattern-title', fields: [ @@ -32,7 +33,7 @@ describe('Data Frame: Define Pivot Common', () => { searchable: true, }, ], - }; + } as IndexPattern; const options = getPivotDropdownOptions(indexPattern); From 989513e4678bdf5cda004ba7672f1ee1df6ead81 Mon Sep 17 00:00:00 2001 From: Jason Rhodes Date: Tue, 23 Jul 2019 07:31:50 -0400 Subject: [PATCH 20/20] Revert "Uses core FieldType instead of custom type" This reverts commit 90d643147e85dfbbbcf08f190d55105a683cbb23. --- .../legacy/plugins/infra/public/graphql/types.ts | 14 ++++++++++---- .../pages/infrastructure/snapshot/toolbar.tsx | 2 +- .../legacy/plugins/infra/server/graphql/types.ts | 13 ++++++++++--- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/graphql/types.ts b/x-pack/legacy/plugins/infra/public/graphql/types.ts index fe300de0aa76a..5f085f67e73fa 100644 --- a/x-pack/legacy/plugins/infra/public/graphql/types.ts +++ b/x-pack/legacy/plugins/infra/public/graphql/types.ts @@ -8,8 +8,6 @@ // Types // ==================================================== -import { FieldType } from 'ui/index_patterns'; - export interface Query { /** Get an infrastructure data source by id.The resolution order for the source configuration attributes is as followswith the first defined value winning:1. The attributes of the saved object with the given 'id'.2. The attributes defined in the static Kibana configuration key'xpack.infra.sources.default'.3. The hard-coded default values.As a consequence, querying a source that doesn't exist doesn't error out,but returns the configured or hardcoded defaults. */ source: InfraSource; @@ -124,8 +122,16 @@ export interface InfraSourceStatus { indexFields: InfraIndexField[]; } /** A descriptor of a field in an index */ -export interface InfraIndexField extends FieldType {} - +export interface InfraIndexField { + /** The name of the field */ + name: string; + /** The type of the field's values as recognized by Kibana */ + type: string; + /** Whether the field's values can be efficiently searched for */ + searchable: boolean; + /** Whether the field's values can be aggregated */ + aggregatable: boolean; +} /** One metadata entry for a node. */ export interface InfraNodeMetadata { id: string; diff --git a/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx b/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx index e70e79a18a66a..dd8f9d4098b77 100644 --- a/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx @@ -106,7 +106,7 @@ export const SnapshotToolbar = injectI18n(({ intl }) => ( groupBy={groupBy} nodeType={nodeType} onChange={changeGroupBy} - fields={derivedIndexPattern.fields} + fields={derivedIndexPattern.fields as any} onChangeCustomOptions={changeCustomOptions} customOptions={customOptions} /> diff --git a/x-pack/legacy/plugins/infra/server/graphql/types.ts b/x-pack/legacy/plugins/infra/server/graphql/types.ts index 6624de544ca66..d161dfac59f31 100644 --- a/x-pack/legacy/plugins/infra/server/graphql/types.ts +++ b/x-pack/legacy/plugins/infra/server/graphql/types.ts @@ -1,7 +1,6 @@ /* tslint:disable */ import { InfraContext } from '../lib/infra_types'; import { GraphQLResolveInfo } from 'graphql'; -import { FieldType } from 'ui/index_patterns'; export type Resolver = ( parent: Parent, @@ -151,8 +150,16 @@ export interface InfraSourceStatus { indexFields: InfraIndexField[]; } /** A descriptor of a field in an index */ -export interface InfraIndexField extends FieldType {} - +export interface InfraIndexField { + /** The name of the field */ + name: string; + /** The type of the field's values as recognized by Kibana */ + type: string; + /** Whether the field's values can be efficiently searched for */ + searchable: boolean; + /** Whether the field's values can be aggregated */ + aggregatable: boolean; +} /** One metadata entry for a node. */ export interface InfraNodeMetadata { id: string;