1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import * as React from 'react';
13 InputAdornment, Input,
14 List, ListItem, ListItemText
15 } from '@material-ui/core';
16 import SearchIcon from '@material-ui/icons/Search';
18 type CssRules = 'container' | 'input' | 'advanced' | 'searchQueryList' | 'list' | 'searchView' | 'searchBar';
20 const styles: StyleRulesCallback<CssRules> = theme => {
29 padding: `0px ${theme.spacing.unit}px`
33 justifyContent: 'flex-end',
34 paddingRight: theme.spacing.unit * 2,
35 paddingBottom: theme.spacing.unit,
39 padding: `${theme.spacing.unit / 2}px ${theme.spacing.unit}px `,
40 background: '#f2f2f2',
56 interface SearchBarDataProps {
60 interface SearchBarActionProps {
61 onSearch: (value: string) => any;
65 type SearchBarProps = SearchBarDataProps & SearchBarActionProps & WithStyles<CssRules>;
67 interface SearchBarState {
69 isSearchViewOpen: boolean;
72 export const DEFAULT_SEARCH_DEBOUNCE = 1000;
74 export const SearchBar = withStyles(styles)(
75 class extends React.Component<SearchBarProps> {
76 state: SearchBarState = {
78 isSearchViewOpen: false
84 const { classes } = this.props;
85 return <Paper className={classes.container} onBlur={this.closeSearchView}>
86 <form onSubmit={this.handleSubmit} className={classes.searchBar}>
88 className={classes.input}
89 onChange={this.handleChange}
91 value={this.state.value}
93 disableUnderline={true}
94 onFocus={this.openSearchView}
96 <InputAdornment position="end">
97 <Tooltip title='Search'>
104 {this.state.isSearchViewOpen
105 ? <Paper className={classes.searchView}>
106 <div className={classes.searchQueryList}>Saved search queries</div>
107 <List component="nav" className={classes.list}>
108 {this.renderListItem('Trash')}
109 {this.renderListItem('Spam')}
111 <div className={classes.searchQueryList}>Recent search queries</div>
112 <List component="nav" className={classes.list}>
113 {this.renderListItem('Trash')}
114 {this.renderListItem('Spam')}
116 <div className={classes.advanced}>Advanced</div>
122 componentDidMount() {
123 this.setState({ value: this.props.value });
126 componentWillReceiveProps(nextProps: SearchBarProps) {
127 if (nextProps.value !== this.props.value) {
128 this.setState({ value: nextProps.value });
132 componentWillUnmount() {
133 clearTimeout(this.timeout);
136 closeSearchView = () =>
137 this.setState({ isSearchViewOpen: false })
140 openSearchView = () =>
141 this.setState({ isSearchViewOpen: true })
144 renderListItem = (text: string) =>
146 <ListItemText secondary={text} />
149 handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
150 event.preventDefault();
151 clearTimeout(this.timeout);
152 this.props.onSearch(this.state.value);
155 handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
156 clearTimeout(this.timeout);
157 this.setState({ value: event.target.value });
158 this.timeout = window.setTimeout(
159 () => this.props.onSearch(this.state.value),
160 this.props.debounce || DEFAULT_SEARCH_DEBOUNCE