Skip to content

Commit

Permalink
[Lens] Fix crash when two layers xychart switches to pie (#75267)
Browse files Browse the repository at this point in the history
* [Lens] fix crash on two layers and add a functional test with two layers switching to pie chart
  • Loading branch information
mbondyra authored Aug 18, 2020
1 parent ce8a92e commit e04e05a
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,12 @@ function LayerPanels(

return (
<EuiForm className="lnsConfigPanel">
{layerIds.map((layerId) => (
{layerIds.map((layerId, index) => (
<LayerPanel
{...props}
key={layerId}
layerId={layerId}
dataTestSubj={`lns-layerPanel-${index}`}
visualizationState={visualizationState}
updateVisualization={setVisualizationState}
updateDatasource={updateDatasource}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ describe('LayerPanel', () => {
onRemoveLayer: jest.fn(),
dispatch: jest.fn(),
core: coreMock.createStart(),
dataTestSubj: 'lns_layerPanel-0',
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const initialPopoverState = {
export function LayerPanel(
props: Exclude<ConfigPanelWrapperProps, 'state' | 'setState'> & {
layerId: string;
dataTestSubj: string;
isOnlyLayer: boolean;
updateVisualization: StateSetter<unknown>;
updateDatasource: (datasourceId: string, newState: unknown) => void;
Expand All @@ -50,7 +51,7 @@ export function LayerPanel(
const dragDropContext = useContext(DragContext);
const [popoverState, setPopoverState] = useState<DimensionPopoverState>(initialPopoverState);

const { framePublicAPI, layerId, isOnlyLayer, onRemoveLayer } = props;
const { framePublicAPI, layerId, isOnlyLayer, onRemoveLayer, dataTestSubj } = props;
const datasourcePublicAPI = framePublicAPI.datasourceLayers[layerId];

useEffect(() => {
Expand Down Expand Up @@ -96,7 +97,7 @@ export function LayerPanel(

return (
<ChildDragDropProvider {...dragDropContext}>
<EuiPanel className="lnsLayerPanel" paddingSize="s">
<EuiPanel data-test-subj={dataTestSubj} className="lnsLayerPanel" paddingSize="s">
<EuiFlexGroup gutterSize="s" alignItems="flexStart" responsive={false}>
<EuiFlexItem grow={false}>
<LayerSettings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import _ from 'lodash';
import _, { camelCase } from 'lodash';
import React, { useState, useEffect, useMemo } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import {
Expand Down Expand Up @@ -122,30 +122,32 @@ const SuggestionPreview = ({
}) => {
return (
<EuiToolTip content={preview.title}>
<EuiPanelFixed
className={classNames('lnsSuggestionPanel__button', {
// eslint-disable-next-line @typescript-eslint/naming-convention
'lnsSuggestionPanel__button-isSelected': selected,
})}
paddingSize="none"
data-test-subj="lnsSuggestion"
onClick={onSelect}
>
{preview.expression ? (
<DebouncedPreviewRenderer
ExpressionRendererComponent={ExpressionRendererComponent}
expression={toExpression(preview.expression)}
withLabel={Boolean(showTitleAsLabel)}
/>
) : (
<span className="lnsSuggestionPanel__suggestionIcon">
<EuiIcon size="xxl" type={preview.icon} />
</span>
)}
{showTitleAsLabel && (
<span className="lnsSuggestionPanel__buttonLabel">{preview.title}</span>
)}
</EuiPanelFixed>
<div data-test-subj={`lnsSuggestion-${camelCase(preview.title)}`}>
<EuiPanelFixed
className={classNames('lnsSuggestionPanel__button', {
// eslint-disable-next-line @typescript-eslint/naming-convention
'lnsSuggestionPanel__button-isSelected': selected,
})}
paddingSize="none"
data-test-subj="lnsSuggestion"
onClick={onSelect}
>
{preview.expression ? (
<DebouncedPreviewRenderer
ExpressionRendererComponent={ExpressionRendererComponent}
expression={toExpression(preview.expression)}
withLabel={Boolean(showTitleAsLabel)}
/>
) : (
<span className="lnsSuggestionPanel__suggestionIcon">
<EuiIcon size="xxl" type={preview.icon} />
</span>
)}
{showTitleAsLabel && (
<span className="lnsSuggestionPanel__buttonLabel">{preview.title}</span>
)}
</EuiPanelFixed>
</div>
</EuiToolTip>
);
};
Expand Down Expand Up @@ -204,8 +206,8 @@ export function SuggestionPanel({
: undefined;

return { suggestions: newSuggestions, currentStateExpression: newStateExpression };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
frame,
currentDatasourceStates,
currentVisualizationState,
currentVisualizationId,
Expand Down
49 changes: 49 additions & 0 deletions x-pack/test/functional/apps/lens/smokescreen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['visualize', 'lens']);
const find = getService('find');
const listingTable = getService('listingTable');
const testSubjects = getService('testSubjects');

describe('lens smokescreen tests', () => {
it('should allow editing saved visualizations', async () => {
Expand Down Expand Up @@ -109,6 +110,54 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
expect(await PageObjects.lens.getLayerCount()).to.eql(2);
});

it('should switch from a multi-layer stacked bar to donut chart using suggestions', async () => {
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickVisType('lens');
await PageObjects.lens.goToTimeRange();

await PageObjects.lens.configureDimension({
dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension',
operation: 'terms',
field: 'geo.dest',
});

await PageObjects.lens.configureDimension({
dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension',
operation: 'avg',
field: 'bytes',
});

await PageObjects.lens.createLayer();

await PageObjects.lens.configureDimension(
{
dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension',
operation: 'terms',
field: 'geo.src',
},
1
);

await PageObjects.lens.configureDimension(
{
dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension',
operation: 'avg',
field: 'bytes',
},
1
);
await PageObjects.lens.save('twolayerchart');
await testSubjects.click('lnsSuggestion-asDonut > lnsSuggestion');

expect(await PageObjects.lens.getLayerCount()).to.eql(1);
expect(await PageObjects.lens.getDimensionTriggerText('lnsPie_sliceByDimensionPanel')).to.eql(
'Top values of geo.dest'
);
expect(await PageObjects.lens.getDimensionTriggerText('lnsPie_sizeByDimensionPanel')).to.eql(
'Average of bytes'
);
});

it('should allow transition from line chart to donut chart and to bar chart', async () => {
await PageObjects.visualize.gotoVisualizationLandingPage();
await listingTable.searchForItemWithName('lnsXYvis');
Expand Down
8 changes: 6 additions & 2 deletions x-pack/test/functional/page_objects/lens_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,14 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont
* @param opts.dimension - the selector of the dimension being changed
* @param opts.operation - the desired operation ID for the dimension
* @param opts.field - the desired field for the dimension
* @param layerIndex - the index of the layer
*/
async configureDimension(opts: { dimension: string; operation: string; field: string }) {
async configureDimension(
opts: { dimension: string; operation: string; field: string },
layerIndex = 0
) {
await retry.try(async () => {
await testSubjects.click(opts.dimension);
await testSubjects.click(`lns-layerPanel-${layerIndex} > ${opts.dimension}`);
await testSubjects.exists(`lns-indexPatternDimension-${opts.operation}`);
});

Expand Down

0 comments on commit e04e05a

Please sign in to comment.