19311: Added check for initial clear
[arvados-workbench2.git] / src / components / search-input / search-input.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React from 'react';
6 import { IconButton, StyleRulesCallback, withStyles, WithStyles, FormControl, InputLabel, Input, InputAdornment, Tooltip } from '@material-ui/core';
7 import SearchIcon from '@material-ui/icons/Search';
8
9 type CssRules = 'container' | 'input' | 'button';
10
11 const styles: StyleRulesCallback<CssRules> = theme => {
12     return {
13         container: {
14             position: 'relative',
15             width: '100%'
16         },
17         input: {
18             border: 'none',
19             borderRadius: theme.spacing.unit / 4,
20             boxSizing: 'border-box',
21             padding: theme.spacing.unit,
22             paddingRight: theme.spacing.unit * 4,
23             width: '100%',
24         },
25         button: {
26             position: 'absolute',
27             top: theme.spacing.unit / 2,
28             right: theme.spacing.unit / 2,
29             width: theme.spacing.unit * 3,
30             height: theme.spacing.unit * 3
31         }
32     };
33 };
34
35 interface SearchInputDataProps {
36     value: string;
37     label?: string;
38     selfClearProp: string;
39 }
40
41 interface SearchInputActionProps {
42     onSearch: (value: string) => any;
43     debounce?: number;
44 }
45
46 type SearchInputProps = SearchInputDataProps & SearchInputActionProps & WithStyles<CssRules>;
47
48 interface SearchInputState {
49     value: string;
50     label: string;
51 }
52
53 let selfClearPropState = '';
54
55 export const DEFAULT_SEARCH_DEBOUNCE = 1000;
56
57 export const SearchInput = withStyles(styles)(
58     class extends React.Component<SearchInputProps> {
59         state: SearchInputState = {
60             value: "",
61             label: ""
62         };
63
64         timeout: number;
65
66         render() {
67             return <form onSubmit={this.handleSubmit}>
68                 <FormControl>
69                     <InputLabel>{this.state.label}</InputLabel>
70                     <Input
71                         type="text"
72                         data-cy="search-input"
73                         value={this.state.value}
74                         onChange={this.handleChange}
75                         endAdornment={
76                             <InputAdornment position="end">
77                                 <Tooltip title='Search'>
78                                     <IconButton
79                                         onClick={this.handleSubmit}>
80                                         <SearchIcon />
81                                     </IconButton>
82                                 </Tooltip>
83                             </InputAdornment>
84                         } />
85                 </FormControl>
86             </form>;
87         }
88
89         componentDidMount() {
90             this.setState({
91                 value: this.props.value,
92                 label: this.props.label || 'Search'
93             });
94         }
95
96         componentWillReceiveProps(nextProps: SearchInputProps) {
97             if (nextProps.value !== this.props.value) {
98                 this.setState({ value: nextProps.value });
99             }
100             if (this.state.value !== '' && nextProps.selfClearProp && nextProps.selfClearProp !== selfClearPropState) {
101                 if (selfClearPropState !== '') {
102                     this.props.onSearch('');
103                 }
104                 selfClearPropState = nextProps.selfClearProp;
105             }
106         }
107
108         componentWillUnmount() {
109             clearTimeout(this.timeout);
110         }
111
112         handleSubmit = (event: React.FormEvent<HTMLElement>) => {
113             event.preventDefault();
114             clearTimeout(this.timeout);
115             this.props.onSearch(this.state.value);
116         }
117
118         handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
119             clearTimeout(this.timeout);
120             this.setState({ value: event.target.value });
121             this.timeout = window.setTimeout(
122                 () => this.props.onSearch(this.state.value),
123                 this.props.debounce || DEFAULT_SEARCH_DEBOUNCE
124             );
125
126         }
127     }
128 );