Merge pull request #4317 from influxdata/feature/filter-protoboards-by-name
Add ability to filter protoboards by name in dashboard steppull/4318/head
commit
3e620a429c
|
@ -1,56 +0,0 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import _ from 'lodash'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
@ErrorHandling
|
||||
class SearchBar extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
searchTerm: '',
|
||||
}
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.handleSearch = _.debounce(this.handleSearch, 50)
|
||||
}
|
||||
|
||||
handleSearch = () => {
|
||||
this.props.onSearch(this.state.searchTerm)
|
||||
}
|
||||
|
||||
handleChange = () => {
|
||||
this.setState({searchTerm: this.refs.searchInput.value}, this.handleSearch)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {placeholder, width} = this.props
|
||||
return (
|
||||
<div className="search-widget" style={{width: `${width}px`}}>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control input-sm"
|
||||
placeholder={placeholder}
|
||||
ref="searchInput"
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<span className="icon search" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {func, number, string} = PropTypes
|
||||
|
||||
SearchBar.defaultProps = {
|
||||
width: 260,
|
||||
}
|
||||
|
||||
SearchBar.propTypes = {
|
||||
width: number,
|
||||
onSearch: func.isRequired,
|
||||
placeholder: string.isRequired,
|
||||
}
|
||||
|
||||
export default SearchBar
|
|
@ -0,0 +1,61 @@
|
|||
// Libraries
|
||||
import React, {PureComponent, ChangeEvent} from 'react'
|
||||
import _ from 'lodash'
|
||||
|
||||
// Decorators
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
width?: number
|
||||
placeholder: string
|
||||
onSearch: (searchTerm: string) => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
searchTerm: string
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class SearchBar extends PureComponent<Props, State> {
|
||||
public static defaultProps: Partial<Props> = {
|
||||
width: 260,
|
||||
}
|
||||
|
||||
public debouncedHandleSearch: () => void
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
searchTerm: '',
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillMount() {
|
||||
this.debouncedHandleSearch = _.debounce(this.handleSearch, 50)
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {placeholder, width} = this.props
|
||||
return (
|
||||
<div className="search-widget" style={{width: `${width}px`}}>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control input-sm"
|
||||
placeholder={placeholder}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<span className="icon search" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private handleSearch = () => {
|
||||
this.props.onSearch(this.state.searchTerm)
|
||||
}
|
||||
|
||||
private handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({searchTerm: e.target.value}, this.debouncedHandleSearch)
|
||||
}
|
||||
}
|
||||
|
||||
export default SearchBar
|
|
@ -2,4 +2,14 @@
|
|||
position: relative;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.dashboard-step--filter-controls {
|
||||
margin-bottom: $ix-marg-c;
|
||||
padding: 0 2px;
|
||||
box-sizing: border-box;
|
||||
min-width: 100%;
|
||||
display: inline-flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
}
|
|
@ -4,16 +4,23 @@ import React, {Component} from 'react'
|
|||
// APIs
|
||||
import {getProtoBoards} from 'src/sources/apis'
|
||||
|
||||
// Components
|
||||
// Decorators
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
// Utils
|
||||
import {isSearchMatch} from 'src/utils/searchMatch'
|
||||
|
||||
// Components
|
||||
import GridSizer from 'src/reusable_ui/components/grid_sizer/GridSizer'
|
||||
import CardSelectCard from 'src/reusable_ui/components/card_select/CardSelectCard'
|
||||
import SearchBar from 'src/hosts/components/SearchBar'
|
||||
|
||||
// Types
|
||||
import {Protoboard} from 'src/types'
|
||||
|
||||
interface State {
|
||||
selected: object
|
||||
searchTerm: string
|
||||
protoboards: Protoboard[]
|
||||
}
|
||||
|
||||
|
@ -24,6 +31,7 @@ class DashboardStep extends Component<{}, State> {
|
|||
this.state = {
|
||||
selected: {},
|
||||
protoboards: [],
|
||||
searchTerm: '',
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,6 +45,12 @@ class DashboardStep extends Component<{}, State> {
|
|||
if (protoboards && protoboards.length) {
|
||||
return (
|
||||
<div className="dashboard-step">
|
||||
<div className="dashboard-step--filter-controls">
|
||||
<SearchBar
|
||||
placeholder="Filter by name..."
|
||||
onSearch={this.setSearchTerm}
|
||||
/>
|
||||
</div>
|
||||
<GridSizer>{this.dashboardCards}</GridSizer>
|
||||
</div>
|
||||
)
|
||||
|
@ -44,10 +58,16 @@ class DashboardStep extends Component<{}, State> {
|
|||
return <div />
|
||||
}
|
||||
|
||||
private get dashboardCards() {
|
||||
const {selected, protoboards} = this.state
|
||||
private setSearchTerm = searchTerm => {
|
||||
this.setState({searchTerm})
|
||||
}
|
||||
|
||||
return protoboards.map((protoboard, i) => {
|
||||
private get dashboardCards() {
|
||||
const {selected, protoboards, searchTerm} = this.state
|
||||
const filteredProtoboards = protoboards.filter(pb =>
|
||||
isSearchMatch(pb.meta.name, searchTerm)
|
||||
)
|
||||
return filteredProtoboards.map((protoboard, i) => {
|
||||
const {meta} = protoboard
|
||||
return (
|
||||
<CardSelectCard
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
export const isSearchMatch = (input: string, searchTerm: string): boolean =>
|
||||
input.toLowerCase().includes(searchTerm.toLowerCase())
|
Loading…
Reference in New Issue