Introduce filtering to FuncButton
parent
d4000e7b5b
commit
376ce0db87
|
@ -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})
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue