From 6347a1f1eb12391d23cfd23f596739c2b84668af Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Mon, 6 Apr 2020 06:06:41 -0700 Subject: [PATCH] VizPicker: show plugins that start with query text first (#23355) * show plugins that start with queyr text first * Memoize keyboard handler Co-authored-by: Dominik Prokop --- .../PanelEditor/VisualizationTab.tsx | 20 +++++++++- .../dashboard/panel_editor/VizTypePicker.tsx | 40 ++++++++++++++----- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/public/app/features/dashboard/components/PanelEditor/VisualizationTab.tsx b/public/app/features/dashboard/components/PanelEditor/VisualizationTab.tsx index 90d3b944886..560e3d40a8f 100644 --- a/public/app/features/dashboard/components/PanelEditor/VisualizationTab.tsx +++ b/public/app/features/dashboard/components/PanelEditor/VisualizationTab.tsx @@ -1,4 +1,4 @@ -import React, { FC, useState } from 'react'; +import React, { FC, useCallback, useState } from 'react'; import { css } from 'emotion'; import { GrafanaTheme, PanelPlugin, PanelPluginMeta } from '@grafana/data'; import { CustomScrollbar, useTheme, stylesFactory, Icon, Input } from '@grafana/ui'; @@ -6,7 +6,7 @@ import { changePanelPlugin } from '../../state/actions'; import { StoreState } from 'app/types'; import { PanelModel } from '../../state/PanelModel'; import { connect, MapStateToProps, MapDispatchToProps } from 'react-redux'; -import { VizTypePicker } from '../../panel_editor/VizTypePicker'; +import { VizTypePicker, getAllPanelPluginMeta, filterPluginList } from '../../panel_editor/VizTypePicker'; import { Field } from '@grafana/ui/src/components/Forms/Field'; interface OwnProps { @@ -35,6 +35,21 @@ export const VisualizationTabUnconnected: FC = ({ panel, plugin, changePa const onPluginTypeChange = (meta: PanelPluginMeta) => { changePanelPlugin(panel, meta.id); }; + + const onKeyPress = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + const query = e.currentTarget.value; + const plugins = getAllPanelPluginMeta(); + const match = filterPluginList(plugins, query); + if (match && match.length) { + onPluginTypeChange(match[0]); + } + } + }, + [onPluginTypeChange] + ); + const suffix = searchQuery !== '' ? ( setSearchQuery('')}> @@ -50,6 +65,7 @@ export const VisualizationTabUnconnected: FC = ({ panel, plugin, changePa setSearchQuery(e.currentTarget.value)} + onKeyPress={onKeyPress} prefix={} suffix={suffix} placeholder="Filter visualisations" diff --git a/public/app/features/dashboard/panel_editor/VizTypePicker.tsx b/public/app/features/dashboard/panel_editor/VizTypePicker.tsx index 7c6ee977bc7..8e0d31b30e1 100644 --- a/public/app/features/dashboard/panel_editor/VizTypePicker.tsx +++ b/public/app/features/dashboard/panel_editor/VizTypePicker.tsx @@ -13,16 +13,39 @@ export interface Props { onClose: () => void; } +export function getAllPanelPluginMeta(): PanelPluginMeta[] { + const allPanels = config.panels; + + return Object.keys(allPanels) + .filter(key => allPanels[key]['hideFromList'] === false) + .map(key => allPanels[key]) + .sort((a: PanelPluginMeta, b: PanelPluginMeta) => a.sort - b.sort); +} + +export function filterPluginList(pluginsList: PanelPluginMeta[], searchQuery: string): PanelPluginMeta[] { + if (!searchQuery.length) { + return pluginsList; + } + const query = searchQuery.toLowerCase(); + const first: PanelPluginMeta[] = []; + const match: PanelPluginMeta[] = []; + for (const item of pluginsList) { + const name = item.name.toLowerCase(); + const idx = name.indexOf(query); + if (idx === 0) { + first.push(item); + } else if (idx > 0) { + match.push(item); + } + } + return first.concat(match); +} + export const VizTypePicker: React.FC = ({ searchQuery, onTypeChange, current }) => { const theme = useTheme(); const styles = getStyles(theme); const pluginsList: PanelPluginMeta[] = useMemo(() => { - const allPanels = config.panels; - - return Object.keys(allPanels) - .filter(key => allPanels[key]['hideFromList'] === false) - .map(key => allPanels[key]) - .sort((a: PanelPluginMeta, b: PanelPluginMeta) => a.sort - b.sort); + return getAllPanelPluginMeta(); }, []); const renderVizPlugin = (plugin: PanelPluginMeta, index: number) => { @@ -42,10 +65,7 @@ export const VizTypePicker: React.FC = ({ searchQuery, onTypeChange, curr }; const getFilteredPluginList = useCallback((): PanelPluginMeta[] => { - const regex = new RegExp(searchQuery, 'i'); - return pluginsList.filter(item => { - return regex.test(item.name); - }); + return filterPluginList(pluginsList, searchQuery); }, [searchQuery]); const filteredPluginList = getFilteredPluginList();