diff --git a/x-pack/plugins/lens/public/async_services.ts b/x-pack/plugins/lens/public/async_services.ts index 365e83eedf513..7bbfaf415db03 100644 --- a/x-pack/plugins/lens/public/async_services.ts +++ b/x-pack/plugins/lens/public/async_services.ts @@ -34,13 +34,11 @@ export { getEditLensConfiguration } from './app_plugin/shared/edit_on_the_fly/ge export * from './datasources/form_based/form_based'; export { getTextBasedDatasource } from './datasources/text_based/text_based_languages'; -export { getValueBasedDatasource } from './datasources/value_based/text_based_languages'; export { createFormulaPublicApi } from './datasources/form_based/operations/definitions/formula/formula_public_api'; export * from './lens_suggestions_api'; export * from './datasources/text_based'; export * from './datasources/form_based'; -export * from './datasources/value_based'; export * from './lens_ui_telemetry'; export * from './lens_ui_errors'; export * from './editor_frame_service/editor_frame'; diff --git a/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx b/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx index 43d971caf24a9..785d538e71698 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx +++ b/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx @@ -223,7 +223,9 @@ export function getTextBasedDatasource({ onRefreshIndexPattern() {}, getUsedDataViews: (state) => { - return Object.values(state.layers).map(({ index }) => index); + return Object.values(state.layers) + .map(({ index }) => index) + .filter((index) => index !== undefined) as string[]; }, getPersistableState({ layers }: TextBasedPrivateState) { @@ -310,16 +312,16 @@ export function getTextBasedDatasource({ return ( Boolean(layers) && Object.values(layers).some((layer) => { - return Boolean(indexPatterns[layer.index]?.timeFieldName); + return layer.index && Boolean(indexPatterns[layer.index]?.timeFieldName); }) ); }, getUsedDataView: (state: TextBasedPrivateState, layerId?: string) => { - if (!layerId) { + if (!layerId || !state.layers[layerId].index) { const layers = Object.values(state.layers); - return layers?.[0]?.index; + return layers?.[0]?.index as string; } - return state.layers[layerId].index; + return state.layers[layerId].index as string; }, removeColumn, @@ -613,9 +615,11 @@ export function getTextBasedDatasource({ getDatasourceInfo: async (state, references, dataViewsService) => { const indexPatterns: DataView[] = []; for (const { index } of Object.values(state.layers)) { - const dataView = await dataViewsService?.get(index); - if (dataView) { - indexPatterns.push(dataView); + if (index) { + const dataView = await dataViewsService?.get(index); + if (dataView) { + indexPatterns.push(dataView); + } } } return Object.entries(state.layers).reduce((acc, [key, layer]) => { diff --git a/x-pack/plugins/lens/public/datasources/text_based/to_expression.ts b/x-pack/plugins/lens/public/datasources/text_based/to_expression.ts index e0c6889a59c79..9d7be5d2fb431 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/to_expression.ts +++ b/x-pack/plugins/lens/public/datasources/text_based/to_expression.ts @@ -10,7 +10,11 @@ import { textBasedQueryStateToExpressionAst } from '@kbn/data-plugin/common'; import type { OriginalColumn } from '../../../common/types'; import { TextBasedPrivateState, TextBasedLayer, IndexPatternRef } from './types'; -function getExpressionForLayer(layer: TextBasedLayer, refs: IndexPatternRef[]): Ast | null { +function getExpressionForLayer( + layer: TextBasedLayer, + layerId: string, + refs: IndexPatternRef[] +): Ast | null { if (!layer.columns || layer.columns?.length === 0) { return null; } @@ -36,24 +40,46 @@ function getExpressionForLayer(layer: TextBasedLayer, refs: IndexPatternRef[]): }); const timeFieldName = layer.timeField ?? undefined; - const textBasedQueryToAst = textBasedQueryStateToExpressionAst({ - query: layer.query, - timeFieldName, - }); + if (!layer.table) { + const textBasedQueryToAst = textBasedQueryStateToExpressionAst({ + query: layer.query, + timeFieldName, + }); - textBasedQueryToAst.chain.push({ - type: 'function', - function: 'lens_map_to_columns', - arguments: { - idMap: [JSON.stringify(idMapper)], - }, - }); - return textBasedQueryToAst; + textBasedQueryToAst.chain.push({ + type: 'function', + function: 'lens_map_to_columns', + arguments: { + idMap: [JSON.stringify(idMapper)], + }, + }); + return textBasedQueryToAst; + } else { + return { + type: 'expression', + chain: [ + { + type: 'function', + function: 'var', + arguments: { + name: [layerId], + }, + }, + { + type: 'function', + function: 'lens_map_to_columns', + arguments: { + idMap: [JSON.stringify(idMapper)], + }, + }, + ], + }; + } } export function toExpression(state: TextBasedPrivateState, layerId: string) { if (state.layers[layerId]) { - return getExpressionForLayer(state.layers[layerId], state.indexPatternRefs); + return getExpressionForLayer(state.layers[layerId], layerId, state.indexPatternRefs); } return null; diff --git a/x-pack/plugins/lens/public/datasources/text_based/types.ts b/x-pack/plugins/lens/public/datasources/text_based/types.ts index 8da183f9b9054..9afd862605af0 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/types.ts +++ b/x-pack/plugins/lens/public/datasources/text_based/types.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { DatatableColumn } from '@kbn/expressions-plugin/public'; +import type { Datatable, DatatableColumn } from '@kbn/expressions-plugin/public'; import type { AggregateQuery } from '@kbn/es-query'; import type { VisualizeFieldContext } from '@kbn/ui-actions-plugin/public'; import type { VisualizeEditorContext } from '../../types'; @@ -21,8 +21,9 @@ export interface TextBasedField { } export interface TextBasedLayer { - index: string; - query: AggregateQuery | undefined; + index?: string; + query?: AggregateQuery | undefined; + table?: Datatable; columns: TextBasedLayerColumn[]; allColumns: TextBasedLayerColumn[]; timeField?: string; diff --git a/x-pack/plugins/lens/public/datasources/value_based/index.ts b/x-pack/plugins/lens/public/datasources/value_based/index.ts deleted file mode 100644 index 073f4788d3f1d..0000000000000 --- a/x-pack/plugins/lens/public/datasources/value_based/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { CoreSetup } from '@kbn/core/public'; -import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { ExpressionsStart } from '@kbn/expressions-plugin/public'; -import { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public'; -import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; -import { EditorFrameSetup } from '../../types'; - -interface TextBasedSetupPlugins { - data: DataPublicPluginSetup; - editorFrame: EditorFrameSetup; -} - -interface TextBasedStartPlugins { - data: DataPublicPluginStart; - dataViews: DataViewsPublicPluginStart; - expressions: ExpressionsStart; -} - -export class ValueBasedDatasource { - constructor() {} - - setup(core: CoreSetup, { editorFrame }: TextBasedSetupPlugins) { - editorFrame.registerDatasource(async () => { - const { getValueBasedDatasource } = await import('../../async_services'); - const [coreStart, { data, dataViews, expressions }] = await core.getStartServices(); - - return getValueBasedDatasource({ - core: coreStart, - storage: new Storage(localStorage), - data, - dataViews, - expressions, - }); - }); - } -} diff --git a/x-pack/plugins/lens/public/datasources/value_based/text_based_languages.tsx b/x-pack/plugins/lens/public/datasources/value_based/text_based_languages.tsx deleted file mode 100644 index 12bda489201ad..0000000000000 --- a/x-pack/plugins/lens/public/datasources/value_based/text_based_languages.tsx +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CoreStart } from '@kbn/core/public'; -import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; -import type { SavedObjectReference } from '@kbn/core/public'; -import type { ExpressionsStart } from '@kbn/expressions-plugin/public'; -import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; -import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import memoizeOne from 'memoize-one'; -import { isEqual } from 'lodash'; -import { toExpression } from './to_expression'; -import { - DatasourceDimensionEditorProps, - DatasourceDataPanelProps, - DatasourceLayerPanelProps, - PublicAPIProps, - DatasourceDimensionTriggerProps, - UserMessage, -} from '../../types'; -import type { - ValueBasedPrivateState, - ValueBasedPersistedState, - ValueBasedLayerColumn, -} from './types'; -import type { Datasource } from '../../types'; -import { getUniqueLabelGenerator, nonNullable } from '../../utils'; - -const getSelectedFieldsFromColumns = memoizeOne( - (columns: ValueBasedLayerColumn[]) => - columns - .map((c) => { - if ('fieldName' in c) { - return c.fieldName; - } - }) - .filter(nonNullable), - isEqual -); - -export function getValueBasedDatasource({ - core, - storage, - data, - expressions, - dataViews, -}: { - core: CoreStart; - storage: IStorageWrapper; - data: DataPublicPluginStart; - expressions: ExpressionsStart; - dataViews: DataViewsPublicPluginStart; -}) { - const ValueBasedDatasource: Datasource = { - id: 'valueBased', - - checkIntegrity: () => { - return []; - }, - removeColumn: (props) => { - return props.prevState; - }, - onDrop: () => { - return undefined; - }, - getDropProps: () => { - return undefined; - }, - getUserMessages: (state) => { - const errors: Error[] = []; - - Object.values(state.layers).forEach((layer) => { - if (layer.errors && layer.errors.length > 0) { - errors.push(...layer.errors); - } - }); - return errors.map((err) => { - const message: UserMessage = { - severity: 'error', - fixableInEditor: true, - displayLocations: [{ id: 'visualization' }, { id: 'textBasedLanguagesQueryInput' }], - shortMessage: err.message, - longMessage: err.message, - }; - return message; - }); - }, - initialize(state?: ValueBasedPersistedState, savedObjectReferences?, context?) { - const initState = state || { layers: {} }; - return { - ...initState, - initialContext: context, - }; - }, - - syncColumns({ state }) { - return state; - }, - - onRefreshIndexPattern() {}, - - getUsedDataViews: () => { - return []; - }, - - getPersistableState({ layers }: ValueBasedPrivateState) { - return { state: { layers }, savedObjectReferences: [] }; - }, - insertLayer(state: ValueBasedPrivateState, newLayerId: string) { - return state; - }, - createEmptyLayer() { - return { - layers: {}, - fieldList: [], - }; - }, - - cloneLayer(state, layerId, newLayerId, getNewId) { - return { - ...state, - }; - }, - - removeLayer(state: ValueBasedPrivateState, layerId: string) { - const newLayers = { - ...state.layers, - [layerId]: { - ...state.layers[layerId], - columns: [], - }, - }; - - return { - removedLayerIds: [layerId], - newState: { - ...state, - layers: newLayers, - fieldList: state.fieldList, - }, - }; - }, - - clearLayer(state: ValueBasedPrivateState, layerId: string) { - return { - removedLayerIds: [], - newState: { - ...state, - layers: { - ...state.layers, - [layerId]: { ...state.layers[layerId], columns: [] }, - }, - }, - }; - }, - - getLayers(state: ValueBasedPrivateState) { - return state && state.layers ? Object.keys(state?.layers) : []; - }, - isTimeBased: (state, indexPatterns) => { - return false; - }, - getUsedDataView: (state: ValueBasedPrivateState, layerId?: string) => { - return ''; - }, - - toExpression: (state, layerId, indexPatterns, dateRange, searchSessionId) => { - return toExpression(state, layerId); - }, - getSelectedFields(state) { - return getSelectedFieldsFromColumns( - Object.values(state?.layers)?.flatMap((l) => Object.values(l.columns)) - ); - }, - - DataPanelComponent(props: DatasourceDataPanelProps) { - return null; - }, - - DimensionTriggerComponent: (props: DatasourceDimensionTriggerProps) => { - return null; - }, - - getRenderEventCounters(state: ValueBasedPrivateState): string[] { - return []; - }, - - DimensionEditorComponent: (props: DatasourceDimensionEditorProps) => { - return null; - }, - - LayerPanelComponent: (props: DatasourceLayerPanelProps) => { - return null; - }, - - uniqueLabels(state: ValueBasedPrivateState) { - const layers = state.layers; - const columnLabelMap = {} as Record; - const uniqueLabelGenerator = getUniqueLabelGenerator(); - - Object.values(layers).forEach((layer) => { - if (!layer.columns) { - return; - } - Object.values(layer.columns).forEach((column) => { - columnLabelMap[column.columnId] = uniqueLabelGenerator(column.fieldName); - }); - }); - - return columnLabelMap; - }, - getPublicAPI({ state, layerId, indexPatterns }: PublicAPIProps) { - return { - datasourceId: 'ValueBased', - isTextBasedLanguage: () => true, - getTableSpec: () => { - const columns = state.layers[layerId]?.columns.filter((c) => { - const columnExists = state?.fieldList?.some((f) => f.name === c?.fieldName); - if (columnExists) return c; - }); - return ( - columns.map((column) => ({ - columnId: column.columnId, - fields: [column.fieldName], - })) || [] - ); - }, - getOperationForColumnId: (columnId: string) => { - return null; - }, - getVisualDefaults: () => ({}), - isValueBasedLanguage: () => true, - getMaxPossibleNumValues: (columnId) => { - return null; - }, - getSourceId: () => { - return undefined; - }, - getFilters: () => { - return { - enabled: { - kuery: [], - lucene: [], - }, - disabled: { - kuery: [], - lucene: [], - }, - }; - }, - hasDefaultTimeField: () => false, - }; - }, - getDatasourceSuggestionsForField(state, draggedField) { - return []; - }, - getDatasourceSuggestionsForVisualizeField: () => { - return []; - }, - getDatasourceSuggestionsFromCurrentState: () => [], - getDatasourceSuggestionsForVisualizeCharts: () => [], - isEqual: ( - persistableState1: ValueBasedPersistedState, - references1: SavedObjectReference[], - persistableState2: ValueBasedPersistedState, - references2: SavedObjectReference[] - ) => isEqual(persistableState1, persistableState2), - getDatasourceInfo: async (state, references, dataViewsService) => { - return []; - }, - }; - - return ValueBasedDatasource; -} diff --git a/x-pack/plugins/lens/public/datasources/value_based/to_expression.ts b/x-pack/plugins/lens/public/datasources/value_based/to_expression.ts deleted file mode 100644 index 3fad7d29e57bb..0000000000000 --- a/x-pack/plugins/lens/public/datasources/value_based/to_expression.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Ast } from '@kbn/interpreter'; -import type { OriginalColumn } from '../../../common/types'; -import { ValueBasedPrivateState, ValueBasedLayer } from './types'; -function getExpressionForLayer(layer: ValueBasedLayer, layerId: string): Ast | null { - if (!layer.columns || layer.columns?.length === 0) { - return null; - } - - let idMapper: Record = {}; - layer.columns.forEach((col) => { - if (idMapper[col.fieldName]) { - idMapper[col.fieldName].push({ - id: col.columnId, - label: col.fieldName, - } as OriginalColumn); - } else { - idMapper = { - ...idMapper, - [col.fieldName]: [ - { - id: col.columnId, - label: col.fieldName, - } as OriginalColumn, - ], - }; - } - }); - - return { - type: 'expression', - chain: [ - { - type: 'function', - function: 'var', - arguments: { - name: [layerId], - }, - }, - { - type: 'function', - function: 'lens_map_to_columns', - arguments: { - idMap: [JSON.stringify(idMapper)], - }, - }, - ], - }; -} - -export function toExpression(state: ValueBasedPrivateState, layerId: string) { - if (state.layers[layerId]) { - return getExpressionForLayer(state.layers[layerId], layerId); - } - - return null; -} diff --git a/x-pack/plugins/lens/public/datasources/value_based/types.ts b/x-pack/plugins/lens/public/datasources/value_based/types.ts deleted file mode 100644 index da7909159bd89..0000000000000 --- a/x-pack/plugins/lens/public/datasources/value_based/types.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import type { Datatable, DatatableColumn } from '@kbn/expressions-plugin/public'; -import type { VisualizeFieldContext } from '@kbn/ui-actions-plugin/public'; -import type { VisualizeEditorContext } from '../../types'; - -export interface ValueBasedLayerColumn { - columnId: string; - fieldName: string; - meta?: DatatableColumn['meta']; -} - -export interface ValueBasedField { - id: string; - field: string; -} - -export interface ValueBasedLayer { - table: Datatable; - columns: ValueBasedLayerColumn[]; - errors?: Error[]; -} - -export interface ValueBasedPersistedState { - layers: Record; - initialContext?: VisualizeFieldContext | VisualizeEditorContext; - fieldList?: DatatableColumn[]; -} - -export type ValueBasedPrivateState = ValueBasedPersistedState; diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx index ca928414d7c63..f58b8e274b021 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx @@ -84,7 +84,6 @@ import { import { DataViewSpec } from '@kbn/data-views-plugin/common'; import { FormattedMessage, I18nProvider } from '@kbn/i18n-react'; import { useEuiFontSize, useEuiTheme, EuiEmptyPrompt } from '@elastic/eui'; -import { ValueBasedPersistedState } from '../datasources/value_based/types'; import { getExecutionContextEvents, trackUiCounterEvents } from '../lens_ui_telemetry'; import { Document } from '../persistence'; import { ExpressionWrapper, ExpressionWrapperProps } from './expression_wrapper'; @@ -142,6 +141,7 @@ import type { LensPluginStartDependencies } from '../plugin'; import { EmbeddableFeatureBadge } from './embeddable_info_badges'; import { getDatasourceLayers } from '../state_management/utils'; import type { EditLensConfigurationProps } from '../app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration'; +import { TextBasedPersistedState } from '../datasources/text_based/types'; export type LensSavedObjectAttributes = Omit; @@ -1083,11 +1083,11 @@ export class Embeddable const getInternalTables = (states: Record) => { const result: Record = {}; - if ('valueBased' in states) { - const layers = (states.valueBased as ValueBasedPersistedState).layers; + if ('textBased' in states) { + const layers = (states.valueBased as TextBasedPersistedState).layers; for (const layer in layers) { - if (layers[layer]) { - result[layer] = layers[layer].table; + if (layers[layer] && layers[layer].table) { + result[layer] = layers[layer].table!; } } } diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx index 1355ee6b59942..d93e3729a6541 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx @@ -37,7 +37,6 @@ import type { DatatableVisualizationState } from '../visualizations/datatable/vi import type { MetricVisualizationState } from '../visualizations/metric/types'; import type { HeatmapVisualizationState } from '../visualizations/heatmap/types'; import type { GaugeVisualizationState } from '../visualizations/gauge/constants'; -import { ValueBasedPersistedState } from '../datasources/value_based/types'; type LensAttributes = Omit< Document, @@ -48,7 +47,6 @@ type LensAttributes = Omit< datasourceStates: { formBased: FormBasedPersistedState; textBased?: TextBasedPersistedState; - valueBased?: ValueBasedPersistedState; }; visualization: TVisState; }; diff --git a/x-pack/plugins/lens/public/plugin.ts b/x-pack/plugins/lens/public/plugin.ts index b526f06991636..63eab92016d50 100644 --- a/x-pack/plugins/lens/public/plugin.ts +++ b/x-pack/plugins/lens/public/plugin.ts @@ -71,7 +71,6 @@ import type { FormulaPublicApi, } from './datasources/form_based'; import type { TextBasedDatasource as TextBasedDatasourceType } from './datasources/text_based'; -import type { ValueBasedDatasource as ValueBasedDatasourceType } from './datasources/value_based'; import type { XyVisualization as XyVisualizationType, @@ -277,7 +276,6 @@ export class LensPlugin { private queuedVisualizations: Array Promise)> = []; private FormBasedDatasource: FormBasedDatasourceType | undefined; private TextBasedDatasource: TextBasedDatasourceType | undefined; - private ValueBasedDatasource: ValueBasedDatasourceType | undefined; private xyVisualization: XyVisualizationType | undefined; private legacyMetricVisualization: LegacyMetricVisualizationType | undefined; private metricVisualization: MetricVisualizationType | undefined; @@ -520,13 +518,11 @@ export class LensPlugin { GaugeVisualization, TagcloudVisualization, TextBasedDatasource, - ValueBasedDatasource, } = await import('./async_services'); this.datatableVisualization = new DatatableVisualization(); this.editorFrameService = new EditorFrameService(); this.FormBasedDatasource = new FormBasedDatasource(); this.TextBasedDatasource = new TextBasedDatasource(); - this.ValueBasedDatasource = new ValueBasedDatasource(); this.xyVisualization = new XyVisualization(); this.legacyMetricVisualization = new LegacyMetricVisualization(); this.metricVisualization = new MetricVisualization(); @@ -551,7 +547,6 @@ export class LensPlugin { }; this.FormBasedDatasource.setup(core, dependencies); this.TextBasedDatasource.setup(core, dependencies); - this.ValueBasedDatasource.setup(core, dependencies); this.xyVisualization.setup(core, dependencies); this.datatableVisualization.setup(core, dependencies); this.legacyMetricVisualization.setup(core, dependencies);