Просмотр исходного кода

Let VizTypePicker use the keyboard navigation hoc

Johannes Schill 7 лет назад
Родитель
Сommit
645812f643

+ 3 - 6
public/app/features/dashboard/dashgrid/DataSourcePicker.tsx

@@ -1,15 +1,12 @@
 import React, { PureComponent } from 'react';
 import classNames from 'classnames';
 import _ from 'lodash';
-import withKeyboardNavigation from './withKeyboardNavigation';
+import withKeyboardNavigation, { KeyboardNavigationProps } from './withKeyboardNavigation';
 import { DataSourceSelectItem } from 'app/types';
 
 export interface Props {
-  onChangeDataSource: (ds: any) => void;
+  onChangeDataSource: (ds: DataSourceSelectItem) => void;
   datasources: DataSourceSelectItem[];
-  selected?: number;
-  onKeyDown?: (evt: any, maxSelectedIndex: number, onEnterAction: () => void) => void;
-  onMouseEnter?: (select: number) => void;
 }
 
 interface State {
@@ -17,7 +14,7 @@ interface State {
 }
 
 export const DataSourcePicker = withKeyboardNavigation(
-  class DataSourcePicker extends PureComponent<Props, State> {
+  class DataSourcePicker extends PureComponent<Props & KeyboardNavigationProps, State> {
     searchInput: HTMLElement;
 
     constructor(props) {

+ 106 - 130
public/app/features/dashboard/dashgrid/VizTypePicker.tsx

@@ -4,153 +4,129 @@ import _ from 'lodash';
 import config from 'app/core/config';
 import { PanelPlugin } from 'app/types/plugins';
 import VizTypePickerPlugin from './VizTypePickerPlugin';
+import withKeyboardNavigation, { KeyboardNavigationProps } from './withKeyboardNavigation';
 
-interface Props {
+export interface Props {
   current: PanelPlugin;
   onTypeChanged: (newType: PanelPlugin) => void;
 }
 
 interface State {
   searchQuery: string;
-  selected: number;
 }
 
-export class VizTypePicker extends PureComponent<Props, State> {
-  searchInput: HTMLElement;
-  pluginList = this.getPanelPlugins('');
+export const VizTypePicker = withKeyboardNavigation(
+  class VizTypePicker extends PureComponent<Props & KeyboardNavigationProps, State> {
+    searchInput: HTMLElement;
+    pluginList = this.getPanelPlugins('');
 
-  constructor(props) {
-    super(props);
+    constructor(props) {
+      super(props);
 
-    this.state = {
-      searchQuery: '',
-      selected: 0,
-    };
-  }
-
-  get maxSelectedIndex() {
-    const filteredPluginList = this.getFilteredPluginList();
-    return filteredPluginList.length - 1;
-  }
+      this.state = {
+        searchQuery: '',
+      };
+    }
 
-  goRight = () => {
-    const nextIndex = this.state.selected >= this.maxSelectedIndex ? 0 : this.state.selected + 1;
-    this.setState({
-      selected: nextIndex,
-    });
-  };
-
-  goLeft = () => {
-    const nextIndex = this.state.selected <= 0 ? this.maxSelectedIndex : this.state.selected - 1;
-    this.setState({
-      selected: nextIndex,
-    });
-  };
-
-  onKeyDown = evt => {
-    if (evt.key === 'ArrowDown') {
-      evt.preventDefault();
-      this.goRight();
+    get maxSelectedIndex() {
+      const filteredPluginList = this.getFilteredPluginList();
+      return filteredPluginList.length - 1;
     }
-    if (evt.key === 'ArrowUp') {
-      evt.preventDefault();
-      this.goLeft();
+
+    componentDidMount() {
+      setTimeout(() => {
+        this.searchInput.focus();
+      }, 300);
     }
-    if (evt.key === 'Enter') {
-      const filteredPluginList = this.getFilteredPluginList();
-      this.props.onTypeChanged(filteredPluginList[this.state.selected]);
+
+    getPanelPlugins(filter): PanelPlugin[] {
+      const panels = _.chain(config.panels)
+        .filter({ hideFromList: false })
+        .map(item => item)
+        .value();
+
+      // add sort by sort property
+      return _.sortBy(panels, 'sort');
     }
-  };
 
-  componentDidMount() {
-    setTimeout(() => {
-      this.searchInput.focus();
-    }, 300);
-  }
+    renderVizPlugin = (plugin: PanelPlugin, index: number) => {
+      const { onTypeChanged, selected, onMouseEnter } = this.props;
+      const isSelected = selected === index;
+      const isCurrent = plugin.id === this.props.current.id;
+      return (
+        <VizTypePickerPlugin
+          key={plugin.id}
+          isSelected={isSelected}
+          isCurrent={isCurrent}
+          plugin={plugin}
+          onMouseEnter={() => {
+            onMouseEnter(index);
+          }}
+          onClick={() => onTypeChanged(plugin)}
+        />
+      );
+    };
 
-  getPanelPlugins(filter): PanelPlugin[] {
-    const panels = _.chain(config.panels)
-      .filter({ hideFromList: false })
-      .map(item => item)
-      .value();
+    getFilteredPluginList = (): PanelPlugin[] => {
+      const { searchQuery } = this.state;
+      const regex = new RegExp(searchQuery, 'i');
+      const pluginList = this.pluginList;
 
-    // add sort by sort property
-    return _.sortBy(panels, 'sort');
-  }
+      const filtered = pluginList.filter(item => {
+        return regex.test(item.name);
+      });
+
+      return filtered;
+    };
 
-  onMouseEnter = (mouseEnterIndex: number) => {
-    this.setState({
-      selected: mouseEnterIndex,
-    });
-  };
-
-  renderVizPlugin = (plugin: PanelPlugin, index: number) => {
-    const isSelected = this.state.selected === index;
-    const isCurrent = plugin.id === this.props.current.id;
-    return (
-      <VizTypePickerPlugin
-        key={plugin.id}
-        isSelected={isSelected}
-        isCurrent={isCurrent}
-        plugin={plugin}
-        onMouseEnter={() => {
-          this.onMouseEnter(index);
-        }}
-        onClick={() => this.props.onTypeChanged(plugin)}
-      />
-    );
-  };
-
-  getFilteredPluginList = (): PanelPlugin[] => {
-    const { searchQuery } = this.state;
-    const regex = new RegExp(searchQuery, 'i');
-    const pluginList = this.pluginList;
-
-    const filtered = pluginList.filter(item => {
-      return regex.test(item.name);
-    });
-
-    return filtered;
-  };
-
-  onSearchQueryChange = evt => {
-    const value = evt.target.value;
-    this.setState(prevState => ({
-      ...prevState,
-      searchQuery: value,
-      selected: 0,
-    }));
-  };
-
-  renderFilters = () => {
-    return (
-      <>
-        <label className="gf-form--has-input-icon">
-          <input
-            type="text"
-            className="gf-form-input width-13"
-            placeholder=""
-            ref={elem => (this.searchInput = elem)}
-            onChange={this.onSearchQueryChange}
-            onKeyDown={this.onKeyDown}
-          />
-          <i className="gf-form-input-icon fa fa-search" />
-        </label>
-      </>
-    );
-  };
-
-  render() {
-    const filteredPluginList = this.getFilteredPluginList();
-
-    return (
-      <>
-        <div className="cta-form__bar">
-          {this.renderFilters()}
-          <div className="gf-form--grow" />
-        </div>
-        <div className="viz-picker">{filteredPluginList.map(this.renderVizPlugin)}</div>
-      </>
-    );
+    onSearchQueryChange = evt => {
+      const value = evt.target.value;
+      this.setState(prevState => ({
+        ...prevState,
+        searchQuery: value,
+      }));
+    };
+
+    renderFilters = () => {
+      const { searchQuery } = this.state;
+      const { onKeyDown } = this.props;
+      return (
+        <>
+          <label className="gf-form--has-input-icon">
+            <input
+              type="text"
+              className="gf-form-input width-13"
+              placeholder=""
+              ref={elem => (this.searchInput = elem)}
+              onChange={this.onSearchQueryChange}
+              value={searchQuery}
+              // onKeyDown={this.props.onKeyDown}
+              onKeyDown={evt => {
+                onKeyDown(evt, this.maxSelectedIndex, () => {
+                  const { onTypeChanged, selected } = this.props;
+                  const vizType = this.getFilteredPluginList()[selected];
+                  onTypeChanged(vizType);
+                });
+              }}
+            />
+            <i className="gf-form-input-icon fa fa-search" />
+          </label>
+        </>
+      );
+    };
+
+    render() {
+      const filteredPluginList = this.getFilteredPluginList();
+
+      return (
+        <>
+          <div className="cta-form__bar">
+            {this.renderFilters()}
+            <div className="gf-form--grow" />
+          </div>
+          <div className="viz-picker">{filteredPluginList.map(this.renderVizPlugin)}</div>
+        </>
+      );
+    }
   }
-}
+);

+ 9 - 2
public/app/features/dashboard/dashgrid/withKeyboardNavigation.tsx

@@ -1,12 +1,19 @@
 import React from 'react';
-import { Props } from './DataSourcePicker';
+import { Props as DataSourceProps } from './DataSourcePicker';
+import { Props as VizTypeProps } from './VizTypePicker';
 
 interface State {
   selected: number;
 }
 
+export interface KeyboardNavigationProps {
+  selected?: number;
+  onKeyDown?: (evt: React.KeyboardEvent<EventTarget>, maxSelectedIndex: number, onEnterAction: () => void) => void;
+  onMouseEnter?: (select: number) => void;
+}
+
 const withKeyboardNavigation = WrappedComponent => {
-  return class extends React.Component<Props, State> {
+  return class extends React.Component<DataSourceProps | VizTypeProps, State> {
     constructor(props) {
       super(props);