Merge branch 'master' into 13969-advanced-tab
[arvados-workbench2.git] / src / views-components / search-bar / search-bar-view.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from 'react';
6 import {
7     IconButton,
8     Paper,
9     StyleRulesCallback,
10     withStyles,
11     WithStyles,
12     Tooltip,
13     InputAdornment, Input,
14     ClickAwayListener
15 } from '@material-ui/core';
16 import SearchIcon from '@material-ui/icons/Search';
17 import { ArvadosTheme } from '~/common/custom-theme';
18 import { SearchView } from '~/store/search-bar/search-bar-reducer';
19 import {
20     SearchBarBasicView,
21     SearchBarBasicViewDataProps,
22     SearchBarBasicViewActionProps
23 } from '~/views-components/search-bar/search-bar-basic-view';
24 import {
25     SearchBarAutocompleteView,
26     SearchBarAutocompleteViewDataProps,
27     SearchBarAutocompleteViewActionProps
28 } from '~/views-components/search-bar/search-bar-autocomplete-view';
29 import {
30     SearchBarAdvancedView,
31     SearchBarAdvancedViewDataProps,
32     SearchBarAdvancedViewActionProps
33 } from '~/views-components/search-bar/search-bar-advanced-view';
34
35 type CssRules = 'container' | 'containerSearchViewOpened' | 'input' | 'view';
36
37 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => {
38     return {
39         container: {
40             position: 'relative',
41             width: '100%',
42             borderRadius: theme.spacing.unit / 2
43         },
44         containerSearchViewOpened: {
45             position: 'relative',
46             width: '100%',
47             borderRadius: `${theme.spacing.unit / 2}px ${theme.spacing.unit / 2}px 0 0`
48         },
49         input: {
50             border: 'none',
51             padding: `0px ${theme.spacing.unit}px`
52         },
53         view: {
54             position: 'absolute',
55             width: '100%',
56             zIndex: 1
57         }
58     };
59 };
60
61 export type SearchBarDataProps = SearchBarViewDataProps
62     & SearchBarAutocompleteViewDataProps
63     & SearchBarAdvancedViewDataProps
64     & SearchBarBasicViewDataProps;
65
66 interface SearchBarViewDataProps {
67     searchValue: string;
68     currentView: string;
69     isPopoverOpen: boolean;
70     debounce?: number;
71 }
72
73 export type SearchBarActionProps = SearchBarViewActionProps
74     & SearchBarAutocompleteViewActionProps
75     & SearchBarAdvancedViewActionProps
76     & SearchBarBasicViewActionProps;
77
78 interface SearchBarViewActionProps {
79     onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
80     onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
81     onSetView: (currentView: string) => void;
82     closeView: () => void;
83     openSearchView: () => void;
84     loadRecentQueries: () => string[];
85 }
86
87 type SearchBarViewProps = SearchBarDataProps & SearchBarActionProps & WithStyles<CssRules>;
88
89 export const SearchBarView = withStyles(styles)(
90     (props : SearchBarViewProps) => {
91         const { classes, isPopoverOpen, closeView, searchValue, openSearchView, onChange, onSubmit } = props;
92         return (
93             <ClickAwayListener onClickAway={closeView}>
94                 <Paper className={isPopoverOpen ? classes.containerSearchViewOpened : classes.container} >
95                     <form onSubmit={onSubmit}>
96                         <Input
97                             className={classes.input}
98                             onChange={onChange}
99                             placeholder="Search"
100                             value={searchValue}
101                             fullWidth={true}
102                             disableUnderline={true}
103                             onClick={openSearchView}
104                             endAdornment={
105                                 <InputAdornment position="end">
106                                     <Tooltip title='Search'>
107                                         <IconButton>
108                                             <SearchIcon />
109                                         </IconButton>
110                                     </Tooltip>
111                                 </InputAdornment>
112                             } />
113                     </form>
114                     <div className={classes.view}>
115                         {isPopoverOpen && getView({...props})}
116                     </div>
117                 </Paper >
118             </ClickAwayListener>
119         );
120     }
121 );
122
123 const getView = (props: SearchBarViewProps) => {
124     const { onSetView, loadRecentQueries, savedQueries, deleteSavedQuery, searchValue,
125         searchResults, saveQuery, onSearch, navigateTo, editSavedQuery, tags, currentView } = props;
126     switch (currentView) {
127         case SearchView.AUTOCOMPLETE:
128             return <SearchBarAutocompleteView
129                 navigateTo={navigateTo}
130                 searchResults={searchResults}
131                 searchValue={searchValue} />;
132         case SearchView.ADVANCED:
133             return <SearchBarAdvancedView
134                 onSetView={onSetView}
135                 saveQuery={saveQuery}
136                 tags={tags} />;
137         default:
138             return <SearchBarBasicView
139                 onSetView={onSetView}
140                 onSearch={onSearch}
141                 loadRecentQueries={loadRecentQueries}
142                 savedQueries={savedQueries}
143                 deleteSavedQuery={deleteSavedQuery}
144                 editSavedQuery={editSavedQuery} />;
145     }
146 };