// eslint-disable-next-line no-restricted-imports import {browserHistory, withRouter, WithRouterProps} from 'react-router'; import styled from '@emotion/styled'; import {openModal} from 'sentry/actionCreators/modal'; import {pinSearch, unpinSearch} from 'sentry/actionCreators/savedSearches'; import Access from 'sentry/components/acl/access'; import Button from 'sentry/components/button'; import MenuItem from 'sentry/components/menuItem'; import CreateSavedSearchModal from 'sentry/components/modals/createSavedSearchModal'; import {IconAdd, IconPin, IconSliders} from 'sentry/icons'; import {t} from 'sentry/locale'; import {SavedSearch, SavedSearchType} from 'sentry/types'; import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent'; import SmartSearchBar from './index'; import {removeSpace} from './utils'; type SmartSearchBarProps = React.ComponentProps; type ActionItem = NonNullable[number]; type ActionProps = React.ComponentProps; type PinSearchActionOpts = { /** * The current issue sort */ sort: string; /** * The currently pinned search */ pinnedSearch?: SavedSearch; }; /** * The Pin Search action toggles the current as a pinned search */ export function makePinSearchAction({pinnedSearch, sort}: PinSearchActionOpts) { const PinSearchAction = ({ menuItemVariant, savedSearchType, organization, api, query, location, }: ActionProps & WithRouterProps) => { const onTogglePinnedSearch = async (evt: React.MouseEvent) => { evt.preventDefault(); evt.stopPropagation(); if (savedSearchType === undefined) { return; } const {cursor: _cursor, page: _page, ...currentQuery} = location.query; trackAdvancedAnalyticsEvent('search.pin', { organization, action: !!pinnedSearch ? 'unpin' : 'pin', search_type: savedSearchType === SavedSearchType.ISSUE ? 'issues' : 'events', query: pinnedSearch?.query ?? query, }); if (!!pinnedSearch) { unpinSearch(api, organization.slug, savedSearchType, pinnedSearch).then(() => { browserHistory.push({ ...location, pathname: `/organizations/${organization.slug}/issues/`, query: { ...currentQuery, query: pinnedSearch.query, sort: pinnedSearch.sort, }, }); }); return; } const resp = await pinSearch( api, organization.slug, savedSearchType, removeSpace(query), sort ); if (!resp || !resp.id) { return; } browserHistory.push({ ...location, pathname: `/organizations/${organization.slug}/issues/searches/${resp.id}/`, query: currentQuery, }); }; const pinTooltip = !!pinnedSearch ? t('Unpin this search') : t('Pin this search'); return menuItemVariant ? ( } onClick={onTogglePinnedSearch} > {!!pinnedSearch ? t('Unpin Search') : t('Pin Search')} ) : ( } /> ); }; return {key: 'pinSearch', Action: withRouter(PinSearchAction)}; } type SaveSearchActionOpts = { /** * The current issue sort */ sort: string; }; /** * The Save Search action triggers the create saved search modal from the * current query. */ export function makeSaveSearchAction({sort}: SaveSearchActionOpts) { const SavedSearchAction = ({menuItemVariant, query, organization}: ActionProps) => { const onClick = () => openModal(deps => ( )); return ( {({hasAccess}) => { const title = hasAccess ? t('Add to organization saved searches') : t('You do not have permission to create a saved search'); return menuItemVariant ? ( } title={!hasAccess ? title : undefined} withBorder > {t('Create Saved Search')} ) : ( } title={title} aria-label={title} data-test-id="save-current-search" /> ); }} ); }; return {key: 'saveSearch', Action: SavedSearchAction}; } type SearchBuilderActionOpts = { onSidebarToggle: React.MouseEventHandler; }; /** * The Search Builder action toggles the Issue Stream search builder */ export function makeSearchBuilderAction({onSidebarToggle}: SearchBuilderActionOpts) { const SearchBuilderAction = ({menuItemVariant}: ActionProps) => menuItemVariant ? ( } onClick={onSidebarToggle}> {t('Toggle sidebar')} ) : ( } /> ); return {key: 'searchBuilder', Action: SearchBuilderAction}; } export const ActionButton = styled(Button)<{isActive?: boolean}>` color: ${p => (p.isActive ? p.theme.blue300 : p.theme.gray300)}; width: 18px; &, &:hover, &:focus { background: transparent; } &:hover { color: ${p => p.theme.gray400}; } `; ActionButton.defaultProps = { type: 'button', borderless: true, size: 'zero', };