quickTraceMeta.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import {Location} from 'history';
  2. import Feature from 'sentry/components/acl/feature';
  3. import FeatureDisabled from 'sentry/components/acl/featureDisabled';
  4. import ErrorBoundary from 'sentry/components/errorBoundary';
  5. import {Hovercard} from 'sentry/components/hovercard';
  6. import ExternalLink from 'sentry/components/links/externalLink';
  7. import Link from 'sentry/components/links/link';
  8. import Placeholder from 'sentry/components/placeholder';
  9. import QuickTrace from 'sentry/components/quickTrace';
  10. import {generateTraceTarget} from 'sentry/components/quickTrace/utils';
  11. import {t, tct, tn} from 'sentry/locale';
  12. import {AvatarProject, OrganizationSummary} from 'sentry/types';
  13. import {Event} from 'sentry/types/event';
  14. import {trackAnalytics} from 'sentry/utils/analytics';
  15. import {getConfigureTracingDocsLink} from 'sentry/utils/docs';
  16. import {getShortEventId} from 'sentry/utils/events';
  17. import {
  18. QuickTraceQueryChildrenProps,
  19. TraceMeta,
  20. } from 'sentry/utils/performance/quickTrace/types';
  21. import useOrganization from 'sentry/utils/useOrganization';
  22. import {MetaData} from './styles';
  23. interface Props
  24. extends Pick<React.ComponentProps<typeof QuickTrace>, 'errorDest' | 'transactionDest'> {
  25. anchor: 'left' | 'right';
  26. event: Event;
  27. location: Location;
  28. quickTrace: QuickTraceQueryChildrenProps | null;
  29. traceMeta: TraceMeta | null;
  30. project?: AvatarProject;
  31. }
  32. function handleTraceLink(organization: OrganizationSummary) {
  33. trackAnalytics('quick_trace.trace_id.clicked', {
  34. organization: organization.id,
  35. source: 'events',
  36. });
  37. }
  38. export default function QuickTraceMeta({
  39. event,
  40. location,
  41. quickTrace,
  42. traceMeta,
  43. anchor,
  44. errorDest,
  45. transactionDest,
  46. project,
  47. }: Props) {
  48. const organization = useOrganization();
  49. const features = ['performance-view'];
  50. const noFeatureMessage = t('Requires performance monitoring.');
  51. const docsLink = getConfigureTracingDocsLink(project);
  52. const traceId = event.contexts?.trace?.trace_id ?? null;
  53. const traceTarget = generateTraceTarget(event, organization);
  54. let body: React.ReactNode;
  55. let footer: React.ReactNode;
  56. if (!traceId || !quickTrace || quickTrace.trace === null) {
  57. // this platform doesn't support performance don't show anything here
  58. if (docsLink === null) {
  59. return null;
  60. }
  61. body = t('Missing Trace');
  62. // need to configure tracing
  63. footer = <ExternalLink href={docsLink}>{t('Read the docs')}</ExternalLink>;
  64. } else {
  65. if (quickTrace.isLoading) {
  66. body = <Placeholder height="20px" />;
  67. } else if (quickTrace.error) {
  68. body = '\u2014';
  69. } else {
  70. body = (
  71. <ErrorBoundary mini>
  72. <QuickTrace
  73. event={event}
  74. quickTrace={{
  75. type: quickTrace.type,
  76. trace: quickTrace.trace,
  77. }}
  78. location={location}
  79. organization={organization}
  80. anchor={anchor}
  81. errorDest={errorDest}
  82. transactionDest={transactionDest}
  83. />
  84. </ErrorBoundary>
  85. );
  86. }
  87. footer = (
  88. <Link to={traceTarget} onClick={() => handleTraceLink(organization)}>
  89. {tct('View Full Trace: [id][events]', {
  90. id: getShortEventId(traceId ?? ''),
  91. events: traceMeta
  92. ? tn(' (%s event)', ' (%s events)', traceMeta.transactions + traceMeta.errors)
  93. : '',
  94. })}
  95. </Link>
  96. );
  97. }
  98. return (
  99. <Feature hookName="feature-disabled:performance-quick-trace" features={features}>
  100. {({hasFeature}) => {
  101. // also need to enable the performance feature
  102. if (!hasFeature) {
  103. footer = (
  104. <Hovercard
  105. body={
  106. <FeatureDisabled
  107. features={features}
  108. hideHelpToggle
  109. message={noFeatureMessage}
  110. featureName={noFeatureMessage}
  111. />
  112. }
  113. >
  114. {footer}
  115. </Hovercard>
  116. );
  117. }
  118. return <QuickTraceMetaBase body={body} footer={footer} />;
  119. }}
  120. </Feature>
  121. );
  122. }
  123. export function QuickTraceMetaBase({
  124. body,
  125. footer,
  126. }: {
  127. body: React.ReactNode;
  128. footer: React.ReactNode;
  129. }) {
  130. return (
  131. <MetaData
  132. headingText={t('Trace Navigator')}
  133. tooltipText={t(
  134. 'An abbreviated version of the full trace. Related frontend and backend services can be added to provide further visibility.'
  135. )}
  136. bodyText={<div data-test-id="quick-trace-body">{body}</div>}
  137. subtext={<div data-test-id="quick-trace-footer">{footer}</div>}
  138. />
  139. );
  140. }