embeddedSpanTree.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import React, {useContext} from 'react';
  2. import styled from '@emotion/styled';
  3. import ErrorBoundary from 'sentry/components/errorBoundary';
  4. import LoadingError from 'sentry/components/loadingError';
  5. import LoadingIndicator from 'sentry/components/loadingIndicator';
  6. import QuickTrace from 'sentry/components/quickTrace';
  7. import {t} from 'sentry/locale';
  8. import space from 'sentry/styles/space';
  9. import {Event, EventTransaction, Organization} from 'sentry/types';
  10. import EventView from 'sentry/utils/discover/eventView';
  11. import GenericDiscoverQuery from 'sentry/utils/discover/genericDiscoverQuery';
  12. import {QuickTraceContext} from 'sentry/utils/performance/quickTrace/quickTraceContext';
  13. import useApi from 'sentry/utils/useApi';
  14. import {useLocation} from 'sentry/utils/useLocation';
  15. import TraceView from './traceView';
  16. import {FocusedSpanIDMap} from './types';
  17. import WaterfallModel from './waterfallModel';
  18. type Props = {
  19. event: Event;
  20. organization: Organization;
  21. projectSlug: string;
  22. focusedSpanIds?: FocusedSpanIDMap;
  23. };
  24. // This is a wrapper class that is intended to be used within Performance Issues
  25. export function EmbeddedSpanTree(props: Props) {
  26. const {event, organization, projectSlug, focusedSpanIds} = props;
  27. const api = useApi();
  28. const location = useLocation();
  29. const quickTrace = useContext(QuickTraceContext);
  30. const eventView = EventView.fromNewQueryWithLocation(
  31. {
  32. id: undefined,
  33. version: 2,
  34. name: '',
  35. fields: ['transaction.duration'],
  36. projects: [1],
  37. query: 'event.type:transaction',
  38. environment: [],
  39. },
  40. location
  41. );
  42. function getContent() {
  43. if (!quickTrace) {
  44. return null;
  45. }
  46. if (quickTrace.isLoading) {
  47. return <LoadingIndicator />;
  48. }
  49. if (!quickTrace.currentEvent) {
  50. return (
  51. <LoadingError
  52. message={t(
  53. 'Error loading the span tree because the root transaction is missing'
  54. )}
  55. />
  56. );
  57. }
  58. return (
  59. <GenericDiscoverQuery
  60. eventView={eventView}
  61. orgSlug={organization.slug}
  62. route={`events/${projectSlug}:${quickTrace.currentEvent.event_id}`}
  63. api={api}
  64. location={location}
  65. >
  66. {_results => {
  67. if (_results.isLoading) {
  68. return <LoadingIndicator />;
  69. }
  70. if (!_results.tableData) {
  71. return (
  72. <LoadingError
  73. message={t(
  74. 'Error loading the span tree because the root transaction is missing'
  75. )}
  76. />
  77. );
  78. }
  79. return (
  80. <Wrapper>
  81. <Header>
  82. <h3>{t('Span Tree')}</h3>
  83. <QuickTrace
  84. event={event}
  85. quickTrace={quickTrace!}
  86. location={location}
  87. organization={organization}
  88. anchor="left"
  89. errorDest="issue"
  90. transactionDest="performance"
  91. />
  92. </Header>
  93. <Section>
  94. <TraceView
  95. organization={organization}
  96. waterfallModel={
  97. new WaterfallModel(
  98. _results.tableData as EventTransaction,
  99. focusedSpanIds
  100. )
  101. }
  102. />
  103. </Section>
  104. </Wrapper>
  105. );
  106. }}
  107. </GenericDiscoverQuery>
  108. );
  109. }
  110. return (
  111. <React.Fragment>
  112. <ErrorBoundary mini>{getContent()}</ErrorBoundary>
  113. </React.Fragment>
  114. );
  115. }
  116. export const Wrapper = styled('div')`
  117. border-top: 1px solid ${p => p.theme.innerBorder};
  118. border-radius: ${p => p.theme.borderRadius};
  119. margin: 0;
  120. /* Padding aligns with Layout.Body */
  121. padding: ${space(3)} ${space(2)} ${space(2)};
  122. @media (min-width: ${p => p.theme.breakpoints.medium}) {
  123. padding: ${space(3)} ${space(4)} ${space(3)};
  124. }
  125. & h3,
  126. & h3 a {
  127. font-size: 14px;
  128. font-weight: 600;
  129. line-height: 1.2;
  130. color: ${p => p.theme.gray300};
  131. }
  132. & h3 {
  133. font-size: 14px;
  134. font-weight: 600;
  135. line-height: 1.2;
  136. padding: ${space(0.75)} 0;
  137. margin-bottom: ${space(2)};
  138. text-transform: uppercase;
  139. }
  140. `;
  141. const Header = styled('div')`
  142. display: flex;
  143. justify-content: space-between;
  144. `;
  145. const Section = styled('div')`
  146. border: 1px solid ${p => p.theme.innerBorder};
  147. border-radius: ${p => p.theme.borderRadius};
  148. `;