Browse Source

fix(trace-view): Consolidate bar colors in waterfall with span view (#25416)

Trace view is currently picking colors for the bars using the depth. This change
consolidates the color picking to use the same process as the span view.
Tony Xiao 3 years ago
parent
commit
1e5aac5350

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

@@ -4,7 +4,7 @@ import styled from '@emotion/styled';
 import CheckboxFancy from 'app/components/checkboxFancy/checkboxFancy';
 import DropdownButton from 'app/components/dropdownButton';
 import DropdownControl from 'app/components/dropdownControl';
-import {pickSpanBarColour} from 'app/components/events/interfaces/spans/utils';
+import {pickBarColour} from 'app/components/waterfallTree/utils';
 import {IconFilter} from 'app/icons';
 import {t, tn} from 'app/locale';
 import overflowEllipsis from 'app/styles/overflowEllipsis';
@@ -155,7 +155,7 @@ class Filter extends React.Component<Props> {
 
                 return (
                   <ListItem key={operationName} isChecked={isActive}>
-                    <OperationDot backgroundColor={pickSpanBarColour(operationName)} />
+                    <OperationDot backgroundColor={pickBarColour(operationName)} />
                     <OperationName>{operationName}</OperationName>
                     <OperationCount>{operationCount}</OperationCount>
                     <CheckboxFancy

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

@@ -10,6 +10,7 @@ import {
 } from 'app/components/waterfallTree/miniHeader';
 import {
   getHumanDuration,
+  pickBarColour,
   rectOfContent,
   toPercent,
 } from 'app/components/waterfallTree/utils';
@@ -33,7 +34,6 @@ import {
   boundsGenerator,
   getSpanID,
   getSpanOperation,
-  pickSpanBarColour,
   SpanBoundsType,
   SpanGeneratedBoundsType,
 } from './utils';
@@ -577,7 +577,7 @@ class ActualMinimap extends React.PureComponent<{
     spanTree: JSX.Element;
     nextSpanNumber: number;
   } {
-    const spanBarColour: string = pickSpanBarColour(getSpanOperation(span));
+    const spanBarColour: string = pickBarColour(getSpanOperation(span));
 
     const bounds = generateBounds({
       startTimestamp: span.start_timestamp,

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

@@ -3,6 +3,7 @@ import styled from '@emotion/styled';
 
 import GuideAnchor from 'app/components/assistant/guideAnchor';
 import {MessageRow} from 'app/components/waterfallTree/messageRow';
+import {pickBarColour} from 'app/components/waterfallTree/utils';
 import {t, tct} from 'app/locale';
 import {Organization} from 'app/types';
 import {EventTransaction} from 'app/types/event';
@@ -30,7 +31,6 @@ import {
   isEventFromBrowserJavaScriptSDK,
   isGapSpan,
   isOrphanSpan,
-  pickSpanBarColour,
   SpanBoundsType,
   SpanGeneratedBoundsType,
 } from './utils';
@@ -184,7 +184,7 @@ class SpanTree extends React.Component<PropType> {
   }): RenderedSpanTree => {
     const {orgId, event, spansWithErrors, organization} = this.props;
 
-    const spanBarColour: string = pickSpanBarColour(getSpanOperation(span));
+    const spanBarColour: string = pickBarColour(getSpanOperation(span));
     const spanChildren: Array<RawSpanType> = childSpans?.[getSpanID(span)] ?? [];
 
     // Mark descendents as being rendered. This is to address potential recursion issues due to malformed data.

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

@@ -3,7 +3,6 @@ import isString from 'lodash/isString';
 import set from 'lodash/set';
 import moment from 'moment';
 
-import CHART_PALETTE from 'app/constants/chartPalette';
 import {EntryType, EventTransaction} from 'app/types/event';
 import {assert} from 'app/types/utils';
 import {WEB_VITAL_DETAILS} from 'app/utils/performance/vitals/constants';
@@ -180,41 +179,6 @@ export const boundsGenerator = (bounds: {
   };
 };
 
-const getLetterIndex = (letter: string): number => {
-  const index = 'abcdefghijklmnopqrstuvwxyz'.indexOf(letter) || 0;
-  return index === -1 ? 0 : index;
-};
-
-const colorsAsArray = Object.keys(CHART_PALETTE).map(key => CHART_PALETTE[17][key]);
-
-export const spanColors = {
-  default: CHART_PALETTE[17][4],
-  transaction: CHART_PALETTE[17][8],
-  http: CHART_PALETTE[17][10],
-  db: CHART_PALETTE[17][17],
-};
-
-export const pickSpanBarColour = (input: string | undefined): string => {
-  // We pick the color for span bars using the first three letters of the op name.
-  // That way colors stay consistent between transactions.
-
-  if (!input || input.length < 3) {
-    return CHART_PALETTE[17][4];
-  }
-
-  if (spanColors[input]) {
-    return spanColors[input];
-  }
-
-  const letterIndex1 = getLetterIndex(input.slice(0, 1));
-  const letterIndex2 = getLetterIndex(input.slice(1, 2));
-  const letterIndex3 = getLetterIndex(input.slice(2, 3));
-
-  return colorsAsArray[
-    (letterIndex1 + letterIndex2 + letterIndex3) % colorsAsArray.length
-  ];
-};
-
 export function generateRootSpan(trace: ParsedTraceType): RawSpanType {
   const rootSpan: RawSpanType = {
     trace_id: trace.traceID,

+ 2 - 2
static/app/components/events/opsBreakdown.tsx

@@ -8,8 +8,8 @@ import {
   SpanEntry,
   TraceContextType,
 } from 'app/components/events/interfaces/spans/types';
-import {pickSpanBarColour} from 'app/components/events/interfaces/spans/utils';
 import QuestionTooltip from 'app/components/questionTooltip';
+import {pickBarColour} from 'app/components/waterfallTree/utils';
 import {t} from 'app/locale';
 import space from 'app/styles/space';
 import {EntryType, Event, EventTransaction} from 'app/types/event';
@@ -237,7 +237,7 @@ class OpsBreakdown extends React.Component<Props> {
 
       const durLabel = Math.round(totalInterval * 1000 * 100) / 100;
       const pctLabel = isFinite(percentage) ? Math.round(percentage * 100) : '∞';
-      const opsColor: string = pickSpanBarColour(operationName);
+      const opsColor: string = pickBarColour(operationName);
 
       return (
         <OpsLine key={operationName}>

+ 36 - 0
static/app/components/waterfallTree/utils.tsx

@@ -1,4 +1,5 @@
 import {DurationDisplay} from 'app/components/waterfallTree/types';
+import CHART_PALETTE from 'app/constants/chartPalette';
 import space from 'app/styles/space';
 import {Theme} from 'app/utils/theme';
 
@@ -185,3 +186,38 @@ export const clamp = (value: number, min: number, max: number): number => {
   }
   return value;
 };
+
+const getLetterIndex = (letter: string): number => {
+  const index = 'abcdefghijklmnopqrstuvwxyz'.indexOf(letter) || 0;
+  return index === -1 ? 0 : index;
+};
+
+const colorsAsArray = Object.keys(CHART_PALETTE).map(key => CHART_PALETTE[17][key]);
+
+export const barColors = {
+  default: CHART_PALETTE[17][4],
+  transaction: CHART_PALETTE[17][8],
+  http: CHART_PALETTE[17][10],
+  db: CHART_PALETTE[17][17],
+};
+
+export const pickBarColour = (input: string | undefined): string => {
+  // We pick the color for span bars using the first three letters of the op name.
+  // That way colors stay consistent between transactions.
+
+  if (!input || input.length < 3) {
+    return CHART_PALETTE[17][4];
+  }
+
+  if (barColors[input]) {
+    return barColors[input];
+  }
+
+  const letterIndex1 = getLetterIndex(input.slice(0, 1));
+  const letterIndex2 = getLetterIndex(input.slice(1, 2));
+  const letterIndex3 = getLetterIndex(input.slice(2, 3));
+
+  return colorsAsArray[
+    (letterIndex1 + letterIndex2 + letterIndex3) % colorsAsArray.length
+  ];
+};

+ 2 - 2
static/app/utils/discover/fieldRenderers.tsx

@@ -5,7 +5,6 @@ import partial from 'lodash/partial';
 
 import Count from 'app/components/count';
 import Duration from 'app/components/duration';
-import {pickSpanBarColour} from 'app/components/events/interfaces/spans/utils';
 import ProjectBadge from 'app/components/idBadge/projectBadge';
 import UserBadge from 'app/components/idBadge/userBadge';
 import UserMisery from 'app/components/userMisery';
@@ -14,6 +13,7 @@ import {DurationPill, RowRectangle} from 'app/components/waterfallTree/rowBar';
 import {
   getDurationDisplay,
   getHumanDuration,
+  pickBarColour,
   toPercent,
 } from 'app/components/waterfallTree/utils';
 import {t} from 'app/locale';
@@ -497,7 +497,7 @@ const spanOperationBreakdownRenderer = (field: string) => (
       <RowRectangle
         spanBarHatch={false}
         style={{
-          backgroundColor: pickSpanBarColour(operationName),
+          backgroundColor: pickBarColour(operationName),
           left: 0,
           width: toPercent(widthPercentage || 0),
         }}

+ 3 - 1
static/app/views/performance/traceDetails/content.tsx

@@ -23,7 +23,7 @@ import {
   VirtualScrollbar,
   VirtualScrollbarGrip,
 } from 'app/components/waterfallTree/miniHeader';
-import {toPercent} from 'app/components/waterfallTree/utils';
+import {pickBarColour, toPercent} from 'app/components/waterfallTree/utils';
 import {IconInfo} from 'app/icons';
 import {t, tct, tn} from 'app/locale';
 import {Organization} from 'app/types';
@@ -426,6 +426,7 @@ class TraceDetailsContent extends React.Component<Props, State> {
             index={index}
             isVisible={isVisible}
             renderedChildren={accumulated.renderedChildren}
+            barColour={pickBarColour(transaction['transaction.op'])}
           />
         </React.Fragment>
       ),
@@ -539,6 +540,7 @@ class TraceDetailsContent extends React.Component<Props, State> {
                       index={0}
                       isVisible
                       renderedChildren={transactionGroups}
+                      barColour={pickBarColour('')}
                     />
                     {this.renderInfoMessage({
                       isVisible: true,

+ 4 - 8
static/app/views/performance/traceDetails/transactionBar.tsx

@@ -1,5 +1,4 @@
 import React from 'react';
-import {withTheme} from 'emotion-theming';
 import {Location} from 'history';
 
 import Count from 'app/components/count';
@@ -35,7 +34,6 @@ import {
 import {Organization} from 'app/types';
 import {TraceFullDetailed} from 'app/utils/performance/quickTrace/types';
 import Projects from 'app/utils/projects';
-import {Theme} from 'app/utils/theme';
 
 import {DividerContainer, ErrorBadge, TransactionBarTitleContent} from './styles';
 import TransactionDetail from './transactionDetail';
@@ -56,7 +54,7 @@ type Props = {
   isExpanded: boolean;
   isVisible: boolean;
   toggleExpandedState: () => void;
-  theme: Theme;
+  barColour?: string;
 };
 
 type State = {
@@ -330,11 +328,9 @@ class TransactionBar extends React.Component<Props, State> {
   }
 
   renderRectangle() {
-    const {transaction, traceInfo, theme} = this.props;
+    const {transaction, traceInfo, barColour} = this.props;
     const {showDetail} = this.state;
 
-    const palette = theme.charts.getColorPalette(traceInfo.maxGeneration);
-
     // Use 1 as the difference in the event that startTimestamp === endTimestamp
     const delta = Math.abs(traceInfo.endTimestamp - traceInfo.startTimestamp) || 1;
     const startPosition = Math.abs(
@@ -348,7 +344,7 @@ class TransactionBar extends React.Component<Props, State> {
       <RowRectangle
         spanBarHatch={false}
         style={{
-          backgroundColor: palette[transaction.generation % palette.length],
+          backgroundColor: barColour,
           left: `clamp(0%, ${toPercent(startPercentage || 0)}, calc(100% - 1px))`,
           width: toPercent(widthPercentage || 0),
         }}
@@ -454,4 +450,4 @@ function getOffset(generation) {
   return generation * (TOGGLE_BORDER_BOX / 2) + MARGIN_LEFT;
 }
 
-export default withTheme(TransactionBar);
+export default TransactionBar;

+ 3 - 0
static/app/views/performance/traceDetails/transactionGroup.tsx

@@ -18,6 +18,7 @@ type Props = {
   index: number;
   isVisible: boolean;
   renderedChildren: React.ReactNode[];
+  barColour?: string;
 };
 
 type State = {
@@ -45,6 +46,7 @@ class TransactionGroup extends React.Component<Props, State> {
       index,
       isVisible,
       renderedChildren,
+      barColour,
     } = this.props;
     const {isExpanded} = this.state;
 
@@ -62,6 +64,7 @@ class TransactionGroup extends React.Component<Props, State> {
           isExpanded={isExpanded}
           toggleExpandedState={this.toggleExpandedState}
           isVisible={isVisible}
+          barColour={barColour}
         />
         {isExpanded && renderedChildren}
       </React.Fragment>

Some files were not shown because too many files changed in this diff