details.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import {Fragment} from 'react';
  2. import type {RouteComponentProps} from 'react-router';
  3. import DetailedError from 'sentry/components/errors/detailedError';
  4. import NotFound from 'sentry/components/errors/notFound';
  5. import List from 'sentry/components/list';
  6. import ListItem from 'sentry/components/list/listItem';
  7. import {
  8. Provider as ReplayContextProvider,
  9. useReplayContext,
  10. } from 'sentry/components/replays/replayContext';
  11. import {t} from 'sentry/locale';
  12. import {PageContent} from 'sentry/styles/organization';
  13. import useReplayData from 'sentry/utils/replays/hooks/useReplayData';
  14. import useReplayLayout from 'sentry/utils/replays/hooks/useReplayLayout';
  15. import useReplayPageview from 'sentry/utils/replays/hooks/useReplayPageview';
  16. import Layout from 'sentry/views/replays/detail/layout';
  17. import Page from 'sentry/views/replays/detail/page';
  18. type Props = RouteComponentProps<
  19. {orgId: string; replaySlug: string},
  20. {},
  21. any,
  22. {t: number}
  23. >;
  24. function ReplayDetails({
  25. location: {
  26. query: {
  27. t: initialTimeOffset, // Time, in seconds, where the video should start
  28. },
  29. },
  30. params: {orgId: orgSlug, replaySlug},
  31. }: Props) {
  32. useReplayPageview();
  33. const {fetching, onRetry, replay, fetchError} = useReplayData({
  34. replaySlug,
  35. orgSlug,
  36. });
  37. if (!fetching && !replay && fetchError) {
  38. if (fetchError.statusText === 'Not Found') {
  39. return (
  40. <Page orgSlug={orgSlug}>
  41. <PageContent>
  42. <NotFound />
  43. </PageContent>
  44. </Page>
  45. );
  46. }
  47. const reasons = [
  48. t('The Replay is still processing and is on its way'),
  49. t('There is an internal systems error or active issue'),
  50. ];
  51. return (
  52. <Page orgSlug={orgSlug}>
  53. <PageContent>
  54. <DetailedError
  55. onRetry={onRetry}
  56. hideSupportLinks
  57. heading={t('There was an error while fetching this Replay')}
  58. message={
  59. <Fragment>
  60. <p>{t('This could be due to a couple of reasons:')}</p>
  61. <List symbol="bullet">
  62. {reasons.map((reason, i) => (
  63. <ListItem key={i}>{reason}</ListItem>
  64. ))}
  65. </List>
  66. </Fragment>
  67. }
  68. />
  69. </PageContent>
  70. </Page>
  71. );
  72. }
  73. if (!fetching && replay && replay.getRRWebEvents().length < 2) {
  74. return (
  75. <Page orgSlug={orgSlug} replayRecord={replay.getReplay()}>
  76. <DetailedError
  77. hideSupportLinks
  78. heading={t('Expected two or more replay events')}
  79. message={
  80. <Fragment>
  81. <p>{t('This Replay may not have captured any user actions.')}</p>
  82. <p>
  83. {t(
  84. 'Or there may be an issue loading the actions from the server, click to try loading the Replay again.'
  85. )}
  86. </p>
  87. </Fragment>
  88. }
  89. />
  90. </Page>
  91. );
  92. }
  93. return (
  94. <ReplayContextProvider replay={replay} initialTimeOffset={initialTimeOffset}>
  95. <LoadedDetails orgSlug={orgSlug} />
  96. </ReplayContextProvider>
  97. );
  98. }
  99. function LoadedDetails({orgSlug}: {orgSlug: string}) {
  100. const {getLayout} = useReplayLayout();
  101. const {replay} = useReplayContext();
  102. return (
  103. <Page
  104. orgSlug={orgSlug}
  105. crumbs={replay?.getRawCrumbs()}
  106. replayRecord={replay?.getReplay()}
  107. >
  108. <Layout layout={getLayout()} />
  109. </Page>
  110. );
  111. }
  112. export default ReplayDetails;