Просмотр исходного кода

feat(spans): Minimap now reflects what is shown on the span view (#28002)

Alberto Leal 3 лет назад
Родитель
Сommit
8bad06abc7

+ 40 - 96
static/app/components/events/interfaces/spans/header.tsx

@@ -18,6 +18,7 @@ import ConfigStore from 'app/stores/configStore';
 import space from 'app/styles/space';
 import {Organization} from 'app/types';
 import {EventTransaction} from 'app/types/event';
+import theme from 'app/utils/theme';
 
 import {
   MINIMAP_CONTAINER_HEIGHT,
@@ -32,14 +33,13 @@ import {ActiveOperationFilter} from './filter';
 import MeasurementsPanel from './measurementsPanel';
 import * as ScrollbarManager from './scrollbarManager';
 import {
+  EnhancedProcessedSpanType,
   ParsedTraceType,
   RawSpanType,
-  SpanChildrenLookupType,
   TickAlignment,
 } from './types';
 import {
   boundsGenerator,
-  getSpanID,
   getSpanOperation,
   SpanBoundsType,
   SpanGeneratedBoundsType,
@@ -54,6 +54,8 @@ type PropType = {
   event: EventTransaction;
   operationNameFilters: ActiveOperationFilter;
   rootSpan: RawSpanType;
+  spans: EnhancedProcessedSpanType[];
+  generateBounds: (bounds: SpanBoundsType) => SpanGeneratedBoundsType;
 };
 
 type State = {
@@ -439,7 +441,8 @@ class TraceViewHeader extends React.Component<PropType, State> {
                   }}
                 />
                 <ActualMinimap
-                  trace={this.props.trace}
+                  spans={this.props.spans}
+                  generateBounds={this.props.generateBounds}
                   dividerPosition={dividerPosition}
                   rootSpan={this.props.rootSpan}
                 />
@@ -508,26 +511,45 @@ class TraceViewHeader extends React.Component<PropType, State> {
 }
 
 class ActualMinimap extends React.PureComponent<{
-  trace: ParsedTraceType;
+  spans: EnhancedProcessedSpanType[];
+  generateBounds: (bounds: SpanBoundsType) => SpanGeneratedBoundsType;
   dividerPosition: number;
   rootSpan: RawSpanType;
 }> {
   renderRootSpan(): React.ReactNode {
-    const {trace, rootSpan} = this.props;
+    const {spans, generateBounds} = this.props;
 
-    const generateBounds = boundsGenerator({
-      traceStartTimestamp: trace.traceStartTimestamp,
-      traceEndTimestamp: trace.traceEndTimestamp,
-      viewStart: 0,
-      viewEnd: 1,
-    });
+    return spans.map(payload => {
+      switch (payload.type) {
+        case 'root_span':
+        case 'span':
+        case 'span_group_chain': {
+          const {span} = payload;
+
+          const spanBarColor: string = pickBarColor(getSpanOperation(span));
 
-    return this.renderSpan({
-      spanNumber: 0,
-      generateBounds,
-      span: rootSpan,
-      childSpans: trace.childSpans,
-    }).spanTree;
+          const bounds = generateBounds({
+            startTimestamp: span.start_timestamp,
+            endTimestamp: span.timestamp,
+          });
+          const {left: spanLeft, width: spanWidth} = this.getBounds(bounds);
+
+          return (
+            <MinimapSpanBar
+              style={{
+                backgroundColor:
+                  payload.type === 'span_group_chain' ? theme.blue300 : spanBarColor,
+                left: spanLeft,
+                width: spanWidth,
+              }}
+            />
+          );
+        }
+        default: {
+          return null;
+        }
+      }
+    });
   }
 
   getBounds(bounds: SpanGeneratedBoundsType): {
@@ -563,85 +585,6 @@ class ActualMinimap extends React.PureComponent<{
     }
   }
 
-  renderSpan({
-    spanNumber,
-    childSpans,
-    generateBounds,
-    span,
-  }: {
-    spanNumber: number;
-    childSpans: SpanChildrenLookupType;
-    generateBounds: (bounds: SpanBoundsType) => SpanGeneratedBoundsType;
-    span: Readonly<RawSpanType>;
-  }): {
-    spanTree: JSX.Element;
-    nextSpanNumber: number;
-  } {
-    const spanBarColor: string = pickBarColor(getSpanOperation(span));
-
-    const bounds = generateBounds({
-      startTimestamp: span.start_timestamp,
-      endTimestamp: span.timestamp,
-    });
-
-    const {left: spanLeft, width: spanWidth} = this.getBounds(bounds);
-
-    const spanChildren: Array<RawSpanType> = childSpans?.[getSpanID(span)] ?? [];
-
-    // Mark descendents as being rendered. This is to address potential recursion issues due to malformed data.
-    // For example if a span has a span_id that's identical to its parent_span_id.
-    childSpans = {
-      ...childSpans,
-    };
-    delete childSpans[getSpanID(span)];
-
-    type AccType = {
-      nextSpanNumber: number;
-      renderedSpanChildren: Array<JSX.Element>;
-    };
-
-    const reduced: AccType = spanChildren.reduce(
-      (acc: AccType, spanChild, index: number) => {
-        const key = `${getSpanID(spanChild, String(index))}`;
-
-        const results = this.renderSpan({
-          spanNumber: acc.nextSpanNumber,
-          childSpans,
-          generateBounds,
-          span: spanChild,
-        });
-
-        acc.renderedSpanChildren.push(
-          <React.Fragment key={key}>{results.spanTree}</React.Fragment>
-        );
-
-        acc.nextSpanNumber = results.nextSpanNumber;
-
-        return acc;
-      },
-      {
-        renderedSpanChildren: [],
-        nextSpanNumber: spanNumber + 1,
-      }
-    );
-
-    return {
-      nextSpanNumber: reduced.nextSpanNumber,
-      spanTree: (
-        <React.Fragment>
-          <MinimapSpanBar
-            style={{
-              backgroundColor: spanBarColor,
-              left: spanLeft,
-              width: spanWidth,
-            }}
-          />
-          {reduced.renderedSpanChildren}
-        </React.Fragment>
-      ),
-    };
-  }
-
   render() {
     const {dividerPosition} = this.props;
     return (
@@ -818,6 +761,7 @@ const MinimapSpanBar = styled('div')`
   margin: 2px 0;
   min-width: 1px;
   border-radius: 1px;
+  box-sizing: border-box;
 `;
 
 const BackgroundSlider = styled('div')`

+ 4 - 4
static/app/components/events/interfaces/spans/spanBar.tsx

@@ -119,6 +119,7 @@ type SpanBarProps = {
     | undefined;
   fetchEmbeddedChildrenState: FetchEmbeddedChildrenState;
   toggleSpanGroup: (() => void) | undefined;
+  numOfSpans: number;
 };
 
 type SpanBarState = {
@@ -521,8 +522,7 @@ class SpanBar extends React.Component<SpanBarProps, SpanBarState> {
             return;
           }
 
-          const shouldMoveMinimap =
-            this.props.trace.numOfSpans > NUM_OF_SPANS_FIT_IN_MINI_MAP;
+          const shouldMoveMinimap = this.props.numOfSpans > NUM_OF_SPANS_FIT_IN_MINI_MAP;
 
           if (!shouldMoveMinimap) {
             return;
@@ -616,10 +616,10 @@ class SpanBar extends React.Component<SpanBarProps, SpanBarState> {
           const panYPixels =
             totalHeightOfHiddenSpans + currentSpanHiddenRatio * MINIMAP_SPAN_BAR_HEIGHT;
 
-          // invariant: this.props.trace.numOfSpansend - spanNumberToStopMoving + 1 = NUM_OF_SPANS_FIT_IN_MINI_MAP
+          // invariant: this.props.numOfSpans - spanNumberToStopMoving + 1 = NUM_OF_SPANS_FIT_IN_MINI_MAP
 
           const spanNumberToStopMoving =
-            this.props.trace.numOfSpans + 1 - NUM_OF_SPANS_FIT_IN_MINI_MAP;
+            this.props.numOfSpans + 1 - NUM_OF_SPANS_FIT_IN_MINI_MAP;
 
           if (spanNumber > spanNumberToStopMoving) {
             // if the last span bar appears on the minimap, we do not want the minimap

+ 15 - 0
static/app/components/events/interfaces/spans/spanTree.tsx

@@ -156,6 +156,20 @@ class SpanTree extends React.Component<PropType> {
       spanNumber: number;
     };
 
+    const numOfSpans = spans.reduce((sum: number, payload: EnhancedProcessedSpanType) => {
+      switch (payload.type) {
+        case 'root_span':
+        case 'span':
+        case 'span_group_chain': {
+          return sum + 1;
+        }
+
+        default: {
+          return sum;
+        }
+      }
+    }, 0);
+
     const {spanTree, numOfSpansOutOfViewAbove, numOfFilteredSpansAbove} = spans.reduce(
       (acc: AccType, payload: EnhancedProcessedSpanType) => {
         const {type} = payload;
@@ -244,6 +258,7 @@ class SpanTree extends React.Component<PropType> {
             toggleEmbeddedChildren={payload.toggleEmbeddedChildren}
             fetchEmbeddedChildrenState={payload.fetchEmbeddedChildrenState}
             toggleSpanGroup={toggleSpanGroup}
+            numOfSpans={numOfSpans}
           />
         );
 

+ 8 - 0
static/app/components/events/interfaces/spans/traceView.tsx

@@ -39,6 +39,14 @@ class TraceView extends PureComponent<Props> {
             virtualScrollBarContainerRef={this.virtualScrollBarContainerRef}
             operationNameFilters={waterfallModel.operationNameFilters}
             rootSpan={waterfallModel.rootSpan.span}
+            spans={waterfallModel.getWaterfall({
+              viewStart: 0,
+              viewEnd: 1,
+            })}
+            generateBounds={waterfallModel.generateBounds({
+              viewStart: 0,
+              viewEnd: 1,
+            })}
           />
         );
       }}

+ 0 - 1
static/app/components/events/interfaces/spans/types.tsx

@@ -117,7 +117,6 @@ export type ParsedTraceType = {
   parentSpanID?: string;
   traceStartTimestamp: number;
   traceEndTimestamp: number;
-  numOfSpans: number;
   spans: SpanType[];
   description?: string;
 };

+ 0 - 2
static/app/components/events/interfaces/spans/utils.tsx

@@ -304,7 +304,6 @@ export function parseTrace(event: Readonly<EventTransaction>): ParsedTraceType {
       rootSpanID,
       rootSpanStatus,
       parentSpanID,
-      numOfSpans: 0,
       spans: [],
       description,
     };
@@ -331,7 +330,6 @@ export function parseTrace(event: Readonly<EventTransaction>): ParsedTraceType {
     rootSpanID,
     rootSpanStatus,
     parentSpanID,
-    numOfSpans: spans.length,
     spans,
     description,
   };