Skip to content

Commit

Permalink
[Lens] Datatable expression types improvement. (#144173)
Browse files Browse the repository at this point in the history
* Fixed way of expression building at Lens datatable.

* CollapseFn type safety added.

* Removed duplicated export.

* Small refactoring

* Added datatableColumnFn expression.

* Added type safety for datatable fn.

* Update x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx

Co-authored-by: Andrew Tate <drewctate@gmail.com>

Co-authored-by: Andrew Tate <drewctate@gmail.com>
  • Loading branch information
Kuznietsov and drewdaemon committed Nov 1, 2022
1 parent f8efa76 commit 74829e5
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 116 deletions.
2 changes: 2 additions & 0 deletions x-pack/plugins/lens/common/expressions/collapse/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export interface CollapseArgs {
fn: CollapseFunction[];
}

export type { CollapseExpressionFunction };

/**
* Collapses multiple rows into a single row using the specified function.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/lens/common/expressions/datatable/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
export * from './datatable_column';
export * from './datatable';

export type { DatatableProps } from './types';
export type { DatatableProps, DatatableExpressionFunction } from './types';
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
})
);
Expand All @@ -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({
Expand Down
188 changes: 86 additions & 102 deletions x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -398,108 +406,84 @@ export const getDatatableVisualization = ({

const datasourceExpression = datasourceExpressionsByLayers[state.layerId];

const lensCollapseFnAsts = columns
.filter((c) => c.collapseFn)
.map((c) =>
buildExpressionFunction<CollapseExpressionFunction>('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<DatatableExpressionFunction>('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<DatatableColumnFunction>(
'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],
};
},

Expand Down

0 comments on commit 74829e5

Please sign in to comment.