import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; import { react2angular } from 'react2angular'; import { debounce, find } from 'lodash'; import Input from 'antd/lib/input'; import Select from 'antd/lib/select'; import { Query } from '@/services/query'; import { toastr } from '@/services/ng'; import { QueryTagsControl } from '@/components/tags-control/TagsControl'; const SEARCH_DEBOUNCE_DURATION = 200; const { Option } = Select; class StaleSearchError extends Error { constructor() { super('stale search'); } } function search(term) { // get recent if (!term) { return Query.recent().$promise .then((results) => { const filteredResults = results.filter(item => !item.is_draft); // filter out draft return Promise.resolve(filteredResults); }); } // search by query return Query.query({ q: term }).$promise .then(({ results }) => Promise.resolve(results)); } export function QuerySelector(props) { const [searchTerm, setSearchTerm] = useState(); const [searching, setSearching] = useState(); const [searchResults, setSearchResults] = useState([]); const [selectedQuery, setSelectedQuery] = useState(); let isStaleSearch = false; const debouncedSearch = debounce(_search, SEARCH_DEBOUNCE_DURATION); const placeholder = 'Search a query by name'; const clearIcon = selectQuery(null)} />; const spinIcon = ; // set selected from prop useEffect(() => { if (props.selectedQuery) { setSelectedQuery(props.selectedQuery); } }, [props.selectedQuery]); // on search term changed, debounced useEffect(() => { // clear results, no search if (searchTerm === null) { setSearchResults(null); return () => {}; } // search debouncedSearch(searchTerm); return () => { debouncedSearch.cancel(); isStaleSearch = true; }; }, [searchTerm]); function _search(term) { setSearching(true); search(term) .then(rejectStale) .then((results) => { setSearchResults(results); setSearching(false); }) .catch((err) => { if (!(err instanceof StaleSearchError)) { setSearching(false); } }); } function rejectStale(results) { return isStaleSearch ? Promise.reject(new StaleSearchError()) : Promise.resolve(results); } function selectQuery(queryId) { let query = null; if (queryId) { query = find(searchResults, { id: queryId }); if (!query) { // shouldn't happen toastr.error('Something went wrong... Couldn\'t select query'); } } setSearchTerm(query ? null : ''); // empty string triggers recent fetch setSelectedQuery(query); props.onChange(query); } function renderResults() { if (!searchResults.length) { return
No results matching search term.
; } return (
{searchResults.map(q => ( selectQuery(q.id)} > {q.name} {' '} ))}
); } if (props.disabled) { return ; } if (props.type === 'select') { const suffixIcon = selectedQuery ? clearIcon : null; const value = selectedQuery ? selectedQuery.name : searchTerm; return ( ); } return ( {selectedQuery ? ( ) : ( setSearchTerm(e.target.value)} suffix={spinIcon} /> )}
{searchResults && renderResults()}
); } QuerySelector.propTypes = { onChange: PropTypes.func.isRequired, selectedQuery: PropTypes.object, // eslint-disable-line react/forbid-prop-types type: PropTypes.oneOf(['select', 'default']), disabled: PropTypes.bool, }; QuerySelector.defaultProps = { selectedQuery: null, type: 'default', disabled: false, }; export default function init(ngModule) { ngModule.component('querySelector', react2angular(QuerySelector)); } init.init = true;