Skip to content

Commit

Permalink
[Lens] Add value labels to Heatmap (elastic#106406)
Browse files Browse the repository at this point in the history
* ✨ Add label values menu

* ✨ Enable value labels for Heatmap

* 🔥 Remove removed translations

* 🏷️ Fix type issue

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
dej611 and kibanamachine authored Oct 25, 2021
1 parent 560cb6f commit cf2a3f5
Show file tree
Hide file tree
Showing 16 changed files with 171 additions and 138 deletions.
3 changes: 1 addition & 2 deletions x-pack/plugins/lens/common/expressions/xy_chart/xy_args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import type { LayerArgs } from './layer_config';
import type { LegendConfigResult } from './legend_config';
import type { TickLabelsConfigResult } from './tick_labels_config';
import type { LabelsOrientationConfigResult } from './labels_orientation_config';

export type ValueLabelConfig = 'hide' | 'inside' | 'outside';
import type { ValueLabelConfig } from '../../types';

export type XYCurveType = 'LINEAR' | 'CURVE_MONOTONE_X';

Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/lens/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,6 @@ export interface CustomPaletteParams {
export type RequiredPaletteParamTypes = Required<CustomPaletteParams>;

export type LayerType = 'data' | 'referenceLine';

// Shared by XY Chart and Heatmap as for now
export type ValueLabelConfig = 'hide' | 'inside' | 'outside';
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,9 @@ export const HeatmapComponent: FC<HeatmapRenderProps> = ({
maxHeight: 'fill',
label: {
visible: args.gridConfig.isCellLabelVisible ?? false,
minFontSize: 8,
maxFontSize: 18,
useGlobalMinFontSize: true, // override the min if there's a different directive upstream
},
border: {
strokeWidth: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { Position } from '@elastic/charts';
import { i18n } from '@kbn/i18n';
import type { VisualizationToolbarProps } from '../types';
import { LegendSettingsPopover } from '../shared_components';
import { LegendSettingsPopover, ToolbarPopover, ValueLabelsSettings } from '../shared_components';
import type { HeatmapVisualizationState } from './types';

const legendOptions: Array<{ id: string; value: 'auto' | 'show' | 'hide'; label: string }> = [
Expand All @@ -37,11 +37,29 @@ export const HeatmapToolbar = memo(
const legendMode = state.legend.isVisible ? 'show' : 'hide';

return (
<EuiFlexGroup gutterSize="m" justifyContent="spaceBetween">
<EuiFlexGroup gutterSize="m" justifyContent="spaceBetween" responsive={false}>
<EuiFlexItem>
<EuiFlexGroup gutterSize="none" responsive={false}>
<ToolbarPopover
title={i18n.translate('xpack.lens.shared.curveLabel', {
defaultMessage: 'Visual options',
})}
type="visualOptions"
groupPosition="left"
buttonDataTestSubj="lnsVisualOptionsButton"
>
<ValueLabelsSettings
valueLabels={state?.gridConfig.isCellLabelVisible ? 'inside' : 'hide'}
onValueLabelChange={(newMode) => {
setState({
...state,
gridConfig: { ...state.gridConfig, isCellLabelVisible: newMode === 'inside' },
});
}}
/>
</ToolbarPopover>
<LegendSettingsPopover
groupPosition={'none'}
groupPosition={'right'}
legendOptions={legendOptions}
mode={legendMode}
onDisplayChange={(optionId) => {
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/lens/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ export type {
XYLayerConfig,
LegendConfig,
SeriesType,
ValueLabelConfig,
YAxisMode,
XYCurveType,
YConfig,
} from '../common/expressions';
export type { ValueLabelConfig } from '../common/types';
export type { DatatableVisualizationState } from './datatable_visualization/visualization';
export type {
IndexPatternPersistedState,
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/lens/public/shared_components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ export * from './coloring';
export { useDebouncedValue } from './debounced_value';
export * from './helpers';
export { LegendActionPopover } from './legend_action_popover';
export { ValueLabelsSettings } from './value_labels_settings';
export * from './static_header';
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 from 'react';
import { shallowWithIntl as shallow } from '@kbn/test/jest';
import { ValueLabelsSettings, VisualOptionsProps } from './value_labels_settings';

describe('Value labels Settings', () => {
let props: VisualOptionsProps;
beforeEach(() => {
props = {
onValueLabelChange: jest.fn(),
};
});

it('should not render the component if not enabled', () => {
const component = shallow(<ValueLabelsSettings {...props} isVisible={false} />);
expect(component.find('[data-test-subj="lens-value-labels-visibility-btn"]').length).toEqual(0);
});

it('should set hide as default value', () => {
const component = shallow(<ValueLabelsSettings {...props} />);
expect(
component.find('[data-test-subj="lens-value-labels-visibility-btn"]').prop('idSelected')
).toEqual(`value_labels_hide`);
});

it('should have called onValueLabelChange function on ButtonGroup change', () => {
const component = shallow(<ValueLabelsSettings {...props} />);
component
.find('[data-test-subj="lens-value-labels-visibility-btn"]')
.simulate('change', 'value_labels_inside');
expect(props.onValueLabelChange).toHaveBeenCalled();
});

it('should render the passed value if given', () => {
const component = shallow(<ValueLabelsSettings {...props} valueLabels="inside" />);
expect(
component.find('[data-test-subj="lens-value-labels-visibility-btn"]').prop('idSelected')
).toEqual(`value_labels_inside`);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* 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, { FC } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiButtonGroup, EuiFormRow } from '@elastic/eui';
import { ValueLabelConfig } from '../../common/types';

const valueLabelsOptions: Array<{
id: string;
value: ValueLabelConfig;
label: string;
'data-test-subj': string;
}> = [
{
id: `value_labels_hide`,
value: 'hide',
label: i18n.translate('xpack.lens.shared.valueLabelsVisibility.auto', {
defaultMessage: 'Hide',
}),
'data-test-subj': 'lns_valueLabels_hide',
},
{
id: `value_labels_inside`,
value: 'inside',
label: i18n.translate('xpack.lens.shared.valueLabelsVisibility.inside', {
defaultMessage: 'Show',
}),
'data-test-subj': 'lns_valueLabels_inside',
},
];

export interface VisualOptionsProps {
isVisible?: boolean;
valueLabels?: ValueLabelConfig;
onValueLabelChange: (newMode: ValueLabelConfig) => void;
}

export const ValueLabelsSettings: FC<VisualOptionsProps> = ({
isVisible = true,
valueLabels = 'hide',
onValueLabelChange,
}) => {
if (!isVisible) {
return null;
}
const label = i18n.translate('xpack.lens.shared.chartValueLabelVisibilityLabel', {
defaultMessage: 'Labels',
});
const isSelected =
valueLabelsOptions.find(({ value }) => value === valueLabels)?.id || 'value_labels_hide';
return (
<EuiFormRow display="columnCompressed" label={<span>{label}</span>}>
<EuiButtonGroup
isFullWidth
legend={label}
data-test-subj="lens-value-labels-visibility-btn"
name="valueLabelsDisplay"
buttonSize="compressed"
options={valueLabelsOptions}
idSelected={isSelected}
onChange={(modeId) => {
const newMode = valueLabelsOptions.find(({ id }) => id === modeId);
if (newMode) {
onValueLabelChange(newMode.value);
}
}}
/>
</EuiFormRow>
);
};
2 changes: 1 addition & 1 deletion x-pack/plugins/lens/public/xy_visualization/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { LensIconChartLine } from '../assets/chart_line';
import type { VisualizationType } from '../types';
import type {
SeriesType,
ValueLabelConfig,
LegendConfig,
AxisExtentConfig,
XYLayerConfig,
Expand All @@ -29,6 +28,7 @@ import type {
FittingFunction,
LabelsOrientationConfig,
} from '../../common/expressions';
import type { ValueLabelConfig } from '../../common/types';

// Persisted parts of the state
export interface XYState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import React from 'react';
import { i18n } from '@kbn/i18n';
import { ToolbarPopover, TooltipWrapper } from '../../../shared_components';
import { ToolbarPopover, TooltipWrapper, ValueLabelsSettings } from '../../../shared_components';
import { MissingValuesOptions } from './missing_values_option';
import { LineCurveOption } from './line_curve_option';
import { FillOpacityOption } from './fill_opacity_option';
Expand Down Expand Up @@ -102,14 +102,17 @@ export const VisualOptionsPopover: React.FC<VisualOptionsPopoverProps> = ({
}}
/>

<MissingValuesOptions
isValueLabelsEnabled={isValueLabelsEnabled}
isFittingEnabled={isFittingEnabled}
valueLabels={state?.valueLabels}
fittingFunction={state?.fittingFunction}
<ValueLabelsSettings
isVisible={isValueLabelsEnabled}
valueLabels={state?.valueLabels ?? 'hide'}
onValueLabelChange={(newMode) => {
setState({ ...state, valueLabels: newMode });
}}
/>

<MissingValuesOptions
isFittingEnabled={isFittingEnabled}
fittingFunction={state?.fittingFunction}
onFittingFnChange={(newVal) => {
setState({ ...state, fittingFunction: newVal });
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,70 +7,23 @@

import React from 'react';
import { shallowWithIntl as shallow, mountWithIntl as mount } from '@kbn/test/jest';
import { EuiSuperSelect, EuiButtonGroup } from '@elastic/eui';
import { EuiSuperSelect } from '@elastic/eui';
import { MissingValuesOptions } from './missing_values_option';

describe('Missing values option', () => {
it('should show currently selected fitting function', () => {
const component = shallow(
<MissingValuesOptions
onFittingFnChange={jest.fn()}
onValueLabelChange={jest.fn()}
fittingFunction={'Carry'}
valueLabels={'hide'}
/>
<MissingValuesOptions onFittingFnChange={jest.fn()} fittingFunction={'Carry'} />
);

expect(component.find(EuiSuperSelect).prop('valueOfSelected')).toEqual('Carry');
});

it('should show currently selected value labels display setting', () => {
const component = mount(
<MissingValuesOptions
onFittingFnChange={jest.fn()}
onValueLabelChange={jest.fn()}
fittingFunction={'Carry'}
valueLabels={'inside'}
/>
);

expect(component.find(EuiButtonGroup).prop('idSelected')).toEqual('value_labels_inside');
});

it('should show display field when enabled', () => {
const component = mount(
<MissingValuesOptions
onFittingFnChange={jest.fn()}
onValueLabelChange={jest.fn()}
fittingFunction={'Carry'}
valueLabels={'inside'}
/>
);

expect(component.exists('[data-test-subj="lnsValueLabelsDisplay"]')).toEqual(true);
});

it('should hide in display value label option when disabled', () => {
const component = mount(
<MissingValuesOptions
onFittingFnChange={jest.fn()}
onValueLabelChange={jest.fn()}
fittingFunction={'Carry'}
valueLabels={'inside'}
isValueLabelsEnabled={false}
/>
);

expect(component.exists('[data-test-subj="lnsValueLabelsDisplay"]')).toEqual(false);
});

it('should show the fitting option when enabled', () => {
const component = mount(
<MissingValuesOptions
onFittingFnChange={jest.fn()}
onValueLabelChange={jest.fn()}
fittingFunction={'Carry'}
valueLabels={'inside'}
isFittingEnabled={true}
/>
);
Expand All @@ -82,9 +35,7 @@ describe('Missing values option', () => {
const component = mount(
<MissingValuesOptions
onFittingFnChange={jest.fn()}
onValueLabelChange={jest.fn()}
fittingFunction={'Carry'}
valueLabels={'inside'}
isFittingEnabled={false}
/>
);
Expand Down
Loading

0 comments on commit cf2a3f5

Please sign in to comment.