replayTimeline.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import {useRef} from 'react';
  2. import styled from '@emotion/styled';
  3. import Panel from 'sentry/components/panels/panel';
  4. import Placeholder from 'sentry/components/placeholder';
  5. import {
  6. MajorGridlines,
  7. MinorGridlines,
  8. } from 'sentry/components/replays/breadcrumbs/gridlines';
  9. import ReplayTimelineEvents from 'sentry/components/replays/breadcrumbs/replayTimelineEvents';
  10. import ReplayTimelineSpans from 'sentry/components/replays/breadcrumbs/replayTimelineSpans';
  11. import Stacked from 'sentry/components/replays/breadcrumbs/stacked';
  12. import {
  13. CompactTimelineScrubber,
  14. TimelineScrubber,
  15. } from 'sentry/components/replays/player/scrubber';
  16. import {useTimelineScrubberMouseTracking} from 'sentry/components/replays/player/useScrubberMouseTracking';
  17. import {useReplayContext} from 'sentry/components/replays/replayContext';
  18. import {divide} from 'sentry/components/replays/utils';
  19. import toPercent from 'sentry/utils/number/toPercent';
  20. import {useDimensions} from 'sentry/utils/useDimensions';
  21. import useOrganization from 'sentry/utils/useOrganization';
  22. type Props = {};
  23. function ReplayTimeline({}: Props) {
  24. const {replay, currentTime, timelineScale} = useReplayContext();
  25. const panelRef = useRef<HTMLDivElement>(null);
  26. const mouseTrackingProps = useTimelineScrubberMouseTracking(
  27. {elem: panelRef},
  28. timelineScale
  29. );
  30. const stackedRef = useRef<HTMLDivElement>(null);
  31. const {width} = useDimensions<HTMLDivElement>({elementRef: stackedRef});
  32. const organization = useOrganization();
  33. const hasNewTimeline = organization.features.includes('session-replay-new-timeline');
  34. if (!replay) {
  35. return <Placeholder height={hasNewTimeline ? '20px' : '54px'} />;
  36. }
  37. const durationMs = replay.getDurationMs();
  38. const startTimestampMs = replay.getReplay().started_at.getTime();
  39. const chapterFrames = replay.getChapterFrames();
  40. const networkFrames = replay.getNetworkFrames();
  41. // start of the timeline is in the middle
  42. const initialTranslate = 0.5 / timelineScale;
  43. const translate =
  44. initialTranslate - (currentTime > durationMs ? 1 : divide(currentTime, durationMs));
  45. return hasNewTimeline ? (
  46. <VisiblePanel ref={panelRef} {...mouseTrackingProps}>
  47. <Stacked
  48. style={{
  49. width: `${toPercent(timelineScale)}`,
  50. transform: `translate(${toPercent(translate)}, 0%)`,
  51. }}
  52. ref={stackedRef}
  53. >
  54. <MinorGridlines durationMs={durationMs} width={width} />
  55. <MajorGridlines durationMs={durationMs} width={width} />
  56. <CompactTimelineScrubber />
  57. <TimelineEventsContainer>
  58. <ReplayTimelineEvents
  59. durationMs={durationMs}
  60. frames={chapterFrames}
  61. startTimestampMs={startTimestampMs}
  62. width={width}
  63. />
  64. </TimelineEventsContainer>
  65. </Stacked>
  66. </VisiblePanel>
  67. ) : (
  68. <PanelNoMargin ref={panelRef} {...mouseTrackingProps}>
  69. <Stacked ref={stackedRef}>
  70. <MinorGridlines durationMs={durationMs} width={width} />
  71. <MajorGridlines durationMs={durationMs} width={width} />
  72. <TimelineScrubber />
  73. <div style={{paddingTop: '36px'}}>
  74. <ReplayTimelineSpans
  75. durationMs={durationMs}
  76. frames={networkFrames}
  77. startTimestampMs={startTimestampMs}
  78. />
  79. </div>
  80. <div style={{paddingTop: '26px'}}>
  81. <ReplayTimelineEvents
  82. durationMs={durationMs}
  83. frames={chapterFrames}
  84. startTimestampMs={startTimestampMs}
  85. width={width}
  86. />
  87. </div>
  88. </Stacked>
  89. </PanelNoMargin>
  90. );
  91. }
  92. const PanelNoMargin = styled(Panel)`
  93. margin: 0;
  94. `;
  95. const VisiblePanel = styled(Panel)`
  96. margin: 0;
  97. border: 0;
  98. overflow: hidden;
  99. background: ${p => p.theme.translucentInnerBorder};
  100. `;
  101. const TimelineEventsContainer = styled('div')`
  102. padding-top: 10px;
  103. padding-bottom: 10px;
  104. `;
  105. export default ReplayTimeline;