utils.tsx 5.3 KB

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