From 040efae166243f44973cd8bec5b02cd751c77a4f Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Wed, 11 May 2022 08:53:28 +0300 Subject: [PATCH] [Lens] `lens_multitable` removal. (#131699) * Removed lens_multitable from lens_datatable * Removed lens_multitable from heatmap. * Added datasource to the metric. * Added datasource expression to pie. * Added datasource expression to gauge. * Fixed tests. * Removed LensMultiTable. * Removed additional `kibana` expression from the xy to_expression. * Removed lens_multitable from x-pack/maps. * Removed unused translation. * Added `handlers.inspectorAdapters.tables.reset` to all the expressions from lens. * Fixed choropleth chart. * Fixed gauge tests. * Fixed jest tests with inspector.tables.reset. * Added tests for the new behavior. --- .../gauge_function.test.ts | 1 + .../expression_functions/gauge_function.ts | 3 + .../heatmap_function.test.ts | 1 + .../expression_functions/heatmap_function.ts | 3 + .../metric_vis_function.test.ts | 1 + .../metric_vis_function.ts | 3 + .../mosaic_vis_function.test.ts | 1 + .../mosaic_vis_function.ts | 3 + .../pie_vis_function.test.ts | 1 + .../expression_functions/pie_vis_function.ts | 3 + .../treemap_vis_function.test.ts | 1 + .../treemap_vis_function.ts | 3 + .../waffle_vis_function.test.ts | 1 + .../waffle_vis_function.ts | 3 + .../tagcloud_function.test.ts | 1 + .../expression_xy/common/constants.ts | 1 - .../common/expression_functions/xy_vis_fn.ts | 3 + .../expression_xy/common/index.ts | 1 - .../common/types/expression_functions.ts | 10 - .../expression_xy/public/__mocks__/index.tsx | 264 +++++++++--------- .../public/components/legend_action.test.tsx | 253 +++++++++-------- .../public/components/xy_chart.test.tsx | 4 +- .../table/public/table_vis_fn.test.ts | 1 + .../common/expressions/datatable/datatable.ts | 2 +- .../expressions/datatable/datatable_fn.ts | 31 +- .../common/expressions/datatable/types.ts | 9 +- .../expressions/expression_types/index.ts | 9 - .../expression_types/lens_multitable.ts | 28 -- .../plugins/lens/common/expressions/index.ts | 3 - .../common/expressions/merge_tables/index.ts | 86 ------ .../merge_tables/merge_tables.test.ts | 114 -------- x-pack/plugins/lens/common/types.ts | 10 - .../components/table_actions.test.ts | 38 +-- .../components/table_actions.ts | 5 +- .../components/table_basic.test.tsx | 185 +++++------- .../components/table_basic.tsx | 18 +- .../expression.test.tsx | 79 +++--- .../datatable_visualization/expression.tsx | 7 +- .../datatable_visualization/visualization.tsx | 10 +- .../editor_frame/editor_frame.test.tsx | 145 +--------- .../editor_frame/expression_helpers.ts | 91 ++---- .../editor_frame/suggestion_panel.test.tsx | 4 +- .../editor_frame/suggestion_panel.tsx | 36 +-- .../workspace_panel/workspace_panel.test.tsx | 173 ++++-------- x-pack/plugins/lens/public/expressions.ts | 5 - .../heatmap_visualization/visualization.tsx | 13 +- x-pack/plugins/lens/public/index.ts | 1 - .../indexpattern.test.ts | 23 +- .../indexpattern_datasource/to_expression.ts | 1 + .../metric_visualization/visualization.tsx | 26 +- .../public/pie_visualization/to_expression.ts | 48 +++- .../pie_visualization/visualization.tsx | 8 +- x-pack/plugins/lens/public/types.ts | 6 - .../visualizations/gauge/visualization.tsx | 20 +- .../__snapshots__/to_expression.test.ts.snap | 8 +- .../xy_visualization/color_assignment.test.ts | 6 +- .../public/xy_visualization/to_expression.ts | 10 +- .../public/xy_visualization/visualization.tsx | 2 - .../lens/server/expressions/expressions.ts | 3 - .../choropleth_chart/choropleth_chart.tsx | 12 +- .../choropleth_chart/expression_function.ts | 13 +- .../public/lens/choropleth_chart/types.ts | 4 +- .../lens/choropleth_chart/visualization.tsx | 4 +- .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - .../test/functional/apps/lens/group3/gauge.ts | 2 + 67 files changed, 696 insertions(+), 1171 deletions(-) delete mode 100644 x-pack/plugins/lens/common/expressions/expression_types/index.ts delete mode 100644 x-pack/plugins/lens/common/expressions/expression_types/lens_multitable.ts delete mode 100644 x-pack/plugins/lens/common/expressions/merge_tables/index.ts delete mode 100644 x-pack/plugins/lens/common/expressions/merge_tables/merge_tables.test.ts diff --git a/src/plugins/chart_expressions/expression_gauge/common/expression_functions/gauge_function.test.ts b/src/plugins/chart_expressions/expression_gauge/common/expression_functions/gauge_function.test.ts index ac8cb5c8b86a3..705516a9f1e96 100644 --- a/src/plugins/chart_expressions/expression_gauge/common/expression_functions/gauge_function.test.ts +++ b/src/plugins/chart_expressions/expression_gauge/common/expression_functions/gauge_function.test.ts @@ -111,6 +111,7 @@ describe('interpreter/functions#gauge', () => { logDatatable: (name: string, datatable: Datatable) => { loggedTable = datatable; }, + reset: () => {}, }, }, }; diff --git a/src/plugins/chart_expressions/expression_gauge/common/expression_functions/gauge_function.ts b/src/plugins/chart_expressions/expression_gauge/common/expression_functions/gauge_function.ts index 48c7261e43016..70ecd25839d19 100644 --- a/src/plugins/chart_expressions/expression_gauge/common/expression_functions/gauge_function.ts +++ b/src/plugins/chart_expressions/expression_gauge/common/expression_functions/gauge_function.ts @@ -194,6 +194,9 @@ export const gaugeFunction = (): GaugeExpressionFunctionDefinition => ({ } if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.reset(); + handlers.inspectorAdapters.tables.allowCsvExport = true; + const logTable = prepareLogTable( data, [ diff --git a/src/plugins/chart_expressions/expression_heatmap/common/expression_functions/heatmap_function.test.ts b/src/plugins/chart_expressions/expression_heatmap/common/expression_functions/heatmap_function.test.ts index 13beee6b0f701..d34442ca3f518 100644 --- a/src/plugins/chart_expressions/expression_heatmap/common/expression_functions/heatmap_function.test.ts +++ b/src/plugins/chart_expressions/expression_heatmap/common/expression_functions/heatmap_function.test.ts @@ -69,6 +69,7 @@ describe('interpreter/functions#heatmap', () => { logDatatable: (name: string, datatable: Datatable) => { loggedTable = datatable; }, + reset: () => {}, }, }, }; diff --git a/src/plugins/chart_expressions/expression_heatmap/common/expression_functions/heatmap_function.ts b/src/plugins/chart_expressions/expression_heatmap/common/expression_functions/heatmap_function.ts index c440176962faf..954c5acee7152 100644 --- a/src/plugins/chart_expressions/expression_heatmap/common/expression_functions/heatmap_function.ts +++ b/src/plugins/chart_expressions/expression_heatmap/common/expression_functions/heatmap_function.ts @@ -161,6 +161,9 @@ export const heatmapFunction = (): HeatmapExpressionFunctionDefinition => ({ validateAccessor(args.splitColumnAccessor, data.columns); if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.reset(); + handlers.inspectorAdapters.tables.allowCsvExport = true; + const argsTable: Dimension[] = []; if (args.valueAccessor) { prepareHeatmapLogTable( diff --git a/src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.test.ts b/src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.test.ts index 65f738e8e227d..6524c15c44af1 100644 --- a/src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.test.ts +++ b/src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.test.ts @@ -68,6 +68,7 @@ describe('interpreter/functions#metric', () => { logDatatable: (name: string, datatable: Datatable) => { loggedTable = datatable; }, + reset: () => {}, }, }, }; diff --git a/src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.ts b/src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.ts index 2310ffb8c5926..add31e7b12014 100644 --- a/src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.ts +++ b/src/plugins/chart_expressions/expression_metric/common/expression_functions/metric_vis_function.ts @@ -146,6 +146,9 @@ export const metricVisFunction = (): MetricVisExpressionFunctionDefinition => ({ validateAccessor(args.bucket, input.columns); if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.reset(); + handlers.inspectorAdapters.tables.allowCsvExport = true; + const argsTable: Dimension[] = [ [ args.metric, diff --git a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/mosaic_vis_function.test.ts b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/mosaic_vis_function.test.ts index 0ce174b38677f..54b478e7deed9 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/mosaic_vis_function.test.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/mosaic_vis_function.test.ts @@ -135,6 +135,7 @@ describe('interpreter/functions#mosaicVis', () => { logDatatable: (name: string, datatable: Datatable) => { loggedTable = datatable; }, + reset: () => {}, }, }, }; diff --git a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/mosaic_vis_function.ts b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/mosaic_vis_function.ts index 2f08ecb28c931..ae3f17ff8df3a 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/mosaic_vis_function.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/mosaic_vis_function.ts @@ -144,6 +144,9 @@ export const mosaicVisFunction = (): MosaicVisExpressionFunctionDefinition => ({ }; if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.reset(); + handlers.inspectorAdapters.tables.allowCsvExport = true; + const logTable = prepareLogTable( context, [ diff --git a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/pie_vis_function.test.ts b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/pie_vis_function.test.ts index 58ba8e837d339..2ac50372e178d 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/pie_vis_function.test.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/pie_vis_function.test.ts @@ -129,6 +129,7 @@ describe('interpreter/functions#pieVis', () => { logDatatable: (name: string, datatable: Datatable) => { loggedTable = datatable; }, + reset: () => {}, }, }, }; diff --git a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/pie_vis_function.ts b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/pie_vis_function.ts index 707334466ea99..5b69fbc6194fd 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/pie_vis_function.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/pie_vis_function.ts @@ -164,6 +164,9 @@ export const pieVisFunction = (): PieVisExpressionFunctionDefinition => ({ }; if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.reset(); + handlers.inspectorAdapters.tables.allowCsvExport = true; + const logTable = prepareLogTable( context, [ diff --git a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/treemap_vis_function.test.ts b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/treemap_vis_function.test.ts index 5d2cd5b8a0c38..e10dbf09dd179 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/treemap_vis_function.test.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/treemap_vis_function.test.ts @@ -135,6 +135,7 @@ describe('interpreter/functions#treemapVis', () => { logDatatable: (name: string, datatable: Datatable) => { loggedTable = datatable; }, + reset: () => {}, }, }, }; diff --git a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/treemap_vis_function.ts b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/treemap_vis_function.ts index ab6f0c962e205..427179ca5a25a 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/treemap_vis_function.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/treemap_vis_function.ts @@ -144,6 +144,9 @@ export const treemapVisFunction = (): TreemapVisExpressionFunctionDefinition => }; if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.reset(); + handlers.inspectorAdapters.tables.allowCsvExport = true; + const logTable = prepareLogTable( context, [ diff --git a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/waffle_vis_function.test.ts b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/waffle_vis_function.test.ts index 01cbe844728b3..af36e4ea04a10 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/waffle_vis_function.test.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/waffle_vis_function.test.ts @@ -106,6 +106,7 @@ describe('interpreter/functions#waffleVis', () => { logDatatable: (name: string, datatable: Datatable) => { loggedTable = datatable; }, + reset: () => {}, }, }, }; diff --git a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/waffle_vis_function.ts b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/waffle_vis_function.ts index 0311f5466142f..0867e6cb9bd76 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/waffle_vis_function.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/waffle_vis_function.ts @@ -139,6 +139,9 @@ export const waffleVisFunction = (): WaffleVisExpressionFunctionDefinition => ({ }; if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.reset(); + handlers.inspectorAdapters.tables.allowCsvExport = true; + const logTable = prepareLogTable( context, [ diff --git a/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.test.ts b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.test.ts index c9ddd7c30557b..ccc365096495b 100644 --- a/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.test.ts +++ b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.test.ts @@ -93,6 +93,7 @@ describe('interpreter/functions#tagcloud', () => { logDatatable: (name: string, datatable: Datatable) => { loggedTable = datatable; }, + reset: () => {}, }, }, }; diff --git a/src/plugins/chart_expressions/expression_xy/common/constants.ts b/src/plugins/chart_expressions/expression_xy/common/constants.ts index 931ece6ef8a78..68ac2963c9646 100644 --- a/src/plugins/chart_expressions/expression_xy/common/constants.ts +++ b/src/plugins/chart_expressions/expression_xy/common/constants.ts @@ -10,7 +10,6 @@ export const XY_VIS = 'xyVis'; export const LAYERED_XY_VIS = 'layeredXyVis'; export const Y_CONFIG = 'yConfig'; export const EXTENDED_Y_CONFIG = 'extendedYConfig'; -export const MULTITABLE = 'lens_multitable'; export const DATA_LAYER = 'dataLayer'; export const EXTENDED_DATA_LAYER = 'extendedDataLayer'; export const LEGEND_CONFIG = 'legendConfig'; diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts index 6ce3116d377e1..5e2f7432ddf93 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts @@ -62,6 +62,9 @@ export const xyVisFn: XyVisFn['fn'] = async (data, args, handlers) => { ]; if (handlers.inspectorAdapters.tables) { + handlers.inspectorAdapters.tables.reset(); + handlers.inspectorAdapters.tables.allowCsvExport = true; + const layerDimensions = layers.reduce((dimensions, layer) => { if (layer.layerType === LayerTypes.ANNOTATIONS) { return dimensions; diff --git a/src/plugins/chart_expressions/expression_xy/common/index.ts b/src/plugins/chart_expressions/expression_xy/common/index.ts index 4bee4a3e7f2b6..7211a7a7db1b7 100755 --- a/src/plugins/chart_expressions/expression_xy/common/index.ts +++ b/src/plugins/chart_expressions/expression_xy/common/index.ts @@ -29,7 +29,6 @@ export type { LegendConfig, IconPosition, DataLayerArgs, - LensMultiTable, ValueLabelMode, AxisExtentMode, DataLayerConfig, diff --git a/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts index 86eb173d4d4ed..3cd84fa14682c 100644 --- a/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts @@ -18,7 +18,6 @@ import { FittingFunctions, IconPositions, LayerTypes, - MULTITABLE, LineStyles, SeriesTypes, ValueLabelModes, @@ -296,15 +295,6 @@ export type XYExtendedLayerConfigResult = | ExtendedReferenceLineLayerConfigResult | ExtendedAnnotationLayerConfigResult; -export interface LensMultiTable { - type: typeof MULTITABLE; - tables: Record; - dateRange?: { - fromDate: Date; - toDate: Date; - }; -} - export type ReferenceLineLayerConfigResult = ReferenceLineLayerArgs & { type: typeof REFERENCE_LINE_LAYER; layerType: typeof LayerTypes.REFERENCELINE; diff --git a/src/plugins/chart_expressions/expression_xy/public/__mocks__/index.tsx b/src/plugins/chart_expressions/expression_xy/public/__mocks__/index.tsx index 194bfc2bf5c9d..e84d8c001fb82 100644 --- a/src/plugins/chart_expressions/expression_xy/public/__mocks__/index.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/__mocks__/index.tsx @@ -8,7 +8,6 @@ import { Datatable } from '@kbn/expressions-plugin/common'; import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; -import { LensMultiTable } from '../../common'; import { LayerTypes } from '../../common/constants'; import { DataLayerConfig, XYProps } from '../../common/types'; import { mockPaletteOutput, sampleArgs } from '../../common/__mocks__'; @@ -21,151 +20,142 @@ export const chartsActiveCursorService = chartStartContract.activeCursor; export const paletteService = chartPluginMock.createPaletteRegistry(); -export const dateHistogramData: LensMultiTable = { - type: 'lens_multitable', - tables: { - timeLayer: { - type: 'datatable', - rows: [ - { - xAccessorId: 1585758120000, - splitAccessorId: "Men's Clothing", - yAccessorId: 1, - }, - { - xAccessorId: 1585758360000, - splitAccessorId: "Women's Accessories", - yAccessorId: 1, - }, - { - xAccessorId: 1585758360000, - splitAccessorId: "Women's Clothing", - yAccessorId: 1, - }, - { - xAccessorId: 1585759380000, - splitAccessorId: "Men's Clothing", - yAccessorId: 1, - }, - { - xAccessorId: 1585759380000, - splitAccessorId: "Men's Shoes", - yAccessorId: 1, - }, - { - xAccessorId: 1585759380000, - splitAccessorId: "Women's Clothing", - yAccessorId: 1, - }, - { - xAccessorId: 1585760700000, - splitAccessorId: "Men's Clothing", - yAccessorId: 1, - }, - { - xAccessorId: 1585760760000, - splitAccessorId: "Men's Clothing", - yAccessorId: 1, - }, - { - xAccessorId: 1585760760000, - splitAccessorId: "Men's Shoes", - yAccessorId: 1, - }, - { - xAccessorId: 1585761120000, - splitAccessorId: "Men's Shoes", - yAccessorId: 1, - }, - ], - columns: [ - { - id: 'xAccessorId', - name: 'order_date per minute', - meta: { - type: 'date', +export const dateHistogramData: Datatable = { + type: 'datatable', + rows: [ + { + xAccessorId: 1585758120000, + splitAccessorId: "Men's Clothing", + yAccessorId: 1, + }, + { + xAccessorId: 1585758360000, + splitAccessorId: "Women's Accessories", + yAccessorId: 1, + }, + { + xAccessorId: 1585758360000, + splitAccessorId: "Women's Clothing", + yAccessorId: 1, + }, + { + xAccessorId: 1585759380000, + splitAccessorId: "Men's Clothing", + yAccessorId: 1, + }, + { + xAccessorId: 1585759380000, + splitAccessorId: "Men's Shoes", + yAccessorId: 1, + }, + { + xAccessorId: 1585759380000, + splitAccessorId: "Women's Clothing", + yAccessorId: 1, + }, + { + xAccessorId: 1585760700000, + splitAccessorId: "Men's Clothing", + yAccessorId: 1, + }, + { + xAccessorId: 1585760760000, + splitAccessorId: "Men's Clothing", + yAccessorId: 1, + }, + { + xAccessorId: 1585760760000, + splitAccessorId: "Men's Shoes", + yAccessorId: 1, + }, + { + xAccessorId: 1585761120000, + splitAccessorId: "Men's Shoes", + yAccessorId: 1, + }, + ], + columns: [ + { + id: 'xAccessorId', + name: 'order_date per minute', + meta: { + type: 'date', + field: 'order_date', + source: 'esaggs', + index: 'indexPatternId', + sourceParams: { + indexPatternId: 'indexPatternId', + type: 'date_histogram', + appliedTimeRange: { + from: '2020-04-01T16:14:16.246Z', + to: '2020-04-01T17:15:41.263Z', + }, + params: { field: 'order_date', - source: 'esaggs', - index: 'indexPatternId', - sourceParams: { - indexPatternId: 'indexPatternId', - type: 'date_histogram', - appliedTimeRange: { - from: '2020-04-01T16:14:16.246Z', - to: '2020-04-01T17:15:41.263Z', - }, - params: { - field: 'order_date', - timeRange: { from: '2020-04-01T16:14:16.246Z', to: '2020-04-01T17:15:41.263Z' }, - useNormalizedEsInterval: true, - scaleMetricValues: false, - interval: '1m', - drop_partials: false, - min_doc_count: 0, - extended_bounds: {}, - }, - }, - params: { id: 'date', params: { pattern: 'HH:mm' } }, + timeRange: { from: '2020-04-01T16:14:16.246Z', to: '2020-04-01T17:15:41.263Z' }, + useNormalizedEsInterval: true, + scaleMetricValues: false, + interval: '1m', + drop_partials: false, + min_doc_count: 0, + extended_bounds: {}, }, }, - { - id: 'splitAccessorId', - name: 'Top values of category.keyword', - meta: { - type: 'string', + params: { id: 'date', params: { pattern: 'HH:mm' } }, + }, + }, + { + id: 'splitAccessorId', + name: 'Top values of category.keyword', + meta: { + type: 'string', + field: 'category.keyword', + source: 'esaggs', + index: 'indexPatternId', + sourceParams: { + indexPatternId: 'indexPatternId', + type: 'terms', + params: { field: 'category.keyword', - source: 'esaggs', - index: 'indexPatternId', - sourceParams: { - indexPatternId: 'indexPatternId', - type: 'terms', - params: { - field: 'category.keyword', - orderBy: 'yAccessorId', - order: 'desc', - size: 3, - otherBucket: false, - otherBucketLabel: 'Other', - missingBucket: false, - missingBucketLabel: 'Missing', - }, - }, - params: { - id: 'terms', - params: { - id: 'string', - otherBucketLabel: 'Other', - missingBucketLabel: 'Missing', - parsedUrl: { - origin: 'http://localhost:5601', - pathname: '/jiy/app/kibana', - basePath: '/jiy', - }, - }, - }, + orderBy: 'yAccessorId', + order: 'desc', + size: 3, + otherBucket: false, + otherBucketLabel: 'Other', + missingBucket: false, + missingBucketLabel: 'Missing', }, }, - { - id: 'yAccessorId', - name: 'Count of records', - meta: { - type: 'number', - source: 'esaggs', - index: 'indexPatternId', - sourceParams: { - indexPatternId: 'indexPatternId', - params: {}, + params: { + id: 'terms', + params: { + id: 'string', + otherBucketLabel: 'Other', + missingBucketLabel: 'Missing', + parsedUrl: { + origin: 'http://localhost:5601', + pathname: '/jiy/app/kibana', + basePath: '/jiy', }, - params: { id: 'number' }, }, }, - ], + }, + }, + { + id: 'yAccessorId', + name: 'Count of records', + meta: { + type: 'number', + source: 'esaggs', + index: 'indexPatternId', + sourceParams: { + indexPatternId: 'indexPatternId', + params: {}, + }, + params: { id: 'number' }, + }, }, - }, - dateRange: { - fromDate: new Date('2020-04-01T16:14:16.246Z'), - toDate: new Date('2020-04-01T17:15:41.263Z'), - }, + ], }; export const dateHistogramLayer: DataLayerConfig = { @@ -181,7 +171,7 @@ export const dateHistogramLayer: DataLayerConfig = { seriesType: 'bar_stacked', accessors: ['yAccessorId'], palette: mockPaletteOutput, - table: dateHistogramData.tables.timeLayer, + table: dateHistogramData, }; export function sampleArgsWithReferenceLine(value: number = 150) { diff --git a/src/plugins/chart_expressions/expression_xy/public/components/legend_action.test.tsx b/src/plugins/chart_expressions/expression_xy/public/components/legend_action.test.tsx index 7c60a6a3a5769..78ac1ed8d10cf 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/legend_action.test.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/legend_action.test.tsx @@ -7,151 +7,150 @@ */ import React from 'react'; +import { Datatable } from '@kbn/expressions-plugin/common'; import { LegendActionProps, SeriesIdentifier } from '@elastic/charts'; import { EuiPopover } from '@elastic/eui'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { ComponentType, ReactWrapper } from 'enzyme'; -import type { DataLayerConfig, LensMultiTable } from '../../common'; +import type { DataLayerConfig } from '../../common'; import { LayerTypes } from '../../common/constants'; import { getLegendAction } from './legend_action'; import { LegendActionPopover } from './legend_action_popover'; import { mockPaletteOutput } from '../../common/__mocks__'; -const tables = { - first: { - type: 'datatable', - rows: [ - { - xAccessorId: 1585758120000, - splitAccessorId: "Men's Clothing", - yAccessorId: 1, - }, - { - xAccessorId: 1585758360000, - splitAccessorId: "Women's Accessories", - yAccessorId: 1, - }, - { - xAccessorId: 1585758360000, - splitAccessorId: "Women's Clothing", - yAccessorId: 1, - }, - { - xAccessorId: 1585759380000, - splitAccessorId: "Men's Clothing", - yAccessorId: 1, - }, - { - xAccessorId: 1585759380000, - splitAccessorId: "Men's Shoes", - yAccessorId: 1, - }, - { - xAccessorId: 1585759380000, - splitAccessorId: "Women's Clothing", - yAccessorId: 1, - }, - { - xAccessorId: 1585760700000, - splitAccessorId: "Men's Clothing", - yAccessorId: 1, - }, - { - xAccessorId: 1585760760000, - splitAccessorId: "Men's Clothing", - yAccessorId: 1, - }, - { - xAccessorId: 1585760760000, - splitAccessorId: "Men's Shoes", - yAccessorId: 1, - }, - { - xAccessorId: 1585761120000, - splitAccessorId: "Men's Shoes", - yAccessorId: 1, - }, - ], - columns: [ - { - id: 'xAccessorId', - name: 'order_date per minute', - meta: { - type: 'date', - field: 'order_date', - source: 'esaggs', - index: 'indexPatternId', - sourceParams: { - indexPatternId: 'indexPatternId', - type: 'date_histogram', - params: { - field: 'order_date', - timeRange: { from: '2020-04-01T16:14:16.246Z', to: '2020-04-01T17:15:41.263Z' }, - useNormalizedEsInterval: true, - scaleMetricValues: false, - interval: '1m', - drop_partials: false, - min_doc_count: 0, - extended_bounds: {}, - }, +const table: Datatable = { + type: 'datatable', + rows: [ + { + xAccessorId: 1585758120000, + splitAccessorId: "Men's Clothing", + yAccessorId: 1, + }, + { + xAccessorId: 1585758360000, + splitAccessorId: "Women's Accessories", + yAccessorId: 1, + }, + { + xAccessorId: 1585758360000, + splitAccessorId: "Women's Clothing", + yAccessorId: 1, + }, + { + xAccessorId: 1585759380000, + splitAccessorId: "Men's Clothing", + yAccessorId: 1, + }, + { + xAccessorId: 1585759380000, + splitAccessorId: "Men's Shoes", + yAccessorId: 1, + }, + { + xAccessorId: 1585759380000, + splitAccessorId: "Women's Clothing", + yAccessorId: 1, + }, + { + xAccessorId: 1585760700000, + splitAccessorId: "Men's Clothing", + yAccessorId: 1, + }, + { + xAccessorId: 1585760760000, + splitAccessorId: "Men's Clothing", + yAccessorId: 1, + }, + { + xAccessorId: 1585760760000, + splitAccessorId: "Men's Shoes", + yAccessorId: 1, + }, + { + xAccessorId: 1585761120000, + splitAccessorId: "Men's Shoes", + yAccessorId: 1, + }, + ], + columns: [ + { + id: 'xAccessorId', + name: 'order_date per minute', + meta: { + type: 'date', + field: 'order_date', + source: 'esaggs', + index: 'indexPatternId', + sourceParams: { + indexPatternId: 'indexPatternId', + type: 'date_histogram', + params: { + field: 'order_date', + timeRange: { from: '2020-04-01T16:14:16.246Z', to: '2020-04-01T17:15:41.263Z' }, + useNormalizedEsInterval: true, + scaleMetricValues: false, + interval: '1m', + drop_partials: false, + min_doc_count: 0, + extended_bounds: {}, }, - params: { id: 'date', params: { pattern: 'HH:mm' } }, }, + params: { id: 'date', params: { pattern: 'HH:mm' } }, }, - { - id: 'splitAccessorId', - name: 'Top values of category.keyword', - meta: { - type: 'string', - field: 'category.keyword', - source: 'esaggs', - index: 'indexPatternId', - sourceParams: { - indexPatternId: 'indexPatternId', - type: 'terms', - params: { - field: 'category.keyword', - orderBy: 'yAccessorId', - order: 'desc', - size: 3, - otherBucket: false, - otherBucketLabel: 'Other', - missingBucket: false, - missingBucketLabel: 'Missing', - }, + }, + { + id: 'splitAccessorId', + name: 'Top values of category.keyword', + meta: { + type: 'string', + field: 'category.keyword', + source: 'esaggs', + index: 'indexPatternId', + sourceParams: { + indexPatternId: 'indexPatternId', + type: 'terms', + params: { + field: 'category.keyword', + orderBy: 'yAccessorId', + order: 'desc', + size: 3, + otherBucket: false, + otherBucketLabel: 'Other', + missingBucket: false, + missingBucketLabel: 'Missing', }, + }, + params: { + id: 'terms', params: { - id: 'terms', - params: { - id: 'string', - otherBucketLabel: 'Other', - missingBucketLabel: 'Missing', - parsedUrl: { - origin: 'http://localhost:5601', - pathname: '/jiy/app/kibana', - basePath: '/jiy', - }, + id: 'string', + otherBucketLabel: 'Other', + missingBucketLabel: 'Missing', + parsedUrl: { + origin: 'http://localhost:5601', + pathname: '/jiy/app/kibana', + basePath: '/jiy', }, }, }, }, - { - id: 'yAccessorId', - name: 'Count of records', - meta: { - type: 'number', - source: 'esaggs', - index: 'indexPatternId', - sourceParams: { - indexPatternId: 'indexPatternId', - params: {}, - }, - params: { id: 'number' }, + }, + { + id: 'yAccessorId', + name: 'Count of records', + meta: { + type: 'number', + source: 'esaggs', + index: 'indexPatternId', + sourceParams: { + indexPatternId: 'indexPatternId', + params: {}, }, + params: { id: 'number' }, }, - ], - }, -} as LensMultiTable['tables']; + }, + ], +}; const sampleLayer: DataLayerConfig = { layerId: 'first', @@ -166,7 +165,7 @@ const sampleLayer: DataLayerConfig = { yScaleType: 'linear', isHistogram: false, palette: mockPaletteOutput, - table: tables.first, + table, }; describe('getLegendAction', function () { @@ -228,7 +227,7 @@ describe('getLegendAction', function () { { column: 1, row: 1, - table: tables.first, + table, value: "Women's Accessories", }, ], diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx index 7df73082dfa14..48f2393935413 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx @@ -773,7 +773,7 @@ describe('XYChart component', () => { expect(onSelectRange).toHaveBeenCalledWith({ column: 0, - table: dateHistogramData.tables.timeLayer, + table: dateHistogramData, range: [1585757732783, 1585758880838], }); }); @@ -969,7 +969,7 @@ describe('XYChart component', () => { { column: 0, row: 0, - table: dateHistogramData.tables.timeLayer, + table: dateHistogramData, value: 1585758120000, }, ], diff --git a/src/plugins/vis_types/table/public/table_vis_fn.test.ts b/src/plugins/vis_types/table/public/table_vis_fn.test.ts index 98336d6cc67d4..87da839578117 100644 --- a/src/plugins/vis_types/table/public/table_vis_fn.test.ts +++ b/src/plugins/vis_types/table/public/table_vis_fn.test.ts @@ -79,6 +79,7 @@ describe('interpreter/functions#table', () => { logDatatable: (name: string, datatable: Datatable) => { loggedTable = datatable; }, + reset: () => {}, }, }, }; diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable.ts index 84aba75239ed0..4f04fc1753c82 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable.ts @@ -39,7 +39,7 @@ export const getDatatable = ( ): DatatableExpressionFunction => ({ name: 'lens_datatable', type: 'render', - inputTypes: ['lens_multitable'], + inputTypes: ['datatable'], help: i18n.translate('xpack.lens.datatable.expressionHelpLabel', { defaultMessage: 'Datatable renderer', }), diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts index 713f929d74420..464c70a412397 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable_fn.ts @@ -8,8 +8,8 @@ import { cloneDeep } from 'lodash'; import { i18n } from '@kbn/i18n'; import { prepareLogTable } from '@kbn/visualizations-plugin/common/utils'; -import type { DatatableColumnMeta, ExecutionContext } from '@kbn/expressions-plugin'; -import { FormatFactory, LensMultiTable } from '../../types'; +import type { Datatable, DatatableColumnMeta, ExecutionContext } from '@kbn/expressions-plugin'; +import { FormatFactory } from '../../types'; import { transposeTable } from './transpose_helpers'; import { computeSummaryRowForColumn } from './summary'; import { getSortingCriteria } from './sorting'; @@ -23,11 +23,13 @@ export const datatableFn = ( getFormatFactory: (context: ExecutionContext) => FormatFactory | Promise ): DatatableExpressionFunction['fn'] => - async (data, args, context) => { - const [firstTable] = Object.values(data.tables); + async (table, args, context) => { if (context?.inspectorAdapters?.tables) { + context.inspectorAdapters.tables.reset(); + context.inspectorAdapters.tables.allowCsvExport = true; + const logTable = prepareLogTable( - Object.values(data.tables)[0], + table, [ [ args.columns.map((column) => column.columnId), @@ -42,27 +44,27 @@ export const datatableFn = context.inspectorAdapters.tables.logDatatable('default', logTable); } - let untransposedData: LensMultiTable | undefined; + let untransposedData: Datatable | undefined; // do the sorting at this level to propagate it also at CSV download const [layerId] = Object.keys(context.inspectorAdapters.tables || {}); const formatters: Record> = {}; const formatFactory = await getFormatFactory(context); - firstTable.columns.forEach((column) => { + table.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); + untransposedData = cloneDeep(table); // transposes table and args inplace - transposeTable(args, firstTable, formatters); + transposeTable(args, table, formatters); } const { sortingColumnId: sortBy, sortingDirection: sortDirection } = args; - const columnsReverseLookup = firstTable.columns.reduce< + const columnsReverseLookup = table.columns.reduce< Record >((memo, { id, name, meta }, i) => { memo[id] = { name, index: i, meta }; @@ -73,7 +75,7 @@ export const datatableFn = for (const column of columnsWithSummary) { column.summaryRowValue = computeSummaryRowForColumn( column, - firstTable, + table, formatters, formatFactory({ id: 'number' }) ); @@ -92,20 +94,21 @@ export const datatableFn = sortDirection ); // replace the table here - context.inspectorAdapters.tables[layerId].rows = (firstTable.rows || []) + context.inspectorAdapters.tables[layerId].rows = (table.rows || []) .slice() .sort(sortingCriteria); // replace also the local copy - firstTable.rows = context.inspectorAdapters.tables[layerId].rows; + table.rows = context.inspectorAdapters.tables[layerId].rows; } else { args.sortingColumnId = undefined; args.sortingDirection = 'none'; } + return { type: 'render', as: 'lens_datatable_renderer', value: { - data, + data: table, untransposedData, args, }, diff --git a/x-pack/plugins/lens/common/expressions/datatable/types.ts b/x-pack/plugins/lens/common/expressions/datatable/types.ts index 9e6315bb856d0..a78018fca90f6 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/types.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/types.ts @@ -5,13 +5,12 @@ * 2.0. */ -import type { ExpressionFunctionDefinition } from '@kbn/expressions-plugin'; -import type { LensMultiTable } from '../../types'; +import type { Datatable, ExpressionFunctionDefinition } from '@kbn/expressions-plugin'; import type { DatatableArgs } from './datatable'; export interface DatatableProps { - data: LensMultiTable; - untransposedData?: LensMultiTable; + data: Datatable; + untransposedData?: Datatable; args: DatatableArgs; } @@ -23,7 +22,7 @@ export interface DatatableRender { export type DatatableExpressionFunction = ExpressionFunctionDefinition< 'lens_datatable', - LensMultiTable, + Datatable, DatatableArgs, Promise >; diff --git a/x-pack/plugins/lens/common/expressions/expression_types/index.ts b/x-pack/plugins/lens/common/expressions/expression_types/index.ts deleted file mode 100644 index 78821e429fa8f..0000000000000 --- a/x-pack/plugins/lens/common/expressions/expression_types/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { lensMultitable } from './lens_multitable'; -export type { LensMultitableExpressionTypeDefinition } from './lens_multitable'; diff --git a/x-pack/plugins/lens/common/expressions/expression_types/lens_multitable.ts b/x-pack/plugins/lens/common/expressions/expression_types/lens_multitable.ts deleted file mode 100644 index 2e1ce28534a27..0000000000000 --- a/x-pack/plugins/lens/common/expressions/expression_types/lens_multitable.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ExpressionTypeDefinition } from '@kbn/expressions-plugin/common'; -import { LensMultiTable } from '../../types'; - -const name = 'lens_multitable'; - -type Input = LensMultiTable; - -export type LensMultitableExpressionTypeDefinition = ExpressionTypeDefinition< - typeof name, - Input, - Input ->; - -export const lensMultitable: LensMultitableExpressionTypeDefinition = { - name, - to: { - datatable: (input: Input) => { - return Object.values(input.tables)[0]; - }, - }, -}; diff --git a/x-pack/plugins/lens/common/expressions/index.ts b/x-pack/plugins/lens/common/expressions/index.ts index 47ff8318447b2..2007a61b11bf9 100644 --- a/x-pack/plugins/lens/common/expressions/index.ts +++ b/x-pack/plugins/lens/common/expressions/index.ts @@ -8,8 +8,5 @@ export * from './counter_rate'; export * from './format_column'; export * from './rename_columns'; -export * from './merge_tables'; export * from './time_scale'; export * from './datatable'; - -export * from './expression_types'; diff --git a/x-pack/plugins/lens/common/expressions/merge_tables/index.ts b/x-pack/plugins/lens/common/expressions/merge_tables/index.ts deleted file mode 100644 index 2e0dbc4b44264..0000000000000 --- a/x-pack/plugins/lens/common/expressions/merge_tables/index.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import type { - ExpressionFunctionDefinition, - Datatable, - ExecutionContext, -} from '@kbn/expressions-plugin/common'; -import { toAbsoluteDates } from '@kbn/data-plugin/common'; -import type { ExpressionValueSearchContext } from '@kbn/data-plugin/common'; - -import type { Adapters } from '@kbn/inspector-plugin/common'; -import type { LensMultiTable } from '../../types'; - -interface MergeTables { - layerIds: string[]; - tables: Datatable[]; -} - -export const mergeTables: ExpressionFunctionDefinition< - 'lens_merge_tables', - ExpressionValueSearchContext | null, - MergeTables, - LensMultiTable, - ExecutionContext -> = { - name: 'lens_merge_tables', - type: 'lens_multitable', - help: i18n.translate('xpack.lens.functions.mergeTables.help', { - defaultMessage: - 'A helper to merge any number of kibana tables into a single table and expose it via inspector adapter', - }), - args: { - layerIds: { - types: ['string'], - help: '', - multi: true, - }, - tables: { - types: ['datatable'], - help: '', - multi: true, - }, - }, - inputTypes: ['kibana_context', 'null'], - fn(input, { layerIds, tables }, context) { - const resultTables: Record = {}; - - if (context.inspectorAdapters?.tables) { - context.inspectorAdapters.tables.reset(); - context.inspectorAdapters.tables.allowCsvExport = true; - } - - tables.forEach((table, index) => { - resultTables[layerIds[index]] = table; - }); - - return { - type: 'lens_multitable', - tables: resultTables, - dateRange: getDateRange(input), - }; - }, -}; - -function getDateRange(value?: ExpressionValueSearchContext | null) { - if (!value || !value.timeRange) { - return; - } - - const dateRange = toAbsoluteDates(value.timeRange); - - if (!dateRange) { - return; - } - - return { - fromDate: dateRange.from, - toDate: dateRange.to, - }; -} diff --git a/x-pack/plugins/lens/common/expressions/merge_tables/merge_tables.test.ts b/x-pack/plugins/lens/common/expressions/merge_tables/merge_tables.test.ts deleted file mode 100644 index 4558bdfe68661..0000000000000 --- a/x-pack/plugins/lens/common/expressions/merge_tables/merge_tables.test.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import moment from 'moment'; -import { mergeTables } from '.'; -import type { ExpressionValueSearchContext } from '@kbn/data-plugin/common'; -import { - Datatable, - ExecutionContext, - DefaultInspectorAdapters, - TablesAdapter, -} from '@kbn/expressions-plugin'; - -describe('lens_merge_tables', () => { - const sampleTable1: Datatable = { - type: 'datatable', - columns: [ - { id: 'bucket', name: 'A', meta: { type: 'string' } }, - { id: 'count', name: 'Count', meta: { type: 'number' } }, - ], - rows: [ - { bucket: 'a', count: 5 }, - { bucket: 'b', count: 10 }, - ], - }; - - const sampleTable2: Datatable = { - type: 'datatable', - columns: [ - { id: 'bucket', name: 'C', meta: { type: 'string' } }, - { id: 'avg', name: 'Average', meta: { type: 'number' } }, - ], - rows: [ - { bucket: 'a', avg: 2.5 }, - { bucket: 'b', avg: 9 }, - ], - }; - - it('should produce a row with the nested table as defined', () => { - expect( - mergeTables.fn( - null, - { layerIds: ['first', 'second'], tables: [sampleTable1, sampleTable2] }, - // eslint-disable-next-line - {} as any - ) - ).toEqual({ - tables: { first: sampleTable1, second: sampleTable2 }, - type: 'lens_multitable', - }); - }); - - it('should reset the current tables in the tables inspector', () => { - const adapters = { - tables: new TablesAdapter(), - } as DefaultInspectorAdapters; - - const resetSpy = jest.spyOn(adapters.tables, 'reset'); - - mergeTables.fn(null, { layerIds: ['first', 'second'], tables: [sampleTable1, sampleTable2] }, { - inspectorAdapters: adapters, - } as ExecutionContext); - expect(resetSpy).toHaveBeenCalled(); - }); - - it('should pass the date range along', () => { - expect( - mergeTables.fn( - { - type: 'kibana_context', - timeRange: { - from: '2019-01-01T05:00:00.000Z', - to: '2020-01-01T05:00:00.000Z', - }, - }, - { layerIds: ['first', 'second'], tables: [] }, - // eslint-disable-next-line - {} as any - ) - ).toMatchInlineSnapshot(` - Object { - "dateRange": Object { - "fromDate": 2019-01-01T05:00:00.000Z, - "toDate": 2020-01-01T05:00:00.000Z, - }, - "tables": Object {}, - "type": "lens_multitable", - } - `); - }); - - it('should handle this week now/w', () => { - const { dateRange } = mergeTables.fn( - { - type: 'kibana_context', - timeRange: { - from: 'now/w', - to: 'now/w', - }, - }, - { layerIds: ['first', 'second'], tables: [] }, - // eslint-disable-next-line - {} as any - ); - - expect(moment.duration(moment().startOf('week').diff(dateRange!.fromDate)).asDays()).toEqual(0); - - expect(moment.duration(moment().endOf('week').diff(dateRange!.toDate)).asDays()).toEqual(0); - }); -}); diff --git a/x-pack/plugins/lens/common/types.ts b/x-pack/plugins/lens/common/types.ts index 43f4afb9e0484..d7432e0f10b6f 100644 --- a/x-pack/plugins/lens/common/types.ts +++ b/x-pack/plugins/lens/common/types.ts @@ -10,7 +10,6 @@ import { Position } from '@elastic/charts'; import { $Values } from '@kbn/utility-types'; import type { CustomPaletteParams, PaletteOutput } from '@kbn/coloring'; import type { IFieldFormat, SerializedFieldFormat } from '@kbn/field-formats-plugin/common'; -import type { Datatable } from '@kbn/expressions-plugin/common'; import type { ColorMode } from '@kbn/charts-plugin/common'; import { LegendSize } from '@kbn/visualizations-plugin/common'; import { @@ -41,15 +40,6 @@ export interface PersistableFilter extends Filter { meta: PersistableFilterMeta; } -export interface LensMultiTable { - type: 'lens_multitable'; - tables: Record; - dateRange?: { - fromDate: Date; - toDate: Date; - }; -} - export type SortingHint = 'version'; export type CustomPaletteParamsConfig = CustomPaletteParams & { diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/table_actions.test.ts b/x-pack/plugins/lens/public/datatable_visualization/components/table_actions.test.ts index 118abdcb77c8a..f11fc098b50d9 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/table_actions.test.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/components/table_actions.test.ts @@ -17,7 +17,6 @@ import { createGridHideHandler, createTransposeColumnFilterHandler, } from './table_actions'; -import { LensMultiTable } from '../../../common'; import { LensGridDirection, ColumnConfig } from '../../../common/expressions'; function getDefaultConfig(): ColumnConfig { @@ -49,17 +48,8 @@ function createTableRef( }; } -function createUntransposedRef(options?: { - withDate: boolean; -}): React.MutableRefObject { - return { - current: { - type: 'lens_multitable', - tables: { - first: createTableRef(options).current, - }, - }, - }; +function createUntransposedRef(options?: { withDate: boolean }): React.MutableRefObject { + return { current: createTableRef(options).current }; } describe('Table actions', () => { @@ -147,13 +137,13 @@ describe('Table actions', () => { it('should set a filter on click with the correct configuration', () => { const onClickValue = jest.fn(); const tableRef = createUntransposedRef({ withDate: true }); - tableRef.current.tables.first.rows = [{ a: 123456 }]; + tableRef.current.rows = [{ a: 123456 }]; const filterHandle = createTransposeColumnFilterHandler(onClickValue, tableRef); filterHandle( [ { - originalBucketColumn: tableRef.current.tables.first.columns[0], + originalBucketColumn: tableRef.current.columns[0], value: 123456, }, ], @@ -164,7 +154,7 @@ describe('Table actions', () => { { column: 0, row: 0, - table: tableRef.current.tables.first, + table: tableRef.current, value: 123456, }, ], @@ -175,13 +165,13 @@ describe('Table actions', () => { it('should set a negate filter on click with the correct configuration', () => { const onClickValue = jest.fn(); const tableRef = createUntransposedRef({ withDate: true }); - tableRef.current.tables.first.rows = [{ a: 123456 }]; + tableRef.current.rows = [{ a: 123456 }]; const filterHandle = createTransposeColumnFilterHandler(onClickValue, tableRef); filterHandle( [ { - originalBucketColumn: tableRef.current.tables.first.columns[0], + originalBucketColumn: tableRef.current.columns[0], value: 123456, }, ], @@ -192,7 +182,7 @@ describe('Table actions', () => { { column: 0, row: 0, - table: tableRef.current.tables.first, + table: tableRef.current, value: 123456, }, ], @@ -204,7 +194,7 @@ describe('Table actions', () => { const onClickValue = jest.fn(); const tableRef = createUntransposedRef({ withDate: false }); const filterHandle = createTransposeColumnFilterHandler(onClickValue, tableRef); - tableRef.current.tables.first.columns = [ + tableRef.current.columns = [ { id: 'a', name: 'a', @@ -220,7 +210,7 @@ describe('Table actions', () => { }, }, ]; - tableRef.current.tables.first.rows = [ + tableRef.current.rows = [ { a: 'a1', b: 'b1', @@ -242,11 +232,11 @@ describe('Table actions', () => { filterHandle( [ { - originalBucketColumn: tableRef.current.tables.first.columns[0], + originalBucketColumn: tableRef.current.columns[0], value: 'a2', }, { - originalBucketColumn: tableRef.current.tables.first.columns[1], + originalBucketColumn: tableRef.current.columns[1], value: 'b3', }, ], @@ -257,13 +247,13 @@ describe('Table actions', () => { { column: 0, row: 1, - table: tableRef.current.tables.first, + table: tableRef.current, value: 'a2', }, { column: 1, row: 2, - table: tableRef.current.tables.first, + table: tableRef.current, value: 'b3', }, ], diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/table_actions.ts b/x-pack/plugins/lens/public/datatable_visualization/components/table_actions.ts index fd4bdbe15c1be..ba7e957de083a 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/table_actions.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/components/table_actions.ts @@ -8,7 +8,6 @@ import type { EuiDataGridSorting } from '@elastic/eui'; import type { Datatable, DatatableColumn } from '@kbn/expressions-plugin'; import { ClickTriggerEvent } from '@kbn/charts-plugin/public'; -import type { LensMultiTable } from '../../../common'; import type { LensResizeAction, LensSortAction, LensToggleAction } from './types'; import type { ColumnConfig, LensGridDirection } from '../../../common/expressions'; import { getOriginalId } from '../../../common/expressions'; @@ -93,14 +92,14 @@ export const createGridFilterHandler = export const createTransposeColumnFilterHandler = ( onClickValue: (data: ClickTriggerEvent['data']) => void, - untransposedDataRef: React.MutableRefObject + untransposedDataRef: React.MutableRefObject ) => ( bucketValues: Array<{ originalBucketColumn: DatatableColumn; value: unknown }>, negate: boolean = false ) => { if (!untransposedDataRef.current) return; - const originalTable = Object.values(untransposedDataRef.current.tables)[0]; + const originalTable = untransposedDataRef.current; const data: ClickTriggerEvent['data'] = { negate, diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.test.tsx index 96ffbf371525e..bcf6f50d2bd46 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.test.tsx @@ -20,59 +20,53 @@ import { VisualizationContainer } from '../../visualization_container'; import { EmptyPlaceholder } from '@kbn/charts-plugin/public'; import { LensIconChartDatatable } from '../../assets/chart_datatable'; import { DataContext, DatatableComponent } from './table_basic'; -import { LensMultiTable } from '../../../common'; import { DatatableProps } from '../../../common/expressions'; import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { IUiSettingsClient } from '@kbn/core/public'; -import { RenderMode } from '@kbn/expressions-plugin'; +import { Datatable, RenderMode } from '@kbn/expressions-plugin'; import { LENS_EDIT_PAGESIZE_ACTION } from './constants'; function sampleArgs() { const indexPatternId = 'indexPatternId'; - const data: LensMultiTable = { - type: 'lens_multitable', - tables: { - l1: { - type: 'datatable', - columns: [ - { - id: 'a', - name: 'a', - meta: { - type: 'string', - source: 'esaggs', - field: 'a', - sourceParams: { type: 'terms', indexPatternId }, - }, - }, - { - id: 'b', - name: 'b', - meta: { - type: 'date', - field: 'b', - source: 'esaggs', - sourceParams: { - type: 'date_histogram', - indexPatternId, - }, - }, - }, - { - id: 'c', - name: 'c', - meta: { - type: 'number', - source: 'esaggs', - field: 'c', - sourceParams: { indexPatternId, type: 'count' }, - }, + const data: Datatable = { + type: 'datatable', + columns: [ + { + id: 'a', + name: 'a', + meta: { + type: 'string', + source: 'esaggs', + field: 'a', + sourceParams: { type: 'terms', indexPatternId }, + }, + }, + { + id: 'b', + name: 'b', + meta: { + type: 'date', + field: 'b', + source: 'esaggs', + sourceParams: { + type: 'date_histogram', + indexPatternId, }, - ], - rows: [{ a: 'shoes', b: 1588024800000, c: 3 }], + }, }, - }, + { + id: 'c', + name: 'c', + meta: { + type: 'number', + source: 'esaggs', + field: 'c', + sourceParams: { indexPatternId, type: 'count' }, + }, + }, + ], + rows: [{ a: 'shoes', b: 1588024800000, c: 3 }], }; const args: DatatableProps['args'] = { @@ -175,13 +169,7 @@ describe('DatatableComponent', () => { const wrapper = mountWithIntl( ({ convert: (x) => x } as IFieldFormat)} dispatchEvent={onDispatchEvent} @@ -206,7 +194,7 @@ describe('DatatableComponent', () => { { column: 0, row: 0, - table: data.tables.l1, + table: data, value: 'shoes', }, ], @@ -220,13 +208,7 @@ describe('DatatableComponent', () => { const wrapper = mountWithIntl( ({ convert: (x) => x } as IFieldFormat)} dispatchEvent={onDispatchEvent} @@ -251,7 +233,7 @@ describe('DatatableComponent', () => { { column: 1, row: 0, - table: data.tables.l1, + table: data, value: 1588024800000, }, ], @@ -261,35 +243,30 @@ describe('DatatableComponent', () => { }); test('it invokes executeTriggerActions with correct context on click on timefield from range', async () => { - const data: LensMultiTable = { - type: 'lens_multitable', - tables: { - l1: { - type: 'datatable', - columns: [ - { - id: 'a', - name: 'a', - meta: { - type: 'date', - source: 'esaggs', - field: 'a', - sourceParams: { type: 'date_range', indexPatternId: 'a' }, - }, - }, - { - id: 'b', - name: 'b', - meta: { - type: 'number', - source: 'esaggs', - sourceParams: { type: 'count', indexPatternId: 'a' }, - }, - }, - ], - rows: [{ a: 1588024800000, b: 3 }], + const data: Datatable = { + type: 'datatable', + columns: [ + { + id: 'a', + name: 'a', + meta: { + type: 'date', + source: 'esaggs', + field: 'a', + sourceParams: { type: 'date_range', indexPatternId: 'a' }, + }, }, - }, + { + id: 'b', + name: 'b', + meta: { + type: 'number', + source: 'esaggs', + sourceParams: { type: 'count', indexPatternId: 'a' }, + }, + }, + ], + rows: [{ a: 1588024800000, b: 3 }], }; const args: DatatableProps['args'] = { @@ -305,13 +282,7 @@ describe('DatatableComponent', () => { const wrapper = mountWithIntl( ({ convert: (x) => x } as IFieldFormat)} dispatchEvent={onDispatchEvent} @@ -336,7 +307,7 @@ describe('DatatableComponent', () => { { column: 0, row: 0, - table: data.tables.l1, + table: data, value: 1588024800000, }, ], @@ -350,13 +321,7 @@ describe('DatatableComponent', () => { const wrapper = mountWithIntl( ({ convert: (x) => x } as IFieldFormat)} dispatchEvent={onDispatchEvent} @@ -377,14 +342,9 @@ describe('DatatableComponent', () => { test('it shows emptyPlaceholder for undefined bucketed data', () => { const { args, data } = sampleArgs(); - const emptyData: LensMultiTable = { + const emptyData: Datatable = { ...data, - tables: { - l1: { - ...data.tables.l1, - rows: [{ a: undefined, b: undefined, c: 0 }], - }, - }, + rows: [{ a: undefined, b: undefined, c: 0 }], }; const component = shallow( @@ -551,8 +511,7 @@ describe('DatatableComponent', () => { test('it detect last_value filtered metric type', () => { const { data, args } = sampleArgs(); - const table = data.tables.l1; - const column = table.columns[1]; + const column = data.columns[1]; column.meta = { ...column.meta, @@ -560,7 +519,7 @@ describe('DatatableComponent', () => { type: 'number', sourceParams: { ...column.meta.sourceParams, type: 'filtered_metric' }, }; - table.rows[0].b = 'Hello'; + data.rows[0].b = 'Hello'; const wrapper = shallow( { ); // mnake a copy of the data, changing only the name of the first column const newData = copyData(data); - newData.tables.l1.columns[0].name = 'new a'; + newData.columns[0].name = 'new a'; wrapper.setProps({ data: newData }); wrapper.update(); 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 905a007b8ca03..cf6cd1c635cee 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 @@ -59,8 +59,6 @@ const PAGE_SIZE_OPTIONS = [DEFAULT_PAGE_SIZE, 20, 30, 50, 100]; export const DatatableComponent = (props: DatatableRenderProps) => { const dataGridRef = useRef(null); - const [firstTable] = Object.values(props.data.tables); - const isInteractive = props.interactive; const [columnConfig, setColumnConfig] = useState({ @@ -68,7 +66,7 @@ export const DatatableComponent = (props: DatatableRenderProps) => { sortingColumnId: props.args.sortingColumnId, sortingDirection: props.args.sortingDirection, }); - const [firstLocalTable, updateTable] = useState(firstTable); + const [firstLocalTable, updateTable] = useState(props.data); // ** Pagination config const [pagination, setPagination] = useState<{ pageIndex: number; pageSize: number } | undefined>( @@ -95,8 +93,8 @@ export const DatatableComponent = (props: DatatableRenderProps) => { }, [props.args.columns, props.args.sortingColumnId, props.args.sortingDirection]); useDeepCompareEffect(() => { - updateTable(firstTable); - }, [firstTable]); + updateTable(props.data); + }, [props.data]); const firstTableRef = useRef(firstLocalTable); firstTableRef.current = firstLocalTable; @@ -194,7 +192,7 @@ export const DatatableComponent = (props: DatatableRenderProps) => { const isEmpty = firstLocalTable.rows.length === 0 || (bucketColumns.length && - firstTable.rows.every((row) => bucketColumns.every((col) => row[col] == null))); + props.data.rows.every((row) => bucketColumns.every((col) => row[col] == null))); const visibleColumns = useMemo( () => @@ -253,10 +251,10 @@ export const DatatableComponent = (props: DatatableRenderProps) => { columnConfig.columns .filter(({ columnId }) => isNumericMap[columnId]) .map(({ columnId }) => columnId), - firstTable, + props.data, getOriginalId ); - }, [firstTable, isNumericMap, columnConfig]); + }, [props.data, isNumericMap, columnConfig]); const headerRowHeight = props.args.headerRowHeight ?? 'single'; const headerRowLines = props.args.headerRowHeightLines ?? 1; @@ -376,7 +374,7 @@ export const DatatableComponent = (props: DatatableRenderProps) => { .map((config) => ({ columnId: config.columnId, summaryRowValue: config.summaryRowValue, - ...getFinalSummaryConfiguration(config.columnId, config, firstTable), + ...getFinalSummaryConfiguration(config.columnId, config, props.data), })) .filter(({ summaryRow }) => summaryRow !== 'none'); @@ -402,7 +400,7 @@ export const DatatableComponent = (props: DatatableRenderProps) => { ) : null; }; } - }, [columnConfig.columns, alignments, firstTable, columns]); + }, [columnConfig.columns, alignments, props.data, columns]); if (isEmpty) { return ( 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 8a899780515b2..3e798c5813041 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx @@ -6,56 +6,51 @@ */ import type { DatatableProps } from '../../common/expressions'; -import type { LensMultiTable } from '../../common'; import { createMockExecutionContext } from '@kbn/expressions-plugin/common/mocks'; import type { FormatFactory } from '../../common'; import { getDatatable } from '../../common/expressions'; +import { Datatable } from '@kbn/expressions-plugin'; function sampleArgs() { const indexPatternId = 'indexPatternId'; - const data: LensMultiTable = { - type: 'lens_multitable', - tables: { - l1: { - type: 'datatable', - columns: [ - { - id: 'a', - name: 'a', - meta: { - type: 'string', - source: 'esaggs', - field: 'a', - sourceParams: { type: 'terms', indexPatternId }, - }, - }, - { - id: 'b', - name: 'b', - meta: { - type: 'date', - field: 'b', - source: 'esaggs', - sourceParams: { - type: 'date_histogram', - indexPatternId, - }, - }, - }, - { - id: 'c', - name: 'c', - meta: { - type: 'number', - source: 'esaggs', - field: 'c', - sourceParams: { indexPatternId, type: 'count' }, - }, + const data: Datatable = { + type: 'datatable', + columns: [ + { + id: 'a', + name: 'a', + meta: { + type: 'string', + source: 'esaggs', + field: 'a', + sourceParams: { type: 'terms', indexPatternId }, + }, + }, + { + id: 'b', + name: 'b', + meta: { + type: 'date', + field: 'b', + source: 'esaggs', + sourceParams: { + type: 'date_histogram', + indexPatternId, }, - ], - rows: [{ a: 'shoes', b: 1588024800000, c: 3 }], + }, + }, + { + id: 'c', + name: 'c', + meta: { + type: 'number', + source: 'esaggs', + field: 'c', + sourceParams: { indexPatternId, type: 'count' }, + }, }, - }, + ], + rows: [{ a: 'shoes', b: 1588024800000, c: 3 }], }; const args: DatatableProps['args'] = { diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 1053eadce1363..3ae8057114198 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -46,16 +46,15 @@ export const getDatatableRenderer = (dependencies: { // ROW_CLICK_TRIGGER trigger. let rowHasRowClickTriggerActions: boolean[] = []; if (hasCompatibleActions) { - const table = Object.values(config.data.tables)[0]; - if (!!table) { + if (!!config.data) { rowHasRowClickTriggerActions = await Promise.all( - table.rows.map(async (row, rowIndex) => { + config.data.rows.map(async (row, rowIndex) => { try { const hasActions = await hasCompatibleActions({ name: 'tableRowContextMenuClick', data: { rowIndex, - table, + table: config.data, columns: config.args.columns.map((column) => column.columnId), }, }); diff --git a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx index 8087f43b90e72..4cc44a1b70293 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx @@ -326,7 +326,12 @@ export const getDatatableVisualization = ({ } }, - toExpression(state, datasourceLayers, { title, description } = {}): Ast | null { + toExpression( + state, + datasourceLayers, + { title, description } = {}, + datasourceExpressionsByLayers = {} + ): Ast | null { const { sortedColumns, datasource } = getDataSourceAndSortedColumns(state, datasourceLayers, state.layerId) || {}; @@ -346,9 +351,12 @@ export const getDatatableVisualization = ({ .filter((columnId) => datasource!.getOperationForColumnId(columnId)) .map((columnId) => columnMap[columnId]); + const datasourceExpression = datasourceExpressionsByLayers[state.layerId]; + return { type: 'expression', chain: [ + ...(datasourceExpression?.chain ?? []), { type: 'function', function: 'lens_datatable', diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx index 91ca494866f30..796128df989b4 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx @@ -32,7 +32,6 @@ import { EditorFrame, EditorFrameProps } from './editor_frame'; import { DatasourcePublicAPI, DatasourceSuggestion, Visualization } from '../../types'; import { act } from 'react-dom/test-utils'; import { coreMock } from '@kbn/core/public/mocks'; -import { fromExpression } from '@kbn/interpreter'; import { createMockVisualization, createMockDatasource, @@ -49,6 +48,7 @@ import { expressionsPluginMock } from '@kbn/expressions-plugin/public/mocks'; import { mockDataPlugin, mountWithProvider } from '../../mocks'; import { setState } from '../../state_management'; import { getLensInspectorService } from '../../lens_inspector_service'; +import { toExpression } from '@kbn/interpreter'; function generateSuggestion(state = {}): DatasourceSuggestion { return { @@ -209,10 +209,20 @@ describe('editor_frame', () => { it('should render the resulting expression using the expression renderer', async () => { mockDatasource.getLayers.mockReturnValue(['first']); - const props = { + const props: EditorFrameProps = { ...getDefaultProps(), visualizationMap: { - testVis: { ...mockVisualization, toExpression: () => 'testVis' }, + testVis: { + ...mockVisualization, + toExpression: (state, datasourceLayers, attrs, datasourceExpressionsByLayers = {}) => + toExpression({ + type: 'expression', + chain: [ + ...(datasourceExpressionsByLayers.first?.chain ?? []), + { type: 'function', function: 'testVis', arguments: {} }, + ], + }), + }, }, datasourceMap: { testDatasource: { @@ -242,137 +252,10 @@ describe('editor_frame', () => { instance.update(); expect(instance.find(expressionRendererMock).prop('expression')).toMatchInlineSnapshot(` - "kibana - | lens_merge_tables layerIds=\\"first\\" tables={datasource} + "datasource | testVis" `); }); - - it('should render individual expression for each given layer', async () => { - mockDatasource.toExpression.mockReturnValue('datasource'); - mockDatasource2.toExpression.mockImplementation((_state, layerId) => `datasource_${layerId}`); - mockDatasource.initialize.mockImplementation((initialState) => Promise.resolve(initialState)); - mockDatasource.getLayers.mockReturnValue(['first', 'second']); - mockDatasource2.initialize.mockImplementation((initialState) => - Promise.resolve(initialState) - ); - mockDatasource2.getLayers.mockReturnValue(['third']); - - const props = { - ...getDefaultProps(), - visualizationMap: { - testVis: { ...mockVisualization, toExpression: () => 'testVis' }, - }, - datasourceMap: { - testDatasource: { - ...mockDatasource, - toExpression: () => 'datasource', - }, - testDatasource2: { - ...mockDatasource2, - toExpression: () => 'datasource_second', - }, - }, - - ExpressionRenderer: expressionRendererMock, - }; - - instance = ( - await mountWithProvider(, { - preloadedState: { - visualization: { activeId: 'testVis', state: {} }, - datasourceStates: { - testDatasource: { - isLoading: false, - state: { - internalState1: '', - }, - }, - testDatasource2: { - isLoading: false, - state: { - internalState1: '', - }, - }, - }, - }, - }) - ).instance; - - instance.update(); - - expect( - fromExpression(instance.find(expressionRendererMock).prop('expression') as string) - ).toEqual({ - type: 'expression', - chain: expect.arrayContaining([ - expect.objectContaining({ - arguments: expect.objectContaining({ layerIds: ['first', 'second', 'third'] }), - }), - ]), - }); - expect(fromExpression(instance.find(expressionRendererMock).prop('expression') as string)) - .toMatchInlineSnapshot(` - Object { - "chain": Array [ - Object { - "arguments": Object {}, - "function": "kibana", - "type": "function", - }, - Object { - "arguments": Object { - "layerIds": Array [ - "first", - "second", - "third", - ], - "tables": Array [ - Object { - "chain": Array [ - Object { - "arguments": Object {}, - "function": "datasource", - "type": "function", - }, - ], - "type": "expression", - }, - Object { - "chain": Array [ - Object { - "arguments": Object {}, - "function": "datasource", - "type": "function", - }, - ], - "type": "expression", - }, - Object { - "chain": Array [ - Object { - "arguments": Object {}, - "function": "datasource_second", - "type": "function", - }, - ], - "type": "expression", - }, - ], - }, - "function": "lens_merge_tables", - "type": "function", - }, - Object { - "arguments": Object {}, - "function": "testVis", - "type": "function", - }, - ], - "type": "expression", - } - `); - }); }); describe('state update', () => { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/expression_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/expression_helpers.ts index b5fa32cd8e306..367d156929714 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/expression_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/expression_helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Ast, AstFunction, fromExpression } from '@kbn/interpreter'; +import { Ast, fromExpression } from '@kbn/interpreter'; import { DatasourceStates } from '../../state_management'; import { Visualization, DatasourceMap, DatasourceLayers } from '../../types'; @@ -16,8 +16,12 @@ export function getDatasourceExpressionsByLayers( const datasourceExpressions: Array<[string, Ast | string]> = []; Object.entries(datasourceMap).forEach(([datasourceId, datasource]) => { - const state = datasourceStates[datasourceId].state; - const layers = datasource.getLayers(datasourceStates[datasourceId].state); + const state = datasourceStates[datasourceId]?.state; + if (!state) { + return; + } + + const layers = datasource.getLayers(state); layers.forEach((layerId) => { const result = datasource.toExpression(state, layerId); @@ -40,46 +44,6 @@ export function getDatasourceExpressionsByLayers( ); } -export function prependDatasourceExpression( - visualizationExpression: Ast | string | null, - datasourceMap: DatasourceMap, - datasourceStates: DatasourceStates -): Ast | null { - const datasourceExpressionsByLayers = getDatasourceExpressionsByLayers( - datasourceMap, - datasourceStates - ); - - if (datasourceExpressionsByLayers === null || visualizationExpression === null) { - return null; - } - - const parsedDatasourceExpressions = Object.entries(datasourceExpressionsByLayers); - - const datafetchExpression: AstFunction = { - type: 'function', - function: 'lens_merge_tables', - arguments: { - layerIds: parsedDatasourceExpressions.map(([id]) => id), - tables: parsedDatasourceExpressions.map(([, expr]) => expr), - }, - }; - - const parsedVisualizationExpression = - typeof visualizationExpression === 'string' - ? fromExpression(visualizationExpression) - : visualizationExpression; - - return { - type: 'expression', - chain: [ - { type: 'function', function: 'kibana', arguments: {} }, - datafetchExpression, - ...parsedVisualizationExpression.chain, - ], - }; -} - export function buildExpression({ visualization, visualizationState, @@ -101,31 +65,26 @@ export function buildExpression({ return null; } - if (visualization.shouldBuildDatasourceExpressionManually?.()) { - const datasourceExpressionsByLayers = getDatasourceExpressionsByLayers( - datasourceMap, - datasourceStates - ); + const datasourceExpressionsByLayers = getDatasourceExpressionsByLayers( + datasourceMap, + datasourceStates + ); - const visualizationExpression = visualization.toExpression( - visualizationState, - datasourceLayers, - { - title, - description, - }, - datasourceExpressionsByLayers ?? undefined - ); + const visualizationExpression = visualization.toExpression( + visualizationState, + datasourceLayers, + { + title, + description, + }, + datasourceExpressionsByLayers ?? undefined + ); - return typeof visualizationExpression === 'string' - ? fromExpression(visualizationExpression) - : visualizationExpression; + if (datasourceExpressionsByLayers === null || visualizationExpression === null) { + return null; } - const visualizationExpression = visualization.toExpression(visualizationState, datasourceLayers, { - title, - description, - }); - - return prependDatasourceExpression(visualizationExpression, datasourceMap, datasourceStates); + return typeof visualizationExpression === 'string' + ? fromExpression(visualizationExpression) + : visualizationExpression; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.test.tsx index cda496aa693e8..7eff9a5961e83 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.test.tsx @@ -386,9 +386,7 @@ describe('suggestion_panel', () => { const passedExpression = (expressionRendererMock as jest.Mock).mock.calls[0][0].expression; expect(passedExpression).toMatchInlineSnapshot(` - "kibana - | lens_merge_tables layerIds=\\"first\\" tables={datasource_expression} - | test + "test | expression" `); }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx index dc36e0a671cf0..abd6da25c52ea 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx @@ -39,10 +39,7 @@ import { DatasourceLayers, } from '../../types'; import { getSuggestions, switchToSuggestion } from './suggestion_helpers'; -import { - getDatasourceExpressionsByLayers, - prependDatasourceExpression, -} from './expression_helpers'; +import { getDatasourceExpressionsByLayers } from './expression_helpers'; import { trackUiEvent, trackSuggestionEvent } from '../../lens_ui_telemetry'; import { getMissingIndexPattern, @@ -522,22 +519,15 @@ function getPreviewExpression( }); } - if (visualization.shouldBuildDatasourceExpressionManually?.()) { - const datasourceExpressionsByLayers = getDatasourceExpressionsByLayers( - datasources, - datasourceStates - ); - - return visualization.toPreviewExpression( - visualizableState.visualizationState, - suggestionFrameApi.datasourceLayers, - datasourceExpressionsByLayers ?? undefined - ); - } + const datasourceExpressionsByLayers = getDatasourceExpressionsByLayers( + datasources, + datasourceStates + ); return visualization.toPreviewExpression( visualizableState.visualizationState, - suggestionFrameApi.datasourceLayers + suggestionFrameApi.datasourceLayers, + datasourceExpressionsByLayers ?? undefined ); } @@ -561,15 +551,11 @@ function preparePreviewExpression( } : datasourceStates; - const previewExprDatasourcesStates = visualization.shouldBuildDatasourceExpressionManually?.() - ? datasourceStatesWithSuggestions - : datasourceStates; - const expression = getPreviewExpression( visualizableState, visualization, datasourceMap, - previewExprDatasourcesStates, + datasourceStatesWithSuggestions, framePublicAPI ); @@ -577,9 +563,5 @@ function preparePreviewExpression( return; } - if (visualization.shouldBuildDatasourceExpressionManually?.()) { - return typeof expression === 'string' ? fromExpression(expression) : expression; - } - - return prependDatasourceExpression(expression, datasourceMap, datasourceStatesWithSuggestions); + return typeof expression === 'string' ? fromExpression(expression) : expression; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx index 6e546459a7011..d12d4beb02f2c 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx @@ -26,7 +26,6 @@ jest.mock('../../../debounced_component', () => { import { WorkspacePanel } from './workspace_panel'; import { ReactWrapper } from 'enzyme'; import { DragDrop, ChildDragDropProvider } from '../../../drag_drop'; -import { fromExpression } from '@kbn/interpreter'; import { buildExistsFilter } from '@kbn/es-query'; import { coreMock } from '@kbn/core/public/mocks'; import { DataView } from '@kbn/data-views-plugin/public'; @@ -44,6 +43,7 @@ import { import { getLensInspectorService } from '../../../lens_inspector_service'; import { inspectorPluginMock } from '@kbn/inspector-plugin/public/mocks'; import { disableAutoApply, enableAutoApply } from '../../../state_management/lens_slice'; +import { Ast, toExpression } from '@kbn/interpreter'; const defaultPermissions: Record>> = { navLinks: { management: true }, @@ -73,6 +73,19 @@ const defaultProps = { toggleFullscreen: jest.fn(), }; +const toExpr = ( + datasourceExpressionsByLayers: Record, + fn: string = 'testVis', + layerId: string = 'first' +) => + toExpression({ + type: 'expression', + chain: [ + ...(datasourceExpressionsByLayers[layerId]?.chain ?? []), + { type: 'function', function: fn, arguments: {} }, + ], + }); + const SELECTORS = { applyChangesButton: 'button[data-test-subj="lnsApplyChanges__toolbar"]', dragDropPrompt: '[data-test-subj="workspace-drag-drop-prompt"]', @@ -148,7 +161,11 @@ describe('workspace_panel', () => { 'testVis' }, + testVis: { + ...mockVisualization, + toExpression: (state, datasourceLayers, attrs, datasourceExpressionsByLayers = {}) => + toExpr(datasourceExpressionsByLayers), + }, }} />, @@ -177,7 +194,11 @@ describe('workspace_panel', () => { }} framePublicAPI={framePublicAPI} visualizationMap={{ - testVis: { ...mockVisualization, toExpression: () => 'testVis' }, + testVis: { + ...mockVisualization, + toExpression: (state, datasourceLayers, attrs, datasourceExpressionsByLayers = {}) => + toExpr(datasourceExpressionsByLayers), + }, }} ExpressionRenderer={expressionRendererMock} /> @@ -188,8 +209,7 @@ describe('workspace_panel', () => { instance.update(); expect(instance.find(expressionRendererMock).prop('expression')).toMatchInlineSnapshot(` - "kibana - | lens_merge_tables layerIds=\\"first\\" tables={datasource} + "datasource | testVis" `); }); @@ -210,7 +230,11 @@ describe('workspace_panel', () => { }} framePublicAPI={framePublicAPI} visualizationMap={{ - testVis: { ...mockVisualization, toExpression: () => 'testVis' }, + testVis: { + ...mockVisualization, + toExpression: (state, datasourceLayers, attrs, datasourceExpressionsByLayers = {}) => + toExpr(datasourceExpressionsByLayers), + }, }} ExpressionRenderer={expressionRendererMock} />, @@ -228,26 +252,28 @@ describe('workspace_panel', () => { // allows initial render expect(getExpression()).toMatchInlineSnapshot(` - "kibana - | lens_merge_tables layerIds=\\"first\\" tables={datasource} - | testVis" - `); + "datasource + | testVis" + `); mockDatasource.toExpression.mockReturnValue('new-datasource'); act(() => { instance.setProps({ visualizationMap: { - testVis: { ...mockVisualization, toExpression: () => 'new-vis' }, + testVis: { + ...mockVisualization, + toExpression: (state, datasourceLayers, attrs, datasourceExpressionsByLayers = {}) => + toExpr(datasourceExpressionsByLayers, 'new-vis'), + } as Visualization, }, }); }); instance.update(); expect(getExpression()).toMatchInlineSnapshot(` - "kibana - | lens_merge_tables layerIds=\\"first\\" tables={datasource} - | testVis" - `); + "datasource + | testVis" + `); act(() => { mounted.lensStore.dispatch(applyChanges()); @@ -256,16 +282,19 @@ describe('workspace_panel', () => { // should update expect(getExpression()).toMatchInlineSnapshot(` - "kibana - | lens_merge_tables layerIds=\\"first\\" tables={new-datasource} - | new-vis" - `); + "new-datasource + | new-vis" + `); mockDatasource.toExpression.mockReturnValue('other-new-datasource'); act(() => { instance.setProps({ visualizationMap: { - testVis: { ...mockVisualization, toExpression: () => 'other-new-vis' }, + testVis: { + ...mockVisualization, + toExpression: (state, datasourceLayers, attrs, datasourceExpressionsByLayers = {}) => + toExpr(datasourceExpressionsByLayers, 'other-new-vis'), + } as Visualization, }, }); mounted.lensStore.dispatch(enableAutoApply()); @@ -274,10 +303,9 @@ describe('workspace_panel', () => { // reenabling auto-apply triggers an update as well expect(getExpression()).toMatchInlineSnapshot(` - "kibana - | lens_merge_tables layerIds=\\"first\\" tables={other-new-datasource} - | other-new-vis" - `); + "other-new-datasource + | other-new-vis" + `); }); it('should base saveability on working changes when auto-apply disabled', async () => { @@ -305,7 +333,11 @@ describe('workspace_panel', () => { }} framePublicAPI={framePublicAPI} visualizationMap={{ - testVis: { ...mockVisualization, toExpression: () => 'testVis' }, + testVis: { + ...mockVisualization, + toExpression: (state, datasourceLayers, attrs, datasourceExpressionsByLayers = {}) => + toExpr(datasourceExpressionsByLayers), + }, }} ExpressionRenderer={expressionRendererMock} /> @@ -318,10 +350,9 @@ describe('workspace_panel', () => { // allows initial render expect(instance.find(expressionRendererMock).prop('expression')).toMatchInlineSnapshot(` - "kibana - | lens_merge_tables layerIds=\\"first\\" tables={datasource} - | testVis" - `); + "datasource + | testVis" + `); expect(isSaveable()).toBe(true); act(() => { @@ -499,90 +530,6 @@ describe('workspace_panel', () => { }); }); - it('should include data fetching for each layer in the expression', async () => { - const mockDatasource2 = createMockDatasource('a'); - const framePublicAPI = createMockFramePublicAPI(); - framePublicAPI.datasourceLayers = { - first: mockDatasource.publicAPIMock, - second: mockDatasource2.publicAPIMock, - }; - mockDatasource.toExpression.mockReturnValue('datasource'); - mockDatasource.getLayers.mockReturnValue(['first']); - - mockDatasource2.toExpression.mockReturnValue('datasource2'); - mockDatasource2.getLayers.mockReturnValue(['second', 'third']); - - const mounted = await mountWithProvider( - 'testVis' }, - }} - ExpressionRenderer={expressionRendererMock} - />, - - { - preloadedState: { - datasourceStates: { - testDatasource: { - state: {}, - isLoading: false, - }, - mock2: { - state: {}, - isLoading: false, - }, - }, - }, - } - ); - instance = mounted.instance; - instance.update(); - - const ast = fromExpression(instance.find(expressionRendererMock).prop('expression') as string); - - expect(ast.chain[1].arguments.layerIds).toEqual(['first', 'second', 'third']); - expect(ast.chain[1].arguments.tables).toMatchInlineSnapshot(` - Array [ - Object { - "chain": Array [ - Object { - "arguments": Object {}, - "function": "datasource", - "type": "function", - }, - ], - "type": "expression", - }, - Object { - "chain": Array [ - Object { - "arguments": Object {}, - "function": "datasource2", - "type": "function", - }, - ], - "type": "expression", - }, - Object { - "chain": Array [ - Object { - "arguments": Object {}, - "function": "datasource2", - "type": "function", - }, - ], - "type": "expression", - }, - ] - `); - }); - it('should run the expression again if the date range changes', async () => { const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { diff --git a/x-pack/plugins/lens/public/expressions.ts b/x-pack/plugins/lens/public/expressions.ts index ba8c07078a208..a52d835e3f002 100644 --- a/x-pack/plugins/lens/public/expressions.ts +++ b/x-pack/plugins/lens/public/expressions.ts @@ -8,22 +8,17 @@ import type { ExpressionsSetup } from '@kbn/expressions-plugin/public'; import { getDatatable } from '../common/expressions/datatable/datatable'; import { datatableColumn } from '../common/expressions/datatable/datatable_column'; -import { mergeTables } from '../common/expressions/merge_tables'; import { renameColumns } from '../common/expressions/rename_columns/rename_columns'; import { formatColumn } from '../common/expressions/format_column'; import { counterRate } from '../common/expressions/counter_rate'; import { getTimeScale } from '../common/expressions/time_scale/time_scale'; -import { lensMultitable } from '../common/expressions'; export const setupExpressions = ( expressions: ExpressionsSetup, formatFactory: Parameters[0], getTimeZone: Parameters[0] ) => { - [lensMultitable].forEach((expressionType) => expressions.registerType(expressionType)); - [ - mergeTables, counterRate, formatColumn, renameColumns, diff --git a/x-pack/plugins/lens/public/heatmap_visualization/visualization.tsx b/x-pack/plugins/lens/public/heatmap_visualization/visualization.tsx index f0a8e65889e8e..46c86d8c0adb0 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/heatmap_visualization/visualization.tsx @@ -295,8 +295,14 @@ export const getHeatmapVisualization = ({ } }, - toExpression(state, datasourceLayers, attributes): Ast | null { + toExpression( + state, + datasourceLayers, + attributes, + datasourceExpressionsByLayers = {} + ): Ast | null { const datasource = datasourceLayers[state.layerId]; + const datasourceExpression = datasourceExpressionsByLayers[state.layerId]; const originalOrder = datasource.getTableSpec().map(({ columnId }) => columnId); // When we add a column it could be empty, and therefore have no order @@ -308,6 +314,7 @@ export const getHeatmapVisualization = ({ return { type: 'expression', chain: [ + ...(datasourceExpression?.chain ?? []), { type: 'function', function: FUNCTION_NAME, @@ -383,8 +390,9 @@ export const getHeatmapVisualization = ({ }; }, - toPreviewExpression(state, datasourceLayers): Ast | null { + toPreviewExpression(state, datasourceLayers, datasourceExpressionsByLayers = {}): Ast | null { const datasource = datasourceLayers[state.layerId]; + const datasourceExpression = datasourceExpressionsByLayers[state.layerId]; const originalOrder = datasource.getTableSpec().map(({ columnId }) => columnId); // When we add a column it could be empty, and therefore have no order @@ -396,6 +404,7 @@ export const getHeatmapVisualization = ({ return { type: 'expression', chain: [ + ...(datasourceExpression?.chain ?? []), { type: 'function', function: FUNCTION_NAME, diff --git a/x-pack/plugins/lens/public/index.ts b/x-pack/plugins/lens/public/index.ts index b8d00e7ff61b8..edf57ba703a2e 100644 --- a/x-pack/plugins/lens/public/index.ts +++ b/x-pack/plugins/lens/public/index.ts @@ -87,7 +87,6 @@ export type { IconPosition, ExtendedYConfigResult, DataLayerArgs, - LensMultiTable, ValueLabelMode, AxisExtentMode, DataLayerConfig, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts index db10c420b90de..6806b1ce47795 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts @@ -383,6 +383,11 @@ describe('IndexPattern Data Source', () => { expect(indexPatternDatasource.toExpression(state, 'first')).toMatchInlineSnapshot(` Object { "chain": Array [ + Object { + "arguments": Object {}, + "function": "kibana", + "type": "function", + }, Object { "arguments": Object { "aggs": Array [ @@ -552,7 +557,7 @@ describe('IndexPattern Data Source', () => { const state = enrichBaseState(queryBaseState); const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; - expect(ast.chain[0].arguments.timeFields).toEqual(['timestamp', 'another_datefield']); + expect(ast.chain[1].arguments.timeFields).toEqual(['timestamp', 'another_datefield']); }); it('should pass time shift parameter to metric agg functions', async () => { @@ -589,7 +594,7 @@ describe('IndexPattern Data Source', () => { const state = enrichBaseState(queryBaseState); const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; - expect((ast.chain[0].arguments.aggs[1] as Ast).chain[0].arguments.timeShift).toEqual(['1d']); + expect((ast.chain[1].arguments.aggs[1] as Ast).chain[0].arguments.timeShift).toEqual(['1d']); }); it('should wrap filtered metrics in filtered metric aggregation', async () => { @@ -638,7 +643,7 @@ describe('IndexPattern Data Source', () => { const state = enrichBaseState(queryBaseState); const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; - expect(ast.chain[0].arguments.aggs[0]).toMatchInlineSnapshot(` + expect(ast.chain[1].arguments.aggs[0]).toMatchInlineSnapshot(` Object { "chain": Array [ Object { @@ -898,8 +903,8 @@ describe('IndexPattern Data Source', () => { const state = enrichBaseState(queryBaseState); const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; - expect(ast.chain[0].arguments.metricsAtAllLevels).toEqual([false]); - expect(JSON.parse(ast.chain[1].arguments.idMap[0] as string)).toEqual({ + expect(ast.chain[1].arguments.metricsAtAllLevels).toEqual([false]); + expect(JSON.parse(ast.chain[2].arguments.idMap[0] as string)).toEqual({ 'col-0-0': expect.objectContaining({ id: 'bucket1' }), 'col-1-1': expect.objectContaining({ id: 'bucket2' }), 'col-2-2': expect.objectContaining({ id: 'metric' }), @@ -939,8 +944,8 @@ describe('IndexPattern Data Source', () => { const state = enrichBaseState(queryBaseState); const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; - expect(ast.chain[0].arguments.timeFields).toEqual(['timestamp']); - expect(ast.chain[0].arguments.timeFields).not.toContain('timefield'); + expect(ast.chain[1].arguments.timeFields).toEqual(['timestamp']); + expect(ast.chain[1].arguments.timeFields).not.toContain('timefield'); }); describe('references', () => { @@ -988,7 +993,7 @@ describe('IndexPattern Data Source', () => { const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; // @ts-expect-error we can't isolate just the reference type expect(operationDefinitionMap.testReference.toExpression).toHaveBeenCalled(); - expect(ast.chain[2]).toEqual('mock'); + expect(ast.chain[3]).toEqual('mock'); }); it('should keep correct column mapping keys with reference columns present', async () => { @@ -1021,7 +1026,7 @@ describe('IndexPattern Data Source', () => { const state = enrichBaseState(queryBaseState); const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; - expect(JSON.parse(ast.chain[1].arguments.idMap[0] as string)).toEqual({ + expect(JSON.parse(ast.chain[2].arguments.idMap[0] as string)).toEqual({ 'col-0-0': expect.objectContaining({ id: 'col1', }), diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts b/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts index aee1abd34e7cb..0307e748ac1fb 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts @@ -277,6 +277,7 @@ function getExpressionForLayer( return { type: 'expression', chain: [ + { type: 'function', function: 'kibana', arguments: {} }, buildExpressionFunction('esaggs', { index: buildExpression([ buildExpressionFunction( diff --git a/x-pack/plugins/lens/public/metric_visualization/visualization.tsx b/x-pack/plugins/lens/public/metric_visualization/visualization.tsx index bbb5532e9ed9d..786d5b588baef 100644 --- a/x-pack/plugins/lens/public/metric_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/metric_visualization/visualization.tsx @@ -50,13 +50,15 @@ const toExpression = ( paletteService: PaletteRegistry, state: MetricState, datasourceLayers: DatasourceLayers, - attributes?: Partial> + attributes?: Partial>, + datasourceExpressionsByLayers: Record | undefined = {} ): Ast | null => { if (!state.accessor) { return null; } const [datasource] = Object.values(datasourceLayers); + const datasourceExpression = datasourceExpressionsByLayers[state.layerId]; const operation = datasource && datasource.getOperationForColumnId(state.accessor); const stops = state.palette?.params?.stops || []; @@ -100,6 +102,7 @@ const toExpression = ( return { type: 'expression', chain: [ + ...(datasourceExpression?.chain ?? []), { type: 'function', function: 'metricVis', @@ -273,10 +276,23 @@ export const getMetricVisualization = ({ } }, - toExpression: (state, datasourceLayers, attributes) => - toExpression(paletteService, state, datasourceLayers, { ...attributes }), - toPreviewExpression: (state, datasourceLayers) => - toExpression(paletteService, state, datasourceLayers, { mode: 'reduced' }), + toExpression: (state, datasourceLayers, attributes, datasourceExpressionsByLayers) => + toExpression( + paletteService, + state, + datasourceLayers, + { ...attributes }, + datasourceExpressionsByLayers + ), + + toPreviewExpression: (state, datasourceLayers, datasourceExpressionsByLayers) => + toExpression( + paletteService, + state, + datasourceLayers, + { mode: 'reduced' }, + datasourceExpressionsByLayers + ), setDimension({ prevState, columnId }) { return { ...prevState, accessor: columnId }; diff --git a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts index 73ddeea627967..574f61bfc9232 100644 --- a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts +++ b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts @@ -247,7 +247,8 @@ function expressionHelper( state: PieVisualizationState, datasourceLayers: DatasourceLayers, paletteService: PaletteRegistry, - attributes: Attributes = { isPreview: false } + attributes: Attributes = { isPreview: false }, + datasourceExpressionsByLayers: Record ): Ast | null { const layer = state.layers[0]; const datasource = datasourceLayers[layer.layerId]; @@ -263,26 +264,55 @@ function expressionHelper( if (!layer.metric || !operations.length) { return null; } + const visualizationAst = generateExprAst( + state, + attributes, + operations, + layer, + datasourceLayers, + paletteService + ); - return generateExprAst(state, attributes, operations, layer, datasourceLayers, paletteService); + const datasourceAst = datasourceExpressionsByLayers[layer.layerId]; + return { + type: 'expression', + chain: [ + ...(datasourceAst ? datasourceAst.chain : []), + ...(visualizationAst ? visualizationAst.chain : []), + ], + }; } export function toExpression( state: PieVisualizationState, datasourceLayers: DatasourceLayers, paletteService: PaletteRegistry, - attributes: Partial<{ title: string; description: string }> = {} + attributes: Partial<{ title: string; description: string }> = {}, + datasourceExpressionsByLayers: Record | undefined = {} ) { - return expressionHelper(state, datasourceLayers, paletteService, { - ...attributes, - isPreview: false, - }); + return expressionHelper( + state, + datasourceLayers, + paletteService, + { + ...attributes, + isPreview: false, + }, + datasourceExpressionsByLayers + ); } export function toPreviewExpression( state: PieVisualizationState, datasourceLayers: DatasourceLayers, - paletteService: PaletteRegistry + paletteService: PaletteRegistry, + datasourceExpressionsByLayers: Record | undefined = {} ) { - return expressionHelper(state, datasourceLayers, paletteService, { isPreview: true }); + return expressionHelper( + state, + datasourceLayers, + paletteService, + { isPreview: true }, + datasourceExpressionsByLayers + ); } diff --git a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx index 665fd5522c36f..927c67dce68b7 100644 --- a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx @@ -241,9 +241,11 @@ export const getPieVisualization = ({ return state?.layers.find(({ layerId: id }) => id === layerId)?.layerType; }, - toExpression: (state, layers, attributes) => - toExpression(state, layers, paletteService, attributes), - toPreviewExpression: (state, layers) => toPreviewExpression(state, layers, paletteService), + toExpression: (state, layers, attributes, datasourceExpressionsByLayers) => + toExpression(state, layers, paletteService, attributes, datasourceExpressionsByLayers), + + toPreviewExpression: (state, layers, datasourceExpressionsByLayers) => + toPreviewExpression(state, layers, paletteService, datasourceExpressionsByLayers), renderToolbar(domElement, props) { render( diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 422430efaaec3..1f2ee1266ddb7 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -931,12 +931,6 @@ export interface Visualization { * On Edit events the frame will call this to know what's going to be the next visualization state */ onEditAction?: (state: T, event: LensEditEvent) => T; - - /** - * `datasourceExpressionsByLayers` will be passed to the params of `toExpression` and `toPreviewExpression` - * functions and datasource expressions will not be appended to the expression automatically. - */ - shouldBuildDatasourceExpressionManually?: () => boolean; } // Use same technique as TriggerContext diff --git a/x-pack/plugins/lens/public/visualizations/gauge/visualization.tsx b/x-pack/plugins/lens/public/visualizations/gauge/visualization.tsx index 74f7d518e1166..e85ef81a5dd8c 100644 --- a/x-pack/plugins/lens/public/visualizations/gauge/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/gauge/visualization.tsx @@ -113,9 +113,11 @@ const toExpression = ( paletteService: PaletteRegistry, state: GaugeVisualizationState, datasourceLayers: DatasourceLayers, - attributes?: Partial> + attributes?: Partial>, + datasourceExpressionsByLayers: Record | undefined = {} ): Ast | null => { const datasource = datasourceLayers[state.layerId]; + const datasourceExpression = datasourceExpressionsByLayers[state.layerId]; const originalOrder = datasource.getTableSpec().map(({ columnId }) => columnId); if (!originalOrder || !state.metricAccessor) { @@ -125,6 +127,7 @@ const toExpression = ( return { type: 'expression', chain: [ + ...(datasourceExpression?.chain ?? []), { type: 'function', function: EXPRESSION_GAUGE_NAME, @@ -420,10 +423,17 @@ export const getGaugeVisualization = ({ } }, - toExpression: (state, datasourceLayers, attributes) => - toExpression(paletteService, state, datasourceLayers, { ...attributes }), - toPreviewExpression: (state, datasourceLayers) => - toExpression(paletteService, state, datasourceLayers), + toExpression: (state, datasourceLayers, attributes, datasourceExpressionsByLayers = {}) => + toExpression( + paletteService, + state, + datasourceLayers, + { ...attributes }, + datasourceExpressionsByLayers + ), + + toPreviewExpression: (state, datasourceLayers, datasourceExpressionsByLayers = {}) => + toExpression(paletteService, state, datasourceLayers, undefined, datasourceExpressionsByLayers), getErrorMessages(state) { // not possible to break it? diff --git a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap index 9c4ee0d3b245f..afdfd8e200100 100644 --- a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap +++ b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap @@ -134,13 +134,7 @@ Object { ], "table": Array [ Object { - "chain": Array [ - Object { - "arguments": Object {}, - "function": "kibana", - "type": "function", - }, - ], + "chain": Array [], "type": "expression", }, ], diff --git a/x-pack/plugins/lens/public/xy_visualization/color_assignment.test.ts b/x-pack/plugins/lens/public/xy_visualization/color_assignment.test.ts index a329c12b083a5..67febcd4b9d00 100644 --- a/x-pack/plugins/lens/public/xy_visualization/color_assignment.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/color_assignment.test.ts @@ -6,9 +6,10 @@ */ import { getColorAssignments } from './color_assignment'; -import type { FormatFactory, LensMultiTable } from '../../common'; +import type { FormatFactory } from '../../common'; import { layerTypes } from '../../common'; import { XYDataLayerConfig } from './types'; +import { Datatable } from '@kbn/expressions-plugin'; describe('color_assignment', () => { const layers: XYDataLayerConfig[] = [ @@ -30,8 +31,7 @@ describe('color_assignment', () => { }, ]; - const data: LensMultiTable = { - type: 'lens_multitable', + const data: { tables: Record } = { tables: { '1': { type: 'datatable', diff --git a/x-pack/plugins/lens/public/xy_visualization/to_expression.ts b/x-pack/plugins/lens/public/xy_visualization/to_expression.ts index 1acc53a9db512..cf9a441fc6f53 100644 --- a/x-pack/plugins/lens/public/xy_visualization/to_expression.ts +++ b/x-pack/plugins/lens/public/xy_visualization/to_expression.ts @@ -12,7 +12,6 @@ import type { PaletteRegistry } from '@kbn/coloring'; import { EventAnnotationServiceType } from '@kbn/event-annotation-plugin/public'; import { LegendSize } from '@kbn/visualizations-plugin/common/constants'; import type { AxisExtentConfig, YConfig, ExtendedYConfig } from '@kbn/expression-xy-plugin/common'; -import type { ExpressionAstExpression } from '@kbn/expressions-plugin/common'; import { State, XYDataLayerConfig, @@ -345,11 +344,6 @@ export const buildExpression = ( }; }; -const buildTableExpression = (datasourceExpression: Ast): ExpressionAstExpression => ({ - type: 'expression', - chain: [{ type: 'function', function: 'kibana', arguments: {} }, ...datasourceExpression.chain], -}); - const referenceLineLayerToExpression = ( layer: XYReferenceLineLayerConfig, datasourceLayer: DatasourcePublicAPI, @@ -370,7 +364,7 @@ const referenceLineLayerToExpression = ( : [], accessors: layer.accessors, columnToLabel: [JSON.stringify(getColumnToLabelMap(layer, datasourceLayer))], - ...(datasourceExpression ? { table: [buildTableExpression(datasourceExpression)] } : {}), + ...(datasourceExpression ? { table: [datasourceExpression] } : {}), }, }, ], @@ -439,7 +433,7 @@ const dataLayerToExpression = ( seriesType: [layer.seriesType], accessors: layer.accessors, columnToLabel: [JSON.stringify(columnToLabel)], - ...(datasourceExpression ? { table: [buildTableExpression(datasourceExpression)] } : {}), + ...(datasourceExpression ? { table: [datasourceExpression] } : {}), palette: [ { type: 'expression', diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx index 97bac36a93465..6c3fe3dcaea7f 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx @@ -514,8 +514,6 @@ export const getXyVisualization = ({ ); }, - shouldBuildDatasourceExpressionManually: () => true, - toExpression: (state, layers, attributes, datasourceExpressionsByLayers = {}) => toExpression( state, diff --git a/x-pack/plugins/lens/server/expressions/expressions.ts b/x-pack/plugins/lens/server/expressions/expressions.ts index b124a9cbaf33b..d5bb5587b982e 100644 --- a/x-pack/plugins/lens/server/expressions/expressions.ts +++ b/x-pack/plugins/lens/server/expressions/expressions.ts @@ -13,7 +13,6 @@ import { renameColumns, getTimeScale, getDatatable, - lensMultitable, } from '../../common/expressions'; import { getFormatFactory, getTimeZoneFactory } from './utils'; @@ -23,8 +22,6 @@ export const setupExpressions = ( core: CoreSetup, expressions: ExpressionsServerSetup ) => { - [lensMultitable].forEach((expressionType) => expressions.registerType(expressionType)); - [ counterRate, formatColumn, diff --git a/x-pack/plugins/maps/public/lens/choropleth_chart/choropleth_chart.tsx b/x-pack/plugins/maps/public/lens/choropleth_chart/choropleth_chart.tsx index 5089a8cc6c8d5..467c2ce92ff6e 100644 --- a/x-pack/plugins/maps/public/lens/choropleth_chart/choropleth_chart.tsx +++ b/x-pack/plugins/maps/public/lens/choropleth_chart/choropleth_chart.tsx @@ -45,12 +45,10 @@ export function ChoroplethChart({ return null; } - const table = data.tables[args.layerId]; - let emsLayerId = args.emsLayerId ? args.emsLayerId : emsWorldLayerId; let emsField = args.emsField ? args.emsField : 'iso2'; if (!args.emsLayerId || !args.emsField) { - const emsSuggestion = getEmsSuggestion(emsFileLayers, table, args.regionAccessor); + const emsSuggestion = getEmsSuggestion(emsFileLayers, data, args.regionAccessor); if (emsSuggestion) { emsLayerId = emsSuggestion.layerId; emsField = emsSuggestion.field; @@ -66,7 +64,7 @@ export function ChoroplethChart({ defaultMessage: '{emsLayerLabel} by {accessorLabel}', values: { emsLayerLabel, - accessorLabel: getAccessorLabel(table, args.valueAccessor), + accessorLabel: getAccessorLabel(data, args.valueAccessor), }, }) : '', @@ -76,16 +74,16 @@ export function ChoroplethChart({ right: { id: args.valueAccessor, type: SOURCE_TYPES.TABLE_SOURCE, - __rows: table.rows, + __rows: data.rows, __columns: [ { name: args.regionAccessor, - label: getAccessorLabel(table, args.regionAccessor), + label: getAccessorLabel(data, args.regionAccessor), type: 'string', }, { name: args.valueAccessor, - label: getAccessorLabel(table, args.valueAccessor), + label: getAccessorLabel(data, args.valueAccessor), type: 'number', }, ], diff --git a/x-pack/plugins/maps/public/lens/choropleth_chart/expression_function.ts b/x-pack/plugins/maps/public/lens/choropleth_chart/expression_function.ts index 7ed1ddfbd4381..989cc06c5d53b 100644 --- a/x-pack/plugins/maps/public/lens/choropleth_chart/expression_function.ts +++ b/x-pack/plugins/maps/public/lens/choropleth_chart/expression_function.ts @@ -6,8 +6,8 @@ */ import type { ExpressionFunctionDefinition } from '@kbn/expressions-plugin/common'; +import { Datatable } from '@kbn/expressions-plugin/common'; import { i18n } from '@kbn/i18n'; -import type { LensMultiTable } from '@kbn/lens-plugin/common'; import { prepareLogTable } from '@kbn/visualizations-plugin/common/utils'; import type { ChoroplethChartConfig, ChoroplethChartProps } from './types'; import { RENDERER_ID } from './expression_renderer'; @@ -20,7 +20,7 @@ interface ChoroplethChartRender { export const getExpressionFunction = (): ExpressionFunctionDefinition< 'lens_choropleth_chart', - LensMultiTable, + Datatable, Omit, ChoroplethChartRender > => ({ @@ -57,11 +57,14 @@ export const getExpressionFunction = (): ExpressionFunctionDefinition< help: 'Value accessor identifies the value column', }, }, - inputTypes: ['lens_multitable'], + inputTypes: ['datatable'], fn(data, args, handlers) { if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.reset(); + handlers.inspectorAdapters.tables.allowCsvExport = true; + const logTable = prepareLogTable( - Object.values(data.tables)[0], + data, [ [ args.valueAccessor ? [args.valueAccessor] : undefined, @@ -88,6 +91,6 @@ export const getExpressionFunction = (): ExpressionFunctionDefinition< data, args, }, - } as ChoroplethChartRender; + }; }, }); diff --git a/x-pack/plugins/maps/public/lens/choropleth_chart/types.ts b/x-pack/plugins/maps/public/lens/choropleth_chart/types.ts index 79c05a93ef2d4..7dc9a16056e77 100644 --- a/x-pack/plugins/maps/public/lens/choropleth_chart/types.ts +++ b/x-pack/plugins/maps/public/lens/choropleth_chart/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { LensMultiTable } from '@kbn/lens-plugin/common'; +import { Datatable } from '@kbn/expressions-plugin/common'; export interface ChoroplethChartState { layerId: string; @@ -21,6 +21,6 @@ export interface ChoroplethChartConfig extends ChoroplethChartState { } export interface ChoroplethChartProps { - data: LensMultiTable; + data: Datatable; args: ChoroplethChartConfig; } diff --git a/x-pack/plugins/maps/public/lens/choropleth_chart/visualization.tsx b/x-pack/plugins/maps/public/lens/choropleth_chart/visualization.tsx index cbac26f220163..54f459c3f7b38 100644 --- a/x-pack/plugins/maps/public/lens/choropleth_chart/visualization.tsx +++ b/x-pack/plugins/maps/public/lens/choropleth_chart/visualization.tsx @@ -138,14 +138,16 @@ export const getVisualization = ({ } }, - toExpression: (state, datasourceLayers, attributes) => { + toExpression: (state, datasourceLayers, attributes, datasourceExpressionsByLayers = {}) => { if (!state.regionAccessor || !state.valueAccessor) { return null; } + const datasourceExpression = datasourceExpressionsByLayers[state.layerId]; return { type: 'expression', chain: [ + ...(datasourceExpression ? datasourceExpression.chain : []), { type: 'function', function: 'lens_choropleth_chart', diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 704a6fe19ac17..513f83e23f177 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -365,7 +365,6 @@ "xpack.lens.functions.counterRate.args.outputColumnNameHelpText": "Nom de la colonne dans laquelle le taux de compteur résultant sera stocké", "xpack.lens.functions.counterRate.help": "Calcule le taux de compteur d'une colonne dans un tableau de données", "xpack.lens.functions.lastValue.missingSortField": "Cette vue de données ne contient aucun champ de date.", - "xpack.lens.functions.mergeTables.help": "Aide pour fusionner n'importe quel nombre de tableaux Kibana en un tableau unique et l'exposer via un adaptateur d'inspecteur", "xpack.lens.functions.renameColumns.help": "Aide pour renommer les colonnes d'un tableau de données", "xpack.lens.functions.renameColumns.idMap.help": "Un objet encodé JSON dans lequel les clés sont les anciens ID de colonne et les valeurs sont les nouveaux ID correspondants. Tous les autres ID de colonne sont conservés.", "xpack.lens.functions.timeScale.dateColumnMissingMessage": "L'ID de colonne de date {columnId} n'existe pas.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 8fe72dfd4a870..df42895ac2cbc 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -367,7 +367,6 @@ "xpack.lens.functions.counterRate.args.outputColumnNameHelpText": "結果のカウンターレートを格納する列の名前", "xpack.lens.functions.counterRate.help": "データテーブルの列のカウンターレートを計算します", "xpack.lens.functions.lastValue.missingSortField": "このデータビューには日付フィールドが含まれていません", - "xpack.lens.functions.mergeTables.help": "任意の数の Kibana 表を 1 つの表に結合し、インスペクターアダプター経由で公開するヘルパー", "xpack.lens.functions.renameColumns.help": "データベースの列の名前の変更をアシストします", "xpack.lens.functions.renameColumns.idMap.help": "キーが古い列 ID で値が対応する新しい列 ID となるように JSON エンコーディングされたオブジェクトです。他の列 ID はすべてのそのままです。", "xpack.lens.functions.timeScale.dateColumnMissingMessage": "指定した dateColumnId {columnId} は存在しません。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 6509cfadf3b99..6783295921119 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -372,7 +372,6 @@ "xpack.lens.functions.counterRate.args.outputColumnNameHelpText": "要存储结果计数率的列名称", "xpack.lens.functions.counterRate.help": "在数据表中计算列的计数率", "xpack.lens.functions.lastValue.missingSortField": "此数据视图不包含任何日期字段", - "xpack.lens.functions.mergeTables.help": "将任意数目的 kibana 表合并到单个表中并通过检查器适配器将其开放的助手", "xpack.lens.functions.renameColumns.help": "用于重命名数据表列的助手", "xpack.lens.functions.renameColumns.idMap.help": "旧列 ID 为键且相应新列 ID 为值的 JSON 编码对象。所有其他列 ID 都将保留。", "xpack.lens.functions.timeScale.dateColumnMissingMessage": "指定的 dateColumnId {columnId} 不存在。", diff --git a/x-pack/test/functional/apps/lens/group3/gauge.ts b/x-pack/test/functional/apps/lens/group3/gauge.ts index 9cbcbb606b423..ea029793ddfc0 100644 --- a/x-pack/test/functional/apps/lens/group3/gauge.ts +++ b/x-pack/test/functional/apps/lens/group3/gauge.ts @@ -48,6 +48,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should reflect edits for gauge', async () => { + await PageObjects.lens.switchToVisualization('horizontalBullet', 'gauge'); + await PageObjects.lens.waitForVisualization('gaugeChart'); await PageObjects.lens.configureDimension({ dimension: 'lnsGauge_metricDimensionPanel > lns-dimensionTrigger', operation: 'count',