123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- import styled from '@emotion/styled';
- import {SectionHeading} from 'sentry/components/charts/styles';
- import Count from 'sentry/components/count';
- import PerformanceDuration from 'sentry/components/performanceDuration';
- import {t, tct} from 'sentry/locale';
- import {space} from 'sentry/styles/space';
- import {defined} from 'sentry/utils';
- import {formatPercentage} from 'sentry/utils/number/formatPercentage';
- import type {SpanSlug, SuspectSpan} from 'sentry/utils/performance/suspectSpans/types';
- interface HeaderProps {
- spanSlug: SpanSlug;
- totalCount: number | null;
- suspectSpan?: SuspectSpan;
- }
- export default function SpanDetailsHeader(props: HeaderProps) {
- const {spanSlug, suspectSpan, totalCount} = props;
- const {
- description,
- frequency,
- avgOccurrences,
- p50ExclusiveTime,
- p75ExclusiveTime,
- p95ExclusiveTime,
- p99ExclusiveTime,
- sumExclusiveTime,
- } = suspectSpan ?? {};
- return (
- <ContentHeader>
- <HeaderInfo data-test-id="header-operation-name">
- <StyledSectionHeading>{t('Span Operation')}</StyledSectionHeading>
- <SectionBody>
- <SpanLabelContainer>{description ?? emptyValue}</SpanLabelContainer>
- </SectionBody>
- <SectionSubtext data-test-id="operation-name">{spanSlug.op}</SectionSubtext>
- </HeaderInfo>
- <HeaderInfo data-test-id="header-percentiles">
- <StyledSectionHeading>{t('Self Time Percentiles')}</StyledSectionHeading>
- <PercentileHeaderBodyWrapper>
- <div data-test-id="section-p50">
- <SectionBody>
- {defined(p50ExclusiveTime) ? (
- <PerformanceDuration abbreviation milliseconds={p50ExclusiveTime} />
- ) : (
- '\u2014'
- )}
- </SectionBody>
- <SectionSubtext>{t('p50')}</SectionSubtext>
- </div>
- <div data-test-id="section-p75">
- <SectionBody>
- {defined(p75ExclusiveTime) ? (
- <PerformanceDuration abbreviation milliseconds={p75ExclusiveTime} />
- ) : (
- '\u2014'
- )}
- </SectionBody>
- <SectionSubtext>{t('p75')}</SectionSubtext>
- </div>
- <div data-test-id="section-p95">
- <SectionBody>
- {defined(p95ExclusiveTime) ? (
- <PerformanceDuration abbreviation milliseconds={p95ExclusiveTime} />
- ) : (
- '\u2014'
- )}
- </SectionBody>
- <SectionSubtext>{t('p95')}</SectionSubtext>
- </div>
- <div data-test-id="section-p99">
- <SectionBody>
- {defined(p99ExclusiveTime) ? (
- <PerformanceDuration abbreviation milliseconds={p99ExclusiveTime} />
- ) : (
- '\u2014'
- )}
- </SectionBody>
- <SectionSubtext>{t('p99')}</SectionSubtext>
- </div>
- </PercentileHeaderBodyWrapper>
- </HeaderInfo>
- <HeaderInfo data-test-id="header-frequency">
- <StyledSectionHeading>{t('Frequency')}</StyledSectionHeading>
- <SectionBody>
- {defined(frequency) && defined(totalCount)
- ? formatPercentage(Math.min(frequency, totalCount) / totalCount)
- : '\u2014'}
- </SectionBody>
- <SectionSubtext>
- {defined(avgOccurrences)
- ? tct('[times] times per event', {times: avgOccurrences.toFixed(2)})
- : '\u2014'}
- </SectionSubtext>
- </HeaderInfo>
- <HeaderInfo data-test-id="header-total-exclusive-time">
- <StyledSectionHeading>{t('Total Self Time')}</StyledSectionHeading>
- <SectionBody>
- {defined(sumExclusiveTime) ? (
- <PerformanceDuration abbreviation milliseconds={sumExclusiveTime} />
- ) : (
- '\u2014'
- )}
- </SectionBody>
- <SectionSubtext>
- {defined(frequency)
- ? tct('[events] events', {events: <Count value={frequency} />})
- : '\u2014'}
- </SectionSubtext>
- </HeaderInfo>
- </ContentHeader>
- );
- }
- const ContentHeader = styled('div')`
- display: grid;
- grid-template-columns: 1fr;
- gap: ${space(4)};
- margin-bottom: ${space(2)};
- @media (min-width: ${p => p.theme.breakpoints.medium}) {
- grid-template-columns: 1fr repeat(3, max-content);
- }
- `;
- const HeaderInfo = styled('div')`
- ${p => p.theme.overflowEllipsis};
- height: 78px;
- `;
- const StyledSectionHeading = styled(SectionHeading)`
- margin: 0;
- `;
- const SectionBody = styled('div')<{overflowEllipsis?: boolean}>`
- font-size: ${p => p.theme.fontSizeExtraLarge};
- padding: ${space(0.5)} 0;
- max-height: 32px;
- `;
- const SectionSubtext = styled('div')`
- color: ${p => p.theme.subText};
- font-size: ${p => p.theme.fontSizeMedium};
- `;
- const PercentileHeaderBodyWrapper = styled('div')`
- display: grid;
- grid-template-columns: repeat(4, max-content);
- gap: ${space(3)};
- `;
- export const SpanLabelContainer = styled('div')`
- ${p => p.theme.overflowEllipsis};
- `;
- const EmptyValueContainer = styled('span')`
- color: ${p => p.theme.gray300};
- `;
- const emptyValue = <EmptyValueContainer>{t('(unnamed span)')}</EmptyValueContainer>;
|