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 } from '@material-ui/core';
15 import SearchIcon from '@material-ui/icons/Search';
16 import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
17 import { ArvadosTheme } from '~/common/custom-theme';
18 import { SearchView } from '~/store/search-bar/search-bar-reducer';
21 SearchBarBasicViewDataProps,
22 SearchBarBasicViewActionProps
23 } from '~/views-components/search-bar/search-bar-basic-view';
25 SearchBarAutocompleteView,
26 SearchBarAutocompleteViewDataProps,
27 SearchBarAutocompleteViewActionProps
28 } from '~/views-components/search-bar/search-bar-autocomplete-view';
30 SearchBarAdvancedView,
31 SearchBarAdvancedViewDataProps,
32 SearchBarAdvancedViewActionProps
33 } from '~/views-components/search-bar/search-bar-advanced-view';
34 import { KEY_CODE_DOWN, KEY_CODE_ESC, KEY_CODE_UP, KEY_ENTER } from "~/common/codes";
36 type CssRules = 'container' | 'containerSearchViewOpened' | 'input' | 'view';
38 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => {
43 borderRadius: theme.spacing.unit / 2,
44 zIndex: theme.zIndex.modal,
46 containerSearchViewOpened: {
49 borderRadius: `${theme.spacing.unit / 2}px ${theme.spacing.unit / 2}px 0 0`,
50 zIndex: theme.zIndex.modal,
64 export type SearchBarDataProps = SearchBarViewDataProps
65 & SearchBarAutocompleteViewDataProps
66 & SearchBarAdvancedViewDataProps
67 & SearchBarBasicViewDataProps;
69 interface SearchBarViewDataProps {
72 isPopoverOpen: boolean;
76 export type SearchBarActionProps = SearchBarViewActionProps
77 & SearchBarAutocompleteViewActionProps
78 & SearchBarAdvancedViewActionProps
79 & SearchBarBasicViewActionProps;
81 interface SearchBarViewActionProps {
82 onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
83 onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
84 onSetView: (currentView: string) => void;
85 closeView: () => void;
86 openSearchView: () => void;
87 loadRecentQueries: () => string[];
90 setAdvancedDataFromSearchValue: (search: string) => void;
93 type SearchBarViewProps = SearchBarDataProps & SearchBarActionProps & WithStyles<CssRules>;
95 const handleKeyDown = (e: React.KeyboardEvent, props: SearchBarViewProps) => {
96 if (e.keyCode === KEY_CODE_DOWN) {
98 if (!props.isPopoverOpen) {
99 props.onSetView(SearchView.AUTOCOMPLETE);
100 props.openSearchView();
104 } else if (e.keyCode === KEY_CODE_UP) {
107 } else if (e.keyCode === KEY_CODE_ESC) {
110 } else if (e.keyCode === KEY_ENTER) {
111 if (props.currentView === SearchView.BASIC) {
113 props.onSearch(props.selectedItem.query);
114 } else if (props.currentView === SearchView.AUTOCOMPLETE) {
115 if (props.selectedItem.id !== props.searchValue) {
117 props.navigateTo(props.selectedItem.id);
123 const handleInputClick = (e: React.MouseEvent, props: SearchBarViewProps) => {
124 if (props.searchValue) {
125 props.onSetView(SearchView.AUTOCOMPLETE);
126 props.openSearchView();
132 const handleDropdownClick = (e: React.MouseEvent, props: SearchBarViewProps) => {
134 if (props.isPopoverOpen) {
135 if (props.currentView === SearchView.ADVANCED) {
138 props.setAdvancedDataFromSearchValue(props.searchValue);
139 props.onSetView(SearchView.ADVANCED);
142 props.setAdvancedDataFromSearchValue(props.searchValue);
143 props.onSetView(SearchView.ADVANCED);
147 export const SearchBarView = withStyles(styles)(
148 (props: SearchBarViewProps) => {
149 const { classes, isPopoverOpen } = props;
154 <Backdrop onClick={props.closeView} />}
156 <Paper className={isPopoverOpen ? classes.containerSearchViewOpened : classes.container} >
157 <form onSubmit={props.onSubmit}>
159 className={classes.input}
160 onChange={props.onChange}
162 value={props.searchValue}
164 disableUnderline={true}
165 onClick={e => handleInputClick(e, props)}
166 onKeyDown={e => handleKeyDown(e, props)}
168 <InputAdornment position="start">
169 <Tooltip title='Search'>
170 <IconButton type="submit">
177 <InputAdornment position="end">
178 <Tooltip title='Advanced search'>
179 <IconButton onClick={e => handleDropdownClick(e, props)}>
180 <ArrowDropDownIcon />
186 <div className={classes.view}>
187 {isPopoverOpen && getView({ ...props })}
195 const getView = (props: SearchBarViewProps) => {
196 switch (props.currentView) {
197 case SearchView.AUTOCOMPLETE:
198 return <SearchBarAutocompleteView
199 navigateTo={props.navigateTo}
200 searchResults={props.searchResults}
201 searchValue={props.searchValue}
202 selectedItem={props.selectedItem} />;
203 case SearchView.ADVANCED:
204 return <SearchBarAdvancedView
205 closeAdvanceView={props.closeAdvanceView}
207 saveQuery={props.saveQuery} />;
209 return <SearchBarBasicView
210 onSetView={props.onSetView}
211 onSearch={props.onSearch}
212 loadRecentQueries={props.loadRecentQueries}
213 savedQueries={props.savedQueries}
214 deleteSavedQuery={props.deleteSavedQuery}
215 editSavedQuery={props.editSavedQuery}
216 selectedItem={props.selectedItem} />;
220 const Backdrop = withStyles<'backdrop'>(theme => ({
227 zIndex: theme.zIndex.modal
230 ({ classes, ...props }: WithStyles<'backdrop'> & React.HTMLProps<HTMLDivElement>) =>
231 <div className={classes.backdrop} {...props} />);