import {Fragment, useCallback, useMemo} from 'react'; import styled from '@emotion/styled'; import Access from 'sentry/components/acl/access'; import Badge from 'sentry/components/badge'; import Button from 'sentry/components/button'; import Confirm from 'sentry/components/confirm'; import DropdownButton from 'sentry/components/dropdownButton'; import CompactSelect from 'sentry/components/forms/compactSelect'; import {ControlProps} from 'sentry/components/forms/selectControl'; import QueryCount from 'sentry/components/queryCount'; import {IconDelete} from 'sentry/icons'; import {t} from 'sentry/locale'; import space from 'sentry/styles/space'; import {Organization, SavedSearch} from 'sentry/types'; import {defined} from 'sentry/utils'; import {getSortLabel} from './utils'; type Props = { onSavedSearchDelete: (savedSearch: SavedSearch) => void; onSavedSearchSelect: (savedSearch: SavedSearch) => void; organization: Organization; savedSearchList: SavedSearch[]; sort: string; isActive?: boolean; query?: string; queryCount?: number; }; function SavedSearchTab({ isActive, organization, savedSearchList, onSavedSearchSelect, onSavedSearchDelete, query, queryCount, sort, }: Props) { const savedSearch = savedSearchList.find( search => search.query === query && search.sort === sort ); const savedSearchValue = savedSearch ? savedSearch.isGlobal ? `global-search-${savedSearch.id}` : `saved-search-${savedSearch.id}` : ''; const options: ControlProps['options'] = useMemo(() => { const savedSearches = savedSearchList.filter(search => !search.isGlobal); const globalSearches = savedSearchList.filter( search => search.isGlobal && !search.isPinned && search.query !== 'is:unresolved' ); function getSearchOption(search, keyPrefix) { return { value: `${keyPrefix}-${search.id}`, label: search.name, details: (
{search.query} {` \u2022 ${t('Sort:')} ${getSortLabel(search.sort)}`}
), tooltip: ( {`${search.name} \u2022 `} {search.query} {` \u2022 `} {t('Sort: ')} {getSortLabel(search.sort)} ), tooltipOptions: {delay: 1000}, ...(!search.isPinned && !search.isGlobal && { trailingItems: ( onSavedSearchDelete(search)} message={t('Are you sure you want to delete this saved search?')} stopPropagation > } aria-label={t('delete')} size="zero" /> ), }), trailingItemsSpanFullHeight: true, }; } const searchOptions: ControlProps['options'] = []; if (savedSearches.length > 0) { searchOptions.push({ value: 'saved-searches', label: t('Saved Searches'), options: savedSearches.map(search => getSearchOption(search, 'saved-search')), }); } if (globalSearches.length > 0) { searchOptions.push({ value: 'global-searches', label: t('Recommended Searches'), options: globalSearches.map(search => getSearchOption(search, 'global-search')), }); } return searchOptions; }, []); const trigger = ({props, ref}) => ( {isActive ? ( {savedSearch ? savedSearch.name : t('Custom Search')}  {defined(queryCount) && queryCount > 0 && ( )} ) : ( t('Saved Searches') )} ); const onChange = useCallback( option => { const searchObj = savedSearchList.find(s => s.isGlobal ? `global-search-${s.id}` === option.value : `saved-search-${s.id}` === option.value ); searchObj && onSavedSearchSelect(searchObj); }, [savedSearchList, onSavedSearchSelect] ); return ( ); } export default SavedSearchTab; const StyledCompactSelect = styled(CompactSelect)<{isActive?: boolean}>` && { position: static; } border-bottom-width: 4px; border-bottom-style: solid; border-bottom-color: ${p => (p.isActive ? p.theme.active : 'transparent')}; `; const StyledDropdownTrigger = styled(DropdownButton)<{isActive?: boolean}>` display: flex; height: calc(1.25rem - 2px); align-items: center; color: ${p => (p.isActive ? p.theme.textColor : p.theme.subText)}; box-sizing: content-box; padding: ${space(1)} 0; &:hover { color: ${p => p.theme.textColor}; } `; const Details = styled('span')` font-family: ${p => p.theme.text.familyMono}; font-size: ${p => p.theme.fontSizeExtraSmall}; max-width: 16rem; ${p => p.theme.overflowEllipsis} `; const TooltipSearchQuery = styled('span')` color: ${p => p.theme.subText}; font-weight: normal; font-family: ${p => p.theme.text.familyMono}; `; const DeleteButton = styled(Button)` color: ${p => p.theme.subText}; flex-shrink: 0; padding: ${space(1)} 0; :hover { color: ${p => p.theme.error}; } `;