createSavedSearchModal.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import {useState} from 'react';
  2. import {addLoadingMessage, clearIndicators} from 'sentry/actionCreators/indicator';
  3. import {ModalRenderProps} from 'sentry/actionCreators/modal';
  4. import {Alert} from 'sentry/components/alert';
  5. import {Form} from 'sentry/components/forms';
  6. import {OnSubmitCallback} from 'sentry/components/forms/types';
  7. import {SavedSearchModalContent} from 'sentry/components/modals/savedSearchModal/savedSearchModalContent';
  8. import {t} from 'sentry/locale';
  9. import {Organization, SavedSearchType, SavedSearchVisibility} from 'sentry/types';
  10. import {trackAnalytics} from 'sentry/utils/analytics';
  11. import {useCreateSavedSearch} from 'sentry/views/issueList/mutations/useCreateSavedSearch';
  12. import {IssueSortOptions} from 'sentry/views/issueList/utils';
  13. interface CreateSavedSearchModalProps extends ModalRenderProps {
  14. organization: Organization;
  15. query: string;
  16. sort?: string;
  17. }
  18. const DEFAULT_SORT_OPTIONS = [
  19. IssueSortOptions.DATE,
  20. IssueSortOptions.NEW,
  21. IssueSortOptions.FREQ,
  22. IssueSortOptions.PRIORITY,
  23. IssueSortOptions.USER,
  24. ];
  25. function getSortOptions(organization: Organization) {
  26. return organization?.features?.includes('issue-list-trend-sort')
  27. ? [...DEFAULT_SORT_OPTIONS, IssueSortOptions.TREND]
  28. : DEFAULT_SORT_OPTIONS;
  29. }
  30. function validateSortOption({
  31. organization,
  32. sort,
  33. }: {
  34. organization: Organization;
  35. sort?: string;
  36. }) {
  37. if (getSortOptions(organization).find(option => option === sort)) {
  38. return sort as string;
  39. }
  40. return IssueSortOptions.DATE;
  41. }
  42. export function CreateSavedSearchModal({
  43. Header,
  44. Body,
  45. closeModal,
  46. organization,
  47. query,
  48. sort,
  49. }: CreateSavedSearchModalProps) {
  50. const [error, setError] = useState(null);
  51. const {mutateAsync: createSavedSearch} = useCreateSavedSearch();
  52. const initialData = {
  53. name: '',
  54. query,
  55. sort: validateSortOption({organization, sort}),
  56. visibility: SavedSearchVisibility.Owner,
  57. };
  58. const handleSubmit: OnSubmitCallback = async (
  59. data,
  60. onSubmitSuccess,
  61. onSubmitError,
  62. event
  63. ) => {
  64. event.preventDefault();
  65. setError(null);
  66. addLoadingMessage(t('Saving Changes'));
  67. trackAnalytics('search.saved_search_create', {
  68. name: data.name,
  69. organization,
  70. query: data.query,
  71. search_type: 'issues',
  72. sort: data.sort,
  73. visibility: data.visibility,
  74. });
  75. try {
  76. await createSavedSearch({
  77. orgSlug: organization.slug,
  78. name: data.name,
  79. query: data.query,
  80. sort: data.sort,
  81. type: SavedSearchType.ISSUE,
  82. visibility: data.visibility,
  83. });
  84. closeModal();
  85. clearIndicators();
  86. onSubmitSuccess(data);
  87. } catch (err) {
  88. clearIndicators();
  89. onSubmitError(
  90. err?.responseJSON?.detail
  91. ? err.responseJSON.detail
  92. : t('Unable to save your changes.')
  93. );
  94. }
  95. };
  96. return (
  97. <Form
  98. onSubmit={handleSubmit}
  99. onCancel={closeModal}
  100. saveOnBlur={false}
  101. initialData={initialData}
  102. submitLabel={t('Save')}
  103. onSubmitError={submitError => setError(submitError)}
  104. >
  105. <Header>
  106. <h4>{t('Create a Saved Search')}</h4>
  107. </Header>
  108. <Body>
  109. {error && <Alert type="error">{error}</Alert>}
  110. <SavedSearchModalContent organization={organization} />
  111. </Body>
  112. </Form>
  113. );
  114. }