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, SearchBarAutocompleteViewDataProps } from '~/views-components/search-bar/search-bar-autocomplete-view';
23 import { ArvadosTheme } from '~/common/custom-theme';
25 type CssRules = 'container' | 'containerSearchViewOpened' | 'input' | 'searchBar' | 'view';
27 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => {
32 borderRadius: theme.spacing.unit / 4
34 containerSearchViewOpened: {
37 borderRadius: `${theme.spacing.unit / 4}px ${theme.spacing.unit / 4}px 0 0`
41 padding: `0px ${theme.spacing.unit}px`
54 type SearchBarDataProps = {
57 isPopoverOpen: boolean;
58 savedQueries: string[];
59 } & SearchBarAutocompleteViewDataProps;
61 interface SearchBarActionProps {
62 onSearch: (value: string) => any;
64 onSetView: (currentView: string) => void;
66 closeView: () => void;
67 saveRecentQuery: (query: string) => void;
68 loadRecentQueries: () => string[];
69 saveQuery: (query: string) => void;
70 deleteSavedQuery: (id: number) => void;
73 type SearchBarProps = SearchBarDataProps & SearchBarActionProps & WithStyles<CssRules>;
75 interface SearchBarState {
79 interface RenderSavedQueriesProps {
80 text: string | JSX.Element;
82 deleteSavedQuery: (id: number) => void;
85 interface RenderRecentQueriesProps {
86 text: string | JSX.Element;
89 export const RecentQueriesItem = (props: RenderRecentQueriesProps) => {
90 return <ListItem button>
91 <ListItemText secondary={props.text} />
96 export const RenderSavedQueries = (props: RenderSavedQueriesProps) => {
97 return <ListItem button>
98 <ListItemText secondary={props.text} />
99 <ListItemSecondaryAction>
100 <Tooltip title="Remove">
101 <IconButton aria-label="Remove" onClick={() => props.deleteSavedQuery(props.id)}>
105 </ListItemSecondaryAction>
109 export const DEFAULT_SEARCH_DEBOUNCE = 1000;
111 export const SearchBarView = withStyles(styles)(
112 class extends React.Component<SearchBarProps> {
113 state: SearchBarState = {
120 const { classes, currentView, openView, closeView, isPopoverOpen } = this.props;
121 return <ClickAwayListener onClickAway={() => closeView()}>
122 <Paper className={isPopoverOpen ? classes.containerSearchViewOpened : classes.container} >
123 <form onSubmit={this.handleSubmit} className={classes.searchBar}>
125 className={classes.input}
126 onChange={this.handleChange}
128 value={this.state.value}
130 disableUnderline={true}
131 onClick={() => openView()}
133 <InputAdornment position="end">
134 <Tooltip title='Search'>
142 <div className={classes.view}>
143 {isPopoverOpen && this.getView(currentView)}
146 </ClickAwayListener>;
149 componentDidMount() {
150 this.setState({ value: this.props.searchValue });
153 componentWillReceiveProps(nextProps: SearchBarProps) {
154 if (nextProps.searchValue !== this.props.searchValue) {
155 this.setState({ value: nextProps.searchValue });
159 componentWillUnmount() {
160 clearTimeout(this.timeout);
163 getView = (currentView: string) => {
164 const { onSetView, loadRecentQueries, savedQueries, deleteSavedQuery, searchValue, searchResults } = this.props;
165 switch (currentView) {
166 case SearchView.BASIC:
167 return <SearchBarBasicView setView={onSetView} recentQueries={loadRecentQueries} savedQueries={savedQueries} deleteSavedQuery={deleteSavedQuery} />;
168 case SearchView.ADVANCED:
169 return <SearchBarAdvancedView setView={onSetView} />;
170 case SearchView.AUTOCOMPLETE:
171 return <SearchBarAutocompleteView
172 searchResults={searchResults}
173 searchValue={searchValue} />;
175 return <SearchBarBasicView setView={onSetView} recentQueries={loadRecentQueries} savedQueries={savedQueries} deleteSavedQuery={deleteSavedQuery} />;
179 handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
180 event.preventDefault();
181 clearTimeout(this.timeout);
182 this.props.saveRecentQuery(this.state.value);
183 this.props.saveQuery(this.state.value);
184 this.props.onSearch(this.state.value);
185 this.props.loadRecentQueries();
188 handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
189 clearTimeout(this.timeout);
190 this.setState({ value: event.target.value });
191 this.timeout = window.setTimeout(
192 () => this.props.onSearch(this.state.value),
193 this.props.debounce || DEFAULT_SEARCH_DEBOUNCE
195 if (event.target.value.length > 0) {
196 this.props.onSetView(SearchView.AUTOCOMPLETE);
198 this.props.onSetView(SearchView.BASIC);