From be57365cd2bf112acd0ae82976c009991fe08f5f Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Fri, 17 Apr 2020 13:55:56 +0200 Subject: [PATCH 01/18] wip: datatable --- .../_visualization.scss | 14 +++ .../datatable_visualization/expression.tsx | 114 +++++++++++++++--- .../public/datatable_visualization/index.ts | 10 +- .../datatable_visualization/visualization.tsx | 1 + x-pack/plugins/lens/public/services.ts | 12 ++ .../lens/public/xy_visualization/index.ts | 2 +- .../public/xy_visualization/xy_expression.tsx | 2 +- 7 files changed, 138 insertions(+), 17 deletions(-) create mode 100644 x-pack/plugins/lens/public/services.ts diff --git a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss index e36326d710f72..f35677a429d96 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss +++ b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss @@ -1,3 +1,17 @@ .lnsDataTable { align-self: flex-start; } + +.lnsDataTable__filterGroup { + visibility: hidden; +} + +.lnsDataTable__filter { + cursor: pointer; +} + +.lnsDataTable__cell:hover { + .lnsDataTable__filterGroup { + visibility: visible; + } +} diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 772ee13168d02..c3882e6909daa 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -8,6 +8,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { i18n } from '@kbn/i18n'; import { EuiBasicTable } from '@elastic/eui'; +import { EuiFlexGroup, EuiIconTip, EuiFlexItem } from '@elastic/eui'; import { FormatFactory, LensMultiTable } from '../types'; import { ExpressionFunctionDefinition, @@ -15,9 +16,14 @@ import { IInterpreterRenderHandlers, } from '../../../../../src/plugins/expressions/public'; import { VisualizationContainer } from '../visualization_container'; +import { ValueClickTriggerContext } from '../../../../../src/plugins/embeddable/public'; +import { VIS_EVENT_TO_TRIGGER } from '../../../../../src/plugins/visualizations/public'; +import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; +import { getExecuteTriggerActions } from '../services'; export interface DatatableColumns { columnIds: string[]; + filterable: boolean[]; } interface Args { @@ -91,6 +97,11 @@ export const datatableColumns: ExpressionFunctionDefinition< multi: true, help: '', }, + filterable: { + types: ['boolean'], + multi: true, + help: '', + }, }, fn: function fn(input: unknown, args: DatatableColumns) { return { @@ -116,8 +127,13 @@ export const getDatatableRenderer = ( handlers: IInterpreterRenderHandlers ) => { const resolvedFormatFactory = await formatFactory; + const executeTriggerActions = getExecuteTriggerActions(); ReactDOM.render( - , + , domNode, () => { handlers.done(); @@ -127,7 +143,12 @@ export const getDatatableRenderer = ( }, }); -function DatatableComponent(props: DatatableProps & { formatFactory: FormatFactory }) { +function DatatableComponent( + props: DatatableProps & { + formatFactory: FormatFactory; + executeTriggerActions: UiActionsStart['executeTriggerActions']; + } +) { const [firstTable] = Object.values(props.data.tables); const formatters: Record> = {}; @@ -135,6 +156,30 @@ function DatatableComponent(props: DatatableProps & { formatFactory: FormatFacto formatters[column.id] = props.formatFactory(column.formatHint); }); + const handleFilterClick = (field: string, value: unknown, index: number, negate = false) => { + const timeFieldName = negate + ? undefined + : firstTable.columns.find(col => col?.meta?.type === 'date_histogram')?.meta?.aggConfigParams + ?.field; + const rowIndex = firstTable.rows.findIndex(row => row[field] === value); + + const context: ValueClickTriggerContext = { + data: { + negate, + data: [ + { + row: rowIndex, + column: index, + value, + table: firstTable, + }, + ], + }, + timeFieldName, + }; + props.executeTriggerActions(VIS_EVENT_TO_TRIGGER.filter, context); + }; + return ( { + .map((field, index) => { const col = firstTable.columns.find(c => c.id === field); return { field, name: (col && col.name) || '', + render: (value: unknown) => { + const formattedValue = formatters[field].convert(value); + if (props.args.columns.filterable[index]) { + return ( + + {formattedValue} + + + handleFilterClick(field, value, index)} + data-test-subj="lensFilterForCellValue" + > + + + handleFilterClick(field, value, index, true)} + data-test-subj="lensFilterOutCellValue" + > + + + + + + ); + } + return formattedValue; + }, }; }) .filter(({ field }) => !!field)} - items={ - firstTable - ? firstTable.rows.map(row => { - const formattedRow: Record = {}; - Object.entries(formatters).forEach(([columnId, formatter]) => { - formattedRow[columnId] = formatter.convert(row[columnId]); - }); - return formattedRow; - }) - : [] - } + items={firstTable ? firstTable.rows : []} /> ); diff --git a/x-pack/plugins/lens/public/datatable_visualization/index.ts b/x-pack/plugins/lens/public/datatable_visualization/index.ts index ff036aadfd4cf..c8624ecb81e41 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/index.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/index.ts @@ -4,12 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CoreSetup } from 'kibana/public'; +import { CoreSetup, CoreStart } from 'kibana/public'; import { datatableVisualization } from './visualization'; import { ExpressionsSetup } from '../../../../../src/plugins/expressions/public'; import { datatable, datatableColumns, getDatatableRenderer } from './expression'; import { EditorFrameSetup, FormatFactory } from '../types'; +import { setExecuteTriggerActions } from '../services'; +import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; +interface DatatableVisualizationPluginStartPlugins { + uiActions: UiActionsStart; +} export interface DatatableVisualizationPluginSetupPlugins { expressions: ExpressionsSetup; formatFactory: Promise; @@ -28,4 +33,7 @@ export class DatatableVisualization { expressions.registerRenderer(() => getDatatableRenderer(formatFactory)); editorFrame.registerVisualization(datatableVisualization); } + start(core: CoreStart, { uiActions }: DatatableVisualizationPluginStartPlugins) { + setExecuteTriggerActions(uiActions.executeTriggerActions); + } } diff --git a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx index 359c06a6a9ebc..d31cea3787133 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx @@ -204,6 +204,7 @@ export const datatableVisualization: Visualization< function: 'lens_datatable_columns', arguments: { columnIds: operations.map(o => o.columnId), + filterable: operations.map(o => o.operation.isBucketed), }, }, ], diff --git a/x-pack/plugins/lens/public/services.ts b/x-pack/plugins/lens/public/services.ts new file mode 100644 index 0000000000000..a66743dde2661 --- /dev/null +++ b/x-pack/plugins/lens/public/services.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { createGetterSetter } from '../../../../src/plugins/kibana_utils/public'; +import { UiActionsStart } from '../../../../src/plugins/ui_actions/public'; + +export const [getExecuteTriggerActions, setExecuteTriggerActions] = createGetterSetter< + UiActionsStart['executeTriggerActions'] +>('executeTriggerActions'); diff --git a/x-pack/plugins/lens/public/xy_visualization/index.ts b/x-pack/plugins/lens/public/xy_visualization/index.ts index 5dfae097be834..fcc4ec949c384 100644 --- a/x-pack/plugins/lens/public/xy_visualization/index.ts +++ b/x-pack/plugins/lens/public/xy_visualization/index.ts @@ -13,7 +13,7 @@ import { xyChart, getXyChartRenderer } from './xy_expression'; import { legendConfig, xConfig, layerConfig } from './types'; import { EditorFrameSetup, FormatFactory } from '../types'; import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; -import { setExecuteTriggerActions } from './services'; +import { setExecuteTriggerActions } from '../services'; export interface XyVisualizationPluginSetupPlugins { expressions: ExpressionsSetup; diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx index d6b6de479acfb..602e905da145e 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx @@ -36,7 +36,7 @@ import { VisualizationContainer } from '../visualization_container'; import { isHorizontalChart } from './state_helpers'; import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; import { parseInterval } from '../../../../../src/plugins/data/common'; -import { getExecuteTriggerActions } from './services'; +import { getExecuteTriggerActions } from '../services'; type InferPropType = T extends React.FunctionComponent ? P : T; type SeriesSpec = InferPropType & From 74751986b7467135bdc0877ace88f6f1c10e567a Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Fri, 17 Apr 2020 15:01:40 +0200 Subject: [PATCH 02/18] fix: empty values --- .../lens/public/datatable_visualization/expression.tsx | 7 ++++++- .../lens/public/datatable_visualization/visualization.tsx | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index c3882e6909daa..6b017acb191e2 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -189,12 +189,17 @@ function DatatableComponent( columns={props.args.columns.columnIds .map((field, index) => { const col = firstTable.columns.find(c => c.id === field); + // todo: get the list of unsupported operations from operations + const nonFilterable = + !col?.meta?.type || + ['sum', 'cardinality', 'max', 'min', 'avg', 'count'].includes(col.meta.type); + return { field, name: (col && col.name) || '', render: (value: unknown) => { const formattedValue = formatters[field].convert(value); - if (props.args.columns.filterable[index]) { + if (!nonFilterable && value) { return ( {formattedValue} diff --git a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx index d31cea3787133..359c06a6a9ebc 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx @@ -204,7 +204,6 @@ export const datatableVisualization: Visualization< function: 'lens_datatable_columns', arguments: { columnIds: operations.map(o => o.columnId), - filterable: operations.map(o => o.operation.isBucketed), }, }, ], From a6183a6e29ae97b12f83183c67f1073a74fc7c60 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Fri, 17 Apr 2020 15:01:40 +0200 Subject: [PATCH 03/18] fix: empty values --- .../lens/public/datatable_visualization/expression.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 6b017acb191e2..2c94faad2dd3d 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -187,8 +187,10 @@ function DatatableComponent( data-test-subj="lnsDataTable" tableLayout="auto" columns={props.args.columns.columnIds - .map((field, index) => { + .map(field => { const col = firstTable.columns.find(c => c.id === field); + const colIndex = firstTable.columns.findIndex(c => c.id === field); + // todo: get the list of unsupported operations from operations const nonFilterable = !col?.meta?.type || @@ -207,7 +209,7 @@ function DatatableComponent( handleFilterClick(field, value, index)} + onClick={() => handleFilterClick(field, value, colIndex)} data-test-subj="lensFilterForCellValue" > handleFilterClick(field, value, index, true)} + onClick={() => handleFilterClick(field, value, colIndex, true)} data-test-subj="lensFilterOutCellValue" > Date: Mon, 20 Apr 2020 12:36:04 +0200 Subject: [PATCH 04/18] translations --- .../lens/public/datatable_visualization/expression.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 2c94faad2dd3d..b3221df82e012 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -215,7 +215,7 @@ function DatatableComponent( Date: Tue, 21 Apr 2020 15:00:11 +0200 Subject: [PATCH 05/18] using dataPlugin to get buckets --- .../public/datatable_visualization/expression.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index b3221df82e012..954d6fab85f81 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -15,6 +15,7 @@ import { ExpressionRenderDefinition, IInterpreterRenderHandlers, } from '../../../../../src/plugins/expressions/public'; +import { BUCKET_TYPES } from '../../../../../src/plugins/data/public'; import { VisualizationContainer } from '../visualization_container'; import { ValueClickTriggerContext } from '../../../../../src/plugins/embeddable/public'; import { VIS_EVENT_TO_TRIGGER } from '../../../../../src/plugins/visualizations/public'; @@ -191,17 +192,15 @@ function DatatableComponent( const col = firstTable.columns.find(c => c.id === field); const colIndex = firstTable.columns.findIndex(c => c.id === field); - // todo: get the list of unsupported operations from operations - const nonFilterable = - !col?.meta?.type || - ['sum', 'cardinality', 'max', 'min', 'avg', 'count'].includes(col.meta.type); - + const filterable = Boolean( + Object.values(BUCKET_TYPES).find(bucketType => bucketType === col?.meta?.type) + ); return { field, name: (col && col.name) || '', render: (value: unknown) => { const formattedValue = formatters[field].convert(value); - if (!nonFilterable && value) { + if (filterable && value) { return ( {formattedValue} From af89e2756d0e801d91c352455743c86e29a9fa13 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Tue, 21 Apr 2020 18:00:50 +0200 Subject: [PATCH 06/18] one more time, passing aggs data --- .../datatable_visualization/expression.tsx | 29 ++++++++++--------- .../public/datatable_visualization/index.ts | 13 +++++++-- x-pack/plugins/lens/public/plugin.tsx | 1 + .../lens/public/xy_visualization/services.ts | 12 -------- 4 files changed, 27 insertions(+), 28 deletions(-) delete mode 100644 x-pack/plugins/lens/public/xy_visualization/services.ts diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 954d6fab85f81..76134a16bfd8c 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -15,7 +15,6 @@ import { ExpressionRenderDefinition, IInterpreterRenderHandlers, } from '../../../../../src/plugins/expressions/public'; -import { BUCKET_TYPES } from '../../../../../src/plugins/data/public'; import { VisualizationContainer } from '../visualization_container'; import { ValueClickTriggerContext } from '../../../../../src/plugins/embeddable/public'; import { VIS_EVENT_TO_TRIGGER } from '../../../../../src/plugins/visualizations/public'; @@ -37,6 +36,12 @@ export interface DatatableProps { args: Args; } +type DatatableRenderProps = DatatableProps & { + formatFactory: FormatFactory; + executeTriggerActions: UiActionsStart['executeTriggerActions']; + getType: Function; +}; + export interface DatatableRender { type: 'render'; as: 'lens_datatable_renderer'; @@ -112,9 +117,10 @@ export const datatableColumns: ExpressionFunctionDefinition< }, }; -export const getDatatableRenderer = ( - formatFactory: Promise -): ExpressionRenderDefinition => ({ +export const getDatatableRenderer = (dependencies: { + formatFactory: Promise; + getType: Promise; +}): ExpressionRenderDefinition => ({ name: 'lens_datatable_renderer', displayName: i18n.translate('xpack.lens.datatable.visualizationName', { defaultMessage: 'Datatable', @@ -127,13 +133,15 @@ export const getDatatableRenderer = ( config: DatatableProps, handlers: IInterpreterRenderHandlers ) => { - const resolvedFormatFactory = await formatFactory; + const resolvedFormatFactory = await dependencies.formatFactory; const executeTriggerActions = getExecuteTriggerActions(); + const resolvedGetType = await dependencies.getType; ReactDOM.render( , domNode, () => { @@ -144,12 +152,7 @@ export const getDatatableRenderer = ( }, }); -function DatatableComponent( - props: DatatableProps & { - formatFactory: FormatFactory; - executeTriggerActions: UiActionsStart['executeTriggerActions']; - } -) { +function DatatableComponent(props: DatatableRenderProps) { const [firstTable] = Object.values(props.data.tables); const formatters: Record> = {}; @@ -192,9 +195,7 @@ function DatatableComponent( const col = firstTable.columns.find(c => c.id === field); const colIndex = firstTable.columns.findIndex(c => c.id === field); - const filterable = Boolean( - Object.values(BUCKET_TYPES).find(bucketType => bucketType === col?.meta?.type) - ); + const filterable = col?.meta?.type && props.getType(col.meta.type)?.type === 'buckets'; return { field, name: (col && col.name) || '', diff --git a/x-pack/plugins/lens/public/datatable_visualization/index.ts b/x-pack/plugins/lens/public/datatable_visualization/index.ts index c8624ecb81e41..44894d31da51d 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/index.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/index.ts @@ -11,9 +11,11 @@ import { datatable, datatableColumns, getDatatableRenderer } from './expression' import { EditorFrameSetup, FormatFactory } from '../types'; import { setExecuteTriggerActions } from '../services'; import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; +import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; interface DatatableVisualizationPluginStartPlugins { uiActions: UiActionsStart; + data: DataPublicPluginStart; } export interface DatatableVisualizationPluginSetupPlugins { expressions: ExpressionsSetup; @@ -25,12 +27,19 @@ export class DatatableVisualization { constructor() {} setup( - _core: CoreSetup | null, + core: CoreSetup, { expressions, formatFactory, editorFrame }: DatatableVisualizationPluginSetupPlugins ) { expressions.registerFunction(() => datatableColumns); expressions.registerFunction(() => datatable); - expressions.registerRenderer(() => getDatatableRenderer(formatFactory)); + expressions.registerRenderer(() => + getDatatableRenderer({ + formatFactory, + getType: core + .getStartServices() + .then(([_, { data: dataStart }]) => dataStart.search.aggs.types.get), + }) + ); editorFrame.registerVisualization(datatableVisualization); } start(core: CoreStart, { uiActions }: DatatableVisualizationPluginStartPlugins) { diff --git a/x-pack/plugins/lens/public/plugin.tsx b/x-pack/plugins/lens/public/plugin.tsx index 8d760eb0df501..fe0e81177e259 100644 --- a/x-pack/plugins/lens/public/plugin.tsx +++ b/x-pack/plugins/lens/public/plugin.tsx @@ -200,6 +200,7 @@ export class LensPlugin { start(core: CoreStart, startDependencies: LensPluginStartDependencies) { this.createEditorFrame = this.editorFrameService.start(core, startDependencies).createInstance; this.xyVisualization.start(core, startDependencies); + this.datatableVisualization.start(core, startDependencies); } stop() { diff --git a/x-pack/plugins/lens/public/xy_visualization/services.ts b/x-pack/plugins/lens/public/xy_visualization/services.ts deleted file mode 100644 index 51289fe0c63e7..0000000000000 --- a/x-pack/plugins/lens/public/xy_visualization/services.ts +++ /dev/null @@ -1,12 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { createGetterSetter } from '../../../../../src/plugins/kibana_utils/public'; -import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; - -export const [getExecuteTriggerActions, setExecuteTriggerActions] = createGetterSetter< - UiActionsStart['executeTriggerActions'] ->('executeTriggerActions'); From 9647389cf5d33ab2a50ddf6d9f84a3b944c32b98 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Wed, 22 Apr 2020 14:23:35 +0200 Subject: [PATCH 07/18] tests: added --- .../__snapshots__/expression.test.tsx.snap | 41 +++++++ .../expression.test.tsx | 110 ++++++++++++++++++ .../datatable_visualization/expression.tsx | 12 +- 3 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 x-pack/plugins/lens/public/datatable_visualization/__snapshots__/expression.test.tsx.snap create mode 100644 x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx diff --git a/x-pack/plugins/lens/public/datatable_visualization/__snapshots__/expression.test.tsx.snap b/x-pack/plugins/lens/public/datatable_visualization/__snapshots__/expression.test.tsx.snap new file mode 100644 index 0000000000000..b905ccff5b379 --- /dev/null +++ b/x-pack/plugins/lens/public/datatable_visualization/__snapshots__/expression.test.tsx.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`datatable_expression DatatableComponent it renders the title and value 1`] = ` + + + +`; diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx new file mode 100644 index 0000000000000..7abba5d18371d --- /dev/null +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { datatable, DatatableComponent } from './expression'; +import { LensMultiTable } from '../types'; +import React from 'react'; +import { shallow } from 'enzyme'; +import { DatatableProps } from './expression'; +import { createMockExecutionContext } from '../../../../../src/plugins/expressions/common/mocks'; +import { IFieldFormat } from '../../../../../src/plugins/data/public'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; + +const executeTriggerActions = jest.fn(); + +function sampleArgs() { + const data: LensMultiTable = { + type: 'lens_multitable', + tables: { + l1: { + type: 'kibana_datatable', + columns: [ + { id: 'a', name: 'a', meta: { type: 'count' } }, + { id: 'b', name: 'b', meta: { type: 'date_histogram' } }, + { id: 'c', name: 'c', meta: { type: 'cardinality' } }, + ], + rows: [{ a: 10110, b: 2, c: 3 }], + }, + }, + }; + + const args: DatatableProps['args'] = { + title: 'My fanci metric chart', + columns: { + columnIds: ['a', 'b', 'c'], + type: 'lens_datatable_columns', + }, + }; + + return { data, args }; +} + +describe('datatable_expression', () => { + describe('datatable renders', () => { + test('it renders with the specified data and args', () => { + const { data, args } = sampleArgs(); + const result = datatable.fn(data, args, createMockExecutionContext()); + + expect(result).toEqual({ + type: 'render', + as: 'lens_datatable_renderer', + value: { data, args }, + }); + }); + }); + + describe('DatatableComponent', () => { + test('it renders the title and value', () => { + const { data, args } = sampleArgs(); + + expect( + shallow( + x as IFieldFormat} + executeTriggerActions={executeTriggerActions} + getType={jest.fn()} + /> + ) + ).toMatchSnapshot(); + }); + + test('it invokes executeTriggerActions with correct context', () => { + const { args, data } = sampleArgs(); + + const wrapper = mountWithIntl( + x as IFieldFormat} + executeTriggerActions={executeTriggerActions} + getType={jest.fn(() => ({ type: 'buckets' }))} + /> + ); + + wrapper + .find('[data-test-subj="lensFilterForCellValue"]') + .first() + .simulate('click'); + + expect(executeTriggerActions).toHaveBeenCalledWith('VALUE_CLICK_TRIGGER', { + data: { + data: [ + { + column: 0, + row: 0, + table: data.tables.l1, + value: 10110, + }, + ], + negate: false, + }, + timeFieldName: undefined, + }); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 76134a16bfd8c..dcd28c8fbec55 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -23,7 +23,6 @@ import { getExecuteTriggerActions } from '../services'; export interface DatatableColumns { columnIds: string[]; - filterable: boolean[]; } interface Args { @@ -103,11 +102,6 @@ export const datatableColumns: ExpressionFunctionDefinition< multi: true, help: '', }, - filterable: { - types: ['boolean'], - multi: true, - help: '', - }, }, fn: function fn(input: unknown, args: DatatableColumns) { return { @@ -152,7 +146,7 @@ export const getDatatableRenderer = (dependencies: { }, }); -function DatatableComponent(props: DatatableRenderProps) { +export function DatatableComponent(props: DatatableRenderProps) { const [firstTable] = Object.values(props.data.tables); const formatters: Record> = {}; @@ -200,12 +194,12 @@ function DatatableComponent(props: DatatableRenderProps) { field, name: (col && col.name) || '', render: (value: unknown) => { - const formattedValue = formatters[field].convert(value); + const formattedValue = formatters[field]?.convert(value); if (filterable && value) { return ( {formattedValue} - + Date: Thu, 23 Apr 2020 14:59:35 +0200 Subject: [PATCH 08/18] feat: new design applied --- .../_visualization.scss | 10 +- .../expression.test.tsx | 6 +- .../datatable_visualization/expression.tsx | 142 ++++++++++++------ .../datatable_visualization/filter_icon.tsx | 24 +++ 4 files changed, 127 insertions(+), 55 deletions(-) create mode 100644 x-pack/plugins/lens/public/datatable_visualization/filter_icon.tsx diff --git a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss index f35677a429d96..f4b999c7c5a49 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss +++ b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss @@ -2,16 +2,18 @@ align-self: flex-start; } -.lnsDataTable__filterGroup { +.lnsDataTable__filter { + cursor: pointer; visibility: hidden; } -.lnsDataTable__filter { - cursor: pointer; +.lnsDataTable__filterIcon { + fill: $euiColorPrimary; + vertical-align: text-bottom; } .lnsDataTable__cell:hover { - .lnsDataTable__filterGroup { + .lnsDataTable__filter { visibility: visible; } } 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 7abba5d18371d..902df3e6a4872 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { datatable, DatatableComponent } from './expression'; -import { LensMultiTable } from '../types'; import React from 'react'; import { shallow } from 'enzyme'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { datatable, DatatableComponent } from './expression'; +import { LensMultiTable } from '../types'; import { DatatableProps } from './expression'; import { createMockExecutionContext } from '../../../../../src/plugins/expressions/common/mocks'; import { IFieldFormat } from '../../../../../src/plugins/data/public'; -import { mountWithIntl } from 'test_utils/enzyme_helpers'; const executeTriggerActions = jest.fn(); diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index dcd28c8fbec55..cb31bdcbe3fed 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -7,8 +7,8 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { i18n } from '@kbn/i18n'; -import { EuiBasicTable } from '@elastic/eui'; -import { EuiFlexGroup, EuiIconTip, EuiFlexItem } from '@elastic/eui'; +import { I18nProvider, FormattedMessage } from '@kbn/i18n/react'; +import { EuiBasicTable, EuiFlexGroup, EuiIconTip, EuiFlexItem, EuiText } from '@elastic/eui'; import { FormatFactory, LensMultiTable } from '../types'; import { ExpressionFunctionDefinition, @@ -20,6 +20,7 @@ import { ValueClickTriggerContext } from '../../../../../src/plugins/embeddable/ import { VIS_EVENT_TO_TRIGGER } from '../../../../../src/plugins/visualizations/public'; import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; import { getExecuteTriggerActions } from '../services'; +import { Icon } from './filter_icon'; export interface DatatableColumns { columnIds: string[]; @@ -131,12 +132,14 @@ export const getDatatableRenderer = (dependencies: { const executeTriggerActions = getExecuteTriggerActions(); const resolvedGetType = await dependencies.getType; ReactDOM.render( - , + + + , domNode, () => { handlers.done(); @@ -197,47 +200,90 @@ export function DatatableComponent(props: DatatableRenderProps) { const formattedValue = formatters[field]?.convert(value); if (filterable && value) { return ( - + {formattedValue} - - - handleFilterClick(field, value, colIndex)} - data-test-subj="lensFilterForCellValue" - > - - - handleFilterClick(field, value, colIndex, true)} - data-test-subj="lensFilterOutCellValue" - > - - - + + handleFilterClick(field, value, colIndex, shiftKey ? true : false) + } + data-test-subj="lensFilterForCellValue" + > + + {formattedValue}, + }} + /> + + } + content={ + <> + + + {i18n.translate( + 'xpack.lens.datatable.filter.tooltip.filterFor.click', + { + defaultMessage: 'Click', + description: `Part of 'Click to filter for value'`, + } + )} + + ), + for: ( + + {i18n.translate('xpack.lens.datatable.filter.tooltip.for', { + defaultMessage: 'for', + description: `Part of 'Click to filter for value'`, + })} + + ), + }} + /> + + + + {i18n.translate( + 'xpack.lens.datatable.filter.tooltip.shiftClick', + { + defaultMessage: 'Shift + click', + description: `Part of 'Shift + click to filter out value'`, + } + )} + + ), + // description:{} + out: ( + + {i18n.translate('xpack.lens.datatable.filter.tooltip.out', { + defaultMessage: 'out', + description: `Part of 'Shift + click to filter out value'`, + })} + + ), + }} + /> + + + } + /> ); diff --git a/x-pack/plugins/lens/public/datatable_visualization/filter_icon.tsx b/x-pack/plugins/lens/public/datatable_visualization/filter_icon.tsx new file mode 100644 index 0000000000000..5b2f3e46d087c --- /dev/null +++ b/x-pack/plugins/lens/public/datatable_visualization/filter_icon.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; + +export const Icon = () => ( + + filter out icon + + +); From 632e0960abc8cafb08240982cd9ac71458eee1f2 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Fri, 24 Apr 2020 13:06:33 +0200 Subject: [PATCH 09/18] remove icon --- .../datatable_visualization/filter_icon.tsx | 24 ------------------- 1 file changed, 24 deletions(-) delete mode 100644 x-pack/plugins/lens/public/datatable_visualization/filter_icon.tsx diff --git a/x-pack/plugins/lens/public/datatable_visualization/filter_icon.tsx b/x-pack/plugins/lens/public/datatable_visualization/filter_icon.tsx deleted file mode 100644 index 5b2f3e46d087c..0000000000000 --- a/x-pack/plugins/lens/public/datatable_visualization/filter_icon.tsx +++ /dev/null @@ -1,24 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; - -export const Icon = () => ( - - filter out icon - - -); From a57d980e4459c0d464d67807a5ab4c5cb9f946d9 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Fri, 24 Apr 2020 13:22:52 +0200 Subject: [PATCH 10/18] feat: old design --- .../_visualization.scss | 13 +- .../expression.test.tsx | 4 +- .../datatable_visualization/expression.tsx | 139 +++++++----------- .../test/functional/apps/lens/smokescreen.ts | 31 ++-- 4 files changed, 84 insertions(+), 103 deletions(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss index f4b999c7c5a49..1258127fac2b5 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss +++ b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss @@ -3,17 +3,12 @@ } .lnsDataTable__filter { - cursor: pointer; - visibility: hidden; -} - -.lnsDataTable__filterIcon { - fill: $euiColorPrimary; - vertical-align: text-bottom; + opacity: 0; + transition: opacity 250ms ease-in-out; } .lnsDataTable__cell:hover { .lnsDataTable__filter { - visibility: visible; + opacity: 1; } -} +} \ No newline at end of file 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 902df3e6a4872..75444d63c7e9f 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx @@ -87,7 +87,7 @@ describe('datatable_expression', () => { ); wrapper - .find('[data-test-subj="lensFilterForCellValue"]') + .find('[data-test-subj="lensDatatableFilterOut"]') .first() .simulate('click'); @@ -101,7 +101,7 @@ describe('datatable_expression', () => { value: 10110, }, ], - negate: false, + negate: true, }, timeFieldName: undefined, }); diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index cb31bdcbe3fed..af74368eedc30 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -8,7 +8,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { i18n } from '@kbn/i18n'; import { I18nProvider, FormattedMessage } from '@kbn/i18n/react'; -import { EuiBasicTable, EuiFlexGroup, EuiIconTip, EuiFlexItem, EuiText } from '@elastic/eui'; +import { EuiBasicTable, EuiFlexGroup, EuiButtonIcon, EuiFlexItem, EuiToolTip } from '@elastic/eui'; import { FormatFactory, LensMultiTable } from '../types'; import { ExpressionFunctionDefinition, @@ -20,7 +20,6 @@ import { ValueClickTriggerContext } from '../../../../../src/plugins/embeddable/ import { VIS_EVENT_TO_TRIGGER } from '../../../../../src/plugins/visualizations/public'; import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; import { getExecuteTriggerActions } from '../services'; -import { Icon } from './filter_icon'; export interface DatatableColumns { columnIds: string[]; @@ -200,95 +199,71 @@ export function DatatableComponent(props: DatatableRenderProps) { const formattedValue = formatters[field]?.convert(value); if (filterable && value) { return ( - + {formattedValue} - - handleFilterClick(field, value, colIndex, shiftKey ? true : false) - } - data-test-subj="lensFilterForCellValue" - > - + + + {formattedValue}, - }} + id="xpack.lens.filterForValueButtonTooltip" + defaultMessage="Filter for value" /> - - } - content={ - <> - + } + > + handleFilterClick(field, value, colIndex)} + /> + + + - {i18n.translate( - 'xpack.lens.datatable.filter.tooltip.filterFor.click', - { - defaultMessage: 'Click', - description: `Part of 'Click to filter for value'`, - } - )} - - ), - for: ( - - {i18n.translate('xpack.lens.datatable.filter.tooltip.for', { - defaultMessage: 'for', - description: `Part of 'Click to filter for value'`, - })} - - ), - }} + id="xpack.lens.filterOutValueButtonTooltip" + defaultMessage="Filter out value" /> - - - - {i18n.translate( - 'xpack.lens.datatable.filter.tooltip.shiftClick', - { - defaultMessage: 'Shift + click', - description: `Part of 'Shift + click to filter out value'`, - } - )} - - ), - // description:{} - out: ( - - {i18n.translate('xpack.lens.datatable.filter.tooltip.out', { - defaultMessage: 'out', - description: `Part of 'Shift + click to filter out value'`, - })} - - ), - }} - /> - - - } - /> + } + > + handleFilterClick(field, value, colIndex, true)} + /> + + + ); } - return formattedValue; + return {formattedValue}; }, }; }) diff --git a/x-pack/test/functional/apps/lens/smokescreen.ts b/x-pack/test/functional/apps/lens/smokescreen.ts index be7a2faae6711..1f8a0f7de2aec 100644 --- a/x-pack/test/functional/apps/lens/smokescreen.ts +++ b/x-pack/test/functional/apps/lens/smokescreen.ts @@ -26,12 +26,12 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const filterBar = getService('filterBar'); - async function assertExpectedMetric() { + async function assertExpectedMetric(metricCount: string) { await PageObjects.lens.assertExactText( '[data-test-subj="lns_metric_title"]', 'Maximum of bytes' ); - await PageObjects.lens.assertExactText('[data-test-subj="lns_metric_value"]', '19,986'); + await PageObjects.lens.assertExactText('[data-test-subj="lns_metric_value"]', metricCount); } async function assertExpectedTable() { @@ -40,8 +40,12 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { 'Maximum of bytes' ); await PageObjects.lens.assertExactText( - '[data-test-subj="lnsDataTable"] tbody .euiTableCellContent__text', - '19,986' + '[data-test-subj="lnsDataTable"] [data-test-subj="lnsDataTableCellValue"]', + '19,985' + ); + await PageObjects.lens.assertExactText( + '[data-test-subj="lnsDataTable"] [data-test-subj="lnsDataTableCellValueFilterable"]', + 'IN' ); } @@ -73,7 +77,7 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.visualize.gotoVisualizationLandingPage(); await PageObjects.lens.clickVisualizeListItemTitle('Artistpreviouslyknownaslens'); await PageObjects.lens.goToTimeRange(); - await assertExpectedMetric(); + await assertExpectedMetric('19,986'); }); it('metric should be embeddable in dashboards', async () => { @@ -83,10 +87,10 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { await find.clickByButtonText('Artistpreviouslyknownaslens'); await dashboardAddPanel.closeAddPanel(); await PageObjects.lens.goToTimeRange(); - await assertExpectedMetric(); + await assertExpectedMetric('19,986'); }); - it('click on the bar in XYChart adds proper filters/timerange', async () => { + it('click on the bar in XYChart adds proper filters/timerange in dashboard', async () => { await PageObjects.common.navigateToApp('dashboard'); await PageObjects.dashboard.clickNewDashboard(); await dashboardAddPanel.clickOpenAddPanel(); @@ -102,15 +106,22 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { expect(hasIpFilter).to.be(true); }); - it('should allow seamless transition to and from table view', async () => { + it('should allow seamless transition to and from table view and add a filter', async () => { await PageObjects.visualize.gotoVisualizationLandingPage(); await PageObjects.lens.clickVisualizeListItemTitle('Artistpreviouslyknownaslens'); await PageObjects.lens.goToTimeRange(); - await assertExpectedMetric(); + await assertExpectedMetric('19,986'); await PageObjects.lens.switchToVisualization('lnsChartSwitchPopover_lnsDatatable'); + await PageObjects.lens.configureDimension({ + dimension: '[data-test-subj="lnsDatatable_column"] [data-test-subj="lns-empty-dimension"]', + operation: 'terms', + field: 'geo.dest', + }); + await PageObjects.lens.save('Artistpreviouslyknownaslens'); + await find.clickByCssSelector('[data-test-subj="lensDatatableFilterOut"]'); await assertExpectedTable(); await PageObjects.lens.switchToVisualization('lnsChartSwitchPopover_lnsMetric'); - await assertExpectedMetric(); + await assertExpectedMetric('19,985'); }); it('should allow creation of lens visualizations', async () => { From 7d3d93a1b071354effd877f35a7c4a2a37be301f Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Tue, 28 Apr 2020 09:34:46 +0200 Subject: [PATCH 11/18] CR corrections --- .../__snapshots__/expression.test.tsx.snap | 2 +- .../expression.test.tsx | 58 +++++++++++++++++-- .../datatable_visualization/expression.tsx | 39 +++++-------- .../test/functional/apps/lens/smokescreen.ts | 8 +-- 4 files changed, 73 insertions(+), 34 deletions(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/__snapshots__/expression.test.tsx.snap b/x-pack/plugins/lens/public/datatable_visualization/__snapshots__/expression.test.tsx.snap index b905ccff5b379..76063d230bdb6 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/__snapshots__/expression.test.tsx.snap +++ b/x-pack/plugins/lens/public/datatable_visualization/__snapshots__/expression.test.tsx.snap @@ -28,7 +28,7 @@ exports[`datatable_expression DatatableComponent it renders the title and value Array [ Object { "a": 10110, - "b": 2, + "b": 1588024800000, "c": 3, }, ] 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 75444d63c7e9f..6d5b1153ad1bc 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx @@ -12,7 +12,7 @@ import { LensMultiTable } from '../types'; import { DatatableProps } from './expression'; import { createMockExecutionContext } from '../../../../../src/plugins/expressions/common/mocks'; import { IFieldFormat } from '../../../../../src/plugins/data/public'; - +import { IAggType } from 'src/plugins/data/public'; const executeTriggerActions = jest.fn(); function sampleArgs() { @@ -23,10 +23,10 @@ function sampleArgs() { type: 'kibana_datatable', columns: [ { id: 'a', name: 'a', meta: { type: 'count' } }, - { id: 'b', name: 'b', meta: { type: 'date_histogram' } }, + { id: 'b', name: 'b', meta: { type: 'date_histogram', aggConfigParams: { field: 'b' } } }, { id: 'c', name: 'c', meta: { type: 'cardinality' } }, ], - rows: [{ a: 10110, b: 2, c: 3 }], + rows: [{ a: 10110, b: 1588024800000, c: 3 }], }, }, }; @@ -73,16 +73,22 @@ describe('datatable_expression', () => { ).toMatchSnapshot(); }); - test('it invokes executeTriggerActions with correct context', () => { + test('it invokes executeTriggerActions with correct context on click on top value', () => { const { args, data } = sampleArgs(); const wrapper = mountWithIntl( x as IFieldFormat} executeTriggerActions={executeTriggerActions} - getType={jest.fn(() => ({ type: 'buckets' }))} + getType={jest.fn(() => ({ type: 'buckets' } as IAggType))} /> ); @@ -106,5 +112,45 @@ describe('datatable_expression', () => { timeFieldName: undefined, }); }); + + test('it invokes executeTriggerActions with correct context on click on timefield', () => { + const { args, data } = sampleArgs(); + + const wrapper = mountWithIntl( + x as IFieldFormat} + executeTriggerActions={executeTriggerActions} + getType={jest.fn(() => ({ type: 'buckets' } as IAggType))} + /> + ); + + wrapper + .find('[data-test-subj="lensDatatableFilterFor"]') + .at(3) + .simulate('click'); + + expect(executeTriggerActions).toHaveBeenCalledWith('VALUE_CLICK_TRIGGER', { + data: { + data: [ + { + column: 1, + row: 0, + table: data.tables.l1, + value: 1588024800000, + }, + ], + negate: false, + }, + timeFieldName: 'b', + }); + }); }); }); diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index af74368eedc30..6ae6e77ceaf9b 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -7,8 +7,9 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { i18n } from '@kbn/i18n'; -import { I18nProvider, FormattedMessage } from '@kbn/i18n/react'; +import { I18nProvider } from '@kbn/i18n/react'; import { EuiBasicTable, EuiFlexGroup, EuiButtonIcon, EuiFlexItem, EuiToolTip } from '@elastic/eui'; +import { IAggType } from 'src/plugins/data/public'; import { FormatFactory, LensMultiTable } from '../types'; import { ExpressionFunctionDefinition, @@ -20,7 +21,6 @@ import { ValueClickTriggerContext } from '../../../../../src/plugins/embeddable/ import { VIS_EVENT_TO_TRIGGER } from '../../../../../src/plugins/visualizations/public'; import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; import { getExecuteTriggerActions } from '../services'; - export interface DatatableColumns { columnIds: string[]; } @@ -38,7 +38,7 @@ export interface DatatableProps { type DatatableRenderProps = DatatableProps & { formatFactory: FormatFactory; executeTriggerActions: UiActionsStart['executeTriggerActions']; - getType: Function; + getType: (type: string) => IAggType; }; export interface DatatableRender { @@ -113,7 +113,7 @@ export const datatableColumns: ExpressionFunctionDefinition< export const getDatatableRenderer = (dependencies: { formatFactory: Promise; - getType: Promise; + getType: Promise<(type: string) => IAggType>; }): ExpressionRenderDefinition => ({ name: 'lens_datatable_renderer', displayName: i18n.translate('xpack.lens.datatable.visualizationName', { @@ -156,11 +156,10 @@ export function DatatableComponent(props: DatatableRenderProps) { formatters[column.id] = props.formatFactory(column.formatHint); }); - const handleFilterClick = (field: string, value: unknown, index: number, negate = false) => { - const timeFieldName = negate - ? undefined - : firstTable.columns.find(col => col?.meta?.type === 'date_histogram')?.meta?.aggConfigParams - ?.field; + const handleFilterClick = (field: string, value: unknown, colIndex: number, negate = false) => { + const col = firstTable.columns[colIndex]; + const isDateHistogram = col.meta?.type === 'date_histogram'; + const timeFieldName = negate && isDateHistogram ? undefined : col?.meta?.aggConfigParams?.field; const rowIndex = firstTable.rows.findIndex(row => row[field] === value); const context: ValueClickTriggerContext = { @@ -169,7 +168,7 @@ export function DatatableComponent(props: DatatableRenderProps) { data: [ { row: rowIndex, - column: index, + column: colIndex, value, table: firstTable, }, @@ -197,7 +196,7 @@ export function DatatableComponent(props: DatatableRenderProps) { name: (col && col.name) || '', render: (value: unknown) => { const formattedValue = formatters[field]?.convert(value); - if (filterable && value) { + if (filterable) { return ( - } + content={i18n.translate('xpack.lens.filterForValueButtonTooltip', { + defaultMessage: 'Filter for value', + })} > - } + content={i18n.translate('xpack.lens.filterOutValueButtonTooltip', { + defaultMessage: 'Filter out value', + })} > { @@ -87,7 +87,7 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { await find.clickByButtonText('Artistpreviouslyknownaslens'); await dashboardAddPanel.closeAddPanel(); await PageObjects.lens.goToTimeRange(); - await assertExpectedMetric('19,986'); + await assertExpectedMetric(); }); it('click on the bar in XYChart adds proper filters/timerange in dashboard', async () => { @@ -110,7 +110,7 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.visualize.gotoVisualizationLandingPage(); await PageObjects.lens.clickVisualizeListItemTitle('Artistpreviouslyknownaslens'); await PageObjects.lens.goToTimeRange(); - await assertExpectedMetric('19,986'); + await assertExpectedMetric(); await PageObjects.lens.switchToVisualization('lnsChartSwitchPopover_lnsDatatable'); await PageObjects.lens.configureDimension({ dimension: '[data-test-subj="lnsDatatable_column"] [data-test-subj="lns-empty-dimension"]', From badca7ddda6b3c48facaf82c194dfc19b576b92a Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Tue, 28 Apr 2020 09:36:47 +0200 Subject: [PATCH 12/18] better name --- .../lens/public/datatable_visualization/expression.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 6ae6e77ceaf9b..000f823faae40 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -38,7 +38,7 @@ export interface DatatableProps { type DatatableRenderProps = DatatableProps & { formatFactory: FormatFactory; executeTriggerActions: UiActionsStart['executeTriggerActions']; - getType: (type: string) => IAggType; + getType: (name: string) => IAggType; }; export interface DatatableRender { @@ -113,7 +113,7 @@ export const datatableColumns: ExpressionFunctionDefinition< export const getDatatableRenderer = (dependencies: { formatFactory: Promise; - getType: Promise<(type: string) => IAggType>; + getType: Promise<(name: string) => IAggType>; }): ExpressionRenderDefinition => ({ name: 'lens_datatable_renderer', displayName: i18n.translate('xpack.lens.datatable.visualizationName', { From 1615f23fd4a5a166b91df1c6ca446043ed2b15bf Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Wed, 29 Apr 2020 19:26:39 -0400 Subject: [PATCH 13/18] Fix merge issue --- x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx index 85cf5753befd7..bd8f41754567e 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx @@ -36,7 +36,7 @@ import { XYArgs, SeriesType, visualizationTypes } from './types'; import { VisualizationContainer } from '../visualization_container'; import { isHorizontalChart } from './state_helpers'; import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; -import { getExecuteTriggerActions } from './services'; +import { getExecuteTriggerActions } from '../services'; import { parseInterval } from '../../../../../src/plugins/data/common'; type InferPropType = T extends React.FunctionComponent ? P : T; From 594210db4a480f56a70d132ff001ba78f0cc1928 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 30 Apr 2020 10:33:07 +0200 Subject: [PATCH 14/18] fix: design changes --- .../datatable_visualization/_visualization.scss | 5 +++-- .../public/datatable_visualization/expression.tsx | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss index 1258127fac2b5..3b2d91ccf5f78 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss +++ b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss @@ -4,10 +4,11 @@ .lnsDataTable__filter { opacity: 0; - transition: opacity 250ms ease-in-out; + transition: opacity $euiAnimSpeedNormal ease-in-out; } -.lnsDataTable__cell:hover { +.lnsDataTable__cell:hover, +.lnsDataTable__cell:focus-within { .lnsDataTable__filter { opacity: 1; } diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 000f823faae40..230c1f93fdc6a 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -196,6 +196,8 @@ export function DatatableComponent(props: DatatableRenderProps) { name: (col && col.name) || '', render: (value: unknown) => { const formattedValue = formatters[field]?.convert(value); + const fieldName = col?.meta?.aggConfigParams.field; + if (filterable) { return ( Date: Thu, 30 Apr 2020 11:39:45 +0200 Subject: [PATCH 15/18] feat: correction --- .../plugins/lens/public/datatable_visualization/expression.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 230c1f93fdc6a..f2efcbfecf0b1 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -196,7 +196,7 @@ export function DatatableComponent(props: DatatableRenderProps) { name: (col && col.name) || '', render: (value: unknown) => { const formattedValue = formatters[field]?.convert(value); - const fieldName = col?.meta?.aggConfigParams.field; + const fieldName = col?.meta?.aggConfigParams?.field; if (filterable) { return ( From dab164a3e0ee4d66066e5b19ad66fd82ce585c24 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 30 Apr 2020 16:26:21 +0200 Subject: [PATCH 16/18] fix: copy changes --- .../datatable_visualization/expression.tsx | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index f2efcbfecf0b1..71d29be1744bb 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -215,22 +215,19 @@ export function DatatableComponent(props: DatatableRenderProps) { > handleFilterClick(field, value, colIndex)} /> @@ -238,17 +235,17 @@ export function DatatableComponent(props: DatatableRenderProps) { Date: Thu, 30 Apr 2020 18:28:38 +0200 Subject: [PATCH 17/18] Update x-pack/plugins/lens/public/datatable_visualization/_visualization.scss Co-authored-by: Caroline Horn <549577+cchaos@users.noreply.github.com> --- .../public/datatable_visualization/_visualization.scss | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss index 3b2d91ccf5f78..4a8925ad381da 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss +++ b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss @@ -7,9 +7,7 @@ transition: opacity $euiAnimSpeedNormal ease-in-out; } -.lnsDataTable__cell:hover, -.lnsDataTable__cell:focus-within { - .lnsDataTable__filter { - opacity: 1; - } -} \ No newline at end of file +.lnsDataTable__cell:hover .lnsDataTable__filter, +.lnsDataTable__filter:focus-within { + opacity: 1; +} From 1dcdfa29feec4010f92ea0c38ea17e79ad921e5f Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 30 Apr 2020 19:15:06 +0200 Subject: [PATCH 18/18] Update _visualization.scss --- .../lens/public/datatable_visualization/_visualization.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss index 4a8925ad381da..7d95d73143870 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss +++ b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss @@ -10,4 +10,4 @@ .lnsDataTable__cell:hover .lnsDataTable__filter, .lnsDataTable__filter:focus-within { opacity: 1; -} +}