[Lens] Get rid of giant union type (#118848)

This commit is contained in:
Joe Reuter 2021-11-19 13:00:35 +01:00 committed by GitHub
parent ad6b687dad
commit 8398d53da4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 862 additions and 781 deletions

View file

@ -27,6 +27,7 @@ import {
PersistedIndexPatternLayer,
XYState,
LensEmbeddableInput,
DateHistogramIndexPatternColumn,
} from '../../../plugins/lens/public';
import { StartDependencies } from './plugin';
@ -55,7 +56,7 @@ function getLensAttributes(
params: { interval: 'auto' },
scale: 'interval',
sourceField: defaultIndexPattern.timeFieldName!,
},
} as DateHistogramIndexPatternColumn,
},
};

View file

@ -10,7 +10,10 @@ import type { Filter } from '@kbn/es-query';
import type { IndexPattern } from '../../../../../../../../../src/plugins/data/common';
import type { CombinedQuery } from '../../../../index_data_visualizer/types/combined_query';
import type {
IndexPatternColumn,
DateHistogramIndexPatternColumn,
GenericIndexPatternColumn,
RangeIndexPatternColumn,
TermsIndexPatternColumn,
TypedLensByValueInput,
XYLayerConfig,
} from '../../../../../../../lens/public';
@ -18,7 +21,7 @@ import { FieldVisConfig } from '../../stats_table/types';
import { JOB_FIELD_TYPES } from '../../../../../../common';
interface ColumnsAndLayer {
columns: Record<string, IndexPatternColumn>;
columns: Record<string, GenericIndexPatternColumn>;
layer: XYLayerConfig;
}
@ -32,7 +35,7 @@ const COUNT = i18n.translate('xpack.dataVisualizer.index.lensChart.countLabel',
export function getNumberSettings(item: FieldVisConfig, defaultIndexPattern: IndexPattern) {
// if index has no timestamp field
if (defaultIndexPattern.timeFieldName === undefined) {
const columns: Record<string, IndexPatternColumn> = {
const columns: Record<string, GenericIndexPatternColumn> = {
col1: {
label: item.fieldName!,
dataType: 'number',
@ -44,7 +47,7 @@ export function getNumberSettings(item: FieldVisConfig, defaultIndexPattern: Ind
ranges: [],
},
sourceField: item.fieldName!,
},
} as RangeIndexPatternColumn,
col2: {
label: COUNT,
dataType: 'number',
@ -64,7 +67,7 @@ export function getNumberSettings(item: FieldVisConfig, defaultIndexPattern: Ind
return { columns, layer };
}
const columns: Record<string, IndexPatternColumn> = {
const columns: Record<string, GenericIndexPatternColumn> = {
col2: {
dataType: 'number',
isBucketed: false,
@ -83,7 +86,7 @@ export function getNumberSettings(item: FieldVisConfig, defaultIndexPattern: Ind
params: { interval: 'auto' },
scale: 'interval',
sourceField: defaultIndexPattern.timeFieldName!,
},
} as DateHistogramIndexPatternColumn,
};
const layer: XYLayerConfig = {
@ -97,7 +100,7 @@ export function getNumberSettings(item: FieldVisConfig, defaultIndexPattern: Ind
return { columns, layer };
}
export function getDateSettings(item: FieldVisConfig) {
const columns: Record<string, IndexPatternColumn> = {
const columns: Record<string, GenericIndexPatternColumn> = {
col2: {
dataType: 'number',
isBucketed: false,
@ -114,7 +117,7 @@ export function getDateSettings(item: FieldVisConfig) {
params: { interval: 'auto' },
scale: 'interval',
sourceField: item.fieldName!,
},
} as DateHistogramIndexPatternColumn,
};
const layer: XYLayerConfig = {
accessors: ['col2'],
@ -128,7 +131,7 @@ export function getDateSettings(item: FieldVisConfig) {
}
export function getKeywordSettings(item: FieldVisConfig) {
const columns: Record<string, IndexPatternColumn> = {
const columns: Record<string, GenericIndexPatternColumn> = {
col1: {
label: TOP_VALUES_LABEL,
dataType: 'string',
@ -140,7 +143,7 @@ export function getKeywordSettings(item: FieldVisConfig) {
orderDirection: 'desc',
},
sourceField: item.fieldName!,
},
} as TermsIndexPatternColumn,
col2: {
label: COUNT,
dataType: 'number',
@ -161,7 +164,7 @@ export function getKeywordSettings(item: FieldVisConfig) {
}
export function getBooleanSettings(item: FieldVisConfig) {
const columns: Record<string, IndexPatternColumn> = {
const columns: Record<string, GenericIndexPatternColumn> = {
col1: {
label: TOP_VALUES_LABEL,
dataType: 'string',
@ -173,7 +176,7 @@ export function getBooleanSettings(item: FieldVisConfig) {
orderDirection: 'desc',
},
sourceField: item.fieldName!,
},
} as TermsIndexPatternColumn,
col2: {
label: COUNT,
dataType: 'number',

View file

@ -31,10 +31,10 @@ export type { DatatableVisualizationState } from './datatable_visualization/visu
export type {
IndexPatternPersistedState,
PersistedIndexPatternLayer,
IndexPatternColumn,
FieldBasedIndexPatternColumn,
OperationType,
IncompleteColumn,
GenericIndexPatternColumn,
FieldBasedIndexPatternColumn,
FiltersIndexPatternColumn,
RangeIndexPatternColumn,
TermsIndexPatternColumn,

View file

@ -26,6 +26,7 @@ import { fieldFormatsServiceMock } from '../../../../../src/plugins/field_format
import { indexPatternFieldEditorPluginMock } from '../../../../../src/plugins/index_pattern_field_editor/public/mocks';
import { getFieldByNameFactory } from './pure_helpers';
import { uiActionsPluginMock } from '../../../../../src/plugins/ui_actions/public/mocks';
import { TermsIndexPatternColumn } from './operations';
const fieldsOne = [
{
@ -173,7 +174,7 @@ const initialState: IndexPatternPrivateState = {
type: 'alphabetical',
},
},
},
} as TermsIndexPatternColumn,
col2: {
label: 'My Op',
dataType: 'number',
@ -200,7 +201,7 @@ const initialState: IndexPatternPrivateState = {
type: 'alphabetical',
},
},
},
} as TermsIndexPatternColumn,
col2: {
label: 'My Op',
dataType: 'number',

View file

@ -8,7 +8,7 @@
import { mount } from 'enzyme';
import React from 'react';
import { BucketNestingEditor } from './bucket_nesting_editor';
import { IndexPatternColumn } from '../indexpattern';
import { GenericIndexPatternColumn } from '../indexpattern';
import { IndexPatternField } from '../types';
const fieldMap: Record<string, IndexPatternField> = {
@ -20,7 +20,7 @@ const fieldMap: Record<string, IndexPatternField> = {
const getFieldByName = (name: string): IndexPatternField | undefined => fieldMap[name];
describe('BucketNestingEditor', () => {
function mockCol(col: Partial<IndexPatternColumn> = {}): IndexPatternColumn {
function mockCol(col: Partial<GenericIndexPatternColumn> = {}): GenericIndexPatternColumn {
const result = {
dataType: 'string',
isBucketed: true,
@ -35,7 +35,7 @@ describe('BucketNestingEditor', () => {
...col,
};
return result as IndexPatternColumn;
return result as GenericIndexPatternColumn;
}
it('should display the top level grouping when at the root', () => {

View file

@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n';
import { EuiFormRow, EuiSwitch, EuiSelect } from '@elastic/eui';
import { IndexPatternLayer, IndexPatternField } from '../types';
import { hasField } from '../utils';
import { IndexPatternColumn } from '../operations';
import { GenericIndexPatternColumn } from '../operations';
function nestColumn(columnOrder: string[], outer: string, inner: string) {
const result = columnOrder.filter((c) => c !== inner);
@ -22,7 +22,7 @@ function nestColumn(columnOrder: string[], outer: string, inner: string) {
}
function getFieldName(
column: IndexPatternColumn,
column: GenericIndexPatternColumn,
getFieldByName: (name: string) => IndexPatternField | undefined
) {
return hasField(column)

View file

@ -19,7 +19,7 @@ import {
} from '@elastic/eui';
import { IndexPatternDimensionEditorProps } from './dimension_panel';
import { OperationSupportMatrix } from './operation_support';
import { IndexPatternColumn } from '../indexpattern';
import { GenericIndexPatternColumn } from '../indexpattern';
import {
operationDefinitionMap,
getOperationDisplay,
@ -62,7 +62,7 @@ import type { TemporaryState } from './dimensions_editor_helpers';
const operationPanels = getOperationDisplay();
export interface DimensionEditorProps extends IndexPatternDimensionEditorProps {
selectedColumn?: IndexPatternColumn;
selectedColumn?: GenericIndexPatternColumn;
layerType: LayerType;
operationSupportMatrix: OperationSupportMatrix;
currentIndexPattern: IndexPattern;

View file

@ -27,7 +27,12 @@ import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup, CoreSetup } f
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
import { generateId } from '../../id_generator';
import { IndexPatternPrivateState } from '../types';
import { IndexPatternColumn, replaceColumn } from '../operations';
import {
FiltersIndexPatternColumn,
GenericIndexPatternColumn,
replaceColumn,
TermsIndexPatternColumn,
} from '../operations';
import { documentField } from '../document_field';
import { OperationMetadata } from '../../types';
import { DateHistogramIndexPatternColumn } from '../operations/definitions/date_histogram';
@ -108,7 +113,7 @@ const expectedIndexPatterns = {
},
};
const bytesColumn: IndexPatternColumn = {
const bytesColumn: GenericIndexPatternColumn = {
label: 'Max of bytes',
dataType: 'number',
isBucketed: false,
@ -133,7 +138,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
let setState: jest.Mock;
let defaultProps: IndexPatternDimensionEditorProps;
function getStateWithColumns(columns: Record<string, IndexPatternColumn>) {
function getStateWithColumns(columns: Record<string, GenericIndexPatternColumn>) {
return {
...state,
layers: { first: { ...state.layers.first, columns, columnOrder: Object.keys(columns) } },
@ -171,7 +176,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
interval: '1d',
},
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
},
incompleteColumns: {},
},
@ -264,7 +269,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
// Private
operationType: 'filters',
params: { filters: [] },
},
} as FiltersIndexPatternColumn,
})}
/>
);
@ -427,7 +432,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
operationType: 'date_histogram',
sourceField: '@timestamp',
params: { interval: 'auto' },
},
} as DateHistogramIndexPatternColumn,
col1: {
label: 'Counter rate',
dataType: 'number',
@ -464,7 +469,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
operationType: 'date_histogram',
sourceField: '@timestamp',
params: { interval: 'auto' },
},
} as DateHistogramIndexPatternColumn,
col1: {
label: 'Cumulative sum',
dataType: 'number',
@ -839,7 +844,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
// Private
operationType: 'filters',
params: { filters: [] },
},
} as FiltersIndexPatternColumn,
})}
/>
);
@ -1066,7 +1071,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
});
describe('time scaling', () => {
function getProps(colOverrides: Partial<IndexPatternColumn>) {
function getProps(colOverrides: Partial<GenericIndexPatternColumn>) {
return {
...defaultProps,
state: getStateWithColumns({
@ -1080,7 +1085,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
params: {
interval: '1d',
},
},
} as DateHistogramIndexPatternColumn,
col2: {
dataType: 'number',
isBucketed: false,
@ -1088,7 +1093,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
operationType: 'count',
sourceField: 'Records',
...colOverrides,
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
}),
columnId: 'col2',
};
@ -1296,7 +1301,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
});
describe('time shift', () => {
function getProps(colOverrides: Partial<IndexPatternColumn>) {
function getProps(colOverrides: Partial<GenericIndexPatternColumn>) {
return {
...defaultProps,
state: getStateWithColumns({
@ -1310,7 +1315,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
params: {
interval: '1d',
},
},
} as DateHistogramIndexPatternColumn,
col2: {
dataType: 'number',
isBucketed: false,
@ -1318,7 +1323,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
operationType: 'count',
sourceField: 'Records',
...colOverrides,
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
}),
columnId: 'col2',
};
@ -1334,7 +1339,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
label: 'Count of records',
operationType: 'count',
sourceField: 'Records',
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
}),
columnId: 'col2',
};
@ -1483,7 +1488,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
});
describe('filtering', () => {
function getProps(colOverrides: Partial<IndexPatternColumn>) {
function getProps(colOverrides: Partial<GenericIndexPatternColumn>) {
return {
...defaultProps,
state: getStateWithColumns({
@ -1497,7 +1502,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
params: {
interval: '1d',
},
},
} as DateHistogramIndexPatternColumn,
col2: {
dataType: 'number',
isBucketed: false,
@ -1505,7 +1510,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
operationType: 'count',
sourceField: 'Records',
...colOverrides,
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
}),
columnId: 'col2',
};
@ -1522,7 +1527,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
orderBy: { type: 'alphabetical' },
size: 5,
},
})}
} as TermsIndexPatternColumn)}
/>
);
expect(

View file

@ -12,7 +12,7 @@ import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup } from 'kibana
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
import { DatasourceDimensionTriggerProps, DatasourceDimensionEditorProps } from '../../types';
import { DataPublicPluginStart } from '../../../../../../src/plugins/data/public';
import { IndexPatternColumn } from '../indexpattern';
import { GenericIndexPatternColumn } from '../indexpattern';
import { isColumnInvalid } from '../utils';
import { IndexPatternPrivateState } from '../types';
import { DimensionEditor } from './dimension_editor';
@ -56,7 +56,7 @@ export const IndexPatternDimensionTriggerComponent = function IndexPatternDimens
[layer, columnId, currentIndexPattern, invalid]
);
const selectedColumn: IndexPatternColumn | null = layer.columns[props.columnId] ?? null;
const selectedColumn: GenericIndexPatternColumn | null = layer.columns[props.columnId] ?? null;
if (!selectedColumn) {
return null;
@ -126,7 +126,7 @@ export const IndexPatternDimensionEditorComponent = function IndexPatternDimensi
}
const operationSupportMatrix = getOperationSupportMatrix(props);
const selectedColumn: IndexPatternColumn | null =
const selectedColumn: GenericIndexPatternColumn | null =
props.state.layers[layerId].columns[props.columnId] || null;
return (
<DimensionEditor

View file

@ -16,7 +16,7 @@ import './dimension_editor.scss';
import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiFormRow, EuiFieldText, EuiTabs, EuiTab, EuiCallOut } from '@elastic/eui';
import { IndexPatternColumn, operationDefinitionMap } from '../operations';
import { GenericIndexPatternColumn, operationDefinitionMap } from '../operations';
import { useDebouncedValue } from '../../shared_components';
export const formulaOperationName = 'formula';
@ -176,7 +176,7 @@ export const DimensionEditorTabs = ({ tabs }: { tabs: DimensionEditorTab[] }) =>
};
export function getErrorMessage(
selectedColumn: IndexPatternColumn | undefined,
selectedColumn: GenericIndexPatternColumn | undefined,
incompleteOperation: boolean,
input: 'none' | 'field' | 'fullReference' | 'managedReference' | undefined,
fieldInvalid: boolean

View file

@ -14,7 +14,12 @@ import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
import { IndexPatternLayer, IndexPatternPrivateState } from '../../types';
import { documentField } from '../../document_field';
import { OperationMetadata, DropType } from '../../../types';
import { IndexPatternColumn, MedianIndexPatternColumn } from '../../operations';
import {
DateHistogramIndexPatternColumn,
GenericIndexPatternColumn,
MedianIndexPatternColumn,
TermsIndexPatternColumn,
} from '../../operations';
import { getFieldByNameFactory } from '../../pure_helpers';
import { generateId } from '../../../id_generator';
import { layerTypes } from '../../../../common';
@ -128,7 +133,7 @@ const oneColumnLayer: IndexPatternLayer = {
interval: '1d',
},
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
},
incompleteColumns: {},
};
@ -150,7 +155,7 @@ const multipleColumnsLayer: IndexPatternLayer = {
size: 10,
},
sourceField: 'src',
},
} as TermsIndexPatternColumn,
col3: {
label: 'Top values of dest',
dataType: 'string',
@ -164,7 +169,7 @@ const multipleColumnsLayer: IndexPatternLayer = {
size: 10,
},
sourceField: 'dest',
},
} as TermsIndexPatternColumn,
col4: {
label: 'Median of bytes',
dataType: 'number',
@ -416,7 +421,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
interval: '1d',
},
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
},
};
@ -771,7 +776,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
interval: '1d',
},
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
col2: {
label: 'Top values of bar',
dataType: 'number',
@ -783,7 +788,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
orderDirection: 'asc',
size: 5,
},
},
} as TermsIndexPatternColumn,
col3: {
operationType: 'average',
sourceField: 'memory',
@ -1158,17 +1163,17 @@ describe('IndexPatternDimensionEditorPanel', () => {
label: 'Date histogram of timestamp',
dataType: 'date',
isBucketed: true,
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
col2: {
label: 'Top values of bar',
dataType: 'number',
isBucketed: true,
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
col3: {
label: 'Top values of memory',
dataType: 'number',
isBucketed: true,
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
},
},
},
@ -1293,7 +1298,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
size: 10,
},
sourceField: 'src',
},
} as TermsIndexPatternColumn,
col3: {
label: 'Count',
dataType: 'number',

View file

@ -16,7 +16,7 @@ import { hasField, isDraggedField } from '../../utils';
import { DragContextState } from '../../../drag_drop/providers';
import { OperationMetadata } from '../../../types';
import { getOperationTypesForField } from '../../operations';
import { IndexPatternColumn } from '../../indexpattern';
import { GenericIndexPatternColumn } from '../../indexpattern';
import {
IndexPatternPrivateState,
IndexPattern,
@ -36,7 +36,7 @@ const operationLabels = getOperationDisplay();
export function getNewOperation(
field: IndexPatternField | undefined | false,
filterOperations: (meta: OperationMetadata) => boolean,
targetColumn: IndexPatternColumn
targetColumn: GenericIndexPatternColumn
) {
if (!field) {
return;
@ -50,7 +50,10 @@ export function getNewOperation(
return shouldOperationPersist ? targetColumn.operationType : newOperations[0];
}
export function getField(column: IndexPatternColumn | undefined, indexPattern: IndexPattern) {
export function getField(
column: GenericIndexPatternColumn | undefined,
indexPattern: IndexPattern
) {
if (!column) {
return;
}
@ -89,7 +92,10 @@ export function getDropProps(props: GetDropProps) {
}
}
function hasTheSameField(sourceColumn: IndexPatternColumn, targetColumn?: IndexPatternColumn) {
function hasTheSameField(
sourceColumn: GenericIndexPatternColumn,
targetColumn?: GenericIndexPatternColumn
) {
return (
targetColumn &&
hasField(targetColumn) &&
@ -127,11 +133,11 @@ function getDropPropsForField({
return;
}
function getDropPropsForSameGroup(targetColumn?: IndexPatternColumn): DropProps {
function getDropPropsForSameGroup(targetColumn?: GenericIndexPatternColumn): DropProps {
return targetColumn ? { dropTypes: ['reorder'] } : { dropTypes: ['duplicate_compatible'] };
}
function getDropPropsForCompatibleGroup(targetColumn?: IndexPatternColumn): DropProps {
function getDropPropsForCompatibleGroup(targetColumn?: GenericIndexPatternColumn): DropProps {
return {
dropTypes: targetColumn
? ['replace_compatible', 'replace_duplicate_compatible', 'swap_compatible']

View file

@ -18,7 +18,7 @@ import {
EuiPopoverProps,
} from '@elastic/eui';
import type { Query } from 'src/plugins/data/public';
import { IndexPatternColumn, operationDefinitionMap } from '../operations';
import { GenericIndexPatternColumn, operationDefinitionMap } from '../operations';
import { validateQuery } from '../operations/definitions/filters';
import { QueryInput } from '../query_input';
import type { IndexPattern, IndexPatternLayer } from '../types';
@ -54,7 +54,7 @@ export function Filtering({
indexPattern,
isInitiallyOpen,
}: {
selectedColumn: IndexPatternColumn;
selectedColumn: GenericIndexPatternColumn;
indexPattern: IndexPattern;
columnId: string;
layer: IndexPatternLayer;

View file

@ -8,7 +8,7 @@
import React, { useCallback, useMemo, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiFormRow, EuiComboBox, EuiSpacer, EuiRange } from '@elastic/eui';
import { IndexPatternColumn } from '../indexpattern';
import { GenericIndexPatternColumn } from '../indexpattern';
const supportedFormats: Record<string, { title: string }> = {
number: {
@ -36,7 +36,7 @@ const defaultOption = {
};
interface FormatSelectorProps {
selectedColumn: IndexPatternColumn;
selectedColumn: GenericIndexPatternColumn;
onChange: (newFormat?: { id: string; params?: Record<string, unknown> }) => void;
}
@ -136,7 +136,7 @@ export function FormatSelector(props: FormatSelectorProps) {
onChange={(e) => {
setState({ decimalPlaces: Number(e.currentTarget.value) });
onChange({
id: (selectedColumn.params as { format: { id: string } }).format.id,
id: currentFormat.id,
params: {
decimals: Number(e.currentTarget.value),
},

View file

@ -17,7 +17,11 @@ import type { DataPublicPluginStart } from 'src/plugins/data/public';
import { OperationMetadata } from '../../types';
import { createMockedIndexPattern, createMockedIndexPatternWithoutType } from '../mocks';
import { ReferenceEditor, ReferenceEditorProps } from './reference_editor';
import { insertOrReplaceColumn } from '../operations';
import {
insertOrReplaceColumn,
LastValueIndexPatternColumn,
TermsIndexPatternColumn,
} from '../operations';
import { FieldSelect } from './field_select';
jest.mock('../operations');
@ -123,7 +127,7 @@ describe('reference editor', () => {
operationType: 'terms',
sourceField: 'dest',
params: { size: 5, orderBy: { type: 'alphabetical' }, orderDirection: 'desc' },
},
} as TermsIndexPatternColumn,
},
}}
validation={{
@ -490,7 +494,7 @@ describe('reference editor', () => {
params: {
sortField: 'timestamp',
},
},
} as LastValueIndexPatternColumn,
},
}}
validation={{
@ -522,7 +526,7 @@ describe('reference editor', () => {
params: {
sortField: 'timestamp',
},
},
} as LastValueIndexPatternColumn,
},
incompleteColumns: {
ref: { operationType: 'max' },

View file

@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n';
import React from 'react';
import {
adjustTimeScaleLabelSuffix,
IndexPatternColumn,
GenericIndexPatternColumn,
operationDefinitionMap,
} from '../operations';
import type { TimeScaleUnit } from '../../../common/expressions';
@ -60,7 +60,7 @@ export function TimeScaling({
layer,
updateLayer,
}: {
selectedColumn: IndexPatternColumn;
selectedColumn: GenericIndexPatternColumn;
columnId: string;
layer: IndexPatternLayer;
updateLayer: (newLayer: IndexPatternLayer) => void;

View file

@ -14,7 +14,7 @@ import { Query } from 'src/plugins/data/public';
import { parseTimeShift } from '../../../../../../src/plugins/data/common';
import {
adjustTimeScaleLabelSuffix,
IndexPatternColumn,
GenericIndexPatternColumn,
operationDefinitionMap,
} from '../operations';
import { IndexPattern, IndexPatternLayer } from '../types';
@ -70,7 +70,7 @@ export function TimeShift({
activeData,
layerId,
}: {
selectedColumn: IndexPatternColumn;
selectedColumn: GenericIndexPatternColumn;
indexPattern: IndexPattern;
columnId: string;
layer: IndexPatternLayer;

View file

@ -8,7 +8,7 @@
import React from 'react';
import 'jest-canvas-mock';
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
import { getIndexPatternDatasource, IndexPatternColumn } from './indexpattern';
import { getIndexPatternDatasource, GenericIndexPatternColumn } from './indexpattern';
import { DatasourcePublicAPI, Operation, Datasource, FramePublicAPI } from '../types';
import { coreMock } from 'src/core/public/mocks';
import { IndexPatternPersistedState, IndexPatternPrivateState } from './types';
@ -16,11 +16,20 @@ import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks';
import { Ast } from '@kbn/interpreter/common';
import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks';
import { getFieldByNameFactory } from './pure_helpers';
import { operationDefinitionMap, getErrorMessages } from './operations';
import {
operationDefinitionMap,
getErrorMessages,
TermsIndexPatternColumn,
DateHistogramIndexPatternColumn,
MovingAverageIndexPatternColumn,
MathIndexPatternColumn,
FormulaIndexPatternColumn,
} from './operations';
import { createMockedFullReference } from './operations/mocks';
import { indexPatternFieldEditorPluginMock } from 'src/plugins/index_pattern_field_editor/public/mocks';
import { uiActionsPluginMock } from '../../../../../src/plugins/ui_actions/public/mocks';
import { fieldFormatsServiceMock } from '../../../../../src/plugins/field_formats/public/mocks';
import { TinymathAST } from 'packages/kbn-tinymath';
jest.mock('./loader');
jest.mock('../id_generator');
@ -200,7 +209,7 @@ describe('IndexPattern Data Source', () => {
orderBy: { type: 'alphabetical' },
orderDirection: 'asc',
},
},
} as TermsIndexPatternColumn,
},
},
},
@ -209,7 +218,7 @@ describe('IndexPattern Data Source', () => {
describe('uniqueLabels', () => {
it('appends a suffix to duplicates', () => {
const col: IndexPatternColumn = {
const col: GenericIndexPatternColumn = {
dataType: 'number',
isBucketed: false,
label: 'Foo',
@ -355,7 +364,7 @@ describe('IndexPattern Data Source', () => {
params: {
interval: '1d',
},
},
} as DateHistogramIndexPatternColumn,
},
},
},
@ -505,7 +514,7 @@ describe('IndexPattern Data Source', () => {
params: {
interval: 'auto',
},
},
} as DateHistogramIndexPatternColumn,
col3: {
label: 'Date 2',
dataType: 'date',
@ -515,7 +524,7 @@ describe('IndexPattern Data Source', () => {
params: {
interval: 'auto',
},
},
} as DateHistogramIndexPatternColumn,
},
},
},
@ -552,7 +561,7 @@ describe('IndexPattern Data Source', () => {
params: {
interval: 'auto',
},
},
} as DateHistogramIndexPatternColumn,
},
},
},
@ -601,7 +610,7 @@ describe('IndexPattern Data Source', () => {
params: {
interval: 'auto',
},
},
} as DateHistogramIndexPatternColumn,
},
},
},
@ -727,7 +736,7 @@ describe('IndexPattern Data Source', () => {
params: {
interval: 'auto',
},
},
} as DateHistogramIndexPatternColumn,
},
},
},
@ -794,7 +803,7 @@ describe('IndexPattern Data Source', () => {
params: {
interval: 'auto',
},
},
} as DateHistogramIndexPatternColumn,
metric: {
label: 'Count of records',
dataType: 'number',
@ -812,7 +821,7 @@ describe('IndexPattern Data Source', () => {
params: {
window: 5,
},
},
} as MovingAverageIndexPatternColumn,
},
},
},
@ -850,7 +859,7 @@ describe('IndexPattern Data Source', () => {
params: {
interval: '1d',
},
},
} as DateHistogramIndexPatternColumn,
bucket2: {
label: 'Terms',
dataType: 'string',
@ -862,7 +871,7 @@ describe('IndexPattern Data Source', () => {
orderDirection: 'asc',
size: 10,
},
},
} as TermsIndexPatternColumn,
},
},
},
@ -902,7 +911,7 @@ describe('IndexPattern Data Source', () => {
params: {
interval: 'auto',
},
},
} as DateHistogramIndexPatternColumn,
},
},
},
@ -947,7 +956,6 @@ describe('IndexPattern Data Source', () => {
label: 'Reference',
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: ['col1'],
},
@ -983,7 +991,6 @@ describe('IndexPattern Data Source', () => {
label: 'Reference',
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: ['col1'],
},
@ -1030,7 +1037,7 @@ describe('IndexPattern Data Source', () => {
params: {
interval: 'auto',
},
},
} as DateHistogramIndexPatternColumn,
formula: {
label: 'Formula',
dataType: 'number',
@ -1042,7 +1049,7 @@ describe('IndexPattern Data Source', () => {
isFormulaBroken: false,
},
references: ['math'],
},
} as FormulaIndexPatternColumn,
countX0: {
label: 'countX0',
dataType: 'number',
@ -1062,8 +1069,7 @@ describe('IndexPattern Data Source', () => {
tinymathAst: {
type: 'function',
name: 'add',
// @ts-expect-error String args are not valid tinymath, but signals something unique to Lens
args: ['countX0', 'count'],
args: ['countX0', 'count'] as unknown as TinymathAST[],
location: {
min: 0,
max: 17,
@ -1073,7 +1079,7 @@ describe('IndexPattern Data Source', () => {
},
references: ['countX0', 'count'],
customLabel: true,
},
} as MathIndexPatternColumn,
},
},
},
@ -1217,7 +1223,7 @@ describe('IndexPattern Data Source', () => {
operationType: 'sum',
sourceField: 'test',
params: {},
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
col2: {
label: 'Cumulative sum',
dataType: 'number',
@ -1226,7 +1232,7 @@ describe('IndexPattern Data Source', () => {
operationType: 'cumulative_sum',
references: ['col1'],
params: {},
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
},
},
},
@ -1268,7 +1274,7 @@ describe('IndexPattern Data Source', () => {
operationType: 'sum',
sourceField: 'test',
params: {},
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
col2: {
label: 'Cumulative sum',
dataType: 'number',
@ -1277,7 +1283,7 @@ describe('IndexPattern Data Source', () => {
operationType: 'cumulative_sum',
references: ['col1'],
params: {},
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
},
},
},
@ -1368,7 +1374,7 @@ describe('IndexPattern Data Source', () => {
dataType: 'date',
isBucketed: true,
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
col2: {
operationType: 'count',
label: '',
@ -1606,7 +1612,7 @@ describe('IndexPattern Data Source', () => {
params: {
interval: '1d',
},
},
} as DateHistogramIndexPatternColumn,
bucket2: {
label: 'Terms',
dataType: 'string',
@ -1618,7 +1624,7 @@ describe('IndexPattern Data Source', () => {
orderDirection: 'asc',
size: 10,
},
},
} as TermsIndexPatternColumn,
},
},
},

View file

@ -44,7 +44,7 @@ import {
import { isColumnInvalid, isDraggedField, normalizeOperationDataType } from './utils';
import { LayerPanel } from './layerpanel';
import { IndexPatternColumn, getErrorMessages, insertNewColumn } from './operations';
import { GenericIndexPatternColumn, getErrorMessages, insertNewColumn } from './operations';
import { IndexPatternField, IndexPatternPrivateState, IndexPatternPersistedState } from './types';
import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public';
import { DataPublicPluginStart } from '../../../../../src/plugins/data/public';
@ -58,10 +58,13 @@ import { GeoFieldWorkspacePanel } from '../editor_frame_service/editor_frame/wor
import { DraggingIdentifier } from '../drag_drop';
import { getStateTimeShiftWarningMessages } from './time_shift_utils';
import { getPrecisionErrorWarningMessages } from './utils';
export type { OperationType, IndexPatternColumn } from './operations';
export type { OperationType, GenericIndexPatternColumn } from './operations';
export { deleteColumn } from './operations';
export function columnToOperation(column: IndexPatternColumn, uniqueLabel?: string): Operation {
export function columnToOperation(
column: GenericIndexPatternColumn,
uniqueLabel?: string
): Operation {
const { dataType, label, isBucketed, scale } = column;
return {
dataType: normalizeOperationDataType(dataType),

View file

@ -18,6 +18,12 @@ import {
import { documentField } from './document_field';
import { getFieldByNameFactory } from './pure_helpers';
import { isEqual } from 'lodash';
import { DateHistogramIndexPatternColumn, TermsIndexPatternColumn } from './operations';
import {
MathIndexPatternColumn,
RangeIndexPatternColumn,
StaticValueIndexPatternColumn,
} from './operations/definitions';
jest.mock('./loader');
jest.mock('../id_generator');
@ -179,7 +185,7 @@ function testInitialState(): IndexPatternPrivateState {
orderBy: { type: 'alphabetical' },
orderDirection: 'asc',
},
},
} as TermsIndexPatternColumn,
},
},
},
@ -733,7 +739,7 @@ describe('IndexPattern Data Source suggestions', () => {
orderDirection: 'asc',
size: 5,
},
},
} as TermsIndexPatternColumn,
colb: {
dataType: 'number',
isBucketed: false,
@ -768,7 +774,7 @@ describe('IndexPattern Data Source suggestions', () => {
params: {
interval: 'w',
},
},
} as DateHistogramIndexPatternColumn,
colb: {
dataType: 'number',
isBucketed: false,
@ -976,7 +982,7 @@ describe('IndexPattern Data Source suggestions', () => {
orderDirection: 'asc',
size: 5,
},
},
} as TermsIndexPatternColumn,
},
columnOrder: ['cola'],
},
@ -1086,7 +1092,7 @@ describe('IndexPattern Data Source suggestions', () => {
operationType: 'date_histogram',
sourceField: 'timestamp',
params: { interval: 'auto' },
},
} as DateHistogramIndexPatternColumn,
metric: {
label: '',
customLabel: true,
@ -1218,7 +1224,7 @@ describe('IndexPattern Data Source suggestions', () => {
params: { value: '0' },
references: [],
scale: 'ratio',
},
} as StaticValueIndexPatternColumn,
},
},
currentLayer: {
@ -1506,7 +1512,7 @@ describe('IndexPattern Data Source suggestions', () => {
orderBy: { type: 'alphabetical' },
orderDirection: 'asc',
},
},
} as TermsIndexPatternColumn,
},
},
},
@ -1648,7 +1654,7 @@ describe('IndexPattern Data Source suggestions', () => {
orderDirection: 'asc',
size: 5,
},
},
} as TermsIndexPatternColumn,
colb: {
label: 'My Op',
customLabel: true,
@ -1726,7 +1732,7 @@ describe('IndexPattern Data Source suggestions', () => {
orderDirection: 'asc',
size: 5,
},
},
} as TermsIndexPatternColumn,
colb: {
label: 'My Op',
customLabel: true,
@ -1830,7 +1836,7 @@ describe('IndexPattern Data Source suggestions', () => {
maxBars: 100,
ranges: [],
},
},
} as RangeIndexPatternColumn,
},
},
},
@ -1876,7 +1882,7 @@ describe('IndexPattern Data Source suggestions', () => {
maxBars: 100,
ranges: [{ from: 1, to: 2, label: '' }],
},
},
} as RangeIndexPatternColumn,
},
},
},
@ -1954,7 +1960,7 @@ describe('IndexPattern Data Source suggestions', () => {
it("should not propose an over time suggestion if there's a top values aggregation with an high size", () => {
const initialState = testInitialState();
(initialState.layers.first.columns.col1 as { params: { size: number } }).params!.size = 6;
(initialState.layers.first.columns.col1 as TermsIndexPatternColumn).params!.size = 6;
const suggestions = getDatasourceSuggestionsFromCurrentState({
...initialState,
indexPatterns: { 1: { ...initialState.indexPatterns['1'], timeFieldName: undefined } },
@ -1995,7 +2001,7 @@ describe('IndexPattern Data Source suggestions', () => {
orderBy: { type: 'alphabetical' },
orderDirection: 'asc',
},
},
} as TermsIndexPatternColumn,
},
},
},
@ -2080,7 +2086,7 @@ describe('IndexPattern Data Source suggestions', () => {
orderBy: { type: 'alphabetical' },
orderDirection: 'asc',
},
},
} as TermsIndexPatternColumn,
col2: {
label: 'My Op',
customLabel: true,
@ -2094,7 +2100,7 @@ describe('IndexPattern Data Source suggestions', () => {
orderBy: { type: 'alphabetical' },
orderDirection: 'asc',
},
},
} as TermsIndexPatternColumn,
col3: {
label: 'My Op',
customLabel: true,
@ -2108,7 +2114,7 @@ describe('IndexPattern Data Source suggestions', () => {
orderBy: { type: 'alphabetical' },
orderDirection: 'asc',
},
},
} as TermsIndexPatternColumn,
col4: {
label: 'My Op',
customLabel: true,
@ -2217,7 +2223,7 @@ describe('IndexPattern Data Source suggestions', () => {
params: {
interval: 'd',
},
},
} as DateHistogramIndexPatternColumn,
id2: {
label: 'Average of field1',
dataType: 'number',
@ -2348,7 +2354,7 @@ describe('IndexPattern Data Source suggestions', () => {
params: {
interval: 'd',
},
},
} as DateHistogramIndexPatternColumn,
id2: {
label: 'Top 5',
dataType: 'string',
@ -2357,7 +2363,7 @@ describe('IndexPattern Data Source suggestions', () => {
operationType: 'terms',
sourceField: 'dest',
params: { size: 5, orderBy: { type: 'alphabetical' }, orderDirection: 'asc' },
},
} as TermsIndexPatternColumn,
id3: {
label: 'Average of field1',
dataType: 'number',
@ -2403,7 +2409,7 @@ describe('IndexPattern Data Source suggestions', () => {
operationType: 'terms',
sourceField: 'nonExistingField',
params: { size: 5, orderBy: { type: 'alphabetical' }, orderDirection: 'asc' },
},
} as TermsIndexPatternColumn,
},
columnOrder: ['col1', 'col2'],
},
@ -2539,7 +2545,7 @@ describe('IndexPattern Data Source suggestions', () => {
operationType: 'date_histogram',
sourceField: 'timestamp',
params: { interval: 'auto' },
},
} as DateHistogramIndexPatternColumn,
ref: {
label: '',
dataType: 'number',
@ -2629,7 +2635,7 @@ describe('IndexPattern Data Source suggestions', () => {
operationType: 'date_histogram',
sourceField: 'timestamp',
params: { interval: 'auto' },
},
} as DateHistogramIndexPatternColumn,
metric: {
label: '',
dataType: 'number',
@ -2681,7 +2687,7 @@ describe('IndexPattern Data Source suggestions', () => {
params: {
tinymathAst: '',
},
},
} as MathIndexPatternColumn,
ref4: {
label: '',
dataType: 'number',
@ -2691,7 +2697,7 @@ describe('IndexPattern Data Source suggestions', () => {
params: {
tinymathAst: '',
},
},
} as MathIndexPatternColumn,
},
},
},
@ -2756,7 +2762,7 @@ describe('IndexPattern Data Source suggestions', () => {
operationType: 'date_histogram',
sourceField: 'timestamp',
params: { interval: 'auto' },
},
} as DateHistogramIndexPatternColumn,
ref: {
label: '',
dataType: 'number',
@ -2806,7 +2812,7 @@ describe('IndexPattern Data Source suggestions', () => {
tinymathAst: '',
},
references: ['metric'],
},
} as MathIndexPatternColumn,
metric: {
label: '',
dataType: 'number',

View file

@ -16,7 +16,7 @@ import {
getMetricOperationTypes,
getOperationTypesForField,
operationDefinitionMap,
IndexPatternColumn,
BaseIndexPatternColumn,
OperationType,
getExistingColumnGroups,
isReferenced,
@ -62,11 +62,11 @@ function buildSuggestion({
// two match up.
const layers = mapValues(updatedState.layers, (layer) => ({
...layer,
columns: pick(layer.columns, layer.columnOrder) as Record<string, IndexPatternColumn>,
columns: pick(layer.columns, layer.columnOrder) as Record<string, BaseIndexPatternColumn>,
}));
const columnOrder = layers[layerId].columnOrder;
const columnMap = layers[layerId].columns as Record<string, IndexPatternColumn>;
const columnMap = layers[layerId].columns as Record<string, BaseIndexPatternColumn>;
const isMultiRow = Object.values(columnMap).some((column) => column.isBucketed);
return {
@ -221,7 +221,7 @@ function getExistingLayerSuggestionsForField(
indexPattern,
field,
columnId: generateId(),
op: metricOperation.type,
op: metricOperation.type as OperationType,
visualizationGroups: [],
});
if (layerWithNewMetric) {
@ -243,7 +243,7 @@ function getExistingLayerSuggestionsForField(
indexPattern,
field,
columnId: metrics[0],
op: metricOperation.type,
op: metricOperation.type as OperationType,
visualizationGroups: [],
});
if (layerWithReplacedMetric) {
@ -336,7 +336,7 @@ function createNewLayerWithMetricAggregation(
return insertNewColumn({
op: 'date_histogram',
layer: insertNewColumn({
op: metricOperation.type,
op: metricOperation.type as OperationType,
layer: { indexPatternId: indexPattern.id, columns: {}, columnOrder: [] },
columnId: generateId(),
field,

View file

@ -13,6 +13,7 @@ import { ShallowWrapper } from 'enzyme';
import { EuiSelectable } from '@elastic/eui';
import { ChangeIndexPattern } from './change_indexpattern';
import { getFieldByNameFactory } from './pure_helpers';
import { TermsIndexPatternColumn } from './operations';
interface IndexPatternPickerOption {
label: string;
@ -160,7 +161,7 @@ const initialState: IndexPatternPrivateState = {
type: 'alphabetical',
},
},
},
} as TermsIndexPatternColumn,
col2: {
label: 'My Op',
dataType: 'number',

View file

@ -26,6 +26,7 @@ import {
} from './types';
import { createMockedRestrictedIndexPattern, createMockedIndexPattern } from './mocks';
import { documentField } from './document_field';
import { DateHistogramIndexPatternColumn } from './operations';
const createMockStorage = (lastData?: Record<string, string>) => {
return {
@ -512,7 +513,7 @@ describe('loader', () => {
interval: 'm',
},
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
col2: {
dataType: 'number',
isBucketed: false,
@ -563,7 +564,7 @@ describe('loader', () => {
interval: 'm',
},
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
col2: {
dataType: 'number',
isBucketed: false,
@ -650,7 +651,7 @@ describe('loader', () => {
interval: 'm',
},
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
col2: {
dataType: 'number',
isBucketed: false,
@ -870,7 +871,7 @@ describe('loader', () => {
interval: 'm',
},
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
},
indexPatternId: '1',
},

View file

@ -19,7 +19,8 @@ import {
import { getFieldByNameFactory } from '../pure_helpers';
import { documentField } from '../document_field';
import { IndexPattern, IndexPatternLayer, IndexPatternField } from '../types';
import { IndexPatternColumn } from '.';
import { GenericIndexPatternColumn } from '.';
import { DateHistogramIndexPatternColumn } from './definitions/date_histogram';
const indexPatternFields = [
{
@ -77,7 +78,7 @@ const indexPattern = {
};
const baseColumnArgs: {
previousColumn: IndexPatternColumn;
previousColumn: GenericIndexPatternColumn;
indexPattern: IndexPattern;
layer: IndexPatternLayer;
field: IndexPatternField;
@ -113,7 +114,7 @@ const layer: IndexPatternLayer = {
operationType: 'date_histogram',
sourceField: 'timestamp',
params: { interval: 'auto' },
},
} as DateHistogramIndexPatternColumn,
metric: {
label: 'metricLabel',
customLabel: true,

View file

@ -9,6 +9,7 @@ import { checkReferences, checkForDataLayerType } from './utils';
import { operationDefinitionMap } from '..';
import { createMockedFullReference } from '../../mocks';
import { layerTypes } from '../../../../../common';
import { DateHistogramIndexPatternColumn } from '../date_histogram';
// Mock prevents issue with circular loading
jest.mock('..');
@ -35,7 +36,6 @@ describe('utils', () => {
columns: {
ref: {
label: 'Label',
// @ts-expect-error test-only operation type
operationType: 'testReference',
isBucketed: false,
dataType: 'number',
@ -57,7 +57,6 @@ describe('utils', () => {
columns: {
ref: {
label: 'Label',
// @ts-expect-error test-only operation type
operationType: 'testReference',
isBucketed: false,
dataType: 'number',
@ -70,7 +69,7 @@ describe('utils', () => {
dataType: 'date',
sourceField: 'timestamp',
params: { interval: 'auto' },
},
} as DateHistogramIndexPatternColumn,
},
columnOrder: ['invalid', 'ref'],
indexPatternId: '',

View file

@ -42,6 +42,11 @@ export interface ReferenceBasedIndexPatternColumn
references: string[];
}
export type GenericIndexPatternColumn =
| BaseIndexPatternColumn
| FieldBasedIndexPatternColumn
| ReferenceBasedIndexPatternColumn;
// Used to store the temporary invalid state
export interface IncompleteColumn {
operationType?: OperationType;

View file

@ -11,7 +11,7 @@ import { buildExpressionFunction } from '../../../../../../../src/plugins/expres
import { OperationDefinition } from './index';
import { FormattedIndexPatternColumn, FieldBasedIndexPatternColumn } from './column_types';
import { IndexPatternField } from '../../types';
import { getInvalidFieldMessage, getFilter } from './helpers';
import { getInvalidFieldMessage, getFilter, isColumnFormatted } from './helpers';
import {
adjustTimeScaleLabelSuffix,
adjustTimeScaleOnOtherColumnChange,
@ -84,9 +84,8 @@ export const countOperation: OperationDefinition<CountIndexPatternColumn, 'field
timeShift: columnParams?.shift || previousColumn?.timeShift,
params:
previousColumn?.dataType === 'number' &&
previousColumn.params &&
'format' in previousColumn.params &&
previousColumn.params.format
isColumnFormatted(previousColumn) &&
previousColumn.params
? { format: previousColumn.params.format }
: undefined,
};

View file

@ -124,7 +124,7 @@ describe('date_histogram', () => {
interval: '42w',
},
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
},
};
});
@ -332,7 +332,7 @@ describe('date_histogram', () => {
interval: 'd',
},
sourceField: 'other_timestamp',
},
} as DateHistogramIndexPatternColumn,
},
};
const instance = shallow(
@ -366,7 +366,7 @@ describe('date_histogram', () => {
interval: 'auto',
},
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
},
};
@ -401,7 +401,7 @@ describe('date_histogram', () => {
interval: 'auto',
},
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
},
};
@ -594,7 +594,7 @@ describe('date_histogram', () => {
operationType: 'date_histogram',
sourceField: 'missing',
params: { interval: 'auto' },
},
} as DateHistogramIndexPatternColumn,
}
)
).toEqual('Missing field');

View file

@ -71,272 +71,275 @@ function getMultipleDateHistogramsErrorMessage(layer: IndexPatternLayer, columnI
});
}
export const dateHistogramOperation: OperationDefinition<DateHistogramIndexPatternColumn, 'field'> =
{
type: 'date_histogram',
displayName: i18n.translate('xpack.lens.indexPattern.dateHistogram', {
defaultMessage: 'Date histogram',
}),
input: 'field',
priority: 5, // Highest priority level used
operationParams: [{ name: 'interval', type: 'string', required: false }],
getErrorMessage: (layer, columnId, indexPattern) =>
[
...(getInvalidFieldMessage(
layer.columns[columnId] as FieldBasedIndexPatternColumn,
indexPattern
) || []),
getMultipleDateHistogramsErrorMessage(layer, columnId) || '',
].filter(Boolean),
getHelpMessage: (props) => <AutoDateHistogramPopover {...props} />,
getPossibleOperationForField: ({ aggregationRestrictions, aggregatable, type }) => {
if (
(type === 'date' || type === 'date_range') &&
aggregatable &&
(!aggregationRestrictions || aggregationRestrictions.date_histogram)
) {
return {
dataType: 'date',
isBucketed: true,
scale: 'interval',
};
}
},
getDefaultLabel: (column, indexPattern) => getSafeName(column.sourceField, indexPattern),
buildColumn({ field }, columnParams) {
export const dateHistogramOperation: OperationDefinition<
DateHistogramIndexPatternColumn,
'field',
{ interval: string }
> = {
type: 'date_histogram',
displayName: i18n.translate('xpack.lens.indexPattern.dateHistogram', {
defaultMessage: 'Date histogram',
}),
input: 'field',
priority: 5, // Highest priority level used
operationParams: [{ name: 'interval', type: 'string', required: false }],
getErrorMessage: (layer, columnId, indexPattern) =>
[
...(getInvalidFieldMessage(
layer.columns[columnId] as FieldBasedIndexPatternColumn,
indexPattern
) || []),
getMultipleDateHistogramsErrorMessage(layer, columnId) || '',
].filter(Boolean),
getHelpMessage: (props) => <AutoDateHistogramPopover {...props} />,
getPossibleOperationForField: ({ aggregationRestrictions, aggregatable, type }) => {
if (
(type === 'date' || type === 'date_range') &&
aggregatable &&
(!aggregationRestrictions || aggregationRestrictions.date_histogram)
) {
return {
label: field.displayName,
dataType: 'date',
operationType: 'date_histogram',
sourceField: field.name,
isBucketed: true,
scale: 'interval',
params: {
interval: columnParams?.interval ?? autoInterval,
},
};
},
isTransferable: (column, newIndexPattern) => {
const newField = newIndexPattern.getFieldByName(column.sourceField);
}
},
getDefaultLabel: (column, indexPattern) => getSafeName(column.sourceField, indexPattern),
buildColumn({ field }, columnParams) {
return {
label: field.displayName,
dataType: 'date',
operationType: 'date_histogram',
sourceField: field.name,
isBucketed: true,
scale: 'interval',
params: {
interval: columnParams?.interval ?? autoInterval,
},
};
},
isTransferable: (column, newIndexPattern) => {
const newField = newIndexPattern.getFieldByName(column.sourceField);
return Boolean(
newField &&
newField.type === 'date' &&
newField.aggregatable &&
(!newField.aggregationRestrictions || newField.aggregationRestrictions.date_histogram)
);
},
onFieldChange: (oldColumn, field) => {
return {
...oldColumn,
label: field.displayName,
sourceField: field.name,
};
},
toEsAggsFn: (column, columnId, indexPattern) => {
const usedField = indexPattern.getFieldByName(column.sourceField);
let timeZone: string | undefined;
let interval = column.params?.interval ?? autoInterval;
if (
usedField &&
usedField.aggregationRestrictions &&
usedField.aggregationRestrictions.date_histogram
) {
interval = restrictedInterval(usedField.aggregationRestrictions) as string;
timeZone = usedField.aggregationRestrictions.date_histogram.time_zone;
}
return buildExpressionFunction<AggFunctionsMapping['aggDateHistogram']>('aggDateHistogram', {
id: columnId,
enabled: true,
schema: 'segment',
field: column.sourceField,
time_zone: timeZone,
useNormalizedEsInterval: !usedField?.aggregationRestrictions?.date_histogram,
interval,
drop_partials: false,
min_doc_count: 0,
extended_bounds: extendedBoundsToAst({}),
}).toAst();
},
paramEditor: function ParamEditor({
layer,
columnId,
currentColumn,
updateLayer,
dateRange,
data,
indexPattern,
}: ParamEditorProps<DateHistogramIndexPatternColumn>) {
const field = currentColumn && indexPattern.getFieldByName(currentColumn.sourceField);
const intervalIsRestricted =
field!.aggregationRestrictions && field!.aggregationRestrictions.date_histogram;
return Boolean(
newField &&
newField.type === 'date' &&
newField.aggregatable &&
(!newField.aggregationRestrictions || newField.aggregationRestrictions.date_histogram)
);
},
onFieldChange: (oldColumn, field) => {
return {
...oldColumn,
label: field.displayName,
sourceField: field.name,
};
},
toEsAggsFn: (column, columnId, indexPattern) => {
const usedField = indexPattern.getFieldByName(column.sourceField);
let timeZone: string | undefined;
let interval = column.params?.interval ?? autoInterval;
if (
usedField &&
usedField.aggregationRestrictions &&
usedField.aggregationRestrictions.date_histogram
) {
interval = restrictedInterval(usedField.aggregationRestrictions) as string;
timeZone = usedField.aggregationRestrictions.date_histogram.time_zone;
}
return buildExpressionFunction<AggFunctionsMapping['aggDateHistogram']>('aggDateHistogram', {
id: columnId,
enabled: true,
schema: 'segment',
field: column.sourceField,
time_zone: timeZone,
useNormalizedEsInterval: !usedField?.aggregationRestrictions?.date_histogram,
interval,
drop_partials: false,
min_doc_count: 0,
extended_bounds: extendedBoundsToAst({}),
}).toAst();
},
paramEditor: function ParamEditor({
layer,
columnId,
currentColumn,
updateLayer,
dateRange,
data,
indexPattern,
}: ParamEditorProps<DateHistogramIndexPatternColumn>) {
const field = currentColumn && indexPattern.getFieldByName(currentColumn.sourceField);
const intervalIsRestricted =
field!.aggregationRestrictions && field!.aggregationRestrictions.date_histogram;
const interval = parseInterval(currentColumn.params.interval);
const interval = parseInterval(currentColumn.params.interval);
// We force the interval value to 1 if it's empty, since that is the ES behavior,
// and the isValidInterval function doesn't handle the empty case properly. Fixing
// isValidInterval involves breaking changes in other areas.
const isValid = isValidInterval(
`${interval.value === '' ? '1' : interval.value}${interval.unit}`,
restrictedInterval(field!.aggregationRestrictions)
);
// We force the interval value to 1 if it's empty, since that is the ES behavior,
// and the isValidInterval function doesn't handle the empty case properly. Fixing
// isValidInterval involves breaking changes in other areas.
const isValid = isValidInterval(
`${interval.value === '' ? '1' : interval.value}${interval.unit}`,
restrictedInterval(field!.aggregationRestrictions)
);
function onChangeAutoInterval(ev: EuiSwitchEvent) {
const { fromDate, toDate } = dateRange;
const value = ev.target.checked
? data.search.aggs.calculateAutoTimeExpression({ from: fromDate, to: toDate }) || '1h'
: autoInterval;
updateLayer(updateColumnParam({ layer, columnId, paramName: 'interval', value }));
}
function onChangeAutoInterval(ev: EuiSwitchEvent) {
const { fromDate, toDate } = dateRange;
const value = ev.target.checked
? data.search.aggs.calculateAutoTimeExpression({ from: fromDate, to: toDate }) || '1h'
: autoInterval;
updateLayer(updateColumnParam({ layer, columnId, paramName: 'interval', value }));
}
const setInterval = (newInterval: typeof interval) => {
const isCalendarInterval = calendarOnlyIntervals.has(newInterval.unit);
const value = `${isCalendarInterval ? '1' : newInterval.value}${newInterval.unit || 'd'}`;
const setInterval = (newInterval: typeof interval) => {
const isCalendarInterval = calendarOnlyIntervals.has(newInterval.unit);
const value = `${isCalendarInterval ? '1' : newInterval.value}${newInterval.unit || 'd'}`;
updateLayer(updateColumnParam({ layer, columnId, paramName: 'interval', value }));
};
updateLayer(updateColumnParam({ layer, columnId, paramName: 'interval', value }));
};
return (
<>
{!intervalIsRestricted && (
<EuiFormRow display="rowCompressed" hasChildLabel={false}>
<EuiSwitch
label={i18n.translate('xpack.lens.indexPattern.dateHistogram.autoInterval', {
defaultMessage: 'Customize time interval',
})}
checked={currentColumn.params.interval !== autoInterval}
onChange={onChangeAutoInterval}
compressed
/>
</EuiFormRow>
)}
{currentColumn.params.interval !== autoInterval && (
<EuiFormRow
label={i18n.translate('xpack.lens.indexPattern.dateHistogram.minimumInterval', {
defaultMessage: 'Minimum interval',
return (
<>
{!intervalIsRestricted && (
<EuiFormRow display="rowCompressed" hasChildLabel={false}>
<EuiSwitch
label={i18n.translate('xpack.lens.indexPattern.dateHistogram.autoInterval', {
defaultMessage: 'Customize time interval',
})}
fullWidth
display="rowCompressed"
>
{intervalIsRestricted ? (
<FormattedMessage
id="xpack.lens.indexPattern.dateHistogram.restrictedInterval"
defaultMessage="Interval fixed to {intervalValue} due to aggregation restrictions."
values={{
intervalValue: restrictedInterval(field!.aggregationRestrictions),
}}
/>
) : (
<>
<EuiFlexGroup responsive={false} gutterSize="s">
<EuiFlexItem>
<EuiFieldNumber
compressed
data-test-subj="lensDateHistogramValue"
value={
typeof interval.value === 'number' || interval.value === ''
? interval.value
: parseInt(interval.value, 10)
}
disabled={calendarOnlyIntervals.has(interval.unit)}
isInvalid={!isValid}
onChange={(e) => {
const newInterval = {
...interval,
value: e.target.value,
};
setInterval(newInterval);
}}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiSelect
compressed
data-test-subj="lensDateHistogramUnit"
value={interval.unit}
onChange={(e) => {
const newInterval = {
...interval,
unit: e.target.value,
};
setInterval(newInterval);
}}
isInvalid={!isValid}
options={[
{
value: 'ms',
text: i18n.translate(
'xpack.lens.indexPattern.dateHistogram.milliseconds',
{
defaultMessage: 'milliseconds',
}
),
},
{
value: 's',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.seconds', {
defaultMessage: 'seconds',
}),
},
{
value: 'm',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.minutes', {
defaultMessage: 'minutes',
}),
},
{
value: 'h',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.hours', {
defaultMessage: 'hours',
}),
},
{
value: 'd',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.days', {
defaultMessage: 'days',
}),
},
{
value: 'w',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.week', {
defaultMessage: 'week',
}),
},
{
value: 'M',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.month', {
defaultMessage: 'month',
}),
},
// Quarterly intervals appear to be unsupported by esaggs
{
value: 'y',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.year', {
defaultMessage: 'year',
}),
},
]}
/>
</EuiFlexItem>
</EuiFlexGroup>
{!isValid && (
<>
<EuiSpacer size="s" />
<EuiTextColor color="danger" data-test-subj="lensDateHistogramError">
{i18n.translate('xpack.lens.indexPattern.invalidInterval', {
defaultMessage: 'Invalid interval value',
})}
</EuiTextColor>
</>
)}
</>
)}
</EuiFormRow>
)}
</>
);
},
};
checked={currentColumn.params.interval !== autoInterval}
onChange={onChangeAutoInterval}
compressed
/>
</EuiFormRow>
)}
{currentColumn.params.interval !== autoInterval && (
<EuiFormRow
label={i18n.translate('xpack.lens.indexPattern.dateHistogram.minimumInterval', {
defaultMessage: 'Minimum interval',
})}
fullWidth
display="rowCompressed"
>
{intervalIsRestricted ? (
<FormattedMessage
id="xpack.lens.indexPattern.dateHistogram.restrictedInterval"
defaultMessage="Interval fixed to {intervalValue} due to aggregation restrictions."
values={{
intervalValue: restrictedInterval(field!.aggregationRestrictions),
}}
/>
) : (
<>
<EuiFlexGroup responsive={false} gutterSize="s">
<EuiFlexItem>
<EuiFieldNumber
compressed
data-test-subj="lensDateHistogramValue"
value={
typeof interval.value === 'number' || interval.value === ''
? interval.value
: parseInt(interval.value, 10)
}
disabled={calendarOnlyIntervals.has(interval.unit)}
isInvalid={!isValid}
onChange={(e) => {
const newInterval = {
...interval,
value: e.target.value,
};
setInterval(newInterval);
}}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiSelect
compressed
data-test-subj="lensDateHistogramUnit"
value={interval.unit}
onChange={(e) => {
const newInterval = {
...interval,
unit: e.target.value,
};
setInterval(newInterval);
}}
isInvalid={!isValid}
options={[
{
value: 'ms',
text: i18n.translate(
'xpack.lens.indexPattern.dateHistogram.milliseconds',
{
defaultMessage: 'milliseconds',
}
),
},
{
value: 's',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.seconds', {
defaultMessage: 'seconds',
}),
},
{
value: 'm',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.minutes', {
defaultMessage: 'minutes',
}),
},
{
value: 'h',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.hours', {
defaultMessage: 'hours',
}),
},
{
value: 'd',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.days', {
defaultMessage: 'days',
}),
},
{
value: 'w',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.week', {
defaultMessage: 'week',
}),
},
{
value: 'M',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.month', {
defaultMessage: 'month',
}),
},
// Quarterly intervals appear to be unsupported by esaggs
{
value: 'y',
text: i18n.translate('xpack.lens.indexPattern.dateHistogram.year', {
defaultMessage: 'year',
}),
},
]}
/>
</EuiFlexItem>
</EuiFlexGroup>
{!isValid && (
<>
<EuiSpacer size="s" />
<EuiTextColor color="danger" data-test-subj="lensDateHistogramError">
{i18n.translate('xpack.lens.indexPattern.invalidInterval', {
defaultMessage: 'Invalid interval value',
})}
</EuiTextColor>
</>
)}
</>
)}
</EuiFormRow>
)}
</>
);
},
};
function parseInterval(currentInterval: string) {
const interval = currentInterval || '';

View file

@ -74,7 +74,7 @@ describe('filters', () => {
},
],
},
},
} as FiltersIndexPatternColumn,
col2: {
label: 'Count',
dataType: 'number',

View file

@ -28,7 +28,7 @@ import { hasFunctionFieldArgument } from '../validation';
import type {
GenericOperationDefinition,
IndexPatternColumn,
GenericIndexPatternColumn,
OperationDefinition,
ParamEditorProps,
} from '../../index';
@ -503,7 +503,7 @@ export function getFunctionSignatureLabel(
function getFunctionArgumentsStringified(
params: Required<
OperationDefinition<IndexPatternColumn, 'field' | 'fullReference'>
OperationDefinition<GenericIndexPatternColumn, 'field' | 'fullReference'>
>['operationParams']
) {
return params

View file

@ -6,15 +6,18 @@
*/
import { createMockedIndexPattern } from '../../../mocks';
import { formulaOperation, GenericOperationDefinition, IndexPatternColumn } from '../index';
import { formulaOperation, GenericOperationDefinition, GenericIndexPatternColumn } from '../index';
import { FormulaIndexPatternColumn } from './formula';
import { regenerateLayerFromAst } from './parse';
import type { IndexPattern, IndexPatternField, IndexPatternLayer } from '../../../types';
import { tinymathFunctions } from './util';
import { TermsIndexPatternColumn } from '../terms';
import { MovingAverageIndexPatternColumn } from '../calculations';
import { StaticValueIndexPatternColumn } from '../static_value';
jest.mock('../../layer_helpers', () => {
return {
getColumnOrder: jest.fn(({ columns }: { columns: Record<string, IndexPatternColumn> }) =>
getColumnOrder: jest.fn(({ columns }: { columns: Record<string, GenericIndexPatternColumn> }) =>
Object.keys(columns)
),
getManagedColumnsFrom: jest.fn().mockReturnValue([]),
@ -113,7 +116,7 @@ describe('formula', () => {
orderDirection: 'asc',
},
sourceField: 'category',
},
} as TermsIndexPatternColumn,
},
};
});
@ -191,7 +194,7 @@ describe('formula', () => {
},
},
},
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
layer,
indexPattern,
})
@ -225,7 +228,7 @@ describe('formula', () => {
// Need to test with multiple replaces due to string replace
query: `category.keyword: "Men's Clothing" or category.keyword: "Men's Shoes"`,
},
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
layer,
indexPattern,
})
@ -254,7 +257,7 @@ describe('formula', () => {
language: 'lucene',
query: `*`,
},
} as IndexPatternColumn,
} as GenericIndexPatternColumn,
layer,
indexPattern,
})
@ -285,7 +288,7 @@ describe('formula', () => {
references: ['col2'],
timeScale: 'd',
params: { window: 3 },
},
} as MovingAverageIndexPatternColumn,
layer: {
indexPatternId: '1',
columnOrder: [],
@ -299,7 +302,7 @@ describe('formula', () => {
references: ['col2'],
timeScale: 'd',
params: { window: 3 },
},
} as MovingAverageIndexPatternColumn,
col2: {
dataType: 'number',
isBucketed: false,
@ -345,7 +348,7 @@ describe('formula', () => {
orderDirection: 'asc',
},
sourceField: 'category',
},
} as TermsIndexPatternColumn,
layer: {
indexPatternId: '1',
columnOrder: [],
@ -361,7 +364,7 @@ describe('formula', () => {
orderDirection: 'asc',
},
sourceField: 'category',
},
} as TermsIndexPatternColumn,
},
},
indexPattern,
@ -392,7 +395,7 @@ describe('formula', () => {
params: {
value: '0',
},
},
} as StaticValueIndexPatternColumn,
layer,
indexPattern,
})
@ -668,7 +671,7 @@ describe('formula', () => {
scale: 'ratio',
params: { formula, isFormulaBroken: isBroken },
references: [],
},
} as FormulaIndexPatternColumn,
},
columnOrder: [],
indexPatternId: '',

View file

@ -15,6 +15,7 @@ import { regenerateLayerFromAst } from './parse';
import { generateFormula } from './generate';
import { filterByVisibleOperation } from './util';
import { getManagedColumnsFrom } from '../../layer_helpers';
import { isColumnFormatted } from '../helpers';
const defaultLabel = i18n.translate('xpack.lens.indexPattern.formulaLabel', {
defaultMessage: 'Formula',
@ -120,8 +121,8 @@ export const formulaOperation: OperationDefinition<FormulaIndexPatternColumn, 'm
// carry over the format settings from previous operation for seamless transfer
// NOTE: this works only for non-default formatters set in Lens
let prevFormat = {};
if (previousColumn?.params && 'format' in previousColumn.params) {
prevFormat = { format: previousColumn.params.format };
if (previousColumn && isColumnFormatted(previousColumn)) {
prevFormat = { format: previousColumn.params?.format };
}
return {
label: previousFormula || defaultLabel,

View file

@ -9,11 +9,13 @@ import { isObject } from 'lodash';
import {
FieldBasedIndexPatternColumn,
GenericOperationDefinition,
IndexPatternColumn,
GenericIndexPatternColumn,
} from '../index';
import { ReferenceBasedIndexPatternColumn } from '../column_types';
import { BaseIndexPatternColumn, ReferenceBasedIndexPatternColumn } from '../column_types';
import { IndexPatternLayer } from '../../../types';
import { unquotedStringRegex } from './util';
import { isColumnOfType } from '../helpers';
import { StaticValueIndexPatternColumn } from '../static_value';
// Just handle two levels for now
type OperationParams = Record<string, string | number | Record<string, string | number>>;
@ -33,12 +35,12 @@ export function getSafeFieldName({
}
export function generateFormula(
previousColumn: ReferenceBasedIndexPatternColumn | IndexPatternColumn,
previousColumn: ReferenceBasedIndexPatternColumn | GenericIndexPatternColumn,
layer: IndexPatternLayer,
previousFormula: string,
operationDefinitionMap: Record<string, GenericOperationDefinition> | undefined
) {
if (previousColumn.operationType === 'static_value') {
if (isColumnOfType<StaticValueIndexPatternColumn>('static_value', previousColumn)) {
if (previousColumn.params && 'value' in previousColumn.params) {
return String(previousColumn.params.value); // make sure it's a string
}
@ -81,17 +83,25 @@ export function generateFormula(
return previousFormula;
}
interface ParameterizedColumn extends BaseIndexPatternColumn {
params: OperationParams;
}
function isParameterizedColumn(col: GenericIndexPatternColumn): col is ParameterizedColumn {
return Boolean('params' in col && col.params);
}
function extractParamsForFormula(
column: IndexPatternColumn | ReferenceBasedIndexPatternColumn,
column: GenericIndexPatternColumn,
operationDefinitionMap: Record<string, GenericOperationDefinition> | undefined
) {
if (!operationDefinitionMap) {
return [];
}
const def = operationDefinitionMap[column.operationType];
if ('operationParams' in def && column.params) {
if ('operationParams' in def && isParameterizedColumn(column)) {
return (def.operationParams || []).flatMap(({ name, required }) => {
const value = (column.params as OperationParams)![name];
const value = column.params[name];
if (isObject(value)) {
return Object.keys(value).map((subName) => ({
name: `${name}-${subName}`,

View file

@ -8,7 +8,11 @@
import { i18n } from '@kbn/i18n';
import { isObject } from 'lodash';
import type { TinymathAST, TinymathVariable, TinymathLocation } from '@kbn/tinymath';
import { OperationDefinition, GenericOperationDefinition, IndexPatternColumn } from '../index';
import {
OperationDefinition,
GenericOperationDefinition,
GenericIndexPatternColumn,
} from '../index';
import { IndexPattern, IndexPatternLayer } from '../../../types';
import { mathOperation } from './math';
import { documentField } from '../../../document_field';
@ -67,8 +71,8 @@ function extractColumns(
layer: IndexPatternLayer,
indexPattern: IndexPattern,
label: string
): Array<{ column: IndexPatternColumn; location?: TinymathLocation }> {
const columns: Array<{ column: IndexPatternColumn; location?: TinymathLocation }> = [];
): Array<{ column: GenericIndexPatternColumn; location?: TinymathLocation }> {
const columns: Array<{ column: GenericIndexPatternColumn; location?: TinymathLocation }> = [];
function parseNode(node: TinymathAST) {
if (typeof node === 'number' || node.type !== 'function') {
@ -102,7 +106,7 @@ function extractColumns(
const mappedParams = getOperationParams(nodeOperation, namedArguments || []);
const newCol = (
nodeOperation as OperationDefinition<IndexPatternColumn, 'field'>
nodeOperation as OperationDefinition<GenericIndexPatternColumn, 'field'>
).buildColumn(
{
layer,
@ -139,7 +143,7 @@ function extractColumns(
const mappedParams = getOperationParams(nodeOperation, namedArguments || []);
const newCol = (
nodeOperation as OperationDefinition<IndexPatternColumn, 'fullReference'>
nodeOperation as OperationDefinition<GenericIndexPatternColumn, 'fullReference'>
).buildColumn(
{
layer,
@ -227,7 +231,7 @@ export function regenerateLayerFromAst(
isFormulaBroken: !isValid,
},
references: !isValid ? [] : [getManagedId(columnId, extracted.length - 1)],
};
} as FormulaIndexPatternColumn;
return {
newLayer: {

View file

@ -13,7 +13,11 @@ import type {
TinymathNamedArgument,
TinymathVariable,
} from 'packages/kbn-tinymath';
import type { OperationDefinition, IndexPatternColumn, GenericOperationDefinition } from '../index';
import type {
OperationDefinition,
GenericIndexPatternColumn,
GenericOperationDefinition,
} from '../index';
import type { GroupedNodes } from './types';
export const unquotedStringRegex = /[^0-9A-Za-z._@\[\]/]/;
@ -46,8 +50,8 @@ export function getValueOrName(node: TinymathAST) {
export function getOperationParams(
operation:
| OperationDefinition<IndexPatternColumn, 'field'>
| OperationDefinition<IndexPatternColumn, 'fullReference'>,
| OperationDefinition<GenericIndexPatternColumn, 'field'>
| OperationDefinition<GenericIndexPatternColumn, 'fullReference'>,
params: TinymathNamedArgument[] = []
): Record<string, string | number> {
const formalArgs: Record<string, string> = (operation.operationParams || []).reduce(

View file

@ -20,7 +20,11 @@ import {
tinymathFunctions,
} from './util';
import type { OperationDefinition, IndexPatternColumn, GenericOperationDefinition } from '../index';
import type {
OperationDefinition,
GenericIndexPatternColumn,
GenericOperationDefinition,
} from '../index';
import type { IndexPattern, IndexPatternLayer } from '../../../types';
import type { TinymathNodeTypes } from './types';
import { parseTimeShift } from '../../../../../../../../src/plugins/data/common';
@ -482,8 +486,8 @@ function checkSingleQuery(namedArguments: TinymathNamedArgument[] | undefined) {
function validateNameArguments(
node: TinymathFunction,
nodeOperation:
| OperationDefinition<IndexPatternColumn, 'field'>
| OperationDefinition<IndexPatternColumn, 'fullReference'>,
| OperationDefinition<GenericIndexPatternColumn, 'field'>
| OperationDefinition<GenericIndexPatternColumn, 'fullReference'>,
namedArguments: TinymathNamedArgument[] | undefined,
indexPattern: IndexPattern
) {
@ -749,16 +753,16 @@ function runFullASTValidation(
export function canHaveParams(
operation:
| OperationDefinition<IndexPatternColumn, 'field'>
| OperationDefinition<IndexPatternColumn, 'fullReference'>
| OperationDefinition<GenericIndexPatternColumn, 'field'>
| OperationDefinition<GenericIndexPatternColumn, 'fullReference'>
) {
return Boolean((operation.operationParams || []).length) || operation.filterable;
}
export function getInvalidParams(
operation:
| OperationDefinition<IndexPatternColumn, 'field'>
| OperationDefinition<IndexPatternColumn, 'fullReference'>,
| OperationDefinition<GenericIndexPatternColumn, 'field'>
| OperationDefinition<GenericIndexPatternColumn, 'fullReference'>,
params: TinymathNamedArgument[] = []
) {
return validateParams(operation, params).filter(
@ -768,8 +772,8 @@ export function getInvalidParams(
export function getMissingParams(
operation:
| OperationDefinition<IndexPatternColumn, 'field'>
| OperationDefinition<IndexPatternColumn, 'fullReference'>,
| OperationDefinition<GenericIndexPatternColumn, 'field'>
| OperationDefinition<GenericIndexPatternColumn, 'fullReference'>,
params: TinymathNamedArgument[] = []
) {
return validateParams(operation, params).filter(
@ -779,8 +783,8 @@ export function getMissingParams(
export function getWrongTypeParams(
operation:
| OperationDefinition<IndexPatternColumn, 'field'>
| OperationDefinition<IndexPatternColumn, 'fullReference'>,
| OperationDefinition<GenericIndexPatternColumn, 'field'>
| OperationDefinition<GenericIndexPatternColumn, 'fullReference'>,
params: TinymathNamedArgument[] = []
) {
return validateParams(operation, params).filter(
@ -789,7 +793,7 @@ export function getWrongTypeParams(
}
function getReturnedType(
operation: OperationDefinition<IndexPatternColumn, 'field'>,
operation: OperationDefinition<GenericIndexPatternColumn, 'field'>,
indexPattern: IndexPattern,
firstArg: TinymathAST
) {
@ -822,8 +826,8 @@ function getDuplicateParams(params: TinymathNamedArgument[] = []) {
export function validateParams(
operation:
| OperationDefinition<IndexPatternColumn, 'field'>
| OperationDefinition<IndexPatternColumn, 'fullReference'>,
| OperationDefinition<GenericIndexPatternColumn, 'field'>
| OperationDefinition<GenericIndexPatternColumn, 'fullReference'>,
params: TinymathNamedArgument[] = []
) {
const paramsObj = getOperationParams(operation, params);

View file

@ -6,8 +6,12 @@
*/
import { i18n } from '@kbn/i18n';
import { IndexPatternColumn, operationDefinitionMap } from '.';
import { FieldBasedIndexPatternColumn, ReferenceBasedIndexPatternColumn } from './column_types';
import { GenericIndexPatternColumn, operationDefinitionMap } from '.';
import {
FieldBasedIndexPatternColumn,
FormattedIndexPatternColumn,
ReferenceBasedIndexPatternColumn,
} from './column_types';
import { IndexPattern } from '../../types';
export function getInvalidFieldMessage(
@ -36,7 +40,7 @@ export function getInvalidFieldMessage(
operationDefinition &&
field &&
!operationDefinition.isTransferable(
column as IndexPatternColumn,
column as GenericIndexPatternColumn,
indexPattern,
operationDefinitionMap
)
@ -90,19 +94,35 @@ export function isValidNumber(
);
}
export function isColumnOfType<C extends GenericIndexPatternColumn>(
type: C['operationType'],
column: GenericIndexPatternColumn
): column is C {
return column.operationType === type;
}
export function isColumnFormatted(
column: GenericIndexPatternColumn
): column is FormattedIndexPatternColumn {
return Boolean(
'params' in column &&
(column as FormattedIndexPatternColumn).params &&
'format' in (column as FormattedIndexPatternColumn).params!
);
}
export function getFormatFromPreviousColumn(
previousColumn: IndexPatternColumn | ReferenceBasedIndexPatternColumn | undefined
previousColumn: GenericIndexPatternColumn | ReferenceBasedIndexPatternColumn | undefined
) {
return previousColumn?.dataType === 'number' &&
previousColumn.params &&
'format' in previousColumn.params &&
previousColumn.params.format
isColumnFormatted(previousColumn) &&
previousColumn.params
? { format: previousColumn.params.format }
: undefined;
}
export function getFilter(
previousColumn: IndexPatternColumn | undefined,
previousColumn: GenericIndexPatternColumn | undefined,
columnParams: { kql?: string | undefined; lucene?: string | undefined } | undefined
) {
let filter = previousColumn?.filter;

View file

@ -7,93 +7,51 @@
import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup, CoreStart } from 'kibana/public';
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
import { termsOperation, TermsIndexPatternColumn } from './terms';
import { filtersOperation, FiltersIndexPatternColumn } from './filters';
import { cardinalityOperation, CardinalityIndexPatternColumn } from './cardinality';
import { percentileOperation, PercentileIndexPatternColumn } from './percentile';
import { termsOperation } from './terms';
import { filtersOperation } from './filters';
import { cardinalityOperation } from './cardinality';
import { percentileOperation } from './percentile';
import {
minOperation,
MinIndexPatternColumn,
averageOperation,
AvgIndexPatternColumn,
sumOperation,
SumIndexPatternColumn,
maxOperation,
MaxIndexPatternColumn,
medianOperation,
MedianIndexPatternColumn,
} from './metrics';
import { dateHistogramOperation, DateHistogramIndexPatternColumn } from './date_histogram';
import { dateHistogramOperation } from './date_histogram';
import {
cumulativeSumOperation,
CumulativeSumIndexPatternColumn,
counterRateOperation,
CounterRateIndexPatternColumn,
derivativeOperation,
DerivativeIndexPatternColumn,
movingAverageOperation,
MovingAverageIndexPatternColumn,
OverallSumIndexPatternColumn,
overallSumOperation,
OverallMinIndexPatternColumn,
overallMinOperation,
OverallMaxIndexPatternColumn,
overallMaxOperation,
OverallAverageIndexPatternColumn,
overallAverageOperation,
} from './calculations';
import { countOperation, CountIndexPatternColumn } from './count';
import {
mathOperation,
MathIndexPatternColumn,
formulaOperation,
FormulaIndexPatternColumn,
} from './formula';
import { staticValueOperation, StaticValueIndexPatternColumn } from './static_value';
import { lastValueOperation, LastValueIndexPatternColumn } from './last_value';
import { countOperation } from './count';
import { mathOperation, formulaOperation } from './formula';
import { staticValueOperation } from './static_value';
import { lastValueOperation } from './last_value';
import { FrameDatasourceAPI, OperationMetadata, ParamEditorCustomProps } from '../../../types';
import type { BaseIndexPatternColumn, ReferenceBasedIndexPatternColumn } from './column_types';
import type {
BaseIndexPatternColumn,
GenericIndexPatternColumn,
ReferenceBasedIndexPatternColumn,
} from './column_types';
import { IndexPattern, IndexPatternField, IndexPatternLayer } from '../../types';
import { DateRange, LayerType } from '../../../../common';
import { ExpressionAstFunction } from '../../../../../../../src/plugins/expressions/public';
import { DataPublicPluginStart } from '../../../../../../../src/plugins/data/public';
import { RangeIndexPatternColumn, rangeOperation } from './ranges';
import { rangeOperation } from './ranges';
import { IndexPatternDimensionEditorProps } from '../../dimension_panel';
/**
* A union type of all available column types. If a column is of an unknown type somewhere
* withing the indexpattern data source it should be typed as `IndexPatternColumn` to make
* typeguards possible that consider all available column types.
*/
export type IndexPatternColumn =
| FiltersIndexPatternColumn
| RangeIndexPatternColumn
| TermsIndexPatternColumn
| DateHistogramIndexPatternColumn
| MinIndexPatternColumn
| MaxIndexPatternColumn
| AvgIndexPatternColumn
| CardinalityIndexPatternColumn
| SumIndexPatternColumn
| MedianIndexPatternColumn
| PercentileIndexPatternColumn
| CountIndexPatternColumn
| LastValueIndexPatternColumn
| CumulativeSumIndexPatternColumn
| OverallSumIndexPatternColumn
| OverallMinIndexPatternColumn
| OverallMaxIndexPatternColumn
| OverallAverageIndexPatternColumn
| CounterRateIndexPatternColumn
| DerivativeIndexPatternColumn
| MovingAverageIndexPatternColumn
| MathIndexPatternColumn
| FormulaIndexPatternColumn
| StaticValueIndexPatternColumn;
export type FieldBasedIndexPatternColumn = Extract<IndexPatternColumn, { sourceField: string }>;
export type { IncompleteColumn } from './column_types';
export type {
IncompleteColumn,
BaseIndexPatternColumn,
GenericIndexPatternColumn,
FieldBasedIndexPatternColumn,
} from './column_types';
export type { TermsIndexPatternColumn } from './terms';
export type { FiltersIndexPatternColumn } from './filters';
@ -125,7 +83,7 @@ export type { StaticValueIndexPatternColumn } from './static_value';
// List of all operation definitions registered to this data source.
// If you want to implement a new operation, add the definition to this array and
// the column type to the `IndexPatternColumn` union type below.
// the column type to the `GenericIndexPatternColumn` union type below.
const internalOperationDefinitions = [
filtersOperation,
termsOperation,
@ -227,7 +185,7 @@ interface BaseOperationDefinitionProps<C extends BaseIndexPatternColumn> {
getDefaultLabel: (
column: C,
indexPattern: IndexPattern,
columns: Record<string, IndexPatternColumn>
columns: Record<string, GenericIndexPatternColumn>
) => string;
/**
* This function is called if another column in the same layer changed or got added/removed.
@ -337,7 +295,7 @@ interface OperationParam {
defaultValue?: string | number;
}
interface FieldlessOperationDefinition<C extends BaseIndexPatternColumn> {
interface FieldlessOperationDefinition<C extends BaseIndexPatternColumn, P = {}> {
input: 'none';
/**
@ -350,9 +308,9 @@ interface FieldlessOperationDefinition<C extends BaseIndexPatternColumn> {
*/
buildColumn: (
arg: BaseBuildColumnArgs & {
previousColumn?: IndexPatternColumn;
previousColumn?: GenericIndexPatternColumn;
},
columnParams?: (IndexPatternColumn & C)['params']
columnParams?: P
) => C;
/**
* Returns the meta data of the operation if applied. Undefined
@ -372,7 +330,7 @@ interface FieldlessOperationDefinition<C extends BaseIndexPatternColumn> {
) => ExpressionAstFunction;
}
interface FieldBasedOperationDefinition<C extends BaseIndexPatternColumn> {
interface FieldBasedOperationDefinition<C extends BaseIndexPatternColumn, P = {}> {
input: 'field';
/**
@ -391,9 +349,9 @@ interface FieldBasedOperationDefinition<C extends BaseIndexPatternColumn> {
buildColumn: (
arg: BaseBuildColumnArgs & {
field: IndexPatternField;
previousColumn?: IndexPatternColumn;
previousColumn?: GenericIndexPatternColumn;
},
columnParams?: (IndexPatternColumn & C)['params'] & {
columnParams?: P & {
kql?: string;
lucene?: string;
shift?: string;
@ -498,7 +456,7 @@ interface FullReferenceOperationDefinition<C extends BaseIndexPatternColumn> {
buildColumn: (
arg: BaseBuildColumnArgs & {
referenceIds: string[];
previousColumn?: IndexPatternColumn;
previousColumn?: GenericIndexPatternColumn;
},
columnParams?: (ReferenceBasedIndexPatternColumn & C)['params'] & {
kql?: string;
@ -528,7 +486,7 @@ interface ManagedReferenceOperationDefinition<C extends BaseIndexPatternColumn>
*/
buildColumn: (
arg: BaseBuildColumnArgs & {
previousColumn?: IndexPatternColumn | ReferenceBasedIndexPatternColumn;
previousColumn?: GenericIndexPatternColumn;
},
columnParams?: (ReferenceBasedIndexPatternColumn & C)['params'],
operationDefinitionMap?: Record<string, GenericOperationDefinition>
@ -559,9 +517,9 @@ interface ManagedReferenceOperationDefinition<C extends BaseIndexPatternColumn>
) => IndexPatternLayer;
}
interface OperationDefinitionMap<C extends BaseIndexPatternColumn> {
field: FieldBasedOperationDefinition<C>;
none: FieldlessOperationDefinition<C>;
interface OperationDefinitionMap<C extends BaseIndexPatternColumn, P = {}> {
field: FieldBasedOperationDefinition<C, P>;
none: FieldlessOperationDefinition<C, P>;
fullReference: FullReferenceOperationDefinition<C>;
managedReference: ManagedReferenceOperationDefinition<C>;
}
@ -573,24 +531,25 @@ interface OperationDefinitionMap<C extends BaseIndexPatternColumn> {
*/
export type OperationDefinition<
C extends BaseIndexPatternColumn,
Input extends keyof OperationDefinitionMap<C>
> = BaseOperationDefinitionProps<C> & OperationDefinitionMap<C>[Input];
Input extends keyof OperationDefinitionMap<C>,
P = {}
> = BaseOperationDefinitionProps<C> & OperationDefinitionMap<C, P>[Input];
/**
* A union type of all available operation types. The operation type is a unique id of an operation.
* Each column is assigned to exactly one operation type.
*/
export type OperationType = typeof internalOperationDefinitions[number]['type'];
export type OperationType = string;
/**
* This is an operation definition of an unspecified column out of all possible
* column types.
*/
export type GenericOperationDefinition =
| OperationDefinition<IndexPatternColumn, 'field'>
| OperationDefinition<IndexPatternColumn, 'none'>
| OperationDefinition<IndexPatternColumn, 'fullReference'>
| OperationDefinition<IndexPatternColumn, 'managedReference'>;
| OperationDefinition<BaseIndexPatternColumn, 'field'>
| OperationDefinition<BaseIndexPatternColumn, 'none'>
| OperationDefinition<BaseIndexPatternColumn, 'fullReference'>
| OperationDefinition<BaseIndexPatternColumn, 'managedReference'>;
/**
* List of all available operation definitions

View file

@ -15,6 +15,7 @@ import { createMockedIndexPattern } from '../../mocks';
import { LastValueIndexPatternColumn } from './last_value';
import { lastValueOperation } from './index';
import type { IndexPattern, IndexPatternLayer } from '../../types';
import { TermsIndexPatternColumn } from './terms';
const uiSettingsMock = {} as IUiSettingsClient;
@ -56,7 +57,7 @@ describe('last_value', () => {
orderDirection: 'asc',
},
sourceField: 'category',
},
} as TermsIndexPatternColumn,
col2: {
label: 'Last value of a',
dataType: 'number',
@ -66,7 +67,7 @@ describe('last_value', () => {
params: {
sortField: 'datefield',
},
},
} as LastValueIndexPatternColumn,
},
};
});
@ -467,7 +468,7 @@ describe('last_value', () => {
params: { sortField: 'timestamp' },
scale: 'ratio',
sourceField: 'bytes',
},
} as LastValueIndexPatternColumn,
},
columnOrder: [],
indexPatternId: '',
@ -499,7 +500,7 @@ describe('last_value', () => {
col1: {
...errorLayer.columns.col1,
params: {
...errorLayer.columns.col1.params,
...(errorLayer.columns.col1 as LastValueIndexPatternColumn).params,
sortField: 'notExisting',
},
} as LastValueIndexPatternColumn,
@ -530,7 +531,7 @@ describe('last_value', () => {
col1: {
...errorLayer.columns.col1,
params: {
...errorLayer.columns.col1.params,
...(errorLayer.columns.col1 as LastValueIndexPatternColumn).params,
sortField: 'bytes',
},
} as LastValueIndexPatternColumn,

View file

@ -17,6 +17,7 @@ import { PercentileIndexPatternColumn } from './percentile';
import { EuiFieldNumber } from '@elastic/eui';
import { act } from 'react-dom/test-utils';
import { EuiFormRow } from '@elastic/eui';
import { TermsIndexPatternColumn } from './terms';
const uiSettingsMock = {} as IUiSettingsClient;
@ -58,7 +59,7 @@ describe('percentile', () => {
orderDirection: 'asc',
},
sourceField: 'category',
},
} as TermsIndexPatternColumn,
col2: {
label: '23rd percentile of a',
dataType: 'number',
@ -68,7 +69,7 @@ describe('percentile', () => {
params: {
percentile: 23,
},
},
} as PercentileIndexPatternColumn,
},
};
});

View file

@ -17,6 +17,7 @@ import {
getSafeName,
isValidNumber,
getFilter,
isColumnOfType,
} from './helpers';
import { FieldBasedIndexPatternColumn } from './column_types';
import { adjustTimeScaleLabelSuffix } from '../time_scale_utils';
@ -53,7 +54,11 @@ const DEFAULT_PERCENTILE_VALUE = 95;
const supportedFieldTypes = ['number', 'histogram'];
export const percentileOperation: OperationDefinition<PercentileIndexPatternColumn, 'field'> = {
export const percentileOperation: OperationDefinition<
PercentileIndexPatternColumn,
'field',
{ percentile: number }
> = {
type: 'percentile',
displayName: i18n.translate('xpack.lens.indexPattern.percentile', {
defaultMessage: 'Percentile',
@ -91,9 +96,8 @@ export const percentileOperation: OperationDefinition<PercentileIndexPatternColu
),
buildColumn: ({ field, previousColumn, indexPattern }, columnParams) => {
const existingPercentileParam =
previousColumn?.operationType === 'percentile' &&
previousColumn.params &&
'percentile' in previousColumn.params &&
previousColumn &&
isColumnOfType<PercentileIndexPatternColumn>('percentile', previousColumn) &&
previousColumn.params.percentile;
const newPercentileParam =
columnParams?.percentile ?? (existingPercentileParam || DEFAULT_PERCENTILE_VALUE);
@ -174,7 +178,7 @@ export const percentileOperation: OperationDefinition<PercentileIndexPatternColu
...currentColumn.params,
percentile: inputValueAsNumber,
},
},
} as PercentileIndexPatternColumn,
},
});
},

View file

@ -154,7 +154,7 @@ describe('ranges', () => {
ranges: [{ from: 0, to: DEFAULT_INTERVAL, label: '' }],
maxBars: 'auto',
},
},
} as RangeIndexPatternColumn,
col2: {
label: 'Count',
dataType: 'number',
@ -385,10 +385,10 @@ describe('ranges', () => {
col1: {
...layer.columns.col1,
params: {
...layer.columns.col1.params,
...(layer.columns.col1 as RangeIndexPatternColumn).params,
maxBars: MAX_HISTOGRAM_VALUE,
},
},
} as RangeIndexPatternColumn,
},
});
});
@ -424,7 +424,7 @@ describe('ranges', () => {
col1: {
...layer.columns.col1,
params: {
...layer.columns.col1.params,
...(layer.columns.col1 as RangeIndexPatternColumn).params,
maxBars: GRANULARITY_DEFAULT_VALUE - GRANULARITY_STEP,
},
},
@ -448,7 +448,7 @@ describe('ranges', () => {
col1: {
...layer.columns.col1,
params: {
...layer.columns.col1.params,
...(layer.columns.col1 as RangeIndexPatternColumn).params,
maxBars: GRANULARITY_DEFAULT_VALUE,
},
},
@ -511,7 +511,10 @@ describe('ranges', () => {
currentColumn={
{
...layer.columns.col1,
params: { ...layer.columns.col1.params, parentFormat: undefined },
params: {
...(layer.columns.col1 as RangeIndexPatternColumn).params,
parentFormat: undefined,
},
} as RangeIndexPatternColumn
}
/>
@ -565,7 +568,7 @@ describe('ranges', () => {
col1: {
...layer.columns.col1,
params: {
...layer.columns.col1.params,
...(layer.columns.col1 as RangeIndexPatternColumn).params,
ranges: [
{ from: 0, to: DEFAULT_INTERVAL, label: '' },
{ from: 50, to: Infinity, label: '' },
@ -620,7 +623,7 @@ describe('ranges', () => {
col1: {
...layer.columns.col1,
params: {
...layer.columns.col1.params,
...(layer.columns.col1 as RangeIndexPatternColumn).params,
ranges: [
{ from: 0, to: DEFAULT_INTERVAL, label: '' },
{ from: DEFAULT_INTERVAL, to: Infinity, label: 'customlabel' },
@ -670,7 +673,7 @@ describe('ranges', () => {
col1: {
...layer.columns.col1,
params: {
...layer.columns.col1.params,
...(layer.columns.col1 as RangeIndexPatternColumn).params,
ranges: [{ from: 0, to: 50, label: '' }],
},
},

View file

@ -244,7 +244,7 @@ export const rangeOperation: OperationDefinition<RangeIndexPatternColumn, 'field
format: currentColumn.params.format,
parentFormat,
},
},
} as RangeIndexPatternColumn,
},
});
};

View file

@ -16,6 +16,7 @@ import { IndexPattern, IndexPatternLayer } from '../../types';
import { StaticValueIndexPatternColumn } from './static_value';
import { EuiFieldNumber } from '@elastic/eui';
import { act } from 'react-dom/test-utils';
import { TermsIndexPatternColumn } from './terms';
jest.mock('lodash', () => {
const original = jest.requireActual('lodash');
@ -65,7 +66,7 @@ describe('static_value', () => {
orderDirection: 'asc',
},
sourceField: 'category',
},
} as TermsIndexPatternColumn,
col2: {
label: 'Static value: 23',
dataType: 'number',
@ -75,7 +76,7 @@ describe('static_value', () => {
params: {
value: '23',
},
},
} as StaticValueIndexPatternColumn,
},
};
});
@ -256,7 +257,7 @@ describe('static_value', () => {
scale: 'ratio',
params: { value: '23' },
references: [],
},
} as StaticValueIndexPatternColumn,
})
).toEqual({
label: 'Static value: 23',
@ -303,7 +304,7 @@ describe('static_value', () => {
scale: 'ratio',
params: { value: '23' },
references: [],
},
} as StaticValueIndexPatternColumn,
},
{ value: '53' }
)
@ -351,7 +352,7 @@ describe('static_value', () => {
params: {
value: '0',
},
},
} as StaticValueIndexPatternColumn,
},
} as IndexPatternLayer;
const instance = shallow(

View file

@ -8,7 +8,7 @@ import React, { useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiFieldNumber, EuiFormLabel, EuiSpacer } from '@elastic/eui';
import { OperationDefinition } from './index';
import { ReferenceBasedIndexPatternColumn } from './column_types';
import { ReferenceBasedIndexPatternColumn, GenericIndexPatternColumn } from './column_types';
import type { IndexPattern } from '../../types';
import { useDebouncedValue } from '../../../shared_components';
import { getFormatFromPreviousColumn, isValidNumber } from './helpers';
@ -46,6 +46,12 @@ export interface StaticValueIndexPatternColumn extends ReferenceBasedIndexPatter
};
}
function isStaticValueColumnLike(
col: GenericIndexPatternColumn
): col is StaticValueIndexPatternColumn {
return Boolean('params' in col && col.params && 'value' in col.params);
}
export const staticValueOperation: OperationDefinition<
StaticValueIndexPatternColumn,
'managedReference'
@ -102,8 +108,8 @@ export const staticValueOperation: OperationDefinition<
},
buildColumn({ previousColumn, layer, indexPattern }, columnParams, operationDefinitionMap) {
const existingStaticValue =
previousColumn?.params &&
'value' in previousColumn.params &&
previousColumn &&
isStaticValueColumnLike(previousColumn) &&
isValidNumber(previousColumn.params.value)
? previousColumn.params.value
: undefined;

View file

@ -20,9 +20,10 @@ import { dataPluginMock } from '../../../../../../../../src/plugins/data/public/
import { createMockedIndexPattern } from '../../../mocks';
import { ValuesInput } from './values_input';
import type { TermsIndexPatternColumn } from '.';
import { termsOperation } from '../index';
import { termsOperation, LastValueIndexPatternColumn } from '../index';
import { IndexPattern, IndexPatternLayer } from '../../../types';
import { FrameDatasourceAPI } from '../../../../types';
import { DateHistogramIndexPatternColumn } from '../date_histogram';
const uiSettingsMock = {} as IUiSettingsClient;
@ -61,7 +62,7 @@ describe('terms', () => {
orderDirection: 'asc',
},
sourceField: 'source',
},
} as TermsIndexPatternColumn,
col2: {
label: 'Count',
dataType: 'number',
@ -357,7 +358,7 @@ describe('terms', () => {
params: {
sortField: 'datefield',
},
},
} as LastValueIndexPatternColumn,
},
columnOrder: [],
indexPatternId: '',
@ -472,7 +473,7 @@ describe('terms', () => {
params: {
sortField: 'time',
},
},
} as LastValueIndexPatternColumn,
},
columnOrder: [],
indexPatternId: '',
@ -551,7 +552,7 @@ describe('terms', () => {
orderDirection: 'asc',
},
sourceField: 'category',
},
} as TermsIndexPatternColumn,
},
columnOrder: [],
indexPatternId: '',
@ -583,7 +584,7 @@ describe('terms', () => {
orderDirection: 'asc',
},
sourceField: 'category',
},
} as TermsIndexPatternColumn,
col1: {
label: 'Value of timestamp',
dataType: 'date',
@ -595,7 +596,7 @@ describe('terms', () => {
interval: 'w',
},
sourceField: 'timestamp',
},
} as DateHistogramIndexPatternColumn,
},
columnOrder: [],
indexPatternId: '',
@ -627,7 +628,7 @@ describe('terms', () => {
orderDirection: 'desc',
},
sourceField: 'category',
},
} as TermsIndexPatternColumn,
},
columnOrder: [],
indexPatternId: '',
@ -755,7 +756,7 @@ describe('terms', () => {
{
...layer.columns.col1,
params: {
...layer.columns.col1.params,
...(layer.columns.col1 as TermsIndexPatternColumn).params,
otherBucket: true,
},
} as TermsIndexPatternColumn
@ -783,7 +784,7 @@ describe('terms', () => {
...layer.columns.col1,
sourceField: 'bytes',
params: {
...layer.columns.col1.params,
...(layer.columns.col1 as TermsIndexPatternColumn).params,
otherBucket: true,
},
} as TermsIndexPatternColumn
@ -1018,7 +1019,7 @@ describe('terms', () => {
},
scale: 'ordinal',
sourceField: 'bytes',
},
} as TermsIndexPatternColumn,
},
columnOrder: [],
indexPatternId: '',

View file

@ -10,7 +10,9 @@ export * from './layer_helpers';
export * from './time_scale_utils';
export type {
OperationType,
IndexPatternColumn,
BaseIndexPatternColumn,
GenericOperationDefinition,
GenericIndexPatternColumn,
FieldBasedIndexPatternColumn,
IncompleteColumn,
RequiredReference,

View file

@ -21,13 +21,21 @@ import { operationDefinitionMap, OperationType } from '../operations';
import { TermsIndexPatternColumn } from './definitions/terms';
import { DateHistogramIndexPatternColumn } from './definitions/date_histogram';
import { AvgIndexPatternColumn } from './definitions/metrics';
import type { IndexPattern, IndexPatternLayer } from '../types';
import type { IndexPattern, IndexPatternLayer, IndexPatternPrivateState } from '../types';
import { documentField } from '../document_field';
import { getFieldByNameFactory } from '../pure_helpers';
import { generateId } from '../../id_generator';
import { createMockedFullReference, createMockedManagedReference } from './mocks';
import { IndexPatternColumn, OperationDefinition } from './definitions';
import {
FiltersIndexPatternColumn,
FormulaIndexPatternColumn,
GenericIndexPatternColumn,
MathIndexPatternColumn,
MovingAverageIndexPatternColumn,
OperationDefinition,
} from './definitions';
import { TinymathAST } from 'packages/kbn-tinymath';
import { CoreStart } from 'kibana/public';
jest.mock('../operations');
jest.mock('../../id_generator');
@ -292,7 +300,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
};
expect(
@ -323,7 +331,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
col3: {
label: 'Reference',
dataType: 'number',
@ -362,7 +370,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
col3: {
label: 'Count of records',
dataType: 'document',
@ -458,7 +466,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
},
columnId: 'col2',
@ -488,7 +496,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
},
columnId: 'col2',
@ -520,7 +528,7 @@ describe('state_helpers', () => {
orderDirection: 'asc',
size: 5,
},
},
} as TermsIndexPatternColumn,
},
},
columnId: 'col2',
@ -598,7 +606,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
},
columnId: 'col2',
@ -680,8 +688,8 @@ describe('state_helpers', () => {
layer,
indexPattern,
columnId: 'col1',
// @ts-expect-error invalid type
op: 'testReference',
visualizationGroups: [],
});
expect(result.columnOrder).toEqual(['id1', 'col1']);
expect(result.columns).toEqual(
@ -700,8 +708,8 @@ describe('state_helpers', () => {
col1: {
dataType: 'number',
isBucketed: false,
label: '',
// @ts-expect-error only in test
operationType: 'testReference',
references: ['ref1'],
},
@ -745,7 +753,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
},
columnId: 'col2',
@ -848,7 +856,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
},
columnId: 'col1',
@ -878,7 +886,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
},
columnId: 'col1',
@ -914,7 +922,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
},
columnId: 'col1',
@ -948,7 +956,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
incompleteColumns: {
col1: { operationType: 'terms' },
@ -986,7 +994,7 @@ describe('state_helpers', () => {
params: {
filters: [],
},
},
} as FiltersIndexPatternColumn,
},
},
indexPattern,
@ -1022,7 +1030,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
},
indexPattern,
@ -1058,7 +1066,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
},
indexPattern,
@ -1093,7 +1101,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
},
indexPattern,
@ -1128,7 +1136,7 @@ describe('state_helpers', () => {
orderDirection: 'asc',
size: 5,
},
},
} as TermsIndexPatternColumn,
},
},
indexPattern,
@ -1160,7 +1168,7 @@ describe('state_helpers', () => {
orderDirection: 'asc',
size: 5,
},
},
} as TermsIndexPatternColumn,
},
},
indexPattern,
@ -1215,7 +1223,7 @@ describe('state_helpers', () => {
scale: 'ratio',
params: { isFormulaBroken: false, formula: 'average(bytes)' },
references: [],
},
} as FormulaIndexPatternColumn,
},
},
indexPattern,
@ -1244,7 +1252,7 @@ describe('state_helpers', () => {
scale: 'ratio',
params: { isFormulaBroken: false, formula: 'average(bytes)' },
references: [],
},
} as FormulaIndexPatternColumn,
},
},
indexPattern,
@ -1490,8 +1498,8 @@ describe('state_helpers', () => {
layer,
indexPattern,
columnId: 'col1',
// @ts-expect-error
op: 'testReference',
visualizationGroups: [],
});
expect(result.columnOrder).toEqual(['id1', 'col1']);
@ -1531,8 +1539,8 @@ describe('state_helpers', () => {
layer,
indexPattern,
columnId: 'col1',
// @ts-expect-error test only
op: 'testReference',
visualizationGroups: [],
});
expect(result.columnOrder).toEqual(['col1', 'id1']);
@ -1572,8 +1580,8 @@ describe('state_helpers', () => {
layer,
indexPattern,
columnId: 'col1',
// @ts-expect-error
op: 'testReference',
visualizationGroups: [],
});
expect(result.incompleteColumns).toEqual({
@ -1612,8 +1620,8 @@ describe('state_helpers', () => {
layer,
indexPattern,
columnId: 'col1',
// @ts-expect-error
op: 'testReference',
visualizationGroups: [],
});
expect(result.incompleteColumns).toEqual({});
@ -1631,8 +1639,8 @@ describe('state_helpers', () => {
operationDefinitionMap.secondTest = {
input: 'fullReference',
displayName: 'Reference test 2',
// @ts-expect-error this type is not statically available
type: 'secondTest',
selectionStyle: 'full',
requiredReferences: [
{
// Any numeric metric that isn't also a reference
@ -1641,7 +1649,6 @@ describe('state_helpers', () => {
meta.dataType === 'number' && !meta.isBucketed,
},
],
// @ts-expect-error don't want to define valid arguments
buildColumn: jest.fn((args) => {
return {
label: 'Test reference',
@ -1684,7 +1691,6 @@ describe('state_helpers', () => {
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: [],
},
@ -1693,7 +1699,6 @@ describe('state_helpers', () => {
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: ['ref1', 'invalid'],
},
@ -1704,8 +1709,8 @@ describe('state_helpers', () => {
layer,
indexPattern,
columnId: 'output',
// @ts-expect-error not statically available
op: 'secondTest',
visualizationGroups: [],
})
).toEqual(
expect.objectContaining({
@ -1738,7 +1743,6 @@ describe('state_helpers', () => {
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: [],
},
@ -1747,7 +1751,6 @@ describe('state_helpers', () => {
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: ['ref1', 'invalid'],
},
@ -1757,8 +1760,8 @@ describe('state_helpers', () => {
layer,
indexPattern,
columnId: 'output',
// @ts-expect-error not statically available
op: 'secondTest',
visualizationGroups: [],
});
expect(layer.columns.output).toEqual(
expect.objectContaining({ references: ['ref1', 'invalid'] })
@ -1787,7 +1790,7 @@ describe('state_helpers', () => {
isFormulaBroken: false,
},
references: ['formulaX3'],
},
} as FormulaIndexPatternColumn,
formulaX0: {
customLabel: true,
dataType: 'number' as const,
@ -1802,7 +1805,7 @@ describe('state_helpers', () => {
label: 'formulaX1',
references: ['formulaX0'],
params: { tinymathAst: 'formulaX0' },
},
} as MathIndexPatternColumn,
formulaX2: {
customLabel: true,
dataType: 'number' as const,
@ -1811,13 +1814,13 @@ describe('state_helpers', () => {
operationType: 'moving_average' as const,
params: { window: 5 },
references: ['formulaX1'],
},
} as MovingAverageIndexPatternColumn,
formulaX3: {
...math,
label: 'formulaX3',
references: ['formulaX2'],
params: { tinymathAst: 'formulaX2' },
},
} as MathIndexPatternColumn,
},
};
@ -1826,8 +1829,8 @@ describe('state_helpers', () => {
layer,
indexPattern,
columnId: 'source',
// @ts-expect-error not statically available
op: 'secondTest',
visualizationGroups: [],
})
).toEqual(
expect.objectContaining({
@ -1854,12 +1857,11 @@ describe('state_helpers', () => {
operationType: 'date_histogram' as const,
sourceField: 'timestamp',
params: { interval: 'auto' },
},
} as DateHistogramIndexPatternColumn,
output: {
label: 'Test reference',
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: ['fieldReused'],
},
@ -1870,8 +1872,8 @@ describe('state_helpers', () => {
layer,
indexPattern,
columnId: 'output',
// @ts-expect-error not statically available
op: 'secondTest',
visualizationGroups: [],
})
).toEqual(
expect.objectContaining({
@ -1922,7 +1924,6 @@ describe('state_helpers', () => {
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: ['col1'],
},
@ -1967,7 +1968,6 @@ describe('state_helpers', () => {
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: ['col1'],
filter: { language: 'kuery', query: 'bytes > 4000' },
@ -2113,7 +2113,6 @@ describe('state_helpers', () => {
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: ['col1'],
},
@ -2281,7 +2280,6 @@ describe('state_helpers', () => {
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: ['col1'],
},
@ -2310,7 +2308,6 @@ describe('state_helpers', () => {
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: ['col1'],
},
@ -2356,7 +2353,6 @@ describe('state_helpers', () => {
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: ['col1'],
},
@ -2365,7 +2361,6 @@ describe('state_helpers', () => {
dataType: 'number',
isBucketed: false,
// @ts-expect-error not a valid type
operationType: 'testReference',
references: ['col2'],
},
@ -2469,7 +2464,7 @@ describe('state_helpers', () => {
params: {
interval: 'h',
},
},
} as DateHistogramIndexPatternColumn,
},
})
).toEqual(['col1']);
@ -2496,7 +2491,7 @@ describe('state_helpers', () => {
},
orderDirection: 'asc',
},
},
} as TermsIndexPatternColumn,
col2: {
label: 'Average of bytes',
dataType: 'number',
@ -2517,7 +2512,7 @@ describe('state_helpers', () => {
params: {
interval: '1d',
},
},
} as DateHistogramIndexPatternColumn,
},
})
).toEqual(['col1', 'col3', 'col2']);
@ -2548,7 +2543,7 @@ describe('state_helpers', () => {
params: {
interval: 'auto',
},
},
} as DateHistogramIndexPatternColumn,
formula: {
label: 'Formula',
dataType: 'number',
@ -2560,7 +2555,7 @@ describe('state_helpers', () => {
isFormulaBroken: false,
},
references: ['math'],
},
} as FormulaIndexPatternColumn,
countX0: {
label: 'countX0',
dataType: 'number',
@ -2580,8 +2575,7 @@ describe('state_helpers', () => {
tinymathAst: {
type: 'function',
name: 'add',
// @ts-expect-error String args are not valid tinymath, but signals something unique to Lens
args: ['countX0', 'count'],
args: ['countX0', 'count'] as unknown as TinymathAST[],
location: {
min: 0,
max: 17,
@ -2591,7 +2585,7 @@ describe('state_helpers', () => {
},
references: ['countX0', 'count'],
customLabel: true,
},
} as MathIndexPatternColumn,
},
})
).toEqual(['date', 'count', 'formula', 'countX0', 'math']);
@ -2679,7 +2673,7 @@ describe('state_helpers', () => {
orderDirection: 'asc',
size: 3,
},
},
} as TermsIndexPatternColumn,
col2: {
dataType: 'number',
isBucketed: false,
@ -2713,7 +2707,7 @@ describe('state_helpers', () => {
params: {
window: 7,
},
},
} as MovingAverageIndexPatternColumn,
col2: {
dataType: 'number',
isBucketed: false,
@ -2742,7 +2736,7 @@ describe('state_helpers', () => {
params: {
interval: 'd',
},
},
} as DateHistogramIndexPatternColumn,
col2: {
dataType: 'number',
isBucketed: false,
@ -2765,10 +2759,10 @@ describe('state_helpers', () => {
operationDefinitionMap.date_histogram.transfer = ((oldColumn) => ({
...oldColumn,
params: {
...oldColumn.params,
...(oldColumn as DateHistogramIndexPatternColumn).params,
interval: 'w',
},
})) as OperationDefinition<IndexPatternColumn, 'field'>['transfer'];
})) as OperationDefinition<GenericIndexPatternColumn, 'field'>['transfer'];
const layer: IndexPatternLayer = {
columnOrder: ['col1', 'col2'],
columns: {
@ -2781,7 +2775,7 @@ describe('state_helpers', () => {
params: {
interval: 'd',
},
},
} as DateHistogramIndexPatternColumn,
},
indexPatternId: 'original',
};
@ -2813,7 +2807,7 @@ describe('state_helpers', () => {
orderDirection: 'asc',
size: 3,
},
},
} as TermsIndexPatternColumn,
col2: {
dataType: 'number',
isBucketed: false,
@ -2846,7 +2840,7 @@ describe('state_helpers', () => {
orderDirection: 'asc',
size: 3,
},
},
} as TermsIndexPatternColumn,
col2: {
dataType: 'number',
isBucketed: false,
@ -2895,15 +2889,19 @@ describe('state_helpers', () => {
indexPatternId: '1',
columnOrder: [],
columns: {
col1:
// @ts-expect-error not statically analyzed
{ operationType: 'testReference', references: [] },
col1: {
operationType: 'testReference',
references: [],
label: '',
dataType: 'number',
isBucketed: false,
},
},
},
indexPattern,
{},
{} as IndexPatternPrivateState,
'1',
{}
{} as CoreStart
);
expect(mock).toHaveBeenCalled();
expect(errors).toHaveLength(1);
@ -2919,20 +2917,26 @@ describe('state_helpers', () => {
indexPatternId: '1',
columnOrder: [],
columns: {
col1:
// @ts-expect-error not statically analyzed
{ operationType: 'managedReference', references: ['col2'] },
col1: {
operationType: 'managedReference',
references: ['col2'],
label: '',
dataType: 'number',
isBucketed: false,
},
col2: {
// @ts-expect-error not statically analyzed
operationType: 'testReference',
references: [],
label: '',
dataType: 'number',
isBucketed: false,
},
},
},
indexPattern,
{},
{} as IndexPatternPrivateState,
'1',
{}
{} as CoreStart
);
expect(notCalledMock).not.toHaveBeenCalled();
expect(mock).toHaveBeenCalledTimes(1);
@ -2953,19 +2957,22 @@ describe('state_helpers', () => {
indexPatternId: '1',
columnOrder: [],
columns: {
col1:
// @ts-expect-error not statically analyzed
{ operationType: 'testReference', references: [] },
col1: {
operationType: 'testReference',
references: [],
label: '',
dataType: 'number',
isBucketed: false,
},
},
incompleteColumns: {
// @ts-expect-error not statically analyzed
col1: { operationType: 'testIncompleteReference' },
},
},
indexPattern,
{},
{} as IndexPatternPrivateState,
'1',
{}
{} as CoreStart
);
expect(savedRef).toHaveBeenCalled();
expect(incompleteRef).not.toHaveBeenCalled();
@ -2982,22 +2989,32 @@ describe('state_helpers', () => {
indexPatternId: '1',
columnOrder: [],
columns: {
col1:
// @ts-expect-error not statically analyzed
{ operationType: 'testReference', references: [] },
col1: {
operationType: 'testReference',
references: [],
label: '',
dataType: 'number',
isBucketed: false,
},
},
},
indexPattern,
{},
{} as IndexPatternPrivateState,
'1',
{}
{} as CoreStart
);
expect(mock).toHaveBeenCalledWith(
{
indexPatternId: '1',
columnOrder: [],
columns: {
col1: { operationType: 'testReference', references: [] },
col1: {
operationType: 'testReference',
references: [],
dataType: 'number',
isBucketed: false,
label: '',
},
},
},
'col1',
@ -3021,7 +3038,7 @@ describe('state_helpers', () => {
params: {
interval: 'd',
},
},
} as DateHistogramIndexPatternColumn,
},
indexPatternId: 'original',
};
@ -3047,7 +3064,7 @@ describe('state_helpers', () => {
orderBy: { type: 'alphabetical' },
orderDirection: 'asc',
},
},
} as TermsIndexPatternColumn,
},
indexPatternId: 'original',
};
@ -3073,7 +3090,7 @@ describe('state_helpers', () => {
orderBy: { type: 'alphabetical' },
orderDirection: 'asc',
},
},
} as TermsIndexPatternColumn,
},
indexPatternId: 'original',
};

View file

@ -18,10 +18,10 @@ import {
operationDefinitionMap,
operationDefinitions,
OperationType,
IndexPatternColumn,
RequiredReference,
OperationDefinition,
GenericOperationDefinition,
TermsIndexPatternColumn,
} from './definitions';
import type {
IndexPattern,
@ -31,9 +31,14 @@ import type {
} from '../types';
import { getSortScoreByPriority } from './operations';
import { generateId } from '../../id_generator';
import { ReferenceBasedIndexPatternColumn } from './definitions/column_types';
import {
GenericIndexPatternColumn,
ReferenceBasedIndexPatternColumn,
BaseIndexPatternColumn,
} from './definitions/column_types';
import { FormulaIndexPatternColumn, regenerateLayerFromAst } from './definitions/formula';
import type { TimeScaleUnit } from '../../../common/expressions';
import { isColumnOfType } from './definitions/helpers';
interface ColumnAdvancedParams {
filter?: Query | undefined;
@ -57,7 +62,7 @@ interface ColumnChange {
interface ColumnCopy {
layer: IndexPatternLayer;
targetId: string;
sourceColumn: IndexPatternColumn;
sourceColumn: GenericIndexPatternColumn;
sourceColumnId: string;
indexPattern: IndexPattern;
shouldDeleteSource?: boolean;
@ -92,7 +97,7 @@ export function copyColumn({
function copyReferencesRecursively(
layer: IndexPatternLayer,
sourceColumn: IndexPatternColumn,
sourceColumn: GenericIndexPatternColumn,
sourceId: string,
targetId: string,
indexPattern: IndexPattern
@ -511,7 +516,7 @@ export function replaceColumn({
if (operationDefinition.input === 'managedReference') {
const newColumn = operationDefinition.buildColumn(
{ ...baseOptions, layer: tempLayer },
previousColumn.params,
'params' in previousColumn ? previousColumn.params : undefined,
operationDefinitionMap
) as FormulaIndexPatternColumn;
@ -665,11 +670,11 @@ export function replaceColumn({
function removeOrphanedColumns(
previousDefinition:
| OperationDefinition<IndexPatternColumn, 'field'>
| OperationDefinition<IndexPatternColumn, 'none'>
| OperationDefinition<IndexPatternColumn, 'fullReference'>
| OperationDefinition<IndexPatternColumn, 'managedReference'>,
previousColumn: IndexPatternColumn,
| OperationDefinition<GenericIndexPatternColumn, 'field'>
| OperationDefinition<GenericIndexPatternColumn, 'none'>
| OperationDefinition<GenericIndexPatternColumn, 'fullReference'>
| OperationDefinition<GenericIndexPatternColumn, 'managedReference'>,
previousColumn: GenericIndexPatternColumn,
tempLayer: IndexPatternLayer,
indexPattern: IndexPattern
) {
@ -765,7 +770,7 @@ function applyReferenceTransition({
}: {
layer: IndexPatternLayer;
columnId: string;
previousColumn: IndexPatternColumn;
previousColumn: GenericIndexPatternColumn;
op: OperationType;
indexPattern: IndexPattern;
visualizationGroups: VisualizationDimensionGroupConfig[];
@ -962,7 +967,10 @@ function applyReferenceTransition({
);
}
function copyCustomLabel(newColumn: IndexPatternColumn, previousOptions: IndexPatternColumn) {
function copyCustomLabel(
newColumn: GenericIndexPatternColumn,
previousOptions: GenericIndexPatternColumn
) {
const adjustedColumn = { ...newColumn };
const operationChanged = newColumn.operationType !== previousOptions.operationType;
const fieldChanged =
@ -978,7 +986,7 @@ function copyCustomLabel(newColumn: IndexPatternColumn, previousOptions: IndexPa
function addBucket(
layer: IndexPatternLayer,
column: IndexPatternColumn,
column: BaseIndexPatternColumn,
addedColumnId: string,
visualizationGroups: VisualizationDimensionGroupConfig[],
targetGroup?: string
@ -1071,7 +1079,7 @@ export function reorderByGroups(
function addMetric(
layer: IndexPatternLayer,
column: IndexPatternColumn,
column: BaseIndexPatternColumn,
addedColumnId: string
): IndexPatternLayer {
const tempLayer = {
@ -1096,7 +1104,7 @@ export function getMetricOperationTypes(field: IndexPatternField) {
});
}
export function updateColumnParam<C extends IndexPatternColumn>({
export function updateColumnParam<C extends GenericIndexPatternColumn>({
layer,
columnId,
paramName,
@ -1107,18 +1115,19 @@ export function updateColumnParam<C extends IndexPatternColumn>({
paramName: string;
value: unknown;
}): IndexPatternLayer {
const oldColumn = layer.columns[columnId];
return {
...layer,
columns: {
...layer.columns,
[columnId]: {
...layer.columns[columnId],
...oldColumn,
params: {
...layer.columns[columnId].params,
...('params' in oldColumn ? oldColumn.params : {}),
[paramName]: value,
},
},
} as Record<string, IndexPatternColumn>,
} as Record<string, GenericIndexPatternColumn>,
};
}
@ -1228,7 +1237,7 @@ export function getExistingColumnGroups(layer: IndexPatternLayer): [string[], st
* Returns true if the given column can be applied to the given index pattern
*/
export function isColumnTransferable(
column: IndexPatternColumn,
column: GenericIndexPatternColumn,
newIndexPattern: IndexPattern,
layer: IndexPatternLayer
): boolean {
@ -1373,9 +1382,7 @@ export function hasTermsWithManyBuckets(layer: IndexPatternLayer): boolean {
return layer.columnOrder.some((columnId) => {
const column = layer.columns[columnId];
if (column) {
return (
column.isBucketed && column.params && 'size' in column.params && column.params.size > 5
);
return isColumnOfType<TermsIndexPatternColumn>('terms', column) && column.params.size > 5;
}
});
}
@ -1447,7 +1454,7 @@ function maybeValidateOperations({
column,
validation,
}: {
column: IndexPatternColumn;
column: GenericIndexPatternColumn;
validation: RequiredReference;
}) {
if (!validation.specificOperations) {
@ -1463,7 +1470,7 @@ export function isColumnValidAsReference({
column,
validation,
}: {
column: IndexPatternColumn;
column: GenericIndexPatternColumn;
validation: RequiredReference;
}): boolean {
if (!column) return false;
@ -1481,14 +1488,14 @@ export function isColumnValidAsReference({
export function getManagedColumnsFrom(
columnId: string,
columns: Record<string, IndexPatternColumn>
): Array<[string, IndexPatternColumn]> {
columns: Record<string, GenericIndexPatternColumn>
): Array<[string, GenericIndexPatternColumn]> {
const allNodes: Record<string, string[]> = {};
Object.entries(columns).forEach(([id, col]) => {
allNodes[id] = 'references' in col ? [...col.references] : [];
});
const queue: string[] = allNodes[columnId];
const store: Array<[string, IndexPatternColumn]> = [];
const store: Array<[string, GenericIndexPatternColumn]> = [];
while (queue.length > 0) {
const nextId = queue.shift()!;

View file

@ -7,7 +7,7 @@
import type { IndexPatternLayer } from '../types';
import type { TimeScaleUnit } from '../../../common/expressions';
import type { IndexPatternColumn } from './definitions';
import type { DateHistogramIndexPatternColumn, GenericIndexPatternColumn } from './definitions';
import { adjustTimeScaleLabelSuffix, adjustTimeScaleOnOtherColumnChange } from './time_scale_utils';
export const DEFAULT_TIME_SCALE = 's' as TimeScaleUnit;
@ -97,7 +97,7 @@ describe('time scale utils', () => {
});
describe('adjustTimeScaleOnOtherColumnChange', () => {
const baseColumn: IndexPatternColumn = {
const baseColumn: GenericIndexPatternColumn = {
operationType: 'count',
sourceField: 'Records',
label: 'Count of records per second',
@ -135,7 +135,7 @@ describe('time scale utils', () => {
label: '',
sourceField: 'date',
params: { interval: 'auto' },
},
} as DateHistogramIndexPatternColumn,
},
},
'col1',

View file

@ -8,7 +8,7 @@
import { unitSuffixesLong } from '../../../common/suffix_formatter';
import type { TimeScaleUnit } from '../../../common/expressions';
import type { IndexPatternLayer } from '../types';
import type { IndexPatternColumn } from './definitions';
import type { GenericIndexPatternColumn } from './definitions';
export const DEFAULT_TIME_SCALE = 's' as TimeScaleUnit;
@ -44,7 +44,7 @@ export function adjustTimeScaleLabelSuffix(
return `${cleanedLabel}${getSuffix(newTimeScale, newShift)}`;
}
export function adjustTimeScaleOnOtherColumnChange<T extends IndexPatternColumn>(
export function adjustTimeScaleOnOtherColumnChange<T extends GenericIndexPatternColumn>(
layer: IndexPatternLayer,
thisColumnId: string,
changedColumnId: string

View file

@ -11,7 +11,7 @@ import { uniq } from 'lodash';
import { FormattedMessage } from '@kbn/i18n/react';
import {
IndexPattern,
IndexPatternColumn,
GenericIndexPatternColumn,
IndexPatternLayer,
IndexPatternPrivateState,
} from './types';
@ -229,7 +229,7 @@ export function getStateTimeShiftWarningMessages(
export function getColumnTimeShiftWarnings(
dateHistogramInterval: ReturnType<typeof getDateHistogramInterval>,
column: IndexPatternColumn
column: GenericIndexPatternColumn
) {
const { isValueTooSmall, isValueNotMultiple } = getLayerTimeShiftChecks(dateHistogramInterval);

View file

@ -20,12 +20,14 @@ import {
ExpressionAstExpressionBuilder,
ExpressionAstFunction,
} from '../../../../../src/plugins/expressions/public';
import { IndexPatternColumn } from './indexpattern';
import { GenericIndexPatternColumn } from './indexpattern';
import { operationDefinitionMap } from './operations';
import { IndexPattern, IndexPatternPrivateState, IndexPatternLayer } from './types';
import { dateHistogramOperation } from './operations/definitions';
import { DateHistogramIndexPatternColumn, RangeIndexPatternColumn } from './operations/definitions';
import { FormattedIndexPatternColumn } from './operations/definitions/column_types';
import { isColumnFormatted, isColumnOfType } from './operations/definitions/helpers';
type OriginalColumn = { id: string } & IndexPatternColumn;
type OriginalColumn = { id: string } & GenericIndexPatternColumn;
function getExpressionForLayer(
layer: IndexPatternLayer,
@ -147,50 +149,29 @@ function getExpressionForLayer(
},
};
}, {} as Record<string, OriginalColumn>);
type FormattedColumn = Required<
Extract<
IndexPatternColumn,
| {
params?: {
format: unknown;
};
}
// when formatters are nested there's a slightly different format
| {
params: {
format?: unknown;
parentFormat?: unknown;
};
}
>
>;
const columnsWithFormatters = columnEntries.filter(
([, col]) =>
col.params &&
(('format' in col.params && col.params.format) ||
('parentFormat' in col.params && col.params.parentFormat))
) as Array<[string, FormattedColumn]>;
const formatterOverrides: ExpressionAstFunction[] = columnsWithFormatters.map(
([id, col]: [string, FormattedColumn]) => {
// TODO: improve the type handling here
const parentFormat = 'parentFormat' in col.params ? col.params!.parentFormat! : undefined;
const format = (col as FormattedColumn).params!.format;
(isColumnOfType<RangeIndexPatternColumn>('range', col) && col.params?.parentFormat) ||
(isColumnFormatted(col) && col.params?.format)
) as Array<[string, RangeIndexPatternColumn | FormattedIndexPatternColumn]>;
const formatterOverrides: ExpressionAstFunction[] = columnsWithFormatters.map(([id, col]) => {
// TODO: improve the type handling here
const parentFormat = 'parentFormat' in col.params! ? col.params!.parentFormat! : undefined;
const format = col.params!.format;
const base: ExpressionAstFunction = {
type: 'function',
function: 'lens_format_column',
arguments: {
format: format ? [format.id] : [''],
columnId: [id],
decimals: typeof format?.params?.decimals === 'number' ? [format.params.decimals] : [],
parentFormat: parentFormat ? [JSON.stringify(parentFormat)] : [],
},
};
const base: ExpressionAstFunction = {
type: 'function',
function: 'lens_format_column',
arguments: {
format: format ? [format.id] : [''],
columnId: [id],
decimals: typeof format?.params?.decimals === 'number' ? [format.params.decimals] : [],
parentFormat: parentFormat ? [JSON.stringify(parentFormat)] : [],
},
};
return base;
}
);
return base;
});
const firstDateHistogramColumn = columnEntries.find(
([, col]) => col.operationType === 'date_histogram'
@ -254,7 +235,9 @@ function getExpressionForLayer(
const allDateHistogramFields = Object.values(columns)
.map((column) =>
column.operationType === dateHistogramOperation.type ? column.sourceField : null
isColumnOfType<DateHistogramIndexPatternColumn>('date_histogram', column)
? column.sourceField
: null
)
.filter((field): field is string => Boolean(field));
@ -291,7 +274,7 @@ function getExpressionForLayer(
}
// Topologically sorts references so that we can execute them in sequence
function sortedReferences(columns: Array<readonly [string, IndexPatternColumn]>) {
function sortedReferences(columns: Array<readonly [string, GenericIndexPatternColumn]>) {
const allNodes: Record<string, string[]> = {};
columns.forEach(([id, col]) => {
allNodes[id] = 'references' in col ? col.references : [];

View file

@ -5,17 +5,17 @@
* 2.0.
*/
import type { IndexPatternColumn, IncompleteColumn } from './operations';
import type { IncompleteColumn, GenericIndexPatternColumn } from './operations';
import type { IndexPatternAggRestrictions } from '../../../../../src/plugins/data/public';
import type { FieldSpec } from '../../../../../src/plugins/data/common';
import type { DragDropIdentifier } from '../drag_drop/providers';
import type { FieldFormatParams } from '../../../../../src/plugins/field_formats/common';
export type {
FieldBasedIndexPatternColumn,
IndexPatternColumn,
GenericIndexPatternColumn,
OperationType,
IncompleteColumn,
FieldBasedIndexPatternColumn,
FiltersIndexPatternColumn,
RangeIndexPatternColumn,
TermsIndexPatternColumn,
@ -67,7 +67,7 @@ export type IndexPatternField = FieldSpec & {
export interface IndexPatternLayer {
columnOrder: string[];
columns: Record<string, IndexPatternColumn>;
columns: Record<string, GenericIndexPatternColumn>;
// Each layer is tied to the index pattern that created it
indexPatternId: string;
// Partial columns represent the temporary invalid states

View file

@ -24,7 +24,7 @@ import type {
ReferenceBasedIndexPatternColumn,
} from './operations/definitions/column_types';
import { operationDefinitionMap, IndexPatternColumn } from './operations';
import { operationDefinitionMap, GenericIndexPatternColumn } from './operations';
import { getInvalidFieldMessage } from './operations/definitions/helpers';
import { isQueryValid } from './operations/definitions/filters';
@ -65,7 +65,7 @@ export function isColumnInvalid(
columnId: string,
indexPattern: IndexPattern
) {
const column: IndexPatternColumn | undefined = layer.columns[columnId];
const column: GenericIndexPatternColumn | undefined = layer.columns[columnId];
if (!column || !indexPattern) return;
const operationDefinition = column.operationType && operationDefinitionMap[column.operationType];
@ -75,12 +75,9 @@ export function isColumnInvalid(
'references' in column &&
Boolean(getReferencesErrors(layer, column, indexPattern).filter(Boolean).length);
const operationErrorMessages = operationDefinition.getErrorMessage?.(
layer,
columnId,
indexPattern,
operationDefinitionMap
);
const operationErrorMessages =
operationDefinition &&
operationDefinition.getErrorMessage?.(layer, columnId, indexPattern, operationDefinitionMap);
const filterHasError = column.filter ? !isQueryValid(column.filter, indexPattern) : false;
@ -108,7 +105,10 @@ function getReferencesErrors(
});
}
export function fieldIsInvalid(column: IndexPatternColumn | undefined, indexPattern: IndexPattern) {
export function fieldIsInvalid(
column: GenericIndexPatternColumn | undefined,
indexPattern: IndexPattern
) {
if (!column || !hasField(column)) {
return false;
}

View file

@ -28,6 +28,7 @@ import {
TypedLensByValueInput,
PersistedIndexPatternLayer,
PieVisualizationState,
TermsIndexPatternColumn,
} from '../../../lens/public';
import { FilterStateStore, DataView } from '../../../../../src/plugins/data/common';
import { useKibana } from '../common/lib/kibana';
@ -88,7 +89,7 @@ function getLensAttributes(
},
orderDirection: 'desc',
},
},
} as TermsIndexPatternColumn,
'ed999e9d-204c-465b-897f-fe1a125b39ed': {
sourceField: 'Records',
isBucketed: false,