diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable.ts index 7a6d68eaa6566..1eab399055480 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable.ts @@ -16,6 +16,11 @@ export interface SortingState { direction: 'asc' | 'desc' | 'none'; } +export interface PagingState { + size: number; + enabled: boolean; +} + export interface DatatableArgs { title: string; description?: string; @@ -23,6 +28,7 @@ export interface DatatableArgs { sortingColumnId: SortingState['columnId']; sortingDirection: SortingState['direction']; fitRowToContent?: boolean; + pageSize?: PagingState['size']; } export const getDatatable = ( @@ -62,6 +68,10 @@ export const getDatatable = ( types: ['boolean'], help: '', }, + pageSize: { + types: ['number'], + help: '', + }, }, async fn(...args) { /** Build optimization: prevent adding extra code into initial bundle **/ diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/constants.ts b/x-pack/plugins/lens/public/datatable_visualization/components/constants.ts index 84ee4f0e8a18e..b1053631b0117 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/constants.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/components/constants.ts @@ -8,3 +8,4 @@ export const LENS_EDIT_SORT_ACTION = 'sort'; export const LENS_EDIT_RESIZE_ACTION = 'resize'; export const LENS_TOGGLE_ACTION = 'toggle'; +export const LENS_EDIT_PAGESIZE_ACTION = 'pagesize'; 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 22407f2b39771..f71d2b9ec6326 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 @@ -6,12 +6,16 @@ */ import React from 'react'; -import { ReactWrapper, shallow } from 'enzyme'; +import { ReactWrapper, shallow, mount } from 'enzyme'; import { act } from 'react-dom/test-utils'; import { mountWithIntl } from '@kbn/test/jest'; import { EuiDataGrid } from '@elastic/eui'; import { IAggType } from 'src/plugins/data/public'; -import { IFieldFormat } from 'src/plugins/field_formats/common'; +import { + FieldFormatParams, + IFieldFormat, + SerializedFieldFormat, +} from 'src/plugins/field_formats/common'; import { VisualizationContainer } from '../../visualization_container'; import { EmptyPlaceholder } from '../../shared_components'; import { LensIconChartDatatable } from '../../assets/chart_datatable'; @@ -20,6 +24,9 @@ import { LensMultiTable } from '../../../common'; import { DatatableProps } from '../../../common/expressions'; import { chartPluginMock } from 'src/plugins/charts/public/mocks'; import { IUiSettingsClient } from 'kibana/public'; +import { RenderMode } from 'src/plugins/expressions'; + +import { LENS_EDIT_PAGESIZE_ACTION } from './constants'; function sampleArgs() { const indexPatternId = 'indexPatternId'; @@ -82,7 +89,7 @@ function sampleArgs() { return { data, args }; } -function copyData(data: LensMultiTable): LensMultiTable { +function copyData(data: T): T { return JSON.parse(JSON.stringify(data)); } @@ -658,4 +665,133 @@ describe('DatatableComponent', () => { expect(wrapper.find('[data-test-subj="lnsDataTable-footer-c"]').exists()).toBe(false); }); + + describe('pagination', () => { + it('enables pagination', async () => { + const { data, args } = sampleArgs(); + + args.pageSize = 10; + + const wrapper = mount( + x as IFieldFormat} + dispatchEvent={onDispatchEvent} + getType={jest.fn()} + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={{ get: jest.fn() } as unknown as IUiSettingsClient} + renderMode="edit" + /> + ); + + const paginationConfig = wrapper.find(EuiDataGrid).prop('pagination'); + expect(paginationConfig).toBeTruthy(); + expect(paginationConfig?.pageIndex).toBe(0); // should start at 0 + expect(paginationConfig?.pageSize).toBe(args.pageSize); + + // trigger new page + const newIndex = 3; + act(() => paginationConfig?.onChangePage(newIndex)); + wrapper.update(); + + const updatedConfig = wrapper.find(EuiDataGrid).prop('pagination'); + expect(updatedConfig).toBeTruthy(); + expect(updatedConfig?.pageIndex).toBe(newIndex); + expect(updatedConfig?.pageSize).toBe(args.pageSize); + }); + + it('disables pagination by default', async () => { + const { data, args } = sampleArgs(); + + delete args.pageSize; + + const wrapper = mount( + x as IFieldFormat} + dispatchEvent={onDispatchEvent} + getType={jest.fn()} + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={{ get: jest.fn() } as unknown as IUiSettingsClient} + renderMode="edit" + /> + ); + + const paginationConfig = wrapper.find(EuiDataGrid).prop('pagination'); + expect(paginationConfig).not.toBeTruthy(); + }); + + it('dynamically toggles pagination', async () => { + const { data, args } = sampleArgs(); + + const argsWithPagination = copyData(args); + argsWithPagination.pageSize = 20; + + const argsWithoutPagination = copyData(args); + delete argsWithoutPagination.pageSize; + + const defaultProps = { + data, + formatFactory: (x?: SerializedFieldFormat) => x as IFieldFormat, + dispatchEvent: onDispatchEvent, + getType: jest.fn(), + paletteService: chartPluginMock.createPaletteRegistry(), + uiSettings: { get: jest.fn() } as unknown as IUiSettingsClient, + renderMode: 'edit' as RenderMode, + }; + + const wrapper = mount( + + ); + wrapper.update(); + + expect(wrapper.find(EuiDataGrid).prop('pagination')).not.toBeTruthy(); + + wrapper.setProps({ args: argsWithPagination }); + wrapper.update(); + + expect(wrapper.find(EuiDataGrid).prop('pagination')).toBeTruthy(); + + wrapper.setProps({ args: argsWithoutPagination }); + wrapper.update(); + + expect(wrapper.find(EuiDataGrid).prop('pagination')).not.toBeTruthy(); + }); + + it('dispatches event when page size changed', async () => { + const { data, args } = sampleArgs(); + + args.pageSize = 10; + + const wrapper = mount( + x as IFieldFormat} + dispatchEvent={onDispatchEvent} + getType={jest.fn()} + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={{ get: jest.fn() } as unknown as IUiSettingsClient} + renderMode="edit" + /> + ); + + const paginationConfig = wrapper.find(EuiDataGrid).prop('pagination'); + expect(paginationConfig).toBeTruthy(); + + const sizeToChangeTo = 100; + paginationConfig?.onChangeItemsPerPage(sizeToChangeTo); + + expect(onDispatchEvent).toHaveBeenCalledTimes(1); + expect(onDispatchEvent).toHaveBeenCalledWith({ + name: 'edit', + data: { + action: LENS_EDIT_PAGESIZE_ACTION, + size: sizeToChangeTo, + }, + }); + }); + }); }); 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 f8a2bb1fabf81..6635ada9a4036 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 @@ -7,7 +7,7 @@ import './table_basic.scss'; -import React, { useCallback, useMemo, useRef, useState, useContext } from 'react'; +import React, { useCallback, useMemo, useRef, useState, useContext, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import useDeepCompareEffect from 'react-use/lib/useDeepCompareEffect'; import { @@ -30,6 +30,7 @@ import type { LensSortAction, LensResizeAction, LensToggleAction, + LensPagesizeAction, } from './types'; import { createGridColumns } from './columns'; import { createGridCell } from './cell_value'; @@ -50,6 +51,9 @@ const gridStyle: EuiDataGridStyle = { header: 'underline', }; +export const DEFAULT_PAGE_SIZE = 10; +const PAGE_SIZE_OPTIONS = [DEFAULT_PAGE_SIZE, 20, 30, 50, 100]; + export const DatatableComponent = (props: DatatableRenderProps) => { const [firstTable] = Object.values(props.data.tables); @@ -60,6 +64,22 @@ export const DatatableComponent = (props: DatatableRenderProps) => { }); const [firstLocalTable, updateTable] = useState(firstTable); + // ** Pagination config + const [pagination, setPagination] = useState<{ pageIndex: number; pageSize: number } | undefined>( + undefined + ); + + useEffect(() => { + setPagination( + props.args.pageSize + ? { + pageIndex: 0, + pageSize: props.args.pageSize ?? DEFAULT_PAGE_SIZE, + } + : undefined + ); + }, [props.args.pageSize]); + useDeepCompareEffect(() => { setColumnConfig({ columns: props.args.columns, @@ -102,11 +122,35 @@ export const DatatableComponent = (props: DatatableRenderProps) => { ); const onEditAction = useCallback( - (data: LensSortAction['data'] | LensResizeAction['data'] | LensToggleAction['data']) => { + ( + data: + | LensSortAction['data'] + | LensResizeAction['data'] + | LensToggleAction['data'] + | LensPagesizeAction['data'] + ) => { dispatchEvent({ name: 'edit', data }); }, [dispatchEvent] ); + + const onChangeItemsPerPage = useCallback( + (pageSize) => onEditAction({ action: 'pagesize', size: pageSize }), + [onEditAction] + ); + + // active page isn't persisted, so we manage this state locally + const onChangePage = useCallback( + (pageIndex) => { + setPagination((_pagination) => { + if (_pagination) { + return { pageSize: _pagination?.pageSize, pageIndex }; + } + }); + }, + [setPagination] + ); + const onRowContextMenuClick = useCallback( (data: LensTableRowContextMenuEvent['data']) => { dispatchEvent({ name: 'tableRowContextMenuClick', data }); @@ -346,6 +390,15 @@ export const DatatableComponent = (props: DatatableRenderProps) => { }} > id).join('-') + '-' + pagination.pageSize, + } + : {}) + } aria-label={dataGridAriaLabel} data-test-subj="lnsDataTable" rowHeightsOptions={ @@ -362,6 +415,14 @@ export const DatatableComponent = (props: DatatableRenderProps) => { renderCellValue={renderCellValue} gridStyle={gridStyle} sorting={sorting} + pagination={ + pagination && { + ...pagination, + pageSizeOptions: PAGE_SIZE_OPTIONS, + onChangeItemsPerPage, + onChangePage, + } + } onColumnResize={onColumnResize} toolbarVisibility={false} renderFooterCellValue={renderSummaryRow} diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/toolbar.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/toolbar.test.tsx new file mode 100644 index 0000000000000..35e5c81cb72c4 --- /dev/null +++ b/x-pack/plugins/lens/public/datatable_visualization/components/toolbar.test.tsx @@ -0,0 +1,125 @@ +/* + * 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 React, { FormEvent } from 'react'; +import { mountWithIntl } from '@kbn/test/jest'; +import { DataTableToolbar } from './toolbar'; +import { DatatableVisualizationState } from '../visualization'; +import { FramePublicAPI, VisualizationToolbarProps } from '../../types'; +import { ToolbarButton } from 'src/plugins/kibana_react/public'; +import { ReactWrapper } from 'enzyme'; +import { PagingState } from '../../../common/expressions'; + +class Harness { + wrapper: ReactWrapper; + + constructor(wrapper: ReactWrapper) { + this.wrapper = wrapper; + } + + togglePopover() { + this.wrapper.find(ToolbarButton).simulate('click'); + } + + public get fitRowToContentSwitch() { + return this.wrapper.find('EuiSwitch[data-test-subj="lens-legend-auto-height-switch"]'); + } + + toggleFitRowToContent() { + this.fitRowToContentSwitch.prop('onChange')!({} as FormEvent); + } + + public get paginationSwitch() { + return this.wrapper.find('EuiSwitch[data-test-subj="lens-table-pagination-switch"]'); + } + + togglePagination() { + this.paginationSwitch.prop('onChange')!({} as FormEvent); + } +} + +describe('datatable toolbar', () => { + const defaultPagingState: PagingState = { + size: 10, + enabled: true, + }; + + let harness: Harness; + let defaultProps: VisualizationToolbarProps; + + beforeEach(() => { + defaultProps = { + setState: jest.fn(), + frame: {} as FramePublicAPI, + state: { + fitRowToContent: false, + } as DatatableVisualizationState, + }; + + harness = new Harness(mountWithIntl()); + }); + + it('should reflect state in the UI', async () => { + harness.togglePopover(); + + expect(harness.fitRowToContentSwitch.prop('checked')).toBe(false); + expect(harness.paginationSwitch.prop('checked')).toBe(false); + + harness.wrapper.setProps({ + state: { + fitRowToContent: true, + paging: defaultPagingState, + }, + }); + + expect(harness.fitRowToContentSwitch.prop('checked')).toBe(true); + expect(harness.paginationSwitch.prop('checked')).toBe(true); + }); + + it('should toggle fit-row-to-content', async () => { + harness.togglePopover(); + + harness.toggleFitRowToContent(); + + expect(defaultProps.setState).toHaveBeenCalledTimes(1); + expect(defaultProps.setState).toHaveBeenNthCalledWith(1, { + fitRowToContent: true, + }); + + harness.wrapper.setProps({ state: { fitRowToContent: true } }); // update state manually + harness.toggleFitRowToContent(); // turn it off + + expect(defaultProps.setState).toHaveBeenCalledTimes(2); + expect(defaultProps.setState).toHaveBeenNthCalledWith(2, { + fitRowToContent: false, + }); + }); + + it('should toggle table pagination', async () => { + harness.togglePopover(); + + harness.togglePagination(); + + expect(defaultProps.setState).toHaveBeenCalledTimes(1); + expect(defaultProps.setState).toHaveBeenNthCalledWith(1, { + paging: defaultPagingState, + fitRowToContent: false, + }); + + // update state manually + harness.wrapper.setProps({ + state: { fitRowToContent: false, paging: defaultPagingState }, + }); + harness.togglePagination(); // turn it off. this should disable pagination but preserve the default page size + + expect(defaultProps.setState).toHaveBeenCalledTimes(2); + expect(defaultProps.setState).toHaveBeenNthCalledWith(2, { + fitRowToContent: false, + paging: { ...defaultPagingState, enabled: false }, + }); + }); +}); diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/toolbar.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/toolbar.tsx index 8da980af64462..e95ae98e37563 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/toolbar.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/toolbar.tsx @@ -7,15 +7,16 @@ import React, { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiFlexGroup, EuiFormRow, EuiSwitch } from '@elastic/eui'; +import { EuiFlexGroup, EuiFormRow, EuiSwitch, EuiToolTip } from '@elastic/eui'; import { ToolbarPopover } from '../../shared_components'; import type { VisualizationToolbarProps } from '../../types'; import type { DatatableVisualizationState } from '../visualization'; +import { DEFAULT_PAGE_SIZE } from './table_basic'; export function DataTableToolbar(props: VisualizationToolbarProps) { const { state, setState } = props; - const onChange = useCallback(() => { + const onToggleFitRow = useCallback(() => { const current = state.fitRowToContent ?? false; setState({ ...state, @@ -23,6 +24,15 @@ export function DataTableToolbar(props: VisualizationToolbarProps { + const current = state.paging ?? { size: DEFAULT_PAGE_SIZE, enabled: false }; + + setState({ + ...state, + paging: { ...current, enabled: !current.enabled }, + }); + }, [setState, state]); + return ( + + + ); diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/types.ts b/x-pack/plugins/lens/public/datatable_visualization/components/types.ts index f3d81c2d13340..e7be5b78545e8 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/types.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/components/types.ts @@ -10,7 +10,12 @@ import { CustomPaletteState, PaletteRegistry } from 'src/plugins/charts/public'; import type { IAggType } from 'src/plugins/data/public'; import type { Datatable, RenderMode } from 'src/plugins/expressions'; import type { ILensInterpreterRenderHandlers, LensEditEvent } from '../../types'; -import { LENS_EDIT_SORT_ACTION, LENS_EDIT_RESIZE_ACTION, LENS_TOGGLE_ACTION } from './constants'; +import { + LENS_EDIT_SORT_ACTION, + LENS_EDIT_RESIZE_ACTION, + LENS_TOGGLE_ACTION, + LENS_EDIT_PAGESIZE_ACTION, +} from './constants'; import type { FormatFactory } from '../../../common'; import type { DatatableProps, LensGridDirection } from '../../../common/expressions'; @@ -28,9 +33,14 @@ export interface LensToggleActionData { columnId: string; } +export interface LensPagesizeActionData { + size: number; +} + export type LensSortAction = LensEditEvent; export type LensResizeAction = LensEditEvent; export type LensToggleAction = LensEditEvent; +export type LensPagesizeAction = LensEditEvent; export type DatatableRenderProps = DatatableProps & { formatFactory: FormatFactory; diff --git a/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx index 64d5a6f8f25a6..4f27d33e0a94f 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx @@ -7,7 +7,7 @@ import { Ast } from '@kbn/interpreter/common'; import { buildExpression } from '../../../../../src/plugins/expressions/public'; -import { createMockDatasource, createMockFramePublicAPI } from '../mocks'; +import { createMockDatasource, createMockFramePublicAPI, DatasourceMock } from '../mocks'; import { DatatableVisualizationState, getDatatableVisualization } from './visualization'; import { Operation, @@ -453,11 +453,29 @@ describe('Datatable Visualization', () => { }); describe('#toExpression', () => { - it('reorders the rendered colums based on the order from the datasource', () => { - const datasource = createMockDatasource('test'); - const frame = mockFrame(); - frame.datasourceLayers = { a: datasource.publicAPIMock }; + const getDatatableExpressionArgs = (state: DatatableVisualizationState) => + buildExpression( + datatableVisualization.toExpression(state, frame.datasourceLayers) as Ast + ).findFunction('lens_datatable')[0].arguments; + + const defaultExpressionTableState = { + layerId: 'a', + layerType: layerTypes.DATA, + columns: [{ columnId: 'b' }, { columnId: 'c' }], + }; + + let datasource: DatasourceMock; + let frame: FramePublicAPI; + + beforeEach(() => { + datasource = createMockDatasource('test'); datasource.publicAPIMock.getTableSpec.mockReturnValue([{ columnId: 'c' }, { columnId: 'b' }]); + + frame = mockFrame(); + frame.datasourceLayers = { a: datasource.publicAPIMock }; + }); + + it('reorders the rendered colums based on the order from the datasource', () => { datasource.publicAPIMock.getOperationForColumnId.mockReturnValue({ dataType: 'string', isBucketed: false, // <= make them metrics @@ -465,11 +483,7 @@ describe('Datatable Visualization', () => { }); const expression = datatableVisualization.toExpression( - { - layerId: 'a', - layerType: layerTypes.DATA, - columns: [{ columnId: 'b' }, { columnId: 'c' }], - }, + defaultExpressionTableState, frame.datasourceLayers ) as Ast; @@ -509,10 +523,6 @@ describe('Datatable Visualization', () => { }); it('returns no expression if the metric dimension is not defined', () => { - const datasource = createMockDatasource('test'); - const frame = mockFrame(); - frame.datasourceLayers = { a: datasource.publicAPIMock }; - datasource.publicAPIMock.getTableSpec.mockReturnValue([{ columnId: 'c' }, { columnId: 'b' }]); datasource.publicAPIMock.getOperationForColumnId.mockReturnValue({ dataType: 'string', isBucketed: true, // move it from the metric to the break down by side @@ -520,16 +530,46 @@ describe('Datatable Visualization', () => { }); const expression = datatableVisualization.toExpression( - { - layerId: 'a', - layerType: layerTypes.DATA, - columns: [{ columnId: 'b' }, { columnId: 'c' }], - }, + defaultExpressionTableState, frame.datasourceLayers ); expect(expression).toEqual(null); }); + + it('sets pagination based on state', () => { + expect(getDatatableExpressionArgs({ ...defaultExpressionTableState }).pageSize).toEqual([]); + + expect( + getDatatableExpressionArgs({ + ...defaultExpressionTableState, + paging: { size: 20, enabled: false }, + }).pageSize + ).toEqual([]); + + expect( + getDatatableExpressionArgs({ + ...defaultExpressionTableState, + paging: { size: 20, enabled: true }, + }).pageSize + ).toEqual([20]); + }); + + it('sets fitRowToContent based on state', () => { + expect( + getDatatableExpressionArgs({ ...defaultExpressionTableState }).fitRowToContent + ).toEqual([false]); + + expect( + getDatatableExpressionArgs({ ...defaultExpressionTableState, fitRowToContent: false }) + .fitRowToContent + ).toEqual([false]); + + expect( + getDatatableExpressionArgs({ ...defaultExpressionTableState, fitRowToContent: true }) + .fitRowToContent + ).toEqual([true]); + }); }); describe('#getErrorMessages', () => { @@ -628,5 +668,23 @@ describe('Datatable Visualization', () => { columns: [{ columnId: 'saved', width: undefined }], }); }); + + it('should update page size', () => { + const currentState: DatatableVisualizationState = { + layerId: 'foo', + layerType: layerTypes.DATA, + columns: [{ columnId: 'saved', width: 5000 }], + paging: { enabled: true, size: 10 }, + }; + expect( + datatableVisualization.onEditAction!(currentState, { + name: 'edit', + data: { action: 'pagesize', size: 30 }, + }) + ).toEqual({ + ...currentState, + paging: { enabled: true, size: 30 }, + }); + }); }); }); diff --git a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx index a953da4c380f0..903dd7bcaa74a 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx @@ -22,7 +22,7 @@ import { TableDimensionEditor } from './components/dimension_editor'; import { CUSTOM_PALETTE } from '../shared_components/coloring/constants'; import { getStopsForFixedMode } from '../shared_components'; import { LayerType, layerTypes } from '../../common'; -import { getDefaultSummaryLabel } from '../../common/expressions'; +import { getDefaultSummaryLabel, PagingState } from '../../common/expressions'; import type { ColumnState, SortingState } from '../../common/expressions'; import { DataTableToolbar } from './components/toolbar'; export interface DatatableVisualizationState { @@ -31,6 +31,7 @@ export interface DatatableVisualizationState { layerType: LayerType; sorting?: SortingState; fitRowToContent?: boolean; + paging?: PagingState; } const visualizationLabel = i18n.translate('xpack.lens.datatable.label', { @@ -391,6 +392,7 @@ export const getDatatableVisualization = ({ sortingColumnId: [state.sorting?.columnId || ''], sortingDirection: [state.sorting?.direction || 'none'], fitRowToContent: [state.fitRowToContent ?? false], + pageSize: state.paging?.enabled ? [state.paging.size] : [], }, }, ], @@ -421,10 +423,11 @@ export const getDatatableVisualization = ({ }, }; case 'toggle': + const toggleColumnId = event.data.columnId; return { ...state, columns: state.columns.map((column) => { - if (column.columnId === event.data.columnId) { + if (column.columnId === toggleColumnId) { return { ...column, hidden: !column.hidden, @@ -436,10 +439,11 @@ export const getDatatableVisualization = ({ }; case 'resize': const targetWidth = event.data.width; + const resizeColumnId = event.data.columnId; return { ...state, columns: state.columns.map((column) => { - if (column.columnId === event.data.columnId) { + if (column.columnId === resizeColumnId) { return { ...column, width: targetWidth, @@ -449,6 +453,14 @@ export const getDatatableVisualization = ({ } }), }; + case 'pagesize': + return { + ...state, + paging: { + enabled: state.paging?.enabled || false, + size: event.data.size, + }, + }; default: return state; } diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index a9a9539064659..362c7a979107f 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -26,6 +26,7 @@ import type { LensSortActionData, LensResizeActionData, LensToggleActionData, + LensPagesizeActionData, } from './datatable_visualization/components/types'; import type { UiActionsStart, @@ -37,6 +38,7 @@ import { LENS_EDIT_SORT_ACTION, LENS_EDIT_RESIZE_ACTION, LENS_TOGGLE_ACTION, + LENS_EDIT_PAGESIZE_ACTION, } from './datatable_visualization/components/constants'; import type { LensInspector } from './lens_inspector_service'; @@ -782,6 +784,7 @@ export interface LensEditContextMapping { [LENS_EDIT_SORT_ACTION]: LensSortActionData; [LENS_EDIT_RESIZE_ACTION]: LensResizeActionData; [LENS_TOGGLE_ACTION]: LensToggleActionData; + [LENS_EDIT_PAGESIZE_ACTION]: LensPagesizeActionData; } type LensEditSupportedActions = keyof LensEditContextMapping;