Introduce filtering to FuncButton

pull/10616/head
Andrew Watkins 2018-03-26 15:53:29 -07:00 committed by Brandon Farmer
parent d4000e7b5b
commit 376ce0db87
3 changed files with 105 additions and 28 deletions

View File

@ -1,29 +1,31 @@
import React, {PureComponent} from 'react'
import React, {PureComponent, ChangeEvent, KeyboardEvent} from 'react'
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
import DropdownInput from 'src/shared/components/DropdownInput'
import OnClickOutside from 'src/shared/components/OnClickOutside'
interface State {
isOpen: boolean
inputText: string
}
interface Props {
funcs: string[]
}
class FuncsButton extends PureComponent<Props, State> {
export class FuncsButton extends PureComponent<Props, State> {
constructor(props) {
super(props)
this.state = {
isOpen: false,
inputText: '',
}
}
public render() {
const {isOpen} = this.state
const {funcs} = this.props
const {isOpen, inputText} = this.state
return (
<div className={`dropdown dashboard-switcher ${isOpen ? 'open' : ''}`}>
@ -34,14 +36,17 @@ class FuncsButton extends PureComponent<Props, State> {
<span className="icon plus" />
</button>
<ul className="dropdown-menu funcs">
<DropdownInput
buttonSize="btn-xs"
buttonColor="btn-default"
onFilterChange={this.handleInputChange}
onFilterKeyPress={this.handleKeyDown}
searchTerm={inputText}
/>
<FancyScrollbar autoHide={false} autoHeight={true} maxHeight={240}>
{isOpen &&
funcs.map((func, i) => (
<li
className="dropdown-item func"
data-test="func-item"
key={i}
>
this.availableFuncs.map((func, i) => (
<li className="dropdown-item func" key={i}>
<a>{func}</a>
</li>
))}
@ -51,6 +56,24 @@ class FuncsButton extends PureComponent<Props, State> {
)
}
private get availableFuncs(): string[] {
return this.props.funcs.filter(f =>
f.toLowerCase().includes(this.state.inputText)
)
}
private handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
this.setState({inputText: e.target.value})
}
private handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
if (e.key !== 'Escape') {
return
}
this.setState({inputText: '', isOpen: false})
}
private handleClick = () => {
this.setState({isOpen: !this.state.isOpen})
}

View File

@ -1,9 +1,21 @@
import React from 'react'
import PropTypes from 'prop-types'
import React, {SFC, ChangeEvent, KeyboardEvent} from 'react'
const disabledClass = disabled => (disabled ? ' disabled' : '')
const DropdownInput = ({
type OnFilterChangeHandler = (e: ChangeEvent<HTMLInputElement>) => void
type OnFilterKeyPress = (e: KeyboardEvent<HTMLInputElement>) => void
interface Props {
searchTerm: string
buttonSize: string
buttonColor: string
toggleStyle?: object
disabled?: boolean
onFilterChange: OnFilterChangeHandler
onFilterKeyPress: OnFilterKeyPress
}
const DropdownInput: SFC<Props> = ({
searchTerm,
buttonSize,
buttonColor,
@ -33,15 +45,3 @@ const DropdownInput = ({
)
export default DropdownInput
const {bool, func, shape, string} = PropTypes
DropdownInput.propTypes = {
searchTerm: string,
buttonSize: string,
buttonColor: string,
toggleStyle: shape({}),
disabled: bool,
onFilterChange: func.isRequired,
onFilterKeyPress: func.isRequired,
}

View File

@ -1,6 +1,7 @@
import React from 'react'
import {shallow} from 'enzyme'
import FuncsButton from 'src/ifql/components/FuncsButton'
import {FuncsButton} from 'src/ifql/components/FuncsButton'
import DropdownInput from 'src/shared/components/DropdownInput'
const setup = (override = {}) => {
const props = {
@ -39,14 +40,67 @@ describe('IFQL.Components.FuncsButton', () => {
it('displays the list of functions', () => {
const {wrapper} = setup()
wrapper.simulate('click')
const dropdownButton = wrapper.find('button')
dropdownButton.simulate('click')
const list = wrapper.find({'data-test': 'func-item'})
const list = wrapper.find('.func')
expect(list.length).toBe(2)
expect(list.first().text()).toBe('f1')
expect(list.last().text()).toBe('f2')
})
})
describe('filtering the list', () => {
it('displays the filtered funcs', () => {
const {wrapper} = setup()
const dropdownButton = wrapper.find('button')
dropdownButton.simulate('click')
let list = wrapper.find('.func')
expect(list.length).toBe(2)
expect(list.first().text()).toBe('f1')
expect(list.last().text()).toBe('f2')
const input = wrapper
.find(DropdownInput)
.dive()
.find('input')
input.simulate('change', {target: {value: '2'}})
wrapper.update()
list = wrapper.find('.func')
expect(list.length).toBe(1)
expect(list.first().text()).toBe('f2')
})
})
describe('exiting the list', () => {
it('closes when ESC is pressed', () => {
const {wrapper} = setup()
const dropdownButton = wrapper.find('button')
dropdownButton.simulate('click')
let list = wrapper.find('.func')
expect(list.exists()).toBe(true)
const input = wrapper
.find(DropdownInput)
.dive()
.find('input')
input.simulate('keyDown', {key: 'Escape'})
wrapper.update()
list = wrapper.find('.func')
expect(list.exists()).toBe(false)
})
})
})
})