// Copyright (C) The Arvados Authors. All rights reserved. // // SPDX-License-Identifier: AGPL-3.0 import * as React from 'react'; import { IconButton, Paper, StyleRulesCallback, withStyles, WithStyles, Tooltip, InputAdornment, Input, ListItem, ListItemText, ListItemSecondaryAction, ClickAwayListener } from '@material-ui/core'; import SearchIcon from '@material-ui/icons/Search'; import { RemoveIcon, EditSavedQueryIcon } from '~/components/icon/icon'; import { SearchView } from '~/store/search-bar/search-bar-reducer'; import { SearchBarBasicView } from '~/views-components/search-bar/search-bar-basic-view'; import { SearchBarAdvancedView } from '~/views-components/search-bar/search-bar-advanced-view'; import { SearchBarAutocompleteView, SearchBarAutocompleteViewDataProps } from '~/views-components/search-bar/search-bar-autocomplete-view'; import { ArvadosTheme } from '~/common/custom-theme'; import { SearchBarAdvanceFormData } from '~/models/search-bar'; type CssRules = 'container' | 'containerSearchViewOpened' | 'input' | 'view'; const styles: StyleRulesCallback = (theme: ArvadosTheme) => { return { container: { position: 'relative', width: '100%', borderRadius: theme.spacing.unit / 2 }, containerSearchViewOpened: { position: 'relative', width: '100%', borderRadius: `${theme.spacing.unit / 2}px ${theme.spacing.unit / 2}px 0 0` }, input: { border: 'none', padding: `0px ${theme.spacing.unit}px` }, view: { position: 'absolute', width: '100%', zIndex: 1 } }; }; type SearchBarDataProps = { searchValue: string; currentView: string; isPopoverOpen: boolean; savedQueries: SearchBarAdvanceFormData[]; } & SearchBarAutocompleteViewDataProps; interface SearchBarActionProps { onSearch: (value: string) => any; searchDataOnEnter: (value: string) => void; debounce?: number; onSetView: (currentView: string) => void; closeView: () => void; saveRecentQuery: (query: string) => void; loadRecentQueries: () => string[]; saveQuery: (data: SearchBarAdvanceFormData) => void; deleteSavedQuery: (id: number) => void; openSearchView: () => void; navigateTo: (uuid: string) => void; editSavedQuery: (data: SearchBarAdvanceFormData, id: number) => void; } type SearchBarProps = SearchBarDataProps & SearchBarActionProps & WithStyles; interface SearchBarState { value: string; } interface RenderRecentQueriesProps { text: string; onSearch: (searchValue: string) => void; } export const RenderRecentQueries = (props: RenderRecentQueriesProps) => { return props.onSearch(props.text)} /> ; }; interface RenderAutocompleteItemsProps { text: string | JSX.Element; navigateTo: (uuid: string) => void; uuid: string; } export const RenderAutocompleteItems = (props: RenderAutocompleteItemsProps) => { return props.navigateTo(props.uuid)} /> ; }; interface RenderSavedQueriesProps { text: string; id: number; deleteSavedQuery: (id: number) => void; onSearch: (searchValue: string) => void; editSavedQuery: (data: SearchBarAdvanceFormData, id: number) => void; data: SearchBarAdvanceFormData; } export const RenderSavedQueries = (props: RenderSavedQueriesProps) => { return props.onSearch(props.text)} /> props.editSavedQuery(props.data, props.id)}> props.deleteSavedQuery(props.id)}> ; }; export const DEFAULT_SEARCH_DEBOUNCE = 1000; export const SearchBarView = withStyles(styles)( class extends React.Component { state: SearchBarState = { value: "" }; timeout: number; render() { const { classes, currentView, openSearchView, closeView, isPopoverOpen } = this.props; return
} />
{isPopoverOpen && this.getView(currentView)}
; } componentDidMount() { this.setState({ value: this.props.searchValue }); } componentWillReceiveProps(nextProps: SearchBarProps) { if (nextProps.searchValue !== this.props.searchValue) { this.setState({ value: nextProps.searchValue }); } } componentWillUnmount() { clearTimeout(this.timeout); } getView = (currentView: string) => { const { onSetView, loadRecentQueries, savedQueries, deleteSavedQuery, searchValue, searchResults, saveQuery, onSearch, navigateTo, editSavedQuery } = this.props; switch (currentView) { case SearchView.BASIC: return ; case SearchView.ADVANCED: return ; case SearchView.AUTOCOMPLETE: return ; default: return ; } } handleSubmit = (event: React.FormEvent) => { event.preventDefault(); clearTimeout(this.timeout); this.props.saveRecentQuery(this.state.value); this.props.searchDataOnEnter(this.state.value); this.props.loadRecentQueries(); } handleChange = (event: React.ChangeEvent) => { clearTimeout(this.timeout); this.setState({ value: event.target.value }); this.timeout = window.setTimeout( () => this.props.onSearch(this.state.value), this.props.debounce || DEFAULT_SEARCH_DEBOUNCE ); if (event.target.value.length > 0) { this.props.onSetView(SearchView.AUTOCOMPLETE); } else { this.props.onSetView(SearchView.BASIC); } } } );