utils.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import {Location, LocationDescriptor} from 'history';
  2. import {getParams} from 'app/components/organizations/globalSelectionHeader/getParams';
  3. import {ALL_ACCESS_PROJECTS} from 'app/constants/globalSelectionHeader';
  4. import {OrganizationSummary} from 'app/types';
  5. import {Event} from 'app/types/event';
  6. import {defined} from 'app/utils';
  7. import EventView from 'app/utils/discover/eventView';
  8. import {eventDetailsRouteWithEventView, generateEventSlug} from 'app/utils/discover/urls';
  9. import {
  10. EventLite,
  11. QuickTraceEvent,
  12. TraceError,
  13. } from 'app/utils/performance/quickTrace/types';
  14. import {getTraceTimeRangeFromEvent} from 'app/utils/performance/quickTrace/utils';
  15. import {QueryResults} from 'app/utils/tokenizeSearch';
  16. import {getTraceDetailsUrl} from 'app/views/performance/traceDetails/utils';
  17. import {getTransactionDetailsUrl} from 'app/views/performance/utils';
  18. export function isQuickTraceEvent(
  19. event: QuickTraceEvent | TraceError
  20. ): event is QuickTraceEvent {
  21. return defined((event as QuickTraceEvent)['transaction.duration']);
  22. }
  23. export type ErrorDestination = 'discover' | 'issue';
  24. export type TransactionDestination = 'discover' | 'performance';
  25. export function generateIssueEventTarget(
  26. event: TraceError,
  27. organization: OrganizationSummary
  28. ): LocationDescriptor {
  29. return `/organizations/${organization.slug}/issues/${event.issue_id}/events/${event.event_id}`;
  30. }
  31. function generatePerformanceEventTarget(
  32. event: EventLite,
  33. organization: OrganizationSummary,
  34. location: Location
  35. ): LocationDescriptor {
  36. const eventSlug = generateEventSlug({
  37. id: event.event_id,
  38. project: event.project_slug,
  39. });
  40. return getTransactionDetailsUrl(
  41. organization,
  42. eventSlug,
  43. event.transaction,
  44. location.query
  45. );
  46. }
  47. function generateDiscoverEventTarget(
  48. event: EventLite | TraceError,
  49. organization: OrganizationSummary,
  50. location: Location
  51. ): LocationDescriptor {
  52. const eventSlug = generateEventSlug({
  53. id: event.event_id,
  54. project: event.project_slug,
  55. });
  56. return eventDetailsRouteWithEventView({
  57. orgSlug: organization.slug,
  58. eventSlug,
  59. eventView: EventView.fromLocation(location),
  60. });
  61. }
  62. export function generateSingleErrorTarget(
  63. event: TraceError,
  64. organization: OrganizationSummary,
  65. location: Location,
  66. destination: ErrorDestination
  67. ): LocationDescriptor {
  68. switch (destination) {
  69. case 'issue':
  70. return generateIssueEventTarget(event, organization);
  71. case 'discover':
  72. default:
  73. return generateDiscoverEventTarget(event, organization, location);
  74. }
  75. }
  76. export function generateSingleTransactionTarget(
  77. event: EventLite,
  78. organization: OrganizationSummary,
  79. location: Location,
  80. destination: TransactionDestination
  81. ): LocationDescriptor {
  82. switch (destination) {
  83. case 'performance':
  84. return generatePerformanceEventTarget(event, organization, location);
  85. case 'discover':
  86. default:
  87. return generateDiscoverEventTarget(event, organization, location);
  88. }
  89. }
  90. export function generateMultiTransactionsTarget(
  91. currentEvent: Event,
  92. events: EventLite[],
  93. organization: OrganizationSummary,
  94. groupType: 'Ancestor' | 'Children' | 'Descendant'
  95. ): LocationDescriptor {
  96. const queryResults = new QueryResults([]);
  97. const eventIds = events.map(child => child.event_id);
  98. for (let i = 0; i < eventIds.length; i++) {
  99. queryResults.addOp(i === 0 ? '(' : 'OR');
  100. queryResults.addQuery(`id:${eventIds[i]}`);
  101. if (i === eventIds.length - 1) {
  102. queryResults.addOp(')');
  103. }
  104. }
  105. const {start, end} = getTraceTimeRangeFromEvent(currentEvent);
  106. const traceEventView = EventView.fromSavedQuery({
  107. id: undefined,
  108. name: `${groupType} Transactions of Event ID ${currentEvent.id}`,
  109. fields: ['transaction', 'project', 'trace.span', 'transaction.duration', 'timestamp'],
  110. orderby: '-timestamp',
  111. query: queryResults.formatString(),
  112. projects: [...new Set(events.map(child => child.project_id))],
  113. version: 2,
  114. start,
  115. end,
  116. });
  117. return traceEventView.getResultsViewUrlTarget(organization.slug);
  118. }
  119. export function generateTraceTarget(
  120. event: Event,
  121. organization: OrganizationSummary
  122. ): LocationDescriptor {
  123. const traceId = event.contexts?.trace?.trace_id ?? '';
  124. const dateSelection = getParams(getTraceTimeRangeFromEvent(event));
  125. if (organization.features.includes('performance-view')) {
  126. // TODO(txiao): Should this persist the current query when going to trace view?
  127. return getTraceDetailsUrl(organization, traceId, dateSelection, {});
  128. }
  129. const eventView = EventView.fromSavedQuery({
  130. id: undefined,
  131. name: `Events with Trace ID ${traceId}`,
  132. fields: ['title', 'event.type', 'project', 'trace.span', 'timestamp'],
  133. orderby: '-timestamp',
  134. query: `trace:${traceId}`,
  135. projects: organization.features.includes('global-views')
  136. ? [ALL_ACCESS_PROJECTS]
  137. : [Number(event.projectID)],
  138. version: 2,
  139. ...dateSelection,
  140. });
  141. return eventView.getResultsViewUrlTarget(organization.slug);
  142. }