quickTraceMeta.tsx 4.6 KB

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