123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- import {Component} from 'react';
- import {withRouter, WithRouterProps} from 'react-router';
- import styled from '@emotion/styled';
- import debounce from 'lodash/debounce';
- import {Client, ResponseMeta} from 'sentry/api';
- import Input from 'sentry/components/input';
- import LoadingIndicator from 'sentry/components/loadingIndicator';
- import {t} from 'sentry/locale';
- type RenderProps = {
- busy: boolean;
- defaultSearchBar: React.ReactNode;
- handleChange: (value: string) => void;
- value: string;
- };
- type DefaultProps = {
-
- placeholder: string;
-
- debounceWait?: number;
- };
- type Props = WithRouterProps &
- DefaultProps & {
- api: Client;
- onError: () => void;
- onSuccess: (data: object, resp: ResponseMeta | undefined) => void;
-
- url: string;
-
- children?: (otps: RenderProps) => React.ReactNode;
- className?: string;
- onSearchSubmit?: (query: string, event: React.FormEvent) => void;
-
- updateRoute?: boolean;
- };
- type State = {
- busy: boolean;
- query: string;
- };
- class AsyncComponentSearchInput extends Component<Props, State> {
- static defaultProps: DefaultProps = {
- placeholder: t('Search...'),
- debounceWait: 200,
- };
- state: State = {
- query: '',
- busy: false,
- };
- immediateQuery = async (searchQuery: string) => {
- const {location, api} = this.props;
- this.setState({busy: true});
- try {
- const [data, , resp] = await api.requestPromise(`${this.props.url}`, {
- includeAllArgs: true,
- method: 'GET',
- query: {...location.query, query: searchQuery},
- });
-
- if (this.state.query === searchQuery) {
- this.props.onSuccess(data, resp);
- }
- } catch {
- this.props.onError();
- }
- this.setState({busy: false});
- };
- query = debounce(this.immediateQuery, this.props.debounceWait);
- handleChange = (query: string) => {
- this.query(query);
- this.setState({query});
- };
- handleInputChange = (evt: React.ChangeEvent<HTMLInputElement>) =>
- this.handleChange(evt.target.value);
-
- handleSearch = (evt: React.FormEvent<HTMLFormElement>) => {
- const {updateRoute, onSearchSubmit} = this.props;
- evt.preventDefault();
-
- if (updateRoute) {
- const {router, location} = this.props;
- router.push({
- pathname: location.pathname,
- query: {
- query: this.state.query,
- },
- });
- }
- if (typeof onSearchSubmit !== 'function') {
- return;
- }
- onSearchSubmit(this.state.query, evt);
- };
- render() {
- const {placeholder, children, className} = this.props;
- const {busy, query} = this.state;
- const defaultSearchBar = (
- <Form onSubmit={this.handleSearch}>
- <Input
- value={query}
- onChange={this.handleInputChange}
- className={className}
- placeholder={placeholder}
- />
- {busy && <StyledLoadingIndicator size={18} hideMessage mini />}
- </Form>
- );
- return children === undefined
- ? defaultSearchBar
- : children({defaultSearchBar, busy, value: query, handleChange: this.handleChange});
- }
- }
- const StyledLoadingIndicator = styled(LoadingIndicator)`
- position: absolute;
- right: 25px;
- top: 50%;
- transform: translateY(-13px);
- `;
- const Form = styled('form')`
- position: relative;
- `;
- export default withRouter(AsyncComponentSearchInput);
|