mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Lens] Improve Datatable content height with custom row height (#127134)
* ✨ Add new rowHeight feature * ✅ Add unit tests for new feature * 🗃️ Update migration logic * 🏷️ Fix type issue * ✅ fix usual map migration test * Update x-pack/plugins/lens/public/datatable_visualization/components/toolbar.tsx * 🐛 Enable word wrap for multi lines * ✅ Fix unit test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
e932d83944
commit
b7f3271fae
16 changed files with 426 additions and 51 deletions
|
@ -28,6 +28,7 @@ export interface DatatableArgs {
|
|||
sortingColumnId: SortingState['columnId'];
|
||||
sortingDirection: SortingState['direction'];
|
||||
fitRowToContent?: boolean;
|
||||
rowHeightLines?: number;
|
||||
pageSize?: PagingState['size'];
|
||||
}
|
||||
|
||||
|
@ -68,6 +69,10 @@ export const getDatatable = (
|
|||
types: ['boolean'],
|
||||
help: '',
|
||||
},
|
||||
rowHeightLines: {
|
||||
types: ['number'],
|
||||
help: '',
|
||||
},
|
||||
pageSize: {
|
||||
types: ['number'],
|
||||
help: '',
|
||||
|
|
|
@ -227,6 +227,13 @@ exports[`DatatableComponent it renders actions column when there are row actions
|
|||
onColumnResize={[Function]}
|
||||
renderCellValue={[Function]}
|
||||
rowCount={1}
|
||||
rowHeightsOptions={
|
||||
Object {
|
||||
"defaultHeight": Object {
|
||||
"lineCount": 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
sorting={
|
||||
Object {
|
||||
"columns": Array [],
|
||||
|
@ -472,6 +479,13 @@ exports[`DatatableComponent it renders the title and value 1`] = `
|
|||
onColumnResize={[Function]}
|
||||
renderCellValue={[Function]}
|
||||
rowCount={1}
|
||||
rowHeightsOptions={
|
||||
Object {
|
||||
"defaultHeight": Object {
|
||||
"lineCount": 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
sorting={
|
||||
Object {
|
||||
"columns": Array [],
|
||||
|
@ -712,6 +726,13 @@ exports[`DatatableComponent it should render hide, reset, and sort actions on he
|
|||
onColumnResize={[Function]}
|
||||
renderCellValue={[Function]}
|
||||
rowCount={1}
|
||||
rowHeightsOptions={
|
||||
Object {
|
||||
"defaultHeight": Object {
|
||||
"lineCount": 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
sorting={
|
||||
Object {
|
||||
"columns": Array [],
|
||||
|
|
|
@ -86,7 +86,7 @@ describe('datatable cell renderer', () => {
|
|||
/>
|
||||
</DataContext.Provider>
|
||||
);
|
||||
expect(cell.find('.lnsTableCell').prop('className')).toContain('--right');
|
||||
expect(cell.find('.lnsTableCell--right').exists()).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('dynamic coloring', () => {
|
||||
|
@ -127,6 +127,7 @@ describe('datatable cell renderer', () => {
|
|||
],
|
||||
sortingColumnId: '',
|
||||
sortingDirection: 'none',
|
||||
rowHeightLines: 1,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,8 @@ export const createGridCell = (
|
|||
columnConfig: ColumnConfig,
|
||||
DataContext: React.Context<DataContextType>,
|
||||
uiSettings: IUiSettingsClient,
|
||||
fitRowToContent?: boolean
|
||||
fitRowToContent?: boolean,
|
||||
rowHeight?: number
|
||||
) => {
|
||||
// Changing theme requires a full reload of the page, so we can cache here
|
||||
const IS_DARK_THEME = uiSettings.get('theme:darkMode');
|
||||
|
@ -31,7 +32,7 @@ export const createGridCell = (
|
|||
const currentAlignment = alignments && alignments[columnId];
|
||||
const alignmentClassName = `lnsTableCell--${currentAlignment}`;
|
||||
const className = classNames(alignmentClassName, {
|
||||
lnsTableCell: !fitRowToContent,
|
||||
lnsTableCell: !fitRowToContent && rowHeight === 1,
|
||||
});
|
||||
|
||||
const { colorMode, palette } =
|
||||
|
|
|
@ -84,6 +84,7 @@ function sampleArgs() {
|
|||
],
|
||||
sortingColumnId: '',
|
||||
sortingDirection: 'none',
|
||||
rowHeightLines: 1,
|
||||
};
|
||||
|
||||
return { data, args };
|
||||
|
@ -299,6 +300,7 @@ describe('DatatableComponent', () => {
|
|||
],
|
||||
sortingColumnId: '',
|
||||
sortingDirection: 'none',
|
||||
rowHeightLines: 1,
|
||||
};
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
|
|
|
@ -334,9 +334,16 @@ export const DatatableComponent = (props: DatatableRenderProps) => {
|
|||
columnConfig,
|
||||
DataContext,
|
||||
props.uiSettings,
|
||||
props.args.fitRowToContent
|
||||
props.args.fitRowToContent,
|
||||
props.args.rowHeightLines
|
||||
),
|
||||
[formatters, columnConfig, props.uiSettings, props.args.fitRowToContent]
|
||||
[
|
||||
formatters,
|
||||
columnConfig,
|
||||
props.uiSettings,
|
||||
props.args.fitRowToContent,
|
||||
props.args.rowHeightLines,
|
||||
]
|
||||
);
|
||||
|
||||
const columnVisibility = useMemo(
|
||||
|
@ -414,13 +421,15 @@ export const DatatableComponent = (props: DatatableRenderProps) => {
|
|||
<EuiDataGrid
|
||||
aria-label={dataGridAriaLabel}
|
||||
data-test-subj="lnsDataTable"
|
||||
rowHeightsOptions={
|
||||
props.args.fitRowToContent
|
||||
rowHeightsOptions={{
|
||||
defaultHeight: props.args.fitRowToContent
|
||||
? 'auto'
|
||||
: props.args.rowHeightLines
|
||||
? {
|
||||
defaultHeight: 'auto',
|
||||
lineCount: props.args.rowHeightLines,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
: undefined,
|
||||
}}
|
||||
columns={columns}
|
||||
columnVisibility={columnVisibility}
|
||||
trailingControlColumns={trailingControlColumns}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { FormEvent } from 'react';
|
||||
import React, { ChangeEvent, FormEvent } from 'react';
|
||||
import { mountWithIntl } from '@kbn/test-jest-helpers';
|
||||
import { DataTableToolbar } from './toolbar';
|
||||
import { DatatableVisualizationState } from '../visualization';
|
||||
|
@ -13,6 +13,19 @@ import { FramePublicAPI, VisualizationToolbarProps } from '../../types';
|
|||
import { ToolbarButton } from 'src/plugins/kibana_react/public';
|
||||
import { ReactWrapper } from 'enzyme';
|
||||
import { PagingState } from '../../../common/expressions';
|
||||
import { EuiButtonGroup, EuiRange } from '@elastic/eui';
|
||||
|
||||
// mocking random id generator function
|
||||
jest.mock('@elastic/eui', () => {
|
||||
const original = jest.requireActual('@elastic/eui');
|
||||
|
||||
return {
|
||||
...original,
|
||||
htmlIdGenerator: (fn: unknown) => {
|
||||
return () => '';
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
class Harness {
|
||||
wrapper: ReactWrapper;
|
||||
|
@ -25,12 +38,25 @@ class Harness {
|
|||
this.wrapper.find(ToolbarButton).simulate('click');
|
||||
}
|
||||
|
||||
public get fitRowToContentSwitch() {
|
||||
return this.wrapper.find('EuiSwitch[data-test-subj="lens-legend-auto-height-switch"]');
|
||||
public get rowHeight() {
|
||||
return this.wrapper.find(EuiButtonGroup);
|
||||
}
|
||||
|
||||
toggleFitRowToContent() {
|
||||
this.fitRowToContentSwitch.prop('onChange')!({} as FormEvent);
|
||||
changeRowHeight(newMode: 'single' | 'auto' | 'custom') {
|
||||
this.rowHeight.prop('onChange')!(newMode);
|
||||
}
|
||||
|
||||
public get rowHeightLines() {
|
||||
return this.wrapper.find(EuiRange);
|
||||
}
|
||||
|
||||
changeRowHeightLines(lineCount: number) {
|
||||
this.rowHeightLines.prop('onChange')!(
|
||||
{
|
||||
currentTarget: { value: lineCount },
|
||||
} as unknown as ChangeEvent<HTMLInputElement>,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
public get paginationSwitch() {
|
||||
|
@ -56,7 +82,7 @@ describe('datatable toolbar', () => {
|
|||
setState: jest.fn(),
|
||||
frame: {} as FramePublicAPI,
|
||||
state: {
|
||||
fitRowToContent: false,
|
||||
rowHeight: 'single',
|
||||
} as DatatableVisualizationState,
|
||||
};
|
||||
|
||||
|
@ -66,39 +92,57 @@ describe('datatable toolbar', () => {
|
|||
it('should reflect state in the UI', async () => {
|
||||
harness.togglePopover();
|
||||
|
||||
expect(harness.fitRowToContentSwitch.prop('checked')).toBe(false);
|
||||
expect(harness.rowHeight.prop('idSelected')).toBe('single');
|
||||
expect(harness.paginationSwitch.prop('checked')).toBe(false);
|
||||
|
||||
harness.wrapper.setProps({
|
||||
state: {
|
||||
fitRowToContent: true,
|
||||
rowHeight: 'auto',
|
||||
paging: defaultPagingState,
|
||||
},
|
||||
});
|
||||
|
||||
expect(harness.fitRowToContentSwitch.prop('checked')).toBe(true);
|
||||
expect(harness.rowHeight.prop('idSelected')).toBe('auto');
|
||||
expect(harness.paginationSwitch.prop('checked')).toBe(true);
|
||||
});
|
||||
|
||||
it('should toggle fit-row-to-content', async () => {
|
||||
it('should change row height to "Auto" mode', async () => {
|
||||
harness.togglePopover();
|
||||
|
||||
harness.toggleFitRowToContent();
|
||||
harness.changeRowHeight('auto');
|
||||
|
||||
expect(defaultProps.setState).toHaveBeenCalledTimes(1);
|
||||
expect(defaultProps.setState).toHaveBeenNthCalledWith(1, {
|
||||
fitRowToContent: true,
|
||||
rowHeight: 'auto',
|
||||
rowHeightLines: undefined,
|
||||
});
|
||||
|
||||
harness.wrapper.setProps({ state: { fitRowToContent: true } }); // update state manually
|
||||
harness.toggleFitRowToContent(); // turn it off
|
||||
harness.wrapper.setProps({ state: { rowHeight: 'auto' } }); // update state manually
|
||||
harness.changeRowHeight('single'); // turn it off
|
||||
|
||||
expect(defaultProps.setState).toHaveBeenCalledTimes(2);
|
||||
expect(defaultProps.setState).toHaveBeenNthCalledWith(2, {
|
||||
fitRowToContent: false,
|
||||
rowHeight: 'single',
|
||||
rowHeightLines: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('should change row height to "Custom" mode', async () => {
|
||||
harness.togglePopover();
|
||||
|
||||
harness.changeRowHeight('custom');
|
||||
|
||||
expect(defaultProps.setState).toHaveBeenCalledTimes(1);
|
||||
expect(defaultProps.setState).toHaveBeenNthCalledWith(1, {
|
||||
rowHeight: 'custom',
|
||||
rowHeightLines: 2,
|
||||
});
|
||||
|
||||
harness.wrapper.setProps({ state: { rowHeight: 'custom' } }); // update state manually
|
||||
|
||||
expect(harness.rowHeightLines.prop('value')).toBe(2);
|
||||
});
|
||||
|
||||
it('should toggle table pagination', async () => {
|
||||
harness.togglePopover();
|
||||
|
||||
|
@ -107,18 +151,18 @@ describe('datatable toolbar', () => {
|
|||
expect(defaultProps.setState).toHaveBeenCalledTimes(1);
|
||||
expect(defaultProps.setState).toHaveBeenNthCalledWith(1, {
|
||||
paging: defaultPagingState,
|
||||
fitRowToContent: false,
|
||||
rowHeight: 'single',
|
||||
});
|
||||
|
||||
// update state manually
|
||||
harness.wrapper.setProps({
|
||||
state: { fitRowToContent: false, paging: defaultPagingState },
|
||||
state: { rowHeight: 'single', 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,
|
||||
rowHeight: 'single',
|
||||
paging: { ...defaultPagingState, enabled: false },
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,22 +7,47 @@
|
|||
|
||||
import React, { useCallback } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiFlexGroup, EuiFormRow, EuiSwitch, EuiToolTip } from '@elastic/eui';
|
||||
import {
|
||||
EuiButtonGroup,
|
||||
EuiFlexGroup,
|
||||
EuiFormRow,
|
||||
EuiRange,
|
||||
EuiSwitch,
|
||||
EuiToolTip,
|
||||
htmlIdGenerator,
|
||||
} 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';
|
||||
|
||||
const idPrefix = htmlIdGenerator()();
|
||||
|
||||
export function DataTableToolbar(props: VisualizationToolbarProps<DatatableVisualizationState>) {
|
||||
const { state, setState } = props;
|
||||
|
||||
const onToggleFitRow = useCallback(() => {
|
||||
const current = state.fitRowToContent ?? false;
|
||||
setState({
|
||||
...state,
|
||||
fitRowToContent: !current,
|
||||
});
|
||||
}, [setState, state]);
|
||||
const onChangeRowHeight = useCallback(
|
||||
(newHeightMode) => {
|
||||
const rowHeightLines =
|
||||
newHeightMode === 'single' ? 1 : newHeightMode !== 'auto' ? 2 : undefined;
|
||||
setState({
|
||||
...state,
|
||||
rowHeight: newHeightMode,
|
||||
rowHeightLines,
|
||||
});
|
||||
},
|
||||
[setState, state]
|
||||
);
|
||||
|
||||
const onChangeRowHeightLines = useCallback(
|
||||
(newRowHeightLines) => {
|
||||
setState({
|
||||
...state,
|
||||
rowHeightLines: newRowHeightLines,
|
||||
});
|
||||
},
|
||||
[state, setState]
|
||||
);
|
||||
|
||||
const onTogglePagination = useCallback(() => {
|
||||
const current = state.paging ?? { size: DEFAULT_PAGE_SIZE, enabled: false };
|
||||
|
@ -33,6 +58,30 @@ export function DataTableToolbar(props: VisualizationToolbarProps<DatatableVisua
|
|||
});
|
||||
}, [setState, state]);
|
||||
|
||||
const rowHeightModeOptions = [
|
||||
{
|
||||
id: `${idPrefix}single`,
|
||||
label: i18n.translate('xpack.lens.table.rowHeight.single', {
|
||||
defaultMessage: 'Single',
|
||||
}),
|
||||
'data-test-subj': 'lnsDatatable_rowHeight_single',
|
||||
},
|
||||
{
|
||||
id: `${idPrefix}auto`,
|
||||
label: i18n.translate('xpack.lens.table.rowHeight.auto', {
|
||||
defaultMessage: 'Auto fit',
|
||||
}),
|
||||
'data-test-subj': 'lnsDatatable_rowHeight_auto',
|
||||
},
|
||||
{
|
||||
id: `${idPrefix}custom`,
|
||||
label: i18n.translate('xpack.lens.table.rowHeight.custom', {
|
||||
defaultMessage: 'Custom',
|
||||
}),
|
||||
'data-test-subj': 'lnsDatatable_rowHeight_custom',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="none" justifyContent="spaceBetween" responsive={false}>
|
||||
<ToolbarPopover
|
||||
|
@ -45,19 +94,52 @@ export function DataTableToolbar(props: VisualizationToolbarProps<DatatableVisua
|
|||
>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.lens.table.visualOptionsFitRowToContentLabel', {
|
||||
defaultMessage: 'Fit row to content',
|
||||
defaultMessage: 'Row height',
|
||||
})}
|
||||
display="columnCompressedSwitch"
|
||||
display="columnCompressed"
|
||||
>
|
||||
<EuiSwitch
|
||||
compressed
|
||||
data-test-subj="lens-legend-auto-height-switch"
|
||||
label=""
|
||||
showLabel={false}
|
||||
checked={Boolean(state.fitRowToContent)}
|
||||
onChange={onToggleFitRow}
|
||||
<EuiButtonGroup
|
||||
isFullWidth
|
||||
legend={i18n.translate('xpack.lens.table.visualOptionsRowHeight', {
|
||||
defaultMessage: 'Row height',
|
||||
})}
|
||||
data-test-subj="lens-table-row-height"
|
||||
name="legendLocation"
|
||||
buttonSize="compressed"
|
||||
options={rowHeightModeOptions}
|
||||
idSelected={`${idPrefix}${state.rowHeight ?? 'single'}`}
|
||||
onChange={(optionId) => {
|
||||
const newMode = optionId.replace(
|
||||
idPrefix,
|
||||
''
|
||||
) as DatatableVisualizationState['rowHeight'];
|
||||
onChangeRowHeight(newMode);
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
{state.rowHeight === 'custom' ? (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.lens.table.visualOptionsCustomRowHeight', {
|
||||
defaultMessage: 'Lines per row',
|
||||
})}
|
||||
display="columnCompressed"
|
||||
>
|
||||
<EuiRange
|
||||
compressed
|
||||
fullWidth
|
||||
showInput
|
||||
min={1}
|
||||
max={20}
|
||||
step={1}
|
||||
value={state.rowHeightLines ?? 2}
|
||||
onChange={(e) => {
|
||||
const lineCount = Number(e.currentTarget.value);
|
||||
onChangeRowHeightLines(lineCount);
|
||||
}}
|
||||
data-test-subj="lens-table-row-height-lineCountNumber"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
) : null}
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.lens.table.visualOptionsPaginateTable', {
|
||||
defaultMessage: 'Paginate table',
|
||||
|
|
|
@ -597,21 +597,62 @@ describe('Datatable Visualization', () => {
|
|||
).toEqual([20]);
|
||||
});
|
||||
|
||||
it('sets fitRowToContent based on state', () => {
|
||||
it('sets rowHeight "auto" fit based on state', () => {
|
||||
expect(
|
||||
getDatatableExpressionArgs({ ...defaultExpressionTableState }).fitRowToContent
|
||||
).toEqual([false]);
|
||||
|
||||
expect(
|
||||
getDatatableExpressionArgs({ ...defaultExpressionTableState, fitRowToContent: false })
|
||||
getDatatableExpressionArgs({ ...defaultExpressionTableState, rowHeight: 'single' })
|
||||
.fitRowToContent
|
||||
).toEqual([false]);
|
||||
|
||||
expect(
|
||||
getDatatableExpressionArgs({ ...defaultExpressionTableState, fitRowToContent: true })
|
||||
getDatatableExpressionArgs({ ...defaultExpressionTableState, rowHeight: 'custom' })
|
||||
.fitRowToContent
|
||||
).toEqual([false]);
|
||||
|
||||
expect(
|
||||
getDatatableExpressionArgs({ ...defaultExpressionTableState, rowHeight: 'auto' })
|
||||
.fitRowToContent
|
||||
).toEqual([true]);
|
||||
});
|
||||
|
||||
it('sets rowHeightLines fit based on state', () => {
|
||||
expect(getDatatableExpressionArgs({ ...defaultExpressionTableState }).rowHeightLines).toEqual(
|
||||
[1]
|
||||
);
|
||||
|
||||
expect(
|
||||
getDatatableExpressionArgs({ ...defaultExpressionTableState, rowHeight: 'single' })
|
||||
.rowHeightLines
|
||||
).toEqual([1]);
|
||||
|
||||
// should ignore lines value based on mode
|
||||
expect(
|
||||
getDatatableExpressionArgs({
|
||||
...defaultExpressionTableState,
|
||||
rowHeight: 'single',
|
||||
rowHeightLines: 5,
|
||||
}).rowHeightLines
|
||||
).toEqual([1]);
|
||||
|
||||
expect(
|
||||
getDatatableExpressionArgs({
|
||||
...defaultExpressionTableState,
|
||||
rowHeight: 'custom',
|
||||
rowHeightLines: 5,
|
||||
}).rowHeightLines
|
||||
).toEqual([5]);
|
||||
|
||||
// should fallback to 2 for custom in case it's not set
|
||||
expect(
|
||||
getDatatableExpressionArgs({
|
||||
...defaultExpressionTableState,
|
||||
rowHeight: 'custom',
|
||||
}).rowHeightLines
|
||||
).toEqual([2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getErrorMessages', () => {
|
||||
|
|
|
@ -32,7 +32,8 @@ export interface DatatableVisualizationState {
|
|||
layerId: string;
|
||||
layerType: LayerType;
|
||||
sorting?: SortingState;
|
||||
fitRowToContent?: boolean;
|
||||
rowHeight?: 'auto' | 'single' | 'custom';
|
||||
rowHeightLines?: number;
|
||||
paging?: PagingState;
|
||||
}
|
||||
|
||||
|
@ -400,7 +401,10 @@ export const getDatatableVisualization = ({
|
|||
}),
|
||||
sortingColumnId: [state.sorting?.columnId || ''],
|
||||
sortingDirection: [state.sorting?.direction || 'none'],
|
||||
fitRowToContent: [state.fitRowToContent ?? false],
|
||||
fitRowToContent: [state.rowHeight === 'auto'],
|
||||
rowHeightLines: [
|
||||
!state.rowHeight || state.rowHeight === 'single' ? 1 : state.rowHeightLines ?? 2,
|
||||
],
|
||||
pageSize: state.paging?.enabled ? [state.paging.size] : [],
|
||||
},
|
||||
},
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
} from '../../../../../src/plugins/kibana_utils/common';
|
||||
import { DOC_TYPE } from '../../common';
|
||||
import {
|
||||
commonEnhanceTableRowHeight,
|
||||
commonMakeReversePaletteAsCustom,
|
||||
commonRemoveTimezoneDateHistogramParam,
|
||||
commonRenameFilterReferences,
|
||||
|
@ -26,8 +27,10 @@ import {
|
|||
CustomVisualizationMigrations,
|
||||
LensDocShape713,
|
||||
LensDocShape715,
|
||||
LensDocShape810,
|
||||
LensDocShapePre712,
|
||||
VisState716,
|
||||
VisState810,
|
||||
VisStatePre715,
|
||||
} from '../migrations/types';
|
||||
import { extract, inject } from '../../common/embeddable_factory';
|
||||
|
@ -88,6 +91,14 @@ export const makeLensEmbeddableFactory =
|
|||
attributes: migratedLensState,
|
||||
} as unknown as SerializableRecord;
|
||||
},
|
||||
'8.2.0': (state) => {
|
||||
const lensState = state as unknown as { attributes: LensDocShape810<VisState810> };
|
||||
const migratedLensState = commonEnhanceTableRowHeight(lensState.attributes);
|
||||
return {
|
||||
...lensState,
|
||||
attributes: migratedLensState,
|
||||
} as unknown as SerializableRecord;
|
||||
},
|
||||
}),
|
||||
getLensCustomVisualizationMigrations(customVisualizationMigrations)
|
||||
),
|
||||
|
|
|
@ -23,6 +23,8 @@ import {
|
|||
VisStatePost715,
|
||||
VisStatePre715,
|
||||
VisState716,
|
||||
VisState810,
|
||||
VisState820,
|
||||
CustomVisualizationMigrations,
|
||||
LensDocShape810,
|
||||
} from './types';
|
||||
|
@ -192,6 +194,20 @@ export const commonRenameFilterReferences = (attributes: LensDocShape715): LensD
|
|||
return newAttributes as LensDocShape810;
|
||||
};
|
||||
|
||||
export const commonEnhanceTableRowHeight = (
|
||||
attributes: LensDocShape810<VisState810>
|
||||
): LensDocShape810<VisState820> => {
|
||||
if (attributes.visualizationType !== 'lnsDatatable') {
|
||||
return attributes;
|
||||
}
|
||||
const visState810 = attributes.state.visualization as VisState810;
|
||||
const newAttributes = cloneDeep(attributes);
|
||||
const vizState = newAttributes.state.visualization as VisState820;
|
||||
vizState.rowHeight = visState810.fitRowToContent ? 'auto' : 'single';
|
||||
vizState.rowHeightLines = visState810.fitRowToContent ? 2 : 1;
|
||||
return newAttributes;
|
||||
};
|
||||
|
||||
const getApplyCustomVisualizationMigrationToLens = (id: string, migration: MigrateFunction) => {
|
||||
return (savedObject: { attributes: LensDocShape }) => {
|
||||
if (savedObject.attributes.visualizationType !== id) return savedObject;
|
||||
|
|
|
@ -18,6 +18,8 @@ import {
|
|||
VisState716,
|
||||
VisStatePost715,
|
||||
VisStatePre715,
|
||||
VisState810,
|
||||
VisState820,
|
||||
} from './types';
|
||||
import { CustomPaletteParams, layerTypes } from '../../common';
|
||||
import { PaletteOutput } from 'src/plugins/charts/common';
|
||||
|
@ -1779,4 +1781,122 @@ describe('Lens migrations', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('8.2.0 rename fitRowToContent to new detailed rowHeight and rowHeightLines', () => {
|
||||
const context = { log: { warning: () => {} } } as unknown as SavedObjectMigrationContext;
|
||||
function getExample(fitToContent: boolean) {
|
||||
return {
|
||||
type: 'lens',
|
||||
id: 'mocked-saved-object-id',
|
||||
attributes: {
|
||||
visualizationType: 'lnsDatatable',
|
||||
title: 'Lens visualization',
|
||||
references: [
|
||||
{
|
||||
id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f',
|
||||
name: 'indexpattern-datasource-current-indexpattern',
|
||||
type: 'index-pattern',
|
||||
},
|
||||
{
|
||||
id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f',
|
||||
name: 'indexpattern-datasource-layer-cddd8f79-fb20-4191-a3e7-92484780cc62',
|
||||
type: 'index-pattern',
|
||||
},
|
||||
],
|
||||
state: {
|
||||
datasourceStates: {
|
||||
indexpattern: {
|
||||
layers: {
|
||||
'cddd8f79-fb20-4191-a3e7-92484780cc62': {
|
||||
indexPatternId: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f',
|
||||
columns: {
|
||||
'221f0abf-6e54-4c61-9316-4107ad6fa500': {
|
||||
label: 'Top values of category.keyword',
|
||||
dataType: 'string',
|
||||
operationType: 'terms',
|
||||
scale: 'ordinal',
|
||||
sourceField: 'category.keyword',
|
||||
isBucketed: true,
|
||||
params: {
|
||||
size: 5,
|
||||
orderBy: {
|
||||
type: 'column',
|
||||
columnId: 'c6f07a26-64eb-4871-ad62-c7d937230e33',
|
||||
},
|
||||
orderDirection: 'desc',
|
||||
otherBucket: true,
|
||||
missingBucket: false,
|
||||
parentFormat: {
|
||||
id: 'terms',
|
||||
},
|
||||
},
|
||||
},
|
||||
'c6f07a26-64eb-4871-ad62-c7d937230e33': {
|
||||
label: 'Count of records',
|
||||
dataType: 'number',
|
||||
operationType: 'count',
|
||||
isBucketed: false,
|
||||
scale: 'ratio',
|
||||
sourceField: '___records___',
|
||||
},
|
||||
},
|
||||
columnOrder: [
|
||||
'221f0abf-6e54-4c61-9316-4107ad6fa500',
|
||||
'c6f07a26-64eb-4871-ad62-c7d937230e33',
|
||||
],
|
||||
incompleteColumns: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
visualization: {
|
||||
columns: [
|
||||
{
|
||||
isTransposed: false,
|
||||
columnId: '221f0abf-6e54-4c61-9316-4107ad6fa500',
|
||||
},
|
||||
{
|
||||
isTransposed: false,
|
||||
columnId: 'c6f07a26-64eb-4871-ad62-c7d937230e33',
|
||||
},
|
||||
],
|
||||
layerId: 'cddd8f79-fb20-4191-a3e7-92484780cc62',
|
||||
layerType: 'data',
|
||||
fitRowToContent: fitToContent,
|
||||
},
|
||||
filters: [],
|
||||
query: {
|
||||
query: '',
|
||||
language: 'kuery',
|
||||
},
|
||||
},
|
||||
},
|
||||
} as unknown as SavedObjectUnsanitizedDoc<LensDocShape810>;
|
||||
}
|
||||
|
||||
it('should migrate enabled fitRowToContent to new rowHeight: "auto"', () => {
|
||||
const result = migrations['8.2.0'](getExample(true), context) as ReturnType<
|
||||
SavedObjectMigrationFn<LensDocShape810<VisState810>, LensDocShape810<VisState820>>
|
||||
>;
|
||||
|
||||
expect(result.attributes.state.visualization as VisState820).toEqual(
|
||||
expect.objectContaining({
|
||||
rowHeight: 'auto',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should migrate disabled fitRowToContent to new rowHeight: "single"', () => {
|
||||
const result = migrations['8.2.0'](getExample(false), context) as ReturnType<
|
||||
SavedObjectMigrationFn<LensDocShape810<VisState810>, LensDocShape810<VisState820>>
|
||||
>;
|
||||
|
||||
expect(result.attributes.state.visualization as VisState820).toEqual(
|
||||
expect.objectContaining({
|
||||
rowHeight: 'single',
|
||||
rowHeightLines: 1,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -40,6 +40,7 @@ import {
|
|||
getLensCustomVisualizationMigrations,
|
||||
commonRenameRecordsField,
|
||||
fixLensTopValuesCustomFormatting,
|
||||
commonEnhanceTableRowHeight,
|
||||
} from './common_migrations';
|
||||
|
||||
interface LensDocShapePre710<VisualizationState = unknown> {
|
||||
|
@ -464,6 +465,11 @@ const addParentFormatter: SavedObjectMigrationFn<LensDocShape810, LensDocShape81
|
|||
return { ...newDoc, attributes: fixLensTopValuesCustomFormatting(newDoc.attributes) };
|
||||
};
|
||||
|
||||
const enhanceTableRowHeight: SavedObjectMigrationFn<LensDocShape810, LensDocShape810> = (doc) => {
|
||||
const newDoc = cloneDeep(doc);
|
||||
return { ...newDoc, attributes: commonEnhanceTableRowHeight(newDoc.attributes) };
|
||||
};
|
||||
|
||||
const lensMigrations: SavedObjectMigrationMap = {
|
||||
'7.7.0': removeInvalidAccessors,
|
||||
// The order of these migrations matter, since the timefield migration relies on the aggConfigs
|
||||
|
@ -478,6 +484,7 @@ const lensMigrations: SavedObjectMigrationMap = {
|
|||
'7.15.0': addLayerTypeToVisualization,
|
||||
'7.16.0': moveDefaultReversedPaletteToCustom,
|
||||
'8.1.0': flow(renameFilterReferences, renameRecordsField, addParentFormatter),
|
||||
'8.2.0': enhanceTableRowHeight,
|
||||
};
|
||||
|
||||
export const getAllMigrations = (
|
||||
|
|
|
@ -246,3 +246,14 @@ export type VisState716 =
|
|||
| {
|
||||
palette?: PaletteOutput<CustomPaletteParams>;
|
||||
};
|
||||
|
||||
// Datatable only
|
||||
export interface VisState810 {
|
||||
fitRowToContent?: boolean;
|
||||
}
|
||||
|
||||
// Datatable only
|
||||
export interface VisState820 {
|
||||
rowHeight: 'auto' | 'single' | 'custom';
|
||||
rowHeightLines: number;
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ export default function ({ getService }) {
|
|||
}
|
||||
expect(panels.length).to.be(1);
|
||||
expect(panels[0].type).to.be('map');
|
||||
expect(panels[0].version).to.be('8.1.0');
|
||||
expect(panels[0].version).to.be('8.2.0');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue