From 69c0c2d545355037f1151aef484eccef3bfad62e Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Tue, 7 Sep 2021 13:06:32 +0300 Subject: [PATCH] lens should register expression functions in setup contract (#110639) (#111324) * lens should register expression functions in setup contract Closes: #106510 * fix CI * build optimization * build optimizations - step 3 * fix CI * try to optimize bundle * Update x-pack/plugins/lens/common/expressions/time_scale/types.ts Co-authored-by: Marta Bondyra * Update types.ts Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Marta Bondyra Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Marta Bondyra --- .../counter_rate/counter_rate.test.ts | 78 ++++++----- .../counter_rate/counter_rate_fn.ts | 54 ++++++++ .../common/expressions/counter_rate/index.ts | 64 +-------- .../common/expressions/counter_rate/types.ts | 16 +++ .../common/expressions/datatable/datatable.ts | 108 ++------------- .../expressions/datatable/datatable_fn.ts | 93 +++++++++++++ .../common/expressions/datatable/index.ts | 2 + .../common/expressions/datatable/types.ts | 29 ++++ .../format_column/format_column.test.ts | 44 +++--- .../format_column/format_column_fn.ts | 84 ++++++++++++ .../common/expressions/format_column/index.ts | 117 +--------------- .../format_column/supported_formats.ts | 36 +++++ .../common/expressions/format_column/types.ts | 19 +++ .../common/expressions/merge_tables/index.ts | 2 +- .../expressions/metric_chart/metric_chart.ts | 12 +- .../common/expressions/pie_chart/index.ts | 11 +- .../common/expressions/pie_chart/pie_chart.ts | 3 +- .../expressions/rename_columns/index.ts | 2 +- .../rename_columns/rename_columns.test.ts | 12 +- .../rename_columns/rename_columns.ts | 74 +--------- .../rename_columns/rename_columns_fn.ts | 62 +++++++++ .../expressions/rename_columns/types.ts | 22 +++ .../common/expressions/time_scale/index.ts | 4 +- .../expressions/time_scale/time_scale.test.ts | 7 +- .../expressions/time_scale/time_scale.ts | 123 +---------------- .../expressions/time_scale/time_scale_fn.ts | 105 ++++++++++++++ .../common/expressions/time_scale/types.ts | 20 +++ .../lens/public/app_plugin/mounter.tsx | 10 +- .../app_plugin/shared/saved_modal_lazy.tsx | 16 ++- .../components/table_basic.tsx | 2 +- .../expression.test.tsx | 2 +- .../datatable_visualization/expression.tsx | 4 +- .../public/datatable_visualization/index.ts | 12 +- .../public/editor_frame_service/service.tsx | 12 +- .../embeddable/embeddable_component.tsx | 4 +- .../public/embeddable/embeddable_factory.ts | 2 +- x-pack/plugins/lens/public/expressions.ts | 64 +++++++++ .../heatmap_visualization/expression.tsx | 2 - .../public/heatmap_visualization/index.ts | 15 +- .../dimension_panel/time_scaling.tsx | 15 +- .../public/indexpattern_datasource/index.ts | 20 +-- .../indexpattern_datasource/indexpattern.tsx | 10 +- .../indexpattern_suggestions.ts | 4 +- .../operations/definitions/ranges/ranges.tsx | 2 +- .../lens/public/lens_attribute_service.ts | 10 +- .../metric_visualization/expression.test.tsx | 4 +- .../metric_visualization/expression.tsx | 4 +- .../lens/public/metric_visualization/index.ts | 8 +- .../metric_suggestions.ts | 2 +- .../public/pie_visualization/expression.tsx | 2 - .../lens/public/pie_visualization/index.ts | 6 +- x-pack/plugins/lens/public/plugin.ts | 129 +++++++++--------- x-pack/plugins/lens/public/search_provider.ts | 7 +- .../visualize_field_actions.ts | 2 +- x-pack/plugins/lens/public/utils.ts | 20 +-- x-pack/plugins/lens/public/vis_type_alias.ts | 4 +- .../xy_visualization/expression.test.tsx | 3 +- .../public/xy_visualization/expression.tsx | 12 -- .../lens/public/xy_visualization/index.ts | 25 +--- .../lens/public/xy_visualization/types.ts | 4 +- 60 files changed, 883 insertions(+), 758 deletions(-) create mode 100644 x-pack/plugins/lens/common/expressions/counter_rate/counter_rate_fn.ts create mode 100644 x-pack/plugins/lens/common/expressions/counter_rate/types.ts create mode 100644 x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts create mode 100644 x-pack/plugins/lens/common/expressions/datatable/types.ts create mode 100644 x-pack/plugins/lens/common/expressions/format_column/format_column_fn.ts create mode 100644 x-pack/plugins/lens/common/expressions/format_column/supported_formats.ts create mode 100644 x-pack/plugins/lens/common/expressions/format_column/types.ts create mode 100644 x-pack/plugins/lens/common/expressions/rename_columns/rename_columns_fn.ts create mode 100644 x-pack/plugins/lens/common/expressions/rename_columns/types.ts create mode 100644 x-pack/plugins/lens/common/expressions/time_scale/time_scale_fn.ts create mode 100644 x-pack/plugins/lens/public/expressions.ts diff --git a/x-pack/plugins/lens/common/expressions/counter_rate/counter_rate.test.ts b/x-pack/plugins/lens/common/expressions/counter_rate/counter_rate.test.ts index 3e1a5ad8e3964..5e41e1e4f95f8 100644 --- a/x-pack/plugins/lens/common/expressions/counter_rate/counter_rate.test.ts +++ b/x-pack/plugins/lens/common/expressions/counter_rate/counter_rate.test.ts @@ -12,10 +12,10 @@ import { functionWrapper } from 'src/plugins/expressions/common/expression_funct describe('lens_counter_rate', () => { const fn = functionWrapper(counterRate); - const runFn = (input: Datatable, args: CounterRateArgs) => fn(input, args) as Datatable; + const runFn = (input: Datatable, args: CounterRateArgs) => fn(input, args) as Promise; - it('calculates counter rate', () => { - const result = runFn( + it('calculates counter rate', async () => { + const result = await runFn( { type: 'datatable', columns: [{ id: 'val', name: 'val', meta: { type: 'number' } }], @@ -31,8 +31,8 @@ describe('lens_counter_rate', () => { expect(result.rows.map((row) => row.output)).toEqual([undefined, 0, 2, 3, 2]); }); - it('calculates counter rate with decreasing values in input', () => { - const result = runFn( + it('calculates counter rate with decreasing values in input', async () => { + const result = await runFn( { type: 'datatable', columns: [{ id: 'val', name: 'val', meta: { type: 'number' } }], @@ -48,8 +48,8 @@ describe('lens_counter_rate', () => { expect(result.rows.map((row) => row.output)).toEqual([undefined, 6, 5, 4]); }); - it('skips null or undefined values until there is real data', () => { - const result = runFn( + it('skips null or undefined values until there is real data', async () => { + const result = await runFn( { type: 'datatable', columns: [{ id: 'val', name: 'val', meta: { type: 'number' } }], @@ -85,8 +85,8 @@ describe('lens_counter_rate', () => { ]); }); - it('treats 0 as real data', () => { - const result = runFn( + it('treats 0 as real data', async () => { + const result = await runFn( { type: 'datatable', columns: [{ id: 'val', name: 'val', meta: { type: 'number' } }], @@ -123,8 +123,8 @@ describe('lens_counter_rate', () => { ]); }); - it('calculates counter rate for multiple series', () => { - const result = runFn( + it('calculates counter rate for multiple series', async () => { + const result = await runFn( { type: 'datatable', columns: [ @@ -157,8 +157,8 @@ describe('lens_counter_rate', () => { ]); }); - it('treats missing split column as separate series', () => { - const result = runFn( + it('treats missing split column as separate series', async () => { + const result = await runFn( { type: 'datatable', columns: [ @@ -190,8 +190,8 @@ describe('lens_counter_rate', () => { ]); }); - it('treats null like undefined and empty string for split columns', () => { - const result = runFn( + it('treats null like undefined and empty string for split columns', async () => { + const result = await runFn( { type: 'datatable', columns: [ @@ -225,8 +225,8 @@ describe('lens_counter_rate', () => { ]); }); - it('calculates counter rate for multiple series by multiple split columns', () => { - const result = runFn( + it('calculates counter rate for multiple series by multiple split columns', async () => { + const result = await runFn( { type: 'datatable', columns: [ @@ -259,8 +259,8 @@ describe('lens_counter_rate', () => { ]); }); - it('splits separate series by the string representation of the cell values', () => { - const result = runFn( + it('splits separate series by the string representation of the cell values', async () => { + const result = await runFn( { type: 'datatable', columns: [ @@ -280,8 +280,8 @@ describe('lens_counter_rate', () => { expect(result.rows.map((row) => row.output)).toEqual([undefined, 2 - 1, undefined, 11 - 10]); }); - it('casts values to number before calculating counter rate', () => { - const result = runFn( + it('casts values to number before calculating counter rate', async () => { + const result = await runFn( { type: 'datatable', columns: [{ id: 'val', name: 'val', meta: { type: 'number' } }], @@ -292,8 +292,8 @@ describe('lens_counter_rate', () => { expect(result.rows.map((row) => row.output)).toEqual([undefined, 7 - 5, 3, 2]); }); - it('casts values to number before calculating counter rate for NaN like values', () => { - const result = runFn( + it('casts values to number before calculating counter rate for NaN like values', async () => { + const result = await runFn( { type: 'datatable', columns: [{ id: 'val', name: 'val', meta: { type: 'number' } }], @@ -304,8 +304,8 @@ describe('lens_counter_rate', () => { expect(result.rows.map((row) => row.output)).toEqual([undefined, 7 - 5, NaN, 2, 5 - 2]); }); - it('copies over meta information from the source column', () => { - const result = runFn( + it('copies over meta information from the source column', async () => { + const result = await runFn( { type: 'datatable', columns: [ @@ -346,8 +346,8 @@ describe('lens_counter_rate', () => { }); }); - it('sets output name on output column if specified', () => { - const result = runFn( + it('sets output name on output column if specified', async () => { + const result = await runFn( { type: 'datatable', columns: [ @@ -370,7 +370,7 @@ describe('lens_counter_rate', () => { }); }); - it('returns source table if input column does not exist', () => { + it('returns source table if input column does not exist', async () => { const input: Datatable = { type: 'datatable', columns: [ @@ -384,12 +384,16 @@ describe('lens_counter_rate', () => { ], rows: [{ val: 5 }], }; - expect(runFn(input, { inputColumnId: 'nonexisting', outputColumnId: 'output' })).toBe(input); + expect(await runFn(input, { inputColumnId: 'nonexisting', outputColumnId: 'output' })).toBe( + input + ); }); - it('throws an error if output column exists already', () => { - expect(() => - runFn( + it('throws an error if output column exists already', async () => { + let error: Error | undefined; + + try { + await runFn( { type: 'datatable', columns: [ @@ -404,7 +408,13 @@ describe('lens_counter_rate', () => { rows: [{ val: 5 }], }, { inputColumnId: 'val', outputColumnId: 'val' } - ) - ).toThrow(); + ); + } catch (e) { + error = e; + } + + expect(error).toMatchInlineSnapshot( + `[Error: Specified outputColumnId val already exists. Please pick another column id.]` + ); }); }); diff --git a/x-pack/plugins/lens/common/expressions/counter_rate/counter_rate_fn.ts b/x-pack/plugins/lens/common/expressions/counter_rate/counter_rate_fn.ts new file mode 100644 index 0000000000000..6412b508b9649 --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/counter_rate/counter_rate_fn.ts @@ -0,0 +1,54 @@ +/* + * 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 { + buildResultColumns, + getBucketIdentifier, +} from '../../../../../../src/plugins/expressions/common'; +import type { CounterRateExpressionFunction } from './types'; + +export const counterRateFn: CounterRateExpressionFunction['fn'] = ( + input, + { by, inputColumnId, outputColumnId, outputColumnName } +) => { + const resultColumns = buildResultColumns(input, outputColumnId, inputColumnId, outputColumnName); + + if (!resultColumns) { + return input; + } + const previousValues: Partial> = {}; + + return { + ...input, + columns: resultColumns, + rows: input.rows.map((row) => { + const newRow = { ...row }; + + const bucketIdentifier = getBucketIdentifier(row, by); + const previousValue = previousValues[bucketIdentifier]; + const currentValue = newRow[inputColumnId]; + if (currentValue != null && previousValue != null) { + const currentValueAsNumber = Number(currentValue); + if (currentValueAsNumber >= previousValue) { + newRow[outputColumnId] = currentValueAsNumber - previousValue; + } else { + newRow[outputColumnId] = currentValueAsNumber; + } + } else { + newRow[outputColumnId] = undefined; + } + + if (currentValue != null) { + previousValues[bucketIdentifier] = Number(currentValue); + } else { + previousValues[bucketIdentifier] = undefined; + } + + return newRow; + }), + }; +}; diff --git a/x-pack/plugins/lens/common/expressions/counter_rate/index.ts b/x-pack/plugins/lens/common/expressions/counter_rate/index.ts index 41f5547dff969..f58b65814768d 100644 --- a/x-pack/plugins/lens/common/expressions/counter_rate/index.ts +++ b/x-pack/plugins/lens/common/expressions/counter_rate/index.ts @@ -6,14 +6,8 @@ */ import { i18n } from '@kbn/i18n'; -import { - getBucketIdentifier, - buildResultColumns, -} from '../../../../../../src/plugins/expressions/common'; -import type { - ExpressionFunctionDefinition, - Datatable, -} from '../../../../../../src/plugins/expressions/common'; + +import type { CounterRateExpressionFunction } from './types'; export interface CounterRateArgs { by?: string[]; @@ -22,13 +16,6 @@ export interface CounterRateArgs { outputColumnName?: string; } -export type ExpressionFunctionCounterRate = ExpressionFunctionDefinition< - 'lens_counter_rate', - Datatable, - CounterRateArgs, - Datatable ->; - /** * Calculates the counter rate of a specified column in the data table. * @@ -59,7 +46,7 @@ export type ExpressionFunctionCounterRate = ExpressionFunctionDefinition< * before comparison. If the values are objects, the return value of their `toString` method will be used for comparison. * Missing values (`null` and `undefined`) will be treated as empty strings. */ -export const counterRate: ExpressionFunctionCounterRate = { +export const counterRate: CounterRateExpressionFunction = { name: 'lens_counter_rate', type: 'datatable', @@ -101,46 +88,9 @@ export const counterRate: ExpressionFunctionCounterRate = { }, }, - fn(input, { by, inputColumnId, outputColumnId, outputColumnName }) { - const resultColumns = buildResultColumns( - input, - outputColumnId, - inputColumnId, - outputColumnName - ); - - if (!resultColumns) { - return input; - } - const previousValues: Partial> = {}; - return { - ...input, - columns: resultColumns, - rows: input.rows.map((row) => { - const newRow = { ...row }; - - const bucketIdentifier = getBucketIdentifier(row, by); - const previousValue = previousValues[bucketIdentifier]; - const currentValue = newRow[inputColumnId]; - if (currentValue != null && previousValue != null) { - const currentValueAsNumber = Number(currentValue); - if (currentValueAsNumber >= previousValue) { - newRow[outputColumnId] = currentValueAsNumber - previousValue; - } else { - newRow[outputColumnId] = currentValueAsNumber; - } - } else { - newRow[outputColumnId] = undefined; - } - - if (currentValue != null) { - previousValues[bucketIdentifier] = Number(currentValue); - } else { - previousValues[bucketIdentifier] = undefined; - } - - return newRow; - }), - }; + async fn(...args) { + /** Build optimization: prevent adding extra code into initial bundle **/ + const { counterRateFn } = await import('./counter_rate_fn'); + return counterRateFn(...args); }, }; diff --git a/x-pack/plugins/lens/common/expressions/counter_rate/types.ts b/x-pack/plugins/lens/common/expressions/counter_rate/types.ts new file mode 100644 index 0000000000000..f9e1cbbb43de3 --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/counter_rate/types.ts @@ -0,0 +1,16 @@ +/* + * 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 { Datatable, ExpressionFunctionDefinition } from '../../../../../../src/plugins/expressions'; +import { CounterRateArgs } from './index'; + +export type CounterRateExpressionFunction = ExpressionFunctionDefinition< + 'lens_counter_rate', + Datatable, + CounterRateArgs, + Datatable | Promise +>; diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable.ts index 32f6c1c089543..d9f1f9c1196ff 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable.ts @@ -6,35 +6,16 @@ */ import { i18n } from '@kbn/i18n'; -import { cloneDeep } from 'lodash'; -import type { - ExecutionContext, - DatatableColumnMeta, - ExpressionFunctionDefinition, -} from '../../../../../../src/plugins/expressions/common'; -import type { FormatFactory, LensMultiTable } from '../../types'; +import type { ExecutionContext } from '../../../../../../src/plugins/expressions/common'; +import type { FormatFactory } from '../../types'; import type { ColumnConfigArg } from './datatable_column'; -import { getSortingCriteria } from './sorting'; -import { computeSummaryRowForColumn } from './summary'; -import { transposeTable } from './transpose_helpers'; +import type { DatatableExpressionFunction } from './types'; export interface SortingState { columnId: string | undefined; direction: 'asc' | 'desc' | 'none'; } -export interface DatatableProps { - data: LensMultiTable; - untransposedData?: LensMultiTable; - args: DatatableArgs; -} - -export interface DatatableRender { - type: 'render'; - as: 'lens_datatable_renderer'; - value: DatatableProps; -} - export interface DatatableArgs { title: string; description?: string; @@ -43,18 +24,9 @@ export interface DatatableArgs { sortingDirection: SortingState['direction']; } -function isRange(meta: { params?: { id?: string } } | undefined) { - return meta?.params?.id === 'range'; -} - export const getDatatable = ( getFormatFactory: (context: ExecutionContext) => FormatFactory | Promise -): ExpressionFunctionDefinition< - 'lens_datatable', - LensMultiTable, - DatatableArgs, - Promise -> => ({ +): DatatableExpressionFunction => ({ name: 'lens_datatable', type: 'render', inputTypes: ['lens_multitable'], @@ -86,73 +58,9 @@ export const getDatatable = ( help: '', }, }, - async fn(data, args, context) { - let untransposedData: LensMultiTable | undefined; - // do the sorting at this level to propagate it also at CSV download - const [firstTable] = Object.values(data.tables); - const [layerId] = Object.keys(context.inspectorAdapters.tables || {}); - const formatters: Record> = {}; - const formatFactory = await getFormatFactory(context); - - firstTable.columns.forEach((column) => { - formatters[column.id] = formatFactory(column.meta?.params); - }); - - const hasTransposedColumns = args.columns.some((c) => c.isTransposed); - if (hasTransposedColumns) { - // store original shape of data separately - untransposedData = cloneDeep(data); - // transposes table and args inplace - transposeTable(args, firstTable, formatters); - } - - const { sortingColumnId: sortBy, sortingDirection: sortDirection } = args; - - const columnsReverseLookup = firstTable.columns.reduce< - Record - >((memo, { id, name, meta }, i) => { - memo[id] = { name, index: i, meta }; - return memo; - }, {}); - - const columnsWithSummary = args.columns.filter((c) => c.summaryRow); - for (const column of columnsWithSummary) { - column.summaryRowValue = computeSummaryRowForColumn( - column, - firstTable, - formatters, - formatFactory({ id: 'number' }) - ); - } - - if (sortBy && columnsReverseLookup[sortBy] && sortDirection !== 'none') { - // Sort on raw values for these types, while use the formatted value for the rest - const sortingCriteria = getSortingCriteria( - isRange(columnsReverseLookup[sortBy]?.meta) - ? 'range' - : columnsReverseLookup[sortBy]?.meta?.type, - sortBy, - formatters[sortBy], - sortDirection - ); - // replace the table here - context.inspectorAdapters.tables[layerId].rows = (firstTable.rows || []) - .slice() - .sort(sortingCriteria); - // replace also the local copy - firstTable.rows = context.inspectorAdapters.tables[layerId].rows; - } else { - args.sortingColumnId = undefined; - args.sortingDirection = 'none'; - } - return { - type: 'render', - as: 'lens_datatable_renderer', - value: { - data, - untransposedData, - args, - }, - }; + async fn(...args) { + /** Build optimization: prevent adding extra code into initial bundle **/ + const { datatableFn } = await import('./datatable_fn'); + return datatableFn(getFormatFactory)(...args); }, }); diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts new file mode 100644 index 0000000000000..cb03ec7f9dda6 --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts @@ -0,0 +1,93 @@ +/* + * 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 { cloneDeep } from 'lodash'; +import { FormatFactory, LensMultiTable } from '../../types'; +import { transposeTable } from './transpose_helpers'; +import { computeSummaryRowForColumn } from './summary'; +import { getSortingCriteria } from './sorting'; +import type { + DatatableColumnMeta, + ExecutionContext, +} from '../../../../../../src/plugins/expressions'; +import type { DatatableExpressionFunction } from './types'; + +function isRange(meta: { params?: { id?: string } } | undefined) { + return meta?.params?.id === 'range'; +} + +export const datatableFn = ( + getFormatFactory: (context: ExecutionContext) => FormatFactory | Promise +): DatatableExpressionFunction['fn'] => async (data, args, context) => { + let untransposedData: LensMultiTable | undefined; + // do the sorting at this level to propagate it also at CSV download + const [firstTable] = Object.values(data.tables); + const [layerId] = Object.keys(context.inspectorAdapters.tables || {}); + const formatters: Record> = {}; + const formatFactory = await getFormatFactory(context); + + firstTable.columns.forEach((column) => { + formatters[column.id] = formatFactory(column.meta?.params); + }); + + const hasTransposedColumns = args.columns.some((c) => c.isTransposed); + if (hasTransposedColumns) { + // store original shape of data separately + untransposedData = cloneDeep(data); + // transposes table and args inplace + transposeTable(args, firstTable, formatters); + } + + const { sortingColumnId: sortBy, sortingDirection: sortDirection } = args; + + const columnsReverseLookup = firstTable.columns.reduce< + Record + >((memo, { id, name, meta }, i) => { + memo[id] = { name, index: i, meta }; + return memo; + }, {}); + + const columnsWithSummary = args.columns.filter((c) => c.summaryRow); + for (const column of columnsWithSummary) { + column.summaryRowValue = computeSummaryRowForColumn( + column, + firstTable, + formatters, + formatFactory({ id: 'number' }) + ); + } + + if (sortBy && columnsReverseLookup[sortBy] && sortDirection !== 'none') { + // Sort on raw values for these types, while use the formatted value for the rest + const sortingCriteria = getSortingCriteria( + isRange(columnsReverseLookup[sortBy]?.meta) + ? 'range' + : columnsReverseLookup[sortBy]?.meta?.type, + sortBy, + formatters[sortBy], + sortDirection + ); + // replace the table here + context.inspectorAdapters.tables[layerId].rows = (firstTable.rows || []) + .slice() + .sort(sortingCriteria); + // replace also the local copy + firstTable.rows = context.inspectorAdapters.tables[layerId].rows; + } else { + args.sortingColumnId = undefined; + args.sortingDirection = 'none'; + } + return { + type: 'render', + as: 'lens_datatable_renderer', + value: { + data, + untransposedData, + args, + }, + }; +}; diff --git a/x-pack/plugins/lens/common/expressions/datatable/index.ts b/x-pack/plugins/lens/common/expressions/datatable/index.ts index 2602aae252ca9..cf9fb1d0b4791 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/index.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/index.ts @@ -10,3 +10,5 @@ export * from './datatable'; export * from './summary'; export * from './transpose_helpers'; export * from './utils'; + +export type { DatatableProps } from './types'; diff --git a/x-pack/plugins/lens/common/expressions/datatable/types.ts b/x-pack/plugins/lens/common/expressions/datatable/types.ts new file mode 100644 index 0000000000000..340f3eb0576b0 --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/datatable/types.ts @@ -0,0 +1,29 @@ +/* + * 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 { ExpressionFunctionDefinition } from '../../../../../../src/plugins/expressions'; +import type { LensMultiTable } from '../../types'; +import type { DatatableArgs } from './datatable'; + +export interface DatatableProps { + data: LensMultiTable; + untransposedData?: LensMultiTable; + args: DatatableArgs; +} + +export interface DatatableRender { + type: 'render'; + as: 'lens_datatable_renderer'; + value: DatatableProps; +} + +export type DatatableExpressionFunction = ExpressionFunctionDefinition< + 'lens_datatable', + LensMultiTable, + DatatableArgs, + Promise +>; diff --git a/x-pack/plugins/lens/common/expressions/format_column/format_column.test.ts b/x-pack/plugins/lens/common/expressions/format_column/format_column.test.ts index 4428225b349da..fbf3ff9c05b19 100644 --- a/x-pack/plugins/lens/common/expressions/format_column/format_column.test.ts +++ b/x-pack/plugins/lens/common/expressions/format_column/format_column.test.ts @@ -10,7 +10,9 @@ import { functionWrapper } from 'src/plugins/expressions/common/expression_funct import { FormatColumnArgs, formatColumn } from './index'; describe('format_column', () => { - const fn: (input: Datatable, args: FormatColumnArgs) => Datatable = functionWrapper(formatColumn); + const fn: (input: Datatable, args: FormatColumnArgs) => Promise = functionWrapper( + formatColumn + ); let datatable: Datatable; @@ -33,17 +35,17 @@ describe('format_column', () => { }; }); - it('overwrites format', () => { + it('overwrites format', async () => { datatable.columns[0].meta.params = { id: 'myformatter', params: {} }; - const result = fn(datatable, { columnId: 'test', format: 'otherformatter' }); + const result = await fn(datatable, { columnId: 'test', format: 'otherformatter' }); expect(result.columns[0].meta.params).toEqual({ id: 'otherformatter', }); }); - it('overwrites format with well known pattern', () => { + it('overwrites format with well known pattern', async () => { datatable.columns[0].meta.params = { id: 'myformatter', params: {} }; - const result = fn(datatable, { columnId: 'test', format: 'number' }); + const result = await fn(datatable, { columnId: 'test', format: 'number' }); expect(result.columns[0].meta.params).toEqual({ id: 'number', params: { @@ -52,9 +54,9 @@ describe('format_column', () => { }); }); - it('uses number of decimals if provided', () => { + it('uses number of decimals if provided', async () => { datatable.columns[0].meta.params = { id: 'myformatter', params: {} }; - const result = fn(datatable, { columnId: 'test', format: 'number', decimals: 5 }); + const result = await fn(datatable, { columnId: 'test', format: 'number', decimals: 5 }); expect(result.columns[0].meta.params).toEqual({ id: 'number', params: { @@ -63,9 +65,9 @@ describe('format_column', () => { }); }); - it('has special handling for 0 decimals', () => { + it('has special handling for 0 decimals', async () => { datatable.columns[0].meta.params = { id: 'myformatter', params: {} }; - const result = fn(datatable, { columnId: 'test', format: 'number', decimals: 0 }); + const result = await fn(datatable, { columnId: 'test', format: 'number', decimals: 0 }); expect(result.columns[0].meta.params).toEqual({ id: 'number', params: { @@ -75,8 +77,8 @@ describe('format_column', () => { }); describe('parent format', () => { - it('should ignore parent format if it is not specifying an id', () => { - const result = fn(datatable, { + it('should ignore parent format if it is not specifying an id', async () => { + const result = await fn(datatable, { columnId: 'test', format: '', parentFormat: JSON.stringify({ some: 'key' }), @@ -84,8 +86,8 @@ describe('format_column', () => { expect(result.columns[0].meta.params).toEqual(datatable.columns[0].meta.params); }); - it('set parent format with params', () => { - const result = fn(datatable, { + it('set parent format with params', async () => { + const result = await fn(datatable, { columnId: 'test', format: '', parentFormat: JSON.stringify({ id: 'wrapper', params: { wrapperParam: 123 } }), @@ -99,9 +101,9 @@ describe('format_column', () => { }); }); - it('retain inner formatter params', () => { + it('retain inner formatter params', async () => { datatable.columns[0].meta.params = { id: 'myformatter', params: { innerParam: 456 } }; - const result = fn(datatable, { + const result = await fn(datatable, { columnId: 'test', format: '', parentFormat: JSON.stringify({ id: 'wrapper', params: { wrapperParam: 123 } }), @@ -118,12 +120,12 @@ describe('format_column', () => { }); }); - it('overwrite existing wrapper param', () => { + it('overwrite existing wrapper param', async () => { datatable.columns[0].meta.params = { id: 'wrapper', params: { wrapperParam: 0, id: 'myformatter', params: { innerParam: 456 } }, }; - const result = fn(datatable, { + const result = await fn(datatable, { columnId: 'test', format: '', parentFormat: JSON.stringify({ id: 'wrapper', params: { wrapperParam: 123 } }), @@ -140,12 +142,12 @@ describe('format_column', () => { }); }); - it('overwrites format with well known pattern including decimals', () => { + it('overwrites format with well known pattern including decimals', async () => { datatable.columns[0].meta.params = { id: 'previousWrapper', params: { id: 'myformatter', params: { innerParam: 456 } }, }; - const result = fn(datatable, { + const result = await fn(datatable, { columnId: 'test', format: 'number', decimals: 5, @@ -164,10 +166,10 @@ describe('format_column', () => { }); }); - it('does not touch other column meta data', () => { + it('does not touch other column meta data', async () => { const extraColumn: DatatableColumn = { id: 'test2', name: 'test2', meta: { type: 'number' } }; datatable.columns.push(extraColumn); - const result = fn(datatable, { columnId: 'test', format: 'number' }); + const result = await fn(datatable, { columnId: 'test', format: 'number' }); expect(result.columns[1]).toEqual(extraColumn); }); }); diff --git a/x-pack/plugins/lens/common/expressions/format_column/format_column_fn.ts b/x-pack/plugins/lens/common/expressions/format_column/format_column_fn.ts new file mode 100644 index 0000000000000..37540ee0950af --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/format_column/format_column_fn.ts @@ -0,0 +1,84 @@ +/* + * 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 { supportedFormats } from './supported_formats'; +import type { DatatableColumn } from '../../../../../../src/plugins/expressions'; +import type { FormatColumnArgs } from './index'; +import type { FormatColumnExpressionFunction } from './types'; + +function isNestedFormat(params: DatatableColumn['meta']['params']) { + // if there is a nested params object with an id, it's a nested format + return !!params?.params?.id; +} + +function withParams(col: DatatableColumn, params: Record) { + return { ...col, meta: { ...col.meta, params } }; +} + +export const formatColumnFn: FormatColumnExpressionFunction['fn'] = ( + input, + { format, columnId, decimals, parentFormat }: FormatColumnArgs +) => ({ + ...input, + columns: input.columns.map((col) => { + if (col.id === columnId) { + if (!parentFormat) { + if (supportedFormats[format]) { + return withParams(col, { + id: format, + params: { pattern: supportedFormats[format].decimalsToPattern(decimals) }, + }); + } else if (format) { + return withParams(col, { id: format }); + } else { + return col; + } + } + + const parsedParentFormat = JSON.parse(parentFormat); + const parentFormatId = parsedParentFormat.id; + const parentFormatParams = parsedParentFormat.params ?? {}; + + if (!parentFormatId) { + return col; + } + + if (format && supportedFormats[format]) { + return withParams(col, { + id: parentFormatId, + params: { + id: format, + params: { + pattern: supportedFormats[format].decimalsToPattern(decimals), + }, + ...parentFormatParams, + }, + }); + } + if (parentFormatParams) { + // if original format is already a nested one, we are just replacing the wrapper params + // otherwise wrapping it inside parentFormatId/parentFormatParams + const isNested = isNestedFormat(col.meta.params); + const innerParams = isNested + ? col.meta.params?.params + : { id: col.meta.params?.id, params: col.meta.params?.params }; + + const formatId = isNested ? col.meta.params?.id : parentFormatId; + + return withParams(col, { + ...col.meta.params, + id: formatId, + params: { + ...innerParams, + ...parentFormatParams, + }, + }); + } + } + return col; + }), +}); diff --git a/x-pack/plugins/lens/common/expressions/format_column/index.ts b/x-pack/plugins/lens/common/expressions/format_column/index.ts index c874eac1ede1f..0fc99ff8f7089 100644 --- a/x-pack/plugins/lens/common/expressions/format_column/index.ts +++ b/x-pack/plugins/lens/common/expressions/format_column/index.ts @@ -5,11 +5,7 @@ * 2.0. */ -import type { - ExpressionFunctionDefinition, - Datatable, - DatatableColumn, -} from '../../../../../../src/plugins/expressions/common'; +import type { FormatColumnExpressionFunction } from './types'; export interface FormatColumnArgs { format: string; @@ -18,42 +14,7 @@ export interface FormatColumnArgs { parentFormat?: string; } -export const supportedFormats: Record< - string, - { decimalsToPattern: (decimals?: number) => string } -> = { - number: { - decimalsToPattern: (decimals = 2) => { - if (decimals === 0) { - return `0,0`; - } - return `0,0.${'0'.repeat(decimals)}`; - }, - }, - percent: { - decimalsToPattern: (decimals = 2) => { - if (decimals === 0) { - return `0,0%`; - } - return `0,0.${'0'.repeat(decimals)}%`; - }, - }, - bytes: { - decimalsToPattern: (decimals = 2) => { - if (decimals === 0) { - return `0,0b`; - } - return `0,0.${'0'.repeat(decimals)}b`; - }, - }, -}; - -export const formatColumn: ExpressionFunctionDefinition< - 'lens_format_column', - Datatable, - FormatColumnArgs, - Datatable -> = { +export const formatColumn: FormatColumnExpressionFunction = { name: 'lens_format_column', type: 'datatable', help: '', @@ -78,75 +39,9 @@ export const formatColumn: ExpressionFunctionDefinition< }, }, inputTypes: ['datatable'], - fn(input, { format, columnId, decimals, parentFormat }: FormatColumnArgs) { - return { - ...input, - columns: input.columns.map((col) => { - if (col.id === columnId) { - if (!parentFormat) { - if (supportedFormats[format]) { - return withParams(col, { - id: format, - params: { pattern: supportedFormats[format].decimalsToPattern(decimals) }, - }); - } else if (format) { - return withParams(col, { id: format }); - } else { - return col; - } - } - - const parsedParentFormat = JSON.parse(parentFormat); - const parentFormatId = parsedParentFormat.id; - const parentFormatParams = parsedParentFormat.params ?? {}; - - if (!parentFormatId) { - return col; - } - - if (format && supportedFormats[format]) { - return withParams(col, { - id: parentFormatId, - params: { - id: format, - params: { - pattern: supportedFormats[format].decimalsToPattern(decimals), - }, - ...parentFormatParams, - }, - }); - } - if (parentFormatParams) { - // if original format is already a nested one, we are just replacing the wrapper params - // otherwise wrapping it inside parentFormatId/parentFormatParams - const isNested = isNestedFormat(col.meta.params); - const innerParams = isNested - ? col.meta.params?.params - : { id: col.meta.params?.id, params: col.meta.params?.params }; - - const formatId = isNested ? col.meta.params?.id : parentFormatId; - - return withParams(col, { - ...col.meta.params, - id: formatId, - params: { - ...innerParams, - ...parentFormatParams, - }, - }); - } - } - return col; - }), - }; + async fn(...args) { + /** Build optimization: prevent adding extra code into initial bundle **/ + const { formatColumnFn } = await import('./format_column_fn'); + return formatColumnFn(...args); }, }; - -function isNestedFormat(params: DatatableColumn['meta']['params']) { - // if there is a nested params object with an id, it's a nested format - return !!params?.params?.id; -} - -function withParams(col: DatatableColumn, params: Record) { - return { ...col, meta: { ...col.meta, params } }; -} diff --git a/x-pack/plugins/lens/common/expressions/format_column/supported_formats.ts b/x-pack/plugins/lens/common/expressions/format_column/supported_formats.ts new file mode 100644 index 0000000000000..d00d2f7dfc22f --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/format_column/supported_formats.ts @@ -0,0 +1,36 @@ +/* + * 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. + */ + +export const supportedFormats: Record< + string, + { decimalsToPattern: (decimals?: number) => string } +> = { + number: { + decimalsToPattern: (decimals = 2) => { + if (decimals === 0) { + return `0,0`; + } + return `0,0.${'0'.repeat(decimals)}`; + }, + }, + percent: { + decimalsToPattern: (decimals = 2) => { + if (decimals === 0) { + return `0,0%`; + } + return `0,0.${'0'.repeat(decimals)}%`; + }, + }, + bytes: { + decimalsToPattern: (decimals = 2) => { + if (decimals === 0) { + return `0,0b`; + } + return `0,0.${'0'.repeat(decimals)}b`; + }, + }, +}; diff --git a/x-pack/plugins/lens/common/expressions/format_column/types.ts b/x-pack/plugins/lens/common/expressions/format_column/types.ts new file mode 100644 index 0000000000000..589422b253b93 --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/format_column/types.ts @@ -0,0 +1,19 @@ +/* + * 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, + ExpressionFunctionDefinition, +} from '../../../../../../src/plugins/expressions'; +import type { FormatColumnArgs } from './index'; + +export type FormatColumnExpressionFunction = ExpressionFunctionDefinition< + 'lens_format_column', + Datatable, + FormatColumnArgs, + Datatable | Promise +>; diff --git a/x-pack/plugins/lens/common/expressions/merge_tables/index.ts b/x-pack/plugins/lens/common/expressions/merge_tables/index.ts index e190da19886df..7ede2236e8b07 100644 --- a/x-pack/plugins/lens/common/expressions/merge_tables/index.ts +++ b/x-pack/plugins/lens/common/expressions/merge_tables/index.ts @@ -15,7 +15,7 @@ import { toAbsoluteDates } from '../../../../../../src/plugins/data/common'; import type { ExpressionValueSearchContext } from '../../../../../../src/plugins/data/common'; import type { LensMultiTable } from '../../types'; -import { Adapters } from '../../../../../../src/plugins/inspector/common'; +import type { Adapters } from '../../../../../../src/plugins/inspector/common'; interface MergeTables { layerIds: string[]; diff --git a/x-pack/plugins/lens/common/expressions/metric_chart/metric_chart.ts b/x-pack/plugins/lens/common/expressions/metric_chart/metric_chart.ts index 6c05502bb2b03..0a867e4155c22 100644 --- a/x-pack/plugins/lens/common/expressions/metric_chart/metric_chart.ts +++ b/x-pack/plugins/lens/common/expressions/metric_chart/metric_chart.ts @@ -9,17 +9,17 @@ import type { ExpressionFunctionDefinition } from '../../../../../../src/plugins import type { LensMultiTable } from '../../types'; import type { MetricConfig } from './types'; -export interface MetricChartProps { - data: LensMultiTable; - args: MetricConfig; -} - -export interface MetricRender { +interface MetricRender { type: 'render'; as: 'lens_metric_chart_renderer'; value: MetricChartProps; } +export interface MetricChartProps { + data: LensMultiTable; + args: MetricConfig; +} + export const metricChart: ExpressionFunctionDefinition< 'lens_metric_chart', LensMultiTable, diff --git a/x-pack/plugins/lens/common/expressions/pie_chart/index.ts b/x-pack/plugins/lens/common/expressions/pie_chart/index.ts index e82294f8aff25..1c1f6fdae4578 100644 --- a/x-pack/plugins/lens/common/expressions/pie_chart/index.ts +++ b/x-pack/plugins/lens/common/expressions/pie_chart/index.ts @@ -5,5 +5,12 @@ * 2.0. */ -export * from './types'; -export * from './pie_chart'; +export { pie } from './pie_chart'; + +export type { + SharedPieLayerState, + PieLayerState, + PieVisualizationState, + PieExpressionArgs, + PieExpressionProps, +} from './types'; diff --git a/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts b/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts index 7d228f04c25e7..ed0391a16af25 100644 --- a/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts +++ b/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts @@ -7,11 +7,12 @@ import { Position } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; + import type { ExpressionFunctionDefinition } from '../../../../../../src/plugins/expressions/common'; import type { LensMultiTable } from '../../types'; import type { PieExpressionProps, PieExpressionArgs } from './types'; -export interface PieRender { +interface PieRender { type: 'render'; as: 'lens_pie_renderer'; value: PieExpressionProps; diff --git a/x-pack/plugins/lens/common/expressions/rename_columns/index.ts b/x-pack/plugins/lens/common/expressions/rename_columns/index.ts index 4cb8ff75f486d..86ab16e06ec01 100644 --- a/x-pack/plugins/lens/common/expressions/rename_columns/index.ts +++ b/x-pack/plugins/lens/common/expressions/rename_columns/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export * from './rename_columns'; +export { renameColumns } from './rename_columns'; diff --git a/x-pack/plugins/lens/common/expressions/rename_columns/rename_columns.test.ts b/x-pack/plugins/lens/common/expressions/rename_columns/rename_columns.test.ts index f3db64c1d2257..3bfed88625c89 100644 --- a/x-pack/plugins/lens/common/expressions/rename_columns/rename_columns.test.ts +++ b/x-pack/plugins/lens/common/expressions/rename_columns/rename_columns.test.ts @@ -10,7 +10,7 @@ import { Datatable } from '../../../../../../src/plugins/expressions/common'; import { createMockExecutionContext } from '../../../../../../src/plugins/expressions/common/mocks'; describe('rename_columns', () => { - it('should rename columns of a given datatable', () => { + it('should rename columns of a given datatable', async () => { const input: Datatable = { type: 'datatable', columns: [ @@ -36,7 +36,7 @@ describe('rename_columns', () => { }, }; - const result = renameColumns.fn( + const result = await renameColumns.fn( input, { idMap: JSON.stringify(idMap) }, createMockExecutionContext() @@ -83,7 +83,7 @@ describe('rename_columns', () => { `); }); - it('should keep columns which are not mapped', () => { + it('should keep columns which are not mapped', async () => { const input: Datatable = { type: 'datatable', columns: [ @@ -102,7 +102,7 @@ describe('rename_columns', () => { b: { id: 'c', label: 'Catamaran' }, }; - const result = renameColumns.fn( + const result = await renameColumns.fn( input, { idMap: JSON.stringify(idMap) }, createMockExecutionContext() @@ -149,7 +149,7 @@ describe('rename_columns', () => { `); }); - it('should rename date histograms', () => { + it('should rename date histograms', async () => { const input: Datatable = { type: 'datatable', columns: [ @@ -168,7 +168,7 @@ describe('rename_columns', () => { b: { id: 'c', label: 'Apple', operationType: 'date_histogram', sourceField: 'banana' }, }; - const result = renameColumns.fn( + const result = await renameColumns.fn( input, { idMap: JSON.stringify(idMap) }, createMockExecutionContext() diff --git a/x-pack/plugins/lens/common/expressions/rename_columns/rename_columns.ts b/x-pack/plugins/lens/common/expressions/rename_columns/rename_columns.ts index 517bd683d80ae..d425d5c80d18d 100644 --- a/x-pack/plugins/lens/common/expressions/rename_columns/rename_columns.ts +++ b/x-pack/plugins/lens/common/expressions/rename_columns/rename_columns.ts @@ -6,27 +6,9 @@ */ import { i18n } from '@kbn/i18n'; -import { - ExpressionFunctionDefinition, - Datatable, - DatatableColumn, -} from '../../../../../../src/plugins/expressions/common'; +import type { RenameColumnsExpressionFunction } from './types'; -interface RemapArgs { - idMap: string; -} - -type OriginalColumn = { id: string; label: string } & ( - | { operationType: 'date_histogram'; sourceField: string } - | { operationType: string; sourceField: never } -); - -export const renameColumns: ExpressionFunctionDefinition< - 'lens_rename_columns', - Datatable, - RemapArgs, - Datatable -> = { +export const renameColumns: RenameColumnsExpressionFunction = { name: 'lens_rename_columns', type: 'datatable', help: i18n.translate('xpack.lens.functions.renameColumns.help', { @@ -42,53 +24,9 @@ export const renameColumns: ExpressionFunctionDefinition< }, }, inputTypes: ['datatable'], - fn(data, { idMap: encodedIdMap }) { - const idMap = JSON.parse(encodedIdMap) as Record; - - return { - type: 'datatable', - rows: data.rows.map((row) => { - const mappedRow: Record = {}; - Object.entries(idMap).forEach(([fromId, toId]) => { - mappedRow[toId.id] = row[fromId]; - }); - - Object.entries(row).forEach(([id, value]) => { - if (id in idMap) { - mappedRow[idMap[id].id] = value; - } else { - mappedRow[id] = value; - } - }); - - return mappedRow; - }), - columns: data.columns.map((column) => { - const mappedItem = idMap[column.id]; - - if (!mappedItem) { - return column; - } - - return { - ...column, - id: mappedItem.id, - name: getColumnName(mappedItem, column), - }; - }), - }; + async fn(...args) { + /** Build optimization: prevent adding extra code into initial bundle **/ + const { renameColumnFn } = await import('./rename_columns_fn'); + return renameColumnFn(...args); }, }; - -function getColumnName(originalColumn: OriginalColumn, newColumn: DatatableColumn) { - if (originalColumn?.operationType === 'date_histogram') { - const fieldName = originalColumn.sourceField; - - // HACK: This is a hack, and introduces some fragility into - // column naming. Eventually, this should be calculated and - // built more systematically. - return newColumn.name.replace(fieldName, originalColumn.label); - } - - return originalColumn.label; -} diff --git a/x-pack/plugins/lens/common/expressions/rename_columns/rename_columns_fn.ts b/x-pack/plugins/lens/common/expressions/rename_columns/rename_columns_fn.ts new file mode 100644 index 0000000000000..ee0c7ed1eebec --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/rename_columns/rename_columns_fn.ts @@ -0,0 +1,62 @@ +/* + * 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 { DatatableColumn } from '../../../../../../src/plugins/expressions/common'; +import type { OriginalColumn, RenameColumnsExpressionFunction } from './types'; + +function getColumnName(originalColumn: OriginalColumn, newColumn: DatatableColumn) { + if (originalColumn?.operationType === 'date_histogram') { + const fieldName = originalColumn.sourceField; + + // HACK: This is a hack, and introduces some fragility into + // column naming. Eventually, this should be calculated and + // built more systematically. + return newColumn.name.replace(fieldName, originalColumn.label); + } + + return originalColumn.label; +} + +export const renameColumnFn: RenameColumnsExpressionFunction['fn'] = ( + data, + { idMap: encodedIdMap } +) => { + const idMap = JSON.parse(encodedIdMap) as Record; + + return { + type: 'datatable', + rows: data.rows.map((row) => { + const mappedRow: Record = {}; + Object.entries(idMap).forEach(([fromId, toId]) => { + mappedRow[toId.id] = row[fromId]; + }); + + Object.entries(row).forEach(([id, value]) => { + if (id in idMap) { + mappedRow[idMap[id].id] = value; + } else { + mappedRow[id] = value; + } + }); + + return mappedRow; + }), + columns: data.columns.map((column) => { + const mappedItem = idMap[column.id]; + + if (!mappedItem) { + return column; + } + + return { + ...column, + id: mappedItem.id, + name: getColumnName(mappedItem, column), + }; + }), + }; +}; diff --git a/x-pack/plugins/lens/common/expressions/rename_columns/types.ts b/x-pack/plugins/lens/common/expressions/rename_columns/types.ts new file mode 100644 index 0000000000000..685ccfb89e4ca --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/rename_columns/types.ts @@ -0,0 +1,22 @@ +/* + * 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 { Datatable, ExpressionFunctionDefinition } from '../../../../../../src/plugins/expressions'; + +export type OriginalColumn = { id: string; label: string } & ( + | { operationType: 'date_histogram'; sourceField: string } + | { operationType: string; sourceField: never } +); + +export type RenameColumnsExpressionFunction = ExpressionFunctionDefinition< + 'lens_rename_columns', + Datatable, + { + idMap: string; + }, + Datatable | Promise +>; diff --git a/x-pack/plugins/lens/common/expressions/time_scale/index.ts b/x-pack/plugins/lens/common/expressions/time_scale/index.ts index 92fec01a9ecbc..b5bd7dbcbb074 100644 --- a/x-pack/plugins/lens/common/expressions/time_scale/index.ts +++ b/x-pack/plugins/lens/common/expressions/time_scale/index.ts @@ -5,5 +5,5 @@ * 2.0. */ -export * from './time_scale'; -export * from './types'; +export { getTimeScale } from './time_scale'; +export type { TimeScaleUnit, TimeScaleArgs } from './types'; diff --git a/x-pack/plugins/lens/common/expressions/time_scale/time_scale.test.ts b/x-pack/plugins/lens/common/expressions/time_scale/time_scale.test.ts index 9f299d9e3d74f..d51f2594b4267 100644 --- a/x-pack/plugins/lens/common/expressions/time_scale/time_scale.test.ts +++ b/x-pack/plugins/lens/common/expressions/time_scale/time_scale.test.ts @@ -6,8 +6,8 @@ */ import moment from 'moment'; -import { Datatable } from 'src/plugins/expressions/public'; -import { TimeRange } from 'src/plugins/data/public'; +import type { Datatable } from 'src/plugins/expressions/public'; +import type { TimeRange } from 'src/plugins/data/public'; import { functionWrapper } from 'src/plugins/expressions/common/expression_functions/specs/tests/utils'; // mock the specific inner variable: @@ -22,7 +22,8 @@ jest.mock('../../../../../../src/plugins/data/common/query/timefilter/get_time', }; }); -import { getTimeScale, TimeScaleArgs } from './time_scale'; +import { getTimeScale } from './time_scale'; +import type { TimeScaleArgs } from './types'; describe('time_scale', () => { let timeScaleWrapped: (input: Datatable, args: TimeScaleArgs) => Promise; diff --git a/x-pack/plugins/lens/common/expressions/time_scale/time_scale.ts b/x-pack/plugins/lens/common/expressions/time_scale/time_scale.ts index 711b770fb140f..21bef6de980ac 100644 --- a/x-pack/plugins/lens/common/expressions/time_scale/time_scale.ts +++ b/x-pack/plugins/lens/common/expressions/time_scale/time_scale.ts @@ -5,46 +5,12 @@ * 2.0. */ -import moment from 'moment-timezone'; -import { i18n } from '@kbn/i18n'; -import type { - ExpressionFunctionDefinition, - Datatable, -} from '../../../../../../src/plugins/expressions/common'; -import { - getDateHistogramMetaDataByDatatableColumn, - parseInterval, - calculateBounds, -} from '../../../../../../src/plugins/data/common'; -import { - buildResultColumns, - ExecutionContext, -} from '../../../../../../src/plugins/expressions/common'; -import type { TimeScaleUnit } from './types'; - -export interface TimeScaleArgs { - dateColumnId: string; - inputColumnId: string; - outputColumnId: string; - targetUnit: TimeScaleUnit; - outputColumnName?: string; -} - -const unitInMs: Record = { - s: 1000, - m: 1000 * 60, - h: 1000 * 60 * 60, - d: 1000 * 60 * 60 * 24, -}; +import type { ExecutionContext } from '../../../../../../src/plugins/expressions/common'; +import type { TimeScaleExpressionFunction } from './types'; export const getTimeScale = ( getTimezone: (context: ExecutionContext) => string | Promise -): ExpressionFunctionDefinition< - 'lens_time_scale', - Datatable, - TimeScaleArgs, - Promise -> => ({ +): TimeScaleExpressionFunction => ({ name: 'lens_time_scale', type: 'datatable', help: '', @@ -76,84 +42,9 @@ export const getTimeScale = ( }, }, inputTypes: ['datatable'], - async fn( - input, - { dateColumnId, inputColumnId, outputColumnId, outputColumnName, targetUnit }: TimeScaleArgs, - context - ) { - const dateColumnDefinition = input.columns.find((column) => column.id === dateColumnId); - - if (!dateColumnDefinition) { - throw new Error( - i18n.translate('xpack.lens.functions.timeScale.dateColumnMissingMessage', { - defaultMessage: 'Specified dateColumnId {columnId} does not exist.', - values: { - columnId: dateColumnId, - }, - }) - ); - } - - const resultColumns = buildResultColumns( - input, - outputColumnId, - inputColumnId, - outputColumnName, - { allowColumnOverwrite: true } - ); - - if (!resultColumns) { - return input; - } - - const targetUnitInMs = unitInMs[targetUnit]; - const timeInfo = getDateHistogramMetaDataByDatatableColumn(dateColumnDefinition, { - timeZone: await getTimezone(context), - }); - const intervalDuration = timeInfo?.interval && parseInterval(timeInfo.interval); - - if (!timeInfo || !intervalDuration) { - throw new Error( - i18n.translate('xpack.lens.functions.timeScale.timeInfoMissingMessage', { - defaultMessage: 'Could not fetch date histogram information', - }) - ); - } - // the datemath plugin always parses dates by using the current default moment time zone. - // to use the configured time zone, we are switching just for the bounds calculation. - const defaultTimezone = moment().zoneName(); - moment.tz.setDefault(timeInfo.timeZone); - - const timeBounds = timeInfo.timeRange && calculateBounds(timeInfo.timeRange); - - const result = { - ...input, - columns: resultColumns, - rows: input.rows.map((row) => { - const newRow = { ...row }; - - let startOfBucket = moment(row[dateColumnId]); - let endOfBucket = startOfBucket.clone().add(intervalDuration); - if (timeBounds && timeBounds.min) { - startOfBucket = moment.max(startOfBucket, timeBounds.min); - } - if (timeBounds && timeBounds.max) { - endOfBucket = moment.min(endOfBucket, timeBounds.max); - } - const bucketSize = endOfBucket.diff(startOfBucket); - const factor = bucketSize / targetUnitInMs; - - const currentValue = newRow[inputColumnId]; - if (currentValue != null) { - newRow[outputColumnId] = Number(currentValue) / factor; - } - - return newRow; - }), - }; - // reset default moment timezone - moment.tz.setDefault(defaultTimezone); - - return result; + async fn(...args) { + /** Build optimization: prevent adding extra code into initial bundle **/ + const { timeScaleFn } = await import('./time_scale_fn'); + return timeScaleFn(getTimezone)(...args); }, }); diff --git a/x-pack/plugins/lens/common/expressions/time_scale/time_scale_fn.ts b/x-pack/plugins/lens/common/expressions/time_scale/time_scale_fn.ts new file mode 100644 index 0000000000000..e6113afebca22 --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/time_scale/time_scale_fn.ts @@ -0,0 +1,105 @@ +/* + * 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 moment from 'moment-timezone'; +import { i18n } from '@kbn/i18n'; +import { + buildResultColumns, + ExecutionContext, +} from '../../../../../../src/plugins/expressions/common'; +import { + calculateBounds, + getDateHistogramMetaDataByDatatableColumn, + parseInterval, +} from '../../../../../../src/plugins/data/common'; +import type { TimeScaleExpressionFunction, TimeScaleUnit, TimeScaleArgs } from './types'; + +const unitInMs: Record = { + s: 1000, + m: 1000 * 60, + h: 1000 * 60 * 60, + d: 1000 * 60 * 60 * 24, +}; + +export const timeScaleFn = ( + getTimezone: (context: ExecutionContext) => string | Promise +): TimeScaleExpressionFunction['fn'] => async ( + input, + { dateColumnId, inputColumnId, outputColumnId, outputColumnName, targetUnit }: TimeScaleArgs, + context +) => { + const dateColumnDefinition = input.columns.find((column) => column.id === dateColumnId); + + if (!dateColumnDefinition) { + throw new Error( + i18n.translate('xpack.lens.functions.timeScale.dateColumnMissingMessage', { + defaultMessage: 'Specified dateColumnId {columnId} does not exist.', + values: { + columnId: dateColumnId, + }, + }) + ); + } + + const resultColumns = buildResultColumns(input, outputColumnId, inputColumnId, outputColumnName, { + allowColumnOverwrite: true, + }); + + if (!resultColumns) { + return input; + } + + const targetUnitInMs = unitInMs[targetUnit]; + const timeInfo = getDateHistogramMetaDataByDatatableColumn(dateColumnDefinition, { + timeZone: await getTimezone(context), + }); + const intervalDuration = timeInfo?.interval && parseInterval(timeInfo.interval); + + if (!timeInfo || !intervalDuration) { + throw new Error( + i18n.translate('xpack.lens.functions.timeScale.timeInfoMissingMessage', { + defaultMessage: 'Could not fetch date histogram information', + }) + ); + } + // the datemath plugin always parses dates by using the current default moment time zone. + // to use the configured time zone, we are switching just for the bounds calculation. + const defaultTimezone = moment().zoneName(); + moment.tz.setDefault(timeInfo.timeZone); + + const timeBounds = timeInfo.timeRange && calculateBounds(timeInfo.timeRange); + + const result = { + ...input, + columns: resultColumns, + rows: input.rows.map((row) => { + const newRow = { ...row }; + + let startOfBucket = moment(row[dateColumnId]); + let endOfBucket = startOfBucket.clone().add(intervalDuration); + if (timeBounds && timeBounds.min) { + startOfBucket = moment.max(startOfBucket, timeBounds.min); + } + if (timeBounds && timeBounds.max) { + endOfBucket = moment.min(endOfBucket, timeBounds.max); + } + const bucketSize = endOfBucket.diff(startOfBucket); + const factor = bucketSize / targetUnitInMs; + + const currentValue = newRow[inputColumnId]; + if (currentValue != null) { + newRow[outputColumnId] = Number(currentValue) / factor; + } + + return newRow; + }), + }; + // reset default moment timezone + moment.tz.setDefault(defaultTimezone); + + return result; +}; diff --git a/x-pack/plugins/lens/common/expressions/time_scale/types.ts b/x-pack/plugins/lens/common/expressions/time_scale/types.ts index 4ee00ce53e68b..58c5e5723a7c1 100644 --- a/x-pack/plugins/lens/common/expressions/time_scale/types.ts +++ b/x-pack/plugins/lens/common/expressions/time_scale/types.ts @@ -5,4 +5,24 @@ * 2.0. */ +import type { + Datatable, + ExpressionFunctionDefinition, +} from '../../../../../../src/plugins/expressions'; + export type TimeScaleUnit = 's' | 'm' | 'h' | 'd'; + +export interface TimeScaleArgs { + dateColumnId: string; + inputColumnId: string; + outputColumnId: string; + targetUnit: TimeScaleUnit; + outputColumnName?: string; +} + +export type TimeScaleExpressionFunction = ExpressionFunctionDefinition< + 'lens_time_scale', + Datatable, + TimeScaleArgs, + Promise +>; diff --git a/x-pack/plugins/lens/public/app_plugin/mounter.tsx b/x-pack/plugins/lens/public/app_plugin/mounter.tsx index 5bd0fa9594bdf..de091fd305e85 100644 --- a/x-pack/plugins/lens/public/app_plugin/mounter.tsx +++ b/x-pack/plugins/lens/public/app_plugin/mounter.tsx @@ -45,7 +45,7 @@ import { getPreloadedState } from '../state_management/lens_slice'; export async function getLensServices( coreStart: CoreStart, startDependencies: LensPluginStartDependencies, - attributeService: () => Promise + attributeService: LensAttributeService ): Promise { const { data, @@ -71,7 +71,7 @@ export async function getLensServices( stateTransfer, usageCollection, savedObjectsTagging, - attributeService: await attributeService(), + attributeService, http: coreStart.http, chrome: coreStart.chrome, overlays: coreStart.overlays, @@ -97,8 +97,8 @@ export async function mountApp( params: AppMountParameters, mountProps: { createEditorFrame: EditorFrameStart['createInstance']; - attributeService: () => Promise; - getPresentationUtilContext: () => Promise; + attributeService: LensAttributeService; + getPresentationUtilContext: () => FC; } ) { const { createEditorFrame, attributeService, getPresentationUtilContext } = mountProps; @@ -252,7 +252,7 @@ export async function mountApp( params.element.classList.add('lnsAppWrapper'); - const PresentationUtilContext = await getPresentationUtilContext(); + const PresentationUtilContext = getPresentationUtilContext(); render( diff --git a/x-pack/plugins/lens/public/app_plugin/shared/saved_modal_lazy.tsx b/x-pack/plugins/lens/public/app_plugin/shared/saved_modal_lazy.tsx index f1a537fe65928..e1df6ca60dd6e 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/saved_modal_lazy.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/saved_modal_lazy.tsx @@ -8,11 +8,11 @@ import React, { Suspense, useEffect, useState } from 'react'; import { EuiLoadingSpinner, EuiOverlayMask } from '@elastic/eui'; -import { CoreStart } from 'kibana/public'; +import type { CoreStart } from 'kibana/public'; import type { SaveModalContainerProps } from '../save_modal_container'; -import type { LensAttributeService } from '../../lens_attribute_service'; import type { LensPluginStartDependencies } from '../../plugin'; import type { LensAppServices } from '../types'; + const SaveModal = React.lazy(() => import('../save_modal_container')); function LoadingSpinnerWithOverlay() { @@ -33,16 +33,20 @@ const LensSavedModalLazy = (props: SaveModalContainerProps) => { export function getSaveModalComponent( coreStart: CoreStart, - startDependencies: LensPluginStartDependencies, - attributeService: () => Promise + startDependencies: LensPluginStartDependencies ) { return (props: Omit) => { const [lensServices, setLensServices] = useState(); useEffect(() => { async function loadLensService() { - const { getLensServices } = await import('../../async_services'); - const lensServicesT = await getLensServices(coreStart, startDependencies, attributeService); + const { getLensServices, getLensAttributeService } = await import('../../async_services'); + + const lensServicesT = await getLensServices( + coreStart, + startDependencies, + getLensAttributeService(coreStart, startDependencies) + ); setLensServices(lensServicesT); } diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.tsx index ac1324385dbd1..6f00dc37fcd52 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.tsx @@ -20,7 +20,7 @@ import { } from '@elastic/eui'; import type { LensFilterEvent, LensTableRowContextMenuEvent } from '../../types'; import type { FormatFactory } from '../../../common'; -import { LensGridDirection } from '../../../common/expressions'; +import type { LensGridDirection } from '../../../common/expressions'; import { VisualizationContainer } from '../../visualization_container'; import { EmptyPlaceholder, findMinMaxByColumnId } from '../../shared_components'; import { LensIconChartDatatable } from '../../assets/chart_datatable'; diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx index b2a25cba329df..74c33a2b02a5b 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx @@ -9,7 +9,7 @@ import type { DatatableProps } from '../../common/expressions'; import type { LensMultiTable } from '../../common'; import { createMockExecutionContext } from '../../../../../src/plugins/expressions/common/mocks'; import type { FormatFactory } from '../../common'; -import { getDatatable } from './expression'; +import { getDatatable } from '../../common/expressions'; function sampleArgs() { const indexPatternId = 'indexPatternId'; diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 4e541bce9a8c2..03691d56ee56a 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -18,9 +18,7 @@ import { DatatableComponent } from './components/table_basic'; import type { ILensInterpreterRenderHandlers } from '../types'; import type { FormatFactory } from '../../common'; -import { DatatableProps } from '../../common/expressions'; - -export { datatableColumn, getDatatable } from '../../common/expressions'; +import type { DatatableProps } from '../../common/expressions'; export const getDatatableRenderer = (dependencies: { formatFactory: FormatFactory; diff --git a/x-pack/plugins/lens/public/datatable_visualization/index.ts b/x-pack/plugins/lens/public/datatable_visualization/index.ts index 3349f229a6048..51f1f54cc03ce 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/index.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/index.ts @@ -23,23 +23,14 @@ export interface DatatableVisualizationPluginSetupPlugins { } export class DatatableVisualization { - constructor() {} - setup( core: CoreSetup, { expressions, formatFactory, editorFrame, charts }: DatatableVisualizationPluginSetupPlugins ) { editorFrame.registerVisualization(async () => { - const { - getDatatable, - datatableColumn, - getDatatableRenderer, - getDatatableVisualization, - } = await import('../async_services'); + const { getDatatableRenderer, getDatatableVisualization } = await import('../async_services'); const palettes = await charts.palettes.getPalettes(); - expressions.registerFunction(() => datatableColumn); - expressions.registerFunction(() => getDatatable(() => formatFactory)); expressions.registerRenderer(() => getDatatableRenderer({ formatFactory, @@ -50,6 +41,7 @@ export class DatatableVisualization { uiSettings: core.uiSettings, }) ); + return getDatatableVisualization({ paletteService: palettes }); }); } diff --git a/x-pack/plugins/lens/public/editor_frame_service/service.tsx b/x-pack/plugins/lens/public/editor_frame_service/service.tsx index e1b1c637fa24b..d97cfd3cbca23 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/service.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/service.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { CoreSetup, CoreStart } from 'kibana/public'; +import { CoreStart } from 'kibana/public'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; import { ExpressionsSetup, ExpressionsStart } from '../../../../../src/plugins/expressions/public'; import { EmbeddableSetup, EmbeddableStart } from '../../../../../src/plugins/embeddable/public'; @@ -22,7 +22,6 @@ import { EditorFrameStart, } from '../types'; import { Document } from '../persistence/saved_object_store'; -import { mergeTables } from '../../common/expressions'; import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; import { ChartsPluginSetup } from '../../../../../src/plugins/charts/public'; import { DashboardStart } from '../../../../../src/plugins/dashboard/public'; @@ -59,8 +58,6 @@ async function collectAsyncDefinitions( } export class EditorFrameService { - constructor() {} - private readonly datasources: Array Promise)> = []; private readonly visualizations: Array Promise)> = []; @@ -81,12 +78,7 @@ export class EditorFrameService { return await persistedStateToExpression(resolvedDatasources, resolvedVisualizations, doc); }; - public setup( - core: CoreSetup, - plugins: EditorFrameSetupPlugins - ): EditorFrameSetup { - plugins.expressions.registerFunction(() => mergeTables); - + public setup(): EditorFrameSetup { return { registerDatasource: (datasource) => { this.datasources.push(datasource as Datasource); diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx index e8095f6c741a4..7f65e50bf4429 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx @@ -6,8 +6,8 @@ */ import React, { FC, useEffect } from 'react'; -import { CoreStart } from 'kibana/public'; -import { UiActionsStart } from 'src/plugins/ui_actions/public'; +import type { CoreStart } from 'kibana/public'; +import type { UiActionsStart } from 'src/plugins/ui_actions/public'; import type { Start as InspectorStartContract } from 'src/plugins/inspector/public'; import { EuiLoadingChart } from '@elastic/eui'; import { diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts b/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts index 5620f053cebf2..954905c51a4b7 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts +++ b/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts @@ -21,7 +21,7 @@ import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; import { Start as InspectorStart } from '../../../../../src/plugins/inspector/public'; import { Document } from '../persistence/saved_object_store'; import { LensAttributeService } from '../lens_attribute_service'; -import { DOC_TYPE } from '../../common'; +import { DOC_TYPE } from '../../common/constants'; import { ErrorMessage } from '../editor_frame_service/types'; import { extract, inject } from '../../common/embeddable_factory'; diff --git a/x-pack/plugins/lens/public/expressions.ts b/x-pack/plugins/lens/public/expressions.ts new file mode 100644 index 0000000000000..27f3179a2d0c8 --- /dev/null +++ b/x-pack/plugins/lens/public/expressions.ts @@ -0,0 +1,64 @@ +/* + * 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 { ExpressionsSetup } from 'src/plugins/expressions/public'; + +import { + axisExtentConfig, + yAxisConfig, + axisTitlesVisibilityConfig, +} from '../common/expressions/xy_chart/axis_config'; +import { gridlinesConfig } from '../common/expressions/xy_chart/grid_lines_config'; +import { labelsOrientationConfig } from '../common/expressions/xy_chart/labels_orientation_config'; +import { layerConfig } from '../common/expressions/xy_chart/layer_config'; +import { legendConfig } from '../common/expressions/xy_chart/legend_config'; +import { tickLabelsConfig } from '../common/expressions/xy_chart/tick_labels_config'; +import { xyChart } from '../common/expressions/xy_chart/xy_chart'; + +import { getDatatable } from '../common/expressions/datatable/datatable'; +import { datatableColumn } from '../common/expressions/datatable/datatable_column'; + +import { heatmap } from '../common/expressions/heatmap_chart/heatmap_chart'; +import { heatmapGridConfig } from '../common/expressions/heatmap_chart/heatmap_grid'; +import { heatmapLegendConfig } from '../common/expressions/heatmap_chart/heatmap_legend'; + +import { mergeTables } from '../common/expressions/merge_tables'; +import { renameColumns } from '../common/expressions/rename_columns/rename_columns'; +import { pie } from '../common/expressions/pie_chart/pie_chart'; +import { formatColumn } from '../common/expressions/format_column'; +import { counterRate } from '../common/expressions/counter_rate'; +import { getTimeScale } from '../common/expressions/time_scale/time_scale'; +import { metricChart } from '../common/expressions/metric_chart/metric_chart'; + +export const setupExpressions = ( + expressions: ExpressionsSetup, + formatFactory: Parameters[0], + getTimeZone: Parameters[0] +) => + [ + pie, + xyChart, + mergeTables, + counterRate, + metricChart, + yAxisConfig, + layerConfig, + formatColumn, + legendConfig, + renameColumns, + gridlinesConfig, + datatableColumn, + tickLabelsConfig, + axisTitlesVisibilityConfig, + heatmap, + heatmapLegendConfig, + heatmapGridConfig, + axisExtentConfig, + labelsOrientationConfig, + getDatatable(formatFactory), + getTimeScale(getTimeZone), + ].forEach((expressionFn) => expressions.registerFunction(expressionFn)); diff --git a/x-pack/plugins/lens/public/heatmap_visualization/expression.tsx b/x-pack/plugins/lens/public/heatmap_visualization/expression.tsx index 98ce4b399ae8d..84c8f987f524d 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/heatmap_visualization/expression.tsx @@ -17,8 +17,6 @@ import type { ChartsPluginSetup, PaletteRegistry } from '../../../../../src/plug import { HeatmapChartReportable } from './chart_component'; import type { HeatmapExpressionProps } from './types'; -export { heatmapGridConfig, heatmapLegendConfig, heatmap } from '../../common/expressions'; - export const getHeatmapRenderer = (dependencies: { formatFactory: FormatFactory; chartsThemeService: ChartsPluginSetup['theme']; diff --git a/x-pack/plugins/lens/public/heatmap_visualization/index.ts b/x-pack/plugins/lens/public/heatmap_visualization/index.ts index 5fb4524939f11..3ac3f769e4b5f 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/index.ts +++ b/x-pack/plugins/lens/public/heatmap_visualization/index.ts @@ -20,28 +20,15 @@ export interface HeatmapVisualizationPluginSetupPlugins { } export class HeatmapVisualization { - constructor() {} - setup( core: CoreSetup, { expressions, formatFactory, editorFrame, charts }: HeatmapVisualizationPluginSetupPlugins ) { editorFrame.registerVisualization(async () => { const timeZone = getTimeZone(core.uiSettings); - - const { - getHeatmapVisualization, - heatmap, - heatmapLegendConfig, - heatmapGridConfig, - getHeatmapRenderer, - } = await import('../async_services'); + const { getHeatmapVisualization, getHeatmapRenderer } = await import('../async_services'); const palettes = await charts.palettes.getPalettes(); - expressions.registerFunction(() => heatmap); - expressions.registerFunction(() => heatmapLegendConfig); - expressions.registerFunction(() => heatmapGridConfig); - expressions.registerRenderer( getHeatmapRenderer({ formatFactory, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/time_scaling.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/time_scaling.tsx index 7c611230683d3..8a670e7562573 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/time_scaling.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/time_scaling.tsx @@ -5,9 +5,16 @@ * 2.0. */ -import { EuiToolTip } from '@elastic/eui'; -import { EuiIcon } from '@elastic/eui'; -import { EuiFormRow, EuiSelect, EuiFlexItem, EuiFlexGroup, EuiButtonIcon } from '@elastic/eui'; +import { + EuiToolTip, + EuiIcon, + EuiFormRow, + EuiSelect, + EuiFlexItem, + EuiFlexGroup, + EuiButtonIcon, +} from '@elastic/eui'; + import { i18n } from '@kbn/i18n'; import React from 'react'; import { @@ -17,7 +24,7 @@ import { } from '../operations'; import type { TimeScaleUnit } from '../../../common/expressions'; import { unitSuffixesLong } from '../../../common/suffix_formatter'; -import { IndexPatternLayer } from '../types'; +import type { IndexPatternLayer } from '../types'; export function setTimeScaling( columnId: string, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/index.ts b/x-pack/plugins/lens/public/indexpattern_datasource/index.ts index 9ff80f51bea97..5f4afc9df6179 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/index.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/index.ts @@ -20,7 +20,6 @@ import type { FieldFormatsStart, FieldFormatsSetup, } from '../../../../../src/plugins/field_formats/public'; -import { getTimeZone } from '../utils'; export interface IndexPatternDatasourceSetupPlugins { expressions: ExpressionsSetup; @@ -38,8 +37,6 @@ export interface IndexPatternDatasourceStartPlugins { } export class IndexPatternDatasource { - constructor() {} - setup( core: CoreSetup, { @@ -50,15 +47,9 @@ export class IndexPatternDatasource { }: IndexPatternDatasourceSetupPlugins ) { editorFrame.registerDatasource(async () => { - const { - getIndexPatternDatasource, - renameColumns, - formatColumn, - counterRate, - getTimeScale, - getSuffixFormatter, - suffixFormatterId, - } = await import('../async_services'); + const { getIndexPatternDatasource, getSuffixFormatter, suffixFormatterId } = await import( + '../async_services' + ); if (!fieldFormatsSetup.has(suffixFormatterId)) { const startServices = createStartServicesGetter(core.getStartServices); @@ -69,11 +60,6 @@ export class IndexPatternDatasource { fieldFormatsSetup.register([suffixFormatter]); } - expressions.registerFunction(getTimeScale(() => getTimeZone(core.uiSettings))); - expressions.registerFunction(counterRate); - expressions.registerFunction(renameColumns); - expressions.registerFunction(formatColumn); - const [ coreStart, { indexPatternFieldEditor, uiActions, data, fieldFormats }, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx index 8f66bcf7fe49c..6a45e3c987f3d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx @@ -70,19 +70,13 @@ export function columnToOperation(column: IndexPatternColumn, uniqueLabel?: stri }; } -export { - CounterRateArgs, - ExpressionFunctionCounterRate, - counterRate, -} from '../../common/expressions'; -export { FormatColumnArgs, supportedFormats, formatColumn } from '../../common/expressions'; +export type { FormatColumnArgs, TimeScaleArgs, CounterRateArgs } from '../../common/expressions'; + export { getSuffixFormatter, unitSuffixesLong, suffixFormatterId, } from '../../common/suffix_formatter'; -export { getTimeScale, TimeScaleArgs } from '../../common/expressions'; -export { renameColumns } from '../../common/expressions'; export function getIndexPatternDatasource({ core, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts index cff036db4813b..b0793bf912bb2 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts @@ -8,7 +8,7 @@ import { flatten, minBy, pick, mapValues, partition } from 'lodash'; import { i18n } from '@kbn/i18n'; import { generateId } from '../id_generator'; -import { DatasourceSuggestion, TableChangeType } from '../types'; +import type { DatasourceSuggestion, TableChangeType } from '../types'; import { columnToOperation } from './indexpattern'; import { insertNewColumn, @@ -23,7 +23,7 @@ import { getReferencedColumnIds, } from './operations'; import { hasField } from './utils'; -import { +import type { IndexPattern, IndexPatternPrivateState, IndexPatternLayer, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx index ceb02ab724ac5..29e7de18ca4ad 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx @@ -21,7 +21,7 @@ import { RangeEditor } from './range_editor'; import { OperationDefinition } from '../index'; import { FieldBasedIndexPatternColumn } from '../column_types'; import { updateColumnParam } from '../../layer_helpers'; -import { supportedFormats } from '../../../../../common/expressions'; +import { supportedFormats } from '../../../../../common/expressions/format_column/supported_formats'; import { MODES, AUTO_BARS, DEFAULT_INTERVAL, MIN_HISTOGRAM_BARS, SLICES } from './constants'; import { IndexPattern, IndexPatternField } from '../../../types'; import { getInvalidFieldMessage, isValidNumber } from '../helpers'; diff --git a/x-pack/plugins/lens/public/lens_attribute_service.ts b/x-pack/plugins/lens/public/lens_attribute_service.ts index 09c98b3dcba72..fb4ef4fee72ef 100644 --- a/x-pack/plugins/lens/public/lens_attribute_service.ts +++ b/x-pack/plugins/lens/public/lens_attribute_service.ts @@ -5,17 +5,17 @@ * 2.0. */ -import { CoreStart } from '../../../../src/core/public'; -import { LensPluginStartDependencies } from './plugin'; -import { AttributeService } from '../../../../src/plugins/embeddable/public'; -import { +import type { CoreStart } from '../../../../src/core/public'; +import type { LensPluginStartDependencies } from './plugin'; +import type { AttributeService } from '../../../../src/plugins/embeddable/public'; +import type { ResolvedLensSavedObjectAttributes, LensByValueInput, LensByReferenceInput, } from './embeddable/embeddable'; import { SavedObjectIndexStore } from './persistence'; import { checkForDuplicateTitle, OnSaveProps } from '../../../../src/plugins/saved_objects/public'; -import { DOC_TYPE } from '../common'; +import { DOC_TYPE } from '../common/constants'; export type LensAttributeService = AttributeService< ResolvedLensSavedObjectAttributes, diff --git a/x-pack/plugins/lens/public/metric_visualization/expression.test.tsx b/x-pack/plugins/lens/public/metric_visualization/expression.test.tsx index 36ae3904f073c..a3ac5b5837772 100644 --- a/x-pack/plugins/lens/public/metric_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/metric_visualization/expression.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { MetricChart, metricChart } from './expression'; -import { MetricConfig } from '../../common/expressions'; +import { MetricChart } from './expression'; +import { MetricConfig, metricChart } from '../../common/expressions'; import React from 'react'; import { shallow } from 'enzyme'; import { createMockExecutionContext } from '../../../../../src/plugins/expressions/common/mocks'; diff --git a/x-pack/plugins/lens/public/metric_visualization/expression.tsx b/x-pack/plugins/lens/public/metric_visualization/expression.tsx index 41b487e790a08..8838e6df777c9 100644 --- a/x-pack/plugins/lens/public/metric_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/metric_visualization/expression.tsx @@ -19,9 +19,7 @@ import { EmptyPlaceholder } from '../shared_components'; import { LensIconChartMetric } from '../assets/chart_metric'; import type { FormatFactory } from '../../common'; import type { MetricChartProps } from '../../common/expressions'; - -export { metricChart } from '../../common/expressions'; -export type { MetricState, MetricConfig } from '../../common/expressions'; +export type { MetricChartProps, MetricState, MetricConfig } from '../../common/expressions'; export const getMetricChartRenderer = ( formatFactory: FormatFactory diff --git a/x-pack/plugins/lens/public/metric_visualization/index.ts b/x-pack/plugins/lens/public/metric_visualization/index.ts index 29138979ab858..20c25b285bd5b 100644 --- a/x-pack/plugins/lens/public/metric_visualization/index.ts +++ b/x-pack/plugins/lens/public/metric_visualization/index.ts @@ -17,18 +17,12 @@ export interface MetricVisualizationPluginSetupPlugins { } export class MetricVisualization { - constructor() {} - setup( _core: CoreSetup | null, { expressions, formatFactory, editorFrame }: MetricVisualizationPluginSetupPlugins ) { editorFrame.registerVisualization(async () => { - const { metricVisualization, metricChart, getMetricChartRenderer } = await import( - '../async_services' - ); - - expressions.registerFunction(() => metricChart); + const { metricVisualization, getMetricChartRenderer } = await import('../async_services'); expressions.registerRenderer(() => getMetricChartRenderer(formatFactory)); return metricVisualization; diff --git a/x-pack/plugins/lens/public/metric_visualization/metric_suggestions.ts b/x-pack/plugins/lens/public/metric_visualization/metric_suggestions.ts index de79f5f0a4cbc..3d6b2683b4ad2 100644 --- a/x-pack/plugins/lens/public/metric_visualization/metric_suggestions.ts +++ b/x-pack/plugins/lens/public/metric_visualization/metric_suggestions.ts @@ -6,7 +6,7 @@ */ import { SuggestionRequest, VisualizationSuggestion, TableSuggestion } from '../types'; -import { MetricState } from '../../common/expressions'; +import type { MetricState } from '../../common/expressions'; import { layerTypes } from '../../common'; import { LensIconChartMetric } from '../assets/chart_metric'; diff --git a/x-pack/plugins/lens/public/pie_visualization/expression.tsx b/x-pack/plugins/lens/public/pie_visualization/expression.tsx index c947d50d5b910..d26289450bd0f 100644 --- a/x-pack/plugins/lens/public/pie_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/expression.tsx @@ -19,8 +19,6 @@ import type { FormatFactory } from '../../common'; import type { PieExpressionProps } from '../../common/expressions'; import type { ChartsPluginSetup, PaletteRegistry } from '../../../../../src/plugins/charts/public'; -export { pie } from '../../common/expressions'; - export const getPieRenderer = (dependencies: { formatFactory: FormatFactory; chartsThemeService: ChartsPluginSetup['theme']; diff --git a/x-pack/plugins/lens/public/pie_visualization/index.ts b/x-pack/plugins/lens/public/pie_visualization/index.ts index 6d34de85f1801..b4670b3b9c9dd 100644 --- a/x-pack/plugins/lens/public/pie_visualization/index.ts +++ b/x-pack/plugins/lens/public/pie_visualization/index.ts @@ -24,18 +24,14 @@ export interface PieVisualizationPluginStartPlugins { } export class PieVisualization { - constructor() {} - setup( core: CoreSetup, { expressions, formatFactory, editorFrame, charts }: PieVisualizationPluginSetupPlugins ) { editorFrame.registerVisualization(async () => { - const { getPieVisualization, pie, getPieRenderer } = await import('../async_services'); + const { getPieVisualization, getPieRenderer } = await import('../async_services'); const palettes = await charts.palettes.getPalettes(); - expressions.registerFunction(() => pie); - expressions.registerRenderer( getPieRenderer({ formatFactory, diff --git a/x-pack/plugins/lens/public/plugin.ts b/x-pack/plugins/lens/public/plugin.ts index 26278f446c558..5326927d2c6c5 100644 --- a/x-pack/plugins/lens/public/plugin.ts +++ b/x-pack/plugins/lens/public/plugin.ts @@ -5,28 +5,34 @@ * 2.0. */ -import { AppMountParameters, CoreSetup, CoreStart } from 'kibana/public'; +import type { AppMountParameters, CoreSetup, CoreStart } from 'kibana/public'; import type { Start as InspectorStartContract } from 'src/plugins/inspector/public'; import type { FieldFormatsSetup, FieldFormatsStart } from 'src/plugins/field_formats/public'; -import { UsageCollectionSetup, UsageCollectionStart } from 'src/plugins/usage_collection/public'; -import { SpacesPluginStart } from '../../spaces/public'; -import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../../src/plugins/data/public'; -import { EmbeddableSetup, EmbeddableStart } from '../../../../src/plugins/embeddable/public'; -import { DashboardStart } from '../../../../src/plugins/dashboard/public'; -import { +import type { + UsageCollectionSetup, + UsageCollectionStart, +} from 'src/plugins/usage_collection/public'; +import type { + DataPublicPluginSetup, + DataPublicPluginStart, +} from '../../../../src/plugins/data/public'; +import type { EmbeddableSetup, EmbeddableStart } from '../../../../src/plugins/embeddable/public'; +import type { DashboardStart } from '../../../../src/plugins/dashboard/public'; +import type { SpacesPluginStart } from '../../spaces/public'; +import type { ExpressionsServiceSetup, ExpressionsSetup, ExpressionsStart, } from '../../../../src/plugins/expressions/public'; -import { +import type { VisualizationsSetup, VisualizationsStart, } from '../../../../src/plugins/visualizations/public'; -import { NavigationPublicPluginStart } from '../../../../src/plugins/navigation/public'; -import { UrlForwardingSetup } from '../../../../src/plugins/url_forwarding/public'; -import { GlobalSearchPluginSetup } from '../../global_search/public'; -import { ChartsPluginSetup, ChartsPluginStart } from '../../../../src/plugins/charts/public'; -import { PresentationUtilPluginStart } from '../../../../src/plugins/presentation_util/public'; +import type { NavigationPublicPluginStart } from '../../../../src/plugins/navigation/public'; +import type { UrlForwardingSetup } from '../../../../src/plugins/url_forwarding/public'; +import type { GlobalSearchPluginSetup } from '../../global_search/public'; +import type { ChartsPluginSetup, ChartsPluginStart } from '../../../../src/plugins/charts/public'; +import type { PresentationUtilPluginStart } from '../../../../src/plugins/presentation_util/public'; import { EmbeddableStateTransfer } from '../../../../src/plugins/embeddable/public'; import type { EditorFrameService as EditorFrameServiceType } from './editor_frame_service'; import { IndexPatternFieldEditorStart } from '../../../../src/plugins/index_pattern_field_editor/public'; @@ -51,29 +57,33 @@ import type { PieVisualizationPluginSetupPlugins, } from './pie_visualization'; import type { HeatmapVisualization as HeatmapVisualizationType } from './heatmap_visualization'; -import { AppNavLinkStatus } from '../../../../src/core/public'; import type { SavedObjectTaggingPluginStart } from '../../saved_objects_tagging/public'; +import { AppNavLinkStatus } from '../../../../src/core/public'; + import { UiActionsStart, ACTION_VISUALIZE_FIELD, VISUALIZE_FIELD_TRIGGER, } from '../../../../src/plugins/ui_actions/public'; -import { APP_ID, FormatFactory, getEditPath, NOT_INTERNATIONALIZED_PRODUCT_NAME } from '../common'; -import type { EditorFrameStart, VisualizationType } from './types'; +import { APP_ID, getEditPath, NOT_INTERNATIONALIZED_PRODUCT_NAME } from '../common/constants'; +import type { FormatFactory } from '../common/types'; +import type { VisualizationType } from './types'; import { getLensAliasConfig } from './vis_type_alias'; import { visualizeFieldAction } from './trigger_actions/visualize_field_actions'; -import { getSearchProvider } from './search_provider'; -import { LensAttributeService } from './lens_attribute_service'; -import { LensEmbeddableInput } from './embeddable'; +import type { LensEmbeddableInput } from './embeddable'; import { EmbeddableFactory, LensEmbeddableStartServices } from './embeddable/embeddable_factory'; import { EmbeddableComponentProps, getEmbeddableComponent, } from './embeddable/embeddable_component'; import { getSaveModalComponent } from './app_plugin/shared/saved_modal_lazy'; -import { SaveModalContainerProps } from './app_plugin/save_modal_container'; +import type { SaveModalContainerProps } from './app_plugin/save_modal_container'; + +import { createStartServicesGetter } from '../../../../src/plugins/kibana_utils/public'; +import { setupExpressions } from './expressions'; +import { getSearchProvider } from './search_provider'; export interface LensPluginSetupDependencies { urlForwarding: UrlForwardingSetup; @@ -154,8 +164,6 @@ export interface LensPublicStart { export class LensPlugin { private datatableVisualization: DatatableVisualizationType | undefined; private editorFrameService: EditorFrameServiceType | undefined; - private createEditorFrame: EditorFrameStart['createInstance'] | null = null; - private attributeService: (() => Promise) | null = null; private indexpatternDatasource: IndexPatternDatasourceType | undefined; private xyVisualization: XyVisualizationType | undefined; private metricVisualization: MetricVisualizationType | undefined; @@ -178,37 +186,32 @@ export class LensPlugin { usageCollection, }: LensPluginSetupDependencies ) { - this.attributeService = async () => { - const { getLensAttributeService } = await import('./async_services'); - const [coreStart, startDependencies] = await core.getStartServices(); - return getLensAttributeService(coreStart, startDependencies); - }; + const startServices = createStartServicesGetter(core.getStartServices); const getStartServices = async (): Promise => { - const [coreStart, deps] = await core.getStartServices(); + const { getLensAttributeService } = await import('./async_services'); + const { core: coreStart, plugins } = startServices(); - this.initParts( + await this.initParts( core, data, - embeddable, charts, expressions, - usageCollection, fieldFormats, - deps.fieldFormats.deserialize + plugins.fieldFormats.deserialize ); return { - attributeService: await this.attributeService!(), + attributeService: getLensAttributeService(coreStart, plugins), capabilities: coreStart.application.capabilities, coreHttp: coreStart.http, - timefilter: deps.data.query.timefilter.timefilter, - expressionRenderer: deps.expressions.ReactExpressionRenderer, + timefilter: plugins.data.query.timefilter.timefilter, + expressionRenderer: plugins.expressions.ReactExpressionRenderer, documentToExpression: this.editorFrameService!.documentToExpression, - indexPatternService: deps.data.indexPatterns, - uiActions: deps.uiActions, + indexPatternService: plugins.data.indexPatterns, + uiActions: plugins.uiActions, usageCollection, - inspector: deps.inspector, + inspector: plugins.inspector, }; }; @@ -218,17 +221,22 @@ export class LensPlugin { visualizations.registerAlias(getLensAliasConfig()); - const getPresentationUtilContext = async () => { - const [, deps] = await core.getStartServices(); - const { ContextProvider } = deps.presentationUtil; - return ContextProvider; - }; + setupExpressions( + expressions, + () => startServices().plugins.fieldFormats.deserialize, + async () => { + const { getTimeZone } = await import('./utils'); + return getTimeZone(core.uiSettings); + } + ); + + const getPresentationUtilContext = () => + startServices().plugins.presentationUtil.ContextProvider; const ensureDefaultIndexPattern = async () => { - const [, deps] = await core.getStartServices(); // make sure a default index pattern exists // if not, the page will be redirected to management and visualize won't be rendered - await deps.data.indexPatterns.ensureDefaultIndexPattern(); + await startServices().plugins.data.indexPatterns.ensureDefaultIndexPattern(); }; core.application.register({ @@ -236,25 +244,27 @@ export class LensPlugin { title: NOT_INTERNATIONALIZED_PRODUCT_NAME, navLinkStatus: AppNavLinkStatus.hidden, mount: async (params: AppMountParameters) => { - const [, deps] = await core.getStartServices(); + const { core: coreStart, plugins: deps } = startServices(); await this.initParts( core, data, - embeddable, charts, expressions, - usageCollection, fieldFormats, deps.fieldFormats.deserialize ); - const { mountApp, stopReportManager } = await import('./async_services'); + const { mountApp, stopReportManager, getLensAttributeService } = await import( + './async_services' + ); + const frameStart = this.editorFrameService!.start(coreStart, deps); + this.stopReportManager = stopReportManager; await ensureDefaultIndexPattern(); return mountApp(core, params, { - createEditorFrame: this.createEditorFrame!, - attributeService: this.attributeService!, + createEditorFrame: frameStart.createInstance, + attributeService: getLensAttributeService(coreStart, deps), getPresentationUtilContext, }); }, @@ -280,10 +290,8 @@ export class LensPlugin { private async initParts( core: CoreSetup, data: DataPublicPluginSetup, - embeddable: EmbeddableSetup | undefined, charts: ChartsPluginSetup, expressions: ExpressionsServiceSetup, - usageCollection: UsageCollectionSetup | undefined, fieldFormats: FieldFormatsSetup, formatFactory: FormatFactory ) { @@ -303,13 +311,9 @@ export class LensPlugin { this.metricVisualization = new MetricVisualization(); this.pieVisualization = new PieVisualization(); this.heatmapVisualization = new HeatmapVisualization(); - const editorFrameSetupInterface = this.editorFrameService.setup(core, { - data, - embeddable, - charts, - expressions, - usageCollection, - }); + + const editorFrameSetupInterface = this.editorFrameService.setup(); + const dependencies: IndexPatternDatasourceSetupPlugins & XyVisualizationPluginSetupPlugins & DatatableVisualizationPluginSetupPlugins & @@ -328,9 +332,6 @@ export class LensPlugin { this.metricVisualization.setup(core, dependencies); this.pieVisualization.setup(core, dependencies); this.heatmapVisualization.setup(core, dependencies); - const [coreStart, startDependencies] = await core.getStartServices(); - const frameStart = this.editorFrameService.start(coreStart, startDependencies); - this.createEditorFrame = frameStart.createInstance; } start(core: CoreStart, startDependencies: LensPluginStartDependencies): LensPublicStart { @@ -345,7 +346,7 @@ export class LensPlugin { return { EmbeddableComponent: getEmbeddableComponent(core, startDependencies), - SaveModalComponent: getSaveModalComponent(core, startDependencies, this.attributeService!), + SaveModalComponent: getSaveModalComponent(core, startDependencies), navigateToPrefilledEditor: ( input, { openInNewTab = false, originatingApp = '', originatingPath } = {} diff --git a/x-pack/plugins/lens/public/search_provider.ts b/x-pack/plugins/lens/public/search_provider.ts index 4bc18f2653a0b..a0d41da2d9740 100644 --- a/x-pack/plugins/lens/public/search_provider.ts +++ b/x-pack/plugins/lens/public/search_provider.ts @@ -5,12 +5,13 @@ * 2.0. */ -import { ApplicationStart } from 'kibana/public'; +import type { ApplicationStart } from 'kibana/public'; import { from, of } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/public'; -import { GlobalSearchResultProvider } from '../../global_search/public'; -import { getFullPath } from '../common'; +import { getFullPath } from '../common/constants'; + +import type { GlobalSearchResultProvider } from '../../global_search/public'; /** * Global search provider adding a Lens entry. diff --git a/x-pack/plugins/lens/public/trigger_actions/visualize_field_actions.ts b/x-pack/plugins/lens/public/trigger_actions/visualize_field_actions.ts index 9e7507b01bc59..4e105ed9db499 100644 --- a/x-pack/plugins/lens/public/trigger_actions/visualize_field_actions.ts +++ b/x-pack/plugins/lens/public/trigger_actions/visualize_field_actions.ts @@ -11,7 +11,7 @@ import { ACTION_VISUALIZE_LENS_FIELD, VisualizeFieldContext, } from '../../../../../src/plugins/ui_actions/public'; -import { ApplicationStart } from '../../../../../src/core/public'; +import type { ApplicationStart } from '../../../../../src/core/public'; export const visualizeFieldAction = (application: ApplicationStart) => createAction({ diff --git a/x-pack/plugins/lens/public/utils.ts b/x-pack/plugins/lens/public/utils.ts index b7dd3ed3733cf..993be9a06a2d9 100644 --- a/x-pack/plugins/lens/public/utils.ts +++ b/x-pack/plugins/lens/public/utils.ts @@ -4,16 +4,20 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import { uniq } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { IndexPattern, IndexPatternsContract, TimefilterContract } from 'src/plugins/data/public'; -import { IUiSettingsClient } from 'kibana/public'; import moment from 'moment-timezone'; -import { SavedObjectReference } from 'kibana/public'; -import { uniq } from 'lodash'; -import { Document } from './persistence/saved_object_store'; -import { Datasource, DatasourceMap } from './types'; -import { DatasourceStates } from './state_management'; + +import type { + IndexPattern, + IndexPatternsContract, + TimefilterContract, +} from 'src/plugins/data/public'; +import type { IUiSettingsClient } from 'kibana/public'; +import type { SavedObjectReference } from 'kibana/public'; +import type { Document } from './persistence/saved_object_store'; +import type { Datasource, DatasourceMap } from './types'; +import type { DatasourceStates } from './state_management'; export function getVisualizeGeoFieldMessage(fieldType: string) { return i18n.translate('xpack.lens.visualizeGeoFieldMessage', { diff --git a/x-pack/plugins/lens/public/vis_type_alias.ts b/x-pack/plugins/lens/public/vis_type_alias.ts index 5b48ef8b31923..96332e07069b0 100644 --- a/x-pack/plugins/lens/public/vis_type_alias.ts +++ b/x-pack/plugins/lens/public/vis_type_alias.ts @@ -6,8 +6,8 @@ */ import { i18n } from '@kbn/i18n'; -import { VisTypeAlias } from 'src/plugins/visualizations/public'; -import { getBasePath, getEditPath } from '../common'; +import type { VisTypeAlias } from 'src/plugins/visualizations/public'; +import { getBasePath, getEditPath } from '../common/constants'; export const getLensAliasConfig = (): VisTypeAlias => ({ aliasPath: getBasePath(), diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx index 3994aadd9a989..671db4653a88a 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx @@ -22,9 +22,10 @@ import { LayoutDirection, } from '@elastic/charts'; import { PaletteOutput } from 'src/plugins/charts/public'; -import { calculateMinInterval, XYChart, XYChartRenderProps, xyChart } from './expression'; +import { calculateMinInterval, XYChart, XYChartRenderProps } from './expression'; import type { LensMultiTable } from '../../common'; import { layerTypes } from '../../common'; +import { xyChart } from '../../common/expressions'; import { layerConfig, legendConfig, diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index 75d14d9b48ee3..b7f1a9dabf3c7 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -74,18 +74,6 @@ type SeriesSpec = InferPropType & InferPropType & InferPropType; -export { - legendConfig, - yAxisConfig, - tickLabelsConfig, - gridlinesConfig, - axisTitlesVisibilityConfig, - axisExtentConfig, - layerConfig, - xyChart, - labelsOrientationConfig, -} from '../../common/expressions'; - export type XYChartRenderProps = XYChartProps & { chartsThemeService: ChartsPluginSetup['theme']; chartsActiveCursorService: ChartsPluginStart['activeCursor']; diff --git a/x-pack/plugins/lens/public/xy_visualization/index.ts b/x-pack/plugins/lens/public/xy_visualization/index.ts index 6823ffedc9d90..f9d48ffaaae37 100644 --- a/x-pack/plugins/lens/public/xy_visualization/index.ts +++ b/x-pack/plugins/lens/public/xy_visualization/index.ts @@ -21,37 +21,14 @@ export interface XyVisualizationPluginSetupPlugins { } export class XyVisualization { - constructor() {} - setup( core: CoreSetup, { expressions, formatFactory, editorFrame }: XyVisualizationPluginSetupPlugins ) { editorFrame.registerVisualization(async () => { - const { - legendConfig, - yAxisConfig, - tickLabelsConfig, - gridlinesConfig, - axisTitlesVisibilityConfig, - axisExtentConfig, - labelsOrientationConfig, - layerConfig, - xyChart, - getXyChartRenderer, - getXyVisualization, - } = await import('../async_services'); + const { getXyChartRenderer, getXyVisualization } = await import('../async_services'); const [, { charts, fieldFormats }] = await core.getStartServices(); const palettes = await charts.palettes.getPalettes(); - expressions.registerFunction(() => legendConfig); - expressions.registerFunction(() => yAxisConfig); - expressions.registerFunction(() => tickLabelsConfig); - expressions.registerFunction(() => axisExtentConfig); - expressions.registerFunction(() => labelsOrientationConfig); - expressions.registerFunction(() => gridlinesConfig); - expressions.registerFunction(() => axisTitlesVisibilityConfig); - expressions.registerFunction(() => layerConfig); - expressions.registerFunction(() => xyChart); expressions.registerRenderer( getXyChartRenderer({ diff --git a/x-pack/plugins/lens/public/xy_visualization/types.ts b/x-pack/plugins/lens/public/xy_visualization/types.ts index 9d32c2f71c530..4729cfb96f324 100644 --- a/x-pack/plugins/lens/public/xy_visualization/types.ts +++ b/x-pack/plugins/lens/public/xy_visualization/types.ts @@ -17,8 +17,8 @@ import { LensIconChartBarHorizontalStacked } from '../assets/chart_bar_horizonta import { LensIconChartBarHorizontalPercentage } from '../assets/chart_bar_horizontal_percentage'; import { LensIconChartLine } from '../assets/chart_line'; -import { VisualizationType } from '../types'; -import { +import type { VisualizationType } from '../types'; +import type { SeriesType, ValueLabelConfig, LegendConfig,