group.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. import type {PlatformKey} from 'sentry/data/platformCategories';
  2. import {FieldKind} from 'sentry/utils/fields';
  3. import type {Actor, TimeseriesValue} from './core';
  4. import type {Event, EventMetadata, EventOrGroupType, Level} from './event';
  5. import type {Commit, PullRequest, Repository} from './integrations';
  6. import type {Team} from './organization';
  7. import type {Project} from './project';
  8. import type {Release} from './release';
  9. import type {AvatarUser, User} from './user';
  10. export type EntryData = Record<string, any | Array<any>>;
  11. /**
  12. * Saved issues searches
  13. */
  14. export type RecentSearch = {
  15. dateCreated: string;
  16. id: string;
  17. lastSeen: string;
  18. organizationId: string;
  19. query: string;
  20. type: SavedSearchType;
  21. };
  22. // XXX: Deprecated Sentry 9 attributes are not included here.
  23. export type SavedSearch = {
  24. dateCreated: string;
  25. id: string;
  26. isGlobal: boolean;
  27. isOrgCustom: boolean;
  28. isPinned: boolean;
  29. name: string;
  30. query: string;
  31. sort: string;
  32. type: SavedSearchType;
  33. };
  34. export enum SavedSearchType {
  35. ISSUE = 0,
  36. EVENT = 1,
  37. SESSION = 2,
  38. }
  39. export enum IssueCategory {
  40. PERFORMANCE = 'performance',
  41. ERROR = 'error',
  42. }
  43. export enum IssueType {
  44. ERROR = 'error',
  45. PERFORMANCE_N_PLUS_ONE = 'performance_n_plus_one',
  46. }
  47. type CapabilityInfo = {
  48. enabled: boolean;
  49. disabledReason?: string;
  50. };
  51. /**
  52. * Defines what capabilities a category of issue has. Not all categories of
  53. * issues work the same.
  54. */
  55. export type IssueCategoryCapabilities = {
  56. /**
  57. * Can the issue be deleted
  58. */
  59. delete: CapabilityInfo;
  60. /**
  61. * Can the issue be deleted and discarded
  62. */
  63. deleteAndDiscard: CapabilityInfo;
  64. /**
  65. * Can the issue be ignored (and the dropdown options)
  66. */
  67. ignore: CapabilityInfo;
  68. /**
  69. * Can the issue be merged
  70. */
  71. merge: CapabilityInfo;
  72. /**
  73. * Can the issue be shared
  74. */
  75. share: CapabilityInfo;
  76. };
  77. // endpoint: /api/0/issues/:issueId/attachments/?limit=50
  78. export type IssueAttachment = {
  79. dateCreated: string;
  80. event_id: string;
  81. headers: object;
  82. id: string;
  83. mimetype: string;
  84. name: string;
  85. sha1: string;
  86. size: number;
  87. type: string;
  88. };
  89. // endpoint: /api/0/projects/:orgSlug/:projSlug/events/:eventId/attachments/
  90. export type EventAttachment = Omit<IssueAttachment, 'event_id'>;
  91. /**
  92. * Issue Tags
  93. */
  94. export type Tag = {
  95. key: string;
  96. name: string;
  97. isInput?: boolean;
  98. kind?: FieldKind;
  99. /**
  100. * How many values should be suggested in autocomplete.
  101. * Overrides SmartSearchBar's `maxSearchItems` prop.
  102. */
  103. maxSuggestedValues?: number;
  104. predefined?: boolean;
  105. totalValues?: number;
  106. values?: string[];
  107. };
  108. export type TagCollection = Record<string, Tag>;
  109. export type TagValue = {
  110. count: number;
  111. firstSeen: string;
  112. lastSeen: string;
  113. name: string;
  114. value: string;
  115. email?: string;
  116. identifier?: string;
  117. ipAddress?: string;
  118. key?: string;
  119. query?: string;
  120. username?: string;
  121. } & AvatarUser;
  122. type Topvalue = {
  123. count: number;
  124. firstSeen: string;
  125. key: string;
  126. lastSeen: string;
  127. name: string;
  128. value: string;
  129. // Might not actually exist.
  130. query?: string;
  131. };
  132. export type TagWithTopValues = {
  133. key: string;
  134. name: string;
  135. topValues: Array<Topvalue>;
  136. totalValues: number;
  137. uniqueValues: number;
  138. canDelete?: boolean;
  139. };
  140. /**
  141. * Inbox, issue owners and Activity
  142. */
  143. export type InboxReasonDetails = {
  144. count?: number | null;
  145. until?: string | null;
  146. user_count?: number | null;
  147. user_window?: number | null;
  148. window?: number | null;
  149. };
  150. export type InboxDetails = {
  151. reason_details: InboxReasonDetails;
  152. date_added?: string;
  153. reason?: number;
  154. };
  155. export type SuggestedOwnerReason = 'suspectCommit' | 'ownershipRule' | 'releaseCommit';
  156. // Received from the backend to denote suggested owners of an issue
  157. export type SuggestedOwner = {
  158. date_added: string;
  159. owner: string;
  160. type: SuggestedOwnerReason;
  161. };
  162. export type IssueOwnership = {
  163. autoAssignment: boolean;
  164. codeownersAutoSync: boolean;
  165. dateCreated: string;
  166. fallthrough: boolean;
  167. isActive: boolean;
  168. lastUpdated: string;
  169. raw: string;
  170. };
  171. export enum GroupActivityType {
  172. NOTE = 'note',
  173. SET_RESOLVED = 'set_resolved',
  174. SET_RESOLVED_BY_AGE = 'set_resolved_by_age',
  175. SET_RESOLVED_IN_RELEASE = 'set_resolved_in_release',
  176. SET_RESOLVED_IN_COMMIT = 'set_resolved_in_commit',
  177. SET_RESOLVED_IN_PULL_REQUEST = 'set_resolved_in_pull_request',
  178. SET_UNRESOLVED = 'set_unresolved',
  179. SET_IGNORED = 'set_ignored',
  180. SET_PUBLIC = 'set_public',
  181. SET_PRIVATE = 'set_private',
  182. SET_REGRESSION = 'set_regression',
  183. CREATE_ISSUE = 'create_issue',
  184. UNMERGE_SOURCE = 'unmerge_source',
  185. UNMERGE_DESTINATION = 'unmerge_destination',
  186. FIRST_SEEN = 'first_seen',
  187. ASSIGNED = 'assigned',
  188. UNASSIGNED = 'unassigned',
  189. MERGE = 'merge',
  190. REPROCESS = 'reprocess',
  191. MARK_REVIEWED = 'mark_reviewed',
  192. }
  193. interface GroupActivityBase {
  194. dateCreated: string;
  195. id: string;
  196. project: Project;
  197. assignee?: string;
  198. issue?: Group;
  199. user?: null | User;
  200. }
  201. interface GroupActivityNote extends GroupActivityBase {
  202. data: {
  203. text: string;
  204. };
  205. type: GroupActivityType.NOTE;
  206. }
  207. interface GroupActivitySetResolved extends GroupActivityBase {
  208. data: Record<string, any>;
  209. type: GroupActivityType.SET_RESOLVED;
  210. }
  211. interface GroupActivitySetUnresolved extends GroupActivityBase {
  212. data: Record<string, any>;
  213. type: GroupActivityType.SET_UNRESOLVED;
  214. }
  215. interface GroupActivitySetPublic extends GroupActivityBase {
  216. data: Record<string, any>;
  217. type: GroupActivityType.SET_PUBLIC;
  218. }
  219. interface GroupActivitySetPrivate extends GroupActivityBase {
  220. data: Record<string, any>;
  221. type: GroupActivityType.SET_PRIVATE;
  222. }
  223. interface GroupActivitySetByAge extends GroupActivityBase {
  224. data: Record<string, any>;
  225. type: GroupActivityType.SET_RESOLVED_BY_AGE;
  226. }
  227. interface GroupActivityUnassigned extends GroupActivityBase {
  228. data: Record<string, any>;
  229. type: GroupActivityType.UNASSIGNED;
  230. }
  231. interface GroupActivityFirstSeen extends GroupActivityBase {
  232. data: Record<string, any>;
  233. type: GroupActivityType.FIRST_SEEN;
  234. }
  235. interface GroupActivityMarkReviewed extends GroupActivityBase {
  236. data: Record<string, any>;
  237. type: GroupActivityType.MARK_REVIEWED;
  238. }
  239. interface GroupActivityRegression extends GroupActivityBase {
  240. data: {
  241. version?: string;
  242. };
  243. type: GroupActivityType.SET_REGRESSION;
  244. }
  245. export interface GroupActivitySetByResolvedInRelease extends GroupActivityBase {
  246. data: {
  247. current_release_version?: string;
  248. version?: string;
  249. };
  250. type: GroupActivityType.SET_RESOLVED_IN_RELEASE;
  251. }
  252. interface GroupActivitySetByResolvedInCommit extends GroupActivityBase {
  253. data: {
  254. commit: Commit;
  255. };
  256. type: GroupActivityType.SET_RESOLVED_IN_COMMIT;
  257. }
  258. interface GroupActivitySetByResolvedInPullRequest extends GroupActivityBase {
  259. data: {
  260. pullRequest: PullRequest;
  261. };
  262. type: GroupActivityType.SET_RESOLVED_IN_PULL_REQUEST;
  263. }
  264. export interface GroupActivitySetIgnored extends GroupActivityBase {
  265. data: {
  266. ignoreCount?: number;
  267. ignoreDuration?: number;
  268. ignoreUntil?: string;
  269. ignoreUserCount?: number;
  270. ignoreUserWindow?: number;
  271. ignoreWindow?: number;
  272. };
  273. type: GroupActivityType.SET_IGNORED;
  274. }
  275. export interface GroupActivityReprocess extends GroupActivityBase {
  276. data: {
  277. eventCount: number;
  278. newGroupId: number;
  279. oldGroupId: number;
  280. };
  281. type: GroupActivityType.REPROCESS;
  282. }
  283. interface GroupActivityUnmergeDestination extends GroupActivityBase {
  284. data: {
  285. fingerprints: Array<string>;
  286. source?: {
  287. id: string;
  288. shortId: string;
  289. };
  290. };
  291. type: GroupActivityType.UNMERGE_DESTINATION;
  292. }
  293. interface GroupActivityUnmergeSource extends GroupActivityBase {
  294. data: {
  295. fingerprints: Array<string>;
  296. destination?: {
  297. id: string;
  298. shortId: string;
  299. };
  300. };
  301. type: GroupActivityType.UNMERGE_SOURCE;
  302. }
  303. interface GroupActivityMerge extends GroupActivityBase {
  304. data: {
  305. issues: Array<any>;
  306. };
  307. type: GroupActivityType.MERGE;
  308. }
  309. export interface GroupActivityAssigned extends GroupActivityBase {
  310. data: {
  311. assignee: string;
  312. assigneeType: string;
  313. user: Team | User;
  314. assigneeEmail?: string;
  315. /**
  316. * If the user was assigned via an integration
  317. */
  318. integration?: 'projectOwnership' | 'codeowners' | 'slack' | 'msteams';
  319. /** Codeowner or Project owner rule as a string */
  320. rule?: string;
  321. };
  322. type: GroupActivityType.ASSIGNED;
  323. }
  324. export interface GroupActivityCreateIssue extends GroupActivityBase {
  325. data: {
  326. location: string;
  327. provider: string;
  328. title: string;
  329. };
  330. type: GroupActivityType.CREATE_ISSUE;
  331. }
  332. export type GroupActivity =
  333. | GroupActivityNote
  334. | GroupActivitySetResolved
  335. | GroupActivitySetUnresolved
  336. | GroupActivitySetIgnored
  337. | GroupActivitySetByAge
  338. | GroupActivitySetByResolvedInRelease
  339. | GroupActivitySetByResolvedInCommit
  340. | GroupActivitySetByResolvedInPullRequest
  341. | GroupActivityFirstSeen
  342. | GroupActivityMerge
  343. | GroupActivityReprocess
  344. | GroupActivityUnassigned
  345. | GroupActivityMarkReviewed
  346. | GroupActivityUnmergeDestination
  347. | GroupActivitySetPublic
  348. | GroupActivitySetPrivate
  349. | GroupActivityRegression
  350. | GroupActivityUnmergeSource
  351. | GroupActivityAssigned
  352. | GroupActivityCreateIssue;
  353. export type Activity = GroupActivity;
  354. interface GroupFiltered {
  355. count: string;
  356. firstSeen: string;
  357. lastSeen: string;
  358. stats: Record<string, TimeseriesValue[]>;
  359. userCount: number;
  360. }
  361. export interface GroupStats extends GroupFiltered {
  362. filtered: GroupFiltered | null;
  363. id: string;
  364. lifetime?: GroupFiltered;
  365. sessionCount?: string | null;
  366. }
  367. export interface BaseGroupStatusReprocessing {
  368. status: 'reprocessing';
  369. statusDetails: {
  370. info: {
  371. dateCreated: string;
  372. totalEvents: number;
  373. } | null;
  374. pendingEvents: number;
  375. };
  376. }
  377. /**
  378. * Issue Resolution
  379. */
  380. export enum ResolutionStatus {
  381. RESOLVED = 'resolved',
  382. UNRESOLVED = 'unresolved',
  383. IGNORED = 'ignored',
  384. }
  385. export type ResolutionStatusDetails = {
  386. actor?: AvatarUser;
  387. autoResolved?: boolean;
  388. ignoreCount?: number;
  389. // Sent in requests. ignoreUntil is used in responses.
  390. ignoreDuration?: number;
  391. ignoreUntil?: string;
  392. ignoreUserCount?: number;
  393. ignoreUserWindow?: number;
  394. ignoreWindow?: number;
  395. inCommit?: {
  396. commit?: string;
  397. dateCreated?: string;
  398. id?: string;
  399. repository?: string | Repository;
  400. };
  401. inNextRelease?: boolean;
  402. inRelease?: string;
  403. repository?: string;
  404. };
  405. export type GroupStatusResolution = {
  406. status: ResolutionStatus;
  407. statusDetails: ResolutionStatusDetails;
  408. };
  409. export type GroupRelease = {
  410. firstRelease: Release;
  411. lastRelease: Release;
  412. };
  413. // TODO(ts): incomplete
  414. export interface BaseGroup extends GroupRelease {
  415. activity: GroupActivity[];
  416. annotations: string[];
  417. assignedTo: Actor;
  418. culprit: string;
  419. firstSeen: string;
  420. hasSeen: boolean;
  421. id: string;
  422. isBookmarked: boolean;
  423. isPublic: boolean;
  424. isSubscribed: boolean;
  425. isUnhandled: boolean;
  426. issueCategory: IssueCategory;
  427. issueType: IssueType;
  428. lastSeen: string;
  429. latestEvent: Event;
  430. level: Level;
  431. logger: string;
  432. metadata: EventMetadata;
  433. numComments: number;
  434. participants: User[];
  435. permalink: string;
  436. platform: PlatformKey;
  437. pluginActions: any[]; // TODO(ts)
  438. pluginContexts: any[]; // TODO(ts)
  439. pluginIssues: any[]; // TODO(ts)
  440. project: Project;
  441. seenBy: User[];
  442. shareId: string;
  443. shortId: string;
  444. status: string;
  445. subscriptionDetails: {disabled?: boolean; reason?: string} | null;
  446. tags: Pick<Tag, 'key' | 'name' | 'totalValues'>[];
  447. title: string;
  448. type: EventOrGroupType;
  449. userReportCount: number;
  450. inbox?: InboxDetails | null | false;
  451. owners?: SuggestedOwner[] | null;
  452. }
  453. export interface GroupReprocessing
  454. // BaseGroupStatusReprocessing status field (enum) incorrectly extends the BaseGroup status field (string) so we omit it.
  455. // A proper fix for this would be to make the status field an enum or string and correctly extend it.
  456. extends Omit<BaseGroup, 'status'>,
  457. GroupStats,
  458. BaseGroupStatusReprocessing {}
  459. export interface GroupResolution
  460. // GroupStatusResolution status field (enum) incorrectly extends the BaseGroup status field (string) so we omit it.
  461. // A proper fix for this would be to make the status field an enum or string and correctly extend it.
  462. extends Omit<BaseGroup, 'status'>,
  463. GroupStats,
  464. GroupStatusResolution {}
  465. export type Group = GroupResolution | GroupReprocessing;
  466. export interface GroupCollapseRelease
  467. extends Omit<Group, keyof GroupRelease>,
  468. Partial<GroupRelease> {}
  469. export type GroupTombstone = {
  470. actor: AvatarUser;
  471. culprit: string;
  472. id: string;
  473. level: Level;
  474. metadata: EventMetadata;
  475. title: string;
  476. };
  477. export type ProcessingIssueItem = {
  478. checksum: string;
  479. data: {
  480. // TODO(ts) This type is likely incomplete, but this is what
  481. // project processing issues settings uses.
  482. _scope: string;
  483. image_arch: string;
  484. image_path: string;
  485. image_uuid: string;
  486. };
  487. id: string;
  488. lastSeen: string;
  489. numEvents: number;
  490. type: string;
  491. };
  492. export type ProcessingIssue = {
  493. hasIssues: boolean;
  494. hasMoreResolveableIssues: boolean;
  495. issuesProcessing: number;
  496. lastSeen: string;
  497. numIssues: number;
  498. project: string;
  499. resolveableIssues: number;
  500. signedLink: string;
  501. issues?: ProcessingIssueItem[];
  502. };
  503. /**
  504. * Datascrubbing
  505. */
  506. export type Meta = {
  507. chunks: Array<ChunkType>;
  508. err: Array<MetaError>;
  509. len: number;
  510. rem: Array<MetaRemark>;
  511. };
  512. export type MetaError = string | [string, any];
  513. export type MetaRemark = Array<string | number>;
  514. export type ChunkType = {
  515. rule_id: string | number;
  516. text: string;
  517. type: string;
  518. remark?: string | number;
  519. };
  520. /**
  521. * User Feedback
  522. */
  523. export type UserReport = {
  524. comments: string;
  525. dateCreated: string;
  526. email: string;
  527. event: {eventID: string; id: string};
  528. eventID: string;
  529. id: string;
  530. issue: Group;
  531. name: string;
  532. user: User;
  533. };
  534. export type KeyValueListData = {
  535. key: string;
  536. subject: string;
  537. actionButton?: React.ReactNode;
  538. meta?: Meta;
  539. subjectDataTestId?: string;
  540. subjectIcon?: React.ReactNode;
  541. value?: React.ReactNode;
  542. }[];
  543. // Response from ShortIdLookupEndpoint
  544. // /organizations/${orgId}/shortids/${query}/
  545. export type ShortIdResponse = {
  546. group: Group;
  547. groupId: string;
  548. organizationSlug: string;
  549. projectSlug: string;
  550. shortId: string;
  551. };
  552. /**
  553. * Note used in Group Activity and Alerts for users to comment
  554. */
  555. export type Note = {
  556. /**
  557. * Array of [id, display string] tuples used for @-mentions
  558. */
  559. mentions: [string, string][];
  560. /**
  561. * Note contents (markdown allowed)
  562. */
  563. text: string;
  564. };