Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Lens] Introduces new chart switcher #91844

Merged
merged 21 commits into from
Mar 2, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5fd3f23
:sparkles: First implementation completed
dej611 Feb 17, 2021
d28a394
:white_check_mark: fix unit tests
dej611 Feb 17, 2021
78b8218
:white_check_mark: Fix functional tests
dej611 Feb 18, 2021
b9b28aa
Merge remote-tracking branch 'upstream/master' into lens/new-chart-sw…
dej611 Feb 18, 2021
89bcb5d
:label: Fix type checks
dej611 Feb 18, 2021
5a8195e
:bulb: Add more explanation for the mock
dej611 Feb 19, 2021
0340e4e
:speech_balloon: Use full label for aria label
dej611 Feb 19, 2021
79a6731
:recycle: Refactored group labels
dej611 Feb 19, 2021
2cc0032
Merge remote-tracking branch 'upstream/master' into lens/new-chart-sw…
dej611 Feb 22, 2021
7abba6c
:lipstick: Adapt list height based on result size
dej611 Feb 22, 2021
0bd7e7c
:recycle: Write numbers as constants
dej611 Feb 22, 2021
0a060ea
:speech_balloon: Revisit vis labels as suggested
dej611 Feb 22, 2021
40f1d19
Merge branch 'master' into lens/new-chart-switcher
kibanamachine Feb 23, 2021
28035d8
:ok_hand: Integrated feedback
dej611 Feb 23, 2021
09b9ff2
:bug: Fix some more copy and failing tests
dej611 Feb 23, 2021
208cdfb
:bug: Fix i18n check
dej611 Feb 24, 2021
71ec4be
:label: Refactor type
dej611 Feb 24, 2021
41e21b0
Merge branch 'master' into lens/new-chart-switcher
kibanamachine Feb 25, 2021
dc262c3
Update x-pack/plugins/lens/public/xy_visualization/visualization.tsx
dej611 Mar 1, 2021
99d5be4
Merge branch 'master' into lens/new-chart-switcher
kibanamachine Mar 1, 2021
9986e6e
:bug: Fix unit test
dej611 Mar 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,18 @@ export interface DatatableVisualizationState {
sorting?: SortingState;
}

const visualizationLabel = i18n.translate('xpack.lens.datatable.label', {
defaultMessage: 'Table',
});

export const datatableVisualization: Visualization<DatatableVisualizationState> = {
id: 'lnsDatatable',

visualizationTypes: [
{
id: 'lnsDatatable',
icon: LensIconChartDatatable,
label: i18n.translate('xpack.lens.datatable.label', {
defaultMessage: 'Data table',
}),
label: visualizationLabel,
groupLabel: i18n.translate('xpack.lens.datatable.groupLabel', {
defaultMessage: 'Tabular and single value',
}),
Expand All @@ -71,9 +73,7 @@ export const datatableVisualization: Visualization<DatatableVisualizationState>
getDescription() {
return {
icon: LensIconChartDatatable,
label: i18n.translate('xpack.lens.datatable.label', {
defaultMessage: 'Data table',
}),
label: visualizationLabel,
};
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
import React, { ReactElement } from 'react';
import { ReactWrapper } from 'enzyme';

// Tests are not ran within the browser and the AutoSizer will always compute a 0x0 size space
// Tests are executed in a jsdom environment who does not have sizing methods,
// thus the AutoSizer will always compute a 0x0 size space
// Mock the AutoSizer inside EuiSelectable (Chart Switch) and return some dimensions > 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Could you leave more detailed info why we have to do this (that the Autosizer behaves in particular way here)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed with Marta- can you specifically say that Jest tests render using jsdom and jsdom does not implement any sizing methods

jest.mock('react-virtualized-auto-sizer', () => {
return function (props: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
createMockDatasource,
} from '../../mocks';

// Tests are not ran within the browser and the AutoSizer will always compute a 0x0 size space
// Tests are executed in a jsdom environment who does not have sizing methods,
// thus the AutoSizer will always compute a 0x0 size space
// Mock the AutoSizer inside EuiSelectable (Chart Switch) and return some dimensions > 0
jest.mock('react-virtualized-auto-sizer', () => {
return function (props: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
EuiFlexItem,
EuiSelectable,
EuiIconTip,
EuiSelectableOption,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
Expand Down Expand Up @@ -51,17 +52,7 @@ interface Props {
>;
}

interface SelectableEntry {
'aria-label'?: string;
checked?: 'on';
isGroupLabel: boolean;
key: string;
value?: string;
'data-test-subj'?: string;
label: string;
prepend?: React.ReactNode;
append?: React.ReactNode;
}
type SelectableEntry = EuiSelectableOption<{ value: string }>;

function VisualizationSummary(props: Props) {
const visualization = props.visualizationMap[props.visualizationId || ''];
Expand Down Expand Up @@ -98,6 +89,13 @@ function computeListHeight(list: SelectableEntry[], maxHeight: number): number {
return Math.min(list.length * ENTRY_HEIGHT, maxHeight);
}

function getCurrentVisualizationId(
activeVisualization: Visualization,
visualizationState: unknown
) {
return activeVisualization.getVisualizationTypeId(visualizationState);
}

export const ChartSwitch = memo(function ChartSwitch(props: Props) {
const [flyoutOpen, setFlyoutOpen] = useState<boolean>(false);

Expand Down Expand Up @@ -213,8 +211,8 @@ export const ChartSwitch = memo(function ChartSwitch(props: Props) {
if (!flyoutOpen) {
return { visualizationTypes: [], visualizationsLookup: {} };
}
const activeVisualization = props.visualizationMap[props.visualizationId || ''];
const subVisualizationId = activeVisualization.getVisualizationTypeId(
const subVisualizationId = getCurrentVisualizationId(
props.visualizationMap[props.visualizationId || ''],
props.visualizationState
);
const lowercasedSearchTerm = searchTerm.toLowerCase();
Expand Down Expand Up @@ -262,38 +260,53 @@ export const ChartSwitch = memo(function ChartSwitch(props: Props) {
if (visualizations.length === 0) {
return [];
}
return [{ key: group, label: group, isGroupLabel: true }].concat(
visualizations.map((v) => ({
'aria-label': v.fullLabel || v.label,
checked: subVisualizationId === v.id ? 'on' : null,
isGroupLabel: false,
key: `${v.visualizationId}:${v.id}`,
value: `${v.visualizationId}:${v.id}`,
'data-test-subj': `lnsChartSwitchPopover_${v.id}`,
label: v.fullLabel || v.label,
prepend: <EuiIcon className="lnsChartSwitch__chartIcon" type={v.icon || 'empty'} />,
append:
v.selection.dataLoss !== 'nothing' ? (
<EuiIconTip
aria-label={i18n.translate('xpack.lens.chartSwitch.dataLossLabel', {
defaultMessage: 'Data loss',
})}
type="alert"
color="warning"
title={i18n.translate('xpack.lens.chartSwitch.dataLossLabel', {
defaultMessage: 'Data loss',
})}
content={i18n.translate('xpack.lens.chartSwitch.dataLossDescription', {
defaultMessage:
'Switching to this chart will lose some of the configuration',
})}
iconProps={{
className: 'lnsChartSwitch__chartIcon',
'data-test-subj': `lnsChartSwitchPopoverAlert_${v.id}`,
}}
/>
) : null,
}))
return [
{
key: group,
label: group,
isGroupLabel: true,
'aria-label': group,
'data-test-subj': `lnsChartSwitchPopover_${group}`,
} as SelectableEntry,
].concat(
visualizations
// alphabetical order within each group
.sort((a, b) => {
return (a.fullLabel || a.label).localeCompare(b.fullLabel || b.label);
})
.map(
(v): SelectableEntry => ({
'aria-label': v.fullLabel || v.label,
isGroupLabel: false,
key: `${v.visualizationId}:${v.id}`,
value: `${v.visualizationId}:${v.id}`,
'data-test-subj': `lnsChartSwitchPopover_${v.id}`,
label: v.fullLabel || v.label,
prepend: (
<EuiIcon className="lnsChartSwitch__chartIcon" type={v.icon || 'empty'} />
),
append:
v.selection.dataLoss !== 'nothing' ? (
<EuiIconTip
aria-label={i18n.translate('xpack.lens.chartSwitch.dataLossLabel', {
defaultMessage: 'Warning',
})}
type="alert"
color="warning"
content={i18n.translate('xpack.lens.chartSwitch.dataLossDescription', {
defaultMessage:
'Selecting this chart type will result in a partial loss of currently applied configuration selections.',
})}
iconProps={{
className: 'lnsChartSwitch__chartIcon',
'data-test-subj': `lnsChartSwitchPopoverAlert_${v.id}`,
}}
/>
) : null,
// Apparently checked: null is not valid for TS
...(subVisualizationId === v.id && { checked: 'on' }),
})
)
);
}),
visualizationsLookup: lookup,
Expand Down Expand Up @@ -354,7 +367,11 @@ export const ChartSwitch = memo(function ChartSwitch(props: Props) {
}}
options={visualizationTypes}
onChange={(newOptions) => {
const id = newOptions.find(({ checked }) => checked === 'on')!.value!;
const chosenType = newOptions.find(({ checked }) => checked === 'on')!;
if (!chosenType) {
return;
}
const id = chosenType.value!;
commitSelection(visualizationsLookup[id].selection);
}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've had this bug before, but this appears to be a pretty big one. Lens crashes if you select the currently selected option.

noMatchesMessage={
Expand Down
10 changes: 5 additions & 5 deletions x-pack/plugins/lens/public/xy_visualization/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ export const visualizationTypes: VisualizationType[] = [
id: 'bar',
icon: LensIconChartBar,
label: i18n.translate('xpack.lens.xyVisualization.barLabel', {
defaultMessage: 'Bar',
defaultMessage: 'Bar vertical',
}),
groupLabel: groupLabelForBar,
},
Expand All @@ -463,15 +463,15 @@ export const visualizationTypes: VisualizationType[] = [
id: 'bar_stacked',
icon: LensIconChartBarStacked,
label: i18n.translate('xpack.lens.xyVisualization.stackedBarLabel', {
defaultMessage: 'Bar stacked',
defaultMessage: 'Bar vertical stacked',
}),
groupLabel: groupLabelForBar,
},
{
id: 'bar_percentage_stacked',
icon: LensIconChartBarPercentage,
label: i18n.translate('xpack.lens.xyVisualization.stackedPercentageBarLabel', {
defaultMessage: 'Bar percentage bar',
defaultMessage: 'Bar vertical percentage',
}),
groupLabel: groupLabelForBar,
},
Expand Down Expand Up @@ -512,15 +512,15 @@ export const visualizationTypes: VisualizationType[] = [
id: 'area_stacked',
icon: LensIconChartAreaStacked,
label: i18n.translate('xpack.lens.xyVisualization.stackedAreaLabel', {
defaultMessage: 'Stacked area',
defaultMessage: 'Area stacked',
}),
groupLabel: groupLabelForLineAndArea,
},
{
id: 'area_percentage_stacked',
icon: LensIconChartAreaPercentage,
label: i18n.translate('xpack.lens.xyVisualization.stackedPercentageAreaLabel', {
defaultMessage: 'Percentage area',
defaultMessage: 'Area percentage',
}),
groupLabel: groupLabelForLineAndArea,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,31 +62,31 @@ describe('xy_visualization', () => {
const desc = xyVisualization.getDescription(mixedState());

expect(desc.icon).toEqual(LensIconChartBar);
expect(desc.label).toEqual('Bar');
expect(desc.label).toEqual('Bar vertical');
});

it('should show mixed horizontal bar chart when multiple horizontal bar types', () => {
const desc = xyVisualization.getDescription(
mixedState('bar_horizontal', 'bar_horizontal_stacked')
);

expect(desc.label).toEqual('Mixed H. bar');
expect(desc.label).toEqual('Mixed Bar horizontal');
});

it('should show bar chart when bar only', () => {
const desc = xyVisualization.getDescription(mixedState('bar_horizontal', 'bar_horizontal'));

expect(desc.label).toEqual('H. Bar');
expect(desc.label).toEqual('Bar horizontal');
});

it('should show the chart description if not mixed', () => {
expect(xyVisualization.getDescription(mixedState('area')).label).toEqual('Area');
expect(xyVisualization.getDescription(mixedState('line')).label).toEqual('Line');
expect(xyVisualization.getDescription(mixedState('area_stacked')).label).toEqual(
'Stacked area'
'Area stacked'
);
expect(xyVisualization.getDescription(mixedState('bar_horizontal_stacked')).label).toEqual(
'H. Stacked bar'
'Bar horizontal stacked'
);
});
});
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/lens/public/xy_visualization/visualization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function getDescription(state?: State) {
return {
icon: LensIconChartBarHorizontal,
label: i18n.translate('xpack.lens.xyVisualization.mixedBarHorizontalLabel', {
defaultMessage: 'Mixed H. bar',
defaultMessage: 'Mixed Bar horizontal',
dej611 marked this conversation as resolved.
Show resolved Hide resolved
}),
};
}
Expand All @@ -74,7 +74,7 @@ function getDescription(state?: State) {

return {
icon: visualizationType.icon,
label: visualizationType.label,
label: visualizationType.fullLabel || visualizationType.label,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ describe('xy_suggestions', () => {
});

expect(rest).toHaveLength(visualizationTypes.length - 1);
expect(suggestion.title).toEqual('Stacked bar');
expect(suggestion.title).toEqual('Bar vertical stacked');
expect(suggestion.state).toEqual(
expect.objectContaining({
layers: [
Expand Down