diff --git a/x-pack/plugins/lens/common/expressions/collapse/index.ts b/x-pack/plugins/lens/common/expressions/collapse/index.ts index 43874859411fc..2b1e89af08bd4 100644 --- a/x-pack/plugins/lens/common/expressions/collapse/index.ts +++ b/x-pack/plugins/lens/common/expressions/collapse/index.ts @@ -16,6 +16,8 @@ export interface CollapseArgs { fn: CollapseFunction[]; } +export type { CollapseExpressionFunction }; + /** * Collapses multiple rows into a single row using the specified function. * diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable_column.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable_column.ts index f955cc1dfa2cb..16e76d3baf2e4 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable_column.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable_column.ts @@ -48,13 +48,14 @@ export interface ColumnState { } export type DatatableColumnResult = ColumnState & { type: 'lens_datatable_column' }; - -export const datatableColumn: ExpressionFunctionDefinition< +export type DatatableColumnFunction = ExpressionFunctionDefinition< 'lens_datatable_column', null, ColumnState & { sortingHint?: SortingHint }, DatatableColumnResult -> = { +>; + +export const datatableColumn: DatatableColumnFunction = { name: 'lens_datatable_column', aliases: [], type: 'lens_datatable_column', diff --git a/x-pack/plugins/lens/common/expressions/datatable/index.ts b/x-pack/plugins/lens/common/expressions/datatable/index.ts index 2fa0312360297..7003fd8d486b8 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/index.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/index.ts @@ -8,4 +8,4 @@ export * from './datatable_column'; export * from './datatable'; -export type { DatatableProps } from './types'; +export type { DatatableProps, DatatableExpressionFunction } from './types'; diff --git a/x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx b/x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx index e6683aee13499..a38d669d73cd5 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx @@ -550,22 +550,16 @@ describe('Datatable Visualization', () => { expect(columnArgs[0].arguments).toEqual( expect.objectContaining({ columnId: ['c'], - hidden: [], - width: [], - isTransposed: [], + palette: [expect.any(Object)], transposable: [true], - alignment: [], colorMode: ['none'], }) ); expect(columnArgs[1].arguments).toEqual( expect.objectContaining({ columnId: ['b'], - hidden: [], - width: [], - isTransposed: [], + palette: [expect.objectContaining({})], transposable: [true], - alignment: [], colorMode: ['none'], }) ); @@ -592,14 +586,16 @@ describe('Datatable Visualization', () => { }); it('sets pagination based on state', () => { - expect(getDatatableExpressionArgs({ ...defaultExpressionTableState }).pageSize).toEqual([]); + expect(getDatatableExpressionArgs({ ...defaultExpressionTableState }).pageSize).toEqual( + undefined + ); expect( getDatatableExpressionArgs({ ...defaultExpressionTableState, paging: { size: 20, enabled: false }, }).pageSize - ).toEqual([]); + ).toEqual(undefined); expect( getDatatableExpressionArgs({ diff --git a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx index 60de4d4d1148c..ccfaff17a8ecb 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { render } from 'react-dom'; -import { Ast, AstFunction } from '@kbn/interpreter'; +import { Ast } from '@kbn/interpreter'; import { I18nProvider } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { PaletteRegistry, CUSTOM_PALETTE } from '@kbn/coloring'; @@ -16,6 +16,7 @@ import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { VIS_EVENT_TO_TRIGGER } from '@kbn/visualizations-plugin/public'; import { IconChartDatatable } from '@kbn/chart-icons'; import { LayerTypes } from '@kbn/expression-xy-plugin/public'; +import { buildExpression, buildExpressionFunction } from '@kbn/expressions-plugin/common'; import type { FormBasedPersistedState } from '../../datasources/form_based/types'; import type { SuggestionRequest, @@ -28,7 +29,14 @@ import { TableDimensionEditor } from './components/dimension_editor'; import { TableDimensionEditorAdditionalSection } from './components/dimension_editor_addtional_section'; import type { LayerType } from '../../../common'; import { getDefaultSummaryLabel } from '../../../common/expressions/datatable/summary'; -import type { ColumnState, SortingState, PagingState } from '../../../common/expressions'; +import type { + ColumnState, + SortingState, + PagingState, + CollapseExpressionFunction, + DatatableColumnFunction, + DatatableExpressionFunction, +} from '../../../common/expressions'; import { DataTableToolbar } from './components/toolbar'; export interface DatatableVisualizationState { @@ -398,108 +406,84 @@ export const getDatatableVisualization = ({ const datasourceExpression = datasourceExpressionsByLayers[state.layerId]; + const lensCollapseFnAsts = columns + .filter((c) => c.collapseFn) + .map((c) => + buildExpressionFunction('lens_collapse', { + by: columns + .filter( + (col) => + col.columnId !== c.columnId && + datasource!.getOperationForColumnId(col.columnId)?.isBucketed + ) + .map((col) => col.columnId), + metric: columns + .filter((col) => !datasource!.getOperationForColumnId(col.columnId)?.isBucketed) + .map((col) => col.columnId), + fn: [c.collapseFn!], + }).toAst() + ); + + const datatableFnAst = buildExpressionFunction('lens_datatable', { + title: title || '', + description: description || '', + columns: columns + .filter((c) => !c.collapseFn) + .map((column) => { + const paletteParams = { + ...column.palette?.params, + // rewrite colors and stops as two distinct arguments + colors: (column.palette?.params?.stops || []).map(({ color }) => color), + stops: + column.palette?.params?.name === 'custom' + ? (column.palette?.params?.stops || []).map(({ stop }) => stop) + : [], + reverse: false, // managed at UI level + }; + const sortingHint = datasource!.getOperationForColumnId(column.columnId)!.sortingHint; + + const hasNoSummaryRow = column.summaryRow == null || column.summaryRow === 'none'; + + const canColor = + datasource!.getOperationForColumnId(column.columnId)?.dataType === 'number'; + + const datatableColumnFn = buildExpressionFunction( + 'lens_datatable_column', + { + columnId: column.columnId, + hidden: column.hidden, + oneClickFilter: column.oneClickFilter, + width: column.width, + isTransposed: column.isTransposed, + transposable: !datasource!.getOperationForColumnId(column.columnId)?.isBucketed, + alignment: column.alignment, + colorMode: canColor && column.colorMode ? column.colorMode : 'none', + palette: paletteService.get(CUSTOM_PALETTE).toExpression(paletteParams), + summaryRow: hasNoSummaryRow ? undefined : column.summaryRow!, + summaryLabel: hasNoSummaryRow + ? undefined + : column.summaryLabel ?? getDefaultSummaryLabel(column.summaryRow!), + sortingHint, + } + ); + return buildExpression([datatableColumnFn]).toAst(); + }), + sortingColumnId: state.sorting?.columnId || '', + sortingDirection: state.sorting?.direction || 'none', + fitRowToContent: state.rowHeight === 'auto', + headerRowHeight: state.headerRowHeight ?? 'single', + rowHeightLines: + !state.rowHeight || state.rowHeight === 'single' ? 1 : state.rowHeightLines ?? 2, + headerRowHeightLines: + !state.headerRowHeight || state.headerRowHeight === 'single' + ? 1 + : state.headerRowHeightLines ?? 2, + pageSize: state.paging?.enabled ? state.paging.size : undefined, + }).toAst(); + return { type: 'expression', - chain: [ - ...(datasourceExpression?.chain ?? []), - ...columns - .filter((c) => c.collapseFn) - .map((c) => { - return { - type: 'function', - function: 'lens_collapse', - arguments: { - by: columns - .filter( - (col) => - col.columnId !== c.columnId && - datasource!.getOperationForColumnId(col.columnId)?.isBucketed - ) - .map((col) => col.columnId), - metric: columns - .filter((col) => !datasource!.getOperationForColumnId(col.columnId)?.isBucketed) - .map((col) => col.columnId), - fn: [c.collapseFn!], - }, - } as AstFunction; - }), - { - type: 'function', - function: 'lens_datatable', - arguments: { - title: [title || ''], - description: [description || ''], - columns: columns - .filter((c) => !c.collapseFn) - .map((column) => { - const paletteParams = { - ...column.palette?.params, - // rewrite colors and stops as two distinct arguments - colors: (column.palette?.params?.stops || []).map(({ color }) => color), - stops: - column.palette?.params?.name === 'custom' - ? (column.palette?.params?.stops || []).map(({ stop }) => stop) - : [], - reverse: false, // managed at UI level - }; - const sortingHint = datasource!.getOperationForColumnId( - column.columnId - )!.sortingHint; - - const hasNoSummaryRow = column.summaryRow == null || column.summaryRow === 'none'; - - const canColor = - datasource!.getOperationForColumnId(column.columnId)?.dataType === 'number'; - - return { - type: 'expression', - chain: [ - { - type: 'function', - function: 'lens_datatable_column', - arguments: { - columnId: [column.columnId], - hidden: typeof column.hidden === 'undefined' ? [] : [column.hidden], - oneClickFilter: - typeof column.oneClickFilter === 'undefined' - ? [] - : [column.oneClickFilter], - width: typeof column.width === 'undefined' ? [] : [column.width], - isTransposed: - typeof column.isTransposed === 'undefined' ? [] : [column.isTransposed], - transposable: [ - !datasource!.getOperationForColumnId(column.columnId)?.isBucketed, - ], - alignment: - typeof column.alignment === 'undefined' ? [] : [column.alignment], - colorMode: [canColor && column.colorMode ? column.colorMode : 'none'], - palette: [paletteService.get(CUSTOM_PALETTE).toExpression(paletteParams)], - summaryRow: hasNoSummaryRow ? [] : [column.summaryRow!], - summaryLabel: hasNoSummaryRow - ? [] - : [column.summaryLabel ?? getDefaultSummaryLabel(column.summaryRow!)], - sortingHint: sortingHint ? [sortingHint] : [], - }, - }, - ], - }; - }), - sortingColumnId: [state.sorting?.columnId || ''], - sortingDirection: [state.sorting?.direction || 'none'], - fitRowToContent: [state.rowHeight === 'auto'], - headerRowHeight: [state.headerRowHeight ?? 'single'], - rowHeightLines: [ - !state.rowHeight || state.rowHeight === 'single' ? 1 : state.rowHeightLines ?? 2, - ], - headerRowHeightLines: [ - !state.headerRowHeight || state.headerRowHeight === 'single' - ? 1 - : state.headerRowHeightLines ?? 2, - ], - pageSize: state.paging?.enabled ? [state.paging.size] : [], - }, - }, - ], + chain: [...(datasourceExpression?.chain ?? []), ...lensCollapseFnAsts, datatableFnAst], }; },