traceView.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import {createRef, memo, useEffect, useState} from 'react';
  2. import {Observer} from 'mobx-react';
  3. import EmptyStateWarning from 'sentry/components/emptyStateWarning';
  4. import {t} from 'sentry/locale';
  5. import {Organization} from 'sentry/types';
  6. import * as CursorGuideHandler from './cursorGuideHandler';
  7. import * as DividerHandlerManager from './dividerHandlerManager';
  8. import DragManager, {DragManagerChildrenProps} from './dragManager';
  9. import TraceViewHeader from './header';
  10. import * as ScrollbarManager from './scrollbarManager';
  11. import * as SpanContext from './spanContext';
  12. import SpanTree from './spanTree';
  13. import {getTraceContext} from './utils';
  14. import WaterfallModel from './waterfallModel';
  15. type Props = {
  16. organization: Organization;
  17. waterfallModel: WaterfallModel;
  18. isEmbedded?: boolean;
  19. };
  20. function TraceView(props: Props) {
  21. const traceViewRef = createRef<HTMLDivElement>();
  22. const traceViewHeaderRef = createRef<HTMLDivElement>();
  23. const virtualScrollBarContainerRef = createRef<HTMLDivElement>();
  24. const minimapInteractiveRef = createRef<HTMLDivElement>();
  25. const [isMounted, setIsMounted] = useState(false);
  26. // Since this component is memoized, we need this hook here.
  27. // renderHeader performs some expensive calculations and so we only want to render once, hence why we memoize.
  28. // However, the virtualScrollbar will not be visible unless we have this effect here. This is a bit of a hack that will
  29. // cause the component to rerender by setting the isMounted state, so we will re-render only once the scrollbar ref is present.
  30. useEffect(() => {
  31. if (virtualScrollBarContainerRef.current && !isMounted) {
  32. setIsMounted(true);
  33. }
  34. }, [virtualScrollBarContainerRef, isMounted]);
  35. const renderHeader = (dragProps: DragManagerChildrenProps) => (
  36. <Observer>
  37. {() => {
  38. const {waterfallModel} = props;
  39. return (
  40. <TraceViewHeader
  41. traceViewHeaderRef={traceViewHeaderRef}
  42. organization={props.organization}
  43. minimapInteractiveRef={minimapInteractiveRef}
  44. dragProps={dragProps}
  45. trace={waterfallModel.parsedTrace}
  46. event={waterfallModel.event}
  47. virtualScrollBarContainerRef={virtualScrollBarContainerRef}
  48. operationNameFilters={waterfallModel.operationNameFilters}
  49. rootSpan={waterfallModel.rootSpan.span}
  50. spans={waterfallModel.getWaterfall({
  51. viewStart: 0,
  52. viewEnd: 1,
  53. })}
  54. generateBounds={waterfallModel.generateBounds({
  55. viewStart: 0,
  56. viewEnd: 1,
  57. })}
  58. />
  59. );
  60. }}
  61. </Observer>
  62. );
  63. const {organization, waterfallModel, isEmbedded} = props;
  64. if (!getTraceContext(waterfallModel.event)) {
  65. return (
  66. <EmptyStateWarning>
  67. <p>{t('There is no trace for this transaction')}</p>
  68. </EmptyStateWarning>
  69. );
  70. }
  71. return (
  72. <SpanContext.Provider>
  73. <SpanContext.Consumer>
  74. {spanContextProps => (
  75. <DragManager interactiveLayerRef={minimapInteractiveRef}>
  76. {(dragProps: DragManagerChildrenProps) => (
  77. <Observer>
  78. {() => {
  79. const parsedTrace = waterfallModel.parsedTrace;
  80. return (
  81. <CursorGuideHandler.Provider
  82. interactiveLayerRef={minimapInteractiveRef}
  83. dragProps={dragProps}
  84. trace={parsedTrace}
  85. >
  86. <DividerHandlerManager.Provider interactiveLayerRef={traceViewRef}>
  87. <DividerHandlerManager.Consumer>
  88. {dividerHandlerChildrenProps => {
  89. return (
  90. <ScrollbarManager.Provider
  91. dividerPosition={
  92. dividerHandlerChildrenProps.dividerPosition
  93. }
  94. interactiveLayerRef={virtualScrollBarContainerRef}
  95. dragProps={dragProps}
  96. isEmbedded={isEmbedded}
  97. >
  98. {renderHeader(dragProps)}
  99. <Observer>
  100. {() => (
  101. <SpanTree
  102. traceViewRef={traceViewRef}
  103. traceViewHeaderRef={traceViewHeaderRef}
  104. dragProps={dragProps}
  105. organization={organization}
  106. waterfallModel={waterfallModel}
  107. filterSpans={waterfallModel.filterSpans}
  108. spans={waterfallModel.getWaterfall({
  109. viewStart: dragProps.viewWindowStart,
  110. viewEnd: dragProps.viewWindowEnd,
  111. })}
  112. focusedSpanIds={waterfallModel.focusedSpanIds}
  113. spanContextProps={spanContextProps}
  114. operationNameFilters={
  115. waterfallModel.operationNameFilters
  116. }
  117. />
  118. )}
  119. </Observer>
  120. </ScrollbarManager.Provider>
  121. );
  122. }}
  123. </DividerHandlerManager.Consumer>
  124. </DividerHandlerManager.Provider>
  125. </CursorGuideHandler.Provider>
  126. );
  127. }}
  128. </Observer>
  129. )}
  130. </DragManager>
  131. )}
  132. </SpanContext.Consumer>
  133. </SpanContext.Provider>
  134. );
  135. }
  136. export default memo(TraceView);