traceWaterfallState.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import {useEffect, useRef} from 'react';
  2. import styled from '@emotion/styled';
  3. import useFeedbackWidget from 'sentry/components/feedback/widget/useFeedbackWidget';
  4. import LoadingIndicator from 'sentry/components/loadingIndicator';
  5. import {t} from 'sentry/locale';
  6. import {traceAnalytics} from 'sentry/views/performance/newTraceDetails/traceAnalytics';
  7. function TraceLoading() {
  8. return (
  9. // Dont flash the animation on load because it's annoying
  10. <LoadingContainer animate={false}>
  11. <NoMarginIndicator size={24}>
  12. <div>{t('Assembling the trace')}</div>
  13. </NoMarginIndicator>
  14. </LoadingContainer>
  15. );
  16. }
  17. function TraceError() {
  18. const linkref = useRef<HTMLAnchorElement>(null);
  19. const feedback = useFeedbackWidget({buttonRef: linkref});
  20. useEffect(() => {
  21. traceAnalytics.trackFailedToFetchTraceState();
  22. }, []);
  23. return (
  24. <LoadingContainer animate error>
  25. <div>{t('Ughhhhh, we failed to load your trace...')}</div>
  26. <div>
  27. {t('Seeing this often? Send us ')}
  28. {feedback ? (
  29. <a href="#" ref={linkref}>
  30. {t('feedback')}
  31. </a>
  32. ) : (
  33. <a href="mailto:support@sentry.io?subject=Trace%20fails%20to%20load">
  34. {t('feedback')}
  35. </a>
  36. )}
  37. </div>
  38. </LoadingContainer>
  39. );
  40. }
  41. function TraceEmpty() {
  42. const linkref = useRef<HTMLAnchorElement>(null);
  43. const feedback = useFeedbackWidget({buttonRef: linkref});
  44. useEffect(() => {
  45. traceAnalytics.trackEmptyTraceState();
  46. }, []);
  47. return (
  48. <LoadingContainer animate>
  49. <div>{t('This trace does not contain any data?!')}</div>
  50. <div>
  51. {t('Seeing this often? Send us ')}
  52. {feedback ? (
  53. <a href="#" ref={linkref}>
  54. {t('feedback')}
  55. </a>
  56. ) : (
  57. <a href="mailto:support@sentry.io?subject=Trace%20does%20not%20contain%20data">
  58. {t('feedback')}
  59. </a>
  60. )}
  61. </div>
  62. </LoadingContainer>
  63. );
  64. }
  65. const LoadingContainer = styled('div')<{animate: boolean; error?: boolean}>`
  66. display: flex;
  67. justify-content: center;
  68. align-items: center;
  69. flex-direction: column;
  70. left: 50%;
  71. top: 50%;
  72. position: absolute;
  73. height: auto;
  74. font-size: ${p => p.theme.fontSizeMedium};
  75. color: ${p => p.theme.gray300};
  76. z-index: 30;
  77. padding: 24px;
  78. background-color: ${p => p.theme.background};
  79. border-radius: ${p => p.theme.borderRadius};
  80. border: 1px solid ${p => p.theme.border};
  81. transform-origin: 50% 50%;
  82. transform: translate(-50%, -50%);
  83. animation: ${p =>
  84. p.animate
  85. ? `${p.error ? 'showLoadingContainerShake' : 'showLoadingContainer'} 300ms cubic-bezier(0.61, 1, 0.88, 1) forwards`
  86. : 'none'};
  87. @keyframes showLoadingContainer {
  88. from {
  89. opacity: 0.6;
  90. transform: scale(0.99) translate(-50%, -50%);
  91. }
  92. to {
  93. opacity: 1;
  94. transform: scale(1) translate(-50%, -50%);
  95. }
  96. }
  97. @keyframes showLoadingContainerShake {
  98. 0% {
  99. transform: translate(-50%, -50%);
  100. }
  101. 25% {
  102. transform: translate(-51%, -50%);
  103. }
  104. 75% {
  105. transform: translate(-49%, -50%);
  106. }
  107. 100% {
  108. transform: translate(-50%, -50%);
  109. }
  110. }
  111. `;
  112. const NoMarginIndicator = styled(LoadingIndicator)`
  113. margin: 0;
  114. `;
  115. export const TraceWaterfallState = {
  116. Loading: TraceLoading,
  117. Error: TraceError,
  118. Empty: TraceEmpty,
  119. };