issueSearchWithSavedSearches.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import styled from '@emotion/styled';
  2. import {Button, ButtonLabel} from 'sentry/components/button';
  3. import {t} from 'sentry/locale';
  4. import {trackAnalytics} from 'sentry/utils/analytics';
  5. import useOrganization from 'sentry/utils/useOrganization';
  6. import {useSyncedLocalStorageState} from 'sentry/utils/useSyncedLocalStorageState';
  7. import {SAVED_SEARCHES_SIDEBAR_OPEN_LOCALSTORAGE_KEY} from 'sentry/views/issueList/utils';
  8. import {useSelectedSavedSearch} from 'sentry/views/issueList/utils/useSelectedSavedSearch';
  9. import IssueListSearchBar from './searchBar';
  10. type IssueSearchWithSavedSearchesProps = {
  11. onSearch: (query: string) => void;
  12. query: string;
  13. className?: string;
  14. };
  15. export function IssueSearchWithSavedSearches({
  16. className,
  17. query,
  18. onSearch,
  19. }: IssueSearchWithSavedSearchesProps) {
  20. const organization = useOrganization();
  21. const selectedSavedSearch = useSelectedSavedSearch();
  22. const [isSavedSearchesOpen, setIsSavedSearchesOpen] = useSyncedLocalStorageState(
  23. SAVED_SEARCHES_SIDEBAR_OPEN_LOCALSTORAGE_KEY,
  24. false
  25. );
  26. function onSavedSearchesToggleClicked() {
  27. const newOpenState = !isSavedSearchesOpen;
  28. trackAnalytics('search.saved_search_sidebar_toggle_clicked', {
  29. organization,
  30. open: newOpenState,
  31. });
  32. setIsSavedSearchesOpen(newOpenState);
  33. }
  34. return (
  35. <SearchBarWithButtonContainer className={className}>
  36. {!organization.features.includes('issue-stream-custom-views') && (
  37. <StyledButton onClick={onSavedSearchesToggleClicked}>
  38. {selectedSavedSearch?.name ?? t('Custom Search')}
  39. </StyledButton>
  40. )}
  41. <StyledIssueListSearchBarWithButton
  42. searchSource="main_search"
  43. organization={organization}
  44. initialQuery={query || ''}
  45. onSearch={onSearch}
  46. placeholder={t('Search for events, users, tags, and more')}
  47. roundCorners={organization.features.includes('issue-stream-custom-views')}
  48. />
  49. </SearchBarWithButtonContainer>
  50. );
  51. }
  52. const SearchBarWithButtonContainer = styled('div')`
  53. flex: 1;
  54. display: flex;
  55. align-items: stretch;
  56. width: 100%;
  57. @media (min-width: ${p => p.theme.breakpoints.small}) {
  58. flex-basis: 35rem;
  59. }
  60. `;
  61. const StyledButton = styled(Button)`
  62. /* Hide this button on small screens */
  63. display: none;
  64. @media (min-width: ${p => p.theme.breakpoints.small}) {
  65. display: flex;
  66. align-items: center;
  67. height: 100%;
  68. max-width: 180px;
  69. text-align: left;
  70. border-top-right-radius: 0;
  71. border-bottom-right-radius: 0;
  72. border-right: none;
  73. ${ButtonLabel} {
  74. height: auto;
  75. display: block;
  76. ${p => p.theme.overflowEllipsis};
  77. }
  78. }
  79. `;
  80. const StyledIssueListSearchBarWithButton = styled(IssueListSearchBar)<{
  81. roundCorners: boolean;
  82. }>`
  83. flex: 1;
  84. min-width: 0;
  85. ${p =>
  86. !p.roundCorners &&
  87. `
  88. @media (min-width: ${p.theme.breakpoints.small}) {
  89. border-top-left-radius: 0;
  90. border-bottom-left-radius: 0;
  91. }
  92. `}
  93. `;