utils.tsx 5.2 KB

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