index.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. text={node.value['transaction.op'] + ' - ' + node.value.transaction}
  71. />
  72. </TraceDrawerComponents.TitleText>
  73. </TraceDrawerComponents.Title>
  74. <TraceDrawerComponents.NodeActions
  75. node={node}
  76. organization={organization}
  77. onTabScrollToNode={onTabScrollToNode}
  78. eventSize={event?.size}
  79. />
  80. </TraceDrawerComponents.HeaderContainer>
  81. );
  82. }
  83. export function TransactionNodeDetails({
  84. node,
  85. organization,
  86. onTabScrollToNode,
  87. onParentClick,
  88. replayRecord,
  89. }: TraceTreeNodeDetailsProps<TraceTreeNode<TraceTree.Transaction>>) {
  90. const location = useLocation();
  91. const {projects} = useProjects();
  92. const issues = useMemo(() => {
  93. return [...node.errors, ...node.performance_issues];
  94. }, [node.errors, node.performance_issues]);
  95. const {
  96. data: event,
  97. isError,
  98. isLoading,
  99. } = useTransaction({
  100. node,
  101. organization,
  102. });
  103. const {data: cacheMetrics} = useSpanMetrics(
  104. {
  105. search: MutableSearch.fromQueryObject({
  106. transaction: node.value.transaction,
  107. } satisfies SpanMetricsQueryFilters),
  108. fields: ['avg(cache.item_size)', 'cache_miss_rate()'],
  109. },
  110. Referrer.TRACE_DRAWER_TRANSACTION_CACHE_METRICS
  111. );
  112. if (isLoading) {
  113. return <LoadingIndicator />;
  114. }
  115. if (isError) {
  116. return <LoadingError message={t('Failed to fetch transaction details')} />;
  117. }
  118. const project = projects.find(proj => proj.slug === event?.projectSlug);
  119. return (
  120. <TraceDrawerComponents.DetailContainer>
  121. <TransactionNodeDetailHeader
  122. node={node}
  123. organization={organization}
  124. project={project}
  125. event={event}
  126. onTabScrollToNode={onTabScrollToNode}
  127. />
  128. <IssueList node={node} organization={organization} issues={issues} />
  129. <TraceDrawerComponents.SectionCardGroup>
  130. <GeneralInfo
  131. node={node}
  132. onParentClick={onParentClick}
  133. organization={organization}
  134. event={event}
  135. location={location}
  136. />
  137. <AdditionalData event={event} />
  138. <Measurements event={event} location={location} organization={organization} />
  139. {cacheMetrics.length > 0 ? <CacheMetrics cacheMetrics={cacheMetrics} /> : null}
  140. <Sdk event={event} />
  141. <CustomMetricsEventData
  142. metricsSummary={event._metrics_summary}
  143. startTimestamp={event.startTimestamp}
  144. projectId={event.projectID}
  145. />
  146. <TraceDrawerComponents.TraceDataSection event={event} />
  147. </TraceDrawerComponents.SectionCardGroup>
  148. <Request event={event} />
  149. {event.projectSlug ? (
  150. <Entries
  151. definedEvent={event}
  152. projectSlug={event.projectSlug}
  153. group={undefined}
  154. organization={organization}
  155. />
  156. ) : null}
  157. <TraceDrawerComponents.EventTags
  158. projectSlug={node.value.project_slug}
  159. event={event}
  160. />
  161. <EventContexts event={event} />
  162. {project ? <EventEvidence event={event} project={project} /> : null}
  163. {replayRecord ? null : <ReplayPreview event={event} organization={organization} />}
  164. <BreadCrumbs event={event} organization={organization} />
  165. {event.projectSlug ? (
  166. <EventAttachments event={event} projectSlug={event.projectSlug} />
  167. ) : null}
  168. {project ? <EventViewHierarchy event={event} project={project} /> : null}
  169. {event.projectSlug ? (
  170. <EventRRWebIntegration
  171. event={event}
  172. orgId={organization.slug}
  173. projectSlug={event.projectSlug}
  174. />
  175. ) : null}
  176. </TraceDrawerComponents.DetailContainer>
  177. );
  178. }