utils.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import ExternalLink from 'sentry/components/links/externalLink';
  2. import {DEFAULT_QUERY} from 'sentry/constants';
  3. import {t, tct} from 'sentry/locale';
  4. import {Organization} from 'sentry/types';
  5. export enum Query {
  6. FOR_REVIEW_OLD = 'is:unresolved is:for_review assigned_or_suggested:[me, none]',
  7. FOR_REVIEW = 'is:unresolved is:for_review assigned_or_suggested:[me, my_teams, none]',
  8. UNRESOLVED = 'is:unresolved',
  9. IGNORED = 'is:ignored',
  10. NEW = 'is:new',
  11. ARCHIVED = 'is:archived',
  12. ESCALATING = 'is:escalating',
  13. REGRESSED = 'is:regressed',
  14. REPROCESSING = 'is:reprocessing',
  15. }
  16. type OverviewTab = {
  17. /**
  18. * Emitted analytics event tab name
  19. */
  20. analyticsName: string;
  21. /**
  22. * Will fetch a count to display on this tab
  23. */
  24. count: boolean;
  25. /**
  26. * Tabs can be disabled via flag
  27. */
  28. enabled: boolean;
  29. name: string;
  30. /**
  31. * Tooltip text to be hoverable when text has links
  32. */
  33. tooltipHoverable?: boolean;
  34. /**
  35. * Tooltip text for each tab
  36. */
  37. tooltipTitle?: React.ReactNode;
  38. };
  39. /**
  40. * Get a list of currently active tabs
  41. */
  42. export function getTabs(organization: Organization) {
  43. const hasEscalatingIssuesUi = organization.features.includes('escalating-issues');
  44. const hasAssignToMe = organization.features.includes('assign-to-me');
  45. const tabs: Array<[string, OverviewTab]> = [
  46. [
  47. Query.UNRESOLVED,
  48. {
  49. name: hasEscalatingIssuesUi ? t('Unresolved') : t('All Unresolved'),
  50. analyticsName: 'unresolved',
  51. count: true,
  52. enabled: true,
  53. },
  54. ],
  55. [
  56. hasAssignToMe ? Query.FOR_REVIEW : Query.FOR_REVIEW_OLD,
  57. {
  58. name: t('For Review'),
  59. analyticsName: 'needs_review',
  60. count: true,
  61. enabled: true,
  62. tooltipTitle: hasEscalatingIssuesUi
  63. ? t(
  64. 'Issues are marked for review if they are new or escalating, and have not been resolved or archived. Issues are automatically marked reviewed in 7 days.'
  65. )
  66. : t(`Issues are marked for review when they are created, unresolved, or unignored.
  67. Mark an issue reviewed to move it out of this list.
  68. Issues are automatically marked reviewed in 7 days.`),
  69. },
  70. ],
  71. [
  72. Query.REGRESSED,
  73. {
  74. name: t('Regressed'),
  75. analyticsName: 'regressed',
  76. count: true,
  77. enabled: hasEscalatingIssuesUi,
  78. },
  79. ],
  80. [
  81. Query.ESCALATING,
  82. {
  83. name: t('Escalating'),
  84. analyticsName: 'escalating',
  85. count: true,
  86. enabled: hasEscalatingIssuesUi,
  87. },
  88. ],
  89. [
  90. Query.ARCHIVED,
  91. {
  92. name: t('Archived'),
  93. analyticsName: 'archived',
  94. count: true,
  95. enabled: hasEscalatingIssuesUi,
  96. },
  97. ],
  98. [
  99. Query.IGNORED,
  100. {
  101. name: t('Ignored'),
  102. analyticsName: 'ignored',
  103. count: true,
  104. enabled: !hasEscalatingIssuesUi,
  105. tooltipTitle: t(`Ignored issues don’t trigger alerts. When their ignore
  106. conditions are met they become Unresolved and are flagged for review.`),
  107. },
  108. ],
  109. [
  110. Query.REPROCESSING,
  111. {
  112. name: t('Reprocessing'),
  113. analyticsName: 'reprocessing',
  114. count: true,
  115. enabled: organization.features.includes('reprocessing-v2'),
  116. tooltipTitle: tct(
  117. `These [link:reprocessing issues] will take some time to complete.
  118. Any new issues that are created during reprocessing will be flagged for review.`,
  119. {
  120. link: (
  121. <ExternalLink href="https://docs.sentry.io/product/error-monitoring/reprocessing/" />
  122. ),
  123. }
  124. ),
  125. tooltipHoverable: true,
  126. },
  127. ],
  128. ];
  129. return tabs.filter(([_query, tab]) => tab.enabled);
  130. }
  131. /**
  132. * @returns queries that should have counts fetched
  133. */
  134. export function getTabsWithCounts(organization: Organization) {
  135. const tabs = getTabs(organization);
  136. return tabs.filter(([_query, tab]) => tab.count).map(([query]) => query);
  137. }
  138. export function isForReviewQuery(query: string | undefined) {
  139. return !!query && /\bis:for_review\b/.test(query);
  140. }
  141. // the tab counts will look like 99+
  142. export const TAB_MAX_COUNT = 99;
  143. type QueryCount = {
  144. count: number;
  145. hasMore: boolean;
  146. };
  147. export type QueryCounts = Partial<Record<Query, QueryCount>>;
  148. export enum IssueSortOptions {
  149. DATE = 'date',
  150. NEW = 'new',
  151. PRIORITY = 'priority',
  152. BETTER_PRIORITY = 'betterPriority',
  153. FREQ = 'freq',
  154. USER = 'user',
  155. INBOX = 'inbox',
  156. }
  157. export const DEFAULT_ISSUE_STREAM_SORT = IssueSortOptions.DATE;
  158. export function isDefaultIssueStreamSearch({
  159. query,
  160. sort,
  161. organization,
  162. }: {
  163. organization: Organization;
  164. query: string;
  165. sort: string;
  166. }) {
  167. const defaultSort = organization.features.includes('issue-list-better-priority-sort')
  168. ? IssueSortOptions.BETTER_PRIORITY
  169. : DEFAULT_ISSUE_STREAM_SORT;
  170. return query === DEFAULT_QUERY && sort === defaultSort;
  171. }
  172. export function getSortLabel(key: string) {
  173. switch (key) {
  174. case IssueSortOptions.NEW:
  175. return t('First Seen');
  176. case IssueSortOptions.PRIORITY:
  177. return t('Priority');
  178. case IssueSortOptions.BETTER_PRIORITY:
  179. return t('Priority');
  180. case IssueSortOptions.FREQ:
  181. return t('Events');
  182. case IssueSortOptions.USER:
  183. return t('Users');
  184. case IssueSortOptions.INBOX:
  185. return t('Date Added');
  186. case IssueSortOptions.DATE:
  187. default:
  188. return t('Last Seen');
  189. }
  190. }
  191. export const DISCOVER_EXCLUSION_FIELDS: string[] = [
  192. 'query',
  193. 'status',
  194. 'bookmarked_by',
  195. 'assigned',
  196. 'assigned_to',
  197. 'unassigned',
  198. 'subscribed_by',
  199. 'active_at',
  200. 'first_release',
  201. 'first_seen',
  202. 'is',
  203. '__text',
  204. ];
  205. export const FOR_REVIEW_QUERIES: string[] = [Query.FOR_REVIEW, Query.FOR_REVIEW_OLD];
  206. export const SAVED_SEARCHES_SIDEBAR_OPEN_LOCALSTORAGE_KEY =
  207. 'issue-stream-saved-searches-sidebar-open';