replayTimelineSpans.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import React from 'react';
  2. import styled from '@emotion/styled';
  3. import {divide, flattenSpans} from 'sentry/components/replays/utils';
  4. import Tooltip from 'sentry/components/tooltip';
  5. import {tn} from 'sentry/locale';
  6. import space from 'sentry/styles/space';
  7. import useActiveReplayTab from 'sentry/utils/replays/hooks/useActiveReplayTab';
  8. import type {ReplaySpan} from 'sentry/views/replays/types';
  9. type Props = {
  10. /**
  11. * Duration, in milliseconds, of the timeline
  12. */
  13. durationMs: number;
  14. /**
  15. * The spans to render into the timeline
  16. */
  17. spans: ReplaySpan[];
  18. /**
  19. * Timestamp when the timeline begins, in milliseconds
  20. */
  21. startTimestampMs: number;
  22. /**
  23. * Extra classNames
  24. */
  25. className?: string;
  26. };
  27. function ReplayTimelineEvents({className, durationMs, spans, startTimestampMs}: Props) {
  28. const flattenedSpans = flattenSpans(spans);
  29. const {setActiveTab} = useActiveReplayTab();
  30. return (
  31. <Spans className={className}>
  32. {flattenedSpans.map((span, i) => {
  33. const sinceStart = span.startTimestamp - startTimestampMs;
  34. const startPct = divide(sinceStart, durationMs);
  35. const widthPct = divide(span.duration, durationMs);
  36. const requestsCount = tn(
  37. '%s network request',
  38. '%s network requests',
  39. span.spanCount
  40. );
  41. return (
  42. <Tooltip
  43. key={i}
  44. title={
  45. <React.Fragment>
  46. {requestsCount}
  47. <br />
  48. {span.duration.toFixed(2)}ms
  49. </React.Fragment>
  50. }
  51. skipWrapper
  52. disableForVisualTest
  53. position="bottom"
  54. >
  55. <Span
  56. startPct={startPct}
  57. widthPct={widthPct}
  58. onClick={() => setActiveTab('network')}
  59. />
  60. </Tooltip>
  61. );
  62. })}
  63. </Spans>
  64. );
  65. }
  66. const Spans = styled('ul')`
  67. /* Reset defaults for <ul> */
  68. list-style: none;
  69. margin: 0;
  70. padding: 0;
  71. height: ${space(1.5)};
  72. margin-bottom: ${space(0.5)};
  73. position: relative;
  74. pointer-events: none;
  75. `;
  76. const Span = styled('li')<{startPct: number; widthPct: number}>`
  77. cursor: pointer;
  78. display: block;
  79. position: absolute;
  80. left: ${p => p.startPct * 100}%;
  81. min-width: 1px;
  82. width: ${p => p.widthPct * 100}%;
  83. height: 100%;
  84. background: ${p => p.theme.charts.colors[0]};
  85. border-radius: 2px;
  86. pointer-events: auto;
  87. `;
  88. export default React.memo(ReplayTimelineEvents);