[TSVB] Long legend values support (#108023)
* [TSVB] Supports legends with long values * Add a unit test * Design optimization * Revert changes * Add the missing prop type * Ensure that the limits are respected Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
544c41e214
commit
fe08d0aa21
|
@ -161,6 +161,8 @@ export interface Panel {
|
|||
series: Series[];
|
||||
show_grid: number;
|
||||
show_legend: number;
|
||||
truncate_legend?: number;
|
||||
max_lines_legend?: number;
|
||||
time_field?: string;
|
||||
time_range_mode?: string;
|
||||
tooltip_mode?: TOOLTIP_MODES;
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { shallowWithIntl as shallow } from '@kbn/test/jest';
|
||||
|
||||
jest.mock('../lib/get_default_query_language', () => ({
|
||||
getDefaultQueryLanguage: () => 'kuery',
|
||||
}));
|
||||
|
||||
import { TimeseriesPanelConfig } from './timeseries';
|
||||
import { PanelConfigProps } from './types';
|
||||
|
||||
describe('TimeseriesPanelConfig', () => {
|
||||
it('sets the number input to the given value', () => {
|
||||
const props = ({
|
||||
fields: {},
|
||||
model: {
|
||||
max_lines_legend: 2,
|
||||
},
|
||||
onChange: jest.fn(),
|
||||
} as unknown) as PanelConfigProps;
|
||||
const wrapper = shallow(<TimeseriesPanelConfig {...props} />);
|
||||
wrapper.instance().setState({ selectedTab: 'options' });
|
||||
expect(
|
||||
wrapper.find('[data-test-subj="timeSeriesEditorDataMaxLegendLines"]').prop('value')
|
||||
).toEqual(2);
|
||||
});
|
||||
|
||||
it('switches on the truncate legend switch if the prop is set to 1 ', () => {
|
||||
const props = ({
|
||||
fields: {},
|
||||
model: {
|
||||
max_lines_legend: 2,
|
||||
truncate_legend: 1,
|
||||
},
|
||||
onChange: jest.fn(),
|
||||
} as unknown) as PanelConfigProps;
|
||||
const wrapper = shallow(<TimeseriesPanelConfig {...props} />);
|
||||
wrapper.instance().setState({ selectedTab: 'options' });
|
||||
expect(
|
||||
wrapper.find('[data-test-subj="timeSeriesEditorDataTruncateLegendSwitch"]').prop('value')
|
||||
).toEqual(1);
|
||||
});
|
||||
|
||||
it('switches off the truncate legend switch if the prop is set to 0', () => {
|
||||
const props = ({
|
||||
fields: {},
|
||||
model: {
|
||||
max_lines_legend: 2,
|
||||
truncate_legend: 0,
|
||||
},
|
||||
onChange: jest.fn(),
|
||||
} as unknown) as PanelConfigProps;
|
||||
const wrapper = shallow(<TimeseriesPanelConfig {...props} />);
|
||||
wrapper.instance().setState({ selectedTab: 'options' });
|
||||
expect(
|
||||
wrapper.find('[data-test-subj="timeSeriesEditorDataTruncateLegendSwitch"]').prop('value')
|
||||
).toEqual(0);
|
||||
});
|
||||
|
||||
it('disables the max lines number input if the truncate legend switch is off', () => {
|
||||
const props = ({
|
||||
fields: {},
|
||||
model: {
|
||||
max_lines_legend: 2,
|
||||
truncate_legend: 0,
|
||||
},
|
||||
onChange: jest.fn(),
|
||||
} as unknown) as PanelConfigProps;
|
||||
const wrapper = shallow(<TimeseriesPanelConfig {...props} />);
|
||||
wrapper.instance().setState({ selectedTab: 'options' });
|
||||
expect(
|
||||
wrapper.find('[data-test-subj="timeSeriesEditorDataMaxLegendLines"]').prop('disabled')
|
||||
).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -23,6 +23,7 @@ import {
|
|||
EuiFieldText,
|
||||
EuiTitle,
|
||||
EuiHorizontalRule,
|
||||
EuiFieldNumber,
|
||||
} from '@elastic/eui';
|
||||
|
||||
// @ts-expect-error not typed yet
|
||||
|
@ -102,6 +103,9 @@ const legendPositionOptions = [
|
|||
},
|
||||
];
|
||||
|
||||
const MAX_TRUNCATE_LINES = 5;
|
||||
const MIN_TRUNCATE_LINES = 1;
|
||||
|
||||
export class TimeseriesPanelConfig extends Component<
|
||||
PanelConfigProps,
|
||||
{ selectedTab: PANEL_CONFIG_TABS }
|
||||
|
@ -344,7 +348,7 @@ export class TimeseriesPanelConfig extends Component<
|
|||
/>
|
||||
</EuiFormLabel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<ColorPicker
|
||||
onChange={this.props.onChange}
|
||||
name="background_color"
|
||||
|
@ -352,47 +356,15 @@ export class TimeseriesPanelConfig extends Component<
|
|||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('visTypeTimeseries.timeseries.optionsTab.showLegendLabel', {
|
||||
defaultMessage: 'Show legend?',
|
||||
})}
|
||||
>
|
||||
<YesNo
|
||||
value={model.show_legend}
|
||||
name="show_legend"
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormLabel htmlFor={htmlId('legendPos')}>
|
||||
<EuiFormLabel>
|
||||
<FormattedMessage
|
||||
id="visTypeTimeseries.timeseries.optionsTab.legendPositionLabel"
|
||||
defaultMessage="Legend position"
|
||||
id="visTypeTimeseries.timeseries.optionsTab.displayGridLabel"
|
||||
defaultMessage="Display grid"
|
||||
/>
|
||||
</EuiFormLabel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiComboBox
|
||||
isClearable={false}
|
||||
id={htmlId('legendPos')}
|
||||
options={legendPositionOptions}
|
||||
selectedOptions={selectedLegendPosOption ? [selectedLegendPosOption] : []}
|
||||
onChange={handleSelectChange('legend_position')}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormRow
|
||||
label={i18n.translate(
|
||||
'visTypeTimeseries.timeseries.optionsTab.displayGridLabel',
|
||||
{
|
||||
defaultMessage: 'Display grid',
|
||||
}
|
||||
)}
|
||||
>
|
||||
<YesNo value={model.show_grid} name="show_grid" onChange={this.props.onChange} />
|
||||
</EuiFormRow>
|
||||
<YesNo value={model.show_grid} name="show_grid" onChange={this.props.onChange} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormLabel>
|
||||
|
@ -402,7 +374,7 @@ export class TimeseriesPanelConfig extends Component<
|
|||
/>
|
||||
</EuiFormLabel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiComboBox
|
||||
isClearable={false}
|
||||
id={htmlId('tooltipMode')}
|
||||
|
@ -413,6 +385,84 @@ export class TimeseriesPanelConfig extends Component<
|
|||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiFlexGroup responsive={false} wrap={true} alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormLabel>
|
||||
<FormattedMessage
|
||||
id="visTypeTimeseries.timeseries.optionsTab.showLegendLabel"
|
||||
defaultMessage="Show legend?"
|
||||
/>
|
||||
</EuiFormLabel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<YesNo
|
||||
value={model.show_legend}
|
||||
name="show_legend"
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormLabel>
|
||||
<FormattedMessage
|
||||
id="visTypeTimeseries.timeseries.optionsTab.truncateLegendLabel"
|
||||
defaultMessage="Truncate legend?"
|
||||
/>
|
||||
</EuiFormLabel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<YesNo
|
||||
value={model.truncate_legend}
|
||||
name="truncate_legend"
|
||||
onChange={this.props.onChange}
|
||||
data-test-subj="timeSeriesEditorDataTruncateLegendSwitch"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormLabel>
|
||||
<FormattedMessage
|
||||
id="visTypeTimeseries.timeseries.optionsTab.maxLinesLabel"
|
||||
defaultMessage="Maximum legend lines"
|
||||
/>
|
||||
</EuiFormLabel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFieldNumber
|
||||
data-test-subj="timeSeriesEditorDataMaxLegendLines"
|
||||
value={model.max_lines_legend}
|
||||
min={MIN_TRUNCATE_LINES}
|
||||
max={MAX_TRUNCATE_LINES}
|
||||
compressed
|
||||
disabled={!Boolean(model.truncate_legend)}
|
||||
onChange={(e) => {
|
||||
const val = Number(e.target.value);
|
||||
this.props.onChange({
|
||||
max_lines_legend: Math.min(
|
||||
MAX_TRUNCATE_LINES,
|
||||
Math.max(val, MIN_TRUNCATE_LINES)
|
||||
),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormLabel htmlFor={htmlId('legendPos')}>
|
||||
<FormattedMessage
|
||||
id="visTypeTimeseries.timeseries.optionsTab.legendPositionLabel"
|
||||
defaultMessage="Legend position"
|
||||
/>
|
||||
</EuiFormLabel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiComboBox
|
||||
isClearable={false}
|
||||
id={htmlId('legendPos')}
|
||||
options={legendPositionOptions}
|
||||
selectedOptions={selectedLegendPosOption ? [selectedLegendPosOption] : []}
|
||||
onChange={handleSelectChange('legend_position')}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -238,6 +238,8 @@ class TimeseriesVisualization extends Component {
|
|||
showGrid={Boolean(model.show_grid)}
|
||||
legend={Boolean(model.show_legend)}
|
||||
legendPosition={model.legend_position}
|
||||
truncateLegend={Boolean(model.truncate_legend)}
|
||||
maxLegendLines={model.max_lines_legend}
|
||||
tooltipMode={model.tooltip_mode}
|
||||
xAxisFormatter={this.xAxisFormatter(interval)}
|
||||
annotations={this.prepareAnnotations()}
|
||||
|
|
|
@ -56,6 +56,8 @@ export const TimeSeries = ({
|
|||
showGrid,
|
||||
legend,
|
||||
legendPosition,
|
||||
truncateLegend,
|
||||
maxLegendLines,
|
||||
tooltipMode,
|
||||
series,
|
||||
yAxis,
|
||||
|
@ -172,6 +174,9 @@ export const TimeSeries = ({
|
|||
background: {
|
||||
color: backgroundColor,
|
||||
},
|
||||
legend: {
|
||||
labelOptions: { maxLines: truncateLegend ? maxLegendLines ?? 1 : 0 },
|
||||
},
|
||||
},
|
||||
chartTheme,
|
||||
]}
|
||||
|
@ -216,6 +221,7 @@ export const TimeSeries = ({
|
|||
lines,
|
||||
data,
|
||||
hideInLegend,
|
||||
truncateLegend,
|
||||
xScaleType,
|
||||
yScaleType,
|
||||
groupId,
|
||||
|
@ -249,6 +255,7 @@ export const TimeSeries = ({
|
|||
name={getValueOrEmpty(seriesName)}
|
||||
data={data}
|
||||
hideInLegend={hideInLegend}
|
||||
truncateLegend={truncateLegend}
|
||||
bars={bars}
|
||||
color={finalColor}
|
||||
stackAccessors={stackAccessors}
|
||||
|
@ -274,6 +281,7 @@ export const TimeSeries = ({
|
|||
name={getValueOrEmpty(seriesName)}
|
||||
data={data}
|
||||
hideInLegend={hideInLegend}
|
||||
truncateLegend={truncateLegend}
|
||||
lines={lines}
|
||||
color={finalColor}
|
||||
stackAccessors={stackAccessors}
|
||||
|
@ -336,6 +344,8 @@ TimeSeries.propTypes = {
|
|||
showGrid: PropTypes.bool,
|
||||
legend: PropTypes.bool,
|
||||
legendPosition: PropTypes.string,
|
||||
truncateLegend: PropTypes.bool,
|
||||
maxLegendLines: PropTypes.number,
|
||||
series: PropTypes.array,
|
||||
yAxis: PropTypes.array,
|
||||
onBrush: PropTypes.func,
|
||||
|
|
|
@ -93,6 +93,8 @@ export const metricsVisDefinition: VisTypeDefinition<
|
|||
axis_formatter: 'number',
|
||||
axis_scale: 'normal',
|
||||
show_legend: 1,
|
||||
truncate_legend: 1,
|
||||
max_lines_legend: 1,
|
||||
show_grid: 1,
|
||||
tooltip_mode: TOOLTIP_MODES.SHOW_ALL,
|
||||
drop_last_bucket: 0,
|
||||
|
|
|
@ -2,30 +2,3 @@
|
|||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@kbn/interpreter@link:../packages/kbn-interpreter":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/optimizer@link:../packages/kbn-optimizer":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/plugin-helpers@link:../packages/kbn-plugin-helpers":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/storybook@link:../packages/kbn-storybook":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/test@link:../packages/kbn-test":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/ui-framework@link:../packages/kbn-ui-framework":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/ui-shared-deps@link:../packages/kbn-ui-shared-deps":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
|
Loading…
Reference in a new issue