Merge branch '21611-log-chunk-delay'
[arvados.git] / services / workbench2 / 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, {useState, useEffect} from 'react';
6 import {
7     IconButton,
8     FormControl,
9     InputLabel,
10     Input,
11     InputAdornment,
12     Tooltip,
13 } from '@material-ui/core';
14 import SearchIcon from '@material-ui/icons/Search';
15
16 interface SearchInputDataProps {
17     value: string;
18     label?: string;
19     selfClearProp: string;
20 }
21
22 interface SearchInputActionProps {
23     onSearch: (value: string) => any;
24     debounce?: number;
25 }
26
27 type SearchInputProps = SearchInputDataProps & SearchInputActionProps;
28
29 export const DEFAULT_SEARCH_DEBOUNCE = 1000;
30
31 export const SearchInput = (props: SearchInputProps) => {
32     const [timeout, setTimeout] = useState(0);
33     const [value, setValue] = useState("");
34     const [label, setLabel] = useState("Search");
35     const [selfClearProp, setSelfClearProp] = useState("");
36
37     useEffect(() => {
38         if (props.value) {
39             setValue(props.value);
40         }
41         if (props.label) {
42             setLabel(props.label);
43         }
44
45         return () => {
46             setValue("");
47             clearTimeout(timeout);
48         };
49         // eslint-disable-next-line react-hooks/exhaustive-deps
50     }, [props.value, props.label]); 
51
52     useEffect(() => {
53         if (selfClearProp !== props.selfClearProp) {
54             setValue("");
55             setSelfClearProp(props.selfClearProp);
56             handleChange({ target: { value: "" } } as any);
57         }
58         // eslint-disable-next-line react-hooks/exhaustive-deps
59     }, [props.selfClearProp]); 
60
61     const handleSubmit = (event: React.FormEvent<HTMLElement>) => {
62         event.preventDefault();
63         clearTimeout(timeout);
64         props.onSearch(value);
65     };
66
67     const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
68         const { target: { value: eventValue } } = event;
69         clearTimeout(timeout);
70         setValue(eventValue);
71
72         setTimeout(window.setTimeout(
73             () => {
74                 props.onSearch(eventValue);
75             },
76             props.debounce || DEFAULT_SEARCH_DEBOUNCE
77         ));
78     };
79
80     return <form onSubmit={handleSubmit}>
81         <FormControl style={{ width: '14rem'}}>
82             <InputLabel>{label}</InputLabel>
83             <Input
84                 type="text"
85                 data-cy="search-input"
86                 value={value}
87                 onChange={handleChange}
88                 endAdornment={
89                     <InputAdornment position="end">
90                         <Tooltip title='Search'>
91                             <IconButton
92                                 onClick={handleSubmit}>
93                                 <SearchIcon />
94                             </IconButton>
95                         </Tooltip>
96                     </InputAdornment>
97                 } />
98         </FormControl>
99     </form>;
100 };