issueListSetAsDefault.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import {browserHistory} from 'react-router';
  2. import Button from 'sentry/components/button';
  3. import {removeSpace} from 'sentry/components/smartSearchBar/utils';
  4. import {IconBookmark} from 'sentry/icons';
  5. import {t} from 'sentry/locale';
  6. import {Organization, SavedSearchType} from 'sentry/types';
  7. import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
  8. import {useLocation} from 'sentry/utils/useLocation';
  9. import useOrganization from 'sentry/utils/useOrganization';
  10. import {usePinSearch} from 'sentry/views/issueList/mutations/usePinSearch';
  11. import {useUnpinSearch} from 'sentry/views/issueList/mutations/useUnpinSearch';
  12. import {useFetchSavedSearchesForOrg} from 'sentry/views/issueList/queries/useFetchSavedSearchesForOrg';
  13. import {isDefaultIssueStreamSearch} from 'sentry/views/issueList/utils';
  14. import {useSelectedSavedSearch} from 'sentry/views/issueList/utils/useSelectedSavedSearch';
  15. interface IssueListSetAsDefaultProps {
  16. organization: Organization;
  17. query: string;
  18. sort: string;
  19. }
  20. const usePinnedSearch = () => {
  21. const organization = useOrganization();
  22. const {data: savedSearches} = useFetchSavedSearchesForOrg(
  23. {orgSlug: organization.slug},
  24. {notifyOnChangeProps: ['data']}
  25. );
  26. return savedSearches?.find(savedSearch => savedSearch.isPinned) ?? null;
  27. };
  28. const IssueListSetAsDefault = ({
  29. organization,
  30. sort,
  31. query,
  32. }: IssueListSetAsDefaultProps) => {
  33. const location = useLocation();
  34. const selectedSavedSearch = useSelectedSavedSearch();
  35. const pinnedSearch = usePinnedSearch();
  36. const pinnedSearchActive = selectedSavedSearch
  37. ? pinnedSearch?.id === selectedSavedSearch?.id
  38. : false;
  39. const {mutate: pinSearch, isLoading: isPinning} = usePinSearch({
  40. onSuccess: response => {
  41. const {cursor: _cursor, page: _page, ...currentQuery} = location.query;
  42. browserHistory.replace({
  43. ...location,
  44. pathname: `/organizations/${organization.slug}/issues/searches/${response.id}/`,
  45. query: {referrer: 'search-bar', ...currentQuery},
  46. });
  47. },
  48. });
  49. const {mutate: unpinSearch, isLoading: isUnpinning} = useUnpinSearch({
  50. onSuccess: () => {
  51. const {cursor: _cursor, page: _page, ...currentQuery} = location.query;
  52. browserHistory.replace({
  53. ...location,
  54. pathname: `/organizations/${organization.slug}/issues/`,
  55. query: {
  56. referrer: 'search-bar',
  57. query,
  58. sort,
  59. ...currentQuery,
  60. },
  61. });
  62. },
  63. });
  64. const onTogglePinnedSearch = () => {
  65. trackAdvancedAnalyticsEvent('search.pin', {
  66. organization,
  67. action: pinnedSearch ? 'unpin' : 'pin',
  68. search_type: 'issues',
  69. query: pinnedSearch?.query ?? query,
  70. });
  71. if (pinnedSearchActive) {
  72. unpinSearch({orgSlug: organization.slug, type: SavedSearchType.ISSUE});
  73. } else {
  74. pinSearch({
  75. orgSlug: organization.slug,
  76. type: SavedSearchType.ISSUE,
  77. query: removeSpace(query),
  78. sort,
  79. });
  80. }
  81. };
  82. // Hide if we are already on the default search,
  83. // except when the user has a different search pinned.
  84. if (
  85. isDefaultIssueStreamSearch({query, sort}) &&
  86. (!pinnedSearch || isDefaultIssueStreamSearch(pinnedSearch))
  87. ) {
  88. return null;
  89. }
  90. return (
  91. <Button
  92. onClick={onTogglePinnedSearch}
  93. size="sm"
  94. icon={<IconBookmark isSolid={pinnedSearchActive} />}
  95. disabled={isPinning || isUnpinning}
  96. >
  97. {pinnedSearchActive ? t('Remove Default') : t('Set as Default')}
  98. </Button>
  99. );
  100. };
  101. export default IssueListSetAsDefault;