details.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import React from 'react';
  2. import styled from '@emotion/styled';
  3. import ErrorBoundary from 'sentry/components/errorBoundary';
  4. import DetailedError from 'sentry/components/errors/detailedError';
  5. import NotFound from 'sentry/components/errors/notFound';
  6. import {HeaderContainer} from 'sentry/components/events/interfaces/spans/header';
  7. import * as Layout from 'sentry/components/layouts/thirds';
  8. import ReplayTimeline from 'sentry/components/replays/breadcrumbs/replayTimeline';
  9. import {Provider as ReplayContextProvider} from 'sentry/components/replays/replayContext';
  10. import ReplayView from 'sentry/components/replays/replayView';
  11. import {t} from 'sentry/locale';
  12. import {PageContent} from 'sentry/styles/organization';
  13. import space from 'sentry/styles/space';
  14. import useFullscreen from 'sentry/utils/replays/hooks/useFullscreen';
  15. import useReplayData from 'sentry/utils/replays/hooks/useReplayData';
  16. import {useRouteContext} from 'sentry/utils/useRouteContext';
  17. import AsideTabs from './detail/asideTabs';
  18. import DetailLayout from './detail/detailLayout';
  19. import FocusArea from './detail/focusArea';
  20. import FocusTabs from './detail/focusTabs';
  21. function ReplayDetails() {
  22. const {
  23. location,
  24. params: {eventSlug, orgId},
  25. } = useRouteContext();
  26. const {
  27. t: initialTimeOffset, // Time, in seconds, where the video should start
  28. } = location.query;
  29. const {fetchError, fetching, onRetry, replay} = useReplayData({
  30. eventSlug,
  31. orgId,
  32. });
  33. const {ref: fullscreenRef, isFullscreen, toggle: toggleFullscreen} = useFullscreen();
  34. if (!fetching && !replay) {
  35. // TODO(replay): Give the user more details when errors happen
  36. console.log({fetching, fetchError}); // eslint-disable-line no-console
  37. return (
  38. <DetailLayout orgId={orgId}>
  39. <PageContent>
  40. <NotFound />
  41. </PageContent>
  42. </DetailLayout>
  43. );
  44. }
  45. if (!fetching && replay && replay.getRRWebEvents().length < 2) {
  46. return (
  47. <DetailLayout orgId={orgId}>
  48. <DetailedError
  49. onRetry={onRetry}
  50. hideSupportLinks
  51. heading={t('Expected two or more replay events')}
  52. message={
  53. <React.Fragment>
  54. <p>{t('This Replay may not have captured any user actions.')}</p>
  55. <p>
  56. {t(
  57. 'Or there may be an issue loading the actions from the server, click to try loading the Replay again.'
  58. )}
  59. </p>
  60. </React.Fragment>
  61. }
  62. />
  63. </DetailLayout>
  64. );
  65. }
  66. return (
  67. <ReplayContextProvider replay={replay} initialTimeOffset={initialTimeOffset}>
  68. <DetailLayout orgId={orgId}>
  69. <Layout.Body>
  70. <Layout.Main ref={fullscreenRef}>
  71. <ReplayView toggleFullscreen={toggleFullscreen} isFullscreen={isFullscreen} />
  72. </Layout.Main>
  73. <Layout.Side>
  74. <ErrorBoundary mini>
  75. <AsideTabs replay={replay} />
  76. </ErrorBoundary>
  77. </Layout.Side>
  78. <StickyMain fullWidth>
  79. <ErrorBoundary mini>
  80. <ReplayTimeline />
  81. </ErrorBoundary>
  82. <FocusTabs />
  83. </StickyMain>
  84. <StyledLayoutMain fullWidth>
  85. <ErrorBoundary mini>
  86. <FocusArea />
  87. </ErrorBoundary>
  88. </StyledLayoutMain>
  89. </Layout.Body>
  90. </DetailLayout>
  91. </ReplayContextProvider>
  92. );
  93. }
  94. const StickyMain = styled(Layout.Main)`
  95. position: sticky;
  96. top: 0;
  97. z-index: ${p => p.theme.zIndex.header};
  98. /* Make this component full-bleed, so the background covers everything underneath it */
  99. margin: -${space(1.5)} -${space(4)} -${space(3)};
  100. padding: ${space(1.5)} ${space(4)} 0;
  101. max-width: none;
  102. background: ${p => p.theme.background};
  103. `;
  104. const StyledLayoutMain = styled(Layout.Main)`
  105. ${HeaderContainer} {
  106. position: relative;
  107. }
  108. `;
  109. export default ReplayDetails;