|
|
@@ -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>
|
|
|
+ </>
|
|
|
+ );
|
|
|
+ }
|
|
|
}
|
|
|
-}
|
|
|
+);
|