issueSearchWithSavedSearches.tsx 3.0 KB

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