replayTimelineSpans.tsx 2.2 KB

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