[Lens] Add search to chart switcher (#77631)
This commit is contained in:
parent
4d58a0041e
commit
11886bf51c
|
@ -16,3 +16,7 @@ img.lnsChartSwitch__chartIcon { // sass-lint:disable-line no-qualifying-elements
|
|||
// The large icons aren't square so max out the width to fill the height
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.lnsChartSwitch__search {
|
||||
width: 4 * $euiSizeXXL;
|
||||
}
|
|
@ -12,9 +12,14 @@ import {
|
|||
EuiPopoverTitle,
|
||||
EuiKeyPadMenu,
|
||||
EuiKeyPadMenuItem,
|
||||
EuiFieldSearch,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiSelectableMessage,
|
||||
} from '@elastic/eui';
|
||||
import { flatten } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { Visualization, FramePublicAPI, Datasource } from '../../../types';
|
||||
import { Action } from '../state_management';
|
||||
import { getSuggestions, switchToSuggestion, Suggestion } from '../suggestion_helpers';
|
||||
|
@ -173,6 +178,8 @@ export function ChartSwitch(props: Props) {
|
|||
};
|
||||
}
|
||||
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
|
||||
const visualizationTypes = useMemo(
|
||||
() =>
|
||||
flyoutOpen &&
|
||||
|
@ -184,10 +191,17 @@ export function ChartSwitch(props: Props) {
|
|||
icon: t.icon,
|
||||
}))
|
||||
)
|
||||
).map((visualizationType) => ({
|
||||
...visualizationType,
|
||||
selection: getSelection(visualizationType.visualizationId, visualizationType.id),
|
||||
})),
|
||||
)
|
||||
.filter(
|
||||
(visualizationType) =>
|
||||
visualizationType.label.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
(visualizationType.fullLabel &&
|
||||
visualizationType.fullLabel.toLowerCase().includes(searchTerm.toLowerCase()))
|
||||
)
|
||||
.map((visualizationType) => ({
|
||||
...visualizationType,
|
||||
selection: getSelection(visualizationType.visualizationId, visualizationType.id),
|
||||
})),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[
|
||||
flyoutOpen,
|
||||
|
@ -195,6 +209,7 @@ export function ChartSwitch(props: Props) {
|
|||
props.framePublicAPI,
|
||||
props.visualizationId,
|
||||
props.visualizationState,
|
||||
searchTerm,
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -219,15 +234,30 @@ export function ChartSwitch(props: Props) {
|
|||
anchorPosition="downLeft"
|
||||
>
|
||||
<EuiPopoverTitle>
|
||||
{i18n.translate('xpack.lens.configPanel.selectVisualization', {
|
||||
defaultMessage: 'Select a visualization',
|
||||
})}
|
||||
<EuiFlexGroup alignItems="center" responsive={false}>
|
||||
<EuiFlexItem>
|
||||
{i18n.translate('xpack.lens.configPanel.chartType', {
|
||||
defaultMessage: 'Chart type',
|
||||
})}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFieldSearch
|
||||
compressed
|
||||
fullWidth={false}
|
||||
className="lnsChartSwitch__search"
|
||||
value={searchTerm}
|
||||
data-test-subj="lnsChartSwitchSearch"
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPopoverTitle>
|
||||
<EuiKeyPadMenu>
|
||||
{(visualizationTypes || []).map((v) => (
|
||||
<EuiKeyPadMenuItem
|
||||
key={`${v.visualizationId}:${v.id}`}
|
||||
label={<span data-test-subj="visTypeTitle">{v.label}</span>}
|
||||
title={v.fullLabel}
|
||||
role="menuitem"
|
||||
data-test-subj={`lnsChartSwitchPopover_${v.id}`}
|
||||
onClick={() => commitSelection(v.selection)}
|
||||
|
@ -251,6 +281,17 @@ export function ChartSwitch(props: Props) {
|
|||
</EuiKeyPadMenuItem>
|
||||
))}
|
||||
</EuiKeyPadMenu>
|
||||
{searchTerm && (visualizationTypes || []).length === 0 && (
|
||||
<EuiSelectableMessage>
|
||||
<FormattedMessage
|
||||
id="xpack.lens.chartSwitch.noResults"
|
||||
defaultMessage="No results found for {term}."
|
||||
values={{
|
||||
term: <strong>{searchTerm}</strong>,
|
||||
}}
|
||||
/>
|
||||
</EuiSelectableMessage>
|
||||
)}
|
||||
</EuiPopover>
|
||||
);
|
||||
|
||||
|
|
|
@ -430,10 +430,26 @@ export interface FramePublicAPI {
|
|||
removeLayers: (layerIds: string[]) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A visualization type advertised to the user in the chart switcher
|
||||
*/
|
||||
export interface VisualizationType {
|
||||
/**
|
||||
* Unique id of the visualization type within the visualization defining it
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Icon used in the chart switcher
|
||||
*/
|
||||
icon: IconType;
|
||||
/**
|
||||
* Visible label used in the chart switcher and above the workspace panel in collapsed state
|
||||
*/
|
||||
label: string;
|
||||
/**
|
||||
* Optional label used in chart type search if chart switcher is expanded and for tooltips
|
||||
*/
|
||||
fullLabel?: string;
|
||||
}
|
||||
|
||||
export interface Visualization<T = unknown> {
|
||||
|
|
|
@ -426,6 +426,9 @@ export const visualizationTypes: VisualizationType[] = [
|
|||
id: 'bar_horizontal',
|
||||
icon: LensIconChartBarHorizontal,
|
||||
label: i18n.translate('xpack.lens.xyVisualization.barHorizontalLabel', {
|
||||
defaultMessage: 'H. Bar',
|
||||
}),
|
||||
fullLabel: i18n.translate('xpack.lens.xyVisualization.barHorizontalFullLabel', {
|
||||
defaultMessage: 'Horizontal bar',
|
||||
}),
|
||||
},
|
||||
|
@ -440,22 +443,31 @@ export const visualizationTypes: VisualizationType[] = [
|
|||
id: 'bar_percentage_stacked',
|
||||
icon: LensIconChartBarPercentage,
|
||||
label: i18n.translate('xpack.lens.xyVisualization.stackedPercentageBarLabel', {
|
||||
defaultMessage: 'Bar percentage',
|
||||
defaultMessage: 'Percentage bar',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 'bar_horizontal_stacked',
|
||||
icon: LensIconChartBarHorizontalStacked,
|
||||
label: i18n.translate('xpack.lens.xyVisualization.stackedBarHorizontalLabel', {
|
||||
defaultMessage: 'Stacked horizontal bar',
|
||||
defaultMessage: 'H. Stacked bar',
|
||||
}),
|
||||
fullLabel: i18n.translate('xpack.lens.xyVisualization.stackedBarHorizontalFullLabel', {
|
||||
defaultMessage: 'Horizontal stacked bar',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 'bar_horizontal_percentage_stacked',
|
||||
icon: LensIconChartBarHorizontalPercentage,
|
||||
label: i18n.translate('xpack.lens.xyVisualization.stackedPercentageBarHorizontalLabel', {
|
||||
defaultMessage: 'Horizontal bar percentage',
|
||||
defaultMessage: 'H. Percentage bar',
|
||||
}),
|
||||
fullLabel: i18n.translate(
|
||||
'xpack.lens.xyVisualization.stackedPercentageBarHorizontalFullLabel',
|
||||
{
|
||||
defaultMessage: 'Horizontal percentage bar',
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'area',
|
||||
|
@ -475,7 +487,7 @@ export const visualizationTypes: VisualizationType[] = [
|
|||
id: 'area_percentage_stacked',
|
||||
icon: LensIconChartAreaPercentage,
|
||||
label: i18n.translate('xpack.lens.xyVisualization.stackedPercentageAreaLabel', {
|
||||
defaultMessage: 'Area percentage',
|
||||
defaultMessage: 'Percentage area',
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
|
|
@ -44,14 +44,14 @@ describe('xy_visualization', () => {
|
|||
it('should show mixed xy chart when multilple series types', () => {
|
||||
const desc = xyVisualization.getDescription(mixedState('bar', 'line'));
|
||||
|
||||
expect(desc.label).toEqual('Mixed XY chart');
|
||||
expect(desc.label).toEqual('Mixed XY');
|
||||
});
|
||||
|
||||
it('should show the preferredSeriesType if there are no layers', () => {
|
||||
const desc = xyVisualization.getDescription(mixedState());
|
||||
|
||||
expect(desc.icon).toEqual(LensIconChartBar);
|
||||
expect(desc.label).toEqual('Bar chart');
|
||||
expect(desc.label).toEqual('Bar');
|
||||
});
|
||||
|
||||
it('should show mixed horizontal bar chart when multiple horizontal bar types', () => {
|
||||
|
@ -59,23 +59,23 @@ describe('xy_visualization', () => {
|
|||
mixedState('bar_horizontal', 'bar_horizontal_stacked')
|
||||
);
|
||||
|
||||
expect(desc.label).toEqual('Mixed horizontal bar chart');
|
||||
expect(desc.label).toEqual('Mixed H. bar');
|
||||
});
|
||||
|
||||
it('should show bar chart when bar only', () => {
|
||||
const desc = xyVisualization.getDescription(mixedState('bar_horizontal', 'bar_horizontal'));
|
||||
|
||||
expect(desc.label).toEqual('Horizontal bar chart');
|
||||
expect(desc.label).toEqual('H. Bar');
|
||||
});
|
||||
|
||||
it('should show the chart description if not mixed', () => {
|
||||
expect(xyVisualization.getDescription(mixedState('area')).label).toEqual('Area chart');
|
||||
expect(xyVisualization.getDescription(mixedState('line')).label).toEqual('Line chart');
|
||||
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 chart'
|
||||
'Stacked area'
|
||||
);
|
||||
expect(xyVisualization.getDescription(mixedState('bar_horizontal_stacked')).label).toEqual(
|
||||
'Stacked horizontal bar chart'
|
||||
'H. Stacked bar'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -53,7 +53,7 @@ function getDescription(state?: State) {
|
|||
return {
|
||||
icon: LensIconChartBarHorizontal,
|
||||
label: i18n.translate('xpack.lens.xyVisualization.mixedBarHorizontalLabel', {
|
||||
defaultMessage: 'Mixed horizontal bar',
|
||||
defaultMessage: 'Mixed H. bar',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
@ -118,14 +118,10 @@ export const xyVisualization: Visualization<State> = {
|
|||
|
||||
getDescription(state) {
|
||||
const { icon, label } = getDescription(state);
|
||||
const chartLabel = i18n.translate('xpack.lens.xyVisualization.chartLabel', {
|
||||
defaultMessage: '{label} chart',
|
||||
values: { label },
|
||||
});
|
||||
|
||||
return {
|
||||
icon: icon || defaultIcon,
|
||||
label: chartLabel,
|
||||
label,
|
||||
};
|
||||
},
|
||||
|
||||
|
|
|
@ -9623,15 +9623,12 @@
|
|||
"xpack.lens.xySuggestions.unstackedChartTitle": "スタックが解除されました",
|
||||
"xpack.lens.xySuggestions.yAxixConjunctionSign": " と ",
|
||||
"xpack.lens.xyVisualization.areaLabel": "エリア",
|
||||
"xpack.lens.xyVisualization.barHorizontalLabel": "横棒",
|
||||
"xpack.lens.xyVisualization.barLabel": "バー",
|
||||
"xpack.lens.xyVisualization.chartLabel": "{label} チャート",
|
||||
"xpack.lens.xyVisualization.lineLabel": "折れ線",
|
||||
"xpack.lens.xyVisualization.mixedBarHorizontalLabel": "ミックスされた横棒",
|
||||
"xpack.lens.xyVisualization.mixedLabel": "ミックスされた XY",
|
||||
"xpack.lens.xyVisualization.noDataLabel": "結果が見つかりませんでした",
|
||||
"xpack.lens.xyVisualization.stackedAreaLabel": "スタックされたエリア",
|
||||
"xpack.lens.xyVisualization.stackedBarHorizontalLabel": "スタックされた横棒",
|
||||
"xpack.lens.xyVisualization.stackedBarLabel": "スタックされたバー",
|
||||
"xpack.lens.xyVisualization.xyLabel": "XY",
|
||||
"xpack.licenseMgmt.app.checkingPermissionsErrorMessage": "パーミッションの確認中にエラーが発生",
|
||||
|
|
|
@ -9629,15 +9629,12 @@
|
|||
"xpack.lens.xySuggestions.unstackedChartTitle": "非堆叠",
|
||||
"xpack.lens.xySuggestions.yAxixConjunctionSign": " & ",
|
||||
"xpack.lens.xyVisualization.areaLabel": "面积图",
|
||||
"xpack.lens.xyVisualization.barHorizontalLabel": "水平条形图",
|
||||
"xpack.lens.xyVisualization.barLabel": "条形图",
|
||||
"xpack.lens.xyVisualization.chartLabel": "{label} 图表",
|
||||
"xpack.lens.xyVisualization.lineLabel": "折线图",
|
||||
"xpack.lens.xyVisualization.mixedBarHorizontalLabel": "混合水平条形图",
|
||||
"xpack.lens.xyVisualization.mixedLabel": "混合 XY",
|
||||
"xpack.lens.xyVisualization.noDataLabel": "找不到结果",
|
||||
"xpack.lens.xyVisualization.stackedAreaLabel": "堆叠面积图",
|
||||
"xpack.lens.xyVisualization.stackedBarHorizontalLabel": "堆叠水平条形图",
|
||||
"xpack.lens.xyVisualization.stackedBarLabel": "堆叠条形图",
|
||||
"xpack.lens.xyVisualization.xyLabel": "XY",
|
||||
"xpack.licenseMgmt.app.checkingPermissionsErrorMessage": "检查权限时出错",
|
||||
|
|
Loading…
Reference in a new issue