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 ListItem, ListItemText, ListItemSecondaryAction,
16 } from '@material-ui/core';
17 import SearchIcon from '@material-ui/icons/Search';
18 import { RemoveIcon } from '~/components/icon/icon';
19 import { SearchView } from '~/store/search-bar/search-bar-reducer';
20 import { SearchBarBasicView } from '~/views-components/search-bar/search-bar-basic-view';
21 import { SearchBarAdvancedView } from '~/views-components/search-bar/search-bar-advanced-view';
22 import { SearchBarAutocompleteView } from '~/views-components/search-bar/search-bar-autocomplete-view';
24 type CssRules = 'container' | 'containerSearchViewOpened' | 'input' | 'searchBar';
26 const styles: StyleRulesCallback<CssRules> = theme => {
31 borderRadius: theme.spacing.unit / 4
33 containerSearchViewOpened: {
36 borderRadius: `${theme.spacing.unit / 4}px ${theme.spacing.unit / 4}px 0 0`
40 padding: `0px ${theme.spacing.unit}px`
48 interface SearchBarDataProps {
54 interface SearchBarActionProps {
55 onSearch: (value: string) => any;
57 onSetView: (currentView: string) => void;
59 closeView: () => void;
60 saveQuery: (query: string) => void;
61 loadQueries: () => string[];
64 type SearchBarProps = SearchBarDataProps & SearchBarActionProps & WithStyles<CssRules>;
66 interface SearchBarState {
70 interface RenderQueriesProps {
74 export const RenderRecentQueries = (props: RenderQueriesProps) => {
75 return <ListItem button>
76 <ListItemText secondary={props.text} />
81 export const RenderSavedQueries = (props: RenderQueriesProps) => {
82 return <ListItem button>
83 <ListItemText secondary={props.text} />
84 <ListItemSecondaryAction>
85 <Tooltip title="Remove">
86 <IconButton aria-label="Remove">
90 </ListItemSecondaryAction>
94 export const DEFAULT_SEARCH_DEBOUNCE = 1000;
96 export const SearchBarView = withStyles(styles)(
97 class extends React.Component<SearchBarProps> {
98 state: SearchBarState = {
105 const { classes, currentView, openView, closeView, open } = this.props;
106 return <ClickAwayListener onClickAway={() => closeView()}>
107 <Paper className={open ? classes.containerSearchViewOpened : classes.container} >
108 <form onSubmit={this.handleSubmit} className={classes.searchBar}>
110 className={classes.input}
111 onChange={this.handleChange}
113 value={this.state.value}
115 disableUnderline={true}
116 onClick={() => openView()}
118 <InputAdornment position="end">
119 <Tooltip title='Search'>
126 {open && this.getView(currentView)}
129 </ClickAwayListener>;
132 componentDidMount() {
133 this.setState({ value: this.props.value });
136 componentWillReceiveProps(nextProps: SearchBarProps) {
137 if (nextProps.value !== this.props.value) {
138 this.setState({ value: nextProps.value });
142 componentWillUnmount() {
143 clearTimeout(this.timeout);
146 getView = (currentView: string) => {
147 switch (currentView) {
148 case SearchView.BASIC:
149 return <SearchBarBasicView setView={this.props.onSetView} recentQueries={this.props.loadQueries} />;
150 case SearchView.ADVANCED:
151 return <SearchBarAdvancedView setView={this.props.onSetView} />;
152 case SearchView.AUTOCOMPLETE:
153 return <SearchBarAutocompleteView />;
155 return <SearchBarBasicView setView={this.props.onSetView} recentQueries={this.props.loadQueries} />;
159 handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
160 event.preventDefault();
161 clearTimeout(this.timeout);
162 this.props.saveQuery(this.state.value);
163 this.props.onSearch(this.state.value);
164 this.props.loadQueries();
167 handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
168 clearTimeout(this.timeout);
169 this.setState({ value: event.target.value });
170 this.timeout = window.setTimeout(
171 () => this.props.onSearch(this.state.value),
172 this.props.debounce || DEFAULT_SEARCH_DEBOUNCE
174 if (event.target.value.length > 0) {
175 this.props.onSetView(SearchView.AUTOCOMPLETE);
177 this.props.onSetView(SearchView.BASIC);