diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.scss index f84191e1bfb1a..e0031d051df81 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.scss @@ -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; +} \ No newline at end of file diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx index f4526cac39c8a..73ffbf56ff45a 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx @@ -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" > - {i18n.translate('xpack.lens.configPanel.selectVisualization', { - defaultMessage: 'Select a visualization', - })} + + + {i18n.translate('xpack.lens.configPanel.chartType', { + defaultMessage: 'Chart type', + })} + + + setSearchTerm(e.target.value)} + /> + + {(visualizationTypes || []).map((v) => ( {v.label}} + title={v.fullLabel} role="menuitem" data-test-subj={`lnsChartSwitchPopover_${v.id}`} onClick={() => commitSelection(v.selection)} @@ -251,6 +281,17 @@ export function ChartSwitch(props: Props) { ))} + {searchTerm && (visualizationTypes || []).length === 0 && ( + + {searchTerm}, + }} + /> + + )} ); diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 6061f928bce41..2b9ca5a2425f8 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -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 { diff --git a/x-pack/plugins/lens/public/xy_visualization/types.ts b/x-pack/plugins/lens/public/xy_visualization/types.ts index cac982f852c7a..abee787888787 100644 --- a/x-pack/plugins/lens/public/xy_visualization/types.ts +++ b/x-pack/plugins/lens/public/xy_visualization/types.ts @@ -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', }), }, { diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts index 621fd082faf2d..d51b8c195c92c 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts @@ -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' ); }); }); diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx index 0b8f7e2ed0f11..76c5a51cb7168 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx @@ -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 = { 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, }; }, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index b1e3ad2edbc67..92dd75445d8fd 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9659,15 +9659,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": "パーミッションの確認中にエラーが発生", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b0ab1f6180485..479081854a2ac 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9665,15 +9665,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": "检查权限时出错",