From 1e2b3d05a5182e9ee7c8e153509509412bbd7c7a Mon Sep 17 00:00:00 2001 From: dej611 Date: Thu, 5 Nov 2020 17:35:11 +0100 Subject: [PATCH 01/10] :zap: Use a lookup for indexPattern fields --- .../indexpattern_suggestions.ts | 27 +++++++++---------- .../public/indexpattern_datasource/loader.ts | 1 + .../operations/definitions/cardinality.tsx | 2 +- .../operations/definitions/date_histogram.tsx | 21 +++++++-------- .../operations/definitions/metrics.tsx | 2 +- .../operations/definitions/ranges/ranges.tsx | 6 ++--- .../operations/definitions/terms/index.tsx | 2 +- .../public/indexpattern_datasource/types.ts | 1 + 8 files changed, 28 insertions(+), 34 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts index 098569d1f460a..7b9cd9d4b9b77 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts @@ -128,7 +128,7 @@ export function getDatasourceSuggestionsForVisualizeField( const layerIds = layers.filter((id) => state.layers[id].indexPatternId === indexPatternId); // Identify the field by the indexPatternId and the fieldName const indexPattern = state.indexPatterns[indexPatternId]; - const field = indexPattern.fields.find((fld) => fld.name === fieldName); + const field = indexPattern.fieldsMap[fieldName]; if (layerIds.length !== 0 || !field) return []; const newId = generateId(); @@ -371,7 +371,7 @@ function createNewLayerWithMetricAggregation( indexPattern: IndexPattern, field: IndexPatternField ): IndexPatternLayer { - const dateField = indexPattern.fields.find((f) => f.name === indexPattern.timeFieldName)!; + const dateField = indexPattern.fieldsMap[indexPattern.timeFieldName!]; const column = getMetricColumn(indexPattern, layerId, field); @@ -451,9 +451,8 @@ export function getDatasourceSuggestionsFromCurrentState( (columnId) => layer.columns[columnId].isBucketed && layer.columns[columnId].dataType === 'date' ); - const timeField = indexPattern.fields.find( - ({ name }) => name === indexPattern.timeFieldName - ); + const timeField = + indexPattern.timeFieldName && indexPattern.fieldsMap[indexPattern.timeFieldName]; const hasNumericDimension = buckets.length === 1 && @@ -507,17 +506,15 @@ function createChangedNestingSuggestion(state: IndexPatternPrivateState, layerId const layer = state.layers[layerId]; const [firstBucket, secondBucket, ...rest] = layer.columnOrder; const updatedLayer = { ...layer, columnOrder: [secondBucket, firstBucket, ...rest] }; - const currentFields = state.indexPatterns[state.currentIndexPatternId].fields; + const currentFields = state.indexPatterns[state.currentIndexPatternId].fieldsMap; + const firstBucketColumn = layer.columns[firstBucket]; const firstBucketLabel = - currentFields.find((field) => { - const column = layer.columns[firstBucket]; - return hasField(column) && column.sourceField === field.name; - })?.displayName || ''; + (hasField(firstBucketColumn) && currentFields[firstBucketColumn.sourceField]?.displayName) || + ''; + const secondBucketColumn = layer.columns[secondBucket]; const secondBucketLabel = - currentFields.find((field) => { - const column = layer.columns[secondBucket]; - return hasField(column) && column.sourceField === field.name; - })?.displayName || ''; + (hasField(secondBucketColumn) && currentFields[secondBucketColumn.sourceField]?.displayName) || + ''; return buildSuggestion({ state, @@ -604,7 +601,7 @@ function createAlternativeMetricSuggestions( if (!hasField(column)) { return; } - const field = indexPattern.fields.find(({ name }) => column.sourceField === name)!; + const field = indexPattern.fieldsMap[column.sourceField]!; const alternativeMetricOperations = getOperationTypesForField(field) .map((op) => buildColumn({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts index 70079cce6cc46..5554e612fd33b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts @@ -112,6 +112,7 @@ export async function loadIndexPatterns({ ]) ), fields: newFields, + fieldsMap: _.keyBy(newFields, 'name'), hasRestrictions: !!typeMeta?.aggs, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx index 65119d3978ee6..b161a291ac3da 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx @@ -43,7 +43,7 @@ export const cardinalityOperation: OperationDefinition { - const newField = newIndexPattern.fields.find((field) => field.name === column.sourceField); + const newField = newIndexPattern.fieldsMap[column.sourceField]; return Boolean( newField && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.tsx index 185f44405bb4b..59f171f3a3234 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.tsx @@ -81,7 +81,7 @@ export const dateHistogramOperation: OperationDefinition< }; }, isTransferable: (column, newIndexPattern) => { - const newField = newIndexPattern.fields.find((field) => field.name === column.sourceField); + const newField = newIndexPattern.fieldsMap[column.sourceField]; return Boolean( newField && @@ -91,12 +91,9 @@ export const dateHistogramOperation: OperationDefinition< ); }, transfer: (column, newIndexPattern) => { - const newField = newIndexPattern.fields.find((field) => field.name === column.sourceField); - if ( - newField && - newField.aggregationRestrictions && - newField.aggregationRestrictions.date_histogram - ) { + const newField = newIndexPattern.fieldsMap[column.sourceField]; + + if (newField?.aggregationRestrictions?.date_histogram) { const restrictions = newField.aggregationRestrictions.date_histogram; return { @@ -123,7 +120,7 @@ export const dateHistogramOperation: OperationDefinition< }; }, toEsAggsConfig: (column, columnId, indexPattern) => { - const usedField = indexPattern.fields.find((field) => field.name === column.sourceField); + const usedField = indexPattern.fieldsMap[column.sourceField]; return { id: columnId, enabled: true, @@ -132,7 +129,7 @@ export const dateHistogramOperation: OperationDefinition< params: { field: column.sourceField, time_zone: column.params.timeZone, - useNormalizedEsInterval: !usedField || !usedField.aggregationRestrictions?.date_histogram, + useNormalizedEsInterval: !usedField?.aggregationRestrictions?.date_histogram, interval: column.params.interval, drop_partials: false, min_doc_count: 0, @@ -143,9 +140,9 @@ export const dateHistogramOperation: OperationDefinition< paramEditor: ({ state, setState, currentColumn, layerId, dateRange, data }) => { const field = currentColumn && - state.indexPatterns[state.layers[layerId].indexPatternId].fields.find( - (currentField) => currentField.name === currentColumn.sourceField - ); + state.indexPatterns[state.layers[layerId].indexPatternId].fieldsMap[ + currentColumn.sourceField + ]; const intervalIsRestricted = field!.aggregationRestrictions && field!.aggregationRestrictions.date_histogram; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx index 1d3ecc165ce74..73bc5281bbfa5 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx @@ -43,7 +43,7 @@ function buildMetricOperation>({ } }, isTransferable: (column, newIndexPattern) => { - const newField = newIndexPattern.fields.find((field) => field.name === column.sourceField); + const newField = newIndexPattern.fieldsMap[column.sourceField]; return Boolean( newField && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx index 1050eef45a71c..7c5ce17d452d6 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx @@ -140,7 +140,7 @@ export const rangeOperation: OperationDefinition { - const newField = newIndexPattern.fields.find((field) => field.name === column.sourceField); + const newField = newIndexPattern.fieldsMap[column.sourceField]; return Boolean( newField && @@ -168,9 +168,7 @@ export const rangeOperation: OperationDefinition { const indexPattern = state.indexPatterns[state.layers[layerId].indexPatternId]; - const currentField = indexPattern.fields.find( - (field) => field.name === currentColumn.sourceField - ); + const currentField = indexPattern.fieldsMap[currentColumn.sourceField]; const numberFormat = currentColumn.params.format; const numberFormatterPattern = numberFormat && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx index 85deb2bac25ca..128f9ff265bac 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx @@ -54,7 +54,7 @@ export const termsOperation: OperationDefinition { - const newField = newIndexPattern.fields.find((field) => field.name === column.sourceField); + const newField = newIndexPattern.fieldsMap[column.sourceField]; return Boolean( newField && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/types.ts b/x-pack/plugins/lens/public/indexpattern_datasource/types.ts index a3c0e8aed7421..0bd46b5e56e5d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/types.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/types.ts @@ -11,6 +11,7 @@ import { IndexPatternAggRestrictions } from '../../../../../src/plugins/data/pub export interface IndexPattern { id: string; fields: IndexPatternField[]; + fieldsMap: Record; title: string; timeFieldName?: string; fieldFormatMap?: Record< From 03dd62caa0e3b6b5a52bfc8eeb84a3d81f6b46c2 Mon Sep 17 00:00:00 2001 From: dej611 Date: Thu, 5 Nov 2020 17:38:38 +0100 Subject: [PATCH 02/10] :white_check_mark: Update all tests to handle new lookup format --- .../datapanel.test.tsx | 254 +++++++------- .../dimension_panel/dimension_panel.test.tsx | 74 ++-- .../dimension_panel/droppable.test.ts | 90 +++-- .../indexpattern.test.ts | 205 +++++------ .../indexpattern_suggestions.test.tsx | 324 ++++++++++-------- .../layerpanel.test.tsx | 232 +++++++------ .../public/indexpattern_datasource/mocks.ts | 117 ++++--- .../definitions/date_histogram.test.tsx | 73 ++++ .../definitions/ranges/ranges.test.tsx | 3 + .../operations/operations.test.ts | 50 +-- .../state_helpers.test.ts | 101 +++--- 11 files changed, 860 insertions(+), 663 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx index c48bc3dc52404..a8419afd9e2db 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx @@ -18,6 +18,131 @@ import { ChangeIndexPattern } from './change_indexpattern'; import { EuiProgress, EuiLoadingSpinner } from '@elastic/eui'; import { documentField } from './document_field'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; +import { keyBy } from 'lodash'; + +const fieldsOne = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'memory', + displayName: 'amemory', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'unsupported', + displayName: 'unsupported', + type: 'geo', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'client', + displayName: 'client', + type: 'ip', + aggregatable: true, + searchable: true, + }, + documentField, +]; + +const fieldsTwo = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + fixed_interval: '1d', + delay: '7d', + time_zone: 'UTC', + }, + }, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + histogram: { + agg: 'histogram', + interval: 1000, + }, + max: { + agg: 'max', + }, + min: { + agg: 'min', + }, + sum: { + agg: 'sum', + }, + }, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + terms: { + agg: 'terms', + }, + }, + }, + documentField, +]; + +const fieldsThree = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + documentField, +]; const initialState: IndexPatternPrivateState = { indexPatternRefs: [], @@ -85,139 +210,24 @@ const initialState: IndexPatternPrivateState = { title: 'idx1', timeFieldName: 'timestamp', hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'memory', - displayName: 'amemory', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'unsupported', - displayName: 'unsupported', - type: 'geo', - aggregatable: true, - searchable: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }, - { - name: 'client', - displayName: 'client', - type: 'ip', - aggregatable: true, - searchable: true, - }, - documentField, - ], + fields: fieldsOne, + fieldsMap: keyBy(fieldsOne, 'name'), }, '2': { id: '2', title: 'idx2', timeFieldName: 'timestamp', hasRestrictions: true, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - date_histogram: { - agg: 'date_histogram', - fixed_interval: '1d', - delay: '7d', - time_zone: 'UTC', - }, - }, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - histogram: { - agg: 'histogram', - interval: 1000, - }, - max: { - agg: 'max', - }, - min: { - agg: 'min', - }, - sum: { - agg: 'sum', - }, - }, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - terms: { - agg: 'terms', - }, - }, - }, - documentField, - ], + fields: fieldsTwo, + fieldsMap: keyBy(fieldsTwo, 'name'), }, '3': { id: '3', title: 'idx3', timeFieldName: 'timestamp', hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }, - documentField, - ], + fields: fieldsThree, + fieldsMap: keyBy(fieldsThree, 'name'), }, }, isFirstExistenceFetch: false, @@ -330,6 +340,7 @@ describe('IndexPattern Data Panel', () => { title: 'aaa', timeFieldName: 'atime', fields: [], + fieldsMap: {}, hasRestrictions: false, }, b: { @@ -337,6 +348,7 @@ describe('IndexPattern Data Panel', () => { title: 'bbb', timeFieldName: 'btime', fields: [], + fieldsMap: {}, hasRestrictions: false, }, }, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx index 829bd333ce2cc..7257057616042 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx @@ -22,6 +22,7 @@ import { IndexPatternColumn } from '../operations'; import { documentField } from '../document_field'; import { OperationMetadata } from '../../types'; import { DateHistogramIndexPatternColumn } from '../operations/definitions/date_histogram'; +import { keyBy } from 'lodash'; jest.mock('../loader'); jest.mock('../state_helpers'); @@ -34,6 +35,42 @@ jest.mock('lodash', () => { }; }); +const fields = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + exists: true, + }, + documentField, +]; + const expectedIndexPatterns = { 1: { id: '1', @@ -41,41 +78,8 @@ const expectedIndexPatterns = { timeFieldName: 'timestamp', hasExistence: true, hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - exists: true, - }, - documentField, - ], + fields, + fieldsMap: keyBy(fields, 'name'), }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.test.ts index bbd1d4e0ae3ab..af4d310055848 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.test.ts @@ -15,9 +15,46 @@ import { IndexPatternPrivateState } from '../types'; import { documentField } from '../document_field'; import { OperationMetadata } from '../../types'; import { IndexPatternColumn } from '../operations'; +import { keyBy } from 'lodash'; jest.mock('../state_helpers'); +const fields = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + exists: true, + }, + documentField, +]; + const expectedIndexPatterns = { 1: { id: '1', @@ -25,41 +62,8 @@ const expectedIndexPatterns = { timeFieldName: 'timestamp', hasExistence: true, hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - exists: true, - }, - documentField, - ], + fields, + fieldsMap: keyBy(fields, 'name'), }, }; @@ -176,6 +180,22 @@ describe('IndexPatternDimensionEditorPanel', () => { type: 'string', }, ], + fieldsMap: { + bar: { + aggregatable: true, + name: 'bar', + displayName: 'bar', + searchable: true, + type: 'number', + }, + mystring: { + aggregatable: true, + name: 'mystring', + displayName: 'mystring', + searchable: true, + type: 'string', + }, + }, }, }, currentIndexPatternId: '1', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts index a3f48b162475a..851c3d9f39a5d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts @@ -12,121 +12,128 @@ import { IndexPatternPersistedState, IndexPatternPrivateState } from './types'; import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; import { Ast } from '@kbn/interpreter/common'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; +import { keyBy } from 'lodash'; jest.mock('./loader'); jest.mock('../id_generator'); -const expectedIndexPatterns = { - 1: { - id: '1', - title: 'my-fake-index-pattern', - timeFieldName: 'timestamp', - hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, +const fieldsOne = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'start_date', + displayName: 'start_date', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'dest', + displayName: 'dest', + type: 'string', + aggregatable: true, + searchable: true, + }, +]; + +const fieldsTwo = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + fixed_interval: '1d', + delay: '7d', + time_zone: 'UTC', }, - { - name: 'start_date', - displayName: 'start_date', - type: 'date', - aggregatable: true, - searchable: true, + }, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + // Ignored in the UI + histogram: { + agg: 'histogram', + interval: 1000, }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, + avg: { + agg: 'avg', }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, + max: { + agg: 'max', }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, + min: { + agg: 'min', }, - { - name: 'dest', - displayName: 'dest', - type: 'string', - aggregatable: true, - searchable: true, + sum: { + agg: 'sum', }, - ], + }, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + terms: { + agg: 'terms', + }, + }, + }, +]; + +const expectedIndexPatterns = { + 1: { + id: '1', + title: 'my-fake-index-pattern', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields: fieldsOne, + fieldsMap: keyBy(fieldsOne, 'name'), }, 2: { id: '2', title: 'my-fake-restricted-pattern', timeFieldName: 'timestamp', hasRestrictions: true, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - date_histogram: { - agg: 'date_histogram', - fixed_interval: '1d', - delay: '7d', - time_zone: 'UTC', - }, - }, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - // Ignored in the UI - histogram: { - agg: 'histogram', - interval: 1000, - }, - avg: { - agg: 'avg', - }, - max: { - agg: 'max', - }, - min: { - agg: 'min', - }, - sum: { - agg: 'sum', - }, - }, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - terms: { - agg: 'terms', - }, - }, - }, - ], + fields: fieldsTwo, + fieldsMap: keyBy(fieldsTwo, 'name'), }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx index c8cb9fcb33ba9..69ee1eba74237 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx @@ -12,121 +12,128 @@ import { getDatasourceSuggestionsFromCurrentState, getDatasourceSuggestionsForVisualizeField, } from './indexpattern_suggestions'; +import { keyBy } from 'lodash'; jest.mock('./loader'); jest.mock('../id_generator'); -const expectedIndexPatterns = { - 1: { - id: '1', - title: 'my-fake-index-pattern', - timeFieldName: 'timestamp', - hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, +const fieldsOne = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'start_date', + displayName: 'start_date', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'dest', + displayName: 'dest', + type: 'string', + aggregatable: true, + searchable: true, + }, +]; + +const fieldsTwo = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + fixed_interval: '1d', + delay: '7d', + time_zone: 'UTC', }, - { - name: 'start_date', - displayName: 'start_date', - type: 'date', - aggregatable: true, - searchable: true, + }, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + // Ignored in the UI + histogram: { + agg: 'histogram', + interval: 1000, }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, + avg: { + agg: 'avg', }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, + max: { + agg: 'max', }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, + min: { + agg: 'min', }, - { - name: 'dest', - displayName: 'dest', - type: 'string', - aggregatable: true, - searchable: true, + sum: { + agg: 'sum', }, - ], + }, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + terms: { + agg: 'terms', + }, + }, + }, +]; + +const expectedIndexPatterns = { + 1: { + id: '1', + title: 'my-fake-index-pattern', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields: fieldsOne, + fieldsMap: keyBy(fieldsOne, 'name'), }, 2: { id: '2', title: 'my-fake-restricted-pattern', hasRestrictions: true, timeFieldName: 'timestamp', - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - date_histogram: { - agg: 'date_histogram', - fixed_interval: '1d', - delay: '7d', - time_zone: 'UTC', - }, - }, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - // Ignored in the UI - histogram: { - agg: 'histogram', - interval: 1000, - }, - avg: { - agg: 'avg', - }, - max: { - agg: 'max', - }, - min: { - agg: 'min', - }, - sum: { - agg: 'sum', - }, - }, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - terms: { - agg: 'terms', - }, - }, - }, - ], + fields: fieldsTwo, + fieldsMap: keyBy(fieldsTwo, 'name'), }, }; @@ -335,6 +342,15 @@ describe('IndexPattern Data Source suggestions', () => { searchable: true, }, ], + fieldsMap: { + bytes: { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + }, }, }, layers: { @@ -546,6 +562,15 @@ describe('IndexPattern Data Source suggestions', () => { searchable: true, }, ], + fieldsMap: { + bytes: { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + }, }, }, layers: { @@ -1531,6 +1556,43 @@ describe('IndexPattern Data Source suggestions', () => { it('returns simplified versions of table with more than 2 columns', () => { const initialState = testInitialState(); + const fields = [ + { + name: 'field1', + displayName: 'field1', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'field2', + displayName: 'field2', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'field3', + displayName: 'field3Label', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'field4', + displayName: 'field4', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'field5', + displayName: 'field5', + type: 'number', + aggregatable: true, + searchable: true, + }, + ]; const state: IndexPatternPrivateState = { indexPatternRefs: [], existingFields: {}, @@ -1540,43 +1602,8 @@ describe('IndexPattern Data Source suggestions', () => { id: '1', title: 'my-fake-index-pattern', hasRestrictions: false, - fields: [ - { - name: 'field1', - displayName: 'field1', - type: 'string', - aggregatable: true, - searchable: true, - }, - { - name: 'field2', - displayName: 'field2', - type: 'string', - aggregatable: true, - searchable: true, - }, - { - name: 'field3', - displayName: 'field3Label', - type: 'string', - aggregatable: true, - searchable: true, - }, - { - name: 'field4', - displayName: 'field4', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'field5', - displayName: 'field5', - type: 'number', - aggregatable: true, - searchable: true, - }, - ], + fields, + fieldsMap: keyBy(fields, 'name'), }, }, isFirstExistenceFetch: false, @@ -1700,6 +1727,22 @@ describe('IndexPattern Data Source suggestions', () => { searchable: true, }, ], + fieldsMap: { + field1: { + name: 'field1', + displayName: 'field1', + type: 'number', + aggregatable: true, + searchable: true, + }, + field2: { + name: 'field2', + displayName: 'field2', + type: 'date', + aggregatable: true, + searchable: true, + }, + }, }, }, isFirstExistenceFetch: false, @@ -1756,6 +1799,15 @@ describe('IndexPattern Data Source suggestions', () => { searchable: true, }, ], + fieldsMap: { + field1: { + name: 'field1', + displayName: 'field1', + type: 'number', + aggregatable: true, + searchable: true, + }, + }, }, }, isFirstExistenceFetch: false, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx index 92e35b257f24a..4a0e55bb6d877 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx @@ -11,6 +11,7 @@ import { shallowWithIntl as shallow } from 'test_utils/enzyme_helpers'; import { ShallowWrapper } from 'enzyme'; import { EuiSelectable } from '@elastic/eui'; import { ChangeIndexPattern } from './change_indexpattern'; +import { keyBy } from 'lodash'; jest.mock('./state_helpers'); @@ -19,6 +20,120 @@ interface IndexPatternPickerOption { checked?: 'on' | 'off'; } +const fieldsOne = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'unsupported', + displayName: 'unsupported', + type: 'geo', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, +]; + +const fieldsTwo = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + fixed_interval: '1d', + delay: '7d', + time_zone: 'UTC', + }, + }, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + histogram: { + agg: 'histogram', + interval: 1000, + }, + max: { + agg: 'max', + }, + min: { + agg: 'min', + }, + sum: { + agg: 'sum', + }, + }, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + terms: { + agg: 'terms', + }, + }, + }, +]; + +const fieldsThree = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, +]; + const initialState: IndexPatternPrivateState = { indexPatternRefs: [ { id: '1', title: 'my-fake-index-pattern' }, @@ -63,129 +178,24 @@ const initialState: IndexPatternPrivateState = { title: 'my-fake-index-pattern', timeFieldName: 'timestamp', hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'unsupported', - displayName: 'unsupported', - type: 'geo', - aggregatable: true, - searchable: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }, - ], + fields: fieldsOne, + fieldsMap: keyBy(fieldsOne, 'name'), }, '2': { id: '2', title: 'my-fake-restricted-pattern', hasRestrictions: true, timeFieldName: 'timestamp', - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - date_histogram: { - agg: 'date_histogram', - fixed_interval: '1d', - delay: '7d', - time_zone: 'UTC', - }, - }, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - histogram: { - agg: 'histogram', - interval: 1000, - }, - max: { - agg: 'max', - }, - min: { - agg: 'min', - }, - sum: { - agg: 'sum', - }, - }, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - terms: { - agg: 'terms', - }, - }, - }, - ], + fields: fieldsTwo, + fieldsMap: keyBy(fieldsTwo, 'name'), }, '3': { id: '3', title: 'my-compatible-pattern', timeFieldName: 'timestamp', hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }, - ], + fields: fieldsThree, + fieldsMap: keyBy(fieldsThree, 'name'), }, }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts index 744a9f6743d09..554e2bc30eaca 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts @@ -4,15 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ +import { keyBy } from 'lodash'; import { DragContextState } from '../drag_drop'; import { IndexPattern } from './types'; -export const createMockedIndexPattern = (): IndexPattern => ({ - id: '1', - title: 'my-fake-index-pattern', - timeFieldName: 'timestamp', - hasRestrictions: false, - fields: [ +export const createMockedIndexPattern = (): IndexPattern => { + const fields = [ { name: 'timestamp', displayName: 'timestampLabel', @@ -74,16 +71,19 @@ export const createMockedIndexPattern = (): IndexPattern => ({ lang: 'painless', script: '1234', }, - ], -}); + ]; + return { + id: '1', + title: 'my-fake-index-pattern', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields, + fieldsMap: keyBy(fields, 'name'), + }; +}; -export const createMockedRestrictedIndexPattern = () => ({ - id: '2', - title: 'my-fake-restricted-pattern', - timeFieldName: 'timestamp', - hasRestrictions: true, - fieldFormatMap: { bytes: { id: 'bytes', params: { pattern: '0.0' } } }, - fields: [ +export const createMockedRestrictedIndexPattern = () => { + const fields = [ { name: 'timestamp', displayName: 'timestampLabel', @@ -109,54 +109,63 @@ export const createMockedRestrictedIndexPattern = () => ({ lang: 'painless', script: '1234', }, - ], - typeMeta: { - params: { - rollup_index: 'my-fake-index-pattern', - }, - aggs: { - terms: { - source: { - agg: 'terms', - }, + ]; + return { + id: '2', + title: 'my-fake-restricted-pattern', + timeFieldName: 'timestamp', + hasRestrictions: true, + fieldFormatMap: { bytes: { id: 'bytes', params: { pattern: '0.0' } } }, + fields, + fieldsMap: keyBy(fields, 'name'), + typeMeta: { + params: { + rollup_index: 'my-fake-index-pattern', }, - date_histogram: { - timestamp: { - agg: 'date_histogram', - fixed_interval: '1d', - delay: '7d', - time_zone: 'UTC', + aggs: { + terms: { + source: { + agg: 'terms', + }, }, - }, - histogram: { - bytes: { - agg: 'histogram', - interval: 1000, + date_histogram: { + timestamp: { + agg: 'date_histogram', + fixed_interval: '1d', + delay: '7d', + time_zone: 'UTC', + }, }, - }, - avg: { - bytes: { - agg: 'avg', + histogram: { + bytes: { + agg: 'histogram', + interval: 1000, + }, }, - }, - max: { - bytes: { - agg: 'max', + avg: { + bytes: { + agg: 'avg', + }, }, - }, - min: { - bytes: { - agg: 'min', + max: { + bytes: { + agg: 'max', + }, }, - }, - sum: { - bytes: { - agg: 'sum', + min: { + bytes: { + agg: 'min', + }, + }, + sum: { + bytes: { + agg: 'sum', + }, }, }, }, - }, -}); + }; +}; export function createMockedDragDropContext(): jest.Mocked { return { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx index ac6bf63c37110..27d9ced3f121f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx @@ -66,6 +66,16 @@ describe('date_histogram', () => { searchable: true, }, ], + fieldsMap: { + timestamp: { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + esTypes: ['date'], + aggregatable: true, + searchable: true, + }, + }, }, 2: { id: '2', @@ -81,6 +91,16 @@ describe('date_histogram', () => { searchable: true, }, ], + fieldsMap: { + other_timestamp: { + name: 'other_timestamp', + displayName: 'other_timestamp', + type: 'date', + esTypes: ['date'], + aggregatable: true, + searchable: true, + }, + }, }, }, layers: { @@ -267,6 +287,22 @@ describe('date_histogram', () => { }, }, ], + fieldsMap: { + timestamp: { + name: 'timestamp', + displayName: 'timestamp', + aggregatable: true, + searchable: true, + type: 'date', + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + time_zone: 'UTC', + calendar_interval: '42w', + }, + }, + }, + }, } ); expect(esAggsConfig).toEqual( @@ -356,6 +392,22 @@ describe('date_histogram', () => { }, }, ], + fieldsMap: { + dateField: { + name: 'dateField', + displayName: 'dateField', + type: 'date', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + time_zone: 'CET', + calendar_interval: 'w', + }, + }, + }, + }, } ); expect(transferedColumn).toEqual( @@ -393,6 +445,15 @@ describe('date_histogram', () => { searchable: true, }, ], + fieldsMap: { + dateField: { + name: 'dateField', + displayName: 'dateField', + type: 'date', + aggregatable: true, + searchable: true, + }, + }, } ); expect(transferedColumn).toEqual( @@ -609,6 +670,18 @@ describe('date_histogram', () => { }, }, ], + fieldsMap: { + [state.indexPatterns[1].fields[0].name]: { + ...state.indexPatterns[1].fields[0], + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + time_zone: 'UTC', + calendar_interval: '1h', + }, + }, + }, + }, }, }, }} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx index c8a8ffa7b128f..ede2862e958d0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx @@ -96,6 +96,9 @@ describe('ranges', () => { title: 'my_index_pattern', hasRestrictions: false, fields: [{ name: sourceField, type: 'number', displayName: sourceField }], + fieldsMap: { + [sourceField]: { name: sourceField, type: 'number', displayName: sourceField }, + }, }, }, existingFields: {}, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts index 6808bc724f26b..5e61eb6a89aa6 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts @@ -8,38 +8,42 @@ import { getOperationTypesForField, getAvailableOperationsByMetadata, buildColum import { AvgIndexPatternColumn } from './definitions/metrics'; import { IndexPatternPrivateState } from '../types'; import { documentField } from '../document_field'; +import { keyBy } from 'lodash'; jest.mock('../loader'); +const fields = [ + { + name: 'timestamp', + displayName: 'timestamp', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, +]; + const expectedIndexPatterns = { 1: { id: '1', title: 'my-fake-index-pattern', timeFieldName: 'timestamp', hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestamp', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }, - ], + fields, + fieldsMap: keyBy(fields, 'name'), }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts index da90a2ce5fcec..baca6dbd5a837 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts @@ -16,6 +16,7 @@ import { TermsIndexPatternColumn } from './operations/definitions/terms'; import { DateHistogramIndexPatternColumn } from './operations/definitions/date_histogram'; import { AvgIndexPatternColumn } from './operations/definitions/metrics'; import { IndexPattern, IndexPatternPrivateState, IndexPatternLayer } from './types'; +import { keyBy } from 'lodash'; jest.mock('./operations'); @@ -585,59 +586,61 @@ describe('state_helpers', () => { }); describe('updateLayerIndexPattern', () => { - const indexPattern: IndexPattern = { - id: 'test', - title: '', - hasRestrictions: true, - fields: [ - { - name: 'fieldA', - displayName: 'fieldA', - aggregatable: true, - searchable: true, - type: 'string', - }, - { - name: 'fieldB', - displayName: 'fieldB', - aggregatable: true, - searchable: true, - type: 'number', - aggregationRestrictions: { - avg: { - agg: 'avg', - }, + const fields = [ + { + name: 'fieldA', + displayName: 'fieldA', + aggregatable: true, + searchable: true, + type: 'string', + }, + { + name: 'fieldB', + displayName: 'fieldB', + aggregatable: true, + searchable: true, + type: 'number', + aggregationRestrictions: { + avg: { + agg: 'avg', }, }, - { - name: 'fieldC', - displayName: 'fieldC', - aggregatable: false, - searchable: true, - type: 'date', - }, - { - name: 'fieldD', - displayName: 'fieldD', - aggregatable: true, - searchable: true, - type: 'date', - aggregationRestrictions: { - date_histogram: { - agg: 'date_histogram', - time_zone: 'CET', - calendar_interval: 'w', - }, + }, + { + name: 'fieldC', + displayName: 'fieldC', + aggregatable: false, + searchable: true, + type: 'date', + }, + { + name: 'fieldD', + displayName: 'fieldD', + aggregatable: true, + searchable: true, + type: 'date', + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + time_zone: 'CET', + calendar_interval: 'w', }, }, - { - name: 'fieldE', - displayName: 'fieldE', - aggregatable: true, - searchable: true, - type: 'date', - }, - ], + }, + { + name: 'fieldE', + displayName: 'fieldE', + aggregatable: true, + searchable: true, + type: 'date', + }, + ]; + const indexPattern: IndexPattern = { + id: 'test', + title: '', + hasRestrictions: true, + fieldsMap: keyBy(fields, 'name'), + fields, }; it('should switch index pattern id in layer', () => { From 7b0ac89c8c2ea52fbd9bbeb31364813399c559ed Mon Sep 17 00:00:00 2001 From: dej611 Date: Fri, 6 Nov 2020 12:07:13 +0100 Subject: [PATCH 03/10] :sparkles: Migrate from map to method --- .../datapanel.test.tsx | 12 +++--- .../dimension_panel/dimension_panel.test.tsx | 4 +- .../dimension_panel/droppable.test.ts | 13 ++++--- .../indexpattern.test.ts | 6 +-- .../indexpattern_suggestions.test.tsx | 36 +++++++++--------- .../indexpattern_suggestions.ts | 19 ++++++---- .../layerpanel.test.tsx | 8 ++-- .../public/indexpattern_datasource/loader.ts | 3 +- .../public/indexpattern_datasource/mocks.ts | 6 +-- .../operations/definitions/cardinality.tsx | 2 +- .../definitions/date_histogram.test.tsx | 38 ++++++++++--------- .../operations/definitions/date_histogram.tsx | 10 ++--- .../operations/definitions/metrics.tsx | 2 +- .../definitions/ranges/ranges.test.tsx | 7 ++-- .../operations/definitions/ranges/ranges.tsx | 4 +- .../operations/definitions/terms/index.tsx | 2 +- .../operations/operations.test.ts | 4 +- .../indexpattern_datasource/pure_helpers.ts | 8 +++- .../state_helpers.test.ts | 4 +- .../public/indexpattern_datasource/types.ts | 2 +- 20 files changed, 104 insertions(+), 86 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx index a8419afd9e2db..d2ec1c81bbeec 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx @@ -18,7 +18,7 @@ import { ChangeIndexPattern } from './change_indexpattern'; import { EuiProgress, EuiLoadingSpinner } from '@elastic/eui'; import { documentField } from './document_field'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; -import { keyBy } from 'lodash'; +import { getFieldByNameFactory } from './pure_helpers'; const fieldsOne = [ { @@ -211,7 +211,7 @@ const initialState: IndexPatternPrivateState = { timeFieldName: 'timestamp', hasRestrictions: false, fields: fieldsOne, - fieldsMap: keyBy(fieldsOne, 'name'), + getFieldByName: getFieldByNameFactory(fieldsOne), }, '2': { id: '2', @@ -219,7 +219,7 @@ const initialState: IndexPatternPrivateState = { timeFieldName: 'timestamp', hasRestrictions: true, fields: fieldsTwo, - fieldsMap: keyBy(fieldsTwo, 'name'), + getFieldByName: getFieldByNameFactory(fieldsTwo), }, '3': { id: '3', @@ -227,7 +227,7 @@ const initialState: IndexPatternPrivateState = { timeFieldName: 'timestamp', hasRestrictions: false, fields: fieldsThree, - fieldsMap: keyBy(fieldsThree, 'name'), + getFieldByName: getFieldByNameFactory(fieldsThree), }, }, isFirstExistenceFetch: false, @@ -340,7 +340,7 @@ describe('IndexPattern Data Panel', () => { title: 'aaa', timeFieldName: 'atime', fields: [], - fieldsMap: {}, + getFieldByName: getFieldByNameFactory([]), hasRestrictions: false, }, b: { @@ -348,7 +348,7 @@ describe('IndexPattern Data Panel', () => { title: 'bbb', timeFieldName: 'btime', fields: [], - fieldsMap: {}, + getFieldByName: getFieldByNameFactory([]), hasRestrictions: false, }, }, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx index 7257057616042..4ff57450edbb3 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx @@ -22,7 +22,7 @@ import { IndexPatternColumn } from '../operations'; import { documentField } from '../document_field'; import { OperationMetadata } from '../../types'; import { DateHistogramIndexPatternColumn } from '../operations/definitions/date_histogram'; -import { keyBy } from 'lodash'; +import { getFieldByNameFactory } from '../pure_helpers'; jest.mock('../loader'); jest.mock('../state_helpers'); @@ -79,7 +79,7 @@ const expectedIndexPatterns = { hasExistence: true, hasRestrictions: false, fields, - fieldsMap: keyBy(fields, 'name'), + getFieldByName: getFieldByNameFactory(fields), }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.test.ts index af4d310055848..89175ee442d22 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.test.ts @@ -15,7 +15,7 @@ import { IndexPatternPrivateState } from '../types'; import { documentField } from '../document_field'; import { OperationMetadata } from '../../types'; import { IndexPatternColumn } from '../operations'; -import { keyBy } from 'lodash'; +import { getFieldByNameFactory } from '../pure_helpers'; jest.mock('../state_helpers'); @@ -63,7 +63,7 @@ const expectedIndexPatterns = { hasExistence: true, hasRestrictions: false, fields, - fieldsMap: keyBy(fields, 'name'), + getFieldByName: getFieldByNameFactory(fields), }, }; @@ -180,22 +180,23 @@ describe('IndexPatternDimensionEditorPanel', () => { type: 'string', }, ], - fieldsMap: { - bar: { + + getFieldByName: getFieldByNameFactory([ + { aggregatable: true, name: 'bar', displayName: 'bar', searchable: true, type: 'number', }, - mystring: { + { aggregatable: true, name: 'mystring', displayName: 'mystring', searchable: true, type: 'string', }, - }, + ]), }, }, currentIndexPatternId: '1', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts index 851c3d9f39a5d..51d95245adb25 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts @@ -12,7 +12,7 @@ import { IndexPatternPersistedState, IndexPatternPrivateState } from './types'; import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; import { Ast } from '@kbn/interpreter/common'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; -import { keyBy } from 'lodash'; +import { getFieldByNameFactory } from './pure_helpers'; jest.mock('./loader'); jest.mock('../id_generator'); @@ -125,7 +125,7 @@ const expectedIndexPatterns = { timeFieldName: 'timestamp', hasRestrictions: false, fields: fieldsOne, - fieldsMap: keyBy(fieldsOne, 'name'), + getFieldByName: getFieldByNameFactory(fieldsOne), }, 2: { id: '2', @@ -133,7 +133,7 @@ const expectedIndexPatterns = { timeFieldName: 'timestamp', hasRestrictions: true, fields: fieldsTwo, - fieldsMap: keyBy(fieldsTwo, 'name'), + getFieldByName: getFieldByNameFactory(fieldsTwo), }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx index 69ee1eba74237..523a1be34ba3d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx @@ -12,7 +12,7 @@ import { getDatasourceSuggestionsFromCurrentState, getDatasourceSuggestionsForVisualizeField, } from './indexpattern_suggestions'; -import { keyBy } from 'lodash'; +import { getFieldByNameFactory } from './pure_helpers'; jest.mock('./loader'); jest.mock('../id_generator'); @@ -125,7 +125,7 @@ const expectedIndexPatterns = { timeFieldName: 'timestamp', hasRestrictions: false, fields: fieldsOne, - fieldsMap: keyBy(fieldsOne, 'name'), + getFieldByName: getFieldByNameFactory(fieldsOne), }, 2: { id: '2', @@ -133,7 +133,7 @@ const expectedIndexPatterns = { hasRestrictions: true, timeFieldName: 'timestamp', fields: fieldsTwo, - fieldsMap: keyBy(fieldsTwo, 'name'), + getFieldByName: getFieldByNameFactory(fieldsTwo), }, }; @@ -342,15 +342,15 @@ describe('IndexPattern Data Source suggestions', () => { searchable: true, }, ], - fieldsMap: { - bytes: { + getFieldByName: getFieldByNameFactory([ + { name: 'bytes', displayName: 'bytes', type: 'number', aggregatable: true, searchable: true, }, - }, + ]), }, }, layers: { @@ -562,15 +562,16 @@ describe('IndexPattern Data Source suggestions', () => { searchable: true, }, ], - fieldsMap: { - bytes: { + + getFieldByName: getFieldByNameFactory([ + { name: 'bytes', displayName: 'bytes', type: 'number', aggregatable: true, searchable: true, }, - }, + ]), }, }, layers: { @@ -1603,7 +1604,7 @@ describe('IndexPattern Data Source suggestions', () => { title: 'my-fake-index-pattern', hasRestrictions: false, fields, - fieldsMap: keyBy(fields, 'name'), + getFieldByName: getFieldByNameFactory(fields), }, }, isFirstExistenceFetch: false, @@ -1727,22 +1728,23 @@ describe('IndexPattern Data Source suggestions', () => { searchable: true, }, ], - fieldsMap: { - field1: { + + getFieldByName: getFieldByNameFactory([ + { name: 'field1', displayName: 'field1', type: 'number', aggregatable: true, searchable: true, }, - field2: { + { name: 'field2', displayName: 'field2', type: 'date', aggregatable: true, searchable: true, }, - }, + ]), }, }, isFirstExistenceFetch: false, @@ -1799,15 +1801,15 @@ describe('IndexPattern Data Source suggestions', () => { searchable: true, }, ], - fieldsMap: { - field1: { + getFieldByName: getFieldByNameFactory([ + { name: 'field1', displayName: 'field1', type: 'number', aggregatable: true, searchable: true, }, - }, + ]), }, }, isFirstExistenceFetch: false, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts index 7b9cd9d4b9b77..c12d7d4be226b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts @@ -128,7 +128,7 @@ export function getDatasourceSuggestionsForVisualizeField( const layerIds = layers.filter((id) => state.layers[id].indexPatternId === indexPatternId); // Identify the field by the indexPatternId and the fieldName const indexPattern = state.indexPatterns[indexPatternId]; - const field = indexPattern.fieldsMap[fieldName]; + const field = indexPattern.getFieldByName(fieldName); if (layerIds.length !== 0 || !field) return []; const newId = generateId(); @@ -371,7 +371,7 @@ function createNewLayerWithMetricAggregation( indexPattern: IndexPattern, field: IndexPatternField ): IndexPatternLayer { - const dateField = indexPattern.fieldsMap[indexPattern.timeFieldName!]; + const dateField = indexPattern.getFieldByName(indexPattern.timeFieldName!); const column = getMetricColumn(indexPattern, layerId, field); @@ -452,7 +452,7 @@ export function getDatasourceSuggestionsFromCurrentState( layer.columns[columnId].isBucketed && layer.columns[columnId].dataType === 'date' ); const timeField = - indexPattern.timeFieldName && indexPattern.fieldsMap[indexPattern.timeFieldName]; + indexPattern.timeFieldName && indexPattern.getFieldByName(indexPattern.timeFieldName); const hasNumericDimension = buckets.length === 1 && @@ -506,14 +506,16 @@ function createChangedNestingSuggestion(state: IndexPatternPrivateState, layerId const layer = state.layers[layerId]; const [firstBucket, secondBucket, ...rest] = layer.columnOrder; const updatedLayer = { ...layer, columnOrder: [secondBucket, firstBucket, ...rest] }; - const currentFields = state.indexPatterns[state.currentIndexPatternId].fieldsMap; + const indexPattern = state.indexPatterns[state.currentIndexPatternId]; const firstBucketColumn = layer.columns[firstBucket]; const firstBucketLabel = - (hasField(firstBucketColumn) && currentFields[firstBucketColumn.sourceField]?.displayName) || + (hasField(firstBucketColumn) && + indexPattern.getFieldByName(firstBucketColumn.sourceField)?.displayName) || ''; const secondBucketColumn = layer.columns[secondBucket]; const secondBucketLabel = - (hasField(secondBucketColumn) && currentFields[secondBucketColumn.sourceField]?.displayName) || + (hasField(secondBucketColumn) && + indexPattern.getFieldByName(secondBucketColumn.sourceField)?.displayName) || ''; return buildSuggestion({ @@ -601,7 +603,10 @@ function createAlternativeMetricSuggestions( if (!hasField(column)) { return; } - const field = indexPattern.fieldsMap[column.sourceField]!; + const field = indexPattern.getFieldByName(column.sourceField); + if (!field) { + return; + } const alternativeMetricOperations = getOperationTypesForField(field) .map((op) => buildColumn({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx index 4a0e55bb6d877..40eb52fe67c6d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx @@ -11,7 +11,7 @@ import { shallowWithIntl as shallow } from 'test_utils/enzyme_helpers'; import { ShallowWrapper } from 'enzyme'; import { EuiSelectable } from '@elastic/eui'; import { ChangeIndexPattern } from './change_indexpattern'; -import { keyBy } from 'lodash'; +import { getFieldByNameFactory } from './pure_helpers'; jest.mock('./state_helpers'); @@ -179,7 +179,7 @@ const initialState: IndexPatternPrivateState = { timeFieldName: 'timestamp', hasRestrictions: false, fields: fieldsOne, - fieldsMap: keyBy(fieldsOne, 'name'), + getFieldByName: getFieldByNameFactory(fieldsOne), }, '2': { id: '2', @@ -187,7 +187,7 @@ const initialState: IndexPatternPrivateState = { hasRestrictions: true, timeFieldName: 'timestamp', fields: fieldsTwo, - fieldsMap: keyBy(fieldsTwo, 'name'), + getFieldByName: getFieldByNameFactory(fieldsTwo), }, '3': { id: '3', @@ -195,7 +195,7 @@ const initialState: IndexPatternPrivateState = { timeFieldName: 'timestamp', hasRestrictions: false, fields: fieldsThree, - fieldsMap: keyBy(fieldsThree, 'name'), + getFieldByName: getFieldByNameFactory(fieldsThree), }, }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts index 5554e612fd33b..fac5d7350e45e 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts @@ -26,6 +26,7 @@ import { import { VisualizeFieldContext } from '../../../../../src/plugins/ui_actions/public'; import { documentField } from './document_field'; import { readFromStorage, writeToStorage } from '../settings_storage'; +import { getFieldByNameFactory } from './pure_helpers'; type SetState = StateSetter; type SavedObjectsClient = Pick; @@ -112,7 +113,7 @@ export async function loadIndexPatterns({ ]) ), fields: newFields, - fieldsMap: _.keyBy(newFields, 'name'), + getFieldByName: getFieldByNameFactory(newFields), hasRestrictions: !!typeMeta?.aggs, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts index 554e2bc30eaca..2c6f42668d863 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { keyBy } from 'lodash'; import { DragContextState } from '../drag_drop'; +import { getFieldByNameFactory } from './pure_helpers'; import { IndexPattern } from './types'; export const createMockedIndexPattern = (): IndexPattern => { @@ -78,7 +78,7 @@ export const createMockedIndexPattern = (): IndexPattern => { timeFieldName: 'timestamp', hasRestrictions: false, fields, - fieldsMap: keyBy(fields, 'name'), + getFieldByName: getFieldByNameFactory(fields), }; }; @@ -117,7 +117,7 @@ export const createMockedRestrictedIndexPattern = () => { hasRestrictions: true, fieldFormatMap: { bytes: { id: 'bytes', params: { pattern: '0.0' } } }, fields, - fieldsMap: keyBy(fields, 'name'), + getFieldByName: getFieldByNameFactory(fields), typeMeta: { params: { rollup_index: 'my-fake-index-pattern', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx index b161a291ac3da..1cfa63511a45c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx @@ -43,7 +43,7 @@ export const cardinalityOperation: OperationDefinition { - const newField = newIndexPattern.fieldsMap[column.sourceField]; + const newField = newIndexPattern.getFieldByName(column.sourceField); return Boolean( newField && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx index 27d9ced3f121f..7d16f11ad2b16 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx @@ -18,6 +18,7 @@ import { } from '../../../../../../../src/plugins/data/public/mocks'; import { createMockedIndexPattern } from '../../mocks'; import { IndexPatternPrivateState } from '../../types'; +import { getFieldByNameFactory } from '../../pure_helpers'; const dataStart = dataPluginMock.createStartContract(); dataStart.search.aggs.calculateAutoTimeExpression = getCalculateAutoTimeExpression( @@ -66,8 +67,9 @@ describe('date_histogram', () => { searchable: true, }, ], - fieldsMap: { - timestamp: { + + getFieldByName: getFieldByNameFactory([ + { name: 'timestamp', displayName: 'timestampLabel', type: 'date', @@ -75,7 +77,7 @@ describe('date_histogram', () => { aggregatable: true, searchable: true, }, - }, + ]), }, 2: { id: '2', @@ -91,8 +93,8 @@ describe('date_histogram', () => { searchable: true, }, ], - fieldsMap: { - other_timestamp: { + getFieldByName: getFieldByNameFactory([ + { name: 'other_timestamp', displayName: 'other_timestamp', type: 'date', @@ -100,7 +102,7 @@ describe('date_histogram', () => { aggregatable: true, searchable: true, }, - }, + ]), }, }, layers: { @@ -287,8 +289,8 @@ describe('date_histogram', () => { }, }, ], - fieldsMap: { - timestamp: { + getFieldByName: getFieldByNameFactory([ + { name: 'timestamp', displayName: 'timestamp', aggregatable: true, @@ -302,7 +304,7 @@ describe('date_histogram', () => { }, }, }, - }, + ]), } ); expect(esAggsConfig).toEqual( @@ -392,8 +394,8 @@ describe('date_histogram', () => { }, }, ], - fieldsMap: { - dateField: { + getFieldByName: getFieldByNameFactory([ + { name: 'dateField', displayName: 'dateField', type: 'date', @@ -407,7 +409,7 @@ describe('date_histogram', () => { }, }, }, - }, + ]), } ); expect(transferedColumn).toEqual( @@ -445,15 +447,15 @@ describe('date_histogram', () => { searchable: true, }, ], - fieldsMap: { - dateField: { + getFieldByName: getFieldByNameFactory([ + { name: 'dateField', displayName: 'dateField', type: 'date', aggregatable: true, searchable: true, }, - }, + ]), } ); expect(transferedColumn).toEqual( @@ -670,8 +672,8 @@ describe('date_histogram', () => { }, }, ], - fieldsMap: { - [state.indexPatterns[1].fields[0].name]: { + getFieldByName: getFieldByNameFactory([ + { ...state.indexPatterns[1].fields[0], aggregationRestrictions: { date_histogram: { @@ -681,7 +683,7 @@ describe('date_histogram', () => { }, }, }, - }, + ]), }, }, }} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.tsx index 59f171f3a3234..19043c03e5a61 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.tsx @@ -81,7 +81,7 @@ export const dateHistogramOperation: OperationDefinition< }; }, isTransferable: (column, newIndexPattern) => { - const newField = newIndexPattern.fieldsMap[column.sourceField]; + const newField = newIndexPattern.getFieldByName(column.sourceField); return Boolean( newField && @@ -91,7 +91,7 @@ export const dateHistogramOperation: OperationDefinition< ); }, transfer: (column, newIndexPattern) => { - const newField = newIndexPattern.fieldsMap[column.sourceField]; + const newField = newIndexPattern.getFieldByName(column.sourceField); if (newField?.aggregationRestrictions?.date_histogram) { const restrictions = newField.aggregationRestrictions.date_histogram; @@ -120,7 +120,7 @@ export const dateHistogramOperation: OperationDefinition< }; }, toEsAggsConfig: (column, columnId, indexPattern) => { - const usedField = indexPattern.fieldsMap[column.sourceField]; + const usedField = indexPattern.getFieldByName(column.sourceField); return { id: columnId, enabled: true, @@ -140,9 +140,9 @@ export const dateHistogramOperation: OperationDefinition< paramEditor: ({ state, setState, currentColumn, layerId, dateRange, data }) => { const field = currentColumn && - state.indexPatterns[state.layers[layerId].indexPatternId].fieldsMap[ + state.indexPatterns[state.layers[layerId].indexPatternId].getFieldByName( currentColumn.sourceField - ]; + ); const intervalIsRestricted = field!.aggregationRestrictions && field!.aggregationRestrictions.date_histogram; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx index 73bc5281bbfa5..fef575c61475c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx @@ -43,7 +43,7 @@ function buildMetricOperation>({ } }, isTransferable: (column, newIndexPattern) => { - const newField = newIndexPattern.fieldsMap[column.sourceField]; + const newField = newIndexPattern.getFieldByName(column.sourceField); return Boolean( newField && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx index ede2862e958d0..a263194843986 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx @@ -30,6 +30,7 @@ import { } from './constants'; import { RangePopover } from './advanced_editor'; import { DragDropBuckets } from '../shared_components'; +import { getFieldByNameFactory } from '../../../pure_helpers'; const dataPluginMockValue = dataPluginMock.createStartContract(); // need to overwrite the formatter field first @@ -96,9 +97,9 @@ describe('ranges', () => { title: 'my_index_pattern', hasRestrictions: false, fields: [{ name: sourceField, type: 'number', displayName: sourceField }], - fieldsMap: { - [sourceField]: { name: sourceField, type: 'number', displayName: sourceField }, - }, + getFieldByName: getFieldByNameFactory([ + { name: sourceField, type: 'number', displayName: sourceField }, + ]), }, }, existingFields: {}, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx index 7c5ce17d452d6..86aa6b75cf648 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx @@ -140,7 +140,7 @@ export const rangeOperation: OperationDefinition { - const newField = newIndexPattern.fieldsMap[column.sourceField]; + const newField = newIndexPattern.getFieldByName(column.sourceField); return Boolean( newField && @@ -168,7 +168,7 @@ export const rangeOperation: OperationDefinition { const indexPattern = state.indexPatterns[state.layers[layerId].indexPatternId]; - const currentField = indexPattern.fieldsMap[currentColumn.sourceField]; + const currentField = indexPattern.getFieldByName(currentColumn.sourceField); const numberFormat = currentColumn.params.format; const numberFormatterPattern = numberFormat && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx index 128f9ff265bac..a7353435c0d41 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx @@ -54,7 +54,7 @@ export const termsOperation: OperationDefinition { - const newField = newIndexPattern.fieldsMap[column.sourceField]; + const newField = newIndexPattern.getFieldByName(column.sourceField); return Boolean( newField && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts index 5e61eb6a89aa6..9767d4bdca688 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts @@ -8,7 +8,7 @@ import { getOperationTypesForField, getAvailableOperationsByMetadata, buildColum import { AvgIndexPatternColumn } from './definitions/metrics'; import { IndexPatternPrivateState } from '../types'; import { documentField } from '../document_field'; -import { keyBy } from 'lodash'; +import { getFieldByNameFactory } from '../pure_helpers'; jest.mock('../loader'); @@ -43,7 +43,7 @@ const expectedIndexPatterns = { timeFieldName: 'timestamp', hasRestrictions: false, fields, - fieldsMap: keyBy(fields, 'name'), + getFieldByName: getFieldByNameFactory(fields), }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.ts b/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.ts index 9e81b5e0c5bf9..c5da3d0c5dcde 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IndexPatternPrivateState } from './types'; +import { keyBy } from 'lodash'; +import { IndexPatternField, IndexPatternPrivateState } from './types'; export function fieldExists( existingFields: IndexPatternPrivateState['existingFields'], @@ -13,3 +14,8 @@ export function fieldExists( ) { return existingFields[indexPatternTitle] && existingFields[indexPatternTitle][fieldName]; } + +export function getFieldByNameFactory(newFields: IndexPatternField[]) { + const fieldsLookup = keyBy(newFields, 'name'); + return (name: string) => fieldsLookup[name]; +} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts index baca6dbd5a837..45008b2d9439a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts @@ -16,7 +16,7 @@ import { TermsIndexPatternColumn } from './operations/definitions/terms'; import { DateHistogramIndexPatternColumn } from './operations/definitions/date_histogram'; import { AvgIndexPatternColumn } from './operations/definitions/metrics'; import { IndexPattern, IndexPatternPrivateState, IndexPatternLayer } from './types'; -import { keyBy } from 'lodash'; +import { getFieldByNameFactory } from './pure_helpers'; jest.mock('./operations'); @@ -639,7 +639,7 @@ describe('state_helpers', () => { id: 'test', title: '', hasRestrictions: true, - fieldsMap: keyBy(fields, 'name'), + getFieldByName: getFieldByNameFactory(fields), fields, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/types.ts b/x-pack/plugins/lens/public/indexpattern_datasource/types.ts index 0bd46b5e56e5d..1e6fc5a5806b5 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/types.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/types.ts @@ -11,7 +11,7 @@ import { IndexPatternAggRestrictions } from '../../../../../src/plugins/data/pub export interface IndexPattern { id: string; fields: IndexPatternField[]; - fieldsMap: Record; + getFieldByName(name: string): IndexPatternField | undefined; title: string; timeFieldName?: string; fieldFormatMap?: Record< From f58610554c60d790bd39ae977ec7ed23ded4c419 Mon Sep 17 00:00:00 2001 From: dej611 Date: Fri, 6 Nov 2020 14:24:55 +0100 Subject: [PATCH 04/10] :sparkles: Expand the use of the getFieldByName method --- .../indexpattern_datasource/datapanel.tsx | 5 ++-- .../bucket_nesting_editor.test.tsx | 22 ++++++++-------- .../dimension_panel/bucket_nesting_editor.tsx | 15 +++++++---- .../dimension_panel/dimension_editor.tsx | 25 ++++++++----------- .../dimension_panel/field_select.tsx | 20 +++++++-------- .../indexpattern_datasource/loader.test.ts | 13 +++------- .../definitions/date_histogram.test.tsx | 4 +-- .../definitions/terms/terms.test.tsx | 2 +- .../public/indexpattern_datasource/utils.ts | 10 ++++---- 9 files changed, 56 insertions(+), 60 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 28c5605f3bfc5..f2c7d7fc20926 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -5,7 +5,7 @@ */ import './datapanel.scss'; -import { uniq, keyBy, groupBy } from 'lodash'; +import { uniq, groupBy } from 'lodash'; import React, { useState, memo, useCallback, useMemo } from 'react'; import { EuiFlexGroup, @@ -266,9 +266,8 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ const fieldInfoUnavailable = existenceFetchFailed || currentIndexPattern.hasRestrictions; const unfilteredFieldGroups: FieldGroups = useMemo(() => { - const fieldByName = keyBy(allFields, 'name'); const containsData = (field: IndexPatternField) => { - const overallField = fieldByName[field.name]; + const overallField = currentIndexPattern.getFieldByName(field.name); return ( overallField && fieldExists(existingFields, currentIndexPattern.title, overallField.name) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.test.tsx index 3696f3ad7b102..ee6a86072236c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.test.tsx @@ -10,12 +10,14 @@ import { BucketNestingEditor } from './bucket_nesting_editor'; import { IndexPatternColumn } from '../indexpattern'; import { IndexPatternField } from '../types'; -const fieldMap = { +const fieldMap: Record = { a: { displayName: 'a' } as IndexPatternField, b: { displayName: 'b' } as IndexPatternField, c: { displayName: 'c' } as IndexPatternField, }; +const getFieldByName = (name: string): IndexPatternField | undefined => fieldMap[name]; + describe('BucketNestingEditor', () => { function mockCol(col: Partial = {}): IndexPatternColumn { const result = { @@ -39,7 +41,7 @@ describe('BucketNestingEditor', () => { it('should display the top level grouping when at the root', () => { const component = mount( { const component = mount( { const component = mount( { const component = mount( { const component = mount( { const component = mount( { const component = mount( { const component = mount( { const setColumns = jest.fn(); const component = mount( , column: IndexPatternColumn) { - return hasField(column) ? fieldMap[column.sourceField]?.displayName || column.sourceField : ''; +function getFieldName( + column: IndexPatternColumn, + getFieldByName: (name: string) => IndexPatternField | undefined +) { + return hasField(column) + ? getFieldByName(column.sourceField)?.displayName || column.sourceField + : ''; } export function BucketNestingEditor({ columnId, layer, setColumns, - fieldMap, + getFieldByName, }: { columnId: string; layer: IndexPatternLayer; setColumns: (columns: string[]) => void; - fieldMap: Record; + getFieldByName: (name: string) => IndexPatternField | undefined; }) { const column = layer.columns[columnId]; const columns = Object.entries(layer.columns); @@ -42,7 +47,7 @@ export function BucketNestingEditor({ .map(([value, c]) => ({ value, text: c.label, - fieldName: getFieldName(fieldMap, c), + fieldName: getFieldName(c, getFieldByName), operationType: c.operationType, })); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx index a18cb69db74cb..d0d250d0be257 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx @@ -97,14 +97,6 @@ export function DimensionEditor(props: DimensionEditorProps) { const ParamEditor = selectedOperationDefinition?.paramEditor; - const fieldMap: Record = useMemo(() => { - const fields: Record = {}; - currentIndexPattern.fields.forEach((field) => { - fields[field.name] = field; - }); - return fields; - }, [currentIndexPattern]); - const possibleOperations = useMemo(() => { return Object.values(operationDefinitionMap) .sort((op1, op2) => { @@ -212,7 +204,7 @@ export function DimensionEditor(props: DimensionEditorProps) { layerId: props.layerId, op: operationType, indexPattern: currentIndexPattern, - field: fieldMap[possibleFields[0]], + field: currentIndexPattern.getFieldByName(possibleFields[0]), previousColumn: selectedColumn, }), }) @@ -236,7 +228,9 @@ export function DimensionEditor(props: DimensionEditorProps) { layerId: props.layerId, op: operationType, indexPattern: currentIndexPattern, - field: hasField(selectedColumn) ? fieldMap[selectedColumn.sourceField] : undefined, + field: hasField(selectedColumn) + ? currentIndexPattern.getFieldByName(selectedColumn.sourceField) + : undefined, previousColumn: selectedColumn, }); @@ -297,7 +291,6 @@ export function DimensionEditor(props: DimensionEditorProps) { fieldIsInvalid={currentFieldIsInvalid} currentIndexPattern={currentIndexPattern} existingFields={state.existingFields} - fieldMap={fieldMap} operationSupportMatrix={operationSupportMatrix} selectedColumnOperationType={selectedColumn && selectedColumn.operationType} selectedColumnSourceField={ @@ -323,7 +316,11 @@ export function DimensionEditor(props: DimensionEditorProps) { ) { // If we just changed the field are not in an error state and the operation didn't change, // we use the operations onFieldChange method to calculate the new column. - column = changeField(selectedColumn, currentIndexPattern, fieldMap[choice.field]); + column = changeField( + selectedColumn, + currentIndexPattern, + currentIndexPattern.getFieldByName(choice.field)! + ); } else { // Otherwise we'll use the buildColumn method to calculate a new column const compatibleOperations = @@ -341,7 +338,7 @@ export function DimensionEditor(props: DimensionEditorProps) { } column = buildColumn({ columns: props.state.layers[props.layerId].columns, - field: fieldMap[choice.field], + field: currentIndexPattern.getFieldByName(choice.field), indexPattern: currentIndexPattern, layerId: props.layerId, suggestedPriority: props.suggestedPriority, @@ -417,12 +414,12 @@ export function DimensionEditor(props: DimensionEditorProps) { {!incompatibleSelectedOperationType && !hideGrouping && ( setState(mergeLayer({ state, layerId, newLayer: { columnOrder } })) } + getFieldByName={currentIndexPattern.getFieldByName} /> )} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx index b1b77f193012d..15da1914cb355 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx @@ -21,7 +21,7 @@ import { OperationType } from '../indexpattern'; import { LensFieldIcon } from '../lens_field_icon'; import { DataType } from '../../types'; import { OperationSupportMatrix } from './operation_support'; -import { IndexPattern, IndexPatternField, IndexPatternPrivateState } from '../types'; +import { IndexPattern, IndexPatternPrivateState } from '../types'; import { trackUiEvent } from '../../lens_ui_telemetry'; import { fieldExists } from '../pure_helpers'; @@ -33,7 +33,6 @@ export interface FieldChoice { export interface FieldSelectProps extends EuiComboBoxProps<{}> { currentIndexPattern: IndexPattern; - fieldMap: Record; incompatibleSelectedOperationType: OperationType | null; selectedColumnOperationType?: OperationType; selectedColumnSourceField?: string; @@ -46,7 +45,6 @@ export interface FieldSelectProps extends EuiComboBoxProps<{}> { export function FieldSelect({ currentIndexPattern, - fieldMap, incompatibleSelectedOperationType, selectedColumnOperationType, selectedColumnSourceField, @@ -73,21 +71,21 @@ export function FieldSelect({ const [specialFields, normalFields] = _.partition( fields, - (field) => fieldMap[field].type === 'document' + (field) => currentIndexPattern.getFieldByName(field)?.type === 'document' ); const containsData = (field: string) => - fieldMap[field].type === 'document' || + currentIndexPattern.getFieldByName(field)?.type === 'document' || fieldExists(existingFields, currentIndexPattern.title, field); function fieldNamesToOptions(items: string[]) { return items .map((field) => ({ - label: fieldMap[field].displayName, + label: currentIndexPattern.getFieldByName(field)?.displayName, value: { type: 'field', field, - dataType: fieldMap[field].type, + dataType: currentIndexPattern.getFieldByName(field)?.type, operationType: selectedColumnOperationType && isCompatibleWithCurrentOperation(field) ? selectedColumnOperationType @@ -118,7 +116,10 @@ export function FieldSelect({ })); } - const [metaFields, nonMetaFields] = _.partition(normalFields, (field) => fieldMap[field].meta); + const [metaFields, nonMetaFields] = _.partition( + normalFields, + (field) => currentIndexPattern.getFieldByName(field)?.meta + ); const [availableFields, emptyFields] = _.partition(nonMetaFields, containsData); const constructFieldsOptions = (fieldsArr: string[], label: string) => @@ -158,7 +159,6 @@ export function FieldSelect({ incompatibleSelectedOperationType, selectedColumnOperationType, currentIndexPattern, - fieldMap, operationByField, existingFields, ]); @@ -180,7 +180,7 @@ export function FieldSelect({ { label: fieldIsInvalid ? selectedColumnSourceField - : fieldMap[selectedColumnSourceField]?.displayName, + : currentIndexPattern.getFieldByName(selectedColumnSourceField)?.displayName, value: { type: 'field', field: selectedColumnSourceField }, }, ] diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts index 4222c02388433..adb86253ab28c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts @@ -285,15 +285,10 @@ describe('loader', () => { } as unknown) as Pick, }); - expect( - cache.foo.fields.find((f: IndexPatternField) => f.name === 'bytes')!.aggregationRestrictions - ).toEqual({ + expect(cache.foo.getFieldByName('bytes')!.aggregationRestrictions).toEqual({ sum: { agg: 'sum' }, }); - expect( - cache.foo.fields.find((f: IndexPatternField) => f.name === 'timestamp')! - .aggregationRestrictions - ).toEqual({ + expect(cache.foo.getFieldByName('timestamp')!.aggregationRestrictions).toEqual({ date_histogram: { agg: 'date_histogram', fixed_interval: 'm' }, }); }); @@ -342,9 +337,7 @@ describe('loader', () => { } as unknown) as Pick, }); - expect(cache.foo.fields.find((f: IndexPatternField) => f.name === 'timestamp')!.meta).toEqual( - true - ); + expect(cache.foo.getFieldByName('timestamp')!.meta).toEqual(true); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx index 7d16f11ad2b16..fc33b64ca508f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx @@ -332,7 +332,7 @@ describe('date_histogram', () => { }, }; const indexPattern = createMockedIndexPattern(); - const newDateField = indexPattern.fields.find((i) => i.name === 'start_date')!; + const newDateField = indexPattern.getFieldByName('start_date')!; const column = dateHistogramOperation.onFieldChange(oldColumn, indexPattern, newDateField); expect(column).toHaveProperty('sourceField', 'start_date'); @@ -352,7 +352,7 @@ describe('date_histogram', () => { }, }; const indexPattern = createMockedIndexPattern(); - const newDateField = indexPattern.fields.find((i) => i.name === 'start_date')!; + const newDateField = indexPattern.getFieldByName('start_date')!; const column = dateHistogramOperation.onFieldChange(oldColumn, indexPattern, newDateField); expect(column).toHaveProperty('sourceField', 'start_date'); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx index 2c4e67ef0d9b9..d2e245aa26dfe 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx @@ -103,7 +103,7 @@ describe('terms', () => { }, }; const indexPattern = createMockedIndexPattern(); - const newDateField = indexPattern.fields.find((i) => i.name === 'dest')!; + const newDateField = indexPattern.getFieldByName('dest')!; const column = termsOperation.onFieldChange(oldColumn, indexPattern, newDateField); expect(column).toHaveProperty('sourceField', 'dest'); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/utils.ts b/x-pack/plugins/lens/public/indexpattern_datasource/utils.ts index d3d65617f2253..d0ea81d135156 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/utils.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/utils.ts @@ -87,15 +87,15 @@ export function fieldIsInvalid( indexPattern: IndexPattern ) { const operationDefinition = operationType && operationDefinitionMap[operationType]; + const field = sourceField ? indexPattern.getFieldByName(sourceField) : undefined; return Boolean( sourceField && operationDefinition && - !indexPattern.fields.some( - (field) => - field.name === sourceField && - operationDefinition?.input === 'field' && - operationDefinition.getPossibleOperationForField(field) !== undefined + !( + field && + operationDefinition?.input === 'field' && + operationDefinition.getPossibleOperationForField(field) !== undefined ) ); } From c2bd3776c07c771664d01e9f5c495b094ee54b27 Mon Sep 17 00:00:00 2001 From: dej611 Date: Fri, 6 Nov 2020 14:25:40 +0100 Subject: [PATCH 05/10] :zap: Improve getOperationSupportMatrix performance --- .../dimension_panel/operation_support.ts | 19 ++++++++++--------- .../operations/operations.ts | 9 +++++---- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts index 2ea28da201556..5cf6751c0ca1d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts @@ -37,16 +37,17 @@ export const getOperationSupportMatrix = (props: Props): OperationSupportMatrix filteredOperationsByMetadata.forEach(({ operations }) => { operations.forEach((operation) => { + // replace spread operator by regular push as it's performance wise faster if (operation.type === 'field') { - supportedOperationsByField[operation.field] = [ - ...(supportedOperationsByField[operation.field] ?? []), - operation.operationType, - ]; - - supportedFieldsByOperation[operation.operationType] = [ - ...(supportedFieldsByOperation[operation.operationType] ?? []), - operation.field, - ]; + if (!supportedOperationsByField[operation.field]) { + supportedOperationsByField[operation.field] = []; + } + supportedOperationsByField[operation.field]?.push(operation.operationType); + + if (!supportedFieldsByOperation[operation.operationType]) { + supportedFieldsByOperation[operation.operationType] = []; + } + supportedFieldsByOperation[operation.operationType]?.push(operation.field); } else if (operation.type === 'none') { supportedOperationsWithoutField.push(operation.operationType); } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts index 46dd73ba849a2..ab31471463f6f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts @@ -146,8 +146,8 @@ export function getAvailableOperationsByMetadata(indexPattern: IndexPattern) { operationDefinitions.sort(getSortScoreByPriority).forEach((operationDefinition) => { if (operationDefinition.input === 'field') { - indexPattern.fields.forEach((field) => { - addToMap( + return indexPattern.fields.forEach((field) => { + return addToMap( { type: 'field', operationType: operationDefinition.type, @@ -156,8 +156,9 @@ export function getAvailableOperationsByMetadata(indexPattern: IndexPattern) { operationDefinition.getPossibleOperationForField(field) ); }); - } else if (operationDefinition.input === 'none') { - addToMap( + } + if (operationDefinition.input === 'none') { + return addToMap( { type: 'none', operationType: operationDefinition.type, From 52cd945a36b660a5b9174f686da4fe0dd982e7e8 Mon Sep 17 00:00:00 2001 From: dej611 Date: Fri, 6 Nov 2020 15:27:18 +0100 Subject: [PATCH 06/10] :label: Fix type issue --- .../dimension_panel/dimension_editor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx index d0d250d0be257..4c19220514136 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx @@ -29,7 +29,7 @@ import { deleteColumn, changeColumn, updateColumnParam, mergeLayer } from '../st import { FieldSelect } from './field_select'; import { hasField, fieldIsInvalid } from '../utils'; import { BucketNestingEditor } from './bucket_nesting_editor'; -import { IndexPattern, IndexPatternField } from '../types'; +import { IndexPattern } from '../types'; import { trackUiEvent } from '../../lens_ui_telemetry'; import { FormatSelector } from './format_selector'; From 39fc23d2e3467dcf379cf78aac29d7b9d49d9850 Mon Sep 17 00:00:00 2001 From: dej611 Date: Mon, 9 Nov 2020 17:21:36 +0100 Subject: [PATCH 07/10] :ok_hand: Implement feedbacks --- .../indexpattern_datasource/dimension_panel/field_select.tsx | 1 + .../indexpattern_datasource/dimension_panel/operation_support.ts | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx index 15da1914cb355..ef005ccc7ae32 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx @@ -80,6 +80,7 @@ export function FieldSelect({ function fieldNamesToOptions(items: string[]) { return items + .filter((field) => currentIndexPattern.getFieldByName(field)?.displayName) .map((field) => ({ label: currentIndexPattern.getFieldByName(field)?.displayName, value: { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts index 5cf6751c0ca1d..68b7ddc39981d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts @@ -37,7 +37,6 @@ export const getOperationSupportMatrix = (props: Props): OperationSupportMatrix filteredOperationsByMetadata.forEach(({ operations }) => { operations.forEach((operation) => { - // replace spread operator by regular push as it's performance wise faster if (operation.type === 'field') { if (!supportedOperationsByField[operation.field]) { supportedOperationsByField[operation.field] = []; From f9b7bec58cc91ef436f9a9d5b44a2c763132aab0 Mon Sep 17 00:00:00 2001 From: dej611 Date: Mon, 9 Nov 2020 17:34:14 +0100 Subject: [PATCH 08/10] :recycle: Restore old branching --- .../indexpattern_datasource/operations/operations.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts index ab31471463f6f..c118f28870577 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts @@ -146,8 +146,8 @@ export function getAvailableOperationsByMetadata(indexPattern: IndexPattern) { operationDefinitions.sort(getSortScoreByPriority).forEach((operationDefinition) => { if (operationDefinition.input === 'field') { - return indexPattern.fields.forEach((field) => { - return addToMap( + indexPattern.fields.forEach((field) => { + addToMap( { type: 'field', operationType: operationDefinition.type, @@ -156,8 +156,7 @@ export function getAvailableOperationsByMetadata(indexPattern: IndexPattern) { operationDefinition.getPossibleOperationForField(field) ); }); - } - if (operationDefinition.input === 'none') { + } else if (operationDefinition.input === 'none') { return addToMap( { type: 'none', From 881e95e72b9d3bb69b64f43140597ab31ec43157 Mon Sep 17 00:00:00 2001 From: dej611 Date: Mon, 9 Nov 2020 17:34:43 +0100 Subject: [PATCH 09/10] :pencil2: Forgotten to remove one return --- .../public/indexpattern_datasource/operations/operations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts index c118f28870577..46dd73ba849a2 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts @@ -157,7 +157,7 @@ export function getAvailableOperationsByMetadata(indexPattern: IndexPattern) { ); }); } else if (operationDefinition.input === 'none') { - return addToMap( + addToMap( { type: 'none', operationType: operationDefinition.type, From 3f4fde52fa00cf1ce9419a3169cd369e0fa56dae Mon Sep 17 00:00:00 2001 From: dej611 Date: Mon, 9 Nov 2020 19:14:41 +0100 Subject: [PATCH 10/10] :zap: Migrate to Set from array to speed up dnd lookups --- .../dimension_panel/dimension_editor.tsx | 20 ++++++------- .../dimension_panel/droppable.ts | 6 ++-- .../dimension_panel/field_select.tsx | 4 +-- .../dimension_panel/operation_support.ts | 28 +++++++++---------- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx index 4c19220514136..7cbfbc1749382 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx @@ -103,9 +103,7 @@ export function DimensionEditor(props: DimensionEditorProps) { return op1.displayName.localeCompare(op2.displayName); }) .map((def) => def.type) - .filter( - (type) => fieldByOperation[type]?.length || operationWithoutField.indexOf(type) !== -1 - ); + .filter((type) => fieldByOperation[type]?.size || operationWithoutField.has(type)); }, [fieldByOperation, operationWithoutField]); // Operations are compatible if they match inputs. They are always compatible in @@ -120,7 +118,7 @@ export function DimensionEditor(props: DimensionEditorProps) { (selectedColumn && hasField(selectedColumn) && definition.input === 'field' && - fieldByOperation[operationType]?.indexOf(selectedColumn.sourceField) !== -1) || + fieldByOperation[operationType]?.has(selectedColumn.sourceField)) || (selectedColumn && !hasField(selectedColumn) && definition.input !== 'field'), }; }); @@ -190,9 +188,9 @@ export function DimensionEditor(props: DimensionEditorProps) { trackUiEvent(`indexpattern_dimension_operation_${operationType}`); return; } else if (!selectedColumn || !compatibleWithCurrentField) { - const possibleFields = fieldByOperation[operationType] || []; + const possibleFields = fieldByOperation[operationType] || new Set(); - if (possibleFields.length === 1) { + if (possibleFields.size === 1) { setState( changeColumn({ state, @@ -204,7 +202,7 @@ export function DimensionEditor(props: DimensionEditorProps) { layerId: props.layerId, op: operationType, indexPattern: currentIndexPattern, - field: currentIndexPattern.getFieldByName(possibleFields[0]), + field: currentIndexPattern.getFieldByName(possibleFields.values().next().value), previousColumn: selectedColumn, }), }) @@ -325,14 +323,14 @@ export function DimensionEditor(props: DimensionEditorProps) { // Otherwise we'll use the buildColumn method to calculate a new column const compatibleOperations = ('field' in choice && operationSupportMatrix.operationByField[choice.field]) || - []; + new Set(); let operation; - if (compatibleOperations.length > 0) { + if (compatibleOperations.size > 0) { operation = incompatibleSelectedOperationType && - compatibleOperations.includes(incompatibleSelectedOperationType) + compatibleOperations.has(incompatibleSelectedOperationType) ? incompatibleSelectedOperationType - : compatibleOperations[0]; + : compatibleOperations.values().next().value; } else if ('field' in choice) { operation = choice.operationType; } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.ts index 7f509cd0244f0..a6ff550af96e9 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.ts @@ -137,9 +137,9 @@ export function onDrop(props: DatasourceDimensionDropHandlerProps>; - operationWithoutField: OperationType[]; - fieldByOperation: Partial>; + operationByField: Partial>>; + operationWithoutField: Set; + fieldByOperation: Partial>>; } type Props = Pick< @@ -31,30 +31,30 @@ export const getOperationSupportMatrix = (props: Props): OperationSupportMatrix currentIndexPattern ).filter((operation) => props.filterOperations(operation.operationMetaData)); - const supportedOperationsByField: Partial> = {}; - const supportedOperationsWithoutField: OperationType[] = []; - const supportedFieldsByOperation: Partial> = {}; + const supportedOperationsByField: Partial>> = {}; + const supportedOperationsWithoutField: Set = new Set(); + const supportedFieldsByOperation: Partial>> = {}; filteredOperationsByMetadata.forEach(({ operations }) => { operations.forEach((operation) => { if (operation.type === 'field') { if (!supportedOperationsByField[operation.field]) { - supportedOperationsByField[operation.field] = []; + supportedOperationsByField[operation.field] = new Set(); } - supportedOperationsByField[operation.field]?.push(operation.operationType); + supportedOperationsByField[operation.field]?.add(operation.operationType); if (!supportedFieldsByOperation[operation.operationType]) { - supportedFieldsByOperation[operation.operationType] = []; + supportedFieldsByOperation[operation.operationType] = new Set(); } - supportedFieldsByOperation[operation.operationType]?.push(operation.field); + supportedFieldsByOperation[operation.operationType]?.add(operation.field); } else if (operation.type === 'none') { - supportedOperationsWithoutField.push(operation.operationType); + supportedOperationsWithoutField.add(operation.operationType); } }); }); return { - operationByField: _.mapValues(supportedOperationsByField, _.uniq), - operationWithoutField: _.uniq(supportedOperationsWithoutField), - fieldByOperation: _.mapValues(supportedFieldsByOperation, _.uniq), + operationByField: supportedOperationsByField, + operationWithoutField: supportedOperationsWithoutField, + fieldByOperation: supportedFieldsByOperation, }; };