123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- import {useTheme} from '@emotion/react';
- import countBy from 'lodash/countBy';
- import type {SpanBarType} from 'sentry/components/performance/waterfall/constants';
- import {
- getSpanBarColours,
- ROW_HEIGHT,
- } from 'sentry/components/performance/waterfall/constants';
- import {DurationPill, RowRectangle} from 'sentry/components/performance/waterfall/rowBar';
- import {
- ConnectorBar,
- TOGGLE_BORDER_BOX,
- TreeConnector,
- } from 'sentry/components/performance/waterfall/treeConnector';
- import {
- getDurationDisplay,
- getHumanDuration,
- } from 'sentry/components/performance/waterfall/utils';
- import {t} from 'sentry/locale';
- import type {AggregateEventTransaction, EventTransaction} from 'sentry/types/event';
- import toPercent from 'sentry/utils/number/toPercent';
- import {SpanGroupBar} from './spanGroupBar';
- import type {EnhancedSpan, ProcessedSpanType, TreeDepthType} from './types';
- import type {SpanBoundsType, SpanGeneratedBoundsType, VerticalMark} from './utils';
- import {
- getSpanGroupBounds,
- getSpanGroupTimestamps,
- getSpanOperation,
- isOrphanSpan,
- isOrphanTreeDepth,
- unwrapTreeDepth,
- } from './utils';
- export type SpanDescendantGroupBarProps = {
- addContentSpanBarRef: (instance: HTMLDivElement | null) => void;
- continuingTreeDepths: Array<TreeDepthType>;
- didAnchoredSpanMount: () => boolean;
- event: Readonly<EventTransaction | AggregateEventTransaction>;
- generateBounds: (bounds: SpanBoundsType) => SpanGeneratedBoundsType;
- getCurrentLeftPos: () => number;
- onWheel: (deltaX: number) => void;
- removeContentSpanBarRef: (instance: HTMLDivElement | null) => void;
- span: ProcessedSpanType;
- spanGrouping: EnhancedSpan[];
- spanNumber: number;
- toggleSpanGroup: () => void;
- treeDepth: number;
- measurements?: Map<number, VerticalMark>;
- spanBarType?: SpanBarType;
- };
- export function SpanDescendantGroupBar(props: SpanDescendantGroupBarProps) {
- const {
- continuingTreeDepths,
- event,
- generateBounds,
- getCurrentLeftPos,
- span,
- spanGrouping,
- spanNumber,
- toggleSpanGroup,
- onWheel,
- addContentSpanBarRef,
- removeContentSpanBarRef,
- didAnchoredSpanMount,
- spanBarType,
- measurements,
- } = props;
- const theme = useTheme();
- function renderGroupSpansTitle() {
- if (spanGrouping.length === 0) {
- return '';
- }
- const operationCounts = countBy(spanGrouping, enhancedSpan =>
- getSpanOperation(enhancedSpan.span)
- );
- const hasOthers = Object.keys(operationCounts).length > 1;
- const [mostFrequentOperationName] = Object.entries(operationCounts).reduce(
- (acc, [operationNameKey, count]) => {
- if (count > acc[1]) {
- return [operationNameKey, count];
- }
- return acc;
- }
- );
- return (
- <strong>{`${t('Autogrouped ')}\u2014 ${mostFrequentOperationName}${
- hasOthers ? t(' and more') : ''
- }`}</strong>
- );
- }
- function renderSpanTreeConnector() {
- const {treeDepth: spanTreeDepth} = props;
- const connectorBars: Array<React.ReactNode> = continuingTreeDepths.map(treeDepth => {
- const depth: number = unwrapTreeDepth(treeDepth);
- if (depth === 0) {
-
-
-
- return null;
- }
- const left = ((spanTreeDepth - depth) * (TOGGLE_BORDER_BOX / 2) + 2) * -1;
- return (
- <ConnectorBar
- style={{left}}
- key={`span-group-${depth}`}
- orphanBranch={isOrphanTreeDepth(treeDepth)}
- />
- );
- });
- connectorBars.push(
- <ConnectorBar
- style={{
- right: '15px',
- height: `${ROW_HEIGHT / 2}px`,
- bottom: `-${ROW_HEIGHT / 2 + 1}px`,
- top: 'auto',
- }}
- key="collapsed-span-group-row-bottom"
- orphanBranch={false}
- />
- );
- return (
- <TreeConnector isLast hasToggler orphanBranch={isOrphanSpan(span)}>
- {connectorBars}
- </TreeConnector>
- );
- }
- function renderSpanRectangles() {
- const bounds = getSpanGroupBounds(spanGrouping, generateBounds);
- const durationDisplay = getDurationDisplay(bounds);
- const {startTimestamp, endTimestamp} = getSpanGroupTimestamps(spanGrouping);
- const duration = Math.abs(endTimestamp - startTimestamp);
- const durationString = getHumanDuration(duration);
- return (
- <RowRectangle
- style={{
- backgroundColor: getSpanBarColours(spanBarType, theme).primary,
- left: `min(${toPercent(bounds.left || 0)}, calc(100% - 1px))`,
- width: toPercent(bounds.width || 0),
- }}
- >
- <DurationPill
- durationDisplay={durationDisplay}
- showDetail={false}
- spanBarType={spanBarType}
- >
- {durationString}
- </DurationPill>
- </RowRectangle>
- );
- }
- return (
- <SpanGroupBar
- data-test-id="span-descendant-group-bar"
- event={event}
- span={span}
- measurements={measurements}
- spanGrouping={spanGrouping}
- treeDepth={props.treeDepth}
- spanNumber={spanNumber}
- generateBounds={generateBounds}
- toggleSpanGroup={toggleSpanGroup}
- renderSpanTreeConnector={renderSpanTreeConnector}
- renderGroupSpansTitle={renderGroupSpansTitle}
- renderSpanRectangles={renderSpanRectangles}
- onWheel={onWheel}
- addContentSpanBarRef={addContentSpanBarRef}
- removeContentSpanBarRef={removeContentSpanBarRef}
- didAnchoredSpanMount={didAnchoredSpanMount}
- getCurrentLeftPos={getCurrentLeftPos}
- spanBarType={spanBarType}
- />
- );
- }
|