index.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import {useMemo} from 'react';
  2. import {EventContexts} from 'sentry/components/events/contexts';
  3. import {EventAttachments} from 'sentry/components/events/eventAttachments';
  4. import {EventEvidence} from 'sentry/components/events/eventEvidence';
  5. import {EventViewHierarchy} from 'sentry/components/events/eventViewHierarchy';
  6. import {EventRRWebIntegration} from 'sentry/components/events/rrwebIntegration';
  7. import ProjectBadge from 'sentry/components/idBadge/projectBadge';
  8. import type {LazyRenderProps} from 'sentry/components/lazyRender';
  9. import LoadingError from 'sentry/components/loadingError';
  10. import LoadingIndicator from 'sentry/components/loadingIndicator';
  11. import {CustomMetricsEventData} from 'sentry/components/metrics/customMetricsEventData';
  12. import {Tooltip} from 'sentry/components/tooltip';
  13. import {t} from 'sentry/locale';
  14. import type {EventTransaction} from 'sentry/types/event';
  15. import type {Organization} from 'sentry/types/organization';
  16. import type {Project} from 'sentry/types/project';
  17. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  18. import {useLocation} from 'sentry/utils/useLocation';
  19. import useProjects from 'sentry/utils/useProjects';
  20. import {useSpanMetrics} from 'sentry/views/insights/common/queries/useDiscover';
  21. import type {SpanMetricsQueryFilters} from 'sentry/views/insights/types';
  22. import {Referrer} from 'sentry/views/performance/newTraceDetails/referrers';
  23. import {useTransaction} from 'sentry/views/performance/newTraceDetails/traceApi/useTransaction';
  24. import {CacheMetrics} from 'sentry/views/performance/newTraceDetails/traceDrawer/details/transaction/sections/cacheMetrics';
  25. import type {TraceTreeNodeDetailsProps} from 'sentry/views/performance/newTraceDetails/traceDrawer/tabs/traceTreeNodeDetails';
  26. import type {
  27. TraceTree,
  28. TraceTreeNode,
  29. } from 'sentry/views/performance/newTraceDetails/traceModels/traceTree';
  30. import {IssueList} from '../issues/issues';
  31. import {TraceDrawerComponents} from '../styles';
  32. import {AdditionalData} from './sections/additionalData';
  33. import {BreadCrumbs} from './sections/breadCrumbs';
  34. import {Entries} from './sections/entries';
  35. import GeneralInfo from './sections/generalInfo';
  36. import {Measurements} from './sections/measurements';
  37. import ReplayPreview from './sections/replayPreview';
  38. import {Request} from './sections/request';
  39. import {Sdk} from './sections/sdk';
  40. export const LAZY_RENDER_PROPS: Partial<LazyRenderProps> = {
  41. observerOptions: {rootMargin: '50px'},
  42. };
  43. type TransactionNodeDetailHeaderProps = {
  44. event: EventTransaction;
  45. node: TraceTreeNode<TraceTree.Transaction>;
  46. onTabScrollToNode: (node: TraceTreeNode<any>) => void;
  47. organization: Organization;
  48. project: Project | undefined;
  49. };
  50. function TransactionNodeDetailHeader({
  51. node,
  52. organization,
  53. project,
  54. onTabScrollToNode,
  55. event,
  56. }: TransactionNodeDetailHeaderProps) {
  57. return (
  58. <TraceDrawerComponents.HeaderContainer>
  59. <TraceDrawerComponents.Title>
  60. <Tooltip title={node.value.project_slug}>
  61. <ProjectBadge
  62. project={project ? project : {slug: node.value.project_slug}}
  63. avatarSize={30}
  64. hideName
  65. />
  66. </Tooltip>
  67. <TraceDrawerComponents.TitleText>
  68. <div>{t('transaction')}</div>
  69. <TraceDrawerComponents.TitleOp>
  70. {' '}
  71. {node.value['transaction.op'] + ' - ' + node.value.transaction}
  72. </TraceDrawerComponents.TitleOp>
  73. </TraceDrawerComponents.TitleText>
  74. </TraceDrawerComponents.Title>
  75. <TraceDrawerComponents.NodeActions
  76. node={node}
  77. organization={organization}
  78. onTabScrollToNode={onTabScrollToNode}
  79. eventSize={event?.size}
  80. />
  81. </TraceDrawerComponents.HeaderContainer>
  82. );
  83. }
  84. export function TransactionNodeDetails({
  85. node,
  86. organization,
  87. onTabScrollToNode,
  88. onParentClick,
  89. replayRecord,
  90. }: TraceTreeNodeDetailsProps<TraceTreeNode<TraceTree.Transaction>>) {
  91. const location = useLocation();
  92. const {projects} = useProjects();
  93. const issues = useMemo(() => {
  94. return [...node.errors, ...node.performance_issues];
  95. }, [node.errors, node.performance_issues]);
  96. const {
  97. data: event,
  98. isError,
  99. isLoading,
  100. } = useTransaction({
  101. node,
  102. organization,
  103. });
  104. const {data: cacheMetrics} = useSpanMetrics(
  105. {
  106. search: MutableSearch.fromQueryObject({
  107. transaction: node.value.transaction,
  108. } satisfies SpanMetricsQueryFilters),
  109. fields: ['avg(cache.item_size)', 'cache_miss_rate()'],
  110. },
  111. Referrer.TRACE_DRAWER_TRANSACTION_CACHE_METRICS
  112. );
  113. if (isLoading) {
  114. return <LoadingIndicator />;
  115. }
  116. if (isError) {
  117. return <LoadingError message={t('Failed to fetch transaction details')} />;
  118. }
  119. const project = projects.find(proj => proj.slug === event?.projectSlug);
  120. return (
  121. <TraceDrawerComponents.DetailContainer>
  122. <TransactionNodeDetailHeader
  123. node={node}
  124. organization={organization}
  125. project={project}
  126. event={event}
  127. onTabScrollToNode={onTabScrollToNode}
  128. />
  129. <IssueList node={node} organization={organization} issues={issues} />
  130. <TraceDrawerComponents.SectionCardGroup>
  131. <GeneralInfo
  132. node={node}
  133. onParentClick={onParentClick}
  134. organization={organization}
  135. event={event}
  136. location={location}
  137. />
  138. <AdditionalData event={event} />
  139. <Measurements event={event} location={location} organization={organization} />
  140. {cacheMetrics.length > 0 ? <CacheMetrics cacheMetrics={cacheMetrics} /> : null}
  141. <Sdk event={event} />
  142. <CustomMetricsEventData
  143. metricsSummary={event._metrics_summary}
  144. startTimestamp={event.startTimestamp}
  145. projectId={event.projectID}
  146. />
  147. <TraceDrawerComponents.TraceDataSection event={event} />
  148. </TraceDrawerComponents.SectionCardGroup>
  149. <Request event={event} />
  150. {event.projectSlug ? (
  151. <Entries
  152. definedEvent={event}
  153. projectSlug={event.projectSlug}
  154. group={undefined}
  155. organization={organization}
  156. />
  157. ) : null}
  158. <TraceDrawerComponents.EventTags
  159. projectSlug={node.value.project_slug}
  160. event={event}
  161. />
  162. <EventContexts event={event} />
  163. {project ? <EventEvidence event={event} project={project} /> : null}
  164. {replayRecord ? null : <ReplayPreview event={event} organization={organization} />}
  165. <BreadCrumbs event={event} organization={organization} />
  166. {event.projectSlug ? (
  167. <EventAttachments event={event} projectSlug={event.projectSlug} />
  168. ) : null}
  169. {project ? <EventViewHierarchy event={event} project={project} /> : null}
  170. {event.projectSlug ? (
  171. <EventRRWebIntegration
  172. event={event}
  173. orgId={organization.slug}
  174. projectSlug={event.projectSlug}
  175. />
  176. ) : null}
  177. </TraceDrawerComponents.DetailContainer>
  178. );
  179. }