meta.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import {useMemo} from 'react';
  2. import styled from '@emotion/styled';
  3. import {SectionHeading} from 'sentry/components/charts/styles';
  4. import TimeSince from 'sentry/components/timeSince';
  5. import {t} from 'sentry/locale';
  6. import {space} from 'sentry/styles/space';
  7. import type {EventTransaction} from 'sentry/types/event';
  8. import type {Organization} from 'sentry/types/organization';
  9. import getDuration from 'sentry/utils/duration/getDuration';
  10. import type {
  11. TraceErrorOrIssue,
  12. TraceMeta,
  13. } from 'sentry/utils/performance/quickTrace/types';
  14. import type {UseApiQueryResult} from 'sentry/utils/queryClient';
  15. import type RequestError from 'sentry/utils/requestError/requestError';
  16. import {TraceDrawerComponents} from '../traceDrawer/details/styles';
  17. import type {TraceTree} from '../traceModels/traceTree';
  18. type MetaDataProps = {
  19. bodyText: React.ReactNode;
  20. headingText: string;
  21. rightAlignBody?: boolean;
  22. };
  23. function MetaSection({headingText, bodyText, rightAlignBody}: MetaDataProps) {
  24. return (
  25. <HeaderInfo>
  26. <StyledSectionHeading>{headingText}</StyledSectionHeading>
  27. <SectionBody rightAlign={rightAlignBody}>{bodyText}</SectionBody>
  28. </HeaderInfo>
  29. );
  30. }
  31. const HeaderInfo = styled('div')`
  32. white-space: nowrap;
  33. `;
  34. const StyledSectionHeading = styled(SectionHeading)`
  35. font-size: ${p => p.theme.fontSizeSmall};
  36. margin: 0;
  37. `;
  38. const SectionBody = styled('div')<{rightAlign?: boolean}>`
  39. font-size: ${p => p.theme.fontSizeExtraLarge};
  40. text-align: ${p => (p.rightAlign ? 'right' : 'left')};
  41. padding: ${space(0.5)} 0;
  42. max-height: 32px;
  43. `;
  44. interface MetaProps {
  45. meta: TraceMeta | undefined;
  46. organization: Organization;
  47. rootEventResults: UseApiQueryResult<EventTransaction, RequestError>;
  48. tree: TraceTree;
  49. }
  50. export function Meta(props: MetaProps) {
  51. const traceNode = props.tree.root.children[0];
  52. const uniqueErrorIssues = useMemo(() => {
  53. if (!traceNode) {
  54. return [];
  55. }
  56. const unique: TraceErrorOrIssue[] = [];
  57. const seenIssues: Set<number> = new Set();
  58. for (const issue of traceNode.errors) {
  59. if (seenIssues.has(issue.issue_id)) {
  60. continue;
  61. }
  62. seenIssues.add(issue.issue_id);
  63. unique.push(issue);
  64. }
  65. return unique;
  66. }, [traceNode]);
  67. const uniquePerformanceIssues = useMemo(() => {
  68. if (!traceNode) {
  69. return [];
  70. }
  71. const unique: TraceErrorOrIssue[] = [];
  72. const seenIssues: Set<number> = new Set();
  73. for (const issue of traceNode.performance_issues) {
  74. if (seenIssues.has(issue.issue_id)) {
  75. continue;
  76. }
  77. seenIssues.add(issue.issue_id);
  78. unique.push(issue);
  79. }
  80. return unique;
  81. }, [traceNode]);
  82. const uniqueIssuesCount = uniqueErrorIssues.length + uniquePerformanceIssues.length;
  83. return (
  84. <MetaWrapper>
  85. <MetaSection
  86. headingText={t('Issues')}
  87. bodyText={
  88. uniqueIssuesCount > 0 ? (
  89. <TraceDrawerComponents.IssuesLink node={traceNode}>
  90. {uniqueIssuesCount}
  91. </TraceDrawerComponents.IssuesLink>
  92. ) : uniqueIssuesCount === 0 ? (
  93. 0
  94. ) : (
  95. '\u2014'
  96. )
  97. }
  98. />
  99. <MetaSection
  100. headingText={t('Events')}
  101. bodyText={(props.meta?.transactions ?? 0) + (props.meta?.errors ?? 0)}
  102. />
  103. {traceNode ? (
  104. <MetaSection
  105. headingText={t('Age')}
  106. bodyText={
  107. <TimeSince
  108. unitStyle="extraShort"
  109. date={new Date(traceNode.space[0])}
  110. tooltipShowSeconds
  111. suffix=""
  112. />
  113. }
  114. />
  115. ) : null}
  116. {traceNode ? (
  117. <MetaSection
  118. headingText={t('Trace Duration')}
  119. rightAlignBody
  120. bodyText={
  121. traceNode.space[1] > 0
  122. ? getDuration(traceNode.space[1] / 1e3, 2, true)
  123. : '\u2014'
  124. }
  125. />
  126. ) : null}
  127. </MetaWrapper>
  128. );
  129. }
  130. const MetaWrapper = styled('div')`
  131. display: flex;
  132. align-items: center;
  133. gap: ${space(2)};
  134. ${HeaderInfo} {
  135. min-height: 0;
  136. }
  137. ${SectionBody} {
  138. padding: 0;
  139. }
  140. `;