kibana/x-pack/legacy/plugins/lens/public/xy_visualization_plugin/xy_config_panel.test.tsx

423 lines
12 KiB
TypeScript
Raw Normal View History

New visualization editor Lens (#36437) * [lens] Initial Commit (#35627) * [visualization editor] Initial Commit * [lens] Add more complete initial state * [lens] Fix type issues * [lens] Remove feature control * [lens] Bring back feature control and add tests * [lens] Update plugin structure and naming per comments * replace any usage by safe casting * [lens] Respond to review comments * [lens] Remove unused EditorFrameState type * [lens] Initial state for IndexPatternDatasource (#36052) * [lens] Add first tests to indexpattern data source * Respond to review comments * Fix type definitions * [lens] Editor frame initializes datasources and visualizations (#36060) * [lens] Editor frame initializes datasources and visualizations * Respond to review comments * Fix build issues * Fix state management issue * [lens][draft] Lens/drag drop (#36268) Add basic drag / drop component to Lens * remove local package (#36456) * [lens] Native renderer (#36165) * Add nativerenderer component * Use native renderer in app and editor frame * [Lens] No explicit any (#36515) * [Lens] Implement basic editor frame state handling (#36443) * [lens] Load index patterns and render in data panel (#36463) * [lens] Editor frame initializes datasources and visualizations * Respond to review comments * Fix build issues * remove local package * [lens] Load index patterns into data source * Redo types for Index Pattern Datasource * Fix one more type * Respond to review comments * [draft] Lens/line chart renderer (#36827) Expression logic for the Lens xy chart. * [lens] Index pattern data panel (initial) (#37015) * [lens] Index pattern switcher * Respond to review comments * [Lens] Editor state 2 (#36513) * [lens] Dimension panel that generates columns (#37117) * [lens] Dimension panel that generates columns * Update from review comments * [lens] Generate esdocs queries from index pattern (#37361) * [lens] Generate esdocs queries from index pattern * Remove unused code * Update yarn.lock from yarn kbn bootstrap * [Lens] Add basic Lens xy chart suggestions (#37030) Basic xy chart suggestions * [Lens] Expression rendering (#37648) * [Lens] Expression handling (#37876) * [Lens] Lens/xy config panel (#37391) Basic xy chart configuration panel * [Lens] Xy expression building (#37967) * [Lens] Initialize visualization with datasource api (#38142) * [lens] Dimension panel lets users select operations and fields individually (#37573) * [lens] Dimension panel lets users select operations and fields individually * Split files and add tests * Fix dimension labeling and add clear button * Support more aggregations, aggregation nesting, rollups, and clearing * Fix esaggs expression * Increase top-level test coverage of dimension panel * Update from review comments * [Lens] Rename columns (#38278) * [Lens] Lens/index pattern drag drop (#37711) * Basic xy chart suggestions * Re-apply XY config panel after force merge * Initial integration of lens drag and drop * Tweak naming, remove irellevant comment * Tweaks per Wylie's feedback * Add xy chart internationalization Tweak types per Joe's feedback * Update xy chart i18n implementation * Fix i18n id * Add drop tests to the lens index pattern * improve tests * [lens] Only allow aggregated dimensions (#38820) * [lens] Only allow aggregated dimensions * [lens] Index pattern suggest on drop * Fully remove value * Revert "[lens] Index pattern suggest on drop" This reverts commit 604c6ed68ca394441ddafa662bdfc5f421de300c. * Fix type errors * [lens] Suggest on drop (#38848) * [lens] Index pattern suggest on drop * Add test for suggestion without date field * fix merge * [Lens] Parameter configurations and new dimension config flow (#38863) * fix eslint failure * [lens] Fix build by updating saved objects and i18n (#39391) * [lens] Update location of saved objects code * Update internatationalization * Remove added file * [lens] Fix arguments to esaggs using booleans (#39462) * [lens] Datatable visualization plugin (#39390) * [lens] Datatable visualization plugin * Fix merge issues and add tests * Update from review * Fix file locations * [lens] Use first suggestion when switching visualizations (#39377) * [lens] Label each Y axis with its operation label (#39461) * [lens] Label each Y axis with its operation label * Remove comment * Add link to chart issue * [Lens] Suggestion preview rendering (#39576) * [Lens] Popover configs (#39565) * [Lens] Basic layouting (#39587) * remove datasource public API in suggestions (#39772) * [Lens] Basic save / load (#39257) Add basic routing, save, and load to Lens * [lens] Fix lint error * [lens] Use node scripts/eslint.js --fix to fix errors * [lens] Include link to lens from Visualize (#40542) * [lens] Support stacking in xy visualization (#40546) * [lens] Support stacking in xy visualization * Use chart type switcher for stacked and horizontal xy charts * Clean up remaining isStacked code * Fix type error * [Lens] Add xy split series support (#39726) * Add split series to lens xy chart * [lens] Lens Filter Ratio (#40196) * WIP filter ratio * Fix test issues * Pass dependencies through plugin like new platform * Pass props into filter ratio popover editor * Provide mocks to filter_ratio popover test * Add another test * Clean up to prepare for review * Clean up unnecessary changes * Respond to review comments * Fix tests * [Lens] Terms order direction (#39884) * fix types * [Lens] Data panel styling and optimizations (#40787) Style the data panel (mostly Joe Reuter's doing). Optimize a bunch of the Lens stack. * [Lens] Optimize dimension panel flow (#41114) * [Lens] re-introduce no-explicit-any (#41454) * [Lens] No results marker (#41450) * [lens] Support layers for visualizing results of multiple queries (#41290) * [lens] WIP add support for layers * [lens] WIP switch to nested tables * Get basic layering to work * Load multiple tables and render in one chart * Fix priority ordering * Reduce quantity of linting errors * Ensure that new xy layer state has a split column * Make the "add" y / split the trailing accessor * Various fixes for datasource public API and implementation * Unify datasource deletion and accessor removal * Fix broken scss * Fix xy visualization TypeScript errors? * Build basic suggestions * Restore save/load and fix typescript bugs * simplify init routine * fix save tests * fix persistence tests * fix state management tests * Ensure the data table is aligned to the top * Add layer support to Lens datatable * Give xy chart a default layer initially * Allow deletion of layers in xy charts * xy: Make split accessor singular Remove commented code blocks * Change expression type for lens_merge_tables * Fix XY chart rendering expression * Fix type errors relating to `layerId` in table suggestions * Pass around tables for suggestions with associated layerIds * fix tests in workspace panel * fix editor_frame tests * Fix xy tests, skip inapplicable tests that will be implemented in a separate PR * add some tests for multiple datasources and layers * Suggest that split series comes before X axis in XY chart * Get datatable suggestion working * Adjust how xy axis labels are computed * Datasource suggestions should handle layers and have tests * Fix linting in XY chart and remove commented code * Update snapshots from earlier change * Fix linting errors * More cleanup * Remove commented code * Test the multi-column editor * XY Visualization does not need to track datasourceId * Fix various comments * Remove unused xy prop Add datasource header to datatable config * Use operation labels for XY chart * Adding and removing layers is reflected in the datasource * rewrote datasource state init * clean up editor_frame frame api implementation * clean up editor frame * [Lens] Embeddable (#41361) * [lens] Move XY chart config into popover and fix layering (#41927) * [lens] Move XY chart config into popover and fix layering * Fix tests * Update style * Change wrapping of layer settings popover * [Lens] Fix bugs in date_histogram and filter ratio (#42046) * [Lens] Performance improvements (#41784) * fix type error * switch default size of terms operation to 3 (#42334) * [lens] Improve suggestions for split series (#42052) * [lens] Add chart switcher (#42093) * solve merge conflicts * fix test case * [Lens] Allow only current visualization on field drop in workspace (#42344) * [Lens] Remove indexpattern id on column (#42429) * [lens] Implement app-level filtering and time picker (#42031) * [lens] Implement app-level filtering and time picker * More integration with filter bar * Clean up test code and type errors * Add frame level tests for syncing with app * Add test coverage for app logic * Simplify state management from app down * Fix import errors * Clarify whether properties are ids or titles for index pattern * pass new saved object by ref * add dirty state checking * Fix tests * [Lens] Add some tests around document handling in dimension panel (#42670) * [Lens] Terms operation boolean support (#42817) * [lens] Minor UX/UI improvements in Lens (#42852) * Make dimension popover toggle when clicking button * Without suggestions hide suggestion panel * Add missing translations (#42921) * [Lens] Config panel design (#42980) * Fix up design of config panel Does not include config popover * Remove a couple of non-null assertions (#43013) * Remove a couple of non-null assertions * Remove orphaned import * [Lens] Switch indexpattern manually (#42599) * [Lens] Update frame to put suggestions at the bottom (#42997) * fix type errors * switch indexpattern on layer if there is only a single empty one (#43079) * [Lens] Suggest reduced versions of current data table (#42537) * [Lens] Field formatter support (#38874) * Fix bugs * [Lens] Add bucket nesting editor to indexpattern (#42869) * [Lens] Remove unnecessary fields and indexing from mappings (#43285) * [Lens] Xy scale type (#42142) * [lens] Allow updater function to be used for updating state (#43373) * [Lens] Lens metric visualization (#39364) * Fix axis rotation (#43792) * [Lens] Auto date histogram (#43775) * Add auto date histogram * Improve documentation and cleanup * Add tests * Change test name * [Lens] Fix query bar integration (#43865) * [Lens] Clean up operations code (#43784) * [Lens] Functional tests (#44279) Foundational layer for lens functional tests. Lens-specific page objects are not in this PR. * [Lens] Add Lens visualizations to Visualize list (#43398) * [Lens] Suggestion improvements (#43688) * [lens] Calculate existence of fields in datasource (#44422) * [lens] Calculate existence of fields in datasource * Fix route registration * Add page object and use existence in functional test * Simplify layout of filters for index pattern * Respond to review feedback * Update class names * Use new URL constant * Fix usage of base path * Fix lint errors * [Lens ] Preview metric (#43755) * format filter ratio as percentage (#44625) * [Lens] Remove datasource suggestion id (#44495) * [Lens] Make breadcrumbs look and feel like Visualize (#44258) * [lens] Fix breakage from app-arch movements (#44720) * [lens] Fix type error in test from merge * [lens] Fix registration of embeddable (#45171) * [Lens] Functional tests (#44814) Basic functional tests for Lens, by no means comprehensive. This is more of a smokescreen test of some normal use cases. * [lens] Add Lens to CODEOWNERS (#45296) * [lens] Fix visualization alias registration * [lens] Fix usage of EUI after typescript upgrade (#45404) * [lens] Fix usage of EUI after typescript upgrade * Use local fix instead of workaround * [lens] Fix usage of expressions plugin (#45544) * [lens] Fix usage of expressions plugin * Use updated exports from #45538 * Fix imports and mocha tests * Use relative instead of absolute path to fix tests * [lens] More cleanup from QueryBar changes in master (#45687) * [lens] Fix build and use new platform from entry points (#45834) * [lens] Fix build and use new platform from entry points * Fix params for existence route
2019-09-17 20:57:53 +02:00
/*
* 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, { FormEvent } from 'react';
import { ReactWrapper } from 'enzyme';
import { mountWithIntl as mount } from 'test_utils/enzyme_helpers';
import { EuiButtonGroupProps } from '@elastic/eui';
import { XYConfigPanel } from './xy_config_panel';
import { DatasourceDimensionPanelProps, Operation, FramePublicAPI } from '../types';
import { State, XYState } from './types';
import { Position } from '@elastic/charts';
import { NativeRendererProps } from '../native_renderer';
import { generateId } from '../id_generator';
import { createMockFramePublicAPI, createMockDatasource } from '../editor_frame_plugin/mocks';
import { act } from 'react-test-renderer';
jest.mock('../id_generator');
describe('XYConfigPanel', () => {
const dragDropContext = { dragging: undefined, setDragging: jest.fn() };
let frame: FramePublicAPI;
function testState(): State {
return {
legend: { isVisible: true, position: Position.Right },
preferredSeriesType: 'bar',
isHorizontal: false,
layers: [
{
seriesType: 'bar',
layerId: 'first',
splitAccessor: 'baz',
xAccessor: 'foo',
accessors: ['bar'],
},
],
};
}
function testSubj(component: ReactWrapper<unknown>, subj: string) {
return component
.find(`[data-test-subj="${subj}"]`)
.first()
.props();
}
function openComponentPopover(component: ReactWrapper<unknown>, layerId: string) {
component
.find(`[data-test-subj="lnsXY_layer_${layerId}"]`)
.first()
.find(`[data-test-subj="lnsXY_layer_advanced"]`)
.first()
.simulate('click');
}
beforeEach(() => {
frame = createMockFramePublicAPI();
frame.datasourceLayers = {
first: createMockDatasource().publicAPIMock,
};
});
test.skip('toggles axis position when going from horizontal bar to any other type', () => {});
test.skip('allows toggling of legend visibility', () => {});
test.skip('allows changing legend position', () => {});
test.skip('allows toggling the y axis gridlines', () => {});
test.skip('allows toggling the x axis gridlines', () => {});
test('puts the horizontal toggle in a popover', () => {
const state = testState();
const setState = jest.fn();
const component = mount(
<XYConfigPanel
dragDropContext={dragDropContext}
frame={frame}
setState={setState}
state={state}
/>
);
component
.find(`[data-test-subj="lnsXY_chart_settings"]`)
.first()
.simulate('click');
act(() => {
component
.find('[data-test-subj="lnsXY_chart_horizontal"]')
.first()
.prop('onChange')!({} as FormEvent);
});
expect(setState).toHaveBeenCalledWith({
...state,
isHorizontal: true,
});
});
test('enables stacked chart types even when there is no split series', () => {
const state = testState();
const component = mount(
<XYConfigPanel
dragDropContext={dragDropContext}
frame={frame}
setState={jest.fn()}
state={{ ...state, layers: [{ ...state.layers[0], xAccessor: 'shazm' }] }}
/>
);
openComponentPopover(component, 'first');
const options = component
.find('[data-test-subj="lnsXY_seriesType"]')
.first()
.prop('options') as EuiButtonGroupProps['options'];
expect(options!.map(({ id }) => id)).toEqual([
'bar',
'bar_stacked',
'line',
'area',
'area_stacked',
]);
expect(options!.filter(({ isDisabled }) => isDisabled).map(({ id }) => id)).toEqual([]);
});
test('the x dimension panel accepts only bucketed operations', () => {
// TODO: this should eventually also accept raw operation
const state = testState();
const component = mount(
<XYConfigPanel
dragDropContext={dragDropContext}
frame={frame}
setState={jest.fn()}
state={{ ...state, layers: [{ ...state.layers[0], xAccessor: 'shazm' }] }}
/>
);
const panel = testSubj(component, 'lnsXY_xDimensionPanel');
const nativeProps = (panel as NativeRendererProps<DatasourceDimensionPanelProps>).nativeProps;
const { columnId, filterOperations } = nativeProps;
const exampleOperation: Operation = {
dataType: 'number',
isBucketed: false,
label: 'bar',
};
const bucketedOps: Operation[] = [
{ ...exampleOperation, isBucketed: true, dataType: 'number' },
{ ...exampleOperation, isBucketed: true, dataType: 'string' },
{ ...exampleOperation, isBucketed: true, dataType: 'boolean' },
{ ...exampleOperation, isBucketed: true, dataType: 'date' },
];
const ops: Operation[] = [
...bucketedOps,
{ ...exampleOperation, dataType: 'number' },
{ ...exampleOperation, dataType: 'string' },
{ ...exampleOperation, dataType: 'boolean' },
{ ...exampleOperation, dataType: 'date' },
];
expect(columnId).toEqual('shazm');
expect(ops.filter(filterOperations)).toEqual(bucketedOps);
});
test('the y dimension panel accepts numeric operations', () => {
const state = testState();
const component = mount(
<XYConfigPanel
dragDropContext={dragDropContext}
frame={frame}
setState={jest.fn()}
state={{ ...state, layers: [{ ...state.layers[0], accessors: ['a', 'b', 'c'] }] }}
/>
);
const filterOperations = component
.find('[data-test-subj="lensXY_yDimensionPanel"]')
.first()
.prop('filterOperations') as (op: Operation) => boolean;
const exampleOperation: Operation = {
dataType: 'number',
isBucketed: false,
label: 'bar',
};
const ops: Operation[] = [
{ ...exampleOperation, dataType: 'number' },
{ ...exampleOperation, dataType: 'string' },
{ ...exampleOperation, dataType: 'boolean' },
{ ...exampleOperation, dataType: 'date' },
];
expect(ops.filter(filterOperations).map(x => x.dataType)).toEqual(['number']);
});
test('allows removal of y dimensions', () => {
const setState = jest.fn();
const state = testState();
const component = mount(
<XYConfigPanel
dragDropContext={dragDropContext}
frame={frame}
setState={setState}
state={{ ...state, layers: [{ ...state.layers[0], accessors: ['a', 'b', 'c'] }] }}
/>
);
openComponentPopover(component, 'first');
const onRemove = component
.find('[data-test-subj="lensXY_yDimensionPanel"]')
.first()
.prop('onRemove') as (accessor: string) => {};
onRemove('b');
expect(setState).toHaveBeenCalledTimes(1);
expect(setState.mock.calls[0][0]).toMatchObject({
layers: [
{
...state.layers[0],
accessors: ['a', 'c'],
},
],
});
});
test('allows adding a y axis dimension', () => {
(generateId as jest.Mock).mockReturnValueOnce('zed');
const setState = jest.fn();
const state = testState();
const component = mount(
<XYConfigPanel
dragDropContext={dragDropContext}
frame={frame}
setState={setState}
state={{ ...state, layers: [{ ...state.layers[0], accessors: ['a', 'b', 'c'] }] }}
/>
);
const onAdd = component
.find('[data-test-subj="lensXY_yDimensionPanel"]')
.first()
.prop('onAdd') as () => {};
onAdd();
expect(setState).toHaveBeenCalledTimes(1);
expect(setState.mock.calls[0][0]).toMatchObject({
layers: [
{
...state.layers[0],
accessors: ['a', 'b', 'c', 'zed'],
},
],
});
});
describe('layers', () => {
it('adds layers', () => {
frame.addNewLayer = jest.fn().mockReturnValue('newLayerId');
(generateId as jest.Mock).mockReturnValue('accessor');
const setState = jest.fn();
const state = testState();
const component = mount(
<XYConfigPanel
dragDropContext={dragDropContext}
frame={frame}
setState={setState}
state={state}
/>
);
component
.find('[data-test-subj="lnsXY_layer_add"]')
.first()
.simulate('click');
expect(frame.addNewLayer).toHaveBeenCalled();
expect(setState).toHaveBeenCalledTimes(1);
expect(generateId).toHaveBeenCalledTimes(4);
expect(setState.mock.calls[0][0]).toMatchObject({
layers: [
...state.layers,
expect.objectContaining({
layerId: 'newLayerId',
xAccessor: 'accessor',
accessors: ['accessor'],
splitAccessor: 'accessor',
}),
],
});
});
it('should use series type of existing layers if they all have the same', () => {
frame.addNewLayer = jest.fn().mockReturnValue('newLayerId');
frame.datasourceLayers.second = createMockDatasource().publicAPIMock;
(generateId as jest.Mock).mockReturnValue('accessor');
const setState = jest.fn();
const state: XYState = {
...testState(),
preferredSeriesType: 'bar',
layers: [
{
seriesType: 'line',
layerId: 'first',
splitAccessor: 'baz',
xAccessor: 'foo',
accessors: ['bar'],
},
{
seriesType: 'line',
layerId: 'second',
splitAccessor: 'baz',
xAccessor: 'foo',
accessors: ['bar'],
},
],
};
const component = mount(
<XYConfigPanel
dragDropContext={dragDropContext}
frame={frame}
setState={setState}
state={state}
/>
);
component
.find('[data-test-subj="lnsXY_layer_add"]')
.first()
.simulate('click');
expect(setState.mock.calls[0][0]).toMatchObject({
layers: [
...state.layers,
expect.objectContaining({
seriesType: 'line',
}),
],
});
});
it('should use preffered series type if there are already various different layers', () => {
frame.addNewLayer = jest.fn().mockReturnValue('newLayerId');
frame.datasourceLayers.second = createMockDatasource().publicAPIMock;
(generateId as jest.Mock).mockReturnValue('accessor');
const setState = jest.fn();
const state: XYState = {
...testState(),
preferredSeriesType: 'bar',
layers: [
{
seriesType: 'area',
layerId: 'first',
splitAccessor: 'baz',
xAccessor: 'foo',
accessors: ['bar'],
},
{
seriesType: 'line',
layerId: 'second',
splitAccessor: 'baz',
xAccessor: 'foo',
accessors: ['bar'],
},
],
};
const component = mount(
<XYConfigPanel
dragDropContext={dragDropContext}
frame={frame}
setState={setState}
state={state}
/>
);
component
.find('[data-test-subj="lnsXY_layer_add"]')
.first()
.simulate('click');
expect(setState.mock.calls[0][0]).toMatchObject({
layers: [
...state.layers,
expect.objectContaining({
seriesType: 'bar',
}),
],
});
});
it('removes layers', () => {
const setState = jest.fn();
const state = testState();
const component = mount(
<XYConfigPanel
dragDropContext={dragDropContext}
frame={frame}
setState={setState}
state={state}
/>
);
openComponentPopover(component, 'first');
component
.find('[data-test-subj="lnsXY_layer_remove"]')
.first()
.simulate('click');
expect(frame.removeLayers).toHaveBeenCalled();
expect(setState).toHaveBeenCalledTimes(1);
expect(setState.mock.calls[0][0]).toMatchObject({
layers: [],
});
});
});
});