diff --git a/client/src/components/Logs/Filters/Form.tsx b/client/src/components/Logs/Filters/Form.tsx index f1b5b7be..317062e0 100644 --- a/client/src/components/Logs/Filters/Form.tsx +++ b/client/src/components/Logs/Filters/Form.tsx @@ -1,15 +1,14 @@ import React, { useEffect } from 'react'; -import { Field, type InjectedFormProps, reduxForm } from 'redux-form'; import { useTranslation } from 'react-i18next'; -import { shallowEqual, useDispatch, useSelector } from 'react-redux'; +import { useDispatch } from 'react-redux'; import { useHistory } from 'react-router-dom'; import classNames from 'classnames'; +import { useForm } from 'react-hook-form'; import { DEBOUNCE_FILTER_TIMEOUT, DEFAULT_LOGS_FILTER, - FORM_NAME, RESPONSE_FILTER, RESPONSE_FILTER_QUERIES, } from '../../../helpers/constants'; @@ -18,182 +17,115 @@ import useDebounce from '../../../helpers/useDebounce'; import { createOnBlurHandler, getLogsUrlParams } from '../../../helpers/helpers'; -import Tooltip from '../../ui/Tooltip'; -import { RootState } from '../../../initialState'; +import { SearchField } from './SearchField'; -interface renderFilterFieldProps { - input: { - value: string; - }; - id: string; - onClearInputClick: (...args: unknown[]) => unknown; - className?: string; - placeholder?: string; - type?: string; - disabled?: boolean; - autoComplete?: string; - tooltip?: string; - onKeyDown?: (...args: unknown[]) => unknown; - normalizeOnBlur?: (...args: unknown[]) => unknown; - meta: { - touched?: boolean; - error?: object; - }; +export type FormValues = { + search: string; + response_status: string; } -const renderFilterField = ({ - input, - id, - className, - placeholder, - type, - disabled, - autoComplete, - tooltip, - meta: { touched, error }, - onClearInputClick, - onKeyDown, - normalizeOnBlur, -}: renderFilterFieldProps) => { - const onBlur = (event: any) => createOnBlurHandler(event, input, normalizeOnBlur); - - return ( - <> -
- - - -
- - - -
- - - -
- - - - - - - - - {!disabled && touched && error && {error}} - - ); -}; - -const FORM_NAMES = { - search: 'search', - response_status: 'response_status', -}; - -type FiltersFormProps = { +type Props = { + initialValues: FormValues; className?: string; - responseStatusClass?: string; setIsLoading: (...args: unknown[]) => unknown; }; -const Form = (props: FiltersFormProps & InjectedFormProps) => { - const { className = '', responseStatusClass, setIsLoading, change } = props; - +export const Form = ({ initialValues, className, setIsLoading }: Props) => { const { t } = useTranslation(); const dispatch = useDispatch(); const history = useHistory(); - const { response_status, search } = useSelector( - (state: RootState) => state?.form[FORM_NAME.LOGS_FILTER].values, - shallowEqual, - ); + const { + register, + watch, + setValue, + } = useForm({ + mode: 'onChange', + defaultValues: { + search: initialValues.search || DEFAULT_LOGS_FILTER.search, + response_status: initialValues.response_status || DEFAULT_LOGS_FILTER.response_status, + }, + }); - const [debouncedSearch, setDebouncedSearch] = useDebounce(search.trim(), DEBOUNCE_FILTER_TIMEOUT); + const searchValue = watch('search'); + const responseStatusValue = watch('response_status'); + + const [debouncedSearch, setDebouncedSearch] = useDebounce( + searchValue.trim(), + DEBOUNCE_FILTER_TIMEOUT + ); useEffect(() => { dispatch( setLogsFilter({ - response_status, + response_status: responseStatusValue, search: debouncedSearch, }), ); - history.replace(`${getLogsUrlParams(debouncedSearch, response_status)}`); - }, [response_status, debouncedSearch]); + history.replace(`${getLogsUrlParams(debouncedSearch, responseStatusValue)}`); + }, [responseStatusValue, debouncedSearch]); - if (response_status && !(response_status in RESPONSE_FILTER_QUERIES)) { - change(FORM_NAMES.response_status, DEFAULT_LOGS_FILTER[FORM_NAMES.response_status]); - } + useEffect(() => { + if (responseStatusValue && !(responseStatusValue in RESPONSE_FILTER_QUERIES)) { + setValue('response_status', DEFAULT_LOGS_FILTER.response_status); + } + }, [responseStatusValue, setValue]); const onInputClear = async () => { setIsLoading(true); - change(FORM_NAMES.search, DEFAULT_LOGS_FILTER[FORM_NAMES.search]); + setValue('search', DEFAULT_LOGS_FILTER.search); setIsLoading(false); }; - const onEnterPress = (e: any) => { + const onEnterPress = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { - setDebouncedSearch(search); + setDebouncedSearch(searchValue); } }; - const normalizeOnBlur = (data: any) => data.trim(); + const handleBlur = (e: React.FocusEvent) => + createOnBlurHandler( + e, + { + value: e.target.value, + onChange: (v: string) => setValue('search', v), + }, + (data: string) => data.trim() + ); return (
{ e.preventDefault(); - }}> + }} + >
- setValue('search', val)} + onBlur={handleBlur} + onKeyDown={onEnterPress} + onClear={onInputClear} placeholder={t('domain_or_client')} tooltip={t('query_log_strict_search')} - onClearInputClick={onInputClear} - onKeyDown={onEnterPress} - normalizeOnBlur={normalizeOnBlur} + className={classNames('form-control form-control--search form-control--transparent', className)} />
- +
); }; - -export const FiltersForm = reduxForm, FiltersFormProps>({ - form: FORM_NAME.LOGS_FILTER, - enableReinitialize: true, -})(Form); diff --git a/client/src/components/Logs/Filters/SearchField.tsx b/client/src/components/Logs/Filters/SearchField.tsx new file mode 100644 index 00000000..1113bba0 --- /dev/null +++ b/client/src/components/Logs/Filters/SearchField.tsx @@ -0,0 +1,56 @@ +import React, { ComponentProps } from 'react'; +import Tooltip from '../../ui/Tooltip'; + +interface Props extends ComponentProps<'input'> { + handleChange: (newValue: string) => void; + onClear: () => void; + tooltip?: string; +} + +export const SearchField = ({ + handleChange, + onClear, + value, + tooltip, + className, + ...rest +}: Props) => { + const handleInputChange = (e: React.ChangeEvent) => { + handleChange(e.target.value); + }; + + return ( + <> +
+ + + +
+ + {typeof value === 'string' && value.length > 0 && ( +
+ + + +
+ )} + {tooltip && ( + + + + + + + + )} + + ); +}; diff --git a/client/src/components/Logs/Filters/index.tsx b/client/src/components/Logs/Filters/index.tsx index dfdbf3ec..d2c5c37a 100644 --- a/client/src/components/Logs/Filters/index.tsx +++ b/client/src/components/Logs/Filters/index.tsx @@ -2,17 +2,17 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; -import { FiltersForm } from './Form'; +import { Form, FormValues } from './Form'; import { refreshFilteredLogs } from '../../../actions/queryLogs'; import { addSuccessToast } from '../../../actions/toasts'; interface FiltersProps { - filter: object; + initialValues: FormValues; processingGetLogs: boolean; setIsLoading: (...args: unknown[]) => unknown; } -const Filters = ({ filter, setIsLoading }: FiltersProps) => { +const Filters = ({ initialValues, setIsLoading }: FiltersProps) => { const { t } = useTranslation(); const dispatch = useDispatch(); @@ -38,7 +38,10 @@ const Filters = ({ filter, setIsLoading }: FiltersProps) => { - +
); }; diff --git a/client/src/components/Logs/index.tsx b/client/src/components/Logs/index.tsx index b98bc6f9..63bc557f 100644 --- a/client/src/components/Logs/index.tsx +++ b/client/src/components/Logs/index.tsx @@ -175,7 +175,7 @@ const Logs = () => { const renderPage = () => ( <>